openlearn-next 0.7.9 → 0.7.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/cli-data.mjs +1 -1
- package/dist/assets/{ActivityWorkspaceWidget-DbspLRxB.js → ActivityWorkspaceWidget-BU88GGUG.js} +1 -1
- package/dist/assets/{AdminDirectoryView-C2ZFIwHx.js → AdminDirectoryView-Cdsk9Mdr.js} +1 -1
- package/dist/assets/{AssessmentCenter-DbJAcTvr.js → AssessmentCenter-BoSWbJMt.js} +1 -1
- package/dist/assets/{AssignmentFilePreview-DEVTb4YJ.js → AssignmentFilePreview-D_POvLmv.js} +1 -1
- package/dist/assets/{BatchPickerModal-czw6eA6e.js → BatchPickerModal-DiHd_6Tg.js} +1 -1
- package/dist/assets/{ClassesView-B1F0tTtB.js → ClassesView-CWKqzWH0.js} +1 -1
- package/dist/assets/{ClassroomCountdownWidget-C9pv3GLy.js → ClassroomCountdownWidget-B5-KUVU8.js} +1 -1
- package/dist/assets/{CloudDriveModal-goDB6dlC.js → CloudDriveModal-CjcvdDiw.js} +1 -1
- package/dist/assets/{ComputerLabView-Csqiqvw2.js → ComputerLabView-CNTcmWAh.js} +1 -1
- package/dist/assets/{CourseManagement-BD-4z2OZ.js → CourseManagement-ha_iSnLU.js} +1 -1
- package/dist/assets/{CourseWizardModal-NXwhuph_.js → CourseWizardModal-oVT9mYSG.js} +1 -1
- package/dist/assets/{Dashboard-CFDWNYSw.js → Dashboard-Vb9coh9_.js} +1 -1
- package/dist/assets/{ExportWeightModal-dBxYVUP4.js → ExportWeightModal-BEesz6rd.js} +1 -1
- package/dist/assets/{HelpView-DSZC-1F0.js → HelpView--Um9DFYx.js} +1 -1
- package/dist/assets/{ImportLessonsModal-m_s44eus.js → ImportLessonsModal-DXGopj4j.js} +1 -1
- package/dist/assets/{InteractiveCoursewareViewer-C7faFOFD.js → InteractiveCoursewareViewer-DzgF9_LU.js} +1 -1
- package/dist/assets/{InteractiveWhiteboard-10fno-bJ.js → InteractiveWhiteboard-DJqgP_tU.js} +7 -7
- package/dist/assets/{LazyCourseware-DNn0O8lA.js → LazyCourseware-6yb_QiYS.js} +2 -2
- package/dist/assets/{LazyWhiteboard-BxpydfnE.js → LazyWhiteboard-CsF9GB6J.js} +2 -2
- package/dist/assets/{LessonEditorView-CMCgnrJD.js → LessonEditorView-CZTZ7Q0B.js} +1 -1
- package/dist/assets/{LiveClassroomView-BA0us3bY.js → LiveClassroomView-D2ugupT9.js} +1 -1
- package/dist/assets/{NotificationDetailModal-BMrt09PY.js → NotificationDetailModal-mUeIQP4R.js} +1 -1
- package/dist/assets/{PluginView-B6gCF1ZB.js → PluginView-CT3-zS2n.js} +1 -1
- package/dist/assets/{QuizGeneratorModal-BNW6tZ78.js → QuizGeneratorModal-ViKxNX5Q.js} +1 -1
- package/dist/assets/{StudentAssignmentEvalPanel-DMwBSOXf.js → StudentAssignmentEvalPanel-BRxHMABY.js} +1 -1
- package/dist/assets/{StudentAssignmentView-cQpPme4_.js → StudentAssignmentView-g-ewJIS3.js} +1 -1
- package/dist/assets/{StudentLessonView-CpGgYV-b.js → StudentLessonView-Dbvr3Xlo.js} +1 -1
- package/dist/assets/{StudentView-BfXi6-NQ.js → StudentView-20vfEk4v.js} +2 -2
- package/dist/assets/{SystemResourceLibraryModal-d4vfqM_9.js → SystemResourceLibraryModal-CDKeaKf8.js} +1 -1
- package/dist/assets/{TeacherView-DSJCvFE-.js → TeacherView-KIKuhXGF.js} +2 -2
- package/dist/assets/{TimetableView-D9Rhnvfj.js → TimetableView-7V2AwWml.js} +1 -1
- package/dist/assets/{index-DCnGJbif.css → index-C4cHQZyx.css} +1 -1
- package/dist/assets/{index-DuxQtTr9.js → index-XduPa2-x.js} +31 -31
- package/dist/assets/{pluginParsers-HRw6CVog.js → pluginParsers-BO6U1E-h.js} +1 -1
- package/dist/assets/{student-workspace-DO1mSl_I.js → student-workspace-DstiW0pM.js} +1 -1
- package/dist/env-validation.cjs +14 -6
- package/dist/index.html +2 -2
- package/dist/server.cjs +681 -346
- package/package.json +2 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{r as n,j as e,R as rr,b as bn}from"./vendor-react-DHoBZpn2.js";import{S as gn,L as yn,G as st,H as rt,a as us,R as Qr,C as en,T as tn}from"./vendor-konva-BOuJWFuE.js";/* empty css */import{aj as Bt,d as wn,N as Pi,h as Di,e as Ls,ak as Ei,al as _i,am as xs,j as ce,L as de,an as Ri,M as sn,E as We,s as Ai,ao as bs,ap as Fi,aq as Li,a0 as Bi,af as Wi,ar as Hi,as as rn,at as Xi,au as Oi,av as Ii,aw as qi}from"./index-DuxQtTr9.js";import{ck as jn,am as Yi,bG as nr,r as vn,cl as Ji,af as bt,M as Nn,c as Ve,V as Zt,s as Ys,a2 as kn,cm as Ui,a8 as Gi,e as Js,R as Et,av as Cn,u as Sn,au as ir,bd as nn,g as gs,aT as Vt,k as Kt,n as Vi,B as Ki,x as Us,ac as ys,D as js,C as Dt,P as Bs,cn as zn,aQ as Mn,bK as $n,bH as Tn,al as Pn,ar,cc as Zi,aU as Gs,bI as Qi,ag as ea,aa as ta,ai as an,an as Qt,X as es,U as Vs,h as ts,T as Dn,E as sa,y as Ks,J as ra,ax as na,a4 as ia,q as aa,co as En,cp as oa,bx as la,cq as ca,cr as da,ah as _n,ad as ua,b$ as xa,bh as ha,ba as Ws}from"./vendor-icons-DLOPlM4i.js";import{P as ma,i as on,a as fa,t as ln,k as pa}from"./vendor-pptx-BqU7v5zS.js";import{A as Rn}from"./AssignmentFilePreview-DEVTb4YJ.js";import"./vendor-utils-BxOuk3id.js";import"./vendor-pdf-DVWGghIL.js";import"./vendor-motion-BFAPOs-b.js";import"./vendor-charts-skggaP9D.js";function ba(t={},r={}){const{replay:l=0,maxItems:i=50}=r,[o,d]=n.useState(()=>l>0?Bt.query(t,{limit:l}):[]),u=n.useRef(t);u.current=t;const x=n.useCallback(a=>{d(w=>{const g=[a,...w];return g.length>i&&(g.length=i),g})},[i]);return n.useEffect(()=>(l>0?d(Bt.query(t,{limit:l})):d([]),Bt.subscribe(u.current,x)),[JSON.stringify(t),l,x]),o}function ga(t,r,l={}){const i=n.useRef(r);i.current=r;const o=n.useRef(t);o.current=t,n.useEffect(()=>Bt.subscribe(o.current,u=>i.current(u),l),[JSON.stringify(t),l.replay])}function ya({lessonId:t,defaultCollapsed:r=!0}){const[l,i]=n.useState(r),[o,d]=n.useState(""),[u,x]=n.useState(""),[a,w]=n.useState(!1),g=n.useMemo(()=>({lessonId:t,types:o?[o]:void 0,sources:u?[u]:void 0}),[t,o,u]),D=ba(g,{replay:100,maxItems:100}),W=n.useMemo(()=>D,[D,a]),k=n.useMemo(()=>Bt.stats(),[D]),z=n.useMemo(()=>Object.keys(k.byType).sort(),[k]);return e.jsx("div",{"data-testid":"whiteboard-event-panel",className:"fixed bottom-4 right-4 z-50",style:{maxWidth:380},children:l?e.jsxs("button",{type:"button",onClick:()=>i(!1),"data-testid":"whiteboard-event-panel-toggle",className:"px-3 py-2 bg-white/95 backdrop-blur-sm rounded-lg shadow-lg border border-gray-200 text-xs font-medium text-gray-700 hover:bg-white",children:["🔔 事件流 (",D.length,")"]}):e.jsxs("div",{"data-testid":"whiteboard-event-panel-body",className:"bg-white/95 backdrop-blur-sm rounded-xl shadow-2xl border border-gray-200 p-3 text-xs",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2 mb-2",children:[e.jsx("div",{className:"font-semibold text-gray-700",children:"白板事件槽"}),e.jsxs("div",{className:"flex gap-1",children:[e.jsx("button",{type:"button",onClick:()=>w(m=>!m),"data-testid":"whiteboard-event-panel-pause",className:`px-2 py-1 rounded ${a?"bg-amber-100 text-amber-700":"bg-gray-100 text-gray-600"}`,children:a?"继续":"暂停"}),e.jsx("button",{type:"button",onClick:()=>Bt.clear(),"data-testid":"whiteboard-event-panel-clear",className:"px-2 py-1 rounded bg-gray-100 text-gray-600",children:"清空"}),e.jsx("button",{type:"button",onClick:()=>i(!0),"data-testid":"whiteboard-event-panel-collapse",className:"px-2 py-1 rounded bg-gray-100 text-gray-600",children:"收起"})]})]}),e.jsxs("div",{className:"flex gap-1 mb-2",children:[e.jsxs("select",{value:o,onChange:m=>d(m.target.value),"data-testid":"whiteboard-event-panel-type-filter",className:"flex-1 px-2 py-1 text-xs border border-gray-200 rounded",children:[e.jsxs("option",{value:"",children:["全部类型 (",k.total,")"]}),z.map(m=>e.jsxs("option",{value:m,children:[m," (",k.byType[m]??0,")"]},m))]}),e.jsxs("select",{value:u,onChange:m=>x(m.target.value),"data-testid":"whiteboard-event-panel-source-filter",className:"px-2 py-1 text-xs border border-gray-200 rounded",children:[e.jsx("option",{value:"",children:"全部来源"}),e.jsx("option",{value:"iframe.postMessage",children:"iframe.postMessage"}),e.jsx("option",{value:"iframe.bridge",children:"iframe.bridge"}),e.jsx("option",{value:"applet.score",children:"applet.score"}),e.jsx("option",{value:"widget.quiz",children:"widget.quiz"}),e.jsx("option",{value:"widget.canvas",children:"widget.canvas"}),e.jsx("option",{value:"manual",children:"manual"})]})]}),e.jsx("div",{"data-testid":"whiteboard-event-panel-list",className:"space-y-1 max-h-80 overflow-y-auto",children:W.length===0?e.jsx("div",{className:"text-center text-gray-400 py-4",children:"暂无事件"}):W.map(m=>e.jsx(wa,{event:m},m.id))})]})})}function wa({event:t}){const[r,l]=n.useState(!1),i=new Date(t.timestamp).toLocaleTimeString(),o=t.type==="courseware.submitted",d=o&&typeof t.payload.score=="number"&&typeof t.payload.total=="number"?` · ${t.payload.score}/${t.payload.total}`:"",u=o&&t.payload.score>=60;return e.jsxs("div",{"data-testid":`whiteboard-event-row-${t.id}`,className:"border border-gray-100 rounded p-1.5 bg-white/80 hover:bg-white",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsxs("button",{type:"button",onClick:()=>l(x=>!x),className:"flex-1 text-left",children:[e.jsx("span",{className:"font-mono text-gray-400 text-[10px]",children:i})," ",e.jsx("span",{className:`font-semibold ${u?"text-green-600":o?"text-red-500":"text-gray-700"}`,children:t.type}),e.jsx("span",{className:"text-gray-500",children:d}),t.coursewareUuid&&e.jsxs("span",{className:"text-gray-400 text-[10px]",children:[" · ",t.coursewareUuid.slice(0,8)]})]})}),r&&e.jsx("pre",{"data-testid":`whiteboard-event-row-detail-${t.id}`,className:"mt-1 text-[10px] text-gray-600 bg-gray-50 rounded p-1 overflow-x-auto whitespace-pre-wrap break-all",children:JSON.stringify(t,null,2)})]})}const vs=8,ja=8,va=["page_meta","pen","highlighter"];function Qe(t){return!va.includes(t)}function yt(t,r=0){const l=typeof t=="number"?t:Number(t);return Number.isFinite(l)?l:r}function ws(t){return{x:t.x,y:t.y,width:Math.max(0,t.width),height:Math.max(0,t.height)}}function Na(t,r,l=0,i){if(r<=0)return[];if(r===1)return[ws(t)];const o=[ws(t)];for(;o.length<r;){let d=0,u=-1;for(let w=0;w<o.length;w+=1){const g=o[w];if(o.length>=2&&i&&(i==="bottom-full"&&g.y>t.y+1||i==="top-full"&&g.y<=t.y+1||i==="right-full"&&g.x>t.x+1||i==="left-full"&&g.x<=t.x+1))continue;const D=g.width*g.height,W=Math.max(g.width,g.height),k=D*1e4+W;k>=u&&(u=k,d=w)}const x=o.splice(d,1)[0];let a=x.width>=x.height;if(o.length===0&&i&&(i==="bottom-full"||i==="top-full"?a=!1:(i==="left-full"||i==="right-full")&&(a=!0)),a){const w=x.width/2,g={x:x.x,y:x.y,width:w,height:x.height},D={x:x.x+w,y:x.y,width:x.width-w,height:x.height};o.splice(d,0,g,D)}else{const w=x.height/2,g={x:x.x,y:x.y,width:x.width,height:w},D={x:x.x,y:x.y+w,width:x.width,height:x.height-w};o.splice(d,0,g,D)}}return o.sort((d,u)=>Math.abs(d.y-u.y)>1?d.y-u.y:d.x-u.x)}function ka(t,r,l,i="fill",o=1/0){return i==="fill"||t.width<=0||t.height<=0?{id:"",x:t.x,y:t.y,width:Math.max(0,t.width),height:Math.max(0,t.height)}:Ca(t,r,l,o)}function Ca(t,r,l,i=1/0){const o=r>0?r:t.width,d=l>0?l:t.height;if(o<=0||d<=0||t.width<=0||t.height<=0)return{id:"",x:t.x,y:t.y,width:Math.max(0,t.width),height:Math.max(0,t.height)};const u=Math.min(t.width/o,t.height/d,i),x=o*u,a=d*u;return{id:"",x:t.x+(t.width-x)/2,y:t.y+(t.height-a)/2,width:x,height:a}}function Sa(t,r,l={}){const i=l.gap??vs,o=l.padding??ja,d=l.fillMode??"fill",u=l.maxScale??1/0;if(t.length===0)return[];if(r.width<=0||r.height<=0)return[];const x=ws({x:o,y:o,width:r.width-o*2,height:r.height-o*2});if(x.width<=0||x.height<=0)return[];const a=Na(x,t.length,0,l.stackDirection),w=Math.max(0,i)/2;return t.map((g,D)=>{const W=a[D];if(!W)return{id:g.id,x:g.x,y:g.y,width:g.width,height:g.height};const k=ws({x:W.x+w,y:W.y+w,width:W.width-w*2,height:W.height-w*2}),z=ka(k,g.width,g.height,d,u);return{id:g.id,x:z.x,y:z.y,width:z.width,height:z.height}})}function Zs(t,r,l){if(!Qe(t.type))return null;const i=yt(r?.x),o=yt(r?.y);if(t.type==="circle"){const d=l.width>0?l.width/2:24,u=yt(r?.radius)>0?yt(r.radius):d;return{id:t.id,x:i,y:o,width:u*2,height:u*2,shape:"circle"}}return{id:t.id,x:i,y:o,width:yt(r?.width)>0?yt(r.width):l.width,height:yt(r?.height)>0?yt(r.height):l.height}}function Qs(t="rect"){return t==="circle"?["x","y","radius"]:["x","y","width","height"]}function at(t,r="rect"){const l={};for(const i of Qs(r)){const o=Number(t?.[i]);l[i]=Number.isFinite(o)?o:0}return l}function za(t){return t.shape==="circle"?{x:t.x,y:t.y,radius:t.width/2}:{x:t.x,y:t.y,width:t.width,height:t.height}}function er(t,r,l,i=.5){const o=d=>Number.isFinite(Number(d))?Number(d):0;return l.every(d=>Math.abs(o(t?.[d])-o(r?.[d]))<i)}function Ma(t,r){if(t.shape==="circle"){const l=Math.max(1,Math.min(r.width,r.height)/2);return{x:r.x+r.width/2,y:r.y+r.height/2,radius:l}}return{x:r.x,y:r.y,width:r.width,height:r.height}}function $a(t,r,l){const i=r.filter(a=>a.id!==t.id);if(i.length===0)return null;const o=t.x+t.width/2,d=t.y+t.height/2;let u=null,x=1/0;for(const a of i){const w=a.x+a.width/2,g=a.y+a.height/2,D=w-o,W=g-d;if(l==="left"&&D>=-1||l==="right"&&D<=1||l==="up"&&W>=-1||l==="down"&&W<=1)continue;const k=l==="left"||l==="right",z=Math.abs(k?D:W),m=Math.abs(k?W:D);let j=0;if(k){const T=Math.max(t.y,a.y),H=Math.min(t.y+t.height,a.y+a.height);j=Math.max(0,H-T)}else{const T=Math.max(t.x,a.x),H=Math.min(t.x+t.width,a.x+a.width);j=Math.max(0,H-T)}const y=j>0?1/(j+1):m*2.5,f=z+m*1.5+y*10;f<x&&(x=f,u=a)}return u}function Ta(t,r,l){for(const i of r)if(i.id!==l&&t.x>=i.x&&t.x<=i.x+i.width&&t.y>=i.y&&t.y<=i.y+i.height)return i;return null}function Pa(t,r){return[...t].sort((l,i)=>{const o=r?.get(l.id),d=r?.get(i.id);return typeof o=="number"&&typeof d=="number"?o-d:typeof o=="number"?-1:typeof d=="number"?1:Math.abs(l.y-i.y)>10?l.y-i.y:l.x-i.x})}function Da(t,r=vs,l=100){const i=[],o=t.length;if(o<2)return i;for(let d=0;d<o;d+=1){const u=t[d];for(let x=0;x<o;x+=1){if(d===x)continue;const a=t[x],w=u.y+u.height+r;if(Math.abs(a.y-w)<=3){const g=Math.max(u.x,a.x),W=Math.min(u.x+u.width,a.x+a.width)-g;if(W>20){const k=u.y+u.height;i.push({id:`h-split-${u.id}-${a.id}`,orientation:"horizontal",x:g,y:k,length:W,thickness:Math.max(r,8),firstIds:[u.id],secondIds:[a.id],minPos:u.y+l,maxPos:a.y+a.height-l-r,currentPos:k})}}}}for(let d=0;d<o;d+=1){const u=t[d];for(let x=0;x<o;x+=1){if(d===x)continue;const a=t[x],w=u.x+u.width+r;if(Math.abs(a.x-w)<=3){const g=Math.max(u.y,a.y),W=Math.min(u.y+u.height,a.y+a.height)-g;if(W>20){const k=u.x+u.width;i.push({id:`v-split-${u.id}-${a.id}`,orientation:"vertical",x:k,y:g,length:W,thickness:Math.max(r,8),firstIds:[u.id],secondIds:[a.id],minPos:u.x+l,maxPos:a.x+a.width-l-r,currentPos:k})}}}}return i}function Ea(t,r,l){const o=Math.max(t.minPos,Math.min(t.maxPos,t.currentPos+r))-t.currentPos;if(Math.abs(o)<.5)return{};const d={},u=t.orientation==="horizontal";for(const x of t.firstIds){const a=l.find(w=>w.id===x);a&&(u?d[x]={height:Math.max(20,a.height+o)}:d[x]={width:Math.max(20,a.width+o)})}for(const x of t.secondIds){const a=l.find(w=>w.id===x);a&&(u?d[x]={y:a.y+o,height:Math.max(20,a.height-o)}:d[x]={x:a.x+o,width:Math.max(20,a.width-o)})}return d}function _a(t,r,l,i=2,o=vs){const d=(r.x-t.x)/t.width,u=(r.y-t.y)/t.height,a=i<=2&&l!==void 0?{x:l.x??0,y:l.y??0,width:l.width,height:l.height}:t,w=Math.max(40,(a.height-o)/2),g=Math.max(40,(a.width-o)/2);return u<.25?{type:"split-top",targetId:t.id,label:"↑ 上方分割插入",previewRect:{x:a.x,y:a.y,width:a.width,height:w}}:u>.75?{type:"split-bottom",targetId:t.id,label:"↓ 下方分割插入",previewRect:{x:a.x,y:a.y+w+o,width:a.width,height:w}}:d<.25?{type:"split-left",targetId:t.id,label:"← 左侧分割插入",previewRect:{x:a.x,y:a.y,width:g,height:a.height}}:d>.75?{type:"split-right",targetId:t.id,label:"→ 右侧分割插入",previewRect:{x:a.x+g+o,y:a.y,width:g,height:a.height}}:{type:"swap",targetId:t.id,label:"⇄ 松开对调位置",previewRect:{x:t.x,y:t.y,width:t.width,height:t.height}}}function Ra(t,r,l,i,o,d=vs){if(t===r)return{};const u=i.find(j=>j.id===t),x=i.find(j=>j.id===r);if(!u||!x)return{};const a={};if(i.length<=2&&o){const j=o.x??0,y=o.y??0,f=o.width,T=o.height,H=Math.max(40,(T-d)/2),Z=Math.max(40,(f-d)/2);return l==="split-bottom"?(a[r]={x:j,y,width:f,height:H},a[t]={x:j,y:y+H+d,width:f,height:H}):l==="split-top"?(a[t]={x:j,y,width:f,height:H},a[r]={x:j,y:y+H+d,width:f,height:H}):l==="split-right"?(a[r]={x:j,y,width:Z,height:T},a[t]={x:j+Z+d,y,width:Z,height:T}):l==="split-left"&&(a[t]={x:j,y,width:Z,height:T},a[r]={x:j+Z+d,y,width:Z,height:T}),a}const w=Math.abs(x.x-u.x)<=4&&Math.abs(x.width-u.width)<=4&&(Math.abs(x.y+x.height+d-u.y)<=4||Math.abs(u.y+u.height+d-x.y)<=4),g=Math.abs(x.y-u.y)<=4&&Math.abs(x.height-u.height)<=4&&(Math.abs(x.x+x.width+d-u.x)<=4||Math.abs(u.x+u.width+d-x.x)<=4);if(w){const j=Math.min(u.y,x.y),y=u.height+x.height+d;if(l==="split-top"){const f=Math.max(40,(y-d)/2);return a[t]={x:x.x,y:j,width:x.width,height:f},a[r]={x:x.x,y:j+f+d,width:x.width,height:f},a}if(l==="split-bottom"){const f=Math.max(40,(y-d)/2);return a[r]={x:x.x,y:j,width:x.width,height:f},a[t]={x:x.x,y:j+f+d,width:x.width,height:f},a}if(l==="split-left"){const f=Math.max(40,(x.width-d)/2);return a[t]={x:x.x,y:j,width:f,height:y},a[r]={x:x.x+f+d,y:j,width:f,height:y},a}if(l==="split-right"){const f=Math.max(40,(x.width-d)/2);return a[r]={x:x.x,y:j,width:f,height:y},a[t]={x:x.x+f+d,y:j,width:f,height:y},a}}if(g){const j=Math.min(u.x,x.x),y=u.width+x.width+d;if(l==="split-left"){const f=Math.max(40,(y-d)/2);return a[t]={x:j,y:x.y,width:f,height:x.height},a[r]={x:j+f+d,y:x.y,width:f,height:x.height},a}if(l==="split-right"){const f=Math.max(40,(y-d)/2);return a[r]={x:j,y:x.y,width:f,height:x.height},a[t]={x:j+f+d,y:x.y,width:f,height:x.height},a}if(l==="split-top"){const f=Math.max(40,(x.height-d)/2);return a[t]={x:j,y:x.y,width:y,height:f},a[r]={x:j,y:x.y+f+d,width:y,height:f},a}if(l==="split-bottom"){const f=Math.max(40,(x.height-d)/2);return a[r]={x:j,y:x.y,width:y,height:f},a[t]={x:j,y:x.y+f+d,width:y,height:f},a}}const D=i.filter(j=>j.id!==t&&j.id!==r),W=D.find(j=>Math.abs(j.x-u.x)<=4&&Math.abs(j.width-u.width)<=4&&(Math.abs(j.y+j.height+d-u.y)<=4||Math.abs(u.y+u.height+d-j.y)<=4)),k=D.find(j=>Math.abs(j.y-u.y)<=4&&Math.abs(j.height-u.height)<=4&&(Math.abs(j.x+j.width+d-u.x)<=4||Math.abs(u.x+u.width+d-j.x)<=4));if(W){const j=Math.min(W.y,u.y),y=W.height+u.height+d;a[W.id]={x:W.x,y:j,width:W.width,height:y}}else if(k){const j=Math.min(k.x,u.x),y=k.width+u.width+d;a[k.id]={x:j,y:k.y,width:y,height:k.height}}const z=Math.max(40,(x.height-d)/2),m=Math.max(40,(x.width-d)/2);return l==="split-top"?(a[t]={x:x.x,y:x.y,width:x.width,height:z},a[r]={x:x.x,y:x.y+z+d,width:x.width,height:z}):l==="split-bottom"?(a[r]={x:x.x,y:x.y,width:x.width,height:z},a[t]={x:x.x,y:x.y+z+d,width:x.width,height:z}):l==="split-left"?(a[t]={x:x.x,y:x.y,width:m,height:x.height},a[r]={x:x.x+m+d,y:x.y,width:m,height:x.height}):l==="split-right"&&(a[r]={x:x.x,y:x.y,width:m,height:x.height},a[t]={x:x.x+m+d,y:x.y,width:m,height:x.height}),a}const Aa=1e3,wt=new Map;function Ue(t,r){const l=r!==void 0?r:{};if(!t)return l;const i=typeof t=="string"?t:t.data;if(!i||typeof i!="string")return i||l;if(wt.has(i)){const o=wt.get(i);return wt.delete(i),wt.set(i,o),o}try{const o=JSON.parse(i);if(wt.size>=Aa){const d=wt.keys().next().value;d!==void 0&&wt.delete(d)}return wt.set(i,o),o}catch(o){return console.warn("[parseElementData] Failed to parse element data:",o,i),l}}function pt(t,r=0){const l=typeof t=="number"?t:Number(t);return Number.isFinite(l)?l:r}function Fa(t){let r=0,l=0;for(const i of t){const o=pt(i?.x),d=pt(i?.y),u=Math.max(0,pt(i?.width)),x=Math.max(0,pt(i?.height));r=Math.max(r,o+u),l=Math.max(l,d+x)}return{maxX:r,maxY:l}}function La(t,r,l=0){const i=Math.max(0,pt(l)),o=Math.max(0,pt(t?.width)),d=Math.max(0,pt(t?.height)),u=Math.ceil(Math.max(0,pt(r?.maxX))+i),x=Math.ceil(Math.max(0,pt(r?.maxY))+i);return{width:Math.max(o,u),height:Math.max(d,x)}}function Ba(t,r,l,i){return{x:t-l.left+(i?.scrollLeft||0),y:r-l.top+(i?.scrollTop||0)}}function An(t,r,l){if(t.type==="page_meta")return!1;try{const i=JSON.parse(t.data),o=i.page??0,d=l[r];return i.pageId&&d?.id?i.pageId===d.id:o===r}catch{return r===0}}function Wa(t,r,l,i){return t.filter(o=>{if(!An(o,r,l))return!1;try{const d=JSON.parse(o.data);return!(i&&d.segmentId&&d.segmentId!==i)}catch{return r===0}})}function Ha(t,r,l=Date.now()){const i=t.length,o={id:`page-${l}-${i}`,title:r||`P${i+1} · 备课页面`,order:i};return{newPages:[...t,o],newIndex:i,newPage:o}}function Xa(t,r,l){const i=l.trim();return i?t.map((o,d)=>d===r?{...o,title:i}:o):t}function Oa(t,r,l=Date.now()){const i=t[r];if(!i)return null;const o=r+1,d={id:`page-${l}-${o}`,title:`${i.title} (副本)`,order:o};return{newPages:[...t.slice(0,o),d,...t.slice(o).map(x=>({...x,order:x.order+1}))],newIndex:o,newPage:d}}function Ia(t,r,l){const i=l==="left"?r-1:r+1;if(i<0||i>=t.length)return null;const o=[...t],d=o[r];return o[r]=o[i],o[i]=d,o.forEach((u,x)=>{u.order=x}),{newPages:o,targetIndex:i}}class qa{constructor(){this.frameTimes=[],this.lastTime=performance.now(),this.stats={fps:60,renderTimeMs:0,drawCount:0,visibleCount:0,totalCount:0,memoryUsageMb:0}}recordFrame(r,l,i,o){const d=performance.now(),u=d-this.lastTime;this.lastTime=d,u>0&&(this.frameTimes.push(1e3/u),this.frameTimes.length>30&&this.frameTimes.shift());const x=Math.round(this.frameTimes.reduce((w,g)=>w+g,0)/(this.frameTimes.length||1));let a=0;performance.memory&&(a=Math.round(performance.memory.usedJSHeapSize/(1024*1024)*10)/10),this.stats={fps:x,renderTimeMs:Math.round(r*100)/100,drawCount:l,visibleCount:i,totalCount:o,memoryUsageMb:a}}getStats(){return{...this.stats}}}new qa;class Ya{constructor(){this.currentTheme="light",this.lightTokens={primary:"#4f46e5",background:"#f8fafc",gridDot:"#cbd5e1",selectionBorder:"#6366f1",selectionHandle:"#4f46e5",textPrimary:"#1e293b",borderDefault:"#e2e8f0",guideLine:"#ec4899"},this.darkTokens={primary:"#6366f1",background:"#0b0f19",gridDot:"#334155",selectionBorder:"#818cf8",selectionHandle:"#6366f1",textPrimary:"#f8fafc",borderDefault:"#1e293b",guideLine:"#f472b6"},this.eyecareTokens={primary:"#2d6a4f",background:"#f2f7f4",gridDot:"#b7d5c5",selectionBorder:"#40916c",selectionHandle:"#2d6a4f",textPrimary:"#143526",borderDefault:"#cce0d6",guideLine:"#10b981"},this.chalkboardTokens={primary:"#4caf50",background:"#0e1713",gridDot:"#2d5242",selectionBorder:"#81c784",selectionHandle:"#4caf50",textPrimary:"#e8f5e9",borderDefault:"#1f382d",guideLine:"#66bb6a"},this.teachingTokens={primary:"#d97706",background:"#fffbeb",gridDot:"#fde68a",selectionBorder:"#f59e0b",selectionHandle:"#d97706",textPrimary:"#78350f",borderDefault:"#fef3c7",guideLine:"#ef4444"},this.customTokens=new Map,this.listeners=new Set}getTokens(){if(this.customTokens.has(this.currentTheme))return this.customTokens.get(this.currentTheme);switch(this.currentTheme){case"dark":return this.darkTokens;case"eyecare":return this.eyecareTokens;case"chalkboard":return this.chalkboardTokens;case"teaching":return this.teachingTokens;default:return this.lightTokens}}setTheme(r){this.currentTheme=r;const l=this.getTokens();this.listeners.forEach(i=>{try{i(l,r)}catch(o){console.error("[ThemeManager] Error in theme change listener:",o)}})}getTheme(){return this.currentTheme}registerCustomTokens(r,l){this.customTokens.set(r,l),this.currentTheme===r&&this.setTheme(r)}unregisterCustomTokens(r){this.customTokens.delete(r),this.currentTheme===r&&this.setTheme("light")}subscribe(r){return this.listeners.add(r),()=>{this.listeners.delete(r)}}}const cn=new Ya;function ut({title:t,icon:r,hidden:l=!1,readOnly:i=!1,isMinimized:o=!1,isMaximized:d=!1,isPropertiesOpen:u=!1,themeColor:x="default",onPointerDown:a,onPointerMove:w,onPointerUp:g,onOpenProperties:D,onMinimize:W,onRestore:k,onMaximize:z,onBrowserFullscreen:m,onDelete:j,extraActions:y}){const f=()=>{switch(x){case"indigo":return"bg-indigo-50/90 dark:bg-indigo-950/60 text-indigo-900 dark:text-indigo-200 border-indigo-200/80 dark:border-indigo-800/60";case"orange":return"bg-orange-50/90 dark:bg-orange-950/60 text-orange-900 dark:text-orange-200 border-orange-200/80 dark:border-orange-800/60";case"purple":return"bg-purple-50/90 dark:bg-purple-950/60 text-purple-900 dark:text-purple-200 border-purple-200/80 dark:border-purple-800/60";case"gray":case"slate":case"default":default:return"bg-surface-secondary/90 text-main border-theme"}};return l?null:e.jsxs("div",{"data-widget-titlebar":"true",className:`px-3 py-1.5 flex justify-between items-center text-xs font-semibold border-b select-none shrink-0 transition-colors ${f()} ${i?"cursor-default":"cursor-move"}`,onPointerDown:a,onPointerMove:w,onPointerUp:g,children:[e.jsxs("div",{className:"flex items-center gap-1.5 min-w-0 mr-2 truncate",children:[r&&e.jsx("span",{className:"shrink-0 opacity-80",children:r}),e.jsx("span",{className:"truncate tracking-tight",children:t}),i&&e.jsx("span",{className:"px-1.5 py-0.5 rounded text-xs bg-amber-100 text-amber-800 dark:bg-amber-950/60 dark:text-amber-300 border border-amber-300 dark:border-amber-700 font-semibold select-none flex items-center gap-0.5 shrink-0",children:"🔒 只读锁定"})]}),!i&&e.jsxs("div",{className:"flex items-center gap-0.5 shrink-0",onPointerDown:T=>T.stopPropagation(),children:[y,D&&e.jsx("button",{type:"button",onClick:D,className:`p-1 rounded-lg transition-all cursor-pointer flex items-center justify-center ${u?"bg-primary-theme text-white shadow-2xs":"text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10"}`,title:"属性配置",children:e.jsx(jn,{size:12})}),W&&e.jsx("button",{type:"button",onClick:W,disabled:o,className:`p-1 rounded-lg transition-all flex items-center justify-center ${o?"opacity-30 cursor-not-allowed text-muted":"text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10 cursor-pointer"}`,title:"最小化组件",children:e.jsx(Yi,{size:12})}),k&&e.jsx("button",{type:"button",onClick:k,className:`p-1 rounded-lg transition-all flex items-center justify-center ${o||d?"text-primary-theme font-bold bg-primary-theme/15 hover:bg-primary-theme/25 cursor-pointer shadow-2xs ring-1 ring-primary-theme/30":"text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10 cursor-pointer"}`,title:"还原组件",children:e.jsx(nr,{size:11,className:o||d?"stroke-[2.5]":""})}),z&&e.jsx("button",{type:"button","data-testid":"widget-titlebar-board-fullscreen",onClick:z,disabled:d,className:`p-1 rounded-lg transition-all flex items-center justify-center ${d?"opacity-30 cursor-not-allowed text-muted":"text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10 cursor-pointer"}`,title:"白板全屏(组件在画布内最大化)",children:e.jsx(vn,{size:11})}),m&&e.jsx("button",{type:"button","data-testid":"widget-titlebar-browser-fullscreen",onClick:m,className:"p-1 rounded-lg text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10 transition-all cursor-pointer flex items-center justify-center",title:"整个浏览器全屏(脱离白板并铺满屏幕,适合投屏)",children:e.jsx(Ji,{size:11})}),j&&e.jsx("button",{type:"button",onClick:j,className:"p-1 rounded-lg text-muted hover:text-rose-600 hover:bg-rose-500/10 transition-all cursor-pointer flex items-center justify-center",title:"删除组件",children:e.jsx(bt,{size:12})})]})]})}const Ja=1e5;function dn({children:t,onMaximize:r,onBrowserFullscreen:l,isBrowserFullscreen:i=!1,browserFullscreenDismissible:o=!0,contentClassName:d="flex-1 min-h-0 overflow-auto",...u}){if(i)return e.jsxs("div",{"data-widget-frame":"browser-fullscreen",style:{pointerEvents:"auto"},className:"fixed inset-0 bg-white dark:bg-slate-950 flex flex-col",children:[o&&l&&e.jsxs("button",{type:"button","data-testid":"widget-frame-exit-browser-fullscreen",onClick:l,className:"fixed top-4 right-4 z-[100001] px-3 py-2 rounded-xl bg-slate-900/85 hover:bg-slate-900 text-slate-100 text-xs font-bold flex items-center gap-1.5 shadow-2xl backdrop-blur-md border border-white/15 transition-colors cursor-pointer",title:"退出全屏(Esc)",children:[e.jsx(Nn,{size:14}),"退出全屏"]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-auto",children:t})]});const{title:x,icon:a,readOnly:w,isMinimized:g,isMaximized:D,isPropertiesOpen:W,themeColor:k,extraActions:z,...m}=u;return e.jsxs("div",{"data-widget-frame":"true",className:"w-full h-full flex flex-col min-h-0",children:[e.jsx(ut,{title:x,icon:a,readOnly:w,isMinimized:g,isMaximized:D,isPropertiesOpen:W,themeColor:k,extraActions:z,...m,onMaximize:r,onBrowserFullscreen:l}),!g&&e.jsx("div",{className:d,children:t})]})}function un(){if(typeof document>"u")return!1;const t=document.documentElement;return!!(t.requestFullscreen||t.webkitRequestFullscreen)}function Hs(){return typeof document>"u"?!1:!!(document.fullscreenElement||document.webkitFullscreenElement)}function Ua({elementId:t,enableNativeFullscreen:r=!0,onChange:l}){const i=un(),[o,d]=n.useState(!1),u=n.useRef(t);u.current=t;const x=n.useRef(l);x.current=l,n.useEffect(()=>()=>{Hs()&&document.exitFullscreen?.()?.catch?.(()=>{})},[]),n.useEffect(()=>{if(typeof document>"u")return;const g=()=>{const D=Hs();d(D),!D&&u.current&&x.current&&x.current(null)};return document.addEventListener("fullscreenchange",g),document.addEventListener("webkitfullscreenchange",g),()=>{document.removeEventListener("fullscreenchange",g),document.removeEventListener("webkitfullscreenchange",g)}},[]);const a=n.useCallback(async g=>{if(x.current?.(g),!!r&&un())try{const D=document.documentElement;await(D.requestFullscreen?.()??D.webkitRequestFullscreen?.()),d(!0)}catch(D){console.warn("[BrowserFullscreen] native fullscreen rejected:",D)}},[r]),w=n.useCallback(async()=>{if(x.current?.(null),Hs())try{await document.exitFullscreen?.()}catch(g){console.warn("[BrowserFullscreen] exit failed:",g)}d(!1)},[]);return{nativeSupported:i,nativeActive:o,enter:a,exit:w}}function Ga({pluginId:t,slot:r,widgetId:l,elementId:i,lessonId:o,classId:d,studentId:u,studentName:x}){const w=wn(z=>z.extensionPoints).get(r)||[],g=w.find(z=>z.id===l)??w.find(z=>z.pluginId===t&&z.id===l),D=!!g&&typeof g.component=="function"&&g.component!==Pi,W=n.useRef(null);if(n.useEffect(()=>{g&&W.current&&!D&&(W.current.innerHTML="",g.render&&Promise.resolve(g.render(W.current,{elementId:i,lessonId:o})).catch(console.error))},[g,D,t,l,i,o]),!g)return e.jsxs("div",{className:"text-center py-6 text-xs text-gray-400 italic flex flex-col justify-center items-center h-full",children:[e.jsx(Ve,{size:16,className:"animate-spin mb-1"}),e.jsxs("span",{children:["组件 [",l,"] 正在加载或未启用..."]})]});if(D)return rr.createElement(g.component,{elementId:i,lessonId:o});const k=g.slotProps?.view||g.view;return k?e.jsx(Di,{pluginId:g.pluginId,view:String(k),label:g.label,slot:r,lessonId:o,classId:d,studentId:u,studentName:x,variant:"panel"}):e.jsx("div",{ref:W,className:"w-full h-full min-h-0"})}function Va({elementId:t,data:r,lessonId:l,classId:i,onElementUpdate:o,onPointerDown:d,onPointerMove:u,onPointerUp:x,onDelete:a,readOnly:w=!1,userRole:g="teacher",isMinimized:D=!1,isMaximized:W=!1,hidden:k=!1,onBrowserFullscreen:z,isPropertiesOpen:m=!1,onOpenProperties:j,onMinimize:y,onRestore:f,onMaximize:T}){const H=Ls(re=>re.classes)||[],Z=Ls(re=>re.onlineStudentIds),J=Ls(re=>re.activeStudentLessons),[O,he]=n.useState(i||r.classId||(H[0]?.id??"")),[K,ue]=n.useState(()=>Array.isArray(r.candidates)&&r.candidates.length>0?r.candidates:Array.isArray(r.allStudents)&&r.allStudents.length>0?r.allStudents:i||r.classId||l?[]:[{id:"mock-s-1",name:"张明",student_number:"101",tier:"basic",term_picked_count:0,lesson_picked_count:0},{id:"mock-s-2",name:"李华",student_number:"102",tier:"intermediate",term_picked_count:1,lesson_picked_count:0},{id:"mock-s-3",name:"王超",student_number:"103",tier:"advanced",term_picked_count:2,lesson_picked_count:0},{id:"mock-s-4",name:"赵丽",student_number:"104",tier:"basic",term_picked_count:0,lesson_picked_count:0},{id:"mock-s-5",name:"钱科",student_number:"105",tier:"intermediate",term_picked_count:1,lesson_picked_count:0},{id:"mock-s-6",name:"孙雪",student_number:"106",tier:"advanced",term_picked_count:3,lesson_picked_count:0}]),[E,te]=n.useState(!!(i||r.classId)),[U,v]=n.useState(r.pickerMode||"fair_all"),[P,C]=n.useState(r.difficulty||"intermediate"),[M,q]=n.useState(r.selectedStudent||null),[X,A]=n.useState(!1),[F,L]=n.useState(null),[p,$]=n.useState(r.evaluation||null),I=n.useMemo(()=>JSON.stringify([r.pickedTime??null,r.selectedStudent?.id??null,r.evaluation?.rating??null,r.evaluation?.submitted??null]),[r.pickedTime,r.selectedStudent,r.evaluation]),G=n.useRef(null),le=n.useRef(r);le.current=r;const se=n.useRef([]),ve=n.useMemo(()=>l?(Z||[]).filter(re=>J?.[re]===l).slice().sort().join("\0"):"",[l,Z,J]);n.useEffect(()=>{r.pickedTime!=null&&G.current!==I&&(G.current=I,q(r.selectedStudent??null),$(r.evaluation??null),A(!1),L(null))},[I,r.pickedTime,r.selectedStudent,r.evaluation]),n.useEffect(()=>{if(!O)return;let re=!0;te(!0);const ge=`/api/classes/${O}/picker-candidates${l?`?lessonId=${encodeURIComponent(l)}`:""}`;return fetch(ge).then(_=>{if(!_.ok)throw new Error("Failed to load class picker candidates");return _.json()}).then(_=>{!re||!Array.isArray(_)||(_.length>0||l)&&ue(_)}).catch(_=>{console.warn("[RollCallWrapper] candidates fallback:",_)}).finally(()=>{re&&te(!1)}),()=>{re=!1}},[O,l,ve]);const Le=n.useMemo(()=>Ei(K,{onlineStudentIds:Z,activeStudentLessons:J,lessonId:l}),[K,Z,J,l]),ze=n.useMemo(()=>{if(U==="fair_all")return Le;const{filtered:re}=_i(Le,P);return re},[Le,U,P]);se.current=ze;const ye=()=>{if(se.current.length===0||X)return;A(!0),$(null);let re=0;const ge=16,b=setInterval(()=>{const V=se.current;if(V.length===0){clearInterval(b),A(!1),L(null);return}const ae=Math.floor(Math.random()*V.length);if(L(V[ae]),re++,re>=ge){clearInterval(b);const Q=se.current;if(Q.length===0){A(!1),L(null);return}const oe=Ri(Q),_e=oe?oe.student:Q[0];q(_e),A(!1),L(null),ue(Ge=>Ge.map(gt=>gt.id===_e.id?{...gt,lesson_picked_count:(gt.lesson_picked_count||0)+1}:gt)),o&&o(t,{...le.current,classId:O,pickerMode:U,difficulty:P,selectedStudent:_e,pickedTime:new Date().toISOString(),status:"picked",evaluation:null}),ce.publish({id:de(),type:"rollcall.picked",source:"rollcall.picker",payload:{elementId:t,studentId:_e.id,studentName:_e.name,classId:O,lessonId:l},timestamp:Date.now()})}},70)},Ce=g==="teacher"||g==="administrator",xt=async re=>{if(!M||p?.submitted)return;const ge=xs[re],_={rating:re,score:ge.score,rewardCoins:ge.rewardCoins,submitted:!0};$(_),ue(b=>b.map(V=>V.id===M.id?{...V,total_reward_coins:(V.total_reward_coins||0)+ge.rewardCoins}:V));try{await fetch("/api/rollcalls/evaluate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:`rollcall-${t}-${M.id}-${Date.now()}`,studentId:M.id,studentName:M.name,classId:O,lessonId:l,rating:re,score:ge.score,rewardCoins:ge.rewardCoins,difficulty:U==="tiered"?P:"intermediate"})})}catch(b){console.error("[RollCallWrapper] evaluate rollcall failed:",b)}o&&o(t,{...le.current,evaluation:_}),ce.publish({id:de(),type:"rollcall.evaluated",source:"rollcall.picker",payload:{elementId:t,studentId:M.id,rating:re,rewardCoins:ge.rewardCoins,score:ge.score},timestamp:Date.now()})};return e.jsxs("div",{className:"w-full h-full bg-gradient-to-br from-indigo-950 via-slate-900 to-indigo-900 border border-indigo-500/50 rounded-xl shadow-2xl overflow-hidden flex flex-col font-sans select-none",style:{pointerEvents:w?"none":"auto"},children:[e.jsx(ut,{title:"随机点名助手 (分层抽问 Fair Picker)",icon:e.jsx(Zt,{size:13,className:"animate-pulse text-amber-400"}),readOnly:w,isMinimized:D,isMaximized:W,hidden:k,onBrowserFullscreen:z,isPropertiesOpen:m,themeColor:"indigo",onPointerDown:d,onPointerMove:u,onPointerUp:x,onOpenProperties:j,onMinimize:y,onRestore:f,onMaximize:T,onDelete:a,extraActions:H.length>1&&Ce?e.jsx("div",{className:"relative mr-1",onPointerDown:re=>re.stopPropagation(),children:e.jsx("select",{value:O,onChange:re=>he(re.target.value),className:"bg-indigo-900/80 text-indigo-100 text-[11px] rounded px-1.5 py-0.5 border border-indigo-700/60 outline-hidden cursor-pointer",children:H.map(re=>e.jsx("option",{value:re.id,className:"bg-slate-900 text-white",children:re.name},re.id))})}):null}),!D&&e.jsxs(e.Fragment,{children:[Ce&&e.jsxs("div",{className:"px-3 py-1.5 bg-indigo-950/40 border-b border-indigo-900/40 flex items-center justify-between gap-2 shrink-0 text-xs",onPointerDown:re=>re.stopPropagation(),children:[e.jsxs("div",{className:"flex items-center gap-1 bg-indigo-900/40 p-0.5 rounded-lg border border-indigo-800/40",children:[e.jsx("button",{onClick:()=>v("fair_all"),className:`px-2 py-0.5 rounded text-xs font-medium transition-all ${U==="fair_all"?"bg-indigo-600 text-white shadow-2xs font-bold":"text-indigo-300 hover:text-white"}`,children:"全员公平"}),e.jsx("button",{onClick:()=>v("tiered"),className:`px-2 py-0.5 rounded text-xs font-medium transition-all ${U==="tiered"?"bg-purple-600 text-white shadow-2xs font-bold":"text-indigo-300 hover:text-white"}`,children:"分层抽问"})]}),U==="tiered"&&e.jsx("div",{className:"flex items-center gap-1",children:["basic","intermediate","advanced"].map(re=>{const ge=re==="basic"?"基础":re==="intermediate"?"进阶":"拔高",_=re==="basic"?"bg-emerald-600 text-white":re==="intermediate"?"bg-blue-600 text-white":"bg-amber-600 text-white";return e.jsx("button",{onClick:()=>C(re),className:`px-1.5 py-0.5 rounded text-xs font-medium transition-all ${P===re?`${_} font-bold shadow-2xs`:"text-indigo-400 hover:text-white"}`,children:ge},re)})})]}),e.jsxs("div",{className:"flex-1 p-3 flex flex-col justify-between min-h-0 text-white gap-2",children:[e.jsx("div",{className:"w-full flex-1 flex flex-col items-center justify-center p-2 rounded-lg bg-indigo-950/50 border border-indigo-900/30 relative overflow-hidden",children:X?e.jsxs("div",{className:"text-center space-y-1.5 animate-pulse",children:[e.jsxs("div",{className:"text-xs text-indigo-300 uppercase tracking-widest font-semibold flex items-center justify-center gap-1.5",children:[e.jsx(Ys,{size:12,className:"animate-spin text-amber-400"}),e.jsx("span",{children:"检索加权公平候选池中..."})]}),e.jsx("div",{className:"text-2xl font-extrabold text-amber-300 scale-105 tracking-wider font-sans",children:F?.name||"..."}),e.jsxs("div",{className:"text-xs text-indigo-400/80 font-mono",children:["学号: ",F?.student_number||"---"]})]}):M?e.jsxs("div",{className:"text-center space-y-1 w-full max-w-[260px]",children:[e.jsxs("div",{className:"text-xs text-indigo-400 uppercase tracking-widest font-semibold flex items-center justify-center gap-1",children:[e.jsx(kn,{size:12,className:"text-emerald-400"}),e.jsx("span",{children:"抽中的幸运答题者"})]}),e.jsx("div",{className:"text-2xl font-black text-transparent bg-clip-text bg-gradient-to-r from-amber-200 via-yellow-400 to-amber-300 tracking-wider",children:M.name}),e.jsxs("div",{className:"flex items-center justify-center gap-2 text-xs text-indigo-300/80 font-mono",children:[e.jsxs("span",{children:["学号 ",M.student_number||M.id]}),e.jsx("span",{children:"•"}),e.jsxs("span",{children:["已回答 ",M.lesson_picked_count||0," 次"]}),M.total_reward_coins!==void 0&&e.jsxs(e.Fragment,{children:[e.jsx("span",{children:"•"}),e.jsxs("span",{className:"text-amber-400 flex items-center gap-0.5 font-bold",children:[e.jsx(Ui,{size:10}),M.total_reward_coins]})]})]}),e.jsx("div",{className:"mt-2 pt-2 border-t border-indigo-900/50 w-full",onPointerDown:re=>re.stopPropagation(),children:p?.submitted?e.jsxs("div",{className:"bg-indigo-900/60 border border-emerald-500/40 rounded-lg p-1.5 flex items-center justify-center gap-2 text-xs",children:[e.jsx(Gi,{size:14,className:"text-emerald-400"}),e.jsxs("span",{className:"font-bold text-emerald-300",children:["已评定: ",xs[p.rating].badge," ",xs[p.rating].label]}),e.jsxs("span",{className:"text-amber-300 font-bold flex items-center gap-0.5",children:["+",p.rewardCoins," 金币"]})]}):Ce?e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-2xs text-indigo-300/70 text-center font-medium",children:"作答表现评定与激励下发:"}),e.jsx("div",{className:"grid grid-cols-3 gap-1",children:["excellent","good","encourage"].map(re=>{const ge=xs[re];return e.jsxs("button",{onClick:()=>void xt(re),className:"bg-indigo-900/80 hover:bg-indigo-800 border border-indigo-700/60 hover:border-amber-400/80 text-white rounded py-1 px-1 flex flex-col items-center gap-0.5 transition-all active:scale-95 cursor-pointer shadow-3xs group",children:[e.jsx("span",{className:"text-sm group-hover:scale-110 transition-transform",children:ge.badge}),e.jsx("span",{className:"text-2xs font-semibold",children:ge.label}),e.jsxs("span",{className:"text-3xs text-amber-300 font-mono",children:["+",ge.rewardCoins,"币"]})]},re)})})]}):null})]}):ze.length===0&&!E?e.jsxs("div",{className:"text-center space-y-1.5 px-3","data-testid":"rollcall-no-present-students",children:[e.jsx(Js,{size:26,className:"text-amber-300/90 mx-auto"}),e.jsx("div",{className:"text-xs text-amber-200 font-semibold",children:"当前课堂没有在场学生"}),e.jsx("p",{className:"text-2xs text-indigo-200/80 leading-relaxed",children:"只会抽取已经进入本节课的学生。有人离开后不会再被点到,请等学生加入后再开始。"})]}):e.jsxs("div",{className:"text-center space-y-1",children:[e.jsx(Js,{size:26,className:"text-indigo-400/80 mx-auto animate-pulse"}),e.jsx("div",{className:"text-xs text-indigo-300 font-semibold",children:"随机抽取与分层轮盘"}),e.jsx("p",{className:"text-2xs text-indigo-400/60 leading-tight",children:"频次反比加权算法 • 支持基础/进阶/拔高分层抽问"})]})}),e.jsxs("div",{className:"w-full shrink-0 flex flex-col items-center gap-1",onPointerDown:re=>re.stopPropagation(),children:[e.jsxs("button",{onClick:ye,disabled:X||ze.length===0,className:"w-full py-1.5 bg-gradient-to-r from-indigo-500 via-purple-600 to-indigo-600 hover:from-indigo-600 hover:to-purple-700 text-white font-bold text-xs uppercase tracking-wider rounded-lg shadow-md active:scale-98 disabled:opacity-50 transition-all flex items-center justify-center gap-1.5 cursor-pointer",children:[e.jsx(Ys,{size:12,className:X?"animate-spin":""}),e.jsx("span",{children:X?"加权滚轮运转中...":M?"抽取下一位学生":"开始随机点名"})]}),e.jsxs("div",{className:"text-2xs text-indigo-400/60 text-center font-mono flex items-center justify-center gap-1.5",children:[e.jsxs("span",{children:["候选池:",ze.length," 人"]}),e.jsx("span",{children:"•"}),e.jsx("span",{children:U==="fair_all"?"全员公平":`分层: ${P}`}),E&&e.jsx(Et,{size:9,className:"animate-spin text-indigo-400"})]}),!E&&ze.length===0&&M&&e.jsx("p",{className:"text-2xs text-amber-200/90 text-center leading-relaxed","data-testid":"rollcall-no-present-students",children:"当前课堂没有在场学生。只会抽取已经进入本节课的学生,离开后不会再被点到。"})]})]})]})]})}const tr="Pure computation only. No page session, cookies, document, or LMS API.",Ka="openlearn-code-sandbox",Za=["'use strict';","const denied = function sandboxDenied() {"," throw new Error('Credentialed network is disabled in this sandbox');","};","const blocked = ['fetch','XMLHttpRequest','WebSocket','EventSource','importScripts','Worker','SharedWorker','Request','WebTransport'];","for (const name of blocked) {"," try {"," Object.defineProperty(self, name, { configurable: false, enumerable: true, writable: false, value: denied });"," } catch (e) {}"," let obj = Object.getPrototypeOf(self);"," while (obj) {"," if (Object.getOwnPropertyDescriptor(obj, name)) {"," try {"," Object.defineProperty(obj, name, { configurable: false, enumerable: true, writable: false, value: denied });"," } catch (e2) {}"," }"," obj = Object.getPrototypeOf(obj);"," }","}","try { Object.defineProperty(self, 'Function', { configurable: false, writable: false, value: denied }); } catch (e) {}","try { Object.defineProperty(self, 'eval', { configurable: false, writable: false, value: denied }); } catch (e) {}","try {"," Object.defineProperty(Function.prototype, 'constructor', { configurable: false, writable: false, value: denied });","} catch (e) {}","try {"," let nav = self.navigator;"," while (nav) {"," if (Object.getOwnPropertyDescriptor(nav, 'sendBeacon')) {"," try {"," Object.defineProperty(nav, 'sendBeacon', { configurable: false, writable: false, value: denied });"," } catch (e2) {}"," }"," nav = Object.getPrototypeOf(nav);"," }","} catch (e) {}","if (typeof document !== 'undefined' && document) {"," try {"," Object.defineProperty(document, 'cookie', {"," configurable: false,",' get() { return ""; },'," set() {},"," });"," } catch (e) {}","}","const logs = [];","console.log = (...args) => {"," logs.push(args.map((a) => {"," if (typeof a === 'object' && a !== null) {"," try { return JSON.stringify(a); } catch (e) { return String(a); }"," }"," return String(a);"," }).join(' '));","};","(async () => {"," try {"," const value = await (async function () {"].join(`
|
|
1
|
+
import{r as n,j as e,R as rr,b as gn}from"./vendor-react-DHoBZpn2.js";import{S as yn,L as wn,G as st,H as rt,a as us,R as en,C as tn,T as sn}from"./vendor-konva-BOuJWFuE.js";/* empty css */import{aj as Bt,d as jn,N as Pi,h as Di,e as Ls,ak as Ei,al as _i,am as xs,j as ce,L as de,an as Ri,M as rn,E as We,s as Ai,ao as bs,ap as Fi,aq as Li,a0 as Bi,af as Wi,ar as Hi,as as nn,at as Xi,au as Oi,av as Ii,aw as qi}from"./index-XduPa2-x.js";import{ck as vn,am as Yi,bG as nr,r as Nn,cl as Ji,af as bt,M as kn,T as ir,c as Ve,V as Zt,s as Ys,a2 as Cn,cm as Ui,a8 as Gi,e as Js,R as Et,av as Sn,u as zn,au as ar,bd as an,g as gs,aT as Vt,k as Kt,n as Vi,B as Ki,x as Us,ac as ys,D as js,C as Dt,P as Bs,cn as Mn,aQ as $n,bK as Tn,bH as Pn,al as Dn,ar as or,cc as Zi,aU as Gs,bI as Qi,ag as ea,aa as ta,ai as on,an as Qt,X as es,U as Vs,h as ts,E as sa,y as Ks,J as ra,ax as na,a4 as ia,q as aa,co as En,cp as oa,bx as la,cq as ca,cr as da,ah as _n,ad as ua,b$ as xa,bh as ha,ba as Ws}from"./vendor-icons-DLOPlM4i.js";import{P as ma,i as ln,a as fa,t as cn,k as pa}from"./vendor-pptx-BqU7v5zS.js";import{A as Rn}from"./AssignmentFilePreview-D_POvLmv.js";import"./vendor-utils-BxOuk3id.js";import"./vendor-pdf-DVWGghIL.js";import"./vendor-motion-BFAPOs-b.js";import"./vendor-charts-skggaP9D.js";function ba(t={},r={}){const{replay:l=0,maxItems:i=50}=r,[o,d]=n.useState(()=>l>0?Bt.query(t,{limit:l}):[]),u=n.useRef(t);u.current=t;const x=n.useCallback(a=>{d(w=>{const g=[a,...w];return g.length>i&&(g.length=i),g})},[i]);return n.useEffect(()=>(l>0?d(Bt.query(t,{limit:l})):d([]),Bt.subscribe(u.current,x)),[JSON.stringify(t),l,x]),o}function ga(t,r,l={}){const i=n.useRef(r);i.current=r;const o=n.useRef(t);o.current=t,n.useEffect(()=>Bt.subscribe(o.current,u=>i.current(u),l),[JSON.stringify(t),l.replay])}function ya({lessonId:t,defaultCollapsed:r=!0}){const[l,i]=n.useState(r),[o,d]=n.useState(""),[u,x]=n.useState(""),[a,w]=n.useState(!1),g=n.useMemo(()=>({lessonId:t,types:o?[o]:void 0,sources:u?[u]:void 0}),[t,o,u]),D=ba(g,{replay:100,maxItems:100}),W=n.useMemo(()=>D,[D,a]),k=n.useMemo(()=>Bt.stats(),[D]),z=n.useMemo(()=>Object.keys(k.byType).sort(),[k]);return e.jsx("div",{"data-testid":"whiteboard-event-panel",className:"fixed bottom-4 right-4 z-50",style:{maxWidth:380},children:l?e.jsxs("button",{type:"button",onClick:()=>i(!1),"data-testid":"whiteboard-event-panel-toggle",className:"px-3 py-2 bg-white/95 backdrop-blur-sm rounded-lg shadow-lg border border-gray-200 text-xs font-medium text-gray-700 hover:bg-white",children:["🔔 事件流 (",D.length,")"]}):e.jsxs("div",{"data-testid":"whiteboard-event-panel-body",className:"bg-white/95 backdrop-blur-sm rounded-xl shadow-2xl border border-gray-200 p-3 text-xs",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2 mb-2",children:[e.jsx("div",{className:"font-semibold text-gray-700",children:"白板事件槽"}),e.jsxs("div",{className:"flex gap-1",children:[e.jsx("button",{type:"button",onClick:()=>w(m=>!m),"data-testid":"whiteboard-event-panel-pause",className:`px-2 py-1 rounded ${a?"bg-amber-100 text-amber-700":"bg-gray-100 text-gray-600"}`,children:a?"继续":"暂停"}),e.jsx("button",{type:"button",onClick:()=>Bt.clear(),"data-testid":"whiteboard-event-panel-clear",className:"px-2 py-1 rounded bg-gray-100 text-gray-600",children:"清空"}),e.jsx("button",{type:"button",onClick:()=>i(!0),"data-testid":"whiteboard-event-panel-collapse",className:"px-2 py-1 rounded bg-gray-100 text-gray-600",children:"收起"})]})]}),e.jsxs("div",{className:"flex gap-1 mb-2",children:[e.jsxs("select",{value:o,onChange:m=>d(m.target.value),"data-testid":"whiteboard-event-panel-type-filter",className:"flex-1 px-2 py-1 text-xs border border-gray-200 rounded",children:[e.jsxs("option",{value:"",children:["全部类型 (",k.total,")"]}),z.map(m=>e.jsxs("option",{value:m,children:[m," (",k.byType[m]??0,")"]},m))]}),e.jsxs("select",{value:u,onChange:m=>x(m.target.value),"data-testid":"whiteboard-event-panel-source-filter",className:"px-2 py-1 text-xs border border-gray-200 rounded",children:[e.jsx("option",{value:"",children:"全部来源"}),e.jsx("option",{value:"iframe.postMessage",children:"iframe.postMessage"}),e.jsx("option",{value:"iframe.bridge",children:"iframe.bridge"}),e.jsx("option",{value:"applet.score",children:"applet.score"}),e.jsx("option",{value:"widget.quiz",children:"widget.quiz"}),e.jsx("option",{value:"widget.canvas",children:"widget.canvas"}),e.jsx("option",{value:"manual",children:"manual"})]})]}),e.jsx("div",{"data-testid":"whiteboard-event-panel-list",className:"space-y-1 max-h-80 overflow-y-auto",children:W.length===0?e.jsx("div",{className:"text-center text-gray-400 py-4",children:"暂无事件"}):W.map(m=>e.jsx(wa,{event:m},m.id))})]})})}function wa({event:t}){const[r,l]=n.useState(!1),i=new Date(t.timestamp).toLocaleTimeString(),o=t.type==="courseware.submitted",d=o&&typeof t.payload.score=="number"&&typeof t.payload.total=="number"?` · ${t.payload.score}/${t.payload.total}`:"",u=o&&t.payload.score>=60;return e.jsxs("div",{"data-testid":`whiteboard-event-row-${t.id}`,className:"border border-gray-100 rounded p-1.5 bg-white/80 hover:bg-white",children:[e.jsx("div",{className:"flex items-center justify-between",children:e.jsxs("button",{type:"button",onClick:()=>l(x=>!x),className:"flex-1 text-left",children:[e.jsx("span",{className:"font-mono text-gray-400 text-[10px]",children:i})," ",e.jsx("span",{className:`font-semibold ${u?"text-green-600":o?"text-red-500":"text-gray-700"}`,children:t.type}),e.jsx("span",{className:"text-gray-500",children:d}),t.coursewareUuid&&e.jsxs("span",{className:"text-gray-400 text-[10px]",children:[" · ",t.coursewareUuid.slice(0,8)]})]})}),r&&e.jsx("pre",{"data-testid":`whiteboard-event-row-detail-${t.id}`,className:"mt-1 text-[10px] text-gray-600 bg-gray-50 rounded p-1 overflow-x-auto whitespace-pre-wrap break-all",children:JSON.stringify(t,null,2)})]})}const vs=8,ja=8,va=["page_meta","pen","highlighter"];function Qe(t){return!va.includes(t)}function yt(t,r=0){const l=typeof t=="number"?t:Number(t);return Number.isFinite(l)?l:r}function ws(t){return{x:t.x,y:t.y,width:Math.max(0,t.width),height:Math.max(0,t.height)}}function Na(t,r,l=0,i){if(r<=0)return[];if(r===1)return[ws(t)];const o=[ws(t)];for(;o.length<r;){let d=0,u=-1;for(let w=0;w<o.length;w+=1){const g=o[w];if(o.length>=2&&i&&(i==="bottom-full"&&g.y>t.y+1||i==="top-full"&&g.y<=t.y+1||i==="right-full"&&g.x>t.x+1||i==="left-full"&&g.x<=t.x+1))continue;const D=g.width*g.height,W=Math.max(g.width,g.height),k=D*1e4+W;k>=u&&(u=k,d=w)}const x=o.splice(d,1)[0];let a=x.width>=x.height;if(o.length===0&&i&&(i==="bottom-full"||i==="top-full"?a=!1:(i==="left-full"||i==="right-full")&&(a=!0)),a){const w=x.width/2,g={x:x.x,y:x.y,width:w,height:x.height},D={x:x.x+w,y:x.y,width:x.width-w,height:x.height};o.splice(d,0,g,D)}else{const w=x.height/2,g={x:x.x,y:x.y,width:x.width,height:w},D={x:x.x,y:x.y+w,width:x.width,height:x.height-w};o.splice(d,0,g,D)}}return o.sort((d,u)=>Math.abs(d.y-u.y)>1?d.y-u.y:d.x-u.x)}function ka(t,r,l,i="fill",o=1/0){return i==="fill"||t.width<=0||t.height<=0?{id:"",x:t.x,y:t.y,width:Math.max(0,t.width),height:Math.max(0,t.height)}:Ca(t,r,l,o)}function Ca(t,r,l,i=1/0){const o=r>0?r:t.width,d=l>0?l:t.height;if(o<=0||d<=0||t.width<=0||t.height<=0)return{id:"",x:t.x,y:t.y,width:Math.max(0,t.width),height:Math.max(0,t.height)};const u=Math.min(t.width/o,t.height/d,i),x=o*u,a=d*u;return{id:"",x:t.x+(t.width-x)/2,y:t.y+(t.height-a)/2,width:x,height:a}}function Sa(t,r,l={}){const i=l.gap??vs,o=l.padding??ja,d=l.fillMode??"fill",u=l.maxScale??1/0;if(t.length===0)return[];if(r.width<=0||r.height<=0)return[];const x=ws({x:o,y:o,width:r.width-o*2,height:r.height-o*2});if(x.width<=0||x.height<=0)return[];const a=Na(x,t.length,0,l.stackDirection),w=Math.max(0,i)/2;return t.map((g,D)=>{const W=a[D];if(!W)return{id:g.id,x:g.x,y:g.y,width:g.width,height:g.height};const k=ws({x:W.x+w,y:W.y+w,width:W.width-w*2,height:W.height-w*2}),z=ka(k,g.width,g.height,d,u);return{id:g.id,x:z.x,y:z.y,width:z.width,height:z.height}})}function Zs(t,r,l){if(!Qe(t.type))return null;const i=yt(r?.x),o=yt(r?.y);if(t.type==="circle"){const d=l.width>0?l.width/2:24,u=yt(r?.radius)>0?yt(r.radius):d;return{id:t.id,x:i,y:o,width:u*2,height:u*2,shape:"circle"}}return{id:t.id,x:i,y:o,width:yt(r?.width)>0?yt(r.width):l.width,height:yt(r?.height)>0?yt(r.height):l.height}}function Qs(t="rect"){return t==="circle"?["x","y","radius"]:["x","y","width","height"]}function at(t,r="rect"){const l={};for(const i of Qs(r)){const o=Number(t?.[i]);l[i]=Number.isFinite(o)?o:0}return l}function za(t){return t.shape==="circle"?{x:t.x,y:t.y,radius:t.width/2}:{x:t.x,y:t.y,width:t.width,height:t.height}}function er(t,r,l,i=.5){const o=d=>Number.isFinite(Number(d))?Number(d):0;return l.every(d=>Math.abs(o(t?.[d])-o(r?.[d]))<i)}function Ma(t,r){if(t.shape==="circle"){const l=Math.max(1,Math.min(r.width,r.height)/2);return{x:r.x+r.width/2,y:r.y+r.height/2,radius:l}}return{x:r.x,y:r.y,width:r.width,height:r.height}}function $a(t,r,l){const i=r.filter(a=>a.id!==t.id);if(i.length===0)return null;const o=t.x+t.width/2,d=t.y+t.height/2;let u=null,x=1/0;for(const a of i){const w=a.x+a.width/2,g=a.y+a.height/2,D=w-o,W=g-d;if(l==="left"&&D>=-1||l==="right"&&D<=1||l==="up"&&W>=-1||l==="down"&&W<=1)continue;const k=l==="left"||l==="right",z=Math.abs(k?D:W),m=Math.abs(k?W:D);let j=0;if(k){const T=Math.max(t.y,a.y),H=Math.min(t.y+t.height,a.y+a.height);j=Math.max(0,H-T)}else{const T=Math.max(t.x,a.x),H=Math.min(t.x+t.width,a.x+a.width);j=Math.max(0,H-T)}const y=j>0?1/(j+1):m*2.5,f=z+m*1.5+y*10;f<x&&(x=f,u=a)}return u}function Ta(t,r,l){for(const i of r)if(i.id!==l&&t.x>=i.x&&t.x<=i.x+i.width&&t.y>=i.y&&t.y<=i.y+i.height)return i;return null}function Pa(t,r){return[...t].sort((l,i)=>{const o=r?.get(l.id),d=r?.get(i.id);return typeof o=="number"&&typeof d=="number"?o-d:typeof o=="number"?-1:typeof d=="number"?1:Math.abs(l.y-i.y)>10?l.y-i.y:l.x-i.x})}function Da(t,r=vs,l=100){const i=[],o=t.length;if(o<2)return i;for(let d=0;d<o;d+=1){const u=t[d];for(let x=0;x<o;x+=1){if(d===x)continue;const a=t[x],w=u.y+u.height+r;if(Math.abs(a.y-w)<=3){const g=Math.max(u.x,a.x),W=Math.min(u.x+u.width,a.x+a.width)-g;if(W>20){const k=u.y+u.height;i.push({id:`h-split-${u.id}-${a.id}`,orientation:"horizontal",x:g,y:k,length:W,thickness:Math.max(r,8),firstIds:[u.id],secondIds:[a.id],minPos:u.y+l,maxPos:a.y+a.height-l-r,currentPos:k})}}}}for(let d=0;d<o;d+=1){const u=t[d];for(let x=0;x<o;x+=1){if(d===x)continue;const a=t[x],w=u.x+u.width+r;if(Math.abs(a.x-w)<=3){const g=Math.max(u.y,a.y),W=Math.min(u.y+u.height,a.y+a.height)-g;if(W>20){const k=u.x+u.width;i.push({id:`v-split-${u.id}-${a.id}`,orientation:"vertical",x:k,y:g,length:W,thickness:Math.max(r,8),firstIds:[u.id],secondIds:[a.id],minPos:u.x+l,maxPos:a.x+a.width-l-r,currentPos:k})}}}}return i}function Ea(t,r,l){const o=Math.max(t.minPos,Math.min(t.maxPos,t.currentPos+r))-t.currentPos;if(Math.abs(o)<.5)return{};const d={},u=t.orientation==="horizontal";for(const x of t.firstIds){const a=l.find(w=>w.id===x);a&&(u?d[x]={height:Math.max(20,a.height+o)}:d[x]={width:Math.max(20,a.width+o)})}for(const x of t.secondIds){const a=l.find(w=>w.id===x);a&&(u?d[x]={y:a.y+o,height:Math.max(20,a.height-o)}:d[x]={x:a.x+o,width:Math.max(20,a.width-o)})}return d}function _a(t,r,l,i=2,o=vs){const d=(r.x-t.x)/t.width,u=(r.y-t.y)/t.height,a=i<=2&&l!==void 0?{x:l.x??0,y:l.y??0,width:l.width,height:l.height}:t,w=Math.max(40,(a.height-o)/2),g=Math.max(40,(a.width-o)/2);return u<.25?{type:"split-top",targetId:t.id,label:"↑ 上方分割插入",previewRect:{x:a.x,y:a.y,width:a.width,height:w}}:u>.75?{type:"split-bottom",targetId:t.id,label:"↓ 下方分割插入",previewRect:{x:a.x,y:a.y+w+o,width:a.width,height:w}}:d<.25?{type:"split-left",targetId:t.id,label:"← 左侧分割插入",previewRect:{x:a.x,y:a.y,width:g,height:a.height}}:d>.75?{type:"split-right",targetId:t.id,label:"→ 右侧分割插入",previewRect:{x:a.x+g+o,y:a.y,width:g,height:a.height}}:{type:"swap",targetId:t.id,label:"⇄ 松开对调位置",previewRect:{x:t.x,y:t.y,width:t.width,height:t.height}}}function Ra(t,r,l,i,o,d=vs){if(t===r)return{};const u=i.find(j=>j.id===t),x=i.find(j=>j.id===r);if(!u||!x)return{};const a={};if(i.length<=2&&o){const j=o.x??0,y=o.y??0,f=o.width,T=o.height,H=Math.max(40,(T-d)/2),Z=Math.max(40,(f-d)/2);return l==="split-bottom"?(a[r]={x:j,y,width:f,height:H},a[t]={x:j,y:y+H+d,width:f,height:H}):l==="split-top"?(a[t]={x:j,y,width:f,height:H},a[r]={x:j,y:y+H+d,width:f,height:H}):l==="split-right"?(a[r]={x:j,y,width:Z,height:T},a[t]={x:j+Z+d,y,width:Z,height:T}):l==="split-left"&&(a[t]={x:j,y,width:Z,height:T},a[r]={x:j+Z+d,y,width:Z,height:T}),a}const w=Math.abs(x.x-u.x)<=4&&Math.abs(x.width-u.width)<=4&&(Math.abs(x.y+x.height+d-u.y)<=4||Math.abs(u.y+u.height+d-x.y)<=4),g=Math.abs(x.y-u.y)<=4&&Math.abs(x.height-u.height)<=4&&(Math.abs(x.x+x.width+d-u.x)<=4||Math.abs(u.x+u.width+d-x.x)<=4);if(w){const j=Math.min(u.y,x.y),y=u.height+x.height+d;if(l==="split-top"){const f=Math.max(40,(y-d)/2);return a[t]={x:x.x,y:j,width:x.width,height:f},a[r]={x:x.x,y:j+f+d,width:x.width,height:f},a}if(l==="split-bottom"){const f=Math.max(40,(y-d)/2);return a[r]={x:x.x,y:j,width:x.width,height:f},a[t]={x:x.x,y:j+f+d,width:x.width,height:f},a}if(l==="split-left"){const f=Math.max(40,(x.width-d)/2);return a[t]={x:x.x,y:j,width:f,height:y},a[r]={x:x.x+f+d,y:j,width:f,height:y},a}if(l==="split-right"){const f=Math.max(40,(x.width-d)/2);return a[r]={x:x.x,y:j,width:f,height:y},a[t]={x:x.x+f+d,y:j,width:f,height:y},a}}if(g){const j=Math.min(u.x,x.x),y=u.width+x.width+d;if(l==="split-left"){const f=Math.max(40,(y-d)/2);return a[t]={x:j,y:x.y,width:f,height:x.height},a[r]={x:j+f+d,y:x.y,width:f,height:x.height},a}if(l==="split-right"){const f=Math.max(40,(y-d)/2);return a[r]={x:j,y:x.y,width:f,height:x.height},a[t]={x:j+f+d,y:x.y,width:f,height:x.height},a}if(l==="split-top"){const f=Math.max(40,(x.height-d)/2);return a[t]={x:j,y:x.y,width:y,height:f},a[r]={x:j,y:x.y+f+d,width:y,height:f},a}if(l==="split-bottom"){const f=Math.max(40,(x.height-d)/2);return a[r]={x:j,y:x.y,width:y,height:f},a[t]={x:j,y:x.y+f+d,width:y,height:f},a}}const D=i.filter(j=>j.id!==t&&j.id!==r),W=D.find(j=>Math.abs(j.x-u.x)<=4&&Math.abs(j.width-u.width)<=4&&(Math.abs(j.y+j.height+d-u.y)<=4||Math.abs(u.y+u.height+d-j.y)<=4)),k=D.find(j=>Math.abs(j.y-u.y)<=4&&Math.abs(j.height-u.height)<=4&&(Math.abs(j.x+j.width+d-u.x)<=4||Math.abs(u.x+u.width+d-j.x)<=4));if(W){const j=Math.min(W.y,u.y),y=W.height+u.height+d;a[W.id]={x:W.x,y:j,width:W.width,height:y}}else if(k){const j=Math.min(k.x,u.x),y=k.width+u.width+d;a[k.id]={x:j,y:k.y,width:y,height:k.height}}const z=Math.max(40,(x.height-d)/2),m=Math.max(40,(x.width-d)/2);return l==="split-top"?(a[t]={x:x.x,y:x.y,width:x.width,height:z},a[r]={x:x.x,y:x.y+z+d,width:x.width,height:z}):l==="split-bottom"?(a[r]={x:x.x,y:x.y,width:x.width,height:z},a[t]={x:x.x,y:x.y+z+d,width:x.width,height:z}):l==="split-left"?(a[t]={x:x.x,y:x.y,width:m,height:x.height},a[r]={x:x.x+m+d,y:x.y,width:m,height:x.height}):l==="split-right"&&(a[r]={x:x.x,y:x.y,width:m,height:x.height},a[t]={x:x.x+m+d,y:x.y,width:m,height:x.height}),a}const Aa=1e3,wt=new Map;function Ue(t,r){const l=r!==void 0?r:{};if(!t)return l;const i=typeof t=="string"?t:t.data;if(!i||typeof i!="string")return i||l;if(wt.has(i)){const o=wt.get(i);return wt.delete(i),wt.set(i,o),o}try{const o=JSON.parse(i);if(wt.size>=Aa){const d=wt.keys().next().value;d!==void 0&&wt.delete(d)}return wt.set(i,o),o}catch(o){return console.warn("[parseElementData] Failed to parse element data:",o,i),l}}function pt(t,r=0){const l=typeof t=="number"?t:Number(t);return Number.isFinite(l)?l:r}function Fa(t){let r=0,l=0;for(const i of t){const o=pt(i?.x),d=pt(i?.y),u=Math.max(0,pt(i?.width)),x=Math.max(0,pt(i?.height));r=Math.max(r,o+u),l=Math.max(l,d+x)}return{maxX:r,maxY:l}}function La(t,r,l=0){const i=Math.max(0,pt(l)),o=Math.max(0,pt(t?.width)),d=Math.max(0,pt(t?.height)),u=Math.ceil(Math.max(0,pt(r?.maxX))+i),x=Math.ceil(Math.max(0,pt(r?.maxY))+i);return{width:Math.max(o,u),height:Math.max(d,x)}}function Ba(t,r,l,i){return{x:t-l.left+(i?.scrollLeft||0),y:r-l.top+(i?.scrollTop||0)}}function An(t,r,l){if(t.type==="page_meta")return!1;try{const i=JSON.parse(t.data),o=i.page??0,d=l[r];return i.pageId&&d?.id?i.pageId===d.id:o===r}catch{return r===0}}function Wa(t,r,l,i){return t.filter(o=>{if(!An(o,r,l))return!1;try{const d=JSON.parse(o.data);return!(i&&d.segmentId&&d.segmentId!==i)}catch{return r===0}})}function Ha(t,r,l=Date.now()){const i=t.length,o={id:`page-${l}-${i}`,title:r||`P${i+1} · 备课页面`,order:i};return{newPages:[...t,o],newIndex:i,newPage:o}}function Xa(t,r,l){const i=l.trim();return i?t.map((o,d)=>d===r?{...o,title:i}:o):t}function Oa(t,r,l=Date.now()){const i=t[r];if(!i)return null;const o=r+1,d={id:`page-${l}-${o}`,title:`${i.title} (副本)`,order:o};return{newPages:[...t.slice(0,o),d,...t.slice(o).map(x=>({...x,order:x.order+1}))],newIndex:o,newPage:d}}function Ia(t,r,l){const i=l==="left"?r-1:r+1;if(i<0||i>=t.length)return null;const o=[...t],d=o[r];return o[r]=o[i],o[i]=d,o.forEach((u,x)=>{u.order=x}),{newPages:o,targetIndex:i}}class qa{constructor(){this.frameTimes=[],this.lastTime=performance.now(),this.stats={fps:60,renderTimeMs:0,drawCount:0,visibleCount:0,totalCount:0,memoryUsageMb:0}}recordFrame(r,l,i,o){const d=performance.now(),u=d-this.lastTime;this.lastTime=d,u>0&&(this.frameTimes.push(1e3/u),this.frameTimes.length>30&&this.frameTimes.shift());const x=Math.round(this.frameTimes.reduce((w,g)=>w+g,0)/(this.frameTimes.length||1));let a=0;performance.memory&&(a=Math.round(performance.memory.usedJSHeapSize/(1024*1024)*10)/10),this.stats={fps:x,renderTimeMs:Math.round(r*100)/100,drawCount:l,visibleCount:i,totalCount:o,memoryUsageMb:a}}getStats(){return{...this.stats}}}new qa;class Ya{constructor(){this.currentTheme="light",this.lightTokens={primary:"#4f46e5",background:"#f8fafc",gridDot:"#cbd5e1",selectionBorder:"#6366f1",selectionHandle:"#4f46e5",textPrimary:"#1e293b",borderDefault:"#e2e8f0",guideLine:"#ec4899"},this.darkTokens={primary:"#6366f1",background:"#0b0f19",gridDot:"#334155",selectionBorder:"#818cf8",selectionHandle:"#6366f1",textPrimary:"#f8fafc",borderDefault:"#1e293b",guideLine:"#f472b6"},this.eyecareTokens={primary:"#2d6a4f",background:"#f2f7f4",gridDot:"#b7d5c5",selectionBorder:"#40916c",selectionHandle:"#2d6a4f",textPrimary:"#143526",borderDefault:"#cce0d6",guideLine:"#10b981"},this.chalkboardTokens={primary:"#4caf50",background:"#0e1713",gridDot:"#2d5242",selectionBorder:"#81c784",selectionHandle:"#4caf50",textPrimary:"#e8f5e9",borderDefault:"#1f382d",guideLine:"#66bb6a"},this.teachingTokens={primary:"#d97706",background:"#fffbeb",gridDot:"#fde68a",selectionBorder:"#f59e0b",selectionHandle:"#d97706",textPrimary:"#78350f",borderDefault:"#fef3c7",guideLine:"#ef4444"},this.customTokens=new Map,this.listeners=new Set}getTokens(){if(this.customTokens.has(this.currentTheme))return this.customTokens.get(this.currentTheme);switch(this.currentTheme){case"dark":return this.darkTokens;case"eyecare":return this.eyecareTokens;case"chalkboard":return this.chalkboardTokens;case"teaching":return this.teachingTokens;default:return this.lightTokens}}setTheme(r){this.currentTheme=r;const l=this.getTokens();this.listeners.forEach(i=>{try{i(l,r)}catch(o){console.error("[ThemeManager] Error in theme change listener:",o)}})}getTheme(){return this.currentTheme}registerCustomTokens(r,l){this.customTokens.set(r,l),this.currentTheme===r&&this.setTheme(r)}unregisterCustomTokens(r){this.customTokens.delete(r),this.currentTheme===r&&this.setTheme("light")}subscribe(r){return this.listeners.add(r),()=>{this.listeners.delete(r)}}}const dn=new Ya;function ut({title:t,icon:r,hidden:l=!1,readOnly:i=!1,isMinimized:o=!1,isMaximized:d=!1,isPropertiesOpen:u=!1,themeColor:x="default",onPointerDown:a,onPointerMove:w,onPointerUp:g,onOpenProperties:D,onMinimize:W,onRestore:k,onMaximize:z,onBrowserFullscreen:m,onDelete:j,extraActions:y}){const f=()=>{switch(x){case"indigo":return"bg-indigo-50/90 dark:bg-indigo-950/60 text-indigo-900 dark:text-indigo-200 border-indigo-200/80 dark:border-indigo-800/60";case"orange":return"bg-orange-50/90 dark:bg-orange-950/60 text-orange-900 dark:text-orange-200 border-orange-200/80 dark:border-orange-800/60";case"purple":return"bg-purple-50/90 dark:bg-purple-950/60 text-purple-900 dark:text-purple-200 border-purple-200/80 dark:border-purple-800/60";case"gray":case"slate":case"default":default:return"bg-surface-secondary/90 text-main border-theme"}};return l?null:e.jsxs("div",{"data-widget-titlebar":"true",className:`px-3 py-1.5 flex justify-between items-center text-xs font-semibold border-b select-none shrink-0 transition-colors ${f()} ${i?"cursor-default":"cursor-move"}`,onPointerDown:a,onPointerMove:w,onPointerUp:g,children:[e.jsxs("div",{className:"flex items-center gap-1.5 min-w-0 mr-2 truncate",children:[r&&e.jsx("span",{className:"shrink-0 opacity-80",children:r}),e.jsx("span",{className:"truncate tracking-tight",children:t}),i&&e.jsx("span",{className:"px-1.5 py-0.5 rounded text-xs bg-amber-100 text-amber-800 dark:bg-amber-950/60 dark:text-amber-300 border border-amber-300 dark:border-amber-700 font-semibold select-none flex items-center gap-0.5 shrink-0",children:"🔒 只读锁定"})]}),!i&&e.jsxs("div",{className:"flex items-center gap-0.5 shrink-0",onPointerDown:T=>T.stopPropagation(),children:[y,D&&e.jsx("button",{type:"button",onClick:D,className:`p-1 rounded-lg transition-all cursor-pointer flex items-center justify-center ${u?"bg-primary-theme text-white shadow-2xs":"text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10"}`,title:"属性配置",children:e.jsx(vn,{size:12})}),W&&e.jsx("button",{type:"button",onClick:W,disabled:o,className:`p-1 rounded-lg transition-all flex items-center justify-center ${o?"opacity-30 cursor-not-allowed text-muted":"text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10 cursor-pointer"}`,title:"最小化组件",children:e.jsx(Yi,{size:12})}),k&&e.jsx("button",{type:"button",onClick:k,className:`p-1 rounded-lg transition-all flex items-center justify-center ${o||d?"text-primary-theme font-bold bg-primary-theme/15 hover:bg-primary-theme/25 cursor-pointer shadow-2xs ring-1 ring-primary-theme/30":"text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10 cursor-pointer"}`,title:"还原组件",children:e.jsx(nr,{size:11,className:o||d?"stroke-[2.5]":""})}),z&&e.jsx("button",{type:"button","data-testid":"widget-titlebar-board-fullscreen",onClick:z,disabled:d,className:`p-1 rounded-lg transition-all flex items-center justify-center ${d?"opacity-30 cursor-not-allowed text-muted":"text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10 cursor-pointer"}`,title:"白板全屏(组件在画布内最大化)",children:e.jsx(Nn,{size:11})}),m&&e.jsx("button",{type:"button","data-testid":"widget-titlebar-browser-fullscreen",onClick:m,className:"p-1 rounded-lg text-muted hover:text-main hover:bg-black/5 dark:hover:bg-white/10 transition-all cursor-pointer flex items-center justify-center",title:"整个浏览器全屏(脱离白板并铺满屏幕,适合投屏)",children:e.jsx(Ji,{size:11})}),j&&e.jsx("button",{type:"button",onClick:j,className:"p-1 rounded-lg text-muted hover:text-rose-600 hover:bg-rose-500/10 transition-all cursor-pointer flex items-center justify-center",title:"删除组件",children:e.jsx(bt,{size:12})})]})]})}const Ja=1e5;function un({children:t,onMaximize:r,onBrowserFullscreen:l,isBrowserFullscreen:i=!1,browserFullscreenDismissible:o=!0,contentClassName:d="flex-1 min-h-0 overflow-auto",...u}){if(i)return e.jsxs("div",{"data-widget-frame":"browser-fullscreen",style:{pointerEvents:"auto"},className:"fixed inset-0 bg-white dark:bg-slate-950 flex flex-col",children:[o&&l&&e.jsxs("button",{type:"button","data-testid":"widget-frame-exit-browser-fullscreen",onClick:l,className:"fixed top-4 right-4 z-[100001] px-3 py-2 rounded-xl bg-slate-900/85 hover:bg-slate-900 text-slate-100 text-xs font-bold flex items-center gap-1.5 shadow-2xl backdrop-blur-md border border-white/15 transition-colors cursor-pointer",title:"退出全屏(Esc)",children:[e.jsx(kn,{size:14}),"退出全屏"]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-auto",children:t})]});const{title:x,icon:a,readOnly:w,isMinimized:g,isMaximized:D,isPropertiesOpen:W,themeColor:k,extraActions:z,...m}=u;return e.jsxs("div",{"data-widget-frame":"true",className:"w-full h-full flex flex-col min-h-0",children:[e.jsx(ut,{title:x,icon:a,readOnly:w,isMinimized:g,isMaximized:D,isPropertiesOpen:W,themeColor:k,extraActions:z,...m,onMaximize:r,onBrowserFullscreen:l}),!g&&e.jsx("div",{className:d,children:t})]})}function xn(){if(typeof document>"u")return!1;const t=document.documentElement;return!!(t.requestFullscreen||t.webkitRequestFullscreen)}function Hs(){return typeof document>"u"?!1:!!(document.fullscreenElement||document.webkitFullscreenElement)}function Ua({elementId:t,enableNativeFullscreen:r=!0,onChange:l}){const i=xn(),[o,d]=n.useState(!1),u=n.useRef(t);u.current=t;const x=n.useRef(l);x.current=l,n.useEffect(()=>()=>{Hs()&&document.exitFullscreen?.()?.catch?.(()=>{})},[]),n.useEffect(()=>{if(typeof document>"u")return;const g=()=>{const D=Hs();d(D),!D&&u.current&&x.current&&x.current(null)};return document.addEventListener("fullscreenchange",g),document.addEventListener("webkitfullscreenchange",g),()=>{document.removeEventListener("fullscreenchange",g),document.removeEventListener("webkitfullscreenchange",g)}},[]);const a=n.useCallback(async g=>{if(x.current?.(g),!!r&&xn())try{const D=document.documentElement;await(D.requestFullscreen?.()??D.webkitRequestFullscreen?.()),d(!0)}catch(D){console.warn("[BrowserFullscreen] native fullscreen rejected:",D)}},[r]),w=n.useCallback(async()=>{if(x.current?.(null),Hs())try{await document.exitFullscreen?.()}catch(g){console.warn("[BrowserFullscreen] exit failed:",g)}d(!1)},[]);return{nativeSupported:i,nativeActive:o,enter:a,exit:w}}function Ga({pluginId:t,slot:r,widgetId:l,elementId:i,lessonId:o,classId:d,studentId:u,studentName:x}){const w=jn(z=>z.extensionPoints).get(r)||[],g=w.find(z=>z.id===l)??w.find(z=>z.pluginId===t&&z.id===l),D=!!g&&typeof g.component=="function"&&g.component!==Pi,W=n.useRef(null);if(n.useEffect(()=>{g&&W.current&&!D&&(W.current.innerHTML="",g.render&&Promise.resolve(g.render(W.current,{elementId:i,lessonId:o})).catch(console.error))},[g,D,t,l,i,o]),!l)return e.jsxs("div",{"data-testid":"plugin-widget-misconfigured",className:"flex h-full flex-col items-center justify-center gap-1 p-3 text-center text-xs text-amber-600",children:[e.jsx(ir,{size:16}),e.jsx("p",{className:"font-bold",children:"挂件未正确配置"}),e.jsxs("p",{className:"text-amber-700/80",children:["缺少 ",r==="teacher.dashboard.widget"?"teacherWidgetId":"studentWidgetId",",请检查插件写入的 payload。"]}),t&&e.jsxs("p",{className:"font-mono text-[10px] text-gray-400",children:["plugin: ",t]})]});if(!g)return e.jsxs("div",{className:"text-center py-6 text-xs text-gray-400 italic flex flex-col justify-center items-center h-full",children:[e.jsx(Ve,{size:16,className:"animate-spin mb-1"}),e.jsxs("span",{children:["组件 [",l,"] 正在加载或未启用..."]})]});if(D)return rr.createElement(g.component,{elementId:i,lessonId:o});const k=g.slotProps?.view||g.view;return k?e.jsx(Di,{pluginId:g.pluginId,view:String(k),label:g.label,slot:r,lessonId:o,classId:d,studentId:u,studentName:x,variant:"panel"}):e.jsx("div",{ref:W,className:"w-full h-full min-h-0"})}function Va({elementId:t,data:r,lessonId:l,classId:i,onElementUpdate:o,onPointerDown:d,onPointerMove:u,onPointerUp:x,onDelete:a,readOnly:w=!1,userRole:g="teacher",isMinimized:D=!1,isMaximized:W=!1,hidden:k=!1,onBrowserFullscreen:z,isPropertiesOpen:m=!1,onOpenProperties:j,onMinimize:y,onRestore:f,onMaximize:T}){const H=Ls(re=>re.classes)||[],Z=Ls(re=>re.onlineStudentIds),J=Ls(re=>re.activeStudentLessons),[O,he]=n.useState(i||r.classId||(H[0]?.id??"")),[K,ue]=n.useState(()=>Array.isArray(r.candidates)&&r.candidates.length>0?r.candidates:Array.isArray(r.allStudents)&&r.allStudents.length>0?r.allStudents:i||r.classId||l?[]:[{id:"mock-s-1",name:"张明",student_number:"101",tier:"basic",term_picked_count:0,lesson_picked_count:0},{id:"mock-s-2",name:"李华",student_number:"102",tier:"intermediate",term_picked_count:1,lesson_picked_count:0},{id:"mock-s-3",name:"王超",student_number:"103",tier:"advanced",term_picked_count:2,lesson_picked_count:0},{id:"mock-s-4",name:"赵丽",student_number:"104",tier:"basic",term_picked_count:0,lesson_picked_count:0},{id:"mock-s-5",name:"钱科",student_number:"105",tier:"intermediate",term_picked_count:1,lesson_picked_count:0},{id:"mock-s-6",name:"孙雪",student_number:"106",tier:"advanced",term_picked_count:3,lesson_picked_count:0}]),[E,te]=n.useState(!!(i||r.classId)),[U,v]=n.useState(r.pickerMode||"fair_all"),[P,C]=n.useState(r.difficulty||"intermediate"),[M,q]=n.useState(r.selectedStudent||null),[X,A]=n.useState(!1),[F,L]=n.useState(null),[p,$]=n.useState(r.evaluation||null),I=n.useMemo(()=>JSON.stringify([r.pickedTime??null,r.selectedStudent?.id??null,r.evaluation?.rating??null,r.evaluation?.submitted??null]),[r.pickedTime,r.selectedStudent,r.evaluation]),G=n.useRef(null),le=n.useRef(r);le.current=r;const se=n.useRef([]),ve=n.useMemo(()=>l?(Z||[]).filter(re=>J?.[re]===l).slice().sort().join("\0"):"",[l,Z,J]);n.useEffect(()=>{r.pickedTime!=null&&G.current!==I&&(G.current=I,q(r.selectedStudent??null),$(r.evaluation??null),A(!1),L(null))},[I,r.pickedTime,r.selectedStudent,r.evaluation]),n.useEffect(()=>{if(!O)return;let re=!0;te(!0);const ge=`/api/classes/${O}/picker-candidates${l?`?lessonId=${encodeURIComponent(l)}`:""}`;return fetch(ge).then(_=>{if(!_.ok)throw new Error("Failed to load class picker candidates");return _.json()}).then(_=>{!re||!Array.isArray(_)||(_.length>0||l)&&ue(_)}).catch(_=>{console.warn("[RollCallWrapper] candidates fallback:",_)}).finally(()=>{re&&te(!1)}),()=>{re=!1}},[O,l,ve]);const Le=n.useMemo(()=>Ei(K,{onlineStudentIds:Z,activeStudentLessons:J,lessonId:l}),[K,Z,J,l]),ze=n.useMemo(()=>{if(U==="fair_all")return Le;const{filtered:re}=_i(Le,P);return re},[Le,U,P]);se.current=ze;const ye=()=>{if(se.current.length===0||X)return;A(!0),$(null);let re=0;const ge=16,b=setInterval(()=>{const V=se.current;if(V.length===0){clearInterval(b),A(!1),L(null);return}const ae=Math.floor(Math.random()*V.length);if(L(V[ae]),re++,re>=ge){clearInterval(b);const Q=se.current;if(Q.length===0){A(!1),L(null);return}const oe=Ri(Q),_e=oe?oe.student:Q[0];q(_e),A(!1),L(null),ue(Ge=>Ge.map(gt=>gt.id===_e.id?{...gt,lesson_picked_count:(gt.lesson_picked_count||0)+1}:gt)),o&&o(t,{...le.current,classId:O,pickerMode:U,difficulty:P,selectedStudent:_e,pickedTime:new Date().toISOString(),status:"picked",evaluation:null}),ce.publish({id:de(),type:"rollcall.picked",source:"rollcall.picker",payload:{elementId:t,studentId:_e.id,studentName:_e.name,classId:O,lessonId:l},timestamp:Date.now()})}},70)},Ce=g==="teacher"||g==="administrator",xt=async re=>{if(!M||p?.submitted)return;const ge=xs[re],_={rating:re,score:ge.score,rewardCoins:ge.rewardCoins,submitted:!0};$(_),ue(b=>b.map(V=>V.id===M.id?{...V,total_reward_coins:(V.total_reward_coins||0)+ge.rewardCoins}:V));try{await fetch("/api/rollcalls/evaluate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:`rollcall-${t}-${M.id}-${Date.now()}`,studentId:M.id,studentName:M.name,classId:O,lessonId:l,rating:re,score:ge.score,rewardCoins:ge.rewardCoins,difficulty:U==="tiered"?P:"intermediate"})})}catch(b){console.error("[RollCallWrapper] evaluate rollcall failed:",b)}o&&o(t,{...le.current,evaluation:_}),ce.publish({id:de(),type:"rollcall.evaluated",source:"rollcall.picker",payload:{elementId:t,studentId:M.id,rating:re,rewardCoins:ge.rewardCoins,score:ge.score},timestamp:Date.now()})};return e.jsxs("div",{className:"w-full h-full bg-gradient-to-br from-indigo-950 via-slate-900 to-indigo-900 border border-indigo-500/50 rounded-xl shadow-2xl overflow-hidden flex flex-col font-sans select-none",style:{pointerEvents:w?"none":"auto"},children:[e.jsx(ut,{title:"随机点名助手 (分层抽问 Fair Picker)",icon:e.jsx(Zt,{size:13,className:"animate-pulse text-amber-400"}),readOnly:w,isMinimized:D,isMaximized:W,hidden:k,onBrowserFullscreen:z,isPropertiesOpen:m,themeColor:"indigo",onPointerDown:d,onPointerMove:u,onPointerUp:x,onOpenProperties:j,onMinimize:y,onRestore:f,onMaximize:T,onDelete:a,extraActions:H.length>1&&Ce?e.jsx("div",{className:"relative mr-1",onPointerDown:re=>re.stopPropagation(),children:e.jsx("select",{value:O,onChange:re=>he(re.target.value),className:"bg-indigo-900/80 text-indigo-100 text-[11px] rounded px-1.5 py-0.5 border border-indigo-700/60 outline-hidden cursor-pointer",children:H.map(re=>e.jsx("option",{value:re.id,className:"bg-slate-900 text-white",children:re.name},re.id))})}):null}),!D&&e.jsxs(e.Fragment,{children:[Ce&&e.jsxs("div",{className:"px-3 py-1.5 bg-indigo-950/40 border-b border-indigo-900/40 flex items-center justify-between gap-2 shrink-0 text-xs",onPointerDown:re=>re.stopPropagation(),children:[e.jsxs("div",{className:"flex items-center gap-1 bg-indigo-900/40 p-0.5 rounded-lg border border-indigo-800/40",children:[e.jsx("button",{onClick:()=>v("fair_all"),className:`px-2 py-0.5 rounded text-xs font-medium transition-all ${U==="fair_all"?"bg-indigo-600 text-white shadow-2xs font-bold":"text-indigo-300 hover:text-white"}`,children:"全员公平"}),e.jsx("button",{onClick:()=>v("tiered"),className:`px-2 py-0.5 rounded text-xs font-medium transition-all ${U==="tiered"?"bg-purple-600 text-white shadow-2xs font-bold":"text-indigo-300 hover:text-white"}`,children:"分层抽问"})]}),U==="tiered"&&e.jsx("div",{className:"flex items-center gap-1",children:["basic","intermediate","advanced"].map(re=>{const ge=re==="basic"?"基础":re==="intermediate"?"进阶":"拔高",_=re==="basic"?"bg-emerald-600 text-white":re==="intermediate"?"bg-blue-600 text-white":"bg-amber-600 text-white";return e.jsx("button",{onClick:()=>C(re),className:`px-1.5 py-0.5 rounded text-xs font-medium transition-all ${P===re?`${_} font-bold shadow-2xs`:"text-indigo-400 hover:text-white"}`,children:ge},re)})})]}),e.jsxs("div",{className:"flex-1 p-3 flex flex-col justify-between min-h-0 text-white gap-2",children:[e.jsx("div",{className:"w-full flex-1 flex flex-col items-center justify-center p-2 rounded-lg bg-indigo-950/50 border border-indigo-900/30 relative overflow-hidden",children:X?e.jsxs("div",{className:"text-center space-y-1.5 animate-pulse",children:[e.jsxs("div",{className:"text-xs text-indigo-300 uppercase tracking-widest font-semibold flex items-center justify-center gap-1.5",children:[e.jsx(Ys,{size:12,className:"animate-spin text-amber-400"}),e.jsx("span",{children:"检索加权公平候选池中..."})]}),e.jsx("div",{className:"text-2xl font-extrabold text-amber-300 scale-105 tracking-wider font-sans",children:F?.name||"..."}),e.jsxs("div",{className:"text-xs text-indigo-400/80 font-mono",children:["学号: ",F?.student_number||"---"]})]}):M?e.jsxs("div",{className:"text-center space-y-1 w-full max-w-[260px]",children:[e.jsxs("div",{className:"text-xs text-indigo-400 uppercase tracking-widest font-semibold flex items-center justify-center gap-1",children:[e.jsx(Cn,{size:12,className:"text-emerald-400"}),e.jsx("span",{children:"抽中的幸运答题者"})]}),e.jsx("div",{className:"text-2xl font-black text-transparent bg-clip-text bg-gradient-to-r from-amber-200 via-yellow-400 to-amber-300 tracking-wider",children:M.name}),e.jsxs("div",{className:"flex items-center justify-center gap-2 text-xs text-indigo-300/80 font-mono",children:[e.jsxs("span",{children:["学号 ",M.student_number||M.id]}),e.jsx("span",{children:"•"}),e.jsxs("span",{children:["已回答 ",M.lesson_picked_count||0," 次"]}),M.total_reward_coins!==void 0&&e.jsxs(e.Fragment,{children:[e.jsx("span",{children:"•"}),e.jsxs("span",{className:"text-amber-400 flex items-center gap-0.5 font-bold",children:[e.jsx(Ui,{size:10}),M.total_reward_coins]})]})]}),e.jsx("div",{className:"mt-2 pt-2 border-t border-indigo-900/50 w-full",onPointerDown:re=>re.stopPropagation(),children:p?.submitted?e.jsxs("div",{className:"bg-indigo-900/60 border border-emerald-500/40 rounded-lg p-1.5 flex items-center justify-center gap-2 text-xs",children:[e.jsx(Gi,{size:14,className:"text-emerald-400"}),e.jsxs("span",{className:"font-bold text-emerald-300",children:["已评定: ",xs[p.rating].badge," ",xs[p.rating].label]}),e.jsxs("span",{className:"text-amber-300 font-bold flex items-center gap-0.5",children:["+",p.rewardCoins," 金币"]})]}):Ce?e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-2xs text-indigo-300/70 text-center font-medium",children:"作答表现评定与激励下发:"}),e.jsx("div",{className:"grid grid-cols-3 gap-1",children:["excellent","good","encourage"].map(re=>{const ge=xs[re];return e.jsxs("button",{onClick:()=>void xt(re),className:"bg-indigo-900/80 hover:bg-indigo-800 border border-indigo-700/60 hover:border-amber-400/80 text-white rounded py-1 px-1 flex flex-col items-center gap-0.5 transition-all active:scale-95 cursor-pointer shadow-3xs group",children:[e.jsx("span",{className:"text-sm group-hover:scale-110 transition-transform",children:ge.badge}),e.jsx("span",{className:"text-2xs font-semibold",children:ge.label}),e.jsxs("span",{className:"text-3xs text-amber-300 font-mono",children:["+",ge.rewardCoins,"币"]})]},re)})})]}):null})]}):ze.length===0&&!E?e.jsxs("div",{className:"text-center space-y-1.5 px-3","data-testid":"rollcall-no-present-students",children:[e.jsx(Js,{size:26,className:"text-amber-300/90 mx-auto"}),e.jsx("div",{className:"text-xs text-amber-200 font-semibold",children:"当前课堂没有在场学生"}),e.jsx("p",{className:"text-2xs text-indigo-200/80 leading-relaxed",children:"只会抽取已经进入本节课的学生。有人离开后不会再被点到,请等学生加入后再开始。"})]}):e.jsxs("div",{className:"text-center space-y-1",children:[e.jsx(Js,{size:26,className:"text-indigo-400/80 mx-auto animate-pulse"}),e.jsx("div",{className:"text-xs text-indigo-300 font-semibold",children:"随机抽取与分层轮盘"}),e.jsx("p",{className:"text-2xs text-indigo-400/60 leading-tight",children:"频次反比加权算法 • 支持基础/进阶/拔高分层抽问"})]})}),e.jsxs("div",{className:"w-full shrink-0 flex flex-col items-center gap-1",onPointerDown:re=>re.stopPropagation(),children:[e.jsxs("button",{onClick:ye,disabled:X||ze.length===0,className:"w-full py-1.5 bg-gradient-to-r from-indigo-500 via-purple-600 to-indigo-600 hover:from-indigo-600 hover:to-purple-700 text-white font-bold text-xs uppercase tracking-wider rounded-lg shadow-md active:scale-98 disabled:opacity-50 transition-all flex items-center justify-center gap-1.5 cursor-pointer",children:[e.jsx(Ys,{size:12,className:X?"animate-spin":""}),e.jsx("span",{children:X?"加权滚轮运转中...":M?"抽取下一位学生":"开始随机点名"})]}),e.jsxs("div",{className:"text-2xs text-indigo-400/60 text-center font-mono flex items-center justify-center gap-1.5",children:[e.jsxs("span",{children:["候选池:",ze.length," 人"]}),e.jsx("span",{children:"•"}),e.jsx("span",{children:U==="fair_all"?"全员公平":`分层: ${P}`}),E&&e.jsx(Et,{size:9,className:"animate-spin text-indigo-400"})]}),!E&&ze.length===0&&M&&e.jsx("p",{className:"text-2xs text-amber-200/90 text-center leading-relaxed","data-testid":"rollcall-no-present-students",children:"当前课堂没有在场学生。只会抽取已经进入本节课的学生,离开后不会再被点到。"})]})]})]})]})}const tr="Pure computation only. No page session, cookies, document, or LMS API.",Ka="openlearn-code-sandbox",Za=["'use strict';","const denied = function sandboxDenied() {"," throw new Error('Credentialed network is disabled in this sandbox');","};","const blocked = ['fetch','XMLHttpRequest','WebSocket','EventSource','importScripts','Worker','SharedWorker','Request','WebTransport'];","for (const name of blocked) {"," try {"," Object.defineProperty(self, name, { configurable: false, enumerable: true, writable: false, value: denied });"," } catch (e) {}"," let obj = Object.getPrototypeOf(self);"," while (obj) {"," if (Object.getOwnPropertyDescriptor(obj, name)) {"," try {"," Object.defineProperty(obj, name, { configurable: false, enumerable: true, writable: false, value: denied });"," } catch (e2) {}"," }"," obj = Object.getPrototypeOf(obj);"," }","}","try { Object.defineProperty(self, 'Function', { configurable: false, writable: false, value: denied }); } catch (e) {}","try { Object.defineProperty(self, 'eval', { configurable: false, writable: false, value: denied }); } catch (e) {}","try {"," Object.defineProperty(Function.prototype, 'constructor', { configurable: false, writable: false, value: denied });","} catch (e) {}","try {"," let nav = self.navigator;"," while (nav) {"," if (Object.getOwnPropertyDescriptor(nav, 'sendBeacon')) {"," try {"," Object.defineProperty(nav, 'sendBeacon', { configurable: false, writable: false, value: denied });"," } catch (e2) {}"," }"," nav = Object.getPrototypeOf(nav);"," }","} catch (e) {}","if (typeof document !== 'undefined' && document) {"," try {"," Object.defineProperty(document, 'cookie', {"," configurable: false,",' get() { return ""; },'," set() {},"," });"," } catch (e) {}","}","const logs = [];","console.log = (...args) => {"," logs.push(args.map((a) => {"," if (typeof a === 'object' && a !== null) {"," try { return JSON.stringify(a); } catch (e) { return String(a); }"," }"," return String(a);"," }).join(' '));","};","(async () => {"," try {"," const value = await (async function () {"].join(`
|
|
2
2
|
`),Qa=[" })();",' if (value !== undefined) logs.push("Return: " + String(value));',' self.postMessage({ source: "openlearn-code-sandbox", success: true, logs: logs.join("\\n") });'," } catch (err) {"," self.postMessage({",' source: "openlearn-code-sandbox",'," success: false,"," error: err && err.message ? err.message : String(err),",' logs: logs.join("\\n"),'," });"," }","})();",""].join(`
|
|
3
3
|
`);function eo(t){return`${Za}
|
|
4
4
|
${t}
|
|
5
5
|
${Qa}`}function to(t){const r=/(^|[^.\w$])import\s*\(/m.test(t),l=/(^|\n)\s*import\s+[\w*{]/m.test(t);return r||l?`Error: ${tr}`:null}function so({elementId:t,data:r,onElementUpdate:l,onPointerDown:i,onPointerMove:o,onPointerUp:d,onDelete:u,readOnly:x=!1,isMinimized:a=!1,isMaximized:w=!1,hidden:g=!1,isPropertiesOpen:D=!1,onOpenProperties:W,onMinimize:k,onRestore:z,onMaximize:m,onBrowserFullscreen:j}){const[y,f]=n.useState(r.code||"console.log('Hello from sandbox!');"),[T,H]=n.useState(""),Z=n.useRef(null);n.useEffect(()=>()=>{const K=Z.current;K&&(K.settled=!0,K.timer!==void 0&&clearTimeout(K.timer),K.worker.terminate(),URL.revokeObjectURL(K.url),Z.current=null)},[]),n.useEffect(()=>{r.code!==void 0&&r.code!==y&&f(r.code)},[r.code]);const J=()=>{const K=Z.current;!K||K.settled||(K.settled=!0,K.timer!==void 0&&clearTimeout(K.timer),K.worker.terminate(),URL.revokeObjectURL(K.url),Z.current=null)},O=()=>{const K=to(y);if(K){J(),H(K);return}J(),H(`Running. ${tr}`);const ue=URL.createObjectURL(new Blob([eo(y)],{type:"application/javascript"}));let E;try{E=new Worker(ue)}catch(v){URL.revokeObjectURL(ue);const P=v instanceof Error?v.message:String(v);H(`Failed to start the sandbox: ${P}`);return}const te={worker:E,url:ue,settled:!1},U=v=>{te.settled||(te.settled=!0,te.timer!==void 0&&clearTimeout(te.timer),E.terminate(),URL.revokeObjectURL(ue),Z.current===te&&(Z.current=null),H(v))};te.timer=setTimeout(()=>{U("Execution timed out (3000ms limit). Worker terminated.")},3e3),Z.current=te,E.onmessage=v=>{const P=v.data;!P||P.source!==Ka||(P.success?U(P.logs||"Code executed successfully (no output)"):U((P.logs?P.logs+`
|
|
6
|
-
`:"")+"Error: "+(P.error||"unknown error")))},E.onerror=v=>{U(`Worker Error: ${v.message||"unknown error"}`)}},he=()=>{l&&y!==r.code&&l(t,{...r,code:y})};return e.jsxs("div",{className:"w-full h-full bg-gray-900 border border-gray-700 rounded-lg shadow-xl overflow-hidden flex flex-col font-mono text-sm",style:{pointerEvents:x?"none":"auto"},children:[e.jsx(ut,{title:r.title||"JS Sandbox",icon:e.jsx(
|
|
6
|
+
`:"")+"Error: "+(P.error||"unknown error")))},E.onerror=v=>{U(`Worker Error: ${v.message||"unknown error"}`)}},he=()=>{l&&y!==r.code&&l(t,{...r,code:y})};return e.jsxs("div",{className:"w-full h-full bg-gray-900 border border-gray-700 rounded-lg shadow-xl overflow-hidden flex flex-col font-mono text-sm",style:{pointerEvents:x?"none":"auto"},children:[e.jsx(ut,{title:r.title||"JS Sandbox",icon:e.jsx(Sn,{size:13,className:"text-emerald-500"}),readOnly:x,isMinimized:a,isMaximized:w,hidden:g,isPropertiesOpen:D,themeColor:"default",onPointerDown:i,onPointerMove:o,onPointerUp:d,onOpenProperties:W,onMinimize:k,onRestore:z,onMaximize:m,onBrowserFullscreen:j,onDelete:u,extraActions:x?null:e.jsx("button",{type:"button",onClick:O,onPointerDown:K=>K.stopPropagation(),className:"bg-emerald-600 hover:bg-emerald-500 text-white px-2 py-0.5 rounded shadow text-xs cursor-pointer font-sans mr-1",children:"Run"})}),!a&&e.jsxs(e.Fragment,{children:[e.jsx("p",{"data-testid":"code-sandbox-description",className:"px-3 py-1 text-[10px] leading-snug text-amber-200/90 bg-gray-950 border-b border-gray-800 shrink-0",children:tr}),e.jsx("textarea",{value:y,onChange:K=>f(K.target.value),onBlur:he,className:"w-full flex-1 min-h-0 bg-gray-900 text-green-400 p-3 focus:outline-none resize-none font-mono text-xs",placeholder:"// Write JS here",onPointerDown:K=>{K.stopPropagation()},onKeyDown:K=>{K.stopPropagation()}}),T&&e.jsx("div",{className:"bg-black text-gray-400 p-2 border-t border-gray-800 h-24 overflow-y-auto whitespace-pre-wrap text-xs shrink-0",children:T})]})]})}function ro(t,r){const l=(t||"").trim();if(!l)return NaN;if(/[;={}\[\]'"`\\&|<>?!]|constructor|prototype|__proto__|window|document|fetch|eval|import|require|process/i.test(l))throw new Error("表达式包含不安全字符");const o=l.replace(/Math\./gi,"").toLowerCase(),d=[];let u=0;for(;u<o.length;){const y=o[u];if(/\s/.test(y)){u++;continue}if(/[0-9.]/.test(y)){let f="";for(;u<o.length&&/[0-9.]/.test(o[u]);)f+=o[u++];d.push(f);continue}if(/[a-z]/.test(y)){let f="";for(;u<o.length&&/[a-z]/.test(o[u]);)f+=o[u++];d.push(f);continue}if("+-*/^%()".includes(y)){d.push(y),u++;continue}throw new Error(`不支持的符号: ${y}`)}let x=0;const a=()=>d[x],w=y=>{const f=d[x++];if(y&&f!==y)throw new Error(`预期 '${y}',但得到 '${f}'`);return f},g=()=>D(),D=()=>{let y=W();for(;a()==="+"||a()==="-";){const f=w(),T=W();y=f==="+"?y+T:y-T}return y},W=()=>{let y=k();for(;a()==="*"||a()==="/"||a()==="%";){const f=w(),T=k();f==="*"?y*=T:f==="/"?y=T===0?NaN:y/T:y%=T}return y},k=()=>{let y=z();for(;a()==="^";){w();const f=k();y=Math.pow(y,f)}return y},z=()=>a()==="-"?(w(),-z()):a()==="+"?(w(),z()):m(),m=()=>{const y=a();if(!y)throw new Error("意外的表达式结尾");if(y==="("){w("(");const T=g();return w(")"),T}if(/^[0-9.]+$/.test(y))return w(),parseFloat(y);if(y==="x")return w(),r;if(y==="pi")return w(),Math.PI;if(y==="e")return w(),Math.E;const f=w();if(a()==="("){w("(");const T=g();switch(w(")"),f){case"sin":return Math.sin(T);case"cos":return Math.cos(T);case"tan":return Math.tan(T);case"sqrt":return Math.sqrt(T);case"abs":return Math.abs(T);case"log":return Math.log(T);case"exp":return Math.exp(T);case"round":return Math.round(T);case"floor":return Math.floor(T);case"ceil":return Math.ceil(T);default:throw new Error(`未知的数学函数: ${f}`)}}throw new Error(`未知的数学标识符: ${y}`)},j=g();if(x<d.length)throw new Error(`多余语法: ${d.slice(x).join(" ")}`);return j}function no({elementId:t,data:r,onElementUpdate:l,onPointerDown:i,onPointerMove:o,onPointerUp:d,onDelete:u,readOnly:x=!1,isMinimized:a=!1,isMaximized:w=!1,hidden:g=!1,isPropertiesOpen:D=!1,onOpenProperties:W,onMinimize:k,onRestore:z,onMaximize:m,onBrowserFullscreen:j}){const[y,f]=n.useState(r.equation||"sin(x)"),[T,H]=n.useState(""),[Z,J]=n.useState(""),[O,he]=n.useState({width:400,height:300}),K=n.useRef(null);n.useEffect(()=>{r.equation!==void 0&&r.equation!==y&&f(r.equation)},[r.equation]),n.useEffect(()=>{if(!K.current)return;const E=new ResizeObserver(te=>{for(const U of te)he({width:U.contentRect.width||400,height:U.contentRect.height||300})});return E.observe(K.current),()=>E.disconnect()},[]),n.useEffect(()=>{try{const E=[],te=O.width/2,U=O.height/2;for(let v=-10;v<=10;v+=.2){const P=v,C=ro(y,P);if(typeof C!="number"||isNaN(C))continue;const M=te+P*20,q=U-C*20;E.push(`${M},${q}`)}H(E.join(" ")),J("")}catch(E){J(E.message)}},[y,O]);const ue=()=>{l&&y!==r.equation&&l(t,{...r,equation:y})};return e.jsxs("div",{className:"w-full h-full bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-mono text-sm",style:{pointerEvents:x?"none":"auto"},children:[e.jsx(ut,{title:r.title||"Math Graph Sandbox",icon:e.jsx(zn,{size:13,className:"text-indigo-500"}),readOnly:x,isMinimized:a,isMaximized:w,hidden:g,isPropertiesOpen:D,themeColor:"default",onPointerDown:i,onPointerMove:o,onPointerUp:d,onOpenProperties:W,onMinimize:k,onRestore:z,onMaximize:m,onBrowserFullscreen:j,onDelete:u}),!a&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"p-3 border-b border-gray-200 flex-none flex flex-col gap-1",children:[e.jsx("span",{className:"text-gray-500 text-xs",children:"y = f(x)"}),e.jsx("input",{type:"text",value:y,disabled:x,onChange:E=>f(E.target.value),onBlur:ue,className:"w-full border border-gray-300 rounded px-2 py-1 focus:outline-none focus:border-indigo-500 font-mono text-xs disabled:bg-gray-100 disabled:cursor-not-allowed",placeholder:"e.g. Math.sin(x) * x",onPointerDown:E=>E.stopPropagation(),onKeyDown:E=>E.stopPropagation()}),Z&&e.jsx("div",{className:"text-red-500 text-xs mt-1",children:Z})]}),e.jsx("div",{className:"flex-1 relative overflow-hidden bg-white min-h-0",ref:K,children:e.jsxs("svg",{width:O.width,height:O.height,viewBox:`0 0 ${O.width} ${O.height}`,className:"absolute top-0 left-0",children:[e.jsx("line",{x1:O.width/2,y1:"0",x2:O.width/2,y2:O.height,stroke:"#e5e7eb",strokeWidth:"1"}),e.jsx("line",{x1:"0",y1:O.height/2,x2:O.width,y2:O.height/2,stroke:"#e5e7eb",strokeWidth:"1"}),T&&e.jsx("polyline",{points:T,fill:"none",stroke:"#6366f1",strokeWidth:"2",strokeLinejoin:"round"})]})})]})]})}function io({elementId:t,data:r,onElementUpdate:l,onPointerDown:i,onPointerMove:o,onPointerUp:d,onDelete:u,lessonId:x,readOnly:a=!1,isMinimized:w=!1,isMaximized:g=!1,hidden:D=!1,onBrowserFullscreen:W,isPropertiesOpen:k=!1,onOpenProperties:z,onMinimize:m,onRestore:j,onMaximize:y}){const[f,T]=n.useState(!1),H=async()=>{T(!0);try{await fetch("/api/commands",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({commandType:"hello.say",payload:{lessonId:x,username:"World",shout:!0}})})}catch(Z){console.error("Failed to trigger hello.say command:",Z)}finally{T(!1)}};return e.jsxs("div",{className:"w-full h-full bg-white border border-slate-200/80 rounded-xl shadow-lg overflow-hidden flex flex-col font-sans select-none",style:{pointerEvents:a?"none":"auto"},children:[e.jsx(ut,{title:"Hello World 插件",icon:e.jsx(Zt,{size:11,className:"text-amber-500 animate-pulse"}),readOnly:a,isMinimized:w,isMaximized:g,hidden:D,onBrowserFullscreen:W,isPropertiesOpen:k,themeColor:"slate",onPointerDown:i,onPointerMove:o,onPointerUp:d,onOpenProperties:z,onMinimize:m,onRestore:j,onMaximize:y,onDelete:u}),!w&&e.jsx("div",{className:"flex-1 p-2 flex items-center justify-center bg-slate-50/20",children:e.jsxs("button",{onClick:H,disabled:f,onPointerDown:Z=>Z.stopPropagation(),className:"w-full py-1 bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-650 hover:to-purple-750 text-white font-bold text-xs rounded-lg shadow-sm active:scale-95 transition-all flex items-center justify-center gap-1 cursor-pointer",children:[e.jsx(ar,{size:11,className:f?"animate-spin":""}),e.jsx("span",{children:f?"输出中...":"点击输出"})]})})]})}let hs=null;const ao=10;async function oo(){if(hs!=null)return hs;try{const t=await fetch("/api/site-settings");if(t.ok){const r=await t.json();typeof r.uploadMaxFileMb=="number"&&r.uploadMaxFileMb>0&&(hs=r.uploadMaxFileMb)}}catch{}return hs??ao}const lo={hiddenPanels:["inspector"]},co=[{code:"en",label:"English",nativeLabel:"English"},{code:"fr",label:"French",nativeLabel:"Français"},{code:"es",label:"Spanish",nativeLabel:"Español"},{code:"de",label:"German",nativeLabel:"Deutsch"},{code:"zh-CN",label:"Chinese (Simplified)",nativeLabel:"简体中文"}];ln.isInitialized||ln.use(fa).init({resources:{en:{translation:cn},"zh-CN":{translation:cn}},lng:"zh-CN",fallbackLng:"en",keySeparator:!1,nsSeparator:!1,interpolation:{escapeValue:!1},parseMissingKeyHandler:t=>pa(t)});function uo({elementId:t,data:r,userRole:l="teacher",onElementUpdate:i}){const[o,d]=n.useState("ppt"),[u,x]=n.useState(r.markdown||`# Title Slide
|
|
7
7
|
---
|
|
8
8
|
## Slide 2`),[a,w]=n.useState(r.slideX||0),[g,D]=n.useState(!1),[W,k]=n.useState(4),[z,m]=n.useState(!1),j=n.useRef(null),y=l==="teacher",f=l==="student",T=r.fileUrl||"",H=r.fileType||"md",Z=r.fileName||"",J=!!T,[O,he]=n.useState(!1),K=n.useRef(null),[ue,E]=n.useState(null),[te,U]=n.useState(!1),[v,P]=n.useState(null),C=n.useRef(null),M=n.useRef(null),q=!!r.isFullscreenSynced,X=!!r.isFullscreenForced,A=z||f&&q&&X,F=u.split(/(?:\r?\n|^)---(?:\r?\n|$)/).map(_=>_.trim()).filter(_=>_.length>0),L=H==="md"?Math.max(1,F.length):r.slideCount||1;n.useEffect(()=>{H!=="md"&&o!=="ppt"&&d("ppt")},[H,o]),n.useEffect(()=>{r.slideX!==void 0&&r.slideX!==a&&w(r.slideX)},[r.slideX]),n.useEffect(()=>{r.markdown!==void 0&&r.markdown!==u&&x(r.markdown)},[r.markdown]);const p=_=>(U(!0),P(null),fetch(_).then(b=>{if(!b.ok)throw new Error(`无法获取课件文件 (HTTP ${b.status})`);return b.arrayBuffer()}).then(b=>{E(new Uint8Array(b)),U(!1)}).catch(b=>{console.error("[RevealPresentationWrapper] Fetch PPTX failed:",b),P(b.message||"课件文件加载失败"),U(!1)}));n.useEffect(()=>{if(H!=="pptx"||!T){E(null),U(!1),P(null);return}let _=!0;return U(!0),P(null),fetch(T).then(b=>{if(!b.ok)throw new Error(`无法获取课件文件 (HTTP ${b.status})`);return b.arrayBuffer()}).then(b=>{_&&(E(new Uint8Array(b)),U(!1))}).catch(b=>{_&&(console.error("[RevealPresentationWrapper] Fetch PPTX failed:",b),P(b.message||"课件文件加载失败"),U(!1))}),()=>{_=!1}},[T,H]),n.useEffect(()=>{if(H==="pptx"){const _=A?M.current:C.current;if(_)try{const b=_.getActiveSlideIndex?.();b!==void 0&&b!==a&&_.setActiveSlideIndex?.(a)}catch(b){console.warn("[RevealPresentationWrapper] Failed to sync PPTX slide index:",b)}}},[a,H,A]);const $=n.useCallback(_=>{_!==a&&(w(_),y&&i&&i(t,{...r,slideX:_}))},[a,y,i,t,r]),I=n.useCallback(_=>{_>0&&y&&i&&r.slideCount!==_&&i(t,{...r,slideCount:_})},[y,i,r,t]),G=_=>te?e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center text-slate-500 gap-3 bg-slate-50 rounded-xl",children:[e.jsx(Ve,{className:"w-8 h-8 animate-spin text-indigo-600"}),e.jsx("span",{className:"text-sm font-medium",children:"正在解析 PPTX 课件..."})]}):v?e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center text-rose-500 gap-2 p-6 text-center bg-slate-50 rounded-xl",children:[e.jsx(Dt,{className:"w-8 h-8"}),e.jsx("p",{className:"text-sm font-medium",children:v}),e.jsx("button",{onClick:()=>{T&&p(T)},className:"mt-2 px-3 py-1 text-xs bg-white border border-slate-200 hover:bg-slate-100 text-slate-700 rounded-md shadow-sm transition-colors",children:"重试加载"})]}):ue?e.jsx("div",{className:"w-full h-full overflow-hidden rounded-xl bg-white border border-slate-100 shadow-md",children:e.jsx(ma,{ref:_?M:C,content:ue,fileName:Z||"课件演示.pptx",canEdit:!1,showToolbar:!1,showThumbnails:_,showCompatibilityToasts:!1,customization:lo,initialSlide:a,defaultLocale:"zh-CN",availableLocales:co,onActiveSlideChange:$,onSlideCountChange:I,className:"w-full h-full"},`${T}-${_?"fs":"card"}`)}):e.jsx("div",{className:"w-full h-full flex items-center justify-center text-slate-400 text-sm bg-slate-50 rounded-xl",children:"课件内容未就绪"});n.useEffect(()=>{if(!g||o!=="ppt"||H!=="md")return;const _=setInterval(()=>{w(b=>{const V=(b+1)%Math.max(1,F.length);return i&&i(t,{...r,slideX:V}),V})},W*1e3);return()=>clearInterval(_)},[g,W,F.length,o,H]),n.useEffect(()=>{const _=b=>{f&&q&&X||(b.key==="ArrowRight"||b.key===" "?(b.preventDefault(),le(a+1)):b.key==="ArrowLeft"?(b.preventDefault(),le(a-1)):b.key==="Escape"&&A&&(b.preventDefault(),ze(!1)))};return window.addEventListener("keydown",_),()=>window.removeEventListener("keydown",_)},[a,A,f,q,X,L]);const le=_=>{if(f&&q&&X)return;const b=Math.min(Math.max(0,_),L-1);w(b),y&&i&&i(t,{...r,slideX:b})},se=_=>{x(_),i&&i(t,{...r,markdown:_})},ve=async _=>{const b=_.target.files?.[0];if(!b)return;const V=b.name.split(".").pop()?.toLowerCase();if(V!=="pdf"&&V!=="pptx"){alert("仅支持上传 PDF 或 PPTX 格式的课件文件!");return}he(!0);try{const ae=await oo();if(b.size>ae*1024*1024){alert(`课件文件超过 ${ae}MB 上限,请压缩后再上传(上限可在管理后台 → 站点设置调整)。`);return}const oe=(await new Promise((gt,Wt)=>{const Ht=new FileReader;Ht.onload=ss=>gt(ss.target?.result??""),Ht.onerror=()=>Wt(new Error("本地文件读取失败")),Ht.readAsDataURL(b)})).split(",")[1],_e=await fetch("/api/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filename:b.name,base64Data:oe})}),Ge=await _e.json().catch(()=>({}));if(!_e.ok)throw _e.status===413?new Error("课件文件过大,超过服务器上传上限(10MB)。"):new Error(Ge.error||`上传失败(HTTP ${_e.status})`);i&&(await i(t,{...r,fileUrl:Ge.fileUrl,fileName:b.name,fileType:Ge.fileType,slideX:0,slideCount:Ge.slideCount||1,isFullscreenSynced:r.isFullscreenSynced!==void 0?r.isFullscreenSynced:!0,isFullscreenForced:!1}),w(0))}catch(ae){console.error("[RevealPresentation] upload failed:",ae),alert(ae?.message||"课件文件上传失败,请重试")}finally{he(!1)}},Le=()=>{window.confirm("确定要清除已上传的课件并恢复为 Markdown 编辑模式吗?")&&i&&(i(t,{...r,fileUrl:"",fileName:"",fileType:"md",slideX:0,slideCount:0,isFullscreenForced:!1}),w(0))},ze=_=>{m(_),y&&i&&i(t,{...r,isFullscreenForced:_})},ye=_=>{i&&i(t,{...r,isFullscreenSynced:_,isFullscreenForced:_?z:!1})},Ce=[{name:"基础通用课件",desc:"标准的课件 structure",content:`# 物理学原理与探究
|
|
9
9
|
---
|
|
@@ -49,17 +49,17 @@ The teacher used the virtual whiteboard to ___ classroom active learning slides.
|
|
|
49
49
|
|
|
50
50
|
## 问题思考
|
|
51
51
|
当马拉着车在水平路面上加速前进时,马拉车的力与车拉马的力,哪一个更大?`}],re=(()=>{const _=u.split(`
|
|
52
|
-
`),b=[];return _.forEach((V,ae)=>{const Q=V.match(/^(#{1,3})\s+(.*)$/);Q&&b.push({text:Q[2].trim(),level:Q[1].length,lineIndex:ae})}),b})();if(H==="file"&&J){const _=(Z.split(".").pop()||"file").toLowerCase();return e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center gap-3 p-5 bg-gradient-to-br from-slate-50 to-white border border-slate-200 rounded-xl","data-testid":"course-package-file-card",children:[e.jsx("div",{className:"w-12 h-12 rounded-xl bg-indigo-50 border border-indigo-100 flex items-center justify-center",children:e.jsx(nn,{size:22,className:"text-indigo-600"})}),e.jsxs("div",{className:"text-center max-w-full",children:[e.jsx("p",{className:"text-sm font-bold text-slate-800 truncate",title:Z||T,children:Z||"课程附件"}),e.jsx("p",{className:"text-[11px] text-slate-400 mt-0.5 font-mono uppercase",children:_})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("a",{href:T,download:Z||void 0,"data-testid":"course-package-file-download",className:"flex items-center gap-1.5 px-3 py-1.5 text-xs font-bold text-white bg-indigo-600 hover:bg-indigo-700 rounded-lg transition-colors",onClick:b=>b.stopPropagation(),children:[e.jsx(nn,{size:13}),"下载附件"]}),y&&i&&e.jsx("button",{onClick:b=>{b.stopPropagation(),window.confirm("确定要移除此附件引用吗?(不会删除已上传的文件)")&&i(t,{...r,fileUrl:"",fileName:"",fileType:"md",slideCount:0})},"data-testid":"course-package-file-clear",className:"px-3 py-1.5 text-xs font-bold text-slate-600 bg-white border border-slate-200 hover:bg-slate-50 rounded-lg transition-colors",children:"移除引用"})]}),e.jsx("p",{className:"text-[10px] text-slate-400 text-center leading-relaxed max-w-[240px]",children:"该类型没有白板内联渲染器,以附件形式提供下载。"})]})}if(A&&typeof document<"u")return e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center bg-slate-900/10 text-slate-400 font-sans p-4",children:[e.jsxs("div",{className:"flex flex-col items-center gap-2",children:[e.jsx(gs,{size:24,className:"text-indigo-500 animate-pulse"}),e.jsx("span",{className:"text-xs",children:"演示文稿正在全屏放映中"})]}),bn.createPortal(e.jsxs("div",{className:"fixed inset-0 z-[99999] bg-neutral-950 flex flex-col items-center justify-center font-sans p-6",children:[e.jsxs("div",{className:"absolute top-4 left-4 right-4 flex items-center justify-between text-white/80 select-none z-[100001] px-4 py-2 bg-neutral-900/60 backdrop-blur-md rounded-xl border border-neutral-800",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full bg-emerald-500 animate-pulse"}),e.jsxs("span",{className:"font-bold text-xs tracking-wider uppercase",children:[H==="md"?"Markdown Slides":`${H.toUpperCase()} Presentation`," ",f&&"(Synced)"]})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("span",{className:"text-xs font-mono text-white/50",children:["Slide ",a+1," / ",L]}),y&&e.jsxs(e.Fragment,{children:[H==="md"&&e.jsx("button",{onClick:()=>D(_=>!_),className:`px-2.5 py-1 rounded-md text-xs uppercase font-bold tracking-wider transition-colors border cursor-pointer ${g?"bg-emerald-50 border-emerald-400 text-white animate-pulse":"bg-transparent border-neutral-700 text-neutral-400 hover:bg-neutral-850"}`,children:g?"Autoplay Live":"Autoplay"}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-white/70 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:q,onChange:_=>ye(_.target.checked),className:"rounded border-neutral-700 bg-neutral-800 text-indigo-500 focus:ring-0 focus:ring-offset-0 cursor-pointer"}),e.jsx("span",{children:"同步学生全屏"})]})]}),(!f||!X||!q||z)&&e.jsx("button",{onClick:()=>ze(!1),className:"p-1 px-2.5 bg-red-600 text-white text-xs font-bold rounded-lg transition-colors cursor-pointer border-0 hover:bg-red-700",title:"退出放映",children:"退出放映 (Esc)"})]})]}),e.jsx("div",{className:"w-full flex-1 min-h-0 flex items-center justify-center relative",children:H==="pdf"?e.jsx("div",{className:"w-full h-full flex items-center justify-center p-2 bg-slate-100 max-w-[90vw] max-h-[82vh] aspect-video rounded-2xl overflow-hidden shadow-2xl border border-neutral-850",children:e.jsx("iframe",{src:`${T}#page=${a+1}&toolbar=0&navpanes=0`,className:"w-full h-full border-0 rounded-xl"},`${T}-fs-${a}`)}):H==="pptx"?e.jsx("div",{className:"w-full h-full flex items-center justify-center p-2 bg-slate-900/5 max-w-[90vw] max-h-[82vh] aspect-video rounded-2xl overflow-hidden shadow-2xl border border-neutral-850",children:G(!0)}):e.jsx("div",{className:"flex-1 w-full flex items-center justify-center max-w-[90vw] min-h-0",children:e.jsxs("div",{className:"w-full bg-white rounded-xl shadow-md border border-slate-100 flex flex-col overflow-y-auto p-6 md:p-8 aspect-video relative transition-all duration-300 hover:shadow-lg max-h-[82vh] max-w-none p-12 md:p-16 border-neutral-850 rounded-3xl shadow-2xl",children:[e.jsxs("div",{className:"flex justify-between items-center text-xs font-semibold text-slate-400 border-b border-slate-100 pb-2 mb-4 shrink-0",children:[e.jsx("span",{className:"tracking-wide uppercase text-indigo-650",children:"SMART CLASS SLIDE DECK"}),e.jsxs("span",{className:"font-mono",children:["SLIDE ",a+1," / ",L]})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto pr-1",children:e.jsx("div",{className:"markdown-body text-slate-800 leading-relaxed font-sans prose prose-neutral max-w-none text-xs",children:F[a]?e.jsx(sn,{children:F[a]}):e.jsx("div",{className:"text-center text-slate-400 italic py-8",children:"幻灯片没有内容,请在“编辑文档”中添加。"})})}),e.jsxs("div",{className:"mt-4 pt-2 border-t border-slate-50 flex items-center justify-between text-xs text-slate-400 shrink-0 font-sans",children:[e.jsx("span",{children:"智慧互动教室白板演示系统"}),e.jsxs("span",{children:["Page ",a+1]})]})]})})}),!(f&&q&&X)&&e.jsxs("div",{className:"absolute bottom-6 bg-neutral-900/80 backdrop-blur-md px-6 py-2.5 rounded-full border border-neutral-800 shadow-2xl z-[100001]",children:[e.jsx("button",{disabled:a===0||f,onClick:()=>le(a-1),className:`p-1.5 rounded-full border transition-colors cursor-pointer ${a===0||f?"border-neutral-800 text-neutral-600 bg-neutral-950/20 cursor-not-allowed":"border-neutral-700 text-neutral-300 hover:bg-neutral-800"}`,title:"上一张 (ArrowLeft)",children:e.jsx(Vt,{size:18})}),e.jsxs("div",{className:"flex items-center gap-1.5 px-1 font-mono text-xs text-neutral-200",children:[e.jsx("span",{className:"font-bold text-white text-base",children:a+1}),e.jsx("span",{className:"text-neutral-600",children:"/"}),e.jsx("span",{children:L})]}),e.jsx("button",{disabled:a>=L-1||f,onClick:()=>le(a+1),className:`p-1.5 rounded-full border transition-colors cursor-pointer ${a>=L-1||f?"border-neutral-800 text-neutral-600 bg-neutral-950/20 cursor-not-allowed":"border-neutral-700 text-neutral-300 hover:bg-neutral-800"}`,title:"下一张 (ArrowRight)",children:e.jsx(Kt,{size:18})})]})]}),document.body)]});const ge=A?"fixed inset-0 z-[99999] bg-neutral-950 flex flex-col items-center justify-center font-sans p-6":"flex-1 flex flex-col items-center justify-between p-4 bg-slate-900/5 relative min-w-0";return e.jsxs("div",{className:"w-full h-full flex flex-col bg-slate-50 text-slate-800 overflow-hidden text-xs relative font-sans",children:[!A&&e.jsxs("div",{className:"flex items-center justify-between px-3 py-1.5 bg-slate-100 border-b border-slate-200 shrink-0 select-none relative z-10",children:[e.jsx("div",{className:"flex items-center gap-1",children:H==="md"?e.jsxs(e.Fragment,{children:[e.jsxs("button",{onClick:()=>d("ppt"),className:`px-2 py-1 rounded flex items-center gap-1 font-medium transition-colors cursor-pointer ${o==="ppt"?"bg-indigo-600 text-white shadow-sm":"text-slate-600 hover:bg-slate-200"}`,title:"播放课件幻灯片 (PPT Mode)",children:[e.jsx(Vi,{size:11}),e.jsx("span",{children:"PPT 播放"})]}),e.jsxs("button",{onClick:()=>d("doc"),className:`px-2 py-1 rounded flex items-center gap-1 font-medium transition-colors cursor-pointer ${o==="doc"?"bg-indigo-600 text-white shadow-sm":"text-slate-600 hover:bg-slate-200"}`,title:"以精美文档形式阅读 (Markdown Document mode)",children:[e.jsx(Ki,{size:11}),e.jsx("span",{children:"文档阅读"})]}),e.jsxs("button",{onClick:()=>d("edit"),className:`px-2 py-1 rounded flex items-center gap-1 font-medium transition-colors cursor-pointer ${o==="edit"?"bg-indigo-600 text-white shadow-sm":"text-slate-600 hover:bg-slate-200"}`,title:"在线编辑 Markdown 内容",children:[e.jsx(Us,{size:11}),e.jsx("span",{children:"编辑文档"})]})]}):e.jsxs("div",{className:"flex items-center gap-1 bg-indigo-50 border border-indigo-200/50 text-indigo-700 px-2 py-0.5 rounded text-xs font-semibold",children:[e.jsx(gs,{size:10}),e.jsxs("span",{children:[H.toUpperCase()," 课件演示中"]})]})}),e.jsxs("div",{className:"flex items-center gap-3",children:[y&&e.jsx("div",{className:"flex items-center gap-1.5 border-r border-slate-200 pr-3",children:O?e.jsxs("div",{className:"flex items-center gap-1 text-xs text-slate-500 font-medium",children:[e.jsx(Ve,{size:10,className:"animate-spin"}),e.jsx("span",{children:"上传解析中..."})]}):J?e.jsxs("div",{className:"flex items-center gap-1.5 bg-slate-200/50 pl-2 pr-1.5 py-0.5 rounded border border-slate-300/30",children:[e.jsx("span",{className:"text-xs font-medium text-slate-600 max-w-[120px] truncate font-mono",title:Z,children:Z}),e.jsx("button",{onClick:Le,className:"p-0.5 hover:bg-slate-300 rounded text-red-500 cursor-pointer border-0 bg-transparent",title:"清除并切换回 Markdown",children:e.jsx(bt,{size:10})})]}):e.jsxs("div",{children:[e.jsxs("button",{onClick:()=>K.current?.click(),className:"px-2 py-1 rounded bg-indigo-50 border border-indigo-200 text-indigo-700 hover:bg-indigo-100 flex items-center gap-1 font-semibold text-xs cursor-pointer",title:"上传 PPTX 或 PDF 课件",children:[e.jsx(ys,{size:10}),e.jsx("span",{children:"上传课件"})]}),e.jsx("input",{type:"file",ref:K,onChange:ve,accept:".pdf,.pptx",className:"hidden"})]})}),o==="ppt"&&H==="md"&&e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("button",{onClick:()=>D(_=>!_),className:`p-1 rounded flex items-center gap-1 font-semibold text-xs transition-colors border cursor-pointer ${g?"bg-emerald-50 border-emerald-300 text-emerald-700":"bg-white border-slate-200 text-slate-500 hover:bg-slate-50"}`,title:"开启/关闭幻灯片自动播放",children:[g?e.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-emerald-500 animate-ping"}):null,e.jsx("span",{children:g?"自动播放中":"自动播放"})]}),g&&e.jsxs("select",{value:W,onChange:_=>k(Number(_.target.value)),className:"bg-white border border-slate-200 rounded px-1 text-xs py-0.5 text-slate-700 font-medium",children:[e.jsx("option",{value:2,children:"2秒"}),e.jsx("option",{value:4,children:"4秒"}),e.jsx("option",{value:6,children:"6秒"}),e.jsx("option",{value:10,children:"10秒"})]})]}),y&&o==="ppt"&&e.jsxs("label",{className:"flex items-center gap-1 text-xs text-slate-500 font-medium cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:q,onChange:_=>ye(_.target.checked),className:"rounded border-slate-300 text-indigo-650 focus:ring-0 focus:ring-offset-0 cursor-pointer"}),e.jsx("span",{children:"同步学生全屏"})]}),o==="ppt"&&(!f||!(q&&X))&&e.jsx("button",{onClick:()=>ze(!0),className:"p-1 rounded-lg text-slate-655 hover:bg-slate-200 border border-slate-200 bg-white transition-colors cursor-pointer",title:"全屏放映",children:e.jsx(vn,{size:11})})]})]}),e.jsxs("div",{className:"flex-1 min-h-0 relative flex flex-row overflow-hidden",children:[o==="ppt"&&e.jsxs("div",{className:ge,children:[A&&e.jsxs("div",{className:"absolute top-4 left-4 right-4 flex items-center justify-between text-white/80 select-none z-[100001] px-4 py-2 bg-neutral-900/60 backdrop-blur-md rounded-xl border border-neutral-800",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full bg-emerald-500 animate-pulse"}),e.jsxs("span",{className:"font-bold text-xs tracking-wider uppercase",children:[H==="md"?"Markdown Slides":`${H.toUpperCase()} Presentation`," ",f&&"(Synced)"]})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("span",{className:"text-xs font-mono text-white/50",children:["Slide ",a+1," / ",L]}),y&&e.jsxs(e.Fragment,{children:[H==="md"&&e.jsx("button",{onClick:()=>D(_=>!_),className:`px-2.5 py-1 rounded-md text-xs uppercase font-bold tracking-wider transition-colors border cursor-pointer ${g?"bg-emerald-50 border-emerald-400 text-white animate-pulse":"bg-transparent border-neutral-700 text-neutral-400 hover:bg-neutral-850"}`,children:g?"Autoplay Live":"Autoplay"}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-white/70 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:q,onChange:_=>ye(_.target.checked),className:"rounded border-neutral-700 bg-neutral-800 text-indigo-500 focus:ring-0 focus:ring-offset-0 cursor-pointer"}),e.jsx("span",{children:"同步学生全屏"})]}),e.jsx("button",{onClick:()=>ze(!1),className:"p-1 px-2.5 bg-red-655 text-white text-xs font-bold rounded-md transition-colors cursor-pointer border-0",title:"退出放映",children:"退出放映 (Esc)"})]})]})]}),e.jsx("div",{className:"w-full flex-1 min-h-0 flex items-center justify-center relative",children:H==="pdf"?e.jsx("div",{className:`w-full h-full flex items-center justify-center p-2 bg-slate-100 ${A?"max-w-5xl aspect-video rounded-2xl overflow-hidden shadow-2xl border border-neutral-850":""}`,children:e.jsx("iframe",{src:`${T}#page=${a+1}&toolbar=0&navpanes=0`,className:"w-full h-full border-0 rounded-xl"},`${T}-${A?"fs":"card"}-${a}`)}):H==="pptx"?e.jsx("div",{className:`w-full h-full flex items-center justify-center p-2 bg-slate-900/5 ${A?"max-w-5xl aspect-video rounded-2xl overflow-hidden shadow-2xl border border-neutral-850":""}`,children:G(!1)}):e.jsx("div",{className:"flex-1 w-full flex items-center justify-center max-w-2xl min-h-0",children:e.jsxs("div",{className:`w-full bg-white rounded-xl shadow-md border border-slate-100 flex flex-col overflow-y-auto p-6 md:p-8 aspect-video relative transition-all duration-300 hover:shadow-lg max-h-full ${A?"max-w-4xl p-12 md:p-16 border-neutral-850 rounded-3xl shadow-2xl":""}`,children:[e.jsxs("div",{className:"flex justify-between items-center text-xs font-semibold text-slate-400 border-b border-slate-100 pb-2 mb-4 shrink-0",children:[e.jsx("span",{className:"tracking-wide uppercase text-indigo-650",children:"SMART CLASS SLIDE DECK"}),e.jsxs("span",{className:"font-mono",children:["SLIDE ",a+1," / ",L]})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto pr-1",children:e.jsx("div",{className:"markdown-body text-slate-800 leading-relaxed font-sans prose prose-neutral max-w-none text-xs",children:F[a]?e.jsx(sn,{children:F[a]}):e.jsx("div",{className:"text-center text-slate-400 italic py-8",children:"幻灯片没有内容,请在“编辑文档”中添加。"})})}),e.jsxs("div",{className:"mt-4 pt-2 border-t border-slate-50 flex items-center justify-between text-xs text-slate-400 shrink-0 font-sans",children:[e.jsx("span",{children:"智慧互动教室白板演示系统"}),e.jsxs("span",{children:["Page ",a+1]})]})]})})}),!(f&&q&&X)&&e.jsxs("div",{className:`mt-4 flex items-center justify-center gap-3 select-none shrink-0 ${A?"absolute bottom-6 bg-neutral-900/80 backdrop-blur-md px-6 py-2.5 rounded-full border border-neutral-800 shadow-2xl z-[100001]":"bg-white px-4 py-2 rounded-full border border-slate-200/80 shadow-md relative z-10"}`,children:[e.jsx("button",{disabled:a===0||f&&q&&X,onClick:()=>le(a-1),className:`p-1.5 rounded-full border transition-colors cursor-pointer ${a===0||f&&q&&X?A?"border-neutral-800 text-neutral-600 bg-neutral-950/20 cursor-not-allowed":"border-slate-100 bg-slate-50 text-slate-300 cursor-not-allowed":A?"border-neutral-700 text-neutral-300 hover:bg-neutral-800":"border-slate-205 text-slate-655 hover:bg-slate-50"}`,title:"上一张 (ArrowLeft)",children:e.jsx(Vt,{size:A?18:14})}),e.jsxs("div",{className:`flex items-center gap-1.5 px-1 font-mono text-xs ${A?"text-neutral-200":"text-slate-700"}`,children:[e.jsx("span",{className:`font-bold ${A?"text-white text-base":"text-slate-900"}`,children:a+1}),e.jsx("span",{className:A?"text-neutral-600":"text-slate-350",children:"/"}),e.jsx("span",{children:L})]}),e.jsx("button",{disabled:a>=L-1||f&&q&&X,onClick:()=>le(a+1),className:`p-1.5 rounded-full border transition-colors cursor-pointer ${a>=L-1||f&&q&&X?A?"border-neutral-800 text-neutral-600 bg-neutral-950/20 cursor-not-allowed":"border-slate-100 bg-slate-50 text-slate-300 cursor-not-allowed":A?"border-neutral-700 text-neutral-300 hover:bg-neutral-800":"border-slate-205 text-slate-655 hover:bg-slate-50"}`,title:"下一张 (ArrowRight)",children:e.jsx(Kt,{size:A?18:14})})]})]}),o==="doc"&&H==="md"&&e.jsxs("div",{className:"flex-1 flex flex-row min-h-0 bg-white",children:[re.length>0&&e.jsxs("div",{className:"w-1/4 min-w-[120px] max-w-[200px] border-r border-slate-200 bg-slate-50/50 flex flex-col py-3 px-2 overflow-y-auto shrink-0 select-none",children:[e.jsxs("span",{className:"text-xs font-bold text-slate-400 uppercase tracking-widest px-2 mb-2 flex items-center gap-1",children:[e.jsx(js,{size:10}),"文档大纲"]}),e.jsx("div",{className:"flex flex-col gap-0.5",children:re.map((_,b)=>e.jsx("button",{onClick:()=>{const V=j.current?.querySelector(`[data-line-index="${_.lineIndex}"]`);V&&V.scrollIntoView({behavior:"smooth",block:"start"})},className:"text-left text-xs py-1 px-2 rounded hover:bg-slate-100 text-slate-600 hover:text-slate-900 truncate cursor-pointer font-medium whitespace-nowrap border-0 bg-transparent",style:{paddingLeft:`${Math.max(8,_.level*6)}px`},title:_.text,children:_.text},b))})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto p-6 md:p-8",ref:j,children:e.jsx("div",{className:"markdown-body prose prose-neutral max-w-none text-xs leading-relaxed text-slate-700",children:u.split(`
|
|
53
|
-
`).map((_,b)=>{const V=_.match(/^(#{1,3})\s+(.*)$/);if(V){const ae=V[1].length,Q=V[2].trim(),oe=ae===1?"h1":ae===2?"h2":"h3",_e=ae===1?"text-lg font-bold text-indigo-900 border-b pb-1 mt-4 mb-2":ae===2?"text-base font-bold text-slate-800 mt-3 mb-1.5":"text-sm font-semibold text-slate-700 mt-2 mb-1";return e.jsx(oe,{"data-line-index":b,className:_e,children:Q},b)}return _.trim()==="---"?e.jsx("hr",{className:"my-4 border-slate-200"},b):e.jsx("p",{className:"my-1.5 text-slate-600 antialiased leading-relaxed",children:_},b)})})})]}),o==="edit"&&H==="md"&&e.jsxs("div",{className:"flex-1 flex flex-col md:flex-row min-h-0 bg-white",children:[e.jsxs("div",{className:"w-full md:w-1/3 border-b md:border-b-0 md:border-r border-slate-100 bg-slate-50/40 p-3 flex flex-col overflow-y-auto shrink-0 select-none",children:[e.jsxs("span",{className:"text-xs font-bold text-slate-400 tracking-wider uppercase mb-2 flex items-center gap-1",children:[e.jsx(
|
|
52
|
+
`),b=[];return _.forEach((V,ae)=>{const Q=V.match(/^(#{1,3})\s+(.*)$/);Q&&b.push({text:Q[2].trim(),level:Q[1].length,lineIndex:ae})}),b})();if(H==="file"&&J){const _=(Z.split(".").pop()||"file").toLowerCase();return e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center gap-3 p-5 bg-gradient-to-br from-slate-50 to-white border border-slate-200 rounded-xl","data-testid":"course-package-file-card",children:[e.jsx("div",{className:"w-12 h-12 rounded-xl bg-indigo-50 border border-indigo-100 flex items-center justify-center",children:e.jsx(an,{size:22,className:"text-indigo-600"})}),e.jsxs("div",{className:"text-center max-w-full",children:[e.jsx("p",{className:"text-sm font-bold text-slate-800 truncate",title:Z||T,children:Z||"课程附件"}),e.jsx("p",{className:"text-[11px] text-slate-400 mt-0.5 font-mono uppercase",children:_})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("a",{href:T,download:Z||void 0,"data-testid":"course-package-file-download",className:"flex items-center gap-1.5 px-3 py-1.5 text-xs font-bold text-white bg-indigo-600 hover:bg-indigo-700 rounded-lg transition-colors",onClick:b=>b.stopPropagation(),children:[e.jsx(an,{size:13}),"下载附件"]}),y&&i&&e.jsx("button",{onClick:b=>{b.stopPropagation(),window.confirm("确定要移除此附件引用吗?(不会删除已上传的文件)")&&i(t,{...r,fileUrl:"",fileName:"",fileType:"md",slideCount:0})},"data-testid":"course-package-file-clear",className:"px-3 py-1.5 text-xs font-bold text-slate-600 bg-white border border-slate-200 hover:bg-slate-50 rounded-lg transition-colors",children:"移除引用"})]}),e.jsx("p",{className:"text-[10px] text-slate-400 text-center leading-relaxed max-w-[240px]",children:"该类型没有白板内联渲染器,以附件形式提供下载。"})]})}if(A&&typeof document<"u")return e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center bg-slate-900/10 text-slate-400 font-sans p-4",children:[e.jsxs("div",{className:"flex flex-col items-center gap-2",children:[e.jsx(gs,{size:24,className:"text-indigo-500 animate-pulse"}),e.jsx("span",{className:"text-xs",children:"演示文稿正在全屏放映中"})]}),gn.createPortal(e.jsxs("div",{className:"fixed inset-0 z-[99999] bg-neutral-950 flex flex-col items-center justify-center font-sans p-6",children:[e.jsxs("div",{className:"absolute top-4 left-4 right-4 flex items-center justify-between text-white/80 select-none z-[100001] px-4 py-2 bg-neutral-900/60 backdrop-blur-md rounded-xl border border-neutral-800",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full bg-emerald-500 animate-pulse"}),e.jsxs("span",{className:"font-bold text-xs tracking-wider uppercase",children:[H==="md"?"Markdown Slides":`${H.toUpperCase()} Presentation`," ",f&&"(Synced)"]})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("span",{className:"text-xs font-mono text-white/50",children:["Slide ",a+1," / ",L]}),y&&e.jsxs(e.Fragment,{children:[H==="md"&&e.jsx("button",{onClick:()=>D(_=>!_),className:`px-2.5 py-1 rounded-md text-xs uppercase font-bold tracking-wider transition-colors border cursor-pointer ${g?"bg-emerald-50 border-emerald-400 text-white animate-pulse":"bg-transparent border-neutral-700 text-neutral-400 hover:bg-neutral-850"}`,children:g?"Autoplay Live":"Autoplay"}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-white/70 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:q,onChange:_=>ye(_.target.checked),className:"rounded border-neutral-700 bg-neutral-800 text-indigo-500 focus:ring-0 focus:ring-offset-0 cursor-pointer"}),e.jsx("span",{children:"同步学生全屏"})]})]}),(!f||!X||!q||z)&&e.jsx("button",{onClick:()=>ze(!1),className:"p-1 px-2.5 bg-red-600 text-white text-xs font-bold rounded-lg transition-colors cursor-pointer border-0 hover:bg-red-700",title:"退出放映",children:"退出放映 (Esc)"})]})]}),e.jsx("div",{className:"w-full flex-1 min-h-0 flex items-center justify-center relative",children:H==="pdf"?e.jsx("div",{className:"w-full h-full flex items-center justify-center p-2 bg-slate-100 max-w-[90vw] max-h-[82vh] aspect-video rounded-2xl overflow-hidden shadow-2xl border border-neutral-850",children:e.jsx("iframe",{src:`${T}#page=${a+1}&toolbar=0&navpanes=0`,className:"w-full h-full border-0 rounded-xl"},`${T}-fs-${a}`)}):H==="pptx"?e.jsx("div",{className:"w-full h-full flex items-center justify-center p-2 bg-slate-900/5 max-w-[90vw] max-h-[82vh] aspect-video rounded-2xl overflow-hidden shadow-2xl border border-neutral-850",children:G(!0)}):e.jsx("div",{className:"flex-1 w-full flex items-center justify-center max-w-[90vw] min-h-0",children:e.jsxs("div",{className:"w-full bg-white rounded-xl shadow-md border border-slate-100 flex flex-col overflow-y-auto p-6 md:p-8 aspect-video relative transition-all duration-300 hover:shadow-lg max-h-[82vh] max-w-none p-12 md:p-16 border-neutral-850 rounded-3xl shadow-2xl",children:[e.jsxs("div",{className:"flex justify-between items-center text-xs font-semibold text-slate-400 border-b border-slate-100 pb-2 mb-4 shrink-0",children:[e.jsx("span",{className:"tracking-wide uppercase text-indigo-650",children:"SMART CLASS SLIDE DECK"}),e.jsxs("span",{className:"font-mono",children:["SLIDE ",a+1," / ",L]})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto pr-1",children:e.jsx("div",{className:"markdown-body text-slate-800 leading-relaxed font-sans prose prose-neutral max-w-none text-xs",children:F[a]?e.jsx(rn,{children:F[a]}):e.jsx("div",{className:"text-center text-slate-400 italic py-8",children:"幻灯片没有内容,请在“编辑文档”中添加。"})})}),e.jsxs("div",{className:"mt-4 pt-2 border-t border-slate-50 flex items-center justify-between text-xs text-slate-400 shrink-0 font-sans",children:[e.jsx("span",{children:"智慧互动教室白板演示系统"}),e.jsxs("span",{children:["Page ",a+1]})]})]})})}),!(f&&q&&X)&&e.jsxs("div",{className:"absolute bottom-6 bg-neutral-900/80 backdrop-blur-md px-6 py-2.5 rounded-full border border-neutral-800 shadow-2xl z-[100001]",children:[e.jsx("button",{disabled:a===0||f,onClick:()=>le(a-1),className:`p-1.5 rounded-full border transition-colors cursor-pointer ${a===0||f?"border-neutral-800 text-neutral-600 bg-neutral-950/20 cursor-not-allowed":"border-neutral-700 text-neutral-300 hover:bg-neutral-800"}`,title:"上一张 (ArrowLeft)",children:e.jsx(Vt,{size:18})}),e.jsxs("div",{className:"flex items-center gap-1.5 px-1 font-mono text-xs text-neutral-200",children:[e.jsx("span",{className:"font-bold text-white text-base",children:a+1}),e.jsx("span",{className:"text-neutral-600",children:"/"}),e.jsx("span",{children:L})]}),e.jsx("button",{disabled:a>=L-1||f,onClick:()=>le(a+1),className:`p-1.5 rounded-full border transition-colors cursor-pointer ${a>=L-1||f?"border-neutral-800 text-neutral-600 bg-neutral-950/20 cursor-not-allowed":"border-neutral-700 text-neutral-300 hover:bg-neutral-800"}`,title:"下一张 (ArrowRight)",children:e.jsx(Kt,{size:18})})]})]}),document.body)]});const ge=A?"fixed inset-0 z-[99999] bg-neutral-950 flex flex-col items-center justify-center font-sans p-6":"flex-1 flex flex-col items-center justify-between p-4 bg-slate-900/5 relative min-w-0";return e.jsxs("div",{className:"w-full h-full flex flex-col bg-slate-50 text-slate-800 overflow-hidden text-xs relative font-sans",children:[!A&&e.jsxs("div",{className:"flex items-center justify-between px-3 py-1.5 bg-slate-100 border-b border-slate-200 shrink-0 select-none relative z-10",children:[e.jsx("div",{className:"flex items-center gap-1",children:H==="md"?e.jsxs(e.Fragment,{children:[e.jsxs("button",{onClick:()=>d("ppt"),className:`px-2 py-1 rounded flex items-center gap-1 font-medium transition-colors cursor-pointer ${o==="ppt"?"bg-indigo-600 text-white shadow-sm":"text-slate-600 hover:bg-slate-200"}`,title:"播放课件幻灯片 (PPT Mode)",children:[e.jsx(Vi,{size:11}),e.jsx("span",{children:"PPT 播放"})]}),e.jsxs("button",{onClick:()=>d("doc"),className:`px-2 py-1 rounded flex items-center gap-1 font-medium transition-colors cursor-pointer ${o==="doc"?"bg-indigo-600 text-white shadow-sm":"text-slate-600 hover:bg-slate-200"}`,title:"以精美文档形式阅读 (Markdown Document mode)",children:[e.jsx(Ki,{size:11}),e.jsx("span",{children:"文档阅读"})]}),e.jsxs("button",{onClick:()=>d("edit"),className:`px-2 py-1 rounded flex items-center gap-1 font-medium transition-colors cursor-pointer ${o==="edit"?"bg-indigo-600 text-white shadow-sm":"text-slate-600 hover:bg-slate-200"}`,title:"在线编辑 Markdown 内容",children:[e.jsx(Us,{size:11}),e.jsx("span",{children:"编辑文档"})]})]}):e.jsxs("div",{className:"flex items-center gap-1 bg-indigo-50 border border-indigo-200/50 text-indigo-700 px-2 py-0.5 rounded text-xs font-semibold",children:[e.jsx(gs,{size:10}),e.jsxs("span",{children:[H.toUpperCase()," 课件演示中"]})]})}),e.jsxs("div",{className:"flex items-center gap-3",children:[y&&e.jsx("div",{className:"flex items-center gap-1.5 border-r border-slate-200 pr-3",children:O?e.jsxs("div",{className:"flex items-center gap-1 text-xs text-slate-500 font-medium",children:[e.jsx(Ve,{size:10,className:"animate-spin"}),e.jsx("span",{children:"上传解析中..."})]}):J?e.jsxs("div",{className:"flex items-center gap-1.5 bg-slate-200/50 pl-2 pr-1.5 py-0.5 rounded border border-slate-300/30",children:[e.jsx("span",{className:"text-xs font-medium text-slate-600 max-w-[120px] truncate font-mono",title:Z,children:Z}),e.jsx("button",{onClick:Le,className:"p-0.5 hover:bg-slate-300 rounded text-red-500 cursor-pointer border-0 bg-transparent",title:"清除并切换回 Markdown",children:e.jsx(bt,{size:10})})]}):e.jsxs("div",{children:[e.jsxs("button",{onClick:()=>K.current?.click(),className:"px-2 py-1 rounded bg-indigo-50 border border-indigo-200 text-indigo-700 hover:bg-indigo-100 flex items-center gap-1 font-semibold text-xs cursor-pointer",title:"上传 PPTX 或 PDF 课件",children:[e.jsx(ys,{size:10}),e.jsx("span",{children:"上传课件"})]}),e.jsx("input",{type:"file",ref:K,onChange:ve,accept:".pdf,.pptx",className:"hidden"})]})}),o==="ppt"&&H==="md"&&e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("button",{onClick:()=>D(_=>!_),className:`p-1 rounded flex items-center gap-1 font-semibold text-xs transition-colors border cursor-pointer ${g?"bg-emerald-50 border-emerald-300 text-emerald-700":"bg-white border-slate-200 text-slate-500 hover:bg-slate-50"}`,title:"开启/关闭幻灯片自动播放",children:[g?e.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-emerald-500 animate-ping"}):null,e.jsx("span",{children:g?"自动播放中":"自动播放"})]}),g&&e.jsxs("select",{value:W,onChange:_=>k(Number(_.target.value)),className:"bg-white border border-slate-200 rounded px-1 text-xs py-0.5 text-slate-700 font-medium",children:[e.jsx("option",{value:2,children:"2秒"}),e.jsx("option",{value:4,children:"4秒"}),e.jsx("option",{value:6,children:"6秒"}),e.jsx("option",{value:10,children:"10秒"})]})]}),y&&o==="ppt"&&e.jsxs("label",{className:"flex items-center gap-1 text-xs text-slate-500 font-medium cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:q,onChange:_=>ye(_.target.checked),className:"rounded border-slate-300 text-indigo-650 focus:ring-0 focus:ring-offset-0 cursor-pointer"}),e.jsx("span",{children:"同步学生全屏"})]}),o==="ppt"&&(!f||!(q&&X))&&e.jsx("button",{onClick:()=>ze(!0),className:"p-1 rounded-lg text-slate-655 hover:bg-slate-200 border border-slate-200 bg-white transition-colors cursor-pointer",title:"全屏放映",children:e.jsx(Nn,{size:11})})]})]}),e.jsxs("div",{className:"flex-1 min-h-0 relative flex flex-row overflow-hidden",children:[o==="ppt"&&e.jsxs("div",{className:ge,children:[A&&e.jsxs("div",{className:"absolute top-4 left-4 right-4 flex items-center justify-between text-white/80 select-none z-[100001] px-4 py-2 bg-neutral-900/60 backdrop-blur-md rounded-xl border border-neutral-800",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-2.5 h-2.5 rounded-full bg-emerald-500 animate-pulse"}),e.jsxs("span",{className:"font-bold text-xs tracking-wider uppercase",children:[H==="md"?"Markdown Slides":`${H.toUpperCase()} Presentation`," ",f&&"(Synced)"]})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("span",{className:"text-xs font-mono text-white/50",children:["Slide ",a+1," / ",L]}),y&&e.jsxs(e.Fragment,{children:[H==="md"&&e.jsx("button",{onClick:()=>D(_=>!_),className:`px-2.5 py-1 rounded-md text-xs uppercase font-bold tracking-wider transition-colors border cursor-pointer ${g?"bg-emerald-50 border-emerald-400 text-white animate-pulse":"bg-transparent border-neutral-700 text-neutral-400 hover:bg-neutral-850"}`,children:g?"Autoplay Live":"Autoplay"}),e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-white/70 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:q,onChange:_=>ye(_.target.checked),className:"rounded border-neutral-700 bg-neutral-800 text-indigo-500 focus:ring-0 focus:ring-offset-0 cursor-pointer"}),e.jsx("span",{children:"同步学生全屏"})]}),e.jsx("button",{onClick:()=>ze(!1),className:"p-1 px-2.5 bg-red-655 text-white text-xs font-bold rounded-md transition-colors cursor-pointer border-0",title:"退出放映",children:"退出放映 (Esc)"})]})]})]}),e.jsx("div",{className:"w-full flex-1 min-h-0 flex items-center justify-center relative",children:H==="pdf"?e.jsx("div",{className:`w-full h-full flex items-center justify-center p-2 bg-slate-100 ${A?"max-w-5xl aspect-video rounded-2xl overflow-hidden shadow-2xl border border-neutral-850":""}`,children:e.jsx("iframe",{src:`${T}#page=${a+1}&toolbar=0&navpanes=0`,className:"w-full h-full border-0 rounded-xl"},`${T}-${A?"fs":"card"}-${a}`)}):H==="pptx"?e.jsx("div",{className:`w-full h-full flex items-center justify-center p-2 bg-slate-900/5 ${A?"max-w-5xl aspect-video rounded-2xl overflow-hidden shadow-2xl border border-neutral-850":""}`,children:G(!1)}):e.jsx("div",{className:"flex-1 w-full flex items-center justify-center max-w-2xl min-h-0",children:e.jsxs("div",{className:`w-full bg-white rounded-xl shadow-md border border-slate-100 flex flex-col overflow-y-auto p-6 md:p-8 aspect-video relative transition-all duration-300 hover:shadow-lg max-h-full ${A?"max-w-4xl p-12 md:p-16 border-neutral-850 rounded-3xl shadow-2xl":""}`,children:[e.jsxs("div",{className:"flex justify-between items-center text-xs font-semibold text-slate-400 border-b border-slate-100 pb-2 mb-4 shrink-0",children:[e.jsx("span",{className:"tracking-wide uppercase text-indigo-650",children:"SMART CLASS SLIDE DECK"}),e.jsxs("span",{className:"font-mono",children:["SLIDE ",a+1," / ",L]})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto pr-1",children:e.jsx("div",{className:"markdown-body text-slate-800 leading-relaxed font-sans prose prose-neutral max-w-none text-xs",children:F[a]?e.jsx(rn,{children:F[a]}):e.jsx("div",{className:"text-center text-slate-400 italic py-8",children:"幻灯片没有内容,请在“编辑文档”中添加。"})})}),e.jsxs("div",{className:"mt-4 pt-2 border-t border-slate-50 flex items-center justify-between text-xs text-slate-400 shrink-0 font-sans",children:[e.jsx("span",{children:"智慧互动教室白板演示系统"}),e.jsxs("span",{children:["Page ",a+1]})]})]})})}),!(f&&q&&X)&&e.jsxs("div",{className:`mt-4 flex items-center justify-center gap-3 select-none shrink-0 ${A?"absolute bottom-6 bg-neutral-900/80 backdrop-blur-md px-6 py-2.5 rounded-full border border-neutral-800 shadow-2xl z-[100001]":"bg-white px-4 py-2 rounded-full border border-slate-200/80 shadow-md relative z-10"}`,children:[e.jsx("button",{disabled:a===0||f&&q&&X,onClick:()=>le(a-1),className:`p-1.5 rounded-full border transition-colors cursor-pointer ${a===0||f&&q&&X?A?"border-neutral-800 text-neutral-600 bg-neutral-950/20 cursor-not-allowed":"border-slate-100 bg-slate-50 text-slate-300 cursor-not-allowed":A?"border-neutral-700 text-neutral-300 hover:bg-neutral-800":"border-slate-205 text-slate-655 hover:bg-slate-50"}`,title:"上一张 (ArrowLeft)",children:e.jsx(Vt,{size:A?18:14})}),e.jsxs("div",{className:`flex items-center gap-1.5 px-1 font-mono text-xs ${A?"text-neutral-200":"text-slate-700"}`,children:[e.jsx("span",{className:`font-bold ${A?"text-white text-base":"text-slate-900"}`,children:a+1}),e.jsx("span",{className:A?"text-neutral-600":"text-slate-350",children:"/"}),e.jsx("span",{children:L})]}),e.jsx("button",{disabled:a>=L-1||f&&q&&X,onClick:()=>le(a+1),className:`p-1.5 rounded-full border transition-colors cursor-pointer ${a>=L-1||f&&q&&X?A?"border-neutral-800 text-neutral-600 bg-neutral-950/20 cursor-not-allowed":"border-slate-100 bg-slate-50 text-slate-300 cursor-not-allowed":A?"border-neutral-700 text-neutral-300 hover:bg-neutral-800":"border-slate-205 text-slate-655 hover:bg-slate-50"}`,title:"下一张 (ArrowRight)",children:e.jsx(Kt,{size:A?18:14})})]})]}),o==="doc"&&H==="md"&&e.jsxs("div",{className:"flex-1 flex flex-row min-h-0 bg-white",children:[re.length>0&&e.jsxs("div",{className:"w-1/4 min-w-[120px] max-w-[200px] border-r border-slate-200 bg-slate-50/50 flex flex-col py-3 px-2 overflow-y-auto shrink-0 select-none",children:[e.jsxs("span",{className:"text-xs font-bold text-slate-400 uppercase tracking-widest px-2 mb-2 flex items-center gap-1",children:[e.jsx(js,{size:10}),"文档大纲"]}),e.jsx("div",{className:"flex flex-col gap-0.5",children:re.map((_,b)=>e.jsx("button",{onClick:()=>{const V=j.current?.querySelector(`[data-line-index="${_.lineIndex}"]`);V&&V.scrollIntoView({behavior:"smooth",block:"start"})},className:"text-left text-xs py-1 px-2 rounded hover:bg-slate-100 text-slate-600 hover:text-slate-900 truncate cursor-pointer font-medium whitespace-nowrap border-0 bg-transparent",style:{paddingLeft:`${Math.max(8,_.level*6)}px`},title:_.text,children:_.text},b))})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto p-6 md:p-8",ref:j,children:e.jsx("div",{className:"markdown-body prose prose-neutral max-w-none text-xs leading-relaxed text-slate-700",children:u.split(`
|
|
53
|
+
`).map((_,b)=>{const V=_.match(/^(#{1,3})\s+(.*)$/);if(V){const ae=V[1].length,Q=V[2].trim(),oe=ae===1?"h1":ae===2?"h2":"h3",_e=ae===1?"text-lg font-bold text-indigo-900 border-b pb-1 mt-4 mb-2":ae===2?"text-base font-bold text-slate-800 mt-3 mb-1.5":"text-sm font-semibold text-slate-700 mt-2 mb-1";return e.jsx(oe,{"data-line-index":b,className:_e,children:Q},b)}return _.trim()==="---"?e.jsx("hr",{className:"my-4 border-slate-200"},b):e.jsx("p",{className:"my-1.5 text-slate-600 antialiased leading-relaxed",children:_},b)})})})]}),o==="edit"&&H==="md"&&e.jsxs("div",{className:"flex-1 flex flex-col md:flex-row min-h-0 bg-white",children:[e.jsxs("div",{className:"w-full md:w-1/3 border-b md:border-b-0 md:border-r border-slate-100 bg-slate-50/40 p-3 flex flex-col overflow-y-auto shrink-0 select-none",children:[e.jsxs("span",{className:"text-xs font-bold text-slate-400 tracking-wider uppercase mb-2 flex items-center gap-1",children:[e.jsx(ar,{size:10,className:"text-indigo-650"}),"推荐课件及文档模板"]}),e.jsx("div",{className:"flex flex-col gap-2",children:Ce.map((_,b)=>e.jsxs("button",{type:"button",onClick:()=>{window.confirm(`确定要加载模板 “${_.name}” 吗?这将会覆盖当前白板课件中的所有编辑内容。`)&&(se(_.content),w(0))},className:"w-full text-left p-2.5 rounded-lg border border-slate-200 bg-white hover:border-indigo-300 hover:shadow-sm transition-all focus:outline-none cursor-pointer group",children:[e.jsx("div",{className:"font-bold text-xs text-slate-800 group-hover:text-indigo-700 whitespace-nowrap overflow-hidden text-ellipsis",children:_.name}),e.jsx("div",{className:"text-xs text-slate-400 mt-0.5",children:_.desc})]},b))}),e.jsxs("div",{className:"mt-4 p-2 bg-amber-50 rounded border border-amber-100 text-xs text-amber-700 font-sans leading-relaxed",children:[e.jsx("strong",{children:"💡 使用提示"}),e.jsx("br",{}),"在任意位置插入一行 ",e.jsx("code",{children:"---"})," 即可分割出一个新的幻灯片(PPT)页面。"]})]}),e.jsxs("div",{className:"flex-1 flex flex-col p-3 min-h-[200px]",children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5 px-1",children:[e.jsx("span",{className:"font-bold text-slate-500 text-xs uppercase",children:"Markdown Source Code"}),e.jsx("span",{className:"text-xs text-slate-400",children:"实时自动同步到所有协同终端"})]}),e.jsx("textarea",{value:u,onChange:_=>se(_.target.value),placeholder:"在此输入 Markdown 文档。使用 '---' 来作为 PPT 页面分页符...",className:"flex-1 w-full p-3 font-mono text-xs bg-slate-50 border border-slate-200 rounded-lg focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:bg-white transition-all resize-none leading-relaxed text-slate-800"})]})]})]})]})}const xo=({tool:t,setTool:r,setSelectedShapeId:l,highlighterColor:i,setHighlighterColor:o,onElementAdd:d,currentPage:u,activeSegmentId:x,lessonId:a,safeElements:w,selectedShapeId:g,showGrid:D,setShowGrid:W,autoTileEnabled:k=!1,onToggleAutoTile:z,readOnly:m=!1,userRole:j="teacher",isSyncing:y,setIsSyncing:f,handleClearBoard:T,handleResetBoard:H,handleElementDelete:Z,setDialog:J,setDialogInput:O,onRefresh:he,classroomTools:K=[],onExecuteTool:ue})=>{const[E,te]=n.useState(!1),U=n.useRef(null),[v,P]=n.useState(null),C=n.useCallback(()=>{const X=U.current?.getBoundingClientRect();X&&P({top:X.bottom+6,left:Math.max(8,Math.min(X.left,window.innerWidth-340))}),te(A=>!A)},[]);n.useEffect(()=>{if(!E)return;const X=()=>te(!1);return window.addEventListener("scroll",X,!0),window.addEventListener("resize",X),()=>{window.removeEventListener("scroll",X,!0),window.removeEventListener("resize",X)}},[E]);const M=n.useCallback(X=>{te(!1),ue?.(X)},[ue]),q=E&&v?gn.createPortal(e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"fixed inset-0 z-[9998]",onPointerDown:()=>te(!1)}),e.jsxs("div",{className:"fixed z-[9999] w-[320px] max-h-[420px] overflow-y-auto bg-surface border border-theme rounded-xl shadow-xl p-2 font-sans text-main",style:{top:v.top,left:v.left},children:[e.jsxs("div",{className:"px-2 py-1.5 text-2xs font-black uppercase tracking-wider text-muted flex items-center gap-1.5 sticky top-0 bg-surface",children:[e.jsx(Bs,{size:11,className:"text-primary-theme"}),K.length>0?`互动工具 · ${K.length} 个插件`:"互动工具"]}),K.length>0?K.map(X=>e.jsxs("button",{onClick:()=>M(X),disabled:!a,title:X.description,className:"w-full flex items-start gap-2.5 px-2 py-2 rounded-lg hover:bg-surface-secondary text-left transition-colors disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer",children:[e.jsx("span",{className:"p-1.5 rounded-lg bg-primary-theme/10 text-primary-theme border border-primary-theme/20 shrink-0",children:e.jsx(Bs,{size:13})}),e.jsxs("span",{className:"min-w-0 flex-1",children:[e.jsx("span",{className:"block text-xs font-bold text-main truncate",children:X.name}),e.jsx("span",{className:"block text-2xs text-muted truncate mt-0.5",children:X.description||X.name})]})]},`${X.pluginId}/${X.id}`)):e.jsx("div",{className:"px-2 py-3 text-xs text-muted italic text-center",children:"暂无可用的互动工具。请在应用商店启用插件。"})]})]}),document.body):null;return e.jsxs("div",{className:"flex items-center justify-between gap-1.5 px-2 py-1 bg-surface/95 backdrop-blur-md border-b border-theme/80 shrink-0 font-sans select-none text-main min-h-[38px] overflow-x-auto no-scrollbar",children:[e.jsxs("div",{className:"flex items-center gap-1.5 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-0.5 bg-surface-secondary/70 p-0.5 rounded-xl border border-theme/60 shrink-0",children:[e.jsx("button",{onClick:()=>{r("cursor"),l(null)},className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${t==="cursor"?"bg-primary-theme text-white shadow-2xs":"text-muted hover:bg-surface hover:text-main"}`,title:"选择工具 (Pointer / Selector)",children:e.jsx(Mn,{size:14})}),e.jsx("div",{className:"w-px h-3.5 bg-border-theme/60 mx-0.5"}),e.jsx("button",{onClick:()=>r("pen"),className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${t==="pen"?"bg-primary-theme text-white shadow-2xs":"text-muted hover:bg-surface hover:text-main"}`,title:"画笔工具 (Pen)",children:e.jsx($n,{size:14})}),e.jsx("button",{onClick:()=>r("highlighter"),className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${t==="highlighter"?"bg-amber-500 text-white shadow-2xs":"text-muted hover:bg-surface hover:text-main"}`,title:"荧光高亮笔 (Highlighter)",children:e.jsx(Tn,{size:14})}),t==="highlighter"&&e.jsx("div",{className:"flex items-center gap-1 bg-surface px-1 py-0.5 rounded-lg border border-theme animate-in zoom-in-95 duration-150",children:[{hex:"#facc15",label:"Yellow"},{hex:"#4ade80",label:"Green"},{hex:"#f472b6",label:"Pink"},{hex:"#60a5fa",label:"Blue"}].map(X=>e.jsx("button",{onClick:()=>o(X.hex),className:`w-3 h-3 rounded-full border transition-all ${i===X.hex?"ring-2 ring-primary-theme scale-110 border-white":"border-transparent"}`,style:{backgroundColor:X.hex},title:X.label},X.hex))}),e.jsx("div",{className:"w-px h-3.5 bg-border-theme/60 mx-0.5"}),e.jsx("button",{onClick:()=>r("rect"),className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${t==="rect"?"bg-primary-theme text-white shadow-2xs":"text-muted hover:bg-surface hover:text-main"}`,title:"矩形工具 (Rectangle)",children:e.jsx(nr,{size:14})}),e.jsx("button",{onClick:()=>r("circle"),className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${t==="circle"?"bg-primary-theme text-white shadow-2xs":"text-muted hover:bg-surface hover:text-main"}`,title:"圆形工具 (Circle)",children:e.jsx(Pn,{size:14})}),e.jsx("button",{onClick:()=>r("text"),className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${t==="text"?"bg-primary-theme text-white shadow-2xs":"text-muted hover:bg-surface hover:text-main"}`,title:"文本工具 (Text)",children:e.jsx(Dn,{size:14})})]}),e.jsxs("div",{className:"flex items-center gap-0.5 bg-surface-secondary/70 p-0.5 rounded-xl border border-theme/60 shrink-0",children:[e.jsx(We,{slot:"anchor:whiteboard-toolbar:presentation",placement:"before"}),e.jsx("button",{onClick:()=>{O(`# Title Slide
|
|
54
54
|
---
|
|
55
55
|
## Slide 2`),J({type:"prompt",title:"添加演示文稿",message:"请输入演示文稿的 Markdown 内容 (使用 --- 拆分新幻灯片):",placeholder:`# Title Slide
|
|
56
56
|
---
|
|
57
57
|
## Slide 2`,onConfirm:async X=>{const A=X||`# Title Slide
|
|
58
58
|
---
|
|
59
|
-
## Slide 2`;f(!0);try{await d("presentation",{markdown:A,x:50,y:50,width:600,height:400,slideX:0,slideY:0,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1),J(null)}}})},className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:bg-surface hover:text-main transition-all cursor-pointer",title:"插入演示幻灯片 (Presentation)",children:e.jsx(gs,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:presentation",placement:"after"}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:code-sandbox",placement:"before"}),e.jsx("button",{onClick:async()=>{f(!0);try{await d("code-sandbox",{code:"console.log('Hello Sandbox!');",x:100,y:100,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:bg-surface hover:text-main transition-all cursor-pointer",title:"插入代码沙箱 (Code Sandbox)",children:e.jsx(
|
|
59
|
+
## Slide 2`;f(!0);try{await d("presentation",{markdown:A,x:50,y:50,width:600,height:400,slideX:0,slideY:0,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1),J(null)}}})},className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:bg-surface hover:text-main transition-all cursor-pointer",title:"插入演示幻灯片 (Presentation)",children:e.jsx(gs,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:presentation",placement:"after"}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:code-sandbox",placement:"before"}),e.jsx("button",{onClick:async()=>{f(!0);try{await d("code-sandbox",{code:"console.log('Hello Sandbox!');",x:100,y:100,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:bg-surface hover:text-main transition-all cursor-pointer",title:"插入代码沙箱 (Code Sandbox)",children:e.jsx(Sn,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:code-sandbox",placement:"after"}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:math-graph",placement:"before"}),e.jsx("button",{onClick:async()=>{f(!0);try{await d("math-graph",{equation:"Math.sin(x)",x:100,y:150,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:bg-surface hover:text-main transition-all cursor-pointer",title:"插入数学函数图表 (Math Graph)",children:e.jsx(zn,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:math-graph",placement:"after"}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:courseware",placement:"before"}),e.jsx("button",{onClick:async()=>{f(!0);try{await d("html-applet",{code:`<!-- Interactive Web Courseware -->
|
|
60
60
|
<div style='padding:20px; text-align:center;'>
|
|
61
61
|
<h2>Interactive Web Courseware</h2>
|
|
62
62
|
<p>可在右侧属性栏中选择本地 ZIP/HTML 部署包。</p>
|
|
63
|
-
</div>`,x:100,y:150,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:bg-surface hover:text-main transition-all cursor-pointer",title:"插入交互网页课件 (Interactive Courseware)",children:e.jsx(ar,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:courseware",placement:"after"}),e.jsx("div",{className:"w-px h-3.5 bg-border-theme/60 mx-0.5"}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:rollcall",placement:"before"}),e.jsx("button",{onClick:async()=>{f(!0);try{await d("rollcall",{title:"随机点名助手",x:120,y:120,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-primary-theme hover:bg-primary-theme-light transition-all cursor-pointer",title:"插入随机点名组件 (Roll Call)",children:e.jsx(kn,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:rollcall",placement:"after"})]}),e.jsx(We,{slot:"classroom.tool"}),e.jsx("div",{className:"flex items-center gap-0.5 bg-surface-secondary/70 p-0.5 rounded-xl border border-theme/60 shrink-0",children:e.jsxs("button",{ref:U,onClick:C,className:`relative w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${E?"bg-primary-theme text-white shadow-2xs":"text-primary-theme hover:bg-primary-theme-light"} ${K.length===0?"opacity-50":""}`,title:"互动工具 (插件扩展)",children:[e.jsx(Bs,{size:14}),K.length>0&&e.jsx("span",{className:"absolute -top-1 -right-1 min-w-[14px] h-[14px] px-0.5 rounded-full bg-primary-theme text-white text-[9px] font-bold flex items-center justify-center leading-none",children:K.length})]})}),q,e.jsx(We,{slot:"anchor:whiteboard-toolbar:ai-tutor",placement:"before"}),e.jsx("button",{onClick:async()=>{f(!0);try{(await fetch(`/api/lessons/${a}/ai-tutor`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elements:w.map(A=>({type:A.type,data:JSON.parse(A.data)}))})})).ok?(ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a}),he&&he()):J({type:"alert",title:"AI 辅导提示",message:"无法获取 AI 授课助手的帮助,请稍后再试。",onConfirm:()=>J(null)})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-purple-600 hover:bg-purple-500/10 transition-all cursor-pointer shrink-0",title:"请求 AI 助教建议 (Ask AI Tutor)",children:e.jsx(ir,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:ai-tutor",placement:"after"})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0 ml-auto",children:[e.jsx(We,{slot:"anchor:whiteboard-toolbar:grid",placement:"before"}),e.jsx("button",{onClick:()=>W(X=>!X),className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${D?"text-primary-theme bg-primary-theme-light":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:D?"关闭网格背景":"开启网格背景",children:e.jsx(Zi,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:grid",placement:"after"}),!m&&z&&e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:z,className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${k?"text-primary-theme bg-primary-theme-light":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:k?"关闭自动平铺,恢复自由布局":"开启自动平铺(i3 式镶嵌布局)",children:e.jsx(Gs,{size:14})}),k&&e.jsx("span",{className:"text-2xs font-semibold text-primary-theme whitespace-nowrap",title:"当前为自动平铺模式,新组件会自动落入下一个格子",children:"平铺中"})]}),g&&e.jsxs("button",{onClick:()=>{Z(g),l(null)},className:"px-2 py-0.5 rounded-lg text-rose-500 bg-rose-500/10 hover:bg-rose-500/20 border border-rose-500/30 text-xs font-semibold flex items-center gap-1 transition-all cursor-pointer shadow-2xs",title:"删除选中图形",children:[e.jsx(bt,{size:12}),e.jsx("span",{className:"hidden sm:inline",children:"删除"})]}),j!=="student"?e.jsx("button",{onClick:T,className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:text-rose-500 hover:bg-rose-500/10 transition-all cursor-pointer",title:"清空白板 (Clear Board)",children:e.jsx(Qi,{size:14})}):e.jsx("button",{onClick:H,className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:text-amber-500 hover:bg-amber-500/10 transition-all cursor-pointer",title:"重置白板 (Reset Board)",children:e.jsx(ea,{size:14})}),y&&e.jsx(Ve,{size:13,className:"text-primary-theme animate-spin ml-0.5"})]})]})},ho=({pages:t,currentPage:r,showPageDrawer:l,setShowPageDrawer:i,editingPageIdx:o,setEditingPageIdx:d,editingPageTitle:u,setEditingPageTitle:x,activeMenuPageIdx:a,setActiveMenuPageIdx:w,safeElements:g,handleSwitchPage:D,handleRenamePage:W,handleDuplicatePage:k,handleMovePage:z,handleDeletePage:m,handleAddPage:j})=>e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"absolute top-3 left-1/2 -translate-x-1/2 z-20 flex items-center gap-1.5 bg-surface/90 backdrop-blur-md px-3 py-1.5 rounded-full shadow-lg border border-theme font-sans select-none text-main",children:[e.jsxs("button",{onClick:()=>i(!l),className:`p-1.5 rounded-full transition-colors cursor-pointer flex items-center gap-1 text-xs font-medium ${l?"bg-primary-theme-light text-primary-theme":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:"页面大纲与预览 (Pages Outline)",children:[e.jsx(Gs,{size:15}),e.jsxs("span",{className:"hidden sm:inline text-xs font-semibold",children:["大纲 (",t.length,")"]})]}),e.jsx("div",{className:"h-4 w-px bg-border-theme mx-0.5"}),e.jsx("button",{onClick:()=>D(Math.max(0,r-1)),className:"p-1 hover:bg-surface-secondary rounded-full text-muted hover:text-main disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer",disabled:r===0,title:"上一页",children:e.jsx(Vt,{size:16})}),e.jsx("div",{className:"flex items-center gap-1 max-w-[500px] overflow-x-auto no-scrollbar py-0.5",children:t.map((y,f)=>{const T=f===r,H=o===f;return e.jsxs("div",{className:"relative group flex items-center",children:[H?e.jsx("input",{type:"text",autoFocus:!0,value:u,onChange:Z=>x(Z.target.value),onKeyDown:Z=>{Z.key==="Enter"&&W(f,u),Z.key==="Escape"&&d(null)},onBlur:()=>W(f,u),className:"px-2 py-0.5 text-xs font-bold bg-surface border border-primary-theme rounded-full outline-none w-28 text-main shadow-2xs"}):e.jsx("button",{onClick:()=>D(f),onDoubleClick:()=>{d(f),x(y.title)},className:`px-3 py-1 rounded-full text-xs font-bold transition-all cursor-pointer flex items-center gap-1 border ${T?"bg-primary-theme text-white border-primary-theme shadow-2xs":"text-muted hover:bg-surface-secondary hover:text-main border-transparent"}`,title:"双击重命名",children:e.jsx("span",{className:"truncate max-w-[120px]",children:y.title})}),e.jsx("button",{onClick:Z=>{Z.stopPropagation(),w(a===f?null:f)},className:`p-0.5 rounded-full hover:bg-black/10 transition-colors ml-[-4px] z-10 ${T?"text-white/80 hover:text-white":"text-muted hover:text-main"}`,title:"页面选项",children:e.jsx(ta,{size:12})}),a===f&&e.jsxs("div",{className:"absolute top-full mt-2 left-1/2 -translate-x-1/2 bg-surface rounded-xl shadow-xl border border-theme py-1 w-36 z-50 text-xs font-normal text-main",onClick:Z=>Z.stopPropagation(),children:[e.jsxs("button",{onClick:()=>{d(f),x(y.title),w(null)},className:"w-full px-3 py-1.5 text-left text-main hover:bg-primary-theme-light hover:text-primary-theme flex items-center gap-2 cursor-pointer",children:[e.jsx(Us,{size:13})," 重命名"]}),e.jsxs("button",{onClick:()=>{k(f),w(null)},className:"w-full px-3 py-1.5 text-left text-main hover:bg-primary-theme-light hover:text-primary-theme flex items-center gap-2 cursor-pointer",children:[e.jsx(an,{size:13})," 复制页面"]}),f>0&&e.jsxs("button",{onClick:()=>{z(f,"left"),w(null)},className:"w-full px-3 py-1.5 text-left text-main hover:bg-primary-theme-light hover:text-primary-theme flex items-center gap-2 cursor-pointer",children:[e.jsx(Vt,{size:13})," 向左移动"]}),f<t.length-1&&e.jsxs("button",{onClick:()=>{z(f,"right"),w(null)},className:"w-full px-3 py-1.5 text-left text-main hover:bg-primary-theme-light hover:text-primary-theme flex items-center gap-2 cursor-pointer",children:[e.jsx(Kt,{size:13})," 向右移动"]}),e.jsx("div",{className:"my-1 border-t border-theme"}),e.jsxs("button",{onClick:()=>{m(f),w(null)},className:"w-full px-3 py-1.5 text-left text-rose-500 hover:bg-rose-500/10 flex items-center gap-2 cursor-pointer disabled:opacity-30",disabled:t.length<=1,children:[e.jsx(bt,{size:13})," 删除页面"]})]})]},y.id||f)})}),e.jsx("button",{onClick:()=>j(),className:"p-1 hover:bg-primary-theme-light hover:text-primary-theme text-muted rounded-full transition-colors cursor-pointer ml-0.5",title:"新建白板页面",children:e.jsx(Qt,{size:16})}),e.jsx("button",{onClick:()=>D(Math.min(t.length-1,r+1)),className:"p-1 hover:bg-surface-secondary rounded-full text-muted hover:text-main disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer",disabled:r>=t.length-1,title:"下一页",children:e.jsx(Kt,{size:16})})]}),l&&e.jsx("div",{className:"absolute inset-0 bg-slate-950/40 backdrop-blur-xs z-30 flex flex-col justify-end pointer-events-auto font-sans",onClick:()=>i(!1),children:e.jsxs("div",{className:"bg-surface/95 backdrop-blur-xl border-t border-theme rounded-t-2xl shadow-2xl p-4 max-h-[70vh] flex flex-col w-full max-w-5xl mx-auto animate-in slide-in-from-bottom duration-200 text-main",onClick:y=>y.stopPropagation(),children:[e.jsxs("div",{className:"flex items-center justify-between pb-3 border-b border-theme shrink-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Gs,{className:"w-5 h-5 text-primary-theme"}),e.jsx("h3",{className:"font-bold text-main text-sm",children:"白板页面大纲与预览"}),e.jsxs("span",{className:"px-2 py-0.5 bg-primary-theme-light text-primary-theme text-xs rounded-full font-semibold",children:["共 ",t.length," 页"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{onClick:()=>j(),className:"px-3 py-1.5 bg-primary-theme hover:bg-primary-theme-hover text-white rounded-lg text-xs font-semibold flex items-center gap-1.5 transition-colors cursor-pointer shadow-xs",children:[e.jsx(Qt,{size:14})," 新建页面"]}),e.jsx("button",{onClick:()=>i(!1),className:"p-1.5 hover:bg-surface-secondary rounded-full text-muted hover:text-main transition-colors cursor-pointer",children:e.jsx(es,{size:16})})]})]}),e.jsx("div",{className:"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-3 py-4 overflow-y-auto max-h-[50vh]",children:t.map((y,f)=>{const T=f===r,H=g.filter(Z=>Z.type!=="page_meta"&&(()=>{try{const J=JSON.parse(Z.data);return(J.page??0)===f||J.pageId===y.id}catch{return f===0}})()).length;return e.jsxs("div",{onClick:()=>{D(f),i(!1)},className:`relative flex flex-col p-3 rounded-xl border-2 transition-all cursor-pointer group bg-surface ${T?"border-primary-theme bg-primary-theme-light/30 shadow-md ring-2 ring-[var(--color-primary)]/20":"border-theme hover:border-primary-theme hover:shadow-sm"}`,children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsxs("span",{className:`text-xs font-extrabold px-2 py-0.5 rounded-md ${T?"bg-primary-theme text-white":"bg-surface-secondary text-muted"}`,children:["P",f+1]}),T&&e.jsx("span",{className:"text-xs font-bold text-primary-theme bg-primary-theme-light px-1.5 py-0.5 rounded",children:"当前激活"})]}),e.jsxs("div",{className:"h-20 bg-surface-secondary border border-theme rounded-lg flex flex-col items-center justify-center mb-2 overflow-hidden relative",children:[e.jsx(js,{size:24,className:T?"text-primary-theme":"text-subtle"}),e.jsxs("span",{className:"text-xs text-muted font-medium mt-1",children:[H," 个组件/笔画"]})]}),e.jsx("div",{className:"font-bold text-xs text-main truncate mb-1",title:y.title,children:y.title}),e.jsxs("div",{className:"flex items-center justify-between pt-2 border-t border-theme text-muted text-xs",onClick:Z=>Z.stopPropagation(),children:[e.jsx("button",{onClick:()=>{d(f),x(y.title)},className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"重命名",children:e.jsx(Us,{size:13})}),e.jsx("button",{onClick:()=>k(f),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"复制页面",children:e.jsx(an,{size:13})}),f>0&&e.jsx("button",{onClick:()=>z(f,"left"),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"向左移",children:e.jsx(Vt,{size:13})}),f<t.length-1&&e.jsx("button",{onClick:()=>z(f,"right"),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"向右移",children:e.jsx(Kt,{size:13})}),e.jsx("button",{onClick:()=>m(f),className:"hover:text-rose-500 p-1 rounded hover:bg-rose-500/10 transition-colors disabled:opacity-30",disabled:t.length<=1,title:"删除页面",children:e.jsx(bt,{size:13})})]})]},y.id||f)})})]})})]}),mo=({dialog:t,dialogInput:r,setDialogInput:l,setDialog:i})=>t?e.jsx("div",{className:"absolute inset-0 bg-neutral-900/40 backdrop-blur-[2px] flex items-center justify-center z-[9999] p-4 font-sans",children:e.jsxs("div",{className:"bg-white rounded-xl shadow-2xl overflow-hidden max-w-sm w-full border border-gray-100 flex flex-col scale-100 pointer-events-auto",children:[e.jsxs("div",{className:"px-5 py-4 border-b border-gray-150/60 bg-gray-50 flex justify-between items-center shrink-0",children:[e.jsx("h3",{className:"font-bold text-gray-800 text-sm",children:t.title}),e.jsx("button",{onClick:()=>i(null),className:"text-gray-400 hover:text-gray-650 transition-colors text-xl font-light cursor-pointer",children:"×"})]}),e.jsxs("div",{className:"p-5 flex-1 min-h-0",children:[e.jsx("p",{className:"text-xs text-gray-600 leading-relaxed whitespace-pre-wrap mb-4 font-medium",children:t.message}),t.type==="prompt"&&e.jsx("textarea",{value:r,onChange:o=>l(o.target.value),placeholder:t.placeholder,className:"w-full h-32 p-3 border border-gray-300 rounded-lg text-xs font-mono focus:outline-none focus:ring-2 focus:ring-indigo-500 bg-gray-50 focus:bg-white transition-all resize-none font-medium",onPointerDown:o=>o.stopPropagation()})]}),e.jsxs("div",{className:"px-5 py-3 border-t border-gray-100 bg-gray-50 flex justify-end gap-2 text-xs shrink-0",children:[t.type!=="alert"&&e.jsx("button",{onClick:()=>i(null),className:"px-4 py-2 text-gray-500 hover:bg-gray-100 rounded-lg transition-colors font-medium border border-gray-200 cursor-pointer",children:"取消"}),e.jsx("button",{onClick:async()=>{try{await t.onConfirm(r)}catch(o){console.error("Dialog action error:",o)}},className:"px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-semibold transition-all shadow-sm cursor-pointer",children:"确定"})]})]})}):null,Xs=[{key:"content",zh:"内容完整",en:"Completeness",weight:30},{key:"technical",zh:"技术实现",en:"Technical",weight:30},{key:"expression",zh:"表达规范",en:"Presentation",weight:20},{key:"innovation",zh:"创新亮点",en:"Originality",weight:20}],Os=[{key:"low",zh:"未达标",en:"Below",factor:.4},{key:"basic",zh:"基本达标",en:"Basic",factor:.7},{key:"good",zh:"良好",en:"Good",factor:.85},{key:"excellent",zh:"优秀",en:"Excellent",factor:1}];function fo(t){if(!Number.isFinite(t)||t<=0)return"0 B";const r=["B","KB","MB","GB"],l=Math.min(r.length-1,Math.floor(Math.log(t)/Math.log(1024)));return`${(t/1024**l).toFixed(l===0?0:1)} ${r[l]}`}function Is(t){if(!t)return"—";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return"—"}}function xn(t,r,l){const i=String.fromCharCode(65+t%26);return l?`${r?"匿名同学":"待评同学"} ${i}`:`${r?"Anonymous":"Peer"} ${i}`}function po({assignmentId:t,tasks:r,onSubmitted:l,onToast:i,lang:o="zh"}){const d=o==="zh",[u,x]=n.useState(null),[a,w]=n.useState({}),[g,D]=n.useState(""),[W,k]=n.useState(""),[z,m]=n.useState(!1),[j,y]=n.useState(null),[f,T]=n.useState(null),[H,Z]=n.useState(null),J=Math.max(0,r.findIndex(C=>C.taskId===u)),O=r[J],he=n.useCallback((C,M,q)=>{if(i){i(C,M,q);return}T(M?`${C}:${M}`:C)},[i]);n.useEffect(()=>{const C=r[J];C&&(D(C.review?String(C.review.score):""),k(C.review?.comment||""),w({}),y(null),T(null))},[J,r]);const K=n.useMemo(()=>{if(Xs.filter(q=>a[q.key]).length===0)return null;const M=Xs.reduce((q,X)=>{const A=Os.find(F=>F.key===a[X.key]);return q+X.weight*(A?.factor??Os[1].factor)},0);return Math.round(M)},[a]),ue=g.trim()===""?K:Math.round(Number(g)),E=O?.dueAt!==null&&O?.dueAt!==void 0&&Date.now()>Number(O.dueAt),te=r.filter(C=>C.review).length,U=(C,M)=>{w(q=>{const X={...q};return X[C]===M?delete X[C]:X[C]=M,X}),D("")},v=n.useCallback(async()=>{if(z||!O||E)return;const C=ue;if(C===null||!Number.isFinite(C)||C<0||C>100){y(d?"请给出 0-100 的互评分数":"Score must be between 0 and 100");return}if(!O.submissionId){y(d?"该互评任务缺少提交物信息,请刷新后重试":"Missing submission for this task");return}m(!0),y(null);try{const M=await fetch(`/api/assignments/${encodeURIComponent(t)}/peer-review`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({submissionId:O.submissionId,score:C,comment:W.trim(),taskId:O.taskId})}),q=await M.json().catch(()=>null);if(!M.ok||q?.success===!1)throw new Error(q?.error||`HTTP ${M.status}`);he(O.review?d?"互评已更新":"Review updated":d?"互评已提交":"Review submitted",d?`已给 ${xn(J,O.anonymous,d)} 打 ${C} 分`:"","success"),await l?.()}catch(M){y(M?.message||(d?"提交失败":"submit failed"))}finally{m(!1)}},[J,O,t,W,E,he,l,ue,z,d]);if(r.length===0)return e.jsxs("div",{className:"rounded-xl border border-theme bg-surface-secondary p-4 text-xs text-muted inline-flex items-center gap-2",children:[e.jsx(Vs,{size:13}),d?"老师还没有给你分配互评任务。":"No peer review task assigned yet."]});const P=O?.submission;return e.jsxs("div",{"data-testid":"peer-review-panel",className:"space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[e.jsxs("div",{className:"text-xs font-semibold text-main inline-flex items-center gap-1.5",children:[e.jsx(Vs,{size:13})," ",d?"互评任务":"Peer review",e.jsx("span",{className:"font-normal text-muted",children:d?`已完成 ${te} / ${r.length}`:`${te} / ${r.length} done`})]}),O?.dueAt?e.jsxs("span",{className:`text-[11px] ${E?"text-red-600":"text-muted"}`,children:[d?"互评截止":"Due"," ",Is(O.dueAt),E?d?"(已截止)":" (closed)":""]}):null]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-[9rem_1fr] gap-3",children:[e.jsx("div",{className:"space-y-1",children:r.map((C,M)=>{const q=M===J;return e.jsxs("button",{type:"button",onClick:()=>x(C.taskId),className:`w-full flex items-center justify-between gap-1 rounded-lg border px-2 py-1.5 text-left text-xs transition-colors ${q?"border-orange-300 bg-orange-50 text-main":"border-theme bg-surface text-muted hover:bg-surface-secondary"}`,children:[e.jsx("span",{className:"truncate",children:xn(M,C.anonymous,d)}),C.review?e.jsxs("span",{className:"inline-flex items-center gap-1 text-emerald-600 shrink-0",children:[e.jsx(ts,{size:11})," ",C.review.score]}):e.jsx("span",{className:"text-[11px] text-amber-600 shrink-0",children:d?"待评":"todo"})]},C.taskId)})}),e.jsxs("div",{className:"rounded-xl border border-theme bg-surface p-3 space-y-3",children:[O?.stale&&e.jsxs("div",{className:"flex items-start gap-1.5 rounded-lg border border-amber-200 bg-amber-50 px-2 py-1.5 text-[11px] text-amber-800",children:[e.jsx(Dn,{size:12,className:"mt-0.5 shrink-0"}),d?"该作者在你评价后又更新了提交,建议复核后再提交一次。":"The author resubmitted after your review."]}),P?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-[11px] text-muted",children:[e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface-secondary border border-theme",children:d?`第 ${P.version} 版`:`v${P.version}`}),e.jsx("span",{children:Is(P.submittedAt)}),P.isLate&&e.jsx("span",{className:"text-amber-600",children:d?"迟交":"late"})]}),P.textContent?e.jsx("pre",{className:"max-h-48 overflow-y-auto whitespace-pre-wrap break-words rounded-lg border border-theme bg-surface-secondary p-2 text-xs text-main",children:P.textContent}):e.jsx("div",{className:"text-[11px] text-muted",children:d?"该同学没有留下文本作答。":"No text answer."}),(()=>{const C=Ai(P.linkUrl);return C?e.jsxs("a",{href:C,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1 text-xs text-orange-600 hover:underline break-all",children:[e.jsx(sa,{size:11})," ",P.linkUrl]}):null})(),P.files.length>0&&e.jsx("div",{className:"space-y-1",children:P.files.map(C=>e.jsxs("div",{className:"flex items-center gap-1.5 rounded-lg border border-theme bg-surface-secondary px-2 py-1.5 text-xs text-main",children:[e.jsxs("button",{onClick:()=>Z({id:C.id,original_name:C.original_name,size:C.size,mime:C.mime??null}),className:"flex items-center gap-1.5 flex-1 min-w-0 text-left hover:text-orange-600",title:d?"预览":"Preview","data-testid":"assignment-peer-file-preview",children:[e.jsx(Ks,{size:12,className:"shrink-0"}),e.jsx("span",{className:"truncate",children:C.original_name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:fo(C.size)})]}),e.jsx("a",{href:`/api/assignments/${encodeURIComponent(t)}/files/${encodeURIComponent(C.id)}`,target:"_blank",rel:"noreferrer",className:"shrink-0 text-muted hover:text-orange-600",title:d?"下载":"Download",children:e.jsx(ra,{size:12})})]},C.id))})]}):e.jsx("div",{className:"text-[11px] text-muted",children:d?"该同学还没有提交,无法互评。":"This peer has not submitted yet."}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("div",{className:"text-[11px] font-semibold text-main",children:d?"评价量规":"Rubric"}),Xs.map(C=>e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsxs("span",{className:"w-20 shrink-0 text-[11px] text-muted",children:[d?C.zh:C.en,e.jsxs("span",{className:"ml-1 text-[10px]",children:["(",C.weight,")"]})]}),Os.map(M=>{const q=a[C.key]===M.key;return e.jsx("button",{type:"button",disabled:E,onClick:()=>U(C.key,M.key),className:`px-1.5 py-0.5 rounded border text-[11px] transition-colors disabled:opacity-50 ${q?"border-orange-300 bg-orange-50 text-main":"border-theme text-muted hover:bg-surface-secondary"}`,children:d?M.zh:M.en},M.key)})]},C.key))]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("label",{className:"text-[11px] text-muted inline-flex items-center gap-1",children:[d?"互评总分":"Score",e.jsx("input",{type:"number",min:0,max:100,value:g,disabled:E,placeholder:K===null?"":String(K),onChange:C=>{D(C.target.value),w({})},className:"w-20 px-2 py-1 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400"})]}),K!==null&&g.trim()===""&&e.jsx("span",{className:"text-[11px] text-muted",children:d?`量规建议 ${K} 分`:`Rubric suggests ${K}`})]}),e.jsx("textarea",{value:W,disabled:E,onChange:C=>k(C.target.value),rows:3,placeholder:d?"写点具体建议:哪里做得好、哪里可以改进…":"Leave specific feedback…",className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400 resize-y"}),j&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:j}),f&&e.jsx("div",{className:"text-[11px] text-emerald-600 break-all",children:f}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-[11px] text-muted",children:O?.review?d?`已评 ${O.review.score} 分 · ${Is(O.review.submittedAt)}`:`Reviewed ${O.review.score}`:d?"同学之间双盲互评,作者看不到是谁评的":"Double-blind review"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{type:"button",disabled:z||E,onClick:()=>{D(O?.review?String(O.review.score):""),k(O?.review?.comment||""),w({}),y(null)},className:"px-2 py-1.5 rounded-lg text-xs border border-theme text-muted hover:bg-surface-secondary inline-flex items-center gap-1 disabled:opacity-50",children:[e.jsx(Et,{size:11})," ",d?"重填":"Reset"]}),e.jsxs("button",{type:"button",disabled:z||E,onClick:()=>void v(),className:"px-3 py-1.5 rounded-lg text-xs font-medium bg-orange-500 text-white hover:bg-orange-600 inline-flex items-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed",children:[z?e.jsx(Ve,{size:12,className:"animate-spin"}):null,E?d?"互评已截止":"Closed":O?.review?d?"更新互评":"Update":d?"提交互评":"Submit"]})]})]})]})]}),H&&e.jsx(Rn,{assignmentId:t,file:H,lang:o,onClose:()=>Z(null)})]})}const bo=".pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.csv,.txt,.md,.rtf,.odt,.odp,.ods,.png,.jpg,.jpeg,.gif,.webp,.bmp,.svg,.heic,.zip,.py,.js,.mjs,.cjs,.ts,.tsx,.jsx,.java,.c,.h,.cpp,.cs,.go,.rs,.rb,.php,.sql,.json,.xml,.html,.css,.ino",qs=50*1024*1024;function ms(t){if(!Number.isFinite(t)||t<=0)return"0 B";const r=["B","KB","MB","GB"],l=Math.min(r.length-1,Math.floor(Math.log(t)/Math.log(1024)));return`${(t/1024**l).toFixed(l===0?0:1)} ${r[l]}`}function hn(t){if(!t)return"—";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return"—"}}function go(t){try{const r=typeof t?.files_json=="string"?JSON.parse(t.files_json):t?.files_json;return Array.isArray(r)?r.filter(l=>l&&typeof l.fileId=="string").map(l=>({fileId:String(l.fileId),name:String(l.name??l.fileId),size:Number(l.size??0)})):[]}catch{return[]}}function yo({assignmentId:t,onClose:r,onToast:l,lang:i="zh"}){const o=i==="zh",[d,u]=n.useState(!0),[x,a]=n.useState(null),[w,g]=n.useState(null),[D,W]=n.useState([]),[k,z]=n.useState([]),[m,j]=n.useState(""),[y,f]=n.useState(""),[T,H]=n.useState(!1),[Z,J]=n.useState(null),[O,he]=n.useState(null),[K,ue]=n.useState(!1),[E,te]=n.useState("submit"),[U,v]=n.useState(null),[P,C]=n.useState(null),M=n.useRef(new Map),q=n.useRef(new Map),X=n.useRef(null),A=n.useCallback((b,V,ae)=>{if(l){l(b,V,ae);return}v({text:V?`${b}:${V}`:b,type:ae==="error"?"warning":ae})},[l]),F=n.useCallback((b,V)=>{z(ae=>ae.map(Q=>Q.key===b?{...Q,...V}:Q))},[]),L=n.useCallback(async(b=!1)=>{b||u(!0),a(null);try{const[V,ae]=await Promise.all([fetch(`/api/assignments/${encodeURIComponent(t)}`),fetch(`/api/assignments/${encodeURIComponent(t)}/files`)]),Q=await V.json().catch(()=>null);if(!V.ok||Q?.success===!1)throw new Error(Q?.error||`HTTP ${V.status}`);g(Q);const oe=await ae.json().catch(()=>null),_e=Array.isArray(oe?.files)?oe.files:[];W(_e.filter(Ge=>!Ge.version_id))}catch(V){a(V?.message||"load failed")}finally{b||u(!1)}},[t]);n.useEffect(()=>{L()},[L]),n.useEffect(()=>{const b=q.current;return()=>{b.forEach(V=>{try{V.abort()}catch{}}),b.clear()}},[]);const p=n.useCallback(b=>new Promise(V=>{const ae=M.current.get(b);if(!ae){F(b,{status:"error",error:o?"文件已失效,请重新选择":"file expired"}),V();return}const Q=new XMLHttpRequest;q.current.set(b,Q),Q.open("POST",`/api/assignments/${encodeURIComponent(t)}/files`,!0),Q.setRequestHeader("X-File-Name",encodeURIComponent(ae.name)),Q.setRequestHeader("Content-Type","application/octet-stream"),Q.upload.onprogress=oe=>{oe.lengthComputable&&F(b,{progress:Math.round(oe.loaded/oe.total*100)})},Q.onload=()=>{q.current.delete(b);let oe=null;try{oe=JSON.parse(Q.responseText||"{}")}catch{oe=null}Q.status>=200&&Q.status<300&&oe?.success!==!1&&oe?.file?.id?(F(b,{status:"done",progress:100,fileId:oe.file.id}),W(_e=>[{id:oe.file.id,original_name:oe.file.name??ae.name,size:oe.file.size??ae.size,uploaded_at:Date.now()},..._e])):F(b,{status:"error",error:oe?.error||`HTTP ${Q.status}`}),V()},Q.onerror=()=>{q.current.delete(b),F(b,{status:"error",error:o?"网络错误":"network error"}),V()},Q.onabort=()=>{q.current.delete(b),V()},F(b,{status:"uploading",progress:0,error:void 0}),Q.send(ae)}),[t,F,o]),$=n.useCallback(b=>{if(!b.length)return;const V=Date.now(),ae=[],Q=[];b.forEach((oe,_e)=>{if(oe.size<=0){Q.push(`${oe.name}(${o?"空文件":"empty"})`);return}if(oe.size>qs){Q.push(`${oe.name}(${o?"超过":"over"} ${ms(qs)})`);return}const Ge=`${V}-${_e}-${oe.name}`;M.current.set(Ge,oe),ae.push({key:Ge,name:oe.name,size:oe.size,status:"queued",progress:0})}),Q.length&&A(o?"部分文件未加入":"Some files skipped",Q.join("、"),"warning"),ae.length&&(z(oe=>[...oe,...ae]),(async()=>{for(const oe of ae)await p(oe.key)})())},[A,p,o]),I=n.useCallback(b=>{p(b)},[p]),G=n.useCallback(b=>{try{q.current.get(b)?.abort()}catch{}M.current.delete(b),z(V=>V.filter(ae=>ae.key!==b))},[]),le=n.useCallback(async b=>{try{const V=await fetch(`/api/assignments/${encodeURIComponent(t)}/files/${b}`,{method:"DELETE"}),ae=await V.json().catch(()=>null);if(!V.ok||ae?.success===!1){A(o?"删除失败":"Delete failed",ae?.error||`HTTP ${V.status}`,"error");return}W(Q=>Q.filter(oe=>oe.id!==b))}catch(V){A(o?"删除失败":"Delete failed",V?.message||"","error")}},[t,A,o]),se=n.useMemo(()=>{const b=D.map(Q=>Q.id),V=new Set(b),ae=[];for(const Q of k)Q.status!=="done"||!Q.fileId||V.has(Q.fileId)||(V.add(Q.fileId),ae.push(Q.fileId));return[...b,...ae]},[D,k]),ve=k.some(b=>b.status==="uploading"),Le=se.length>0||m.trim().length>0||y.trim().length>0,ze=n.useCallback(async()=>{if(!(T||ve)){H(!0),J(null);try{const b=await fetch(`/api/assignments/${encodeURIComponent(t)}/submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({fileIds:se,textContent:m.trim()||void 0,linkUrl:y.trim()||void 0})}),V=await b.json().catch(()=>null);if(!b.ok||V?.success===!1)throw new Error(V?.error||`HTTP ${b.status}`);he(Number(V?.version)||1),z([]),M.current.clear(),j(""),A(o?"提交成功":"Submitted",o?`已生成第 ${V?.version??1} 版提交`:"","success"),await L(!0)}catch(b){J(b?.message||"submit failed")}finally{H(!1)}}},[t,se,L,A,T,m,ve,o]),ye=w?.assignment,Ce=Array.isArray(w?.versions)?w.versions:[],xt=w?.grade,re=w?.stats,ge=Array.isArray(w?.peerReviewTasks)?w.peerReviewTasks:[],_=ge.filter(b=>!b.review||b.stale).length;return e.jsxs("div",{className:"fixed inset-0 z-[120] flex items-center justify-center bg-black/40 p-4",onClick:r,children:[e.jsxs("div",{className:"w-full max-w-2xl max-h-[88vh] flex flex-col rounded-2xl bg-surface border border-theme shadow-2xl overflow-hidden",onClick:b=>b.stopPropagation(),children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 px-4 py-3 border-b border-theme",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(na,{size:14,className:"text-orange-600 shrink-0"}),e.jsx("h3",{className:"font-bold text-main text-sm truncate",children:ye?.title||(o?"课堂作业":"Assignment")})]}),ye&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2 mt-1 text-[11px] text-muted",children:[e.jsx("span",{className:"px-1.5 py-0.5 rounded-full bg-surface-secondary border border-theme",children:ye.status==="published"?o?"已发布":"published":ye.status}),ye.due_at?e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(ia,{size:10})," ",o?"截止":"Due"," ",hn(ye.due_at)]}):null,ye.allow_late?e.jsx("span",{children:o?"允许迟交":"late allowed"}):null,re?e.jsx("span",{children:o?`已提交 ${re.submissionCount}`:`${re.submissionCount} submitted`}):null]})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[e.jsx("button",{onClick:()=>void L(!0),className:"p-1.5 rounded-lg text-muted hover:text-main hover:bg-surface-secondary transition-colors",title:o?"刷新":"Refresh",children:e.jsx(Et,{size:13})}),e.jsx("button",{onClick:r,className:"p-1.5 rounded-lg text-muted hover:text-main hover:bg-surface-secondary transition-colors",title:o?"关闭":"Close",children:e.jsx(es,{size:14})})]})]}),e.jsxs("div",{className:"flex items-center gap-1 px-4 pt-2 border-b border-theme",children:[e.jsx("button",{type:"button",onClick:()=>te("submit"),className:`px-2.5 py-1.5 text-xs rounded-t-lg border-b-2 transition-colors ${E==="submit"?"border-orange-500 text-main font-medium":"border-transparent text-muted hover:text-main"}`,children:o?"我的提交":"My submission"}),ge.length>0&&e.jsxs("button",{type:"button",onClick:()=>te("peer"),className:`px-2.5 py-1.5 text-xs rounded-t-lg border-b-2 transition-colors inline-flex items-center gap-1.5 ${E==="peer"?"border-orange-500 text-main font-medium":"border-transparent text-muted hover:text-main"}`,children:[o?"互评任务":"Peer review",e.jsx("span",{className:"text-[11px]",children:_>0?`${ge.length-_}/${ge.length}`:ge.length}),_>0&&e.jsx("span",{className:"px-1 rounded-full bg-amber-100 text-amber-700 text-[10px]",children:o?`待评 ${_}`:`${_} todo`})]})]}),e.jsx("div",{className:"flex-1 overflow-y-auto px-4 py-3 space-y-4",children:d?e.jsxs("div",{className:"flex items-center justify-center gap-2 py-10 text-muted text-xs",children:[e.jsx(Ve,{size:14,className:"animate-spin"})," ",o?"加载中…":"Loading…"]}):x?e.jsxs("div",{className:"flex items-start gap-2 rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700",children:[e.jsx(Dt,{size:14,className:"mt-0.5 shrink-0"}),e.jsxs("div",{children:[e.jsx("div",{className:"font-semibold",children:o?"无法加载作业":"Failed to load assignment"}),e.jsx("div",{className:"mt-0.5 break-all",children:x})]})]}):E==="peer"?e.jsx(po,{assignmentId:t,tasks:ge,onSubmitted:()=>L(!0),onToast:l,lang:i}):e.jsxs(e.Fragment,{children:[ye?.description?e.jsx("div",{className:"rounded-xl border border-theme bg-surface-secondary px-3 py-2 text-xs text-main whitespace-pre-wrap leading-relaxed",children:ye.description}):null,xt?e.jsxs("div",{className:"rounded-xl border border-theme px-3 py-2 text-xs flex items-center gap-2",children:[e.jsx(aa,{size:14,className:"text-amber-500 shrink-0"}),xt.status==="confirmed"?e.jsxs("span",{className:"text-main",children:[o?"最终成绩":"Final score",":",e.jsx("span",{className:"font-bold text-amber-600 ml-1",children:xt.calculated_final_score})]}):e.jsx("span",{className:"text-muted",children:o?"成绩待教师确认":"Grade pending confirmation"})]}):null,e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsx("span",{className:"text-xs font-semibold text-main",children:o?"作业文件":"Files"}),e.jsxs("span",{className:"text-[11px] text-muted",children:[o?"单个不超过":"max"," ",ms(qs)]})]}),e.jsxs("div",{onDragOver:b=>{b.preventDefault(),ue(!0)},onDragLeave:()=>ue(!1),onDrop:b=>{b.preventDefault(),ue(!1);const V=Array.from(b.dataTransfer?.files||[]);V.length&&$(V)},onClick:()=>X.current?.click(),className:`rounded-xl border-2 border-dashed px-3 py-4 text-center cursor-pointer transition-colors ${K?"border-orange-400 bg-orange-50":"border-theme hover:border-orange-300"}`,children:[e.jsx(ys,{size:16,className:"mx-auto text-muted"}),e.jsx("div",{className:"mt-1 text-xs text-main font-medium",children:o?"点击选择文件,或拖拽到此处":"Click to choose files, or drop them here"}),e.jsx("div",{className:"text-[11px] text-muted mt-0.5",children:o?"支持文档、图片、压缩包与常见代码文件":"documents, images, archives, source files"}),e.jsx("input",{ref:X,type:"file",multiple:!0,accept:bo,className:"hidden",onChange:b=>{const V=Array.from(b.target.files||[]);V.length&&$(V),b.target.value=""}})]}),D.length>0&&e.jsx("ul",{className:"mt-2 space-y-1",children:D.map(b=>e.jsxs("li",{className:"flex items-center gap-2 rounded-lg border border-theme px-2 py-1.5 text-xs",children:[e.jsx(js,{size:12,className:"text-muted shrink-0"}),e.jsx("span",{className:"flex-1 truncate text-main",children:b.original_name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:ms(b.size)}),e.jsx("button",{onClick:()=>C({id:b.id,original_name:b.original_name,size:b.size}),className:"p-1 rounded text-muted hover:text-primary-theme hover:bg-surface-secondary",title:o?"预览":"Preview","aria-label":o?`预览 ${b.original_name}`:`Preview ${b.original_name}`,"data-testid":"assignment-pending-file-preview",children:e.jsx(Ks,{size:12})}),e.jsx("button",{onClick:()=>void le(b.id),className:"p-1 rounded text-orange-600 hover:text-red-500 hover:bg-surface-secondary",title:o?"移除":"Remove",children:e.jsx(bt,{size:12})})]},b.id))}),k.length>0&&e.jsx("ul",{className:"mt-2 space-y-1",children:k.map(b=>e.jsxs("li",{className:"rounded-lg border border-theme px-2 py-1.5 text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[b.status==="done"?e.jsx(ts,{size:12,className:"text-emerald-600 shrink-0"}):b.status==="error"?e.jsx(Dt,{size:12,className:"text-red-500 shrink-0"}):e.jsx(Ve,{size:12,className:"animate-spin text-muted shrink-0"}),e.jsx("span",{className:"flex-1 truncate text-main",children:b.name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:ms(b.size)}),b.status==="error"&&e.jsx("button",{onClick:()=>I(b.key),className:"p-1 rounded text-primary-theme hover:bg-surface-secondary",title:o?"重试":"Retry",children:e.jsx(Et,{size:12})}),e.jsx("button",{onClick:()=>G(b.key),className:"p-1 rounded text-muted hover:text-main hover:bg-surface-secondary",title:o?"从列表移除":"Remove from list",children:e.jsx(es,{size:12})})]}),b.status==="uploading"&&e.jsx("div",{className:"mt-1 h-1 rounded-full bg-surface-secondary overflow-hidden",children:e.jsx("div",{className:"h-full bg-orange-500 transition-all",style:{width:`${b.progress}%`}})}),b.status==="error"&&b.error?e.jsx("div",{className:"mt-0.5 text-[11px] text-red-600 break-all",children:b.error}):null]},b.key))})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-main mb-1",children:o?"文字作答(可选)":"Text answer (optional)"}),e.jsx("textarea",{value:m,onChange:b=>j(b.target.value),className:"w-full h-20 p-2 border border-theme rounded-lg text-xs bg-surface text-main resize-none focus:outline-none focus:ring-1 focus:ring-orange-400",placeholder:o?"可直接粘贴代码或说明…":"Paste code or notes…"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-main mb-1",children:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(En,{size:11})," ",o?"作品链接(可选)":"Link (optional)"]})}),e.jsx("input",{type:"url",value:y,onChange:b=>f(b.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400",placeholder:"https://"})]})]}),Ce.length>0&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-semibold text-main mb-1.5",children:o?`提交历史(共 ${Ce.length} 版)`:`Submission history (${Ce.length})`}),e.jsx("ul",{className:"space-y-1",children:Ce.map(b=>{const V=go(b);return e.jsxs("li",{className:"rounded-lg border border-theme px-2 py-1.5 text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{className:"px-1.5 py-0.5 rounded bg-surface-secondary border border-theme text-[11px] text-main shrink-0",children:["v",b.version]}),e.jsx("span",{className:"flex-1 truncate text-muted",children:b.text_content||b.link_url||"—"}),V.length>0&&e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:o?`${V.length} 个附件`:`${V.length} file(s)`}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:hn(b.created_at||b.submitted_at)})]}),V.length>0&&e.jsx("ul",{className:"mt-1 flex flex-wrap gap-1",children:V.map(ae=>e.jsx("li",{children:e.jsxs("button",{onClick:()=>C({id:ae.fileId,original_name:ae.name,size:ae.size}),className:"flex items-center gap-1 rounded border border-theme px-1.5 py-0.5 text-[11px] text-main hover:border-orange-300",title:o?"预览":"Preview","data-testid":"assignment-version-file-preview",children:[e.jsx(Ks,{size:11,className:"shrink-0"}),e.jsx("span",{className:"max-w-[160px] truncate",children:ae.name})]})},ae.fileId))})]},b.id)})})]}),O!==null&&e.jsxs("div",{className:"flex items-center gap-2 rounded-xl border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-700",children:[e.jsx(ts,{size:14,className:"shrink-0"}),o?`已提交第 ${O} 版`:`Version ${O} submitted`]}),Z&&e.jsxs("div",{className:"flex items-start gap-2 rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700",children:[e.jsx(Dt,{size:14,className:"mt-0.5 shrink-0"}),e.jsx("span",{className:"break-all",children:Z})]})]})}),e.jsxs("div",{className:"flex items-center justify-between gap-2 px-4 py-3 border-t border-theme",children:[e.jsx("span",{className:"text-[11px] text-muted",children:U?e.jsx("span",{className:U.type==="warning"?"text-amber-700":"text-emerald-700",children:U.text}):o?`本次将提交 ${se.length} 个附件${m.trim()?" + 文本":""}${y.trim()?" + 链接":""}`:`${se.length} file(s)`}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:r,className:"px-3 py-1.5 rounded-lg text-xs border border-theme text-main hover:bg-surface-secondary transition-colors",children:o?"关闭":"Close"}),e.jsxs("button",{onClick:()=>void ze(),disabled:T||ve||!Le,className:"px-3 py-1.5 rounded-lg text-xs font-medium bg-orange-600 hover:bg-orange-700 disabled:opacity-50 disabled:cursor-not-allowed text-white transition-colors inline-flex items-center gap-1.5",children:[T?e.jsx(Ve,{size:12,className:"animate-spin"}):e.jsx(ys,{size:12}),T?o?"提交中…":"Submitting…":o?"提交作业":"Submit"]})]})]})]}),P&&e.jsx(Rn,{assignmentId:t,file:P,lang:i,onClose:()=>C(null)})]})}function wo(t){if(!t)return"";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return""}}function jo({lessonId:t,classId:r,elementId:l,value:i,draftTitle:o,draftDescription:d,disabled:u,onChange:x,onToast:a,lang:w="zh"}){const g=w==="zh",[D,W]=n.useState(!1),[k,z]=n.useState([]),[m,j]=n.useState(null),[y,f]=n.useState(null),[T,H]=n.useState(!1),[Z,J]=n.useState(null),O=n.useCallback((U,v,P)=>{if(a){a(U,v,P);return}J({text:v?`${U}:${v}`:U,type:P})},[a]),he=n.useCallback(async(U=!1)=>{if(t){U||W(!0),f(null);try{const v=await fetch(`/api/assignments?lessonId=${encodeURIComponent(t)}`),P=await v.json().catch(()=>null);if(!v.ok||P?.success===!1)throw new Error(P?.error||`HTTP ${v.status}`);z(Array.isArray(P?.assignments)?P.assignments:[])}catch(v){f(v?.message||"load failed")}finally{U||W(!1)}}},[t]),K=n.useCallback(async()=>{if(!i){j(null);return}try{const U=await fetch(`/api/assignments/${encodeURIComponent(i)}`),v=await U.json().catch(()=>null);U.ok&&v?.success!==!1&&j(v.assignment||null)}catch{}},[i]);n.useEffect(()=>{he()},[he]),n.useEffect(()=>{K()},[K]);const ue=n.useCallback(async()=>{if(!(T||!t)){H(!0);try{const U=await fetch("/api/assignments",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({title:o?.trim()||(g?"课堂作业":"Class assignment"),description:d?.trim()||"",lessonId:t,classId:r||void 0,elementId:l||void 0,status:"published"})}),v=await U.json().catch(()=>null);if(!U.ok||v?.success===!1)throw new Error(v?.error||`HTTP ${U.status}`);const P=v?.assignment||v?.result?.assignment,C=P?.id||v?.assignmentId||v?.result?.assignmentId||v?.id;if(!C)throw new Error(g?"服务端未返回作业 ID":"no assignment id returned");j(P||{id:C,title:o,status:"published"}),await he(!0),x(String(C),P),O(g?"已创建并绑定作业":"Assignment created",g?"学生端可以开始提交了":"","success")}catch(U){O(g?"创建作业失败":"Create failed",U?.message||"","error")}finally{H(!1)}}},[r,T,d,o,l,t,he,O,x,g]),E=n.useCallback(U=>{if(!U){x(null),j(null);return}const v=k.find(P=>String(P.id)===U);j(v||null),x(U,v)},[x,k]),te=m?.title||k.find(U=>String(U.id)===i)?.title;return e.jsxs("div",{className:"space-y-2 rounded-xl border border-theme bg-surface-secondary p-2.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("span",{className:"text-xs font-semibold text-main inline-flex items-center gap-1",children:[e.jsx(En,{size:11})," ",g?"绑定作业中心":"Assignment binding"]}),e.jsx("button",{type:"button",onClick:()=>void he(!0),disabled:D,className:"p-1 rounded text-muted hover:text-main hover:bg-surface transition-colors",title:g?"刷新":"Refresh",children:D?e.jsx(Ve,{size:11,className:"animate-spin"}):e.jsx(Et,{size:11})})]}),i&&te?e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-emerald-200 bg-emerald-50 px-2 py-1.5",children:[e.jsx(ts,{size:12,className:"mt-0.5 text-emerald-600 shrink-0"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"text-xs font-medium text-main truncate",children:te}),e.jsx("div",{className:"text-[11px] text-muted truncate",children:[m?.status,m?.due_at?`${g?"截止":"due"} ${wo(m.due_at)}`:""].filter(Boolean).join(" · ")})]}),e.jsx("button",{type:"button",disabled:u,onClick:()=>E(""),className:"p-1 rounded text-muted hover:text-red-500 hover:bg-surface transition-colors shrink-0",title:g?"解除绑定":"Unbind",children:e.jsx(oa,{size:11})})]}):e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 px-2 py-1.5",children:[e.jsx(Dt,{size:12,className:"mt-0.5 text-amber-600 shrink-0"}),e.jsx("span",{className:"text-[11px] text-amber-800",children:g?"尚未绑定作业:学生端只能看到提示、无法提交。请选择已有作业或直接新建。":"Not bound yet — students cannot submit."})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:i||"",disabled:u,onChange:U=>E(U.target.value),className:"flex-1 min-w-0 px-2 py-1.5 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400",children:[e.jsx("option",{value:"",children:g?"— 选择本课时的作业 —":"— select assignment —"}),k.map(U=>e.jsxs("option",{value:U.id,children:[U.title||U.id,U.status?` (${U.status})`:""]},U.id))]}),e.jsxs("button",{type:"button",disabled:u||T||!t,onClick:()=>void ue(),className:"px-2 py-1.5 rounded-lg text-xs font-medium border border-theme text-main hover:bg-surface transition-colors inline-flex items-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed shrink-0",children:[T?e.jsx(Ve,{size:11,className:"animate-spin"}):e.jsx(Qt,{size:11}),g?"新建":"New"]})]}),y&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:y}),Z&&e.jsx("div",{className:`text-[11px] break-all ${Z.type==="success"?"text-emerald-600":Z.type==="error"?"text-red-600":"text-amber-700"}`,children:Z.text}),k.length===0&&!D&&!y&&e.jsx("div",{className:"text-[11px] text-muted",children:g?"本课时还没有作业,点「新建」即可。":"No assignment yet."})]})}const mn={peer_review_pending:{zh:"未完成互评",en:"Pending"},all_full_marks:{zh:"全部满分",en:"All full marks"},score_gap:{zh:"分数差异大",en:"Score gap"}};function vo(){const t=new Date(Date.now()+2592e5),r=l=>String(l).padStart(2,"0");return`${t.getFullYear()}-${r(t.getMonth()+1)}-${r(t.getDate())}T${r(t.getHours())}:${r(t.getMinutes())}`}function No({assignmentId:t,progress:r,onAssigned:l,onToast:i,lang:o="zh"}){const d=o==="zh",[u,x]=n.useState(!1),[a,w]=n.useState(r||null),[g,D]=n.useState(!1),[W,k]=n.useState(!1),[z,m]=n.useState("2"),[j,y]=n.useState(""),[f,T]=n.useState(null),[H,Z]=n.useState(null),J=n.useCallback((E,te,U)=>{if(i){i(E,te,U);return}Z(te?`${E}:${te}`:E)},[i]),O=n.useCallback(async()=>{if(r){w(r);return}D(!0),T(null);try{const E=await fetch(`/api/assignments/${encodeURIComponent(t)}`),te=await E.json().catch(()=>null);if(!E.ok||te?.success===!1)throw new Error(te?.error||`HTTP ${E.status}`);w(te?.peerProgress||null)}catch(E){T(E?.message||"load failed")}finally{D(!1)}},[t,r]);n.useEffect(()=>{O()},[O]);const he=n.useCallback(async()=>{if(!W){k(!0),T(null);try{const E=Math.max(1,Math.min(10,Math.round(Number(z)||2))),te=j?new Date(j).getTime():void 0,U=await fetch(`/api/assignments/${encodeURIComponent(t)}/assign-peer-reviews`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({reviewerCount:E,dueAt:te&&Number.isFinite(te)?te:void 0})}),v=await U.json().catch(()=>null);if(!U.ok||v?.success===!1)throw new Error(v?.error||`HTTP ${U.status}`);J(d?"互评已分配":"Peer reviews assigned",d?`新增 ${v?.created??0} 个互评任务,覆盖 ${v?.submissions??0} 份提交(重复分配不会重复建任务)`:"","success"),x(!0),await O(),await l?.()}catch(E){J(d?"分配互评失败":"Assign failed",E?.message||"","error")}finally{k(!1)}}},[t,W,j,O,J,l,z,d]),K=(a?.reviewers||[]).filter(E=>E.pending>0),ue=a?.flags?.length||0;return e.jsxs("div",{className:"space-y-2 rounded-xl border border-theme bg-surface-secondary p-2.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("span",{className:"text-xs font-semibold text-main inline-flex items-center gap-1",children:[e.jsx(Vs,{size:11})," ",d?"互评进度":"Peer review",a?e.jsx("span",{className:"font-normal text-muted",children:d?`${a.completed} / ${a.tasks} 已完成`:`${a.completed} / ${a.tasks} done`}):null,ue>0?e.jsx("span",{className:"px-1 rounded-full bg-amber-100 text-amber-700 text-[10px]",children:d?`${ue} 项待复核`:`${ue} flags`}):null]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[e.jsx("button",{type:"button",onClick:()=>void O(),disabled:g,className:"p-1 rounded text-muted hover:text-main hover:bg-surface transition-colors",title:d?"刷新":"Refresh",children:g?e.jsx(Ve,{size:11,className:"animate-spin"}):e.jsx(Et,{size:11})}),e.jsx("button",{type:"button",onClick:()=>x(E=>!E),className:"px-1.5 py-0.5 rounded text-[11px] text-muted hover:text-main hover:bg-surface transition-colors",children:u?d?"收起":"Hide":d?"展开":"Show"})]})]}),a?e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5 text-[11px] text-muted",children:[e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface border border-theme",children:d?`提交 ${a.submissions}`:`${a.submissions} subs`}),e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface border border-theme",children:d?`任务 ${a.tasks}`:`${a.tasks} tasks`}),e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface border border-theme",children:d?`待完成 ${a.pending}`:`${a.pending} pending`})]}):e.jsx("div",{className:"text-[11px] text-muted",children:d?"暂无互评数据。":"No peer review data."}),a&&a.tasks===0&&e.jsx("div",{className:"text-[11px] text-muted",children:d?"还没有分配互评:点「随机分配互评」,系统会给每份提交随机分配若干同学(双盲、不评自己、负载均衡)。":"No peer reviews assigned yet."}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("label",{className:"text-[11px] text-muted inline-flex items-center gap-1",children:[d?"每份提交分配":"Reviewers",e.jsx("input",{type:"number",min:1,max:10,value:z,onChange:E=>m(E.target.value),className:"w-14 px-2 py-1 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400"}),d?"人":""]}),e.jsxs("label",{className:"text-[11px] text-muted inline-flex items-center gap-1",children:[d?"互评截止":"Due",e.jsx("input",{type:"datetime-local",value:j,placeholder:vo(),onChange:E=>y(E.target.value),className:"px-2 py-1 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400"})]}),e.jsxs("button",{type:"button",disabled:W,onClick:()=>void he(),className:"px-2 py-1.5 rounded-lg text-xs font-medium border border-theme text-main hover:bg-surface transition-colors inline-flex items-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed",children:[W?e.jsx(Ve,{size:11,className:"animate-spin"}):e.jsx(Ys,{size:11}),d?"随机分配互评":"Assign"]})]}),f&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:f}),H&&e.jsx("div",{className:"text-[11px] text-emerald-600 break-all",children:H}),u&&a&&e.jsxs("div",{className:"space-y-2",children:[a.flags.length>0?e.jsx("div",{className:"space-y-1",children:a.flags.map((E,te)=>e.jsxs("div",{className:"flex items-start gap-1.5 rounded-lg border border-amber-200 bg-amber-50 px-2 py-1 text-[11px] text-amber-800",children:[e.jsx(Dn,{size:11,className:"mt-0.5 shrink-0"}),e.jsxs("span",{className:"break-all",children:[e.jsx("span",{className:"font-medium",children:d?mn[E.type]?.zh||E.type:mn[E.type]?.en||E.type}),":",E.detail]})]},`${E.type}-${E.reviewerId||te}-${te}`))}):e.jsxs("div",{className:"text-[11px] text-emerald-600 inline-flex items-center gap-1",children:[e.jsx(ts,{size:11})," ",d?"暂未发现异常,互评进度正常。":"No anomaly detected."]}),a.reviewers.length>0&&e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-[11px] font-medium text-main",children:d?`互评人(${K.length} 人还有待评)`:"Reviewers"}),e.jsx("div",{className:"max-h-40 overflow-y-auto space-y-0.5",children:a.reviewers.map(E=>e.jsxs("div",{className:"flex items-center justify-between gap-2 rounded border border-theme bg-surface px-2 py-1 text-[11px]",children:[e.jsx("span",{className:"truncate text-main",children:E.name}),e.jsx("span",{className:E.pending>0?"text-amber-700 shrink-0":"text-emerald-600 shrink-0",children:d?`已评 ${E.submitted} · 待评 ${E.pending}`:`${E.submitted} done · ${E.pending} todo`})]},E.studentId))})]})]})]})}const ko="ABCDEFGHIJKLMNOPQRSTUVWXYZ";function Co(t){const r=t?.options;return Array.isArray(r)?r.map(l=>typeof l=="string"?l:l==null?"":String(l)):[]}function ps(t,r){if(typeof t=="number")return Number.isInteger(t)&&t>=0&&(r===0||t<r)?t:null;if(typeof t=="string"){const l=t.trim();if(!/^\d+$/.test(l))return null;const i=Number(l);return r===0||i<r?i:null}return null}function Fn(t,r){const l=t.trim().toUpperCase();if(l.length!==1)return null;const i=ko.indexOf(l);return i<0?null:r===0||i<r?i:null}function Ln(t,r){const l=t.trim();if(!l)return null;const i=r.findIndex(u=>u.trim()===l);if(i>=0)return i;const o=l.toLowerCase(),d=r.findIndex(u=>u.trim().toLowerCase()===o);return d>=0?d:null}function Bn(t){if(!t)return null;const r=Co(t),l=ps(t.correctIndex,r.length);if(l!==null)return l;const i=t.correctAnswer;if(i==null)return null;if(typeof i=="number")return ps(i,r.length);const o=String(i);if(!o.trim())return null;const d=Ln(o,r);if(d!==null)return d;const u=Fn(o,r.length);return u!==null?u:ps(o,r.length)}function sr(t,r){if(t!==null&&typeof t=="object"){const o=t,d=sr(o.optionIndex,r);return d!==null?d:sr(o.answer,r)}if(t==null)return null;const l=ps(t,r.length);if(l!==null)return l;if(typeof t!="string"||!t.trim())return null;const i=Fn(t,r.length);return i!==null?i:Ln(t,r)}function So(t,r){return t===null||t<0||t>=r.length?{correctIndex:null,correctAnswer:null}:{correctIndex:t,correctAnswer:r[t]??null}}const zo=["plugin","hello-world","rollcall","quiz","assignment","html-applet","code-sandbox","math-graph","presentation"],Mo=({isEditMode:t,selectedShapeId:r,setSelectedShapeId:l,activePropertiesElementId:i,setActivePropertiesElementId:o,safeElements:d,editingProperties:u,handleLocalPropChange:x,handlePropBlur:a,handleNumericPropBlur:w,handlePropsUpdate:g,handleUpdateElementData:D,handleElementDelete:W,handleUndoProp:k,handleRedoProp:z,propertyUndoStack:m,propertyRedoStack:j,isSyncing:y,lessonId:f,classId:T,fullscreenBroadcastClassId:H,coursewares:Z,fetchCoursewares:J,setZipCandidates:O,setZipUploadInfo:he,setShowEntrySelector:K,handleAddOption:ue,handleRemoveOption:E,handleOptionChangeLocal:te,handleOptionBlur:U})=>{const[v,P]=n.useState(null),C=n.useRef(null);if(n.useEffect(()=>()=>{C.current&&clearTimeout(C.current)},[]),!t||!r||!u)return null;const M=d.find(p=>p.id===r);if(!M)return null;const q=async()=>{const p=await D(u),$=p==="saved"||p==="failed"?p:null;$&&(C.current&&clearTimeout(C.current),P($),C.current=setTimeout(()=>P(null),$==="failed"?5e3:2500))},X=zo.includes(M.type)||bs.has(M.type);if(X&&i!==r)return null;const A=Array.isArray(u.options)?u.options.map(p=>String(p)):[],F=Bn(u),L=p=>"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[p]||String(p+1);return e.jsxs("div",{className:"w-80 h-full max-h-full bg-surface border-l border-theme flex flex-col font-sans text-xs select-none shadow-xl shrink-0 z-20 animate-in slide-in-from-right duration-200 text-main",onPointerDown:p=>p.stopPropagation(),children:[e.jsxs("div",{className:"px-4 py-3 border-b border-theme bg-surface-secondary flex justify-between items-center shrink-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(la,{size:15,className:"text-muted animate-spin",style:{animationDuration:"6s"}}),e.jsx("span",{className:"font-bold text-main text-sm",children:"属性编辑器"})]}),e.jsxs("div",{className:"flex items-center gap-1.5 font-sans",children:[e.jsxs("button",{onClick:k,disabled:(m[r]||[]).length===0,className:`p-1 rounded-lg transition-all flex items-center justify-center gap-1 border border-transparent select-none cursor-pointer ${(m[r]||[]).length===0?"text-subtle bg-transparent border-transparent opacity-40 cursor-not-allowed":"text-main bg-surface hover:bg-surface-secondary hover:border-theme active:bg-surface-secondary"}`,title:"撤销属性修改",children:[e.jsx(ca,{size:13}),(m[r]||[]).length>0&&e.jsx("span",{className:"text-xs font-bold text-muted",children:(m[r]||[]).length})]}),e.jsxs("button",{onClick:z,disabled:(j[r]||[]).length===0,className:`p-1 rounded-lg transition-all flex items-center justify-center gap-1 border border-transparent select-none cursor-pointer ${(j[r]||[]).length===0?"text-subtle bg-transparent border-transparent opacity-40 cursor-not-allowed":"text-main bg-surface hover:bg-surface-secondary hover:border-theme active:bg-surface-secondary"}`,title:"重做属性修改",children:[e.jsx(da,{size:13}),(j[r]||[]).length>0&&e.jsx("span",{className:"text-xs font-bold text-muted",children:(j[r]||[]).length})]}),e.jsx("div",{className:"h-4 w-px bg-border-theme mx-0.5 shrink-0"}),e.jsx("button",{onClick:()=>{o(null),l(null)},className:"text-muted hover:text-main hover:bg-surface-secondary p-1 rounded-full transition-all cursor-pointer",title:"关闭属性编辑器",children:e.jsx(es,{size:15})})]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-4 space-y-4",children:[e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-muted text-xs font-bold uppercase tracking-wider",children:"组件类型"}),e.jsx("span",{className:"px-2 py-0.5 bg-primary-theme-light text-primary-theme rounded text-xs font-bold uppercase tracking-wider",children:M.type})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-muted text-xs font-bold uppercase tracking-wider",children:"组件标识"}),e.jsx("span",{className:"font-mono text-muted text-xs truncate max-w-[155px]",title:M.id,children:M.id})]})]}),!X&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5 flex items-center gap-1.5",children:"尺寸"}),M.type!=="pen"&&M.type!=="circle"&&e.jsxs("div",{className:"grid grid-cols-2 gap-2 mt-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"宽度 (Width)"}),e.jsx("input",{type:"number",min:"50",value:Math.round(u.width??300),onChange:p=>x("width",parseFloat(p.target.value)||50),onBlur:p=>w("width",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"高度 (Height)"}),e.jsx("input",{type:"number",min:"50",value:Math.round(u.height??300),onChange:p=>x("height",parseFloat(p.target.value)||50),onBlur:p=>w("height",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]})]}),M.type==="circle"&&e.jsxs("div",{className:"mt-2",children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"半径 (Radius)"}),e.jsx("input",{type:"number",min:"5",value:Math.round(u.radius??50),onChange:p=>x("radius",parseFloat(p.target.value)||5),onBlur:p=>w("radius",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]})]}),(()=>{const p=Fi.get(M.type);if(p)return e.jsx(p,{elementId:M.id,elementType:M.type,data:u,updateData:g,lessonId:f,onClose:()=>l(null)});const $=bs.get(M.type);if($){const I=$.editFields||[];return e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsxs("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5 flex items-center justify-between",children:[e.jsxs("span",{children:[$.labelZh," 配置"]}),e.jsx("span",{className:"text-xs text-muted font-normal",children:"插件扩展"})]}),I.length===0?e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"标题 (Title)"}),e.jsx("input",{type:"text",value:u.title||"",onChange:G=>x("title",G.target.value),onBlur:G=>a("title",G.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main",placeholder:"组件标题..."})]}):I.map(G=>{const le=u[G.key]??"";return G.kind==="textarea"?e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:G.labelZh}),e.jsx("textarea",{value:le,onChange:se=>x(G.key,se.target.value),onBlur:se=>a(G.key,se.target.value),className:"w-full h-20 p-2 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main resize-none font-medium leading-relaxed",placeholder:G.placeholderZh||""})]},G.key):G.kind==="select"?e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:G.labelZh}),e.jsxs("select",{value:le,onChange:se=>{x(G.key,se.target.value),a(G.key,se.target.value)},className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-primary-theme",children:[e.jsx("option",{value:"",children:"请选择..."}),(G.options||[]).map(se=>e.jsx("option",{value:se.value,children:se.label},se.value))]})]},G.key):e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:G.labelZh}),e.jsx("input",{type:"text",value:le,onChange:se=>x(G.key,se.target.value),onBlur:se=>a(G.key,se.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main",placeholder:G.placeholderZh||""})]},G.key)})]})}return null})(),M.type==="quiz"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"随堂测验配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"测验题目 (Question)"}),e.jsx("textarea",{value:u.question||"",onChange:p=>x("question",p.target.value),onBlur:p=>a("question",p.target.value),className:"w-full h-20 p-2 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main resize-none font-medium leading-relaxed",placeholder:"编写问题描述..."})]}),(u.options||[]).length>0&&e.jsxs("div",{className:"bg-amber-500/10 border border-amber-500/30 rounded-lg p-2.5",children:[e.jsx("label",{className:"block text-xs text-amber-500 font-bold mb-1.5",children:"⚠️ 正确答案 (Correct Answer)"}),e.jsxs("select",{value:F===null?"":String(F),onChange:p=>{const $=p.target.value,I=$===""?null:Number($);g(So(I,A))},className:`w-full px-2 py-1.5 border rounded-lg text-xs font-medium focus:outline-none focus:ring-1 focus:ring-amber-500 cursor-pointer ${F!==null?"border-green-500/40 bg-green-500/10 text-green-600":"border-amber-500/40 bg-surface text-main"}`,children:[e.jsx("option",{value:"",children:"-- 请选择正确答案 --"}),A.map((p,$)=>e.jsxs("option",{value:String($),children:[L($),". ",p]},$))]}),F===null&&e.jsx("p",{className:"text-xs text-amber-500 mt-1",children:"未设置正确答案将无法自动判分"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-xs text-muted font-semibold",children:"选项列表 (Options)"}),e.jsx("div",{className:"space-y-1.5 max-h-48 overflow-y-auto pr-1",children:(u.options||[]).map((p,$)=>{const G="ABCDEFGHIJKLMNOPQRSTUVWXYZ"[$]||$+1;return e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-bold text-main bg-surface-secondary rounded px-1.5 py-1 text-center shrink-0 min-w-[22px]",children:G}),e.jsx("input",{type:"text",value:p||"",onChange:le=>te($,le.target.value),onBlur:le=>U($,le.target.value),className:"flex-1 px-2 py-1 border border-theme rounded-lg text-xs font-medium bg-surface text-main"}),e.jsx("button",{onClick:()=>E($),title:"删除选项",className:"text-muted hover:text-rose-500 hover:bg-rose-500/10 p-1 rounded-md shrink-0 transition-colors cursor-pointer",children:e.jsx(bt,{size:13})})]},$)})}),e.jsxs("button",{onClick:ue,className:"w-full mt-2 py-1 bg-surface-secondary hover:bg-surface-secondary text-main font-bold border border-theme rounded-lg flex items-center justify-center gap-1 transition-all text-xs cursor-pointer",children:[e.jsx(Qt,{size:12})," 添加选项"]})]})]}),M.type==="assignment"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"作业选项配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"作业任务标题 (Title)"}),e.jsx("input",{type:"text",value:u.title||"",onChange:p=>x("title",p.target.value),onBlur:p=>a("title",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-semibold focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main",placeholder:"作业名..."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"详细作业要求描述"}),e.jsx("textarea",{value:u.description||"",onChange:p=>x("description",p.target.value),onBlur:p=>a("description",p.target.value),className:"w-full h-24 p-2 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main resize-none font-medium leading-relaxed",placeholder:"请输入详细的作业指南..."})]}),e.jsx(jo,{lessonId:f,classId:T||H||void 0,elementId:M.id,value:u.assignmentId||"",draftTitle:u.title||"",draftDescription:u.description||"",onChange:p=>{x("assignmentId",p),a("assignmentId",p)}}),u.assignmentId?e.jsx(No,{assignmentId:String(u.assignmentId)},String(u.assignmentId)):null]}),(M.type==="code-sandbox"||M.type==="html-applet")&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsxs("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5 flex justify-between items-center",children:[e.jsx("span",{children:"动态运行代码定制"}),M.type==="html-applet"&&e.jsx("span",{className:"text-xs bg-primary-theme-light text-primary-theme px-1.5 py-0.5 rounded-full font-bold",children:"HTML Applet"})]}),M.type==="html-applet"&&e.jsxs("div",{className:"space-y-3 border-b border-theme pb-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-primary-theme font-bold mb-1",children:"选择互动网络课件 (ZIP/HTML):"}),e.jsxs("select",{value:u.coursewareUuid||"",onChange:p=>{const $=p.target.value;g({coursewareUuid:$,resourceId:""})},className:"w-full text-xs p-2 bg-surface-secondary border border-theme hover:border-primary-theme rounded-lg text-main focus:outline-none focus:ring-1 focus:ring-primary-theme transition-all font-semibold",children:[e.jsx("option",{value:"",children:"-- 使用自定义沙箱代码 --"}),Z.map(p=>e.jsxs("option",{value:p.uuid,children:["📁 [互动课件] ",p.name]},p.id))]})]}),e.jsxs("div",{className:"bg-surface-secondary p-2.5 rounded-xl border border-theme text-xs text-muted space-y-2",children:[e.jsx("span",{className:"font-bold text-main block",children:"上传新课件 (自动生成独立运行实例):"}),e.jsxs("label",{className:"w-full flex flex-col items-center justify-center p-3 bg-indigo-50 hover:bg-indigo-100 border border-dashed border-indigo-300 hover:border-indigo-400 rounded-lg cursor-pointer text-center transition-all",children:[e.jsx("span",{className:"font-bold text-indigo-700 text-xs",children:"✨ 上传互动网络课件 (.zip / .html)"}),e.jsx("span",{className:"text-xs text-indigo-500 mt-0.5",children:"支持多文件打包 ZIP 或单页 HTML,自动接入 LMS Bridge"}),e.jsx("input",{type:"file",accept:".zip,.html,.htm",className:"hidden",onChange:async p=>{const $=p.target.files?.[0];if(!$)return;const I=new FileReader;I.onload=async G=>{const le=G.target?.result;try{const se=await fetch("/api/courseware/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:$.name.replace(/\.[^/.]+$/,""),filename:$.name,base64Data:le})});if(se.ok){const ve=await se.json();ve.need_select_entry?(O(ve.candidates),he({uuid:ve.uuid,name:ve.name}),K(!0)):(g({coursewareUuid:ve.uuid,resourceId:""}),J({force:!0}))}else{const ve=await se.json();alert("上传失败: "+(ve.error||se.statusText))}}catch(se){console.error("Courseware upload failed:",se)}},I.readAsDataURL($)}})]})]})]}),(!u.coursewareUuid||M.type==="code-sandbox")&&e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-slate-400 font-semibold mb-1",children:"沙箱程序代码 (Source Code)"}),e.jsx("textarea",{value:u.code||"",onChange:p=>x("code",p.target.value),onBlur:p=>a("code",p.target.value),className:"w-full h-48 p-3 border border-slate-300 rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500 bg-slate-900 text-slate-100 resize-none leading-relaxed",placeholder:"// 编写交互沙箱代码..."})]})]}),M.type==="math-graph"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"函数解析拟合"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"函数表达式 y = f(x)"}),e.jsx("input",{type:"text",value:u.equation||"",onChange:p=>x("equation",p.target.value),onBlur:p=>a("equation",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"}),e.jsxs("p",{className:"text-xs text-muted mt-1 leading-snug",children:["支持标准 JS 表达式。 示例:",e.jsx("br",{}),"• ",e.jsx("code",{className:"bg-surface-secondary px-1 rounded",children:"Math.sin(x)"})," 正负弦波形",e.jsx("br",{}),"• ",e.jsx("code",{className:"bg-surface-secondary px-1 rounded",children:"Math.cos(x) * x"})," 振幅衰减"]})]})]}),M.type==="presentation"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"幻灯片 Markdown 文案"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"Markdown 源代码"}),e.jsx("textarea",{value:u.markdown||"",onChange:p=>x("markdown",p.target.value),onBlur:p=>a("markdown",p.target.value),className:"w-full h-64 p-2.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme resize-none font-medium leading-relaxed bg-surface text-main",placeholder:"修改 Markdown 内容..."})]})]}),M.type==="text"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"文字属性管理"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"文本内容"}),e.jsx("input",{type:"text",value:u.text||"",onChange:p=>x("text",p.target.value),onBlur:p=>a("text",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-medium focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"文字大小 (FontSize)"}),e.jsx("input",{type:"number",min:"10",max:"100",value:u.fontSize||16,onChange:p=>x("fontSize",parseInt(p.target.value)||10),onBlur:p=>w("fontSize",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"文字填充颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.color||"#000000",onChange:p=>x("color",p.target.value),onBlur:p=>a("color",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.color||"#000000"})]})]})]}),(M.type==="rectangle"||M.type==="shape")&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"矩形样式配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"外边框颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.stroke||"#000000",onChange:p=>x("stroke",p.target.value),onBlur:p=>a("stroke",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.stroke||"#000000"})]})]})]}),M.type==="circle"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"圆形样式配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"外边框颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.stroke||"#000000",onChange:p=>x("stroke",p.target.value),onBlur:p=>a("stroke",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.stroke||"#000000"})]})]})]}),M.type==="pen"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"线条样式配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"折线颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.color||"#000000",onChange:p=>x("color",p.target.value),onBlur:p=>a("color",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.color||"#000000"})]})]})]}),M.type==="highlighter"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"高亮荧光标记 (Highlighter)"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"荧光笔颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.color||"#facc15",onChange:p=>x("color",p.target.value),onBlur:p=>a("color",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.color||"#facc15"})]})]})]}),e.jsx("div",{className:"text-xs text-muted text-center select-none pt-2 font-medium",children:"提示:属性在失焦或修改时自动同步,多端可见。"})]}),e.jsxs("div",{className:"p-3 border-t border-slate-200 bg-white flex flex-col gap-2 shrink-0",children:[e.jsx("button",{onClick:q,disabled:y,className:"w-full py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-bold transition-all shadow-sm hover:shadow active:scale-[0.98] cursor-pointer flex items-center justify-center gap-1.5 text-xs",children:y?e.jsxs(e.Fragment,{children:[e.jsx(Ve,{size:13,className:"animate-spin"}),"正在保存..."]}):e.jsxs(e.Fragment,{children:[e.jsx(_n,{size:13}),"保存"]})}),e.jsxs("div",{role:"status","aria-live":"polite",className:"min-h-[16px] text-center",children:[v==="saved"&&e.jsxs("span",{"data-testid":"save-feedback-success",className:"inline-flex items-center gap-1 text-xs font-bold text-emerald-600",children:[e.jsx(ua,{size:12}),"已保存"]}),v==="failed"&&e.jsxs("span",{"data-testid":"save-feedback-error",className:"inline-flex items-center gap-1 text-xs font-bold text-red-600",children:[e.jsx(Dt,{size:12}),"保存失败,请重试"]})]}),e.jsxs("button",{onClick:()=>{W(r),l(null)},className:"w-full py-2 bg-red-50 hover:bg-red-105 text-red-650 rounded-lg font-semibold transition-all flex items-center justify-center gap-1.5 border border-red-200 cursor-pointer text-xs",children:[e.jsx(bt,{size:13}),"删除当前组件"]})]})]})},$o=({isVisible:t})=>t?e.jsxs("div",{className:"absolute inset-0 flex flex-col items-center justify-center pointer-events-none select-none text-muted p-6 z-0",children:[e.jsx("div",{className:"w-16 h-16 rounded-2xl bg-primary-theme-light border border-theme flex items-center justify-center mb-3 shadow-2xs",children:e.jsx(Zt,{className:"w-7 h-7 text-primary-theme animate-pulse"})}),e.jsx("p",{className:"font-bold text-sm text-main mb-1",children:"交互式备课白板"}),e.jsx("p",{className:"text-xs text-muted max-w-sm text-center",children:"从左侧组件库拖拽组件至此处,或使用顶部工具栏插入画笔、几何图形与 AI 助教"})]}):null,To=24;function Po({elementId:t,type:r,lessonId:l,readOnly:i=!1,dismissible:o=!0,onExit:d,renderContent:u}){n.useEffect(()=>{if(!o)return;const w=g=>{g.key==="Escape"&&d()};return window.addEventListener("keydown",w),()=>window.removeEventListener("keydown",w)},[d,o]);const[x,a]=n.useState(()=>({width:typeof window>"u"?1024:window.innerWidth,height:typeof window>"u"?768:window.innerHeight}));return n.useEffect(()=>{const w=()=>a({width:window.innerWidth,height:window.innerHeight});return window.addEventListener("resize",w),()=>window.removeEventListener("resize",w)},[]),e.jsxs("div",{"data-testid":"browser-fullscreen-host","data-element-id":t,"data-element-type":r,"data-dismissible":o?"true":"false",style:{pointerEvents:"auto",zIndex:Ja},className:"fixed inset-0 bg-white dark:bg-slate-950 flex flex-col",children:[o?e.jsxs("button",{type:"button","data-testid":"browser-fullscreen-exit",onClick:d,className:"fixed top-4 right-4 z-[100001] px-3 py-2 rounded-xl bg-slate-900/85 hover:bg-slate-900 text-slate-100 text-xs font-bold flex items-center gap-1.5 shadow-2xl backdrop-blur-md border border-white/15 transition-colors cursor-pointer",title:"退出全屏(Esc)",children:[e.jsx(Nn,{size:14}),"退出全屏"]}):e.jsx("span",{className:"fixed top-4 right-4 z-[100001] px-3 py-2 rounded-xl bg-slate-900/85 text-slate-200 text-xs font-bold flex items-center gap-1.5 shadow-2xl border border-white/10 select-none",title:i?"教师已开启全班专注锁定":"由教师端控制,无法在本地退出",children:i?"🔒 教师同步视图":"教师同步视图"}),e.jsx("div",{"data-testid":"browser-fullscreen-content",className:"flex-1 min-h-0 overflow-auto",style:{width:x.width,height:x.height},children:u(x)}),e.jsx("span",{hidden:!0,"data-lesson-id":l})]})}function fn({width:t,height:r,children:l}){return t<=0||r<=0?null:e.jsx(gn,{"data-testid":"widget-fullscreen-stage",width:t,height:r,style:{backgroundColor:"transparent"},children:e.jsx(yn,{children:l})})}const Do={quiz:"📝 随堂测验",timer:"⏱ 计时器",assignment:"📋 作业","code-sandbox":"💻 代码沙箱","html-applet":"🌐 交互课件",rollcall:"🎲 随机点名",presentation:"📽 演示文稿","math-graph":"📐 数学图形",text:"📝 文本"},Eo=({containerSize:t,browserFullscreenElementId:r,isRemoteBrowserFullscreen:l,isBrowserFullscreenDismissible:i,browserFullscreen:o,effectiveFullscreenElementId:d,isRemoteFullscreen:u,isFullscreenDismissible:x,applyFullscreen:a,safeElements:w,lessonId:g,readOnly:D,renderElement:W,children:k})=>{if(t.width<=0||t.height<=0)return null;if(r){const z=w.find(j=>j.id===r);if(!z)return l?e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center bg-slate-900/80 backdrop-blur-xs text-white",children:[e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-400 mb-3"}),e.jsx("p",{className:"text-xs font-medium text-slate-200",children:"正在同步教师端的浏览器全屏组件..."})]}):null;const m=Ue(z);return e.jsx(Po,{elementId:r,type:z.type,data:m,lessonId:g,readOnly:D,dismissible:i,onExit:()=>void o.exit(),renderContent:j=>e.jsx(fn,{width:j.width,height:j.height,children:W(z,{fullscreen:{width:j.width,height:j.height,padding:To}})})})}if(d){const z=w.find(j=>j.id===d);if(!z)return u?e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center bg-slate-900/60 backdrop-blur-xs text-white",children:[e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-400 mb-3"}),e.jsx("p",{className:"text-xs font-medium text-slate-200",children:"正在同步教师端全屏组件..."})]}):null;const m=Ue(z);return e.jsx(Li,{type:z.type,title:Do[z.type]||z.type,data:m,containerSize:t,dismissible:x,onClose:()=>a(null),lessonId:g,elementId:z.id,readOnly:D,renderContent:j=>e.jsx(fn,{width:j.width,height:j.height,children:W(z,{fullscreen:{width:j.width,height:j.height,padding:0}})})})}return e.jsx(e.Fragment,{children:k})},_o=({autoTileEnabled:t,readOnly:r,tilingSplitters:l,activeSplitterDrag:i,activeDropZoneAction:o,handleSplitterPointerDown:d})=>!t||r?null:e.jsxs(e.Fragment,{children:[l.length>0&&e.jsx("div",{className:"absolute inset-0 pointer-events-none z-30",children:l.map(u=>{const x=u.orientation==="horizontal",a=i?.splitter.id===u.id;return e.jsxs("div",{"data-testid":`splitter-${u.orientation}-${u.id}`,className:`absolute pointer-events-auto group flex items-center justify-center select-none ${x?"cursor-row-resize":"cursor-col-resize"}`,style:{left:`${u.x}px`,top:`${u.y}px`,width:`${x?u.length:u.thickness}px`,height:`${x?u.thickness:u.length}px`},onPointerDown:w=>d(w,u),title:x?"拖动调整上下分割高度":"拖动调整左右分割宽度",children:[e.jsx("div",{className:`rounded-full transition-all duration-150 ${x?`w-full h-1 my-auto ${a?"bg-indigo-500 h-1.5 shadow-md":"bg-transparent group-hover:bg-indigo-400/80 group-hover:h-1.5"}`:`h-full w-1 mx-auto ${a?"bg-indigo-500 w-1.5 shadow-md":"bg-transparent group-hover:bg-indigo-400/80 group-hover:w-1.5"}`}`}),e.jsx("div",{className:`absolute rounded-full transition-all duration-150 flex items-center justify-center ${a?"bg-indigo-600 text-white scale-110 shadow-lg":"opacity-0 group-hover:opacity-100 bg-white/95 dark:bg-slate-800/95 text-indigo-600 shadow border border-indigo-200 dark:border-indigo-700"} ${x?"w-8 h-3.5":"h-8 w-3.5"}`,children:e.jsxs("div",{className:`flex ${x?"flex-row gap-0.5":"flex-col gap-0.5"}`,children:[e.jsx("div",{className:"w-1 h-1 rounded-full bg-current opacity-70"}),e.jsx("div",{className:"w-1 h-1 rounded-full bg-current opacity-70"}),e.jsx("div",{className:"w-1 h-1 rounded-full bg-current opacity-70"})]})})]},u.id)})}),o&&o.type!=="swap"&&e.jsx("div",{"data-testid":"directional-split-preview",className:"absolute pointer-events-none rounded-2xl border-3 border-dashed border-indigo-500 bg-indigo-500/20 backdrop-blur-[2px] shadow-2xl flex items-center justify-center transition-all duration-150 z-40 animate-in fade-in zoom-in-95",style:{left:`${o.previewRect.x}px`,top:`${o.previewRect.y}px`,width:`${o.previewRect.width}px`,height:`${o.previewRect.height}px`},children:e.jsx("div",{className:"bg-indigo-600 text-white text-xs md:text-sm font-bold px-4 py-2 rounded-full shadow-lg flex items-center gap-2 select-none animate-bounce",children:e.jsx("span",{children:o.label})})})]}),Ro={quiz:{width:340,height:380},timer:{width:280,height:200},assignment:{width:340,height:400},rollcall:{width:340,height:420},"html-applet":{width:400,height:300},"code-sandbox":{width:400,height:320},"math-graph":{width:400,height:350},presentation:{width:600,height:400},plugin:{width:500,height:400}};function jt(t,r){const l=Ro[t];return l?{width:r?.width||l.width,height:r?.height||l.height}:{width:r?.width||300,height:r?.height||300}}function Ao({containerSize:t,safeElements:r,getCurrentPageElements:l,onElementUpdate:i,lessonId:o,readOnly:d,setLocalGeometry:u,localGeometryRef:x,localGeometryVersion:a,currentPage:w,activeSegmentId:g,pages:D,tileSplitPreferenceRef:W,setIsSyncing:k}){const[z,m]=n.useState(!1),[j,y]=n.useState(null),f=n.useRef(null);n.useEffect(()=>{f.current=j},[j]);const T=n.useCallback(async(v,P,C)=>{if(!i||t.width<=0||t.height<=0)return;const M=v.filter(I=>Qe(I.type));if(M.length===0)return;const q=[],X=new Map,A=new Map;let F=P??W.current;for(const I of M){const G=Ue(I,null);if(!G)continue;!F&&G.tileStackDir&&(F=G.tileStackDir);const le=Zs(I,G,jt(I.type,G));if(le)if(q.push(le),X.set(I.id,G),C){const se=C.indexOf(I.id);A.set(I.id,se>=0?se:void 0)}else A.set(I.id,typeof G.tileOrder=="number"?G.tileOrder:void 0)}if(q.length===0)return;const L=Pa(q,A),p=Sa(L,t,{stackDirection:F});if(p.length===0)return;let $=!1;k(!0);try{for(let I=0;I<L.length;I+=1){const G=L[I],le=X.get(G.id);if(!le)continue;const se=Ma(G,p[I]),ve=Qs(G.shape);if(er(le,se,ve)&&le.tileOrder===I&&le.tileStackDir===F)continue;$=!0,u(G.id,se);const Le={...le,...se,tileOrder:I,tileStackDir:F};le.__preTile||(Le.__preTile=za(G)),Le.__tiled=se;const ze=v.find(ye=>ye.id===G.id)||r.find(ye=>ye.id===G.id);ze&&(ze.data=JSON.stringify(Le)),await i(G.id,Le)}if(!$)return;ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}},[i,t,r,o,u,W,k]),H=n.useCallback(async(v,P)=>{const C=l().filter(M=>Qe(M.type));await T(C,v,P)},[l,T]),Z=n.useCallback(async(v,P)=>{if(!i||v===P)return;const C=r.find(Ce=>Ce.id===v),M=r.find(Ce=>Ce.id===P);if(!C||!M)return;const q=Ue(C,null),X=Ue(M,null);if(!q||!X)return;const A=at(q,C.type==="circle"?"circle":"rect"),F=at(X,M.type==="circle"?"circle":"rect"),L=x.current.get(v),p=x.current.get(P),$={...A,...L||{}},I={...F,...p||{}},G=l().filter(Ce=>Qe(Ce.type)),le=G.findIndex(Ce=>Ce.id===v),se=G.findIndex(Ce=>Ce.id===P),ve=typeof q.tileOrder=="number"?q.tileOrder:le>=0?le:0,Le=typeof X.tileOrder=="number"?X.tileOrder:se>=0?se:1,ze={...q,...I,tileOrder:Le},ye={...X,...$,tileOrder:ve};q.__preTile||(ze.__preTile=at(q,C.type==="circle"?"circle":"rect")),X.__preTile||(ye.__preTile=at(X,M.type==="circle"?"circle":"rect")),ze.__tiled=I,ye.__tiled=$,u(v,I),u(P,$),k(!0);try{await Promise.all([i(v,ze),i(P,ye)]),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}},[i,r,l,u,x,o,k]),J=n.useCallback(async()=>{if(!i)return;const v=[];for(const P of r){const C=Ue(P,null);if(!C||!C.__preTile)continue;const{__preTile:M,__tiled:q,tileOrder:X,...A}=C,F=Qs(P.type==="circle"?"circle":"rect"),L=!q||er(C,q,F);v.push({id:P.id,patch:L?{...A,...M}:A})}if(v.length!==0){k(!0);try{for(const{id:P,patch:C}of v){const M=C.radius!==void 0?"circle":"rect";u(P,at(C,M)),await i(P,C)}ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}}},[i,r,o,u,k]),O=n.useCallback(async(v,P,C)=>{if(!i||v===P)return;const q=l().filter(L=>Qe(L.type)).map(L=>{const p=Ue(L),$=jt(L.type,p),I=x.current.get(L.id);return{id:L.id,x:I?.x??p.x??0,y:I?.y??p.y??0,width:I?.width??p.width??$.width,height:I?.height??p.height??$.height}}),X=12,A={x:X,y:X,width:Math.max(0,t.width-X*2),height:Math.max(0,t.height-X*2)},F=Ra(v,P,C,q,A);if(Object.keys(F).length!==0){k(!0);try{for(const[L,p]of Object.entries(F)){const $=q.find(I=>I.id===L);$&&u(L,Object.assign({x:$.x,y:$.y,width:$.width,height:$.height},p))}await Promise.all(Object.entries(F).map(async([L,p])=>{const $=r.find(ve=>ve.id===L);if(!$)return;const I=Ue($,{}),G=$.type==="circle"?"circle":"rect",se={...at(I,G),...p};u(L,se),await i(L,{...I,...p,__tiled:se})})),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}}},[i,r,l,t,u,x,o,k]),he=n.useCallback(()=>{z&&J(),m(!z)},[z,J]),K=n.useMemo(()=>z?l().filter(P=>Qe(P.type)).map(P=>{let C={};try{C=JSON.parse(P.data)}catch{}const M=jt(P.type,C),q=x.current.get(P.id);return{id:P.id,x:q?.x??C.x??0,y:q?.y??C.y??0,width:q?.width??C.width??M.width,height:q?.height??C.height??M.height}}):[],[z,r,w,g,D,a,l,x]),ue=n.useMemo(()=>!z||K.length<2?[]:Da(K),[z,K]),E=n.useCallback((v,P)=>{if(d)return;v.preventDefault(),v.stopPropagation();const C=P.orientation==="horizontal"?v.clientY:v.clientX;y({splitter:P,startPointerPos:C,initialBoxes:K})},[d,K]),te=n.useRef(H);n.useEffect(()=>{te.current=H},[H]);const U=n.useMemo(()=>z?l().filter(v=>Qe(v.type)).map(v=>v.id).join("|"):"",[z,r,w,g,D,l]);return n.useEffect(()=>{!z||!U||te.current()},[z,U]),n.useEffect(()=>{if(!z||t.width<=0||t.height<=0)return;const v=setTimeout(()=>{te.current()},250);return()=>clearTimeout(v)},[z,t.width,t.height]),n.useEffect(()=>{if(!j)return;const v=C=>{if(!f.current)return;const{splitter:M,startPointerPos:q,initialBoxes:X}=f.current,L=(M.orientation==="horizontal"?C.clientY:C.clientX)-q,p=Ea(M,L,X);for(const[$,I]of Object.entries(p)){const G=X.find(le=>le.id===$);G&&u($,{x:G.x,y:G.y,width:G.width,height:G.height,...I})}},P=async()=>{if(!f.current)return;const{splitter:C,startPointerPos:M,initialBoxes:q}=f.current;if(C.orientation==="horizontal"&&window.event&&window.event.clientY,y(null),i&&q.length>0){k(!0);try{await Promise.all(q.map(async A=>{const F=r.find(L=>L.id===A.id);if(F)try{const L=JSON.parse(F.data),p=x.current.get(A.id);p&&await i(A.id,{...L,...p,__tiled:p})}catch{}})),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}}};return window.addEventListener("pointermove",v),window.addEventListener("pointerup",P),()=>{window.removeEventListener("pointermove",v),window.removeEventListener("pointerup",P)}},[j,i,r,o,u,x,k]),{autoTileEnabled:z,setAutoTileEnabled:m,handleToggleAutoTile:he,currentTilingBoxes:K,tilingSplitters:ue,activeSplitterDrag:j,setActiveSplitterDrag:y,activeSplitterDragRef:f,handleSplitterPointerDown:E,applyAutoTiling:H,applyAutoTilingForElements:T,swapTileElements:Z,restoreAutoTiling:J,insertTileInDirection:O}}const Fo=({showEntrySelector:t,setShowEntrySelector:r,zipUploadInfo:l,zipCandidates:i,handlePropsUpdate:o,fetchCoursewares:d})=>!t||!l?null:e.jsx("div",{className:"absolute inset-0 bg-neutral-900/40 backdrop-blur-[2px] flex items-center justify-center z-[9999] p-4 font-sans",children:e.jsxs("div",{className:"bg-white rounded-xl shadow-2xl overflow-hidden max-w-sm w-full border border-gray-100 flex flex-col scale-100 pointer-events-auto",children:[e.jsxs("div",{className:"px-5 py-4 border-b border-gray-150/60 bg-gray-50 flex justify-between items-center shrink-0",children:[e.jsx("h3",{className:"font-bold text-gray-800 text-sm",children:"选择课件入口页面"}),e.jsx("button",{onClick:()=>r(!1),className:"text-gray-400 hover:text-gray-650 transition-colors text-xl font-light cursor-pointer",children:"×"})]}),e.jsxs("div",{className:"p-5 flex-1 min-h-0 space-y-3",children:[e.jsx("p",{className:"text-xs text-gray-600 leading-relaxed font-medium",children:"ZIP压缩包中含有多个HTML文件,请选择一个作为课件入口:"}),e.jsx("div",{className:"max-h-60 overflow-y-auto border border-gray-200 rounded-lg p-2 bg-gray-50 space-y-1",children:i.map(u=>e.jsxs("button",{onClick:async()=>{try{const x=await fetch("/api/courseware/confirm",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({uuid:l.uuid,name:l.name,entry:u})});if(x.ok){const a=await x.json();o({coursewareUuid:a.uuid,resourceId:""}),r(!1),d({force:!0})}}catch(x){console.error("Failed to confirm entry point:",x)}},className:"w-full text-left p-2 rounded hover:bg-indigo-50 hover:text-indigo-700 text-xs font-semibold font-mono truncate transition-all cursor-pointer",children:["📄 ",u]},u))})]}),e.jsx("div",{className:"px-5 py-3 border-t border-gray-100 bg-gray-50 flex justify-end gap-2 text-xs shrink-0",children:e.jsx("button",{onClick:()=>r(!1),className:"px-4 py-2 text-gray-500 hover:bg-gray-100 rounded-lg transition-colors font-medium border border-gray-200 cursor-pointer",children:"取消"})})]})}),Lo=({isOpen:t,onClose:r,element:l,coursewares:i=[],fetchCoursewares:o,onApplyTemporary:d,onSavePermanent:u})=>{const x=rr.useMemo(()=>{if(!l?.data)return{title:"Interactive Courseware"};try{return typeof l.data=="string"?JSON.parse(l.data):l.data}catch{return{title:"Interactive Courseware"}}},[l]),[a,w]=n.useState(x.title||"Interactive Courseware"),[g,D]=n.useState(x.coursewareUuid||""),[W,k]=n.useState(x.code||""),[z,m]=n.useState(!0),[j,y]=n.useState(!1),[f,T]=n.useState(null);if(n.useEffect(()=>{t&&l&&(w(x.title||"Interactive Courseware"),D(x.coursewareUuid||""),k(x.code||""),m(!0),T(null))},[t,l,x]),n.useEffect(()=>{if(!t)return;const J=O=>{O.key==="Escape"&&r()};return window.addEventListener("keydown",J),()=>window.removeEventListener("keydown",J)},[t,r]),!t||!l)return null;const H=async J=>{y(!0),T(null);try{const O=new FileReader;O.onload=async he=>{const K=he.target?.result;try{const ue=await fetch("/api/courseware/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:J.name.replace(/\.[^/.]+$/,""),filename:J.name,base64Data:K})}),E=await ue.json();ue.ok&&E.uuid?(D(E.uuid),o&&await o({force:!0})):T(E.error||"课件上传失败")}catch(ue){T(ue.message||"网络异常")}finally{y(!1)}},O.readAsDataURL(J)}catch(O){T(O.message||"读取文件失败"),y(!1)}},Z=async()=>{const J={...x,title:a.trim()||"Interactive Courseware",coursewareUuid:g||void 0,code:g?void 0:W};z?d(l.id,J):u&&await u(l.id,J),r()};return e.jsx("div",{className:"fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/60 backdrop-blur-xs select-none animate-in fade-in duration-150",onPointerDown:J=>{J.target===J.currentTarget&&r()},role:"dialog","aria-modal":"true","aria-labelledby":"courseware-props-modal-title",children:e.jsxs("div",{className:"w-full max-w-xl bg-surface border border-theme rounded-2xl shadow-2xl flex flex-col overflow-hidden text-main font-sans animate-in zoom-in-95 duration-150",onPointerDown:J=>J.stopPropagation(),children:[e.jsxs("div",{className:"px-5 py-4 border-b border-theme bg-surface-secondary/50 flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2.5",children:[e.jsx("span",{className:"p-2 rounded-xl bg-primary-theme/10 text-primary-theme border border-primary-theme/20",children:e.jsx(ar,{size:18})}),e.jsxs("div",{children:[e.jsx("h3",{id:"courseware-props-modal-title",className:"text-sm font-bold text-main leading-tight",children:"课堂课件属性临时调整"}),e.jsx("p",{className:"text-xs text-muted mt-0.5",children:"实时调节互动课件展示属性与数据源"})]})]}),e.jsx("button",{onClick:r,className:"p-1.5 rounded-lg text-muted hover:text-main hover:bg-surface-secondary transition-colors cursor-pointer",title:"关闭窗口",children:e.jsx(es,{size:16})})]}),e.jsxs("div",{className:"p-5 space-y-4 max-h-[75vh] overflow-y-auto",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-muted mb-1.5",children:"课件展示标题"}),e.jsx("input",{type:"text",value:a,onChange:J=>w(J.target.value),placeholder:"请输入课件窗口标题...",className:"w-full px-3 py-2 text-xs bg-surface border border-theme hover:border-primary-theme/60 rounded-xl focus:outline-none focus:ring-2 focus:ring-primary-theme/20 text-main transition-all font-medium"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("label",{className:"block text-xs font-semibold text-muted",children:"关联课件源 (选择现有课件包或使用独立代码)"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("select",{value:g,onChange:J=>D(J.target.value),className:"flex-1 px-3 py-2 text-xs bg-surface border border-theme hover:border-primary-theme/60 rounded-xl focus:outline-none focus:ring-1 focus:ring-primary-theme text-main font-medium",children:[e.jsx("option",{value:"",children:"-- 使用下方手写 HTML/JS 代码 --"}),i.map(J=>e.jsxs("option",{value:J.uuid,children:["📦 [互动课件] ",J.name]},J.id||J.uuid))]}),e.jsxs("label",{className:`px-3 py-2 text-xs rounded-xl border border-primary-theme/30 bg-primary-theme/5 hover:bg-primary-theme/10 text-primary-theme font-semibold flex items-center gap-1.5 transition-colors cursor-pointer shrink-0 ${j?"opacity-50 pointer-events-none":""}`,title:"上传本地互动课件包 (.zip / .html)",children:[j?e.jsx(Et,{size:13,className:"animate-spin"}):e.jsx(ys,{size:13}),e.jsx("span",{children:j?"正在上传...":"上传新课件"}),e.jsx("input",{type:"file",accept:".zip,.html,.htm",className:"hidden",onChange:J=>{const O=J.target.files?.[0];O&&H(O)}})]})]}),f&&e.jsxs("div",{className:"p-2.5 rounded-lg bg-rose-500/10 border border-rose-500/20 text-rose-500 text-xs flex items-center gap-2",children:[e.jsx(Dt,{size:14,className:"shrink-0"}),e.jsx("span",{children:f})]}),!g&&e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsxs("span",{className:"text-2xs text-muted flex items-center gap-1 font-semibold",children:[e.jsx(xa,{size:12}),"自定义沙箱代码 (HTML / JavaScript):"]}),e.jsx("span",{className:"text-2xs text-muted/80",children:"已自动注入 LMS Bridge SDK"})]}),e.jsx("textarea",{rows:5,value:W,onChange:J=>k(J.target.value),placeholder:"<!DOCTYPE html><html><body><h1>互动演示</h1>...</body></html>",className:"w-full px-3 py-2 text-xs font-mono bg-surface-secondary/70 border border-theme rounded-xl focus:outline-none focus:ring-1 focus:ring-primary-theme text-main"})]})]}),e.jsx("div",{className:"p-3.5 rounded-xl border border-emerald-500/30 bg-emerald-500/5 space-y-2",children:e.jsxs("label",{className:"flex items-start gap-2.5 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:z,onChange:J=>m(J.target.checked),className:"mt-0.5 rounded border-emerald-400 text-emerald-600 focus:ring-emerald-500 cursor-pointer"}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("span",{className:"text-xs font-bold text-emerald-800 dark:text-emerald-300 flex items-center gap-1.5",children:[e.jsx(ha,{size:14,className:"text-emerald-600"}),"仅在本次课堂临时生效(推荐,不覆盖课程设置中的课件内容)"]}),e.jsx("p",{className:"text-2xs text-emerald-700/80 dark:text-emerald-400/80 mt-0.5",children:z?"当前修改仅即时同步给本堂课的学生设备,不会修改原教案数据库,其他平行班级复用不受影响。":"警告:已取消临时保护,点击应用后将直接持久化更新原课程教案中的课件配置!"})]})]})})]}),e.jsxs("div",{className:"px-5 py-3 border-t border-theme bg-surface-secondary/30 flex items-center justify-between",children:[e.jsx("span",{className:"text-xs text-muted",children:z?"⚡ 即时生效,安全无污染":"💾 将同步写回课程数据库"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:r,className:"px-3.5 py-1.5 rounded-xl text-xs font-semibold text-muted hover:text-main hover:bg-surface-secondary border border-transparent transition-colors cursor-pointer",children:"取消"}),e.jsxs("button",{type:"button",onClick:Z,className:"px-4 py-1.5 rounded-xl text-xs font-bold bg-primary-theme hover:bg-primary-theme/90 text-white shadow-sm flex items-center gap-1.5 transition-transform active:scale-95 cursor-pointer",children:[e.jsx(_n,{size:13}),e.jsx("span",{children:z?"临时应用至本课":"保存并更新课程"})]})]})]})]})})},fs="ABCDEFGHIJKLMNOPQRSTUVWXYZ",Bo=({data:t,lessonId:r,elementId:l})=>{const[i,o]=n.useState({}),[d,u]=n.useState(null),[x,a]=n.useState(null),[w,g]=n.useState(!1),[D,W]=n.useState(null),[k,z]=n.useState(t.submissions||{});n.useEffect(()=>{z(t.submissions||{})},[t.submissions]),n.useEffect(()=>{if(!d||d.role==="student"||!r)return;let F=!1;return fetch(`/api/lessons/${encodeURIComponent(r)}/quiz-submissions`).then(L=>L.ok?L.json():null).then(L=>{if(F||!L?.quizzes)return;const p=L.quizzes.find($=>$.elementId===(l||t.id));p?.submissions&&z($=>({...$,...p.submissions}))}).catch(()=>{}),()=>{F=!0}},[d,r,l]),n.useEffect(()=>{let F=!1;return fetch("/api/students?pageSize=all").then(p=>p.ok?p.json():{data:[]}).then(p=>{if(F)return;const $=Bi(p),I={};for(const G of $)I[G.id]=G.name;o(I)}).catch(()=>{}),(async()=>{try{let p=await fetch("/api/auth/session").catch(()=>null);if((!p||!p.ok)&&(p=await fetch("/api/auth/me").catch(()=>null)),p&&p.ok&&!F){const $=await p.json(),I=$.session||$;I&&typeof I=="object"&&!Array.isArray(I)&&I.role&&u({id:I.id||I.userId,role:I.role,studentId:I.studentId||I.userId||I.id})}}catch{}})(),()=>{F=!0}},[]);const m=Object.entries(k),j=Bn(t),y=j===null?void 0:j,f=D?.correctIndex??y,T=typeof t.passScore=="number"?t.passScore:60,H=d?.studentId||d?.id,Z=H?k[H]:null,J=typeof window<"u"&&(new URLSearchParams(window.location?.search||"").get("mode")==="student_live"||(window.location?.hash||"").includes("student_live")),O=d?.role==="student"||J,he=!!Z||!!D,K=!O||he,ue=F=>{if(typeof F=="number"&&!isNaN(F))return F;if(typeof F=="string"){const L=parseFloat(F);return isNaN(L)?null:L}return null},E=Array.isArray(t.options)?t.options.map(F=>String(F)):[],te=F=>{const L=sr(F,E);return L===null?void 0:L},U=async()=>{if(x===null||w)return;g(!0);const F=fs[x]||String(x),L=x;try{const p=r||"current",$=l||t.id||"quiz",I=await fetch(`/api/lessons/${encodeURIComponent(p)}/quiz-submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elementId:$,answer:L})}),G=await I.json().catch(()=>null);if(I.ok&&G?.success){W({isCorrect:G.isCorrect,score:G.score,answer:F,correctIndex:typeof G.correctIndex=="number"?G.correctIndex:void 0});const le=G.studentId||H||"me";z(se=>({...se,[le]:{answer:x,score:G.score,time:Date.now()}})),window.dispatchEvent(new CustomEvent("openlearn:segment-gate-changed",{detail:{lessonId:p}}))}}catch{}finally{g(!1)}},v=m.map(([F,L])=>{const p=te(L),$=ue(L.score),I=p!==void 0&&f!==void 0?p===f:$!==null?$>=T:!1;return{sid:F,v:L,answerIdx:p,scoreNum:$,isCorrect:I}}),P=m.length,C=v.filter(F=>F.isCorrect).length,M=P>0?Math.round(C/P*100):0,q=v.map(F=>F.scoreNum).filter(F=>F!==null),X=q.length>0?q.reduce((F,L)=>F+L,0)/q.length:null,A=F=>{if(F==null)return"-";const L=typeof F=="number"?F:Number(F),p=isNaN(L)?new Date(String(F)):new Date(L);return isNaN(p.getTime())?"-":p.toLocaleTimeString()};return e.jsxs("div",{className:"max-w-2xl mx-auto space-y-6",children:[e.jsx("h3",{className:"text-xl font-bold text-gray-800","data-testid":"quiz-question",children:t.question}),D&&e.jsxs("div",{"data-testid":"quiz-feedback",className:`p-4 rounded-xl border flex items-center justify-between text-sm font-bold ${D.isCorrect?"bg-emerald-50 border-emerald-300 text-emerald-800":"bg-rose-50 border-rose-300 text-rose-800"}`,children:[e.jsx("span",{children:D.isCorrect?`🎉 回答正确!得分:${D.score} 分`:`❌ 回答错误。得分:${D.score} 分`}),e.jsx("span",{className:"text-xs font-normal",children:"提交已实时同步至教师大屏"})]}),e.jsx("div",{className:"flex flex-col gap-3",children:(t.options||[]).map((F,L)=>{const p=x===L,$=f===L;let I="bg-gray-50 border-gray-200 text-gray-700";return K&&$?I="bg-green-50 border-green-300 text-green-800":p?I="bg-indigo-50 border-indigo-400 text-indigo-900 ring-2 ring-indigo-200 shadow-xs":O&&!he&&(I="bg-white hover:bg-gray-50 border-gray-200 text-gray-800 cursor-pointer"),e.jsxs("div",{"data-testid":`quiz-option-${L}`,onClick:()=>{O&&!he&&a(L)},className:`px-5 py-4 text-left rounded-xl text-base border-2 transition-all ${I}`,children:[e.jsxs("span",{className:"font-bold text-indigo-600 mr-3",children:[fs[L],"."]}),F,K&&$&&e.jsx("span",{className:"ml-2 text-xs font-bold text-green-600",children:"✓ 正确答案"})]},L)})}),O&&!he&&e.jsx("div",{className:"pt-2 flex justify-end",children:e.jsx("button",{"data-testid":"quiz-submit-btn",disabled:x===null||w,onClick:U,className:"px-6 py-2.5 bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed text-white font-bold text-sm rounded-xl shadow-sm transition-all cursor-pointer",children:w?"提交中...":"提交答案"})}),!O&&(P===0?e.jsx("div",{className:"mt-4 p-4 bg-gray-50 rounded-xl text-center text-sm text-gray-400",children:"暂无学生提交"}):e.jsxs("div",{className:"mt-4 space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-4 gap-3","data-testid":"quiz-summary",children:[e.jsxs("div",{className:"bg-gray-50 rounded-xl p-3 text-center",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"提交"}),e.jsx("div",{className:"text-xl font-bold text-gray-700","data-testid":"quiz-stat-submitted",children:P})]}),e.jsxs("div",{className:"bg-green-50 rounded-xl p-3 text-center",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"通过"}),e.jsx("div",{className:"text-xl font-bold text-green-600","data-testid":"quiz-stat-passed",children:C})]}),e.jsxs("div",{className:"bg-indigo-50 rounded-xl p-3 text-center",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"通过率"}),e.jsxs("div",{className:"text-xl font-bold text-indigo-600",children:[M,"%"]})]}),e.jsxs("div",{className:"bg-amber-50 rounded-xl p-3 text-center",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"均分"}),e.jsx("div",{className:"text-xl font-bold text-amber-600",children:X!==null?X.toFixed(1):"-"})]})]}),e.jsx("div",{className:"overflow-x-auto border border-gray-200 rounded-xl",children:e.jsxs("table",{className:"w-full text-sm","data-testid":"quiz-submissions-table",children:[e.jsx("thead",{className:"bg-gray-50 text-gray-500 text-xs uppercase",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2 text-left",children:"学生"}),e.jsx("th",{className:"px-4 py-2 text-left",children:"答案"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"得分"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"提交时间"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-100",children:v.map(({sid:F,v:L,answerIdx:p,scoreNum:$,isCorrect:I})=>{const G=p!==void 0&&p>=0&&p<fs.length?fs[p]:"-",le=$!==null?$:I?100:0,se=i[F]||F;return e.jsxs("tr",{className:"hover:bg-gray-50","data-testid":`quiz-row-${F}`,children:[e.jsx("td",{className:"px-4 py-2 font-medium text-gray-700",children:se}),e.jsxs("td",{className:`px-4 py-2 font-mono ${I?"text-green-600 font-bold":"text-red-500"}`,children:[G,I?" ✓":""]}),e.jsx("td",{className:`px-4 py-2 text-right font-mono font-bold ${le>=T?"text-green-600":"text-gray-600"}`,children:le}),e.jsx("td",{className:"px-4 py-2 text-right text-gray-500 text-xs",children:A(L.time??L.timestamp)})]},F)})})]})})]}))]})};qi.registerHostBuiltin("quiz",Bo);const Wo=80,nt=({title:t="教师已开启全班专注锁定,当前为只读演示视图"})=>e.jsx("div",{"data-testid":"whiteboard-readonly-lock-cover",className:"absolute inset-0 z-50 bg-transparent cursor-not-allowed select-none",style:{pointerEvents:"auto"},onClick:r=>{r.stopPropagation(),r.preventDefault()},onPointerDown:r=>{r.stopPropagation(),r.preventDefault()},onMouseDown:r=>{r.stopPropagation(),r.preventDefault()},onTouchStart:r=>{r.stopPropagation(),r.preventDefault()},title:t});let it={data:[],ts:0,inflight:null};const Ho=[{id:"page-0",title:"P1 · 引入导入",order:0},{id:"page-1",title:"P2 · 核心讲解",order:1},{id:"page-2",title:"P3 · 互动练习",order:2}],pn=4,il=n.forwardRef(({lessonId:t,elements:r,onElementAdd:l,onElementUpdate:i,onElementDelete:o,onClearBoard:d,onRefresh:u,enableAutoAI:x,activeSegmentId:a,onSegmentSync:w,initialPage:g,classroomTools:D,onExecuteTool:W,userRole:k="teacher",isEditMode:z=!0,readOnly:m=!1,classId:j,studentId:y,studentName:f,broadcastFullscreen:T=!1,fullscreenBroadcastClassId:H=null,followRemoteFullscreen:Z=!1,onFullscreenSync:J,hidePageBar:O=!1,onPagesStateChange:he,onElementDragChange:K,onElementDropCheck:ue},E)=>{const[te,U]=n.useState({}),v=n.useMemo(()=>{const s=Array.isArray(r)?r:[];return Object.keys(te).length===0?s:s.map(h=>te[h.id]||h)},[r,te]),P=Wi(s=>s.theme),C=Hi(s=>s.scale)/100;n.useEffect(()=>{cn.setTheme(P)},[P]);const M=cn.getTokens(),q=P==="dark"||P==="chalkboard",X=wn(s=>s.extensionPoints.get("whiteboard.renderer")),[A,F]=n.useState("cursor"),[L,p]=n.useState("#facc15"),[$,I]=n.useState(0),[G,le]=n.useState(!0),[se,ve]=n.useState(null),Le=n.useRef(null);n.useEffect(()=>{Le.current=se},[se]);const ze=n.useRef(null),[ye,Ce]=n.useState(null),xt=n.useRef(null);n.useEffect(()=>{xt.current=ye},[ye]);const re=n.useRef(null),[ge,_]=n.useState(void 0),b=n.useRef(ge);n.useEffect(()=>{b.current=ge},[ge]);const[V,ae]=n.useState(!1),[Q,oe]=n.useState(Ho),[_e,Ge]=n.useState(!1),[gt,Wt]=n.useState(null),[Ht,ss]=n.useState(""),[Wn,or]=n.useState(null);n.useEffect(()=>{he?.({pages:Q,currentPage:$})},[Q,$,he]),n.useEffect(()=>{const s=v.find(h=>h.type==="page_meta");if(s){const h=Ue(s);Array.isArray(h?.pages)&&h.pages.length>0&&oe(h.pages)}},[r]);const lr=n.useRef(!1);n.useEffect(()=>{if(lr.current||!Array.isArray(Q)||Q.length===0)return;const s=Number(g);Number.isFinite(s)&&s>0&&s<Q.length&&I(s),lr.current=!0},[Q]);const cr=n.useCallback(s=>An(s,$,Q),[Q,$]),dr=n.useMemo(()=>Wa(v,$,Q,a),[v,$,Q,a]),ht=n.useCallback(()=>dr,[dr]),_t=n.useRef(null),Ns=n.useRef(null);n.useEffect(()=>(Ns.current=null,()=>{_t.current&&(clearTimeout(_t.current),_t.current=null)}),[t]);const Hn=n.useCallback(s=>{k!=="teacher"||!t||Ns.current!==s&&(_t.current&&clearTimeout(_t.current),_t.current=setTimeout(()=>{fetch(`/api/classroom/sessions/${encodeURIComponent(t)}/view-state`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({currentPage:s})}).then(h=>{h.ok?Ns.current=s:h.status===429&&console.warn("[InteractiveWhiteboard] view-state rate-limited (HTTP 429), skipping transient update.")}).catch(()=>{})},500))},[k,t]);n.useEffect(()=>{m&&(me(null),Me(null),F("cursor"),ot(null),ks(!1),Ss(null))},[m]);const Xt=s=>{const h=v.find(c=>c.type==="page_meta");h&&i?i(h.id,{pages:s}):l&&l("page_meta",{pages:s}),Ne.current&&Ne.current.emit("whiteboard-update",{roomId:t,type:"page-meta-update",payload:{pages:s}})},ur=s=>{I(s),or(null),Ne.current&&Ne.current.emit("whiteboard-update",{roomId:t,type:"page-change",payload:{page:s}}),Hn(s)},xr=s=>{const{newPages:h,newIndex:c}=Ha(Q,s);oe(h),I(c),Xt(h),Ne.current&&Ne.current.emit("whiteboard-update",{roomId:t,type:"page-change",payload:{page:c}})},hr=(s,h)=>{if(!h.trim()){Wt(null);return}const c=Xa(Q,s,h);oe(c),Xt(c),Wt(null),ss("")},mr=s=>{const h=Q[s];if(!h)return;const c=Oa(Q,s);if(!c)return;const{newPages:N,newIndex:R,newPage:B}=c;oe(N),I(R),Xt(N),v.filter(ne=>ne.type!=="page_meta"&&(()=>{try{const xe=JSON.parse(ne.data);return(xe.page??0)===s||xe.pageId===h.id}catch{return s===0}})()).forEach(ne=>{try{const xe=JSON.parse(ne.data);l&&l(ne.type,{...xe,page:R,pageId:B.id,x:(xe.x??100)+20,y:(xe.y??100)+20})}catch(xe){console.error("Failed duplicating page element:",xe)}})},fr=s=>{if(Q.length<=1){Ie({title:"无法删除",message:"至少需要保留一个白板页面!",type:"alert",onConfirm:()=>{}});return}const h=Q[s],c=v.filter(R=>R.type!=="page_meta"&&(()=>{try{const B=JSON.parse(R.data);return(B.page??0)===s||B.pageId===h.id}catch{return s===0}})()),N=()=>{o&&c.forEach(ee=>o(ee.id));const R=Q.filter((ee,ne)=>ne!==s).map((ee,ne)=>({...ee,order:ne}));oe(R);const B=Math.min($,R.length-1);I(B),Xt(R)};c.length>0?Ie({title:"确认删除白板页面",message:`页面 [${h.title}] 包含 ${c.length} 个组件,删除页面将同时清理该页面的组件,是否确定删除?`,type:"confirm",onConfirm:N}):N()},pr=(s,h)=>{const c=Ia(Q,s,h);if(!c)return;const{newPages:N,targetIndex:R}=c;oe(N),$===s?I(R):$===R&&I(s),Xt(N)},[Re,ot]=n.useState(null),[br,ks]=n.useState(!1),Xn=n.useRef(null),[rs,gr]=n.useState({width:0,height:0}),[yr,wr]=n.useState({width:0,height:0}),Te=n.useRef(null),[Cs,we]=n.useState(!1),Ne=n.useRef(null),[On,jr]=n.useState({}),[Xo,Oo]=n.useState({}),[Io,qo]=n.useState({}),[Yo,Jo]=n.useState({}),[In,vr]=n.useState({});n.useEffect(()=>{if(!t)return;let s=!1;return fetch(`/api/lessons/${encodeURIComponent(t)}/quiz-counts`).then(h=>h.ok?h.json():null).then(h=>{if(!h?.quizzes||s)return;const c={};for(const N of h.quizzes)c[N.elementId]=N.submissionCount;vr(c)}).catch(()=>{}),()=>{s=!0}},[t]),ga({types:["quiz.answered"]},s=>{!s.elementId||s.lessonId!==t||vr(h=>({...h,[s.elementId]:(h[s.elementId]??0)+1}))});const[qn,Ss]=n.useState(null),[Yn,Jn]=n.useState(null),Nr=rn(s=>s.remoteFullscreenElementId),vt=Z&&!!Nr,lt=vt?Nr:qn,Un=!vt,kr=rn(s=>s.remoteBrowserFullscreenElementId),ns=Z&&!!kr,Rt=ns?kr:Yn,Gn=!ns,Nt=Ua({elementId:Rt,enableNativeFullscreen:!ns,onChange:s=>{Jn(s),T&&Ne.current&&Ne.current.emit("teacher-broadcast-fullscreen",{classId:H,lessonId:t,elementId:s,mode:"browser"})}});n.useEffect(()=>{Rt&&!v.some(s=>s.id===Rt)&&Nt.exit()},[Rt,v,Nt]);const Cr=n.useRef(J);n.useEffect(()=>{Cr.current=J},[J]);const mt=s=>{Ss(s),J?.(s),T&&Ne.current&&Ne.current.emit("teacher-broadcast-fullscreen",{classId:H,lessonId:t,elementId:s,mode:"board"})};n.useEffect(()=>{if(T)return()=>{Cr.current?.(null);const s={classId:H,lessonId:t,elementId:null};Ne.current?.emit("teacher-broadcast-fullscreen",{...s,mode:"board"}),Ne.current?.emit("teacher-broadcast-fullscreen",{...s,mode:"browser"})}},[T,H,t]);const is=!!lt&&!v.some(s=>s.id===lt),Ot=n.useRef(null);n.useEffect(()=>{if(!is||!vt){Ot.current=null;return}if(Ot.current==null){Ot.current=Date.now();return}Date.now()-Ot.current>=3e3&&(Ot.current=null,Xi.getState().clearRemoteFullscreen())},[is,vt]),n.useEffect(()=>{!is||vt||(Ss(null),J?.(null),T&&Ne.current&&Ne.current.emit("teacher-broadcast-fullscreen",{classId:H,lessonId:t,elementId:null}))},[is,vt,T,H,t,J]);const[It,qt]=n.useState(null),Be=n.useRef(new Map),[zs,kt]=n.useState(0),ct=n.useCallback((s,h)=>{Be.current.set(s,h),kt(c=>c+1)},[]),Sr=n.useCallback(s=>{Be.current.delete(s)&&kt(h=>h+1)},[]);n.useEffect(()=>{Be.current.clear(),kt(s=>s+1)},[t]),n.useEffect(()=>{if(Be.current.size!==0){for(const s of r){const h=Be.current.get(s.id);if(!h)continue;const c=Ue(s,null);if(!c){Be.current.delete(s.id);continue}const N=Object.keys(h);er(c,h,N)&&Be.current.delete(s.id)}kt(s=>s+1)}},[r]);const zr=n.useRef(void 0),{autoTileEnabled:Oe,handleToggleAutoTile:Vn,tilingSplitters:Kn,activeSplitterDrag:Zn,handleSplitterPointerDown:Qn,applyAutoTiling:Mr,applyAutoTilingForElements:At,swapTileElements:$r,insertTileInDirection:Tr}=Ao({containerSize:rs,safeElements:v,getCurrentPageElements:ht,onElementUpdate:i,lessonId:t,readOnly:m,setLocalGeometry:ct,localGeometryRef:Be,localGeometryVersion:zs,currentPage:$,activeSegmentId:a,pages:Q,tileSplitPreferenceRef:b,setIsSyncing:we});n.useEffect(()=>{zr.current=At,ze.current=$r,re.current=Tr},[At,$r,Tr]);const Pr=n.useMemo(()=>{const s=[];for(const h of ht())try{const c=Ue(h),N=Be.current.get(h.id),R=jt(h.type,c);s.push({x:N?.x??(Number.isFinite(c.x)?c.x:0),y:N?.y??(Number.isFinite(c.y)?c.y:0),width:N?.width??(Number.isFinite(c.width)?c.width:R.width),height:N?.height??(Number.isFinite(c.height)?c.height:R.height)})}catch{}return Fa(s)},[ht,zs]),Dr=n.useMemo(()=>La(yr,Pr,Wo),[yr,Pr]),Ke=n.useCallback((s,h)=>{const c=Te.current;if(!c)return null;const N=c.getBoundingClientRect();return Ba(s,h,N,{scrollLeft:c.scrollLeft,scrollTop:c.scrollTop})},[]),Se=n.useRef(null),ke=n.useRef(null),Ct=n.useRef(null),[fe,Er]=n.useState(null),me=s=>{k==="teacher"&&Er(s)},[Ft,ei]=n.useState(null),Me=s=>{k==="teacher"&&ei(s)},[_r,Rr]=n.useState(null),[St,Ms]=n.useState(null),Yt=n.useRef(null),[ti,Ie]=n.useState(null),[si,Ar]=n.useState(""),[Fr,$s]=n.useState(null),[zt,dt]=n.useState(null),[as,Mt]=n.useState(null),[Ts,Lr]=n.useState(null),[Br,Ps]=n.useState({}),[Wr,Ds]=n.useState({}),[Hr,Es]=n.useState([]),[ri,ni]=n.useState([]),[ii,ai]=n.useState(null),[oi,Xr]=n.useState(!1),Jt=n.useRef(null),Ut=async s=>{const h=Date.now();if(!s?.force&&it.data.length>0&&h-it.ts<3e4){Es(it.data);return}if(it.inflight&&!s?.force){const R=await it.inflight;Es(R);return}const N=(async()=>{try{const R=await fetch("/api/courseware");if(R.ok){const B=await R.json();return it={data:Array.isArray(B)?B:[],ts:Date.now(),inflight:null},Es(it.data),it.data}}catch(R){console.error("Error fetching coursewares:",R)}finally{it.inflight=null}return it.data})();it.inflight=N,await N};n.useEffect(()=>{if(fe){const s=v.find(h=>h.id===fe);s?(s.type==="html-applet"?Jt.current!==fe&&(Jt.current=fe,Ut()):Jt.current=null,dt(Ue(s,{}))):(Jt.current=null,dt(null),Mt(null))}else Jt.current=null,dt(null),Mt(null)},[fe,r]);const $t=async s=>{const h=v.find(ee=>ee.id===fe);if(!h)return"noop";const N={...Ue(h,{}),...s},R=h.data,B=JSON.stringify(N);if(R!==B&&(Ps(ee=>{const ne=ee[h.id]?[...ee[h.id]]:[];return ne.length>=30&&ne.shift(),ne.push(R),{...ee,[h.id]:ne}}),Ds(ee=>({...ee,[h.id]:[]}))),i){we(!0);try{return await i(h.id,N),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u(),"saved"}catch(ee){return console.error("更新属性失败:",ee),"failed"}finally{we(!1)}}return"noop"},li=(s,h)=>{const c=v.find(R=>R.id===s);if(!c)return;const N=JSON.stringify(h);U(R=>({...R,[s]:{...c,data:N}})),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,temporary:!0},timestamp:Date.now(),correlationId:t})},ci=async(s,h)=>{if(U(c=>{const N={...c};return delete N[s],N}),i){we(!0);try{await i(s,h),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s},timestamp:Date.now(),correlationId:t}),u&&u()}catch(c){console.error("保存课件属性失败:",c)}finally{we(!1)}}},di=async()=>{if(!fe)return;const s=v.find(B=>B.id===fe);if(!s)return;const h=Br[fe]||[];if(h.length===0)return;const c=h[h.length-1],N=h.slice(0,h.length-1),R=s.data;if(Ds(B=>{const ee=B[fe]?[...B[fe]]:[];return ee.push(R),{...B,[fe]:ee}}),Ps(B=>({...B,[fe]:N})),i){we(!0);try{const B=JSON.parse(c);dt(B),await i(fe,B),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}catch(B){console.error("撤销修改失败:",B)}finally{we(!1)}}},ui=async()=>{if(!fe)return;const s=v.find(B=>B.id===fe);if(!s)return;const h=Wr[fe]||[];if(h.length===0)return;const c=h[h.length-1],N=h.slice(0,h.length-1),R=s.data;if(Ps(B=>{const ee=B[fe]?[...B[fe]]:[];return ee.push(R),{...B,[fe]:ee}}),Ds(B=>({...B,[fe]:N})),i){we(!0);try{const B=JSON.parse(c);dt(B),await i(fe,B),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}catch(B){console.error("重做修改失败:",B)}finally{we(!1)}}},xi=(s,h)=>{dt(c=>c&&{...c,[s]:h})},hi=(s,h)=>{$t({[s]:h})},Or=s=>{dt(h=>h&&{...h,...s}),$t(s)},mi=(s,h)=>{const c=parseFloat(h);isNaN(c)||$t({[s]:c})},fi=(s,h)=>{dt(c=>{if(!c)return c;const N=[...c.options||[]];return N[s]=h,{...c,options:N}})},pi=(s,h)=>{if(!zt)return;const c=[...zt.options||[]];c[s]=h,$t({options:c})},bi=()=>{if(!zt)return;const s=zt.options||[],c="ABCDEFGHIJKLMNOPQRSTUVWXYZ"[s.length]||`Option ${s.length+1}`,N=[...s,`选项 ${c}`];dt(R=>R&&{...R,options:N}),$t({options:N})},gi=s=>{if(!zt)return;const h=(zt.options||[]).filter((c,N)=>N!==s);dt(c=>c&&{...c,options:h}),$t({options:h})};n.useEffect(()=>{const s=()=>{Me(null)};return window.addEventListener("click",s),()=>window.removeEventListener("click",s)},[]);const os=n.useRef(K);n.useEffect(()=>{os.current=K},[K]);const Ir=n.useRef(ue);n.useEffect(()=>{Ir.current=ue},[ue]);const _s=(s,h,c)=>{if(k!=="teacher")return;s.preventDefault();const N=Be.current.get(h),R=N?.x??c.x??0,B=N?.y??c.y??0,ee={id:h,initialX:R,initialY:B,currentX:R,currentY:B,startPointerX:s.clientX,startPointerY:s.clientY,data:{...c,...N??{},x:R,y:B}};Se.current=ee,qt(ee);const ne=v.find(xe=>xe.id===h);os.current?.({elementId:h,elementType:ne?.type||"unknown",elementData:ee.data,clientX:s.clientX,clientY:s.clientY,initialPage:$,initialSegmentId:ee.data.segmentId||a})},Rs=s=>{},As=async s=>{},ls=(s,h,c,N,R,B,ee)=>{if(k!=="teacher")return;s.preventDefault(),s.stopPropagation();const ne={id:h,corner:c,startX:s.clientX,startY:s.clientY,initialX:N,initialY:R,initialWidth:B,initialHeight:ee},xe={id:h,x:N,y:R,width:B,height:ee};ke.current=ne,Ct.current=xe,Rr(ne),Ms(xe)},cs=s=>{},ds=async s=>{};n.useEffect(()=>{if(!It)return;const s=c=>{if(!Se.current)return;const N=c.clientX-Se.current.startPointerX,R=c.clientY-Se.current.startPointerY,B=Se.current.initialX,ee=Se.current.initialY;Se.current.currentX=B+N,Se.current.currentY=ee+R,qt({...Se.current});const ne=v.find(xe=>xe.id===Se.current?.id);if(os.current?.({elementId:Se.current.id,elementType:ne?.type||"unknown",elementData:Se.current.data,clientX:c.clientX,clientY:c.clientY,initialPage:$,initialSegmentId:Se.current.data?.segmentId||a}),Oe){const xe=Ke(c.clientX,c.clientY);if(xe){const pe=xe.x,je=xe.y,Pe=[];let De=0;for(const Ee of ht())if(Qe(Ee.type)&&(De+=1,Ee.id!==Se.current.id))try{const Lt=JSON.parse(Ee.data),$e=Zs(Ee,Lt,jt(Ee.type,Lt));if(!$e)continue;const Ae=Be.current.get(Ee.id);Pe.push({id:Ee.id,x:Ae?.x??$e.x,y:Ae?.y??$e.y,width:Ae?.width??$e.width,height:Ae?.height??$e.height})}catch{}const et=Ta({x:pe,y:je},Pe);if(et){const Lt={x:12,y:12,width:Math.max(0,rs.width-24),height:Math.max(0,rs.height-24)},$e=_a(et,{x:pe,y:je},Lt,De);Ce($e),Le.current!==et.id&&ve(et.id)}else Ce(null),Le.current!==null&&ve(null)}}},h=async c=>{if(!Se.current)return;const N=Se.current.currentX,R=Se.current.currentY,B=Se.current.id,ee=Se.current.data,ne=Se.current.startPointerX,xe=Se.current.startPointerY,pe=Math.abs(c.clientX-ne)>pn||Math.abs(c.clientY-xe)>pn,je=pe?Ir.current?.(c,B):!1;os.current?.(null);const Pe=xt.current;if(Ce(null),ve(null),!pe||je){Se.current=null,qt(null);return}if(Oe){Se.current=null,qt(null),Pe&&Pe.targetId&&Pe.targetId!==B?Pe.type==="swap"?ze.current?.(B,Pe.targetId):re.current?.(B,Pe.targetId,Pe.type):Mr();return}const De=Be.current.get(B),et={...at(ee,ee?.radius!==void 0?"circle":"rect"),...De??{},x:N,y:R};if(ct(B,et),Se.current=null,qt(null),i){we(!0);try{await i(B,{...ee,...De??{},x:N,y:R}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}catch(Ee){console.error("Drag end update error:",Ee),De?ct(B,De):Sr(B)}finally{we(!1)}}};return window.addEventListener("pointermove",s),window.addEventListener("pointerup",h),()=>{window.removeEventListener("pointermove",s),window.removeEventListener("pointerup",h)}},[It,i,t,ct,Oe,ht]),n.useEffect(()=>{if(!_r||!St)return;const s=c=>{if(!ke.current||!Ct.current)return;const N=c.clientX-ke.current.startX,R=c.clientY-ke.current.startY;let B=ke.current.initialX,ee=ke.current.initialY,ne=ke.current.initialWidth,xe=ke.current.initialHeight;const pe=150,je=100,{corner:Pe}=ke.current;if(Pe==="bottom-right")ne=Math.max(pe,ke.current.initialWidth+N),xe=Math.max(je,ke.current.initialHeight+R);else if(Pe==="bottom-left"){const De=ke.current.initialWidth-N;De>=pe&&(ne=De,B=ke.current.initialX+N),xe=Math.max(je,ke.current.initialHeight+R)}else if(Pe==="top-right"){ne=Math.max(pe,ke.current.initialWidth+N);const De=ke.current.initialHeight-R;De>=je&&(xe=De,ee=ke.current.initialY+R)}else if(Pe==="top-left"){const De=ke.current.initialWidth-N;De>=pe&&(ne=De,B=ke.current.initialX+N);const et=ke.current.initialHeight-R;et>=je&&(xe=et,ee=ke.current.initialY+R)}Ct.current={id:ke.current.id,x:B,y:ee,width:ne,height:xe},Ms({...Ct.current})},h=async c=>{if(!ke.current||!Ct.current)return;const{id:N}=ke.current,{x:R,y:B,width:ee,height:ne}=Ct.current,xe=v.find(De=>De.id===N);let pe={};if(xe)try{pe=JSON.parse(xe.data)}catch{}const je=Be.current.get(N),Pe={...at(pe,pe?.radius!==void 0?"circle":"rect"),...je??{},x:R,y:B,width:ee,height:ne};if(ct(N,Pe),ke.current=null,Ct.current=null,Rr(null),Ms(null),xe&&i)try{we(!0),await i(N,{...pe,...je??{},x:R,y:B,width:ee,height:ne}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}catch(De){console.error("Resize end update error:",De),je?ct(N,je):Sr(N)}finally{we(!1)}};return window.addEventListener("pointermove",s),window.addEventListener("pointerup",h),()=>{window.removeEventListener("pointermove",s),window.removeEventListener("pointerup",h)}},[_r,St,r,i,t,ct]);const Tt=s=>{m||Ie({type:"confirm",title:"删除组件",message:"您确定要从白板中删除这个组件或图形吗?该操作不可撤销。",onConfirm:async()=>{we(!0);try{if(Be.current.delete(s),kt(h=>h+1),Oe){const h=ht().filter(c=>c.id!==s&&Qe(c.type));h.length>0&&await zr.current?.(h)}o?await o(s):await fetch(`/api/lessons/${t}/whiteboard/${s}`,{method:"DELETE"}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u(),me(null)}catch(h){console.error("Delete element failed:",h)}finally{we(!1),Ie(null)}}})},yi=()=>{m||Ie({type:"confirm",title:"清空白板",message:"您确定要清空画布上的所有组件、图形和线条吗?此操作将永久清空白板且不可逆!",onConfirm:async()=>{we(!0);try{d?await d():await fetch(`/api/lessons/${t}/whiteboard`,{method:"DELETE"}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u(),me(null)}catch(s){console.error("Clear board failed:",s)}finally{we(!1),Ie(null)}}})},wi=()=>{m||Ie({type:"confirm",title:"重置白板",message:"您确定要将白板重置为开始上课的状态吗?您在白板上做的所有临时修改都将被重置。",onConfirm:async()=>{we(!0);try{await fetch(`/api/lessons/${t}/whiteboard/reset`,{method:"POST"}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u(),me(null)}catch(s){console.error("Reset board failed:",s)}finally{we(!1),Ie(null)}}})};n.useEffect(()=>{const s=h=>{const c=h.target,N=c.tagName==="INPUT"||c.tagName==="TEXTAREA"||c.isContentEditable;if((h.key==="Delete"||h.key==="Backspace")&&fe&&(N||(Tt(fe),me(null))),Oe&&fe&&!N&&h.altKey){let R=null;if(h.key==="ArrowLeft"||h.key==="h"||h.key==="H"?R="left":h.key==="ArrowRight"||h.key==="l"||h.key==="L"?R="right":h.key==="ArrowUp"||h.key==="k"||h.key==="K"?R="up":(h.key==="ArrowDown"||h.key==="j"||h.key==="J")&&(R="down"),R){const B=[];let ee=null;for(const ne of ht())if(Qe(ne.type))try{const xe=JSON.parse(ne.data),pe=Zs(ne,xe,jt(ne.type,xe));if(!pe)continue;const je=Be.current.get(ne.id),Pe={id:ne.id,x:je?.x??pe.x,y:je?.y??pe.y,width:je?.width??pe.width,height:je?.height??pe.height};B.push(Pe),ne.id===fe&&(ee=Pe)}catch{}if(ee&&B.length>1){const ne=$a(ee,B,R);ne&&(h.preventDefault(),h.stopPropagation(),h.shiftKey?ze.current?.(fe,ne.id):me(ne.id))}}}};return window.addEventListener("keydown",s),()=>window.removeEventListener("keydown",s)},[fe,Oe,ht]);const qr=()=>{Yt.current&&clearTimeout(Yt.current),x&&(Yt.current=setTimeout(async()=>{we(!0);try{(await fetch(`/api/lessons/${t}/ai-tutor`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elements:v.map(h=>({type:h.type,data:JSON.parse(h.data)}))})})).ok&&(ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u())}catch(s){console.error(s)}finally{we(!1)}},6e4))};n.useEffect(()=>(qr(),()=>{Yt.current&&clearTimeout(Yt.current)}),[r]),n.useEffect(()=>{const s=Oi();Ne.current=s,s.emit("join-room",t);const h=c=>{c.type==="temp-draw"?jr(N=>({...N,[c.userId]:c.payload})):c.type==="temp-end"?jr(N=>{const R={...N};return delete R[c.userId],R}):c.type==="refresh"?u&&u():c.type==="segment-change"?w&&c.payload?.segmentId&&w(c.payload.segmentId):c.type==="page-change"?typeof c.payload?.page=="number"&&I(c.payload.page):c.type==="page-meta-update"&&Array.isArray(c.payload?.pages)&&oe(c.payload.pages)};return Ne.current.on("whiteboard-sync",h),()=>{Ne.current?.off("whiteboard-sync",h)}},[t,u,w]),n.useEffect(()=>{if(!Te.current)return;const s=new ResizeObserver(c=>{for(let N of c)Te.current&&(gr({width:Te.current.offsetWidth,height:Te.current.offsetHeight}),wr({width:Te.current.clientWidth,height:Te.current.clientHeight}))});s.observe(Te.current);const h=()=>{Te.current&&(gr({width:Te.current.offsetWidth,height:Te.current.offsetHeight}),wr({width:Te.current.clientWidth,height:Te.current.clientHeight}))};return h(),window.addEventListener("resize",h),()=>{s.disconnect(),window.removeEventListener("resize",h)}},[]);const ji=s=>{if(m)return;if(qr(),Me(null),A==="cursor"){s.target===s.target.getStage()&&me(null);return}if(Cs)return;ks(!0);const h=s.target.getStage().getPointerPosition();if(A==="pen"){const c=q?"#f8fafc":"black";ot({type:"pen",points:[h.x,h.y],color:c})}else if(A==="highlighter")ot({type:"highlighter",points:[h.x,h.y],color:L});else if(A==="rect"){const c=q?"#818cf8":"blue";ot({type:"rectangle",x:h.x,y:h.y,width:0,height:0,stroke:c})}else if(A==="circle"){const c=q?"#4ade80":"green";ot({type:"circle",x:h.x,y:h.y,radius:0,stroke:c})}else if(A==="text"){const c=q?"#f8fafc":"black";ot({type:"text",x:h.x,y:h.y,text:"Click to edit...",fontSize:16,color:c})}},vi=s=>{if(!br||!Re)return;const h=s.target.getStage().getPointerPosition();if(Re.type==="pen"||Re.type==="highlighter")ot({...Re,points:Re.points.concat([h.x,h.y])});else if(Re.type==="rectangle")ot({...Re,width:h.x-Re.x,height:h.y-Re.y});else if(Re.type==="circle"){const c=Math.sqrt(Math.pow(h.x-Re.x,2)+Math.pow(h.y-Re.y,2));ot({...Re,radius:c})}},Ni=async()=>{if(!br||!Re)return;ks(!1);const s={...Re,page:$,segmentId:a};ot(null),we(!0);try{await l(s.type,s),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}finally{we(!1)}};n.useEffect(()=>{!Ne.current||!Ne.current.id||(Re?Ne.current.emit("whiteboard-update",{roomId:t,type:"temp-draw",userId:Ne.current.id,payload:{...Re,page:$,segmentId:a}}):Ne.current.emit("whiteboard-update",{roomId:t,type:"temp-end",userId:Ne.current.id}))},[Re,t,$,a]),n.useEffect(()=>{a&&Ne.current&&Ne.current.emit("whiteboard-update",{roomId:t,type:"segment-change",payload:{segmentId:a}})},[a,t]);const Yr=s=>{if(!s)return null;const h=s.page??0,c=Q[$];return!(s.pageId&&c?.id?s.pageId===c.id:h===$)||a&&s.segmentId&&s.segmentId!==a?null:s.type==="pen"?e.jsx(us,{points:s.points,stroke:s.color,strokeWidth:4,tension:.5,lineCap:"round",lineJoin:"round"}):s.type==="highlighter"?e.jsx(us,{points:s.points,stroke:s.color||"#facc15",strokeWidth:18,tension:.5,lineCap:"round",lineJoin:"round",opacity:.5}):s.type==="rectangle"?e.jsx(Qr,{x:s.x,y:s.y,width:s.width,height:s.height,stroke:s.stroke}):s.type==="circle"?e.jsx(en,{x:s.x,y:s.y,radius:s.radius,stroke:s.stroke}):s.type==="text"?e.jsx(tn,{x:s.x,y:s.y,text:s.text,fontSize:Math.round((s.fontSize||16)*C),fill:s.color}):null},ki=()=>Yr(Re?{...Re,page:$,segmentId:a}:null),Ci=()=>Object.values(On).map((s,h)=>e.jsx(rr.Fragment,{children:Yr(s)},h)),Jr=(s,h)=>{try{const c=Ue(s),N=Be.current.get(s.id),R=It?.id===s.id,B=St?.id===s.id,ee=N?.x??c.x??0,ne=N?.y??c.y??0,xe=B?St.x:R?It.currentX:ee,pe=B?St.y:R?It.currentY:ne,je=S=>jt(S,c).width,Pe=S=>jt(S,c).height,De=B?St.width:N?.width??c.width??je(s.type),et=B?St.height:c.isMinimized?36:N?.height??c.height??Pe(s.type),Ee=h?.fullscreen,Lt=!!Ee,$e=Ee?Ee.padding:xe,Ae=Ee?Ee.padding:pe,He=Ee?Math.max(240,Ee.width-Ee.padding*2):De,Xe=Ee?Math.max(180,Ee.height-Ee.padding*2):et,qe=fe===s.id,Ti=Oe&&se===s.id,Ze=!m&&!qe?"group hover:ring-2 hover:ring-indigo-400/80 hover:shadow-2xl transition-all duration-150":"group transition-all duration-150",tt=()=>Ti&&ye?.type==="swap"?e.jsx("div",{className:"absolute -inset-1.5 z-50 rounded-xl border-2 border-dashed border-blue-500 bg-blue-500/20 pointer-events-none flex items-center justify-center backdrop-blur-[1px] animate-pulse shadow-xl",children:e.jsx("div",{className:"bg-blue-600 text-white text-xs font-semibold px-2.5 py-1 rounded-full shadow flex items-center gap-1.5 select-none",children:e.jsx("span",{children:"⇄ 松开对调位置"})})}):m||c.isMinimized?null:qe?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"absolute -inset-1 border-2 border-indigo-500 rounded-lg pointer-events-none z-50 shadow-md animate-pulse duration-1000 animate-in fade-in"}),Oe&&e.jsxs("div",{className:"absolute -top-7 left-0 z-50 bg-indigo-700/90 text-white text-[10px] font-mono px-2 py-0.5 rounded shadow pointer-events-none select-none flex items-center gap-1.5 backdrop-blur",children:[e.jsx("span",{children:"Alt+Shift+方向键 对调"}),e.jsx("span",{className:"text-indigo-300",children:"|"}),e.jsx("span",{children:"Alt+方向键 换焦"})]}),!Oe&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"absolute -top-1.5 -left-1.5 w-3.5 h-3.5 bg-white border-2 border-indigo-600 rounded-full cursor-nwse-resize z-50 hover:bg-indigo-50 hover:scale-110 transition-transform shadow",onPointerDown:S=>ls(S,s.id,"top-left",$e,Ae,He,Xe),onPointerMove:cs,onPointerUp:ds}),e.jsx("div",{className:"absolute -top-1.5 -right-1.5 w-3.5 h-3.5 bg-white border-2 border-indigo-600 rounded-full cursor-nesw-resize z-50 hover:bg-indigo-50 hover:scale-110 transition-transform shadow",onPointerDown:S=>ls(S,s.id,"top-right",$e,Ae,He,Xe),onPointerMove:cs,onPointerUp:ds}),e.jsx("div",{className:"absolute -bottom-1.5 -left-1.5 w-3.5 h-3.5 bg-white border-2 border-indigo-600 rounded-full cursor-nesw-resize z-50 hover:bg-indigo-50 hover:scale-110 transition-transform shadow",onPointerDown:S=>ls(S,s.id,"bottom-left",$e,Ae,He,Xe),onPointerMove:cs,onPointerUp:ds}),e.jsx("div",{className:"absolute -bottom-1.5 -right-1.5 w-3.5 h-3.5 bg-white border-2 border-indigo-600 rounded-full cursor-nwse-resize z-50 hover:bg-indigo-50 hover:scale-110 transition-transform shadow",onPointerDown:S=>ls(S,s.id,"bottom-right",$e,Ae,He,Xe),onPointerMove:cs,onPointerUp:ds})]})]}):e.jsx("div",{className:"absolute -inset-1 border-2 border-transparent group-hover:border-indigo-400/80 rounded-xl pointer-events-none transition-all duration-150 z-20"}),ft=(S,Y,ie="default",be)=>({title:c.title||S,icon:Y,hidden:Lt,readOnly:m,isMinimized:!!c.isMinimized,isMaximized:lt===s.id,isPropertiesOpen:as===s.id||Ts===s.id,themeColor:ie,extraActions:be,onPointerDown:Fe=>!m&&_s(Fe,s.id,c),onPointerMove:m?void 0:Rs,onPointerUp:m?void 0:As,onOpenProperties:()=>{!z&&s.type==="html-applet"?(Ut(),Lr(s.id)):(me(s.id),Mt(Fe=>Fe===s.id?null:s.id))},onMinimize:async()=>{i&&(await i(s.id,{...c,isMinimized:!0}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{lt===s.id&&mt(null),c.isMinimized&&i&&(await i(s.id,{...c,isMinimized:!1}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>mt(s.id),onBrowserFullscreen:()=>void Nt.enter(s.id),onDelete:()=>Tt(s.id)});if(s.type==="plugin"){const S=k==="teacher",Y=S?c.teacherWidgetId:c.studentWidgetId,ie=S?"teacher.dashboard.widget":"student.view";return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:be=>{m||(me(s.id),be.stopPropagation())},onContextMenu:be=>{if(m){be.preventDefault(),be.stopPropagation();return}const Fe=Ke(be.clientX,be.clientY);Fe&&Me({x:Fe.x,y:Fe.y,elementId:s.id})},className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(dn,{...ft("Plugin Component",e.jsx(Ws,{size:13,className:"text-indigo-600"}),"indigo"),contentClassName:"flex-grow bg-white overflow-auto relative min-h-0 p-2",children:e.jsx(Ga,{pluginId:c.pluginId,slot:ie,widgetId:Y,elementId:s.id,lessonId:t,classId:j,studentId:y,studentName:f})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id)}if(s.type==="hello-world")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},className:`bg-transparent relative rounded-lg ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(io,{...Object.assign({elementId:s.id,data:c,readOnly:m},ft("Hello World 插件",e.jsx(Zt,{size:11,className:"text-amber-500 animate-pulse"}),"slate"),{onElementUpdate:i,lessonId:t})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id);if(s.type==="rollcall")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`bg-transparent relative rounded-lg ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(Va,{...Object.assign({elementId:s.id,data:c,lessonId:t,classId:H||c&&c.classId,readOnly:m,userRole:k},ft("随机点名助手 (分层抽问 Fair Picker)",e.jsx(Zt,{size:13,className:"animate-pulse text-amber-400"}),"indigo"),{onElementUpdate:i})}),m&&e.jsx(nt,{}),tt()]})})},s.id);if(s.type==="quiz"){const S=Array.isArray(c.options)?c.options:[],Y=In[s.id]??Object.keys(c.submissions||{}).length;return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:ie=>{m||(me(s.id),ie.stopPropagation())},onContextMenu:ie=>{if(m){ie.preventDefault(),ie.stopPropagation();return}const be=Ke(ie.clientX,ie.clientY);be&&Me({x:be.x,y:be.y,elementId:s.id})},"data-testid":`whiteboard-quiz-${s.id}`,className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative select-none ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(ut,{...ft("随堂测验 (Interactive Quiz)",e.jsx(Js,{size:13,className:"text-indigo-500"}),"indigo"),onMaximize:()=>mt(s.id),onBrowserFullscreen:()=>void Nt.enter(s.id)}),!c.isMinimized&&e.jsxs("div",{className:"p-4 text-center flex-1 overflow-y-auto flex flex-col justify-between min-h-0",children:[e.jsxs("div",{className:"text-left space-y-2",children:[e.jsx("p",{className:"font-semibold text-gray-800 text-xs line-clamp-2",title:c.question,children:c.question||"随堂测验题目"}),S.length>0&&e.jsx("div",{className:"space-y-1",children:S.slice(0,4).map((ie,be)=>e.jsxs("div",{className:"text-[11px] text-gray-600 bg-gray-50 border border-gray-100 rounded px-2 py-0.5 truncate text-left",children:[e.jsxs("span",{className:"font-bold text-indigo-500 mr-1.5",children:[String.fromCharCode(65+be),"."]}),ie]},be))})]}),e.jsx("div",{className:"pt-2",children:e.jsx("button",{"data-testid":"quiz-open-fullscreen",className:"w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-1.5 rounded transition-colors text-xs shadow-sm cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-1.5",disabled:m,onClick:()=>{m||mt(s.id)},children:e.jsx("span",{children:Y>0?`进入测验 (${Y} 人已交)`:"点击全屏答题 / 查看"})})})]}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id)}if(s.type==="assignment")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative select-none ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(ut,{...ft("Assignment Upload Task",e.jsx(js,{size:13,className:"text-orange-500"}),"orange")}),!c.isMinimized&&e.jsxs("div",{className:"p-4 text-center flex-1 overflow-y-auto flex flex-col justify-center min-h-0",children:[e.jsx("p",{className:"font-semibold text-gray-800 mb-1 text-xs",children:c.title}),e.jsx("p",{className:"text-xs text-gray-500 mb-3 line-clamp-3",children:c.description}),e.jsx("button",{"data-testid":"assignment-submit-button",className:"w-full bg-orange-600 hover:bg-orange-700 text-white font-medium py-1.5 rounded transition-colors text-xs shadow-sm cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",disabled:m,onClick:()=>{if(m)return;const S=typeof c.assignmentId=="string"?c.assignmentId:"";if(S){$s(S);return}(async()=>{try{const ie=await(await fetch(`/api/assignments?lessonId=${encodeURIComponent(t||"")}`)).json().catch(()=>null),be=Array.isArray(ie?.assignments)?ie.assignments:[],Fe=be.find(Ye=>Ye?.status==="published")||be[0];if(Fe?.id){$s(String(Fe.id));return}Ie({type:"alert",title:"尚未发布作业",message:"教师还没有发布本课节的作业,请稍后再试。",onConfirm:()=>Ie(null)})}catch(Y){Ie({type:"alert",title:"无法加载作业",message:Y?.message?String(Y.message):"请检查网络后重试。",onConfirm:()=>Ie(null)})}})()},children:c.assignmentId?"提交作业":"Upload File"})]}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id);if(s.type==="html-applet")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(dn,{...ft(c.title||"Interactive Courseware",e.jsx(ar,{size:13,className:"text-primary-theme"}),"default"),contentClassName:"flex-1 bg-white overflow-hidden relative min-h-0",children:e.jsx(Ii,{data:c,lessonId:t,elementId:s.id,className:"w-full h-full border-none"})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id);if(s.type==="pen"){const S=fe===s.id;return e.jsx(us,{id:s.id,points:c.points,stroke:S?M.selectionBorder||"#3b82f6":c.color&&c.color!=="black"&&c.color!=="#000000"?c.color:q?"#f8fafc":c.color||"black",strokeWidth:S?6:4,tension:.5,lineCap:"round",lineJoin:"round",draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=c.points.map((Je,Fs)=>Fs%2===0?Je+be:Je+Fe);i&&(await i(s.id,{...c,points:Ye}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="highlighter"){const S=fe===s.id;return e.jsx(us,{id:s.id,points:c.points,stroke:S?"#3b82f6":c.color||"#facc15",strokeWidth:S?24:18,tension:.5,lineCap:"round",lineJoin:"round",opacity:.5,draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=c.points.map((Je,Fs)=>Fs%2===0?Je+be:Je+Fe);i&&(await i(s.id,{...c,points:Ye}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="rectangle"||s.type==="shape"&&c.shape==="rect"){const S=fe===s.id;return e.jsx(Qr,{id:s.id,x:N?.x??c.x,y:N?.y??c.y,width:N?.width??c.width,height:N?.height??c.height,fill:c.fill||"transparent",stroke:S?"#3b82f6":c.stroke||"blue",strokeWidth:S?3:1,draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=(N?.x??c.x)+be,Je=(N?.y??c.y)+Fe;i&&(ct(s.id,{...at(c,"rect"),...N??{},x:Ye,y:Je}),await i(s.id,{...c,x:Ye,y:Je}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="circle"||s.type==="shape"&&c.shape==="circle"){const S=fe===s.id;return e.jsx(en,{id:s.id,x:N?.x??c.x,y:N?.y??c.y,radius:N?.radius??c.radius,fill:c.fill||"transparent",stroke:S?"#3b82f6":c.stroke||"green",strokeWidth:S?3:1,draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=(N?.x??c.x)+be,Je=(N?.y??c.y)+Fe;i&&(ct(s.id,{...at(c,"circle"),...N??{},x:Ye,y:Je}),await i(s.id,{...c,x:Ye,y:Je}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="text"){const S=fe===s.id;return e.jsx(tn,{id:s.id,x:N?.x??c.x,y:N?.y??c.y,text:c.text,fontSize:Math.round((c.fontSize||16)*C),fill:S?M.selectionBorder||"#3b82f6":c.color&&c.color!=="black"&&c.color!=="#000000"?c.color:q?"#f8fafc":c.color||"black",fontStyle:S?"bold":"normal",draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=(N?.x??c.x)+be,Je=(N?.y??c.y)+Fe;i&&(ct(s.id,{...at(c,"rect"),...N??{},x:Ye,y:Je}),await i(s.id,{...c,x:Ye,y:Je}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="code-sandbox")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`relative rounded-lg shadow-xl ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(so,{elementId:s.id,data:c,readOnly:m,isMinimized:!!c.isMinimized,isMaximized:lt===s.id,isPropertiesOpen:as===s.id,onOpenProperties:()=>{me(s.id),Mt(S=>S===s.id?null:s.id)},onMinimize:async()=>{i&&(await i(s.id,{...c,isMinimized:!0}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{lt===s.id&&mt(null),c.isMinimized&&i&&(await i(s.id,{...c,isMinimized:!1}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>mt(s.id),onBrowserFullscreen:()=>void Nt.enter(s.id),onElementUpdate:i?async(S,Y)=>{await i(S,Y),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0,onPointerDown:S=>!m&&_s(S,s.id,c),onPointerMove:m?void 0:Rs,onPointerUp:m?void 0:As,onDelete:()=>Tt(s.id)}),m&&e.jsx(nt,{}),tt()]})})},s.id);if(s.type==="math-graph")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`relative rounded-lg shadow-xl ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(no,{elementId:s.id,data:c,readOnly:m,isMinimized:!!c.isMinimized,isMaximized:lt===s.id,isPropertiesOpen:as===s.id,onOpenProperties:()=>{me(s.id),Mt(S=>S===s.id?null:s.id)},onMinimize:async()=>{i&&(await i(s.id,{...c,isMinimized:!0}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{lt===s.id&&mt(null),c.isMinimized&&i&&(await i(s.id,{...c,isMinimized:!1}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>mt(s.id),onBrowserFullscreen:()=>void Nt.enter(s.id),onElementUpdate:i?async(S,Y)=>{await i(S,Y),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0,onPointerDown:S=>!m&&_s(S,s.id,c),onPointerMove:m?void 0:Rs,onPointerUp:m?void 0:As,onDelete:()=>Tt(s.id)}),m&&e.jsx(nt,{}),tt()]})})},s.id);if(s.type==="presentation")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`bg-white border border-gray-305 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative select-none ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(ut,{...ft("Interactive Presentation",e.jsx(gs,{size:13,className:"text-purple-600"}),"purple")}),!c.isMinimized&&e.jsx("div",{className:"flex-1 min-h-0 relative bg-white",style:{pointerEvents:m?"none":"auto"},children:e.jsx(uo,{elementId:s.id,data:c,userRole:k,onElementUpdate:i?async(S,Y)=>{await i(S,Y),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id);const Pt=s.type==="whiteboard.renderer"?c.rendererType||c.type||"whiteboard.renderer":s.type,Zr=X?.find(S=>{const Y=S;return Y.targetType===Pt||S.id===Pt||S.route===Pt||`${S.pluginId}/${S.id}`===Pt||Y.slotProps?.elementType===Pt||Y.slotProps?.targetType===Pt});if(Zr){const S=!!c.frameless,Y=!!(c.hideTitleBar||S);return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:ie=>{m||(me(s.id),ie.stopPropagation())},onContextMenu:ie=>{if(m){ie.preventDefault(),ie.stopPropagation();return}const be=Ke(ie.clientX,ie.clientY);be&&Me({x:be.x,y:be.y,elementId:s.id})},className:S?`overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[!Y&&e.jsx(ut,{...ft(c.title||Zr.label||s.type,e.jsx(Ws,{size:13,className:"text-indigo-600"}),"indigo")}),!c.isMinimized&&e.jsx("div",{className:`flex-1 overflow-hidden relative min-h-0 ${S?"":"bg-white"}`,style:{pointerEvents:m?"none":"auto"},children:e.jsx(We,{slot:"whiteboard.renderer",slotProps:{element:s,elementId:s.id,elementType:Pt,data:c,width:He,height:Xe,isSelected:qe,readOnly:m,userRole:k,lessonId:t,onElementUpdate:i?async(ie,be)=>{await i(ie,be),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0}})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id)}const Gt=bs.get(s.type);if(Gt){const S=Gt.component;return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:Y=>{m||(me(s.id),Y.stopPropagation())},onContextMenu:Y=>{if(m){Y.preventDefault(),Y.stopPropagation();return}const ie=Ke(Y.clientX,Y.clientY);ie&&Me({x:ie.x,y:ie.y,elementId:s.id})},className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(ut,{...ft(Gt.labelZh||s.type,e.jsx(Ws,{size:13,className:"text-indigo-600"}),"indigo")}),!c.isMinimized&&e.jsx("div",{className:"flex-1 bg-white overflow-hidden relative min-h-0",style:{pointerEvents:m?"none":"auto"},children:S?e.jsx(S,{elementId:s.id,lessonId:t,data:c,userRole:k,onElementUpdate:i?async(Y,ie)=>{await i(Y,ie),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0}):e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center p-4 text-center text-gray-500 select-none",children:[e.jsx("div",{className:"font-semibold text-gray-700",children:Gt.labelZh}),e.jsx("div",{className:"text-xs mt-1 text-gray-400",children:Gt.descriptionZh}),c.title&&e.jsx("div",{className:"mt-2 text-xs bg-gray-100 px-2 py-1 rounded",children:c.title})]})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id)}}catch(c){console.error(c)}return null},Ur=s=>{s.preventDefault(),s.dataTransfer.dropEffect="copy",V||ae(!0)},Gr=s=>{s.preventDefault(),s.dataTransfer.dropEffect="copy",ae(!0)},Si=s=>{s.preventDefault(),s.currentTarget.contains(s.relatedTarget)||ae(!1)},Vr=(s,h,c,N)=>{const R={x:c,y:N,page:$,segmentId:a},ee=bs.get(s)?.defaultData||{},xe=X?.find(pe=>{const je=pe;return je.targetType===s||pe.id===s||pe.route===s||`${pe.pluginId}/${pe.id}`===s||je.slotProps?.elementType===s||je.slotProps?.targetType===s})?.slotProps?.defaultData||{};switch(s){case"code-sandbox":return{...R,code:h.code??"console.log('Hello Sandbox!');"};case"math-graph":return{...R,equation:h.equation??"Math.sin(x)"};case"presentation":return{...R,markdown:h.markdown??`# Title Slide
|
|
63
|
+
</div>`,x:100,y:150,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:bg-surface hover:text-main transition-all cursor-pointer",title:"插入交互网页课件 (Interactive Courseware)",children:e.jsx(or,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:courseware",placement:"after"}),e.jsx("div",{className:"w-px h-3.5 bg-border-theme/60 mx-0.5"}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:rollcall",placement:"before"}),e.jsx("button",{onClick:async()=>{f(!0);try{await d("rollcall",{title:"随机点名助手",x:120,y:120,page:u,segmentId:x}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-primary-theme hover:bg-primary-theme-light transition-all cursor-pointer",title:"插入随机点名组件 (Roll Call)",children:e.jsx(Cn,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:rollcall",placement:"after"})]}),e.jsx(We,{slot:"classroom.tool"}),e.jsx("div",{className:"flex items-center gap-0.5 bg-surface-secondary/70 p-0.5 rounded-xl border border-theme/60 shrink-0",children:e.jsxs("button",{ref:U,onClick:C,className:`relative w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${E?"bg-primary-theme text-white shadow-2xs":"text-primary-theme hover:bg-primary-theme-light"} ${K.length===0?"opacity-50":""}`,title:"互动工具 (插件扩展)",children:[e.jsx(Bs,{size:14}),K.length>0&&e.jsx("span",{className:"absolute -top-1 -right-1 min-w-[14px] h-[14px] px-0.5 rounded-full bg-primary-theme text-white text-[9px] font-bold flex items-center justify-center leading-none",children:K.length})]})}),q,e.jsx(We,{slot:"anchor:whiteboard-toolbar:ai-tutor",placement:"before"}),e.jsx("button",{onClick:async()=>{f(!0);try{(await fetch(`/api/lessons/${a}/ai-tutor`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elements:w.map(A=>({type:A.type,data:JSON.parse(A.data)}))})})).ok?(ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:a},timestamp:Date.now(),correlationId:a}),he&&he()):J({type:"alert",title:"AI 辅导提示",message:"无法获取 AI 授课助手的帮助,请稍后再试。",onConfirm:()=>J(null)})}finally{f(!1)}},className:"w-7 h-7 flex items-center justify-center rounded-lg text-purple-600 hover:bg-purple-500/10 transition-all cursor-pointer shrink-0",title:"请求 AI 助教建议 (Ask AI Tutor)",children:e.jsx(ar,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:ai-tutor",placement:"after"})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0 ml-auto",children:[e.jsx(We,{slot:"anchor:whiteboard-toolbar:grid",placement:"before"}),e.jsx("button",{onClick:()=>W(X=>!X),className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${D?"text-primary-theme bg-primary-theme-light":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:D?"关闭网格背景":"开启网格背景",children:e.jsx(Zi,{size:14})}),e.jsx(We,{slot:"anchor:whiteboard-toolbar:grid",placement:"after"}),!m&&z&&e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:z,className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${k?"text-primary-theme bg-primary-theme-light":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:k?"关闭自动平铺,恢复自由布局":"开启自动平铺(i3 式镶嵌布局)",children:e.jsx(Gs,{size:14})}),k&&e.jsx("span",{className:"text-2xs font-semibold text-primary-theme whitespace-nowrap",title:"当前为自动平铺模式,新组件会自动落入下一个格子",children:"平铺中"})]}),g&&e.jsxs("button",{onClick:()=>{Z(g),l(null)},className:"px-2 py-0.5 rounded-lg text-rose-500 bg-rose-500/10 hover:bg-rose-500/20 border border-rose-500/30 text-xs font-semibold flex items-center gap-1 transition-all cursor-pointer shadow-2xs",title:"删除选中图形",children:[e.jsx(bt,{size:12}),e.jsx("span",{className:"hidden sm:inline",children:"删除"})]}),j!=="student"?e.jsx("button",{onClick:T,className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:text-rose-500 hover:bg-rose-500/10 transition-all cursor-pointer",title:"清空白板 (Clear Board)",children:e.jsx(Qi,{size:14})}):e.jsx("button",{onClick:H,className:"w-7 h-7 flex items-center justify-center rounded-lg text-muted hover:text-amber-500 hover:bg-amber-500/10 transition-all cursor-pointer",title:"重置白板 (Reset Board)",children:e.jsx(ea,{size:14})}),y&&e.jsx(Ve,{size:13,className:"text-primary-theme animate-spin ml-0.5"})]})]})},ho=({pages:t,currentPage:r,showPageDrawer:l,setShowPageDrawer:i,editingPageIdx:o,setEditingPageIdx:d,editingPageTitle:u,setEditingPageTitle:x,activeMenuPageIdx:a,setActiveMenuPageIdx:w,safeElements:g,handleSwitchPage:D,handleRenamePage:W,handleDuplicatePage:k,handleMovePage:z,handleDeletePage:m,handleAddPage:j})=>e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"absolute top-3 left-1/2 -translate-x-1/2 z-20 flex items-center gap-1.5 bg-surface/90 backdrop-blur-md px-3 py-1.5 rounded-full shadow-lg border border-theme font-sans select-none text-main",children:[e.jsxs("button",{onClick:()=>i(!l),className:`p-1.5 rounded-full transition-colors cursor-pointer flex items-center gap-1 text-xs font-medium ${l?"bg-primary-theme-light text-primary-theme":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:"页面大纲与预览 (Pages Outline)",children:[e.jsx(Gs,{size:15}),e.jsxs("span",{className:"hidden sm:inline text-xs font-semibold",children:["大纲 (",t.length,")"]})]}),e.jsx("div",{className:"h-4 w-px bg-border-theme mx-0.5"}),e.jsx("button",{onClick:()=>D(Math.max(0,r-1)),className:"p-1 hover:bg-surface-secondary rounded-full text-muted hover:text-main disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer",disabled:r===0,title:"上一页",children:e.jsx(Vt,{size:16})}),e.jsx("div",{className:"flex items-center gap-1 max-w-[500px] overflow-x-auto no-scrollbar py-0.5",children:t.map((y,f)=>{const T=f===r,H=o===f;return e.jsxs("div",{className:"relative group flex items-center",children:[H?e.jsx("input",{type:"text",autoFocus:!0,value:u,onChange:Z=>x(Z.target.value),onKeyDown:Z=>{Z.key==="Enter"&&W(f,u),Z.key==="Escape"&&d(null)},onBlur:()=>W(f,u),className:"px-2 py-0.5 text-xs font-bold bg-surface border border-primary-theme rounded-full outline-none w-28 text-main shadow-2xs"}):e.jsx("button",{onClick:()=>D(f),onDoubleClick:()=>{d(f),x(y.title)},className:`px-3 py-1 rounded-full text-xs font-bold transition-all cursor-pointer flex items-center gap-1 border ${T?"bg-primary-theme text-white border-primary-theme shadow-2xs":"text-muted hover:bg-surface-secondary hover:text-main border-transparent"}`,title:"双击重命名",children:e.jsx("span",{className:"truncate max-w-[120px]",children:y.title})}),e.jsx("button",{onClick:Z=>{Z.stopPropagation(),w(a===f?null:f)},className:`p-0.5 rounded-full hover:bg-black/10 transition-colors ml-[-4px] z-10 ${T?"text-white/80 hover:text-white":"text-muted hover:text-main"}`,title:"页面选项",children:e.jsx(ta,{size:12})}),a===f&&e.jsxs("div",{className:"absolute top-full mt-2 left-1/2 -translate-x-1/2 bg-surface rounded-xl shadow-xl border border-theme py-1 w-36 z-50 text-xs font-normal text-main",onClick:Z=>Z.stopPropagation(),children:[e.jsxs("button",{onClick:()=>{d(f),x(y.title),w(null)},className:"w-full px-3 py-1.5 text-left text-main hover:bg-primary-theme-light hover:text-primary-theme flex items-center gap-2 cursor-pointer",children:[e.jsx(Us,{size:13})," 重命名"]}),e.jsxs("button",{onClick:()=>{k(f),w(null)},className:"w-full px-3 py-1.5 text-left text-main hover:bg-primary-theme-light hover:text-primary-theme flex items-center gap-2 cursor-pointer",children:[e.jsx(on,{size:13})," 复制页面"]}),f>0&&e.jsxs("button",{onClick:()=>{z(f,"left"),w(null)},className:"w-full px-3 py-1.5 text-left text-main hover:bg-primary-theme-light hover:text-primary-theme flex items-center gap-2 cursor-pointer",children:[e.jsx(Vt,{size:13})," 向左移动"]}),f<t.length-1&&e.jsxs("button",{onClick:()=>{z(f,"right"),w(null)},className:"w-full px-3 py-1.5 text-left text-main hover:bg-primary-theme-light hover:text-primary-theme flex items-center gap-2 cursor-pointer",children:[e.jsx(Kt,{size:13})," 向右移动"]}),e.jsx("div",{className:"my-1 border-t border-theme"}),e.jsxs("button",{onClick:()=>{m(f),w(null)},className:"w-full px-3 py-1.5 text-left text-rose-500 hover:bg-rose-500/10 flex items-center gap-2 cursor-pointer disabled:opacity-30",disabled:t.length<=1,children:[e.jsx(bt,{size:13})," 删除页面"]})]})]},y.id||f)})}),e.jsx("button",{onClick:()=>j(),className:"p-1 hover:bg-primary-theme-light hover:text-primary-theme text-muted rounded-full transition-colors cursor-pointer ml-0.5",title:"新建白板页面",children:e.jsx(Qt,{size:16})}),e.jsx("button",{onClick:()=>D(Math.min(t.length-1,r+1)),className:"p-1 hover:bg-surface-secondary rounded-full text-muted hover:text-main disabled:opacity-30 disabled:hover:bg-transparent transition-colors cursor-pointer",disabled:r>=t.length-1,title:"下一页",children:e.jsx(Kt,{size:16})})]}),l&&e.jsx("div",{className:"absolute inset-0 bg-slate-950/40 backdrop-blur-xs z-30 flex flex-col justify-end pointer-events-auto font-sans",onClick:()=>i(!1),children:e.jsxs("div",{className:"bg-surface/95 backdrop-blur-xl border-t border-theme rounded-t-2xl shadow-2xl p-4 max-h-[70vh] flex flex-col w-full max-w-5xl mx-auto animate-in slide-in-from-bottom duration-200 text-main",onClick:y=>y.stopPropagation(),children:[e.jsxs("div",{className:"flex items-center justify-between pb-3 border-b border-theme shrink-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Gs,{className:"w-5 h-5 text-primary-theme"}),e.jsx("h3",{className:"font-bold text-main text-sm",children:"白板页面大纲与预览"}),e.jsxs("span",{className:"px-2 py-0.5 bg-primary-theme-light text-primary-theme text-xs rounded-full font-semibold",children:["共 ",t.length," 页"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{onClick:()=>j(),className:"px-3 py-1.5 bg-primary-theme hover:bg-primary-theme-hover text-white rounded-lg text-xs font-semibold flex items-center gap-1.5 transition-colors cursor-pointer shadow-xs",children:[e.jsx(Qt,{size:14})," 新建页面"]}),e.jsx("button",{onClick:()=>i(!1),className:"p-1.5 hover:bg-surface-secondary rounded-full text-muted hover:text-main transition-colors cursor-pointer",children:e.jsx(es,{size:16})})]})]}),e.jsx("div",{className:"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-3 py-4 overflow-y-auto max-h-[50vh]",children:t.map((y,f)=>{const T=f===r,H=g.filter(Z=>Z.type!=="page_meta"&&(()=>{try{const J=JSON.parse(Z.data);return(J.page??0)===f||J.pageId===y.id}catch{return f===0}})()).length;return e.jsxs("div",{onClick:()=>{D(f),i(!1)},className:`relative flex flex-col p-3 rounded-xl border-2 transition-all cursor-pointer group bg-surface ${T?"border-primary-theme bg-primary-theme-light/30 shadow-md ring-2 ring-[var(--color-primary)]/20":"border-theme hover:border-primary-theme hover:shadow-sm"}`,children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsxs("span",{className:`text-xs font-extrabold px-2 py-0.5 rounded-md ${T?"bg-primary-theme text-white":"bg-surface-secondary text-muted"}`,children:["P",f+1]}),T&&e.jsx("span",{className:"text-xs font-bold text-primary-theme bg-primary-theme-light px-1.5 py-0.5 rounded",children:"当前激活"})]}),e.jsxs("div",{className:"h-20 bg-surface-secondary border border-theme rounded-lg flex flex-col items-center justify-center mb-2 overflow-hidden relative",children:[e.jsx(js,{size:24,className:T?"text-primary-theme":"text-subtle"}),e.jsxs("span",{className:"text-xs text-muted font-medium mt-1",children:[H," 个组件/笔画"]})]}),e.jsx("div",{className:"font-bold text-xs text-main truncate mb-1",title:y.title,children:y.title}),e.jsxs("div",{className:"flex items-center justify-between pt-2 border-t border-theme text-muted text-xs",onClick:Z=>Z.stopPropagation(),children:[e.jsx("button",{onClick:()=>{d(f),x(y.title)},className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"重命名",children:e.jsx(Us,{size:13})}),e.jsx("button",{onClick:()=>k(f),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"复制页面",children:e.jsx(on,{size:13})}),f>0&&e.jsx("button",{onClick:()=>z(f,"left"),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"向左移",children:e.jsx(Vt,{size:13})}),f<t.length-1&&e.jsx("button",{onClick:()=>z(f,"right"),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"向右移",children:e.jsx(Kt,{size:13})}),e.jsx("button",{onClick:()=>m(f),className:"hover:text-rose-500 p-1 rounded hover:bg-rose-500/10 transition-colors disabled:opacity-30",disabled:t.length<=1,title:"删除页面",children:e.jsx(bt,{size:13})})]})]},y.id||f)})})]})})]}),mo=({dialog:t,dialogInput:r,setDialogInput:l,setDialog:i})=>t?e.jsx("div",{className:"absolute inset-0 bg-neutral-900/40 backdrop-blur-[2px] flex items-center justify-center z-[9999] p-4 font-sans",children:e.jsxs("div",{className:"bg-white rounded-xl shadow-2xl overflow-hidden max-w-sm w-full border border-gray-100 flex flex-col scale-100 pointer-events-auto",children:[e.jsxs("div",{className:"px-5 py-4 border-b border-gray-150/60 bg-gray-50 flex justify-between items-center shrink-0",children:[e.jsx("h3",{className:"font-bold text-gray-800 text-sm",children:t.title}),e.jsx("button",{onClick:()=>i(null),className:"text-gray-400 hover:text-gray-650 transition-colors text-xl font-light cursor-pointer",children:"×"})]}),e.jsxs("div",{className:"p-5 flex-1 min-h-0",children:[e.jsx("p",{className:"text-xs text-gray-600 leading-relaxed whitespace-pre-wrap mb-4 font-medium",children:t.message}),t.type==="prompt"&&e.jsx("textarea",{value:r,onChange:o=>l(o.target.value),placeholder:t.placeholder,className:"w-full h-32 p-3 border border-gray-300 rounded-lg text-xs font-mono focus:outline-none focus:ring-2 focus:ring-indigo-500 bg-gray-50 focus:bg-white transition-all resize-none font-medium",onPointerDown:o=>o.stopPropagation()})]}),e.jsxs("div",{className:"px-5 py-3 border-t border-gray-100 bg-gray-50 flex justify-end gap-2 text-xs shrink-0",children:[t.type!=="alert"&&e.jsx("button",{onClick:()=>i(null),className:"px-4 py-2 text-gray-500 hover:bg-gray-100 rounded-lg transition-colors font-medium border border-gray-200 cursor-pointer",children:"取消"}),e.jsx("button",{onClick:async()=>{try{await t.onConfirm(r)}catch(o){console.error("Dialog action error:",o)}},className:"px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-semibold transition-all shadow-sm cursor-pointer",children:"确定"})]})]})}):null,Xs=[{key:"content",zh:"内容完整",en:"Completeness",weight:30},{key:"technical",zh:"技术实现",en:"Technical",weight:30},{key:"expression",zh:"表达规范",en:"Presentation",weight:20},{key:"innovation",zh:"创新亮点",en:"Originality",weight:20}],Os=[{key:"low",zh:"未达标",en:"Below",factor:.4},{key:"basic",zh:"基本达标",en:"Basic",factor:.7},{key:"good",zh:"良好",en:"Good",factor:.85},{key:"excellent",zh:"优秀",en:"Excellent",factor:1}];function fo(t){if(!Number.isFinite(t)||t<=0)return"0 B";const r=["B","KB","MB","GB"],l=Math.min(r.length-1,Math.floor(Math.log(t)/Math.log(1024)));return`${(t/1024**l).toFixed(l===0?0:1)} ${r[l]}`}function Is(t){if(!t)return"—";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return"—"}}function hn(t,r,l){const i=String.fromCharCode(65+t%26);return l?`${r?"匿名同学":"待评同学"} ${i}`:`${r?"Anonymous":"Peer"} ${i}`}function po({assignmentId:t,tasks:r,onSubmitted:l,onToast:i,lang:o="zh"}){const d=o==="zh",[u,x]=n.useState(null),[a,w]=n.useState({}),[g,D]=n.useState(""),[W,k]=n.useState(""),[z,m]=n.useState(!1),[j,y]=n.useState(null),[f,T]=n.useState(null),[H,Z]=n.useState(null),J=Math.max(0,r.findIndex(C=>C.taskId===u)),O=r[J],he=n.useCallback((C,M,q)=>{if(i){i(C,M,q);return}T(M?`${C}:${M}`:C)},[i]);n.useEffect(()=>{const C=r[J];C&&(D(C.review?String(C.review.score):""),k(C.review?.comment||""),w({}),y(null),T(null))},[J,r]);const K=n.useMemo(()=>{if(Xs.filter(q=>a[q.key]).length===0)return null;const M=Xs.reduce((q,X)=>{const A=Os.find(F=>F.key===a[X.key]);return q+X.weight*(A?.factor??Os[1].factor)},0);return Math.round(M)},[a]),ue=g.trim()===""?K:Math.round(Number(g)),E=O?.dueAt!==null&&O?.dueAt!==void 0&&Date.now()>Number(O.dueAt),te=r.filter(C=>C.review).length,U=(C,M)=>{w(q=>{const X={...q};return X[C]===M?delete X[C]:X[C]=M,X}),D("")},v=n.useCallback(async()=>{if(z||!O||E)return;const C=ue;if(C===null||!Number.isFinite(C)||C<0||C>100){y(d?"请给出 0-100 的互评分数":"Score must be between 0 and 100");return}if(!O.submissionId){y(d?"该互评任务缺少提交物信息,请刷新后重试":"Missing submission for this task");return}m(!0),y(null);try{const M=await fetch(`/api/assignments/${encodeURIComponent(t)}/peer-review`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({submissionId:O.submissionId,score:C,comment:W.trim(),taskId:O.taskId})}),q=await M.json().catch(()=>null);if(!M.ok||q?.success===!1)throw new Error(q?.error||`HTTP ${M.status}`);he(O.review?d?"互评已更新":"Review updated":d?"互评已提交":"Review submitted",d?`已给 ${hn(J,O.anonymous,d)} 打 ${C} 分`:"","success"),await l?.()}catch(M){y(M?.message||(d?"提交失败":"submit failed"))}finally{m(!1)}},[J,O,t,W,E,he,l,ue,z,d]);if(r.length===0)return e.jsxs("div",{className:"rounded-xl border border-theme bg-surface-secondary p-4 text-xs text-muted inline-flex items-center gap-2",children:[e.jsx(Vs,{size:13}),d?"老师还没有给你分配互评任务。":"No peer review task assigned yet."]});const P=O?.submission;return e.jsxs("div",{"data-testid":"peer-review-panel",className:"space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[e.jsxs("div",{className:"text-xs font-semibold text-main inline-flex items-center gap-1.5",children:[e.jsx(Vs,{size:13})," ",d?"互评任务":"Peer review",e.jsx("span",{className:"font-normal text-muted",children:d?`已完成 ${te} / ${r.length}`:`${te} / ${r.length} done`})]}),O?.dueAt?e.jsxs("span",{className:`text-[11px] ${E?"text-red-600":"text-muted"}`,children:[d?"互评截止":"Due"," ",Is(O.dueAt),E?d?"(已截止)":" (closed)":""]}):null]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-[9rem_1fr] gap-3",children:[e.jsx("div",{className:"space-y-1",children:r.map((C,M)=>{const q=M===J;return e.jsxs("button",{type:"button",onClick:()=>x(C.taskId),className:`w-full flex items-center justify-between gap-1 rounded-lg border px-2 py-1.5 text-left text-xs transition-colors ${q?"border-orange-300 bg-orange-50 text-main":"border-theme bg-surface text-muted hover:bg-surface-secondary"}`,children:[e.jsx("span",{className:"truncate",children:hn(M,C.anonymous,d)}),C.review?e.jsxs("span",{className:"inline-flex items-center gap-1 text-emerald-600 shrink-0",children:[e.jsx(ts,{size:11})," ",C.review.score]}):e.jsx("span",{className:"text-[11px] text-amber-600 shrink-0",children:d?"待评":"todo"})]},C.taskId)})}),e.jsxs("div",{className:"rounded-xl border border-theme bg-surface p-3 space-y-3",children:[O?.stale&&e.jsxs("div",{className:"flex items-start gap-1.5 rounded-lg border border-amber-200 bg-amber-50 px-2 py-1.5 text-[11px] text-amber-800",children:[e.jsx(ir,{size:12,className:"mt-0.5 shrink-0"}),d?"该作者在你评价后又更新了提交,建议复核后再提交一次。":"The author resubmitted after your review."]}),P?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-[11px] text-muted",children:[e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface-secondary border border-theme",children:d?`第 ${P.version} 版`:`v${P.version}`}),e.jsx("span",{children:Is(P.submittedAt)}),P.isLate&&e.jsx("span",{className:"text-amber-600",children:d?"迟交":"late"})]}),P.textContent?e.jsx("pre",{className:"max-h-48 overflow-y-auto whitespace-pre-wrap break-words rounded-lg border border-theme bg-surface-secondary p-2 text-xs text-main",children:P.textContent}):e.jsx("div",{className:"text-[11px] text-muted",children:d?"该同学没有留下文本作答。":"No text answer."}),(()=>{const C=Ai(P.linkUrl);return C?e.jsxs("a",{href:C,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1 text-xs text-orange-600 hover:underline break-all",children:[e.jsx(sa,{size:11})," ",P.linkUrl]}):null})(),P.files.length>0&&e.jsx("div",{className:"space-y-1",children:P.files.map(C=>e.jsxs("div",{className:"flex items-center gap-1.5 rounded-lg border border-theme bg-surface-secondary px-2 py-1.5 text-xs text-main",children:[e.jsxs("button",{onClick:()=>Z({id:C.id,original_name:C.original_name,size:C.size,mime:C.mime??null}),className:"flex items-center gap-1.5 flex-1 min-w-0 text-left hover:text-orange-600",title:d?"预览":"Preview","data-testid":"assignment-peer-file-preview",children:[e.jsx(Ks,{size:12,className:"shrink-0"}),e.jsx("span",{className:"truncate",children:C.original_name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:fo(C.size)})]}),e.jsx("a",{href:`/api/assignments/${encodeURIComponent(t)}/files/${encodeURIComponent(C.id)}`,target:"_blank",rel:"noreferrer",className:"shrink-0 text-muted hover:text-orange-600",title:d?"下载":"Download",children:e.jsx(ra,{size:12})})]},C.id))})]}):e.jsx("div",{className:"text-[11px] text-muted",children:d?"该同学还没有提交,无法互评。":"This peer has not submitted yet."}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("div",{className:"text-[11px] font-semibold text-main",children:d?"评价量规":"Rubric"}),Xs.map(C=>e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsxs("span",{className:"w-20 shrink-0 text-[11px] text-muted",children:[d?C.zh:C.en,e.jsxs("span",{className:"ml-1 text-[10px]",children:["(",C.weight,")"]})]}),Os.map(M=>{const q=a[C.key]===M.key;return e.jsx("button",{type:"button",disabled:E,onClick:()=>U(C.key,M.key),className:`px-1.5 py-0.5 rounded border text-[11px] transition-colors disabled:opacity-50 ${q?"border-orange-300 bg-orange-50 text-main":"border-theme text-muted hover:bg-surface-secondary"}`,children:d?M.zh:M.en},M.key)})]},C.key))]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("label",{className:"text-[11px] text-muted inline-flex items-center gap-1",children:[d?"互评总分":"Score",e.jsx("input",{type:"number",min:0,max:100,value:g,disabled:E,placeholder:K===null?"":String(K),onChange:C=>{D(C.target.value),w({})},className:"w-20 px-2 py-1 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400"})]}),K!==null&&g.trim()===""&&e.jsx("span",{className:"text-[11px] text-muted",children:d?`量规建议 ${K} 分`:`Rubric suggests ${K}`})]}),e.jsx("textarea",{value:W,disabled:E,onChange:C=>k(C.target.value),rows:3,placeholder:d?"写点具体建议:哪里做得好、哪里可以改进…":"Leave specific feedback…",className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400 resize-y"}),j&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:j}),f&&e.jsx("div",{className:"text-[11px] text-emerald-600 break-all",children:f}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-[11px] text-muted",children:O?.review?d?`已评 ${O.review.score} 分 · ${Is(O.review.submittedAt)}`:`Reviewed ${O.review.score}`:d?"同学之间双盲互评,作者看不到是谁评的":"Double-blind review"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{type:"button",disabled:z||E,onClick:()=>{D(O?.review?String(O.review.score):""),k(O?.review?.comment||""),w({}),y(null)},className:"px-2 py-1.5 rounded-lg text-xs border border-theme text-muted hover:bg-surface-secondary inline-flex items-center gap-1 disabled:opacity-50",children:[e.jsx(Et,{size:11})," ",d?"重填":"Reset"]}),e.jsxs("button",{type:"button",disabled:z||E,onClick:()=>void v(),className:"px-3 py-1.5 rounded-lg text-xs font-medium bg-orange-500 text-white hover:bg-orange-600 inline-flex items-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed",children:[z?e.jsx(Ve,{size:12,className:"animate-spin"}):null,E?d?"互评已截止":"Closed":O?.review?d?"更新互评":"Update":d?"提交互评":"Submit"]})]})]})]})]}),H&&e.jsx(Rn,{assignmentId:t,file:H,lang:o,onClose:()=>Z(null)})]})}const bo=".pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.csv,.txt,.md,.rtf,.odt,.odp,.ods,.png,.jpg,.jpeg,.gif,.webp,.bmp,.svg,.heic,.zip,.py,.js,.mjs,.cjs,.ts,.tsx,.jsx,.java,.c,.h,.cpp,.cs,.go,.rs,.rb,.php,.sql,.json,.xml,.html,.css,.ino",qs=50*1024*1024;function ms(t){if(!Number.isFinite(t)||t<=0)return"0 B";const r=["B","KB","MB","GB"],l=Math.min(r.length-1,Math.floor(Math.log(t)/Math.log(1024)));return`${(t/1024**l).toFixed(l===0?0:1)} ${r[l]}`}function mn(t){if(!t)return"—";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return"—"}}function go(t){try{const r=typeof t?.files_json=="string"?JSON.parse(t.files_json):t?.files_json;return Array.isArray(r)?r.filter(l=>l&&typeof l.fileId=="string").map(l=>({fileId:String(l.fileId),name:String(l.name??l.fileId),size:Number(l.size??0)})):[]}catch{return[]}}function yo({assignmentId:t,onClose:r,onToast:l,lang:i="zh"}){const o=i==="zh",[d,u]=n.useState(!0),[x,a]=n.useState(null),[w,g]=n.useState(null),[D,W]=n.useState([]),[k,z]=n.useState([]),[m,j]=n.useState(""),[y,f]=n.useState(""),[T,H]=n.useState(!1),[Z,J]=n.useState(null),[O,he]=n.useState(null),[K,ue]=n.useState(!1),[E,te]=n.useState("submit"),[U,v]=n.useState(null),[P,C]=n.useState(null),M=n.useRef(new Map),q=n.useRef(new Map),X=n.useRef(null),A=n.useCallback((b,V,ae)=>{if(l){l(b,V,ae);return}v({text:V?`${b}:${V}`:b,type:ae==="error"?"warning":ae})},[l]),F=n.useCallback((b,V)=>{z(ae=>ae.map(Q=>Q.key===b?{...Q,...V}:Q))},[]),L=n.useCallback(async(b=!1)=>{b||u(!0),a(null);try{const[V,ae]=await Promise.all([fetch(`/api/assignments/${encodeURIComponent(t)}`),fetch(`/api/assignments/${encodeURIComponent(t)}/files`)]),Q=await V.json().catch(()=>null);if(!V.ok||Q?.success===!1)throw new Error(Q?.error||`HTTP ${V.status}`);g(Q);const oe=await ae.json().catch(()=>null),_e=Array.isArray(oe?.files)?oe.files:[];W(_e.filter(Ge=>!Ge.version_id))}catch(V){a(V?.message||"load failed")}finally{b||u(!1)}},[t]);n.useEffect(()=>{L()},[L]),n.useEffect(()=>{const b=q.current;return()=>{b.forEach(V=>{try{V.abort()}catch{}}),b.clear()}},[]);const p=n.useCallback(b=>new Promise(V=>{const ae=M.current.get(b);if(!ae){F(b,{status:"error",error:o?"文件已失效,请重新选择":"file expired"}),V();return}const Q=new XMLHttpRequest;q.current.set(b,Q),Q.open("POST",`/api/assignments/${encodeURIComponent(t)}/files`,!0),Q.setRequestHeader("X-File-Name",encodeURIComponent(ae.name)),Q.setRequestHeader("Content-Type","application/octet-stream"),Q.upload.onprogress=oe=>{oe.lengthComputable&&F(b,{progress:Math.round(oe.loaded/oe.total*100)})},Q.onload=()=>{q.current.delete(b);let oe=null;try{oe=JSON.parse(Q.responseText||"{}")}catch{oe=null}Q.status>=200&&Q.status<300&&oe?.success!==!1&&oe?.file?.id?(F(b,{status:"done",progress:100,fileId:oe.file.id}),W(_e=>[{id:oe.file.id,original_name:oe.file.name??ae.name,size:oe.file.size??ae.size,uploaded_at:Date.now()},..._e])):F(b,{status:"error",error:oe?.error||`HTTP ${Q.status}`}),V()},Q.onerror=()=>{q.current.delete(b),F(b,{status:"error",error:o?"网络错误":"network error"}),V()},Q.onabort=()=>{q.current.delete(b),V()},F(b,{status:"uploading",progress:0,error:void 0}),Q.send(ae)}),[t,F,o]),$=n.useCallback(b=>{if(!b.length)return;const V=Date.now(),ae=[],Q=[];b.forEach((oe,_e)=>{if(oe.size<=0){Q.push(`${oe.name}(${o?"空文件":"empty"})`);return}if(oe.size>qs){Q.push(`${oe.name}(${o?"超过":"over"} ${ms(qs)})`);return}const Ge=`${V}-${_e}-${oe.name}`;M.current.set(Ge,oe),ae.push({key:Ge,name:oe.name,size:oe.size,status:"queued",progress:0})}),Q.length&&A(o?"部分文件未加入":"Some files skipped",Q.join("、"),"warning"),ae.length&&(z(oe=>[...oe,...ae]),(async()=>{for(const oe of ae)await p(oe.key)})())},[A,p,o]),I=n.useCallback(b=>{p(b)},[p]),G=n.useCallback(b=>{try{q.current.get(b)?.abort()}catch{}M.current.delete(b),z(V=>V.filter(ae=>ae.key!==b))},[]),le=n.useCallback(async b=>{try{const V=await fetch(`/api/assignments/${encodeURIComponent(t)}/files/${b}`,{method:"DELETE"}),ae=await V.json().catch(()=>null);if(!V.ok||ae?.success===!1){A(o?"删除失败":"Delete failed",ae?.error||`HTTP ${V.status}`,"error");return}W(Q=>Q.filter(oe=>oe.id!==b))}catch(V){A(o?"删除失败":"Delete failed",V?.message||"","error")}},[t,A,o]),se=n.useMemo(()=>{const b=D.map(Q=>Q.id),V=new Set(b),ae=[];for(const Q of k)Q.status!=="done"||!Q.fileId||V.has(Q.fileId)||(V.add(Q.fileId),ae.push(Q.fileId));return[...b,...ae]},[D,k]),ve=k.some(b=>b.status==="uploading"),Le=se.length>0||m.trim().length>0||y.trim().length>0,ze=n.useCallback(async()=>{if(!(T||ve)){H(!0),J(null);try{const b=await fetch(`/api/assignments/${encodeURIComponent(t)}/submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({fileIds:se,textContent:m.trim()||void 0,linkUrl:y.trim()||void 0})}),V=await b.json().catch(()=>null);if(!b.ok||V?.success===!1)throw new Error(V?.error||`HTTP ${b.status}`);he(Number(V?.version)||1),z([]),M.current.clear(),j(""),A(o?"提交成功":"Submitted",o?`已生成第 ${V?.version??1} 版提交`:"","success"),await L(!0)}catch(b){J(b?.message||"submit failed")}finally{H(!1)}}},[t,se,L,A,T,m,ve,o]),ye=w?.assignment,Ce=Array.isArray(w?.versions)?w.versions:[],xt=w?.grade,re=w?.stats,ge=Array.isArray(w?.peerReviewTasks)?w.peerReviewTasks:[],_=ge.filter(b=>!b.review||b.stale).length;return e.jsxs("div",{className:"fixed inset-0 z-[120] flex items-center justify-center bg-black/40 p-4",onClick:r,children:[e.jsxs("div",{className:"w-full max-w-2xl max-h-[88vh] flex flex-col rounded-2xl bg-surface border border-theme shadow-2xl overflow-hidden",onClick:b=>b.stopPropagation(),children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 px-4 py-3 border-b border-theme",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(na,{size:14,className:"text-orange-600 shrink-0"}),e.jsx("h3",{className:"font-bold text-main text-sm truncate",children:ye?.title||(o?"课堂作业":"Assignment")})]}),ye&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2 mt-1 text-[11px] text-muted",children:[e.jsx("span",{className:"px-1.5 py-0.5 rounded-full bg-surface-secondary border border-theme",children:ye.status==="published"?o?"已发布":"published":ye.status}),ye.due_at?e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(ia,{size:10})," ",o?"截止":"Due"," ",mn(ye.due_at)]}):null,ye.allow_late?e.jsx("span",{children:o?"允许迟交":"late allowed"}):null,re?e.jsx("span",{children:o?`已提交 ${re.submissionCount}`:`${re.submissionCount} submitted`}):null]})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[e.jsx("button",{onClick:()=>void L(!0),className:"p-1.5 rounded-lg text-muted hover:text-main hover:bg-surface-secondary transition-colors",title:o?"刷新":"Refresh",children:e.jsx(Et,{size:13})}),e.jsx("button",{onClick:r,className:"p-1.5 rounded-lg text-muted hover:text-main hover:bg-surface-secondary transition-colors",title:o?"关闭":"Close",children:e.jsx(es,{size:14})})]})]}),e.jsxs("div",{className:"flex items-center gap-1 px-4 pt-2 border-b border-theme",children:[e.jsx("button",{type:"button",onClick:()=>te("submit"),className:`px-2.5 py-1.5 text-xs rounded-t-lg border-b-2 transition-colors ${E==="submit"?"border-orange-500 text-main font-medium":"border-transparent text-muted hover:text-main"}`,children:o?"我的提交":"My submission"}),ge.length>0&&e.jsxs("button",{type:"button",onClick:()=>te("peer"),className:`px-2.5 py-1.5 text-xs rounded-t-lg border-b-2 transition-colors inline-flex items-center gap-1.5 ${E==="peer"?"border-orange-500 text-main font-medium":"border-transparent text-muted hover:text-main"}`,children:[o?"互评任务":"Peer review",e.jsx("span",{className:"text-[11px]",children:_>0?`${ge.length-_}/${ge.length}`:ge.length}),_>0&&e.jsx("span",{className:"px-1 rounded-full bg-amber-100 text-amber-700 text-[10px]",children:o?`待评 ${_}`:`${_} todo`})]})]}),e.jsx("div",{className:"flex-1 overflow-y-auto px-4 py-3 space-y-4",children:d?e.jsxs("div",{className:"flex items-center justify-center gap-2 py-10 text-muted text-xs",children:[e.jsx(Ve,{size:14,className:"animate-spin"})," ",o?"加载中…":"Loading…"]}):x?e.jsxs("div",{className:"flex items-start gap-2 rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700",children:[e.jsx(Dt,{size:14,className:"mt-0.5 shrink-0"}),e.jsxs("div",{children:[e.jsx("div",{className:"font-semibold",children:o?"无法加载作业":"Failed to load assignment"}),e.jsx("div",{className:"mt-0.5 break-all",children:x})]})]}):E==="peer"?e.jsx(po,{assignmentId:t,tasks:ge,onSubmitted:()=>L(!0),onToast:l,lang:i}):e.jsxs(e.Fragment,{children:[ye?.description?e.jsx("div",{className:"rounded-xl border border-theme bg-surface-secondary px-3 py-2 text-xs text-main whitespace-pre-wrap leading-relaxed",children:ye.description}):null,xt?e.jsxs("div",{className:"rounded-xl border border-theme px-3 py-2 text-xs flex items-center gap-2",children:[e.jsx(aa,{size:14,className:"text-amber-500 shrink-0"}),xt.status==="confirmed"?e.jsxs("span",{className:"text-main",children:[o?"最终成绩":"Final score",":",e.jsx("span",{className:"font-bold text-amber-600 ml-1",children:xt.calculated_final_score})]}):e.jsx("span",{className:"text-muted",children:o?"成绩待教师确认":"Grade pending confirmation"})]}):null,e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsx("span",{className:"text-xs font-semibold text-main",children:o?"作业文件":"Files"}),e.jsxs("span",{className:"text-[11px] text-muted",children:[o?"单个不超过":"max"," ",ms(qs)]})]}),e.jsxs("div",{onDragOver:b=>{b.preventDefault(),ue(!0)},onDragLeave:()=>ue(!1),onDrop:b=>{b.preventDefault(),ue(!1);const V=Array.from(b.dataTransfer?.files||[]);V.length&&$(V)},onClick:()=>X.current?.click(),className:`rounded-xl border-2 border-dashed px-3 py-4 text-center cursor-pointer transition-colors ${K?"border-orange-400 bg-orange-50":"border-theme hover:border-orange-300"}`,children:[e.jsx(ys,{size:16,className:"mx-auto text-muted"}),e.jsx("div",{className:"mt-1 text-xs text-main font-medium",children:o?"点击选择文件,或拖拽到此处":"Click to choose files, or drop them here"}),e.jsx("div",{className:"text-[11px] text-muted mt-0.5",children:o?"支持文档、图片、压缩包与常见代码文件":"documents, images, archives, source files"}),e.jsx("input",{ref:X,type:"file",multiple:!0,accept:bo,className:"hidden",onChange:b=>{const V=Array.from(b.target.files||[]);V.length&&$(V),b.target.value=""}})]}),D.length>0&&e.jsx("ul",{className:"mt-2 space-y-1",children:D.map(b=>e.jsxs("li",{className:"flex items-center gap-2 rounded-lg border border-theme px-2 py-1.5 text-xs",children:[e.jsx(js,{size:12,className:"text-muted shrink-0"}),e.jsx("span",{className:"flex-1 truncate text-main",children:b.original_name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:ms(b.size)}),e.jsx("button",{onClick:()=>C({id:b.id,original_name:b.original_name,size:b.size}),className:"p-1 rounded text-muted hover:text-primary-theme hover:bg-surface-secondary",title:o?"预览":"Preview","aria-label":o?`预览 ${b.original_name}`:`Preview ${b.original_name}`,"data-testid":"assignment-pending-file-preview",children:e.jsx(Ks,{size:12})}),e.jsx("button",{onClick:()=>void le(b.id),className:"p-1 rounded text-orange-600 hover:text-red-500 hover:bg-surface-secondary",title:o?"移除":"Remove",children:e.jsx(bt,{size:12})})]},b.id))}),k.length>0&&e.jsx("ul",{className:"mt-2 space-y-1",children:k.map(b=>e.jsxs("li",{className:"rounded-lg border border-theme px-2 py-1.5 text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[b.status==="done"?e.jsx(ts,{size:12,className:"text-emerald-600 shrink-0"}):b.status==="error"?e.jsx(Dt,{size:12,className:"text-red-500 shrink-0"}):e.jsx(Ve,{size:12,className:"animate-spin text-muted shrink-0"}),e.jsx("span",{className:"flex-1 truncate text-main",children:b.name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:ms(b.size)}),b.status==="error"&&e.jsx("button",{onClick:()=>I(b.key),className:"p-1 rounded text-primary-theme hover:bg-surface-secondary",title:o?"重试":"Retry",children:e.jsx(Et,{size:12})}),e.jsx("button",{onClick:()=>G(b.key),className:"p-1 rounded text-muted hover:text-main hover:bg-surface-secondary",title:o?"从列表移除":"Remove from list",children:e.jsx(es,{size:12})})]}),b.status==="uploading"&&e.jsx("div",{className:"mt-1 h-1 rounded-full bg-surface-secondary overflow-hidden",children:e.jsx("div",{className:"h-full bg-orange-500 transition-all",style:{width:`${b.progress}%`}})}),b.status==="error"&&b.error?e.jsx("div",{className:"mt-0.5 text-[11px] text-red-600 break-all",children:b.error}):null]},b.key))})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-main mb-1",children:o?"文字作答(可选)":"Text answer (optional)"}),e.jsx("textarea",{value:m,onChange:b=>j(b.target.value),className:"w-full h-20 p-2 border border-theme rounded-lg text-xs bg-surface text-main resize-none focus:outline-none focus:ring-1 focus:ring-orange-400",placeholder:o?"可直接粘贴代码或说明…":"Paste code or notes…"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-main mb-1",children:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(En,{size:11})," ",o?"作品链接(可选)":"Link (optional)"]})}),e.jsx("input",{type:"url",value:y,onChange:b=>f(b.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400",placeholder:"https://"})]})]}),Ce.length>0&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-semibold text-main mb-1.5",children:o?`提交历史(共 ${Ce.length} 版)`:`Submission history (${Ce.length})`}),e.jsx("ul",{className:"space-y-1",children:Ce.map(b=>{const V=go(b);return e.jsxs("li",{className:"rounded-lg border border-theme px-2 py-1.5 text-xs",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{className:"px-1.5 py-0.5 rounded bg-surface-secondary border border-theme text-[11px] text-main shrink-0",children:["v",b.version]}),e.jsx("span",{className:"flex-1 truncate text-muted",children:b.text_content||b.link_url||"—"}),V.length>0&&e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:o?`${V.length} 个附件`:`${V.length} file(s)`}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:mn(b.created_at||b.submitted_at)})]}),V.length>0&&e.jsx("ul",{className:"mt-1 flex flex-wrap gap-1",children:V.map(ae=>e.jsx("li",{children:e.jsxs("button",{onClick:()=>C({id:ae.fileId,original_name:ae.name,size:ae.size}),className:"flex items-center gap-1 rounded border border-theme px-1.5 py-0.5 text-[11px] text-main hover:border-orange-300",title:o?"预览":"Preview","data-testid":"assignment-version-file-preview",children:[e.jsx(Ks,{size:11,className:"shrink-0"}),e.jsx("span",{className:"max-w-[160px] truncate",children:ae.name})]})},ae.fileId))})]},b.id)})})]}),O!==null&&e.jsxs("div",{className:"flex items-center gap-2 rounded-xl border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-700",children:[e.jsx(ts,{size:14,className:"shrink-0"}),o?`已提交第 ${O} 版`:`Version ${O} submitted`]}),Z&&e.jsxs("div",{className:"flex items-start gap-2 rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700",children:[e.jsx(Dt,{size:14,className:"mt-0.5 shrink-0"}),e.jsx("span",{className:"break-all",children:Z})]})]})}),e.jsxs("div",{className:"flex items-center justify-between gap-2 px-4 py-3 border-t border-theme",children:[e.jsx("span",{className:"text-[11px] text-muted",children:U?e.jsx("span",{className:U.type==="warning"?"text-amber-700":"text-emerald-700",children:U.text}):o?`本次将提交 ${se.length} 个附件${m.trim()?" + 文本":""}${y.trim()?" + 链接":""}`:`${se.length} file(s)`}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:r,className:"px-3 py-1.5 rounded-lg text-xs border border-theme text-main hover:bg-surface-secondary transition-colors",children:o?"关闭":"Close"}),e.jsxs("button",{onClick:()=>void ze(),disabled:T||ve||!Le,className:"px-3 py-1.5 rounded-lg text-xs font-medium bg-orange-600 hover:bg-orange-700 disabled:opacity-50 disabled:cursor-not-allowed text-white transition-colors inline-flex items-center gap-1.5",children:[T?e.jsx(Ve,{size:12,className:"animate-spin"}):e.jsx(ys,{size:12}),T?o?"提交中…":"Submitting…":o?"提交作业":"Submit"]})]})]})]}),P&&e.jsx(Rn,{assignmentId:t,file:P,lang:i,onClose:()=>C(null)})]})}function wo(t){if(!t)return"";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return""}}function jo({lessonId:t,classId:r,elementId:l,value:i,draftTitle:o,draftDescription:d,disabled:u,onChange:x,onToast:a,lang:w="zh"}){const g=w==="zh",[D,W]=n.useState(!1),[k,z]=n.useState([]),[m,j]=n.useState(null),[y,f]=n.useState(null),[T,H]=n.useState(!1),[Z,J]=n.useState(null),O=n.useCallback((U,v,P)=>{if(a){a(U,v,P);return}J({text:v?`${U}:${v}`:U,type:P})},[a]),he=n.useCallback(async(U=!1)=>{if(t){U||W(!0),f(null);try{const v=await fetch(`/api/assignments?lessonId=${encodeURIComponent(t)}`),P=await v.json().catch(()=>null);if(!v.ok||P?.success===!1)throw new Error(P?.error||`HTTP ${v.status}`);z(Array.isArray(P?.assignments)?P.assignments:[])}catch(v){f(v?.message||"load failed")}finally{U||W(!1)}}},[t]),K=n.useCallback(async()=>{if(!i){j(null);return}try{const U=await fetch(`/api/assignments/${encodeURIComponent(i)}`),v=await U.json().catch(()=>null);U.ok&&v?.success!==!1&&j(v.assignment||null)}catch{}},[i]);n.useEffect(()=>{he()},[he]),n.useEffect(()=>{K()},[K]);const ue=n.useCallback(async()=>{if(!(T||!t)){H(!0);try{const U=await fetch("/api/assignments",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({title:o?.trim()||(g?"课堂作业":"Class assignment"),description:d?.trim()||"",lessonId:t,classId:r||void 0,elementId:l||void 0,status:"published"})}),v=await U.json().catch(()=>null);if(!U.ok||v?.success===!1)throw new Error(v?.error||`HTTP ${U.status}`);const P=v?.assignment||v?.result?.assignment,C=P?.id||v?.assignmentId||v?.result?.assignmentId||v?.id;if(!C)throw new Error(g?"服务端未返回作业 ID":"no assignment id returned");j(P||{id:C,title:o,status:"published"}),await he(!0),x(String(C),P),O(g?"已创建并绑定作业":"Assignment created",g?"学生端可以开始提交了":"","success")}catch(U){O(g?"创建作业失败":"Create failed",U?.message||"","error")}finally{H(!1)}}},[r,T,d,o,l,t,he,O,x,g]),E=n.useCallback(U=>{if(!U){x(null),j(null);return}const v=k.find(P=>String(P.id)===U);j(v||null),x(U,v)},[x,k]),te=m?.title||k.find(U=>String(U.id)===i)?.title;return e.jsxs("div",{className:"space-y-2 rounded-xl border border-theme bg-surface-secondary p-2.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("span",{className:"text-xs font-semibold text-main inline-flex items-center gap-1",children:[e.jsx(En,{size:11})," ",g?"绑定作业中心":"Assignment binding"]}),e.jsx("button",{type:"button",onClick:()=>void he(!0),disabled:D,className:"p-1 rounded text-muted hover:text-main hover:bg-surface transition-colors",title:g?"刷新":"Refresh",children:D?e.jsx(Ve,{size:11,className:"animate-spin"}):e.jsx(Et,{size:11})})]}),i&&te?e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-emerald-200 bg-emerald-50 px-2 py-1.5",children:[e.jsx(ts,{size:12,className:"mt-0.5 text-emerald-600 shrink-0"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"text-xs font-medium text-main truncate",children:te}),e.jsx("div",{className:"text-[11px] text-muted truncate",children:[m?.status,m?.due_at?`${g?"截止":"due"} ${wo(m.due_at)}`:""].filter(Boolean).join(" · ")})]}),e.jsx("button",{type:"button",disabled:u,onClick:()=>E(""),className:"p-1 rounded text-muted hover:text-red-500 hover:bg-surface transition-colors shrink-0",title:g?"解除绑定":"Unbind",children:e.jsx(oa,{size:11})})]}):e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 px-2 py-1.5",children:[e.jsx(Dt,{size:12,className:"mt-0.5 text-amber-600 shrink-0"}),e.jsx("span",{className:"text-[11px] text-amber-800",children:g?"尚未绑定作业:学生端只能看到提示、无法提交。请选择已有作业或直接新建。":"Not bound yet — students cannot submit."})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:i||"",disabled:u,onChange:U=>E(U.target.value),className:"flex-1 min-w-0 px-2 py-1.5 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400",children:[e.jsx("option",{value:"",children:g?"— 选择本课时的作业 —":"— select assignment —"}),k.map(U=>e.jsxs("option",{value:U.id,children:[U.title||U.id,U.status?` (${U.status})`:""]},U.id))]}),e.jsxs("button",{type:"button",disabled:u||T||!t,onClick:()=>void ue(),className:"px-2 py-1.5 rounded-lg text-xs font-medium border border-theme text-main hover:bg-surface transition-colors inline-flex items-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed shrink-0",children:[T?e.jsx(Ve,{size:11,className:"animate-spin"}):e.jsx(Qt,{size:11}),g?"新建":"New"]})]}),y&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:y}),Z&&e.jsx("div",{className:`text-[11px] break-all ${Z.type==="success"?"text-emerald-600":Z.type==="error"?"text-red-600":"text-amber-700"}`,children:Z.text}),k.length===0&&!D&&!y&&e.jsx("div",{className:"text-[11px] text-muted",children:g?"本课时还没有作业,点「新建」即可。":"No assignment yet."})]})}const fn={peer_review_pending:{zh:"未完成互评",en:"Pending"},all_full_marks:{zh:"全部满分",en:"All full marks"},score_gap:{zh:"分数差异大",en:"Score gap"}};function vo(){const t=new Date(Date.now()+2592e5),r=l=>String(l).padStart(2,"0");return`${t.getFullYear()}-${r(t.getMonth()+1)}-${r(t.getDate())}T${r(t.getHours())}:${r(t.getMinutes())}`}function No({assignmentId:t,progress:r,onAssigned:l,onToast:i,lang:o="zh"}){const d=o==="zh",[u,x]=n.useState(!1),[a,w]=n.useState(r||null),[g,D]=n.useState(!1),[W,k]=n.useState(!1),[z,m]=n.useState("2"),[j,y]=n.useState(""),[f,T]=n.useState(null),[H,Z]=n.useState(null),J=n.useCallback((E,te,U)=>{if(i){i(E,te,U);return}Z(te?`${E}:${te}`:E)},[i]),O=n.useCallback(async()=>{if(r){w(r);return}D(!0),T(null);try{const E=await fetch(`/api/assignments/${encodeURIComponent(t)}`),te=await E.json().catch(()=>null);if(!E.ok||te?.success===!1)throw new Error(te?.error||`HTTP ${E.status}`);w(te?.peerProgress||null)}catch(E){T(E?.message||"load failed")}finally{D(!1)}},[t,r]);n.useEffect(()=>{O()},[O]);const he=n.useCallback(async()=>{if(!W){k(!0),T(null);try{const E=Math.max(1,Math.min(10,Math.round(Number(z)||2))),te=j?new Date(j).getTime():void 0,U=await fetch(`/api/assignments/${encodeURIComponent(t)}/assign-peer-reviews`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({reviewerCount:E,dueAt:te&&Number.isFinite(te)?te:void 0})}),v=await U.json().catch(()=>null);if(!U.ok||v?.success===!1)throw new Error(v?.error||`HTTP ${U.status}`);J(d?"互评已分配":"Peer reviews assigned",d?`新增 ${v?.created??0} 个互评任务,覆盖 ${v?.submissions??0} 份提交(重复分配不会重复建任务)`:"","success"),x(!0),await O(),await l?.()}catch(E){J(d?"分配互评失败":"Assign failed",E?.message||"","error")}finally{k(!1)}}},[t,W,j,O,J,l,z,d]),K=(a?.reviewers||[]).filter(E=>E.pending>0),ue=a?.flags?.length||0;return e.jsxs("div",{className:"space-y-2 rounded-xl border border-theme bg-surface-secondary p-2.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("span",{className:"text-xs font-semibold text-main inline-flex items-center gap-1",children:[e.jsx(Vs,{size:11})," ",d?"互评进度":"Peer review",a?e.jsx("span",{className:"font-normal text-muted",children:d?`${a.completed} / ${a.tasks} 已完成`:`${a.completed} / ${a.tasks} done`}):null,ue>0?e.jsx("span",{className:"px-1 rounded-full bg-amber-100 text-amber-700 text-[10px]",children:d?`${ue} 项待复核`:`${ue} flags`}):null]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[e.jsx("button",{type:"button",onClick:()=>void O(),disabled:g,className:"p-1 rounded text-muted hover:text-main hover:bg-surface transition-colors",title:d?"刷新":"Refresh",children:g?e.jsx(Ve,{size:11,className:"animate-spin"}):e.jsx(Et,{size:11})}),e.jsx("button",{type:"button",onClick:()=>x(E=>!E),className:"px-1.5 py-0.5 rounded text-[11px] text-muted hover:text-main hover:bg-surface transition-colors",children:u?d?"收起":"Hide":d?"展开":"Show"})]})]}),a?e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5 text-[11px] text-muted",children:[e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface border border-theme",children:d?`提交 ${a.submissions}`:`${a.submissions} subs`}),e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface border border-theme",children:d?`任务 ${a.tasks}`:`${a.tasks} tasks`}),e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface border border-theme",children:d?`待完成 ${a.pending}`:`${a.pending} pending`})]}):e.jsx("div",{className:"text-[11px] text-muted",children:d?"暂无互评数据。":"No peer review data."}),a&&a.tasks===0&&e.jsx("div",{className:"text-[11px] text-muted",children:d?"还没有分配互评:点「随机分配互评」,系统会给每份提交随机分配若干同学(双盲、不评自己、负载均衡)。":"No peer reviews assigned yet."}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("label",{className:"text-[11px] text-muted inline-flex items-center gap-1",children:[d?"每份提交分配":"Reviewers",e.jsx("input",{type:"number",min:1,max:10,value:z,onChange:E=>m(E.target.value),className:"w-14 px-2 py-1 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400"}),d?"人":""]}),e.jsxs("label",{className:"text-[11px] text-muted inline-flex items-center gap-1",children:[d?"互评截止":"Due",e.jsx("input",{type:"datetime-local",value:j,placeholder:vo(),onChange:E=>y(E.target.value),className:"px-2 py-1 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-orange-400"})]}),e.jsxs("button",{type:"button",disabled:W,onClick:()=>void he(),className:"px-2 py-1.5 rounded-lg text-xs font-medium border border-theme text-main hover:bg-surface transition-colors inline-flex items-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed",children:[W?e.jsx(Ve,{size:11,className:"animate-spin"}):e.jsx(Ys,{size:11}),d?"随机分配互评":"Assign"]})]}),f&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:f}),H&&e.jsx("div",{className:"text-[11px] text-emerald-600 break-all",children:H}),u&&a&&e.jsxs("div",{className:"space-y-2",children:[a.flags.length>0?e.jsx("div",{className:"space-y-1",children:a.flags.map((E,te)=>e.jsxs("div",{className:"flex items-start gap-1.5 rounded-lg border border-amber-200 bg-amber-50 px-2 py-1 text-[11px] text-amber-800",children:[e.jsx(ir,{size:11,className:"mt-0.5 shrink-0"}),e.jsxs("span",{className:"break-all",children:[e.jsx("span",{className:"font-medium",children:d?fn[E.type]?.zh||E.type:fn[E.type]?.en||E.type}),":",E.detail]})]},`${E.type}-${E.reviewerId||te}-${te}`))}):e.jsxs("div",{className:"text-[11px] text-emerald-600 inline-flex items-center gap-1",children:[e.jsx(ts,{size:11})," ",d?"暂未发现异常,互评进度正常。":"No anomaly detected."]}),a.reviewers.length>0&&e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-[11px] font-medium text-main",children:d?`互评人(${K.length} 人还有待评)`:"Reviewers"}),e.jsx("div",{className:"max-h-40 overflow-y-auto space-y-0.5",children:a.reviewers.map(E=>e.jsxs("div",{className:"flex items-center justify-between gap-2 rounded border border-theme bg-surface px-2 py-1 text-[11px]",children:[e.jsx("span",{className:"truncate text-main",children:E.name}),e.jsx("span",{className:E.pending>0?"text-amber-700 shrink-0":"text-emerald-600 shrink-0",children:d?`已评 ${E.submitted} · 待评 ${E.pending}`:`${E.submitted} done · ${E.pending} todo`})]},E.studentId))})]})]})]})}const ko="ABCDEFGHIJKLMNOPQRSTUVWXYZ";function Co(t){const r=t?.options;return Array.isArray(r)?r.map(l=>typeof l=="string"?l:l==null?"":String(l)):[]}function ps(t,r){if(typeof t=="number")return Number.isInteger(t)&&t>=0&&(r===0||t<r)?t:null;if(typeof t=="string"){const l=t.trim();if(!/^\d+$/.test(l))return null;const i=Number(l);return r===0||i<r?i:null}return null}function Fn(t,r){const l=t.trim().toUpperCase();if(l.length!==1)return null;const i=ko.indexOf(l);return i<0?null:r===0||i<r?i:null}function Ln(t,r){const l=t.trim();if(!l)return null;const i=r.findIndex(u=>u.trim()===l);if(i>=0)return i;const o=l.toLowerCase(),d=r.findIndex(u=>u.trim().toLowerCase()===o);return d>=0?d:null}function Bn(t){if(!t)return null;const r=Co(t),l=ps(t.correctIndex,r.length);if(l!==null)return l;const i=t.correctAnswer;if(i==null)return null;if(typeof i=="number")return ps(i,r.length);const o=String(i);if(!o.trim())return null;const d=Ln(o,r);if(d!==null)return d;const u=Fn(o,r.length);return u!==null?u:ps(o,r.length)}function sr(t,r){if(t!==null&&typeof t=="object"){const o=t,d=sr(o.optionIndex,r);return d!==null?d:sr(o.answer,r)}if(t==null)return null;const l=ps(t,r.length);if(l!==null)return l;if(typeof t!="string"||!t.trim())return null;const i=Fn(t,r.length);return i!==null?i:Ln(t,r)}function So(t,r){return t===null||t<0||t>=r.length?{correctIndex:null,correctAnswer:null}:{correctIndex:t,correctAnswer:r[t]??null}}const zo=["plugin","hello-world","rollcall","quiz","assignment","html-applet","code-sandbox","math-graph","presentation"],Mo=({isEditMode:t,selectedShapeId:r,setSelectedShapeId:l,activePropertiesElementId:i,setActivePropertiesElementId:o,safeElements:d,editingProperties:u,handleLocalPropChange:x,handlePropBlur:a,handleNumericPropBlur:w,handlePropsUpdate:g,handleUpdateElementData:D,handleElementDelete:W,handleUndoProp:k,handleRedoProp:z,propertyUndoStack:m,propertyRedoStack:j,isSyncing:y,lessonId:f,classId:T,fullscreenBroadcastClassId:H,coursewares:Z,fetchCoursewares:J,setZipCandidates:O,setZipUploadInfo:he,setShowEntrySelector:K,handleAddOption:ue,handleRemoveOption:E,handleOptionChangeLocal:te,handleOptionBlur:U})=>{const[v,P]=n.useState(null),C=n.useRef(null);if(n.useEffect(()=>()=>{C.current&&clearTimeout(C.current)},[]),!t||!r||!u)return null;const M=d.find(p=>p.id===r);if(!M)return null;const q=async()=>{const p=await D(u),$=p==="saved"||p==="failed"?p:null;$&&(C.current&&clearTimeout(C.current),P($),C.current=setTimeout(()=>P(null),$==="failed"?5e3:2500))},X=zo.includes(M.type)||bs.has(M.type);if(X&&i!==r)return null;const A=Array.isArray(u.options)?u.options.map(p=>String(p)):[],F=Bn(u),L=p=>"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[p]||String(p+1);return e.jsxs("div",{className:"w-80 h-full max-h-full bg-surface border-l border-theme flex flex-col font-sans text-xs select-none shadow-xl shrink-0 z-20 animate-in slide-in-from-right duration-200 text-main",onPointerDown:p=>p.stopPropagation(),children:[e.jsxs("div",{className:"px-4 py-3 border-b border-theme bg-surface-secondary flex justify-between items-center shrink-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(la,{size:15,className:"text-muted animate-spin",style:{animationDuration:"6s"}}),e.jsx("span",{className:"font-bold text-main text-sm",children:"属性编辑器"})]}),e.jsxs("div",{className:"flex items-center gap-1.5 font-sans",children:[e.jsxs("button",{onClick:k,disabled:(m[r]||[]).length===0,className:`p-1 rounded-lg transition-all flex items-center justify-center gap-1 border border-transparent select-none cursor-pointer ${(m[r]||[]).length===0?"text-subtle bg-transparent border-transparent opacity-40 cursor-not-allowed":"text-main bg-surface hover:bg-surface-secondary hover:border-theme active:bg-surface-secondary"}`,title:"撤销属性修改",children:[e.jsx(ca,{size:13}),(m[r]||[]).length>0&&e.jsx("span",{className:"text-xs font-bold text-muted",children:(m[r]||[]).length})]}),e.jsxs("button",{onClick:z,disabled:(j[r]||[]).length===0,className:`p-1 rounded-lg transition-all flex items-center justify-center gap-1 border border-transparent select-none cursor-pointer ${(j[r]||[]).length===0?"text-subtle bg-transparent border-transparent opacity-40 cursor-not-allowed":"text-main bg-surface hover:bg-surface-secondary hover:border-theme active:bg-surface-secondary"}`,title:"重做属性修改",children:[e.jsx(da,{size:13}),(j[r]||[]).length>0&&e.jsx("span",{className:"text-xs font-bold text-muted",children:(j[r]||[]).length})]}),e.jsx("div",{className:"h-4 w-px bg-border-theme mx-0.5 shrink-0"}),e.jsx("button",{onClick:()=>{o(null),l(null)},className:"text-muted hover:text-main hover:bg-surface-secondary p-1 rounded-full transition-all cursor-pointer",title:"关闭属性编辑器",children:e.jsx(es,{size:15})})]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-4 space-y-4",children:[e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-muted text-xs font-bold uppercase tracking-wider",children:"组件类型"}),e.jsx("span",{className:"px-2 py-0.5 bg-primary-theme-light text-primary-theme rounded text-xs font-bold uppercase tracking-wider",children:M.type})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-muted text-xs font-bold uppercase tracking-wider",children:"组件标识"}),e.jsx("span",{className:"font-mono text-muted text-xs truncate max-w-[155px]",title:M.id,children:M.id})]})]}),!X&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5 flex items-center gap-1.5",children:"尺寸"}),M.type!=="pen"&&M.type!=="circle"&&e.jsxs("div",{className:"grid grid-cols-2 gap-2 mt-2",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"宽度 (Width)"}),e.jsx("input",{type:"number",min:"50",value:Math.round(u.width??300),onChange:p=>x("width",parseFloat(p.target.value)||50),onBlur:p=>w("width",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"高度 (Height)"}),e.jsx("input",{type:"number",min:"50",value:Math.round(u.height??300),onChange:p=>x("height",parseFloat(p.target.value)||50),onBlur:p=>w("height",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]})]}),M.type==="circle"&&e.jsxs("div",{className:"mt-2",children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"半径 (Radius)"}),e.jsx("input",{type:"number",min:"5",value:Math.round(u.radius??50),onChange:p=>x("radius",parseFloat(p.target.value)||5),onBlur:p=>w("radius",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]})]}),(()=>{const p=Fi.get(M.type);if(p)return e.jsx(p,{elementId:M.id,elementType:M.type,data:u,updateData:g,lessonId:f,onClose:()=>l(null)});const $=bs.get(M.type);if($){const I=$.editFields||[];return e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsxs("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5 flex items-center justify-between",children:[e.jsxs("span",{children:[$.labelZh," 配置"]}),e.jsx("span",{className:"text-xs text-muted font-normal",children:"插件扩展"})]}),I.length===0?e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"标题 (Title)"}),e.jsx("input",{type:"text",value:u.title||"",onChange:G=>x("title",G.target.value),onBlur:G=>a("title",G.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main",placeholder:"组件标题..."})]}):I.map(G=>{const le=u[G.key]??"";return G.kind==="textarea"?e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:G.labelZh}),e.jsx("textarea",{value:le,onChange:se=>x(G.key,se.target.value),onBlur:se=>a(G.key,se.target.value),className:"w-full h-20 p-2 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main resize-none font-medium leading-relaxed",placeholder:G.placeholderZh||""})]},G.key):G.kind==="select"?e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:G.labelZh}),e.jsxs("select",{value:le,onChange:se=>{x(G.key,se.target.value),a(G.key,se.target.value)},className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs bg-surface text-main focus:outline-none focus:ring-1 focus:ring-primary-theme",children:[e.jsx("option",{value:"",children:"请选择..."}),(G.options||[]).map(se=>e.jsx("option",{value:se.value,children:se.label},se.value))]})]},G.key):e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:G.labelZh}),e.jsx("input",{type:"text",value:le,onChange:se=>x(G.key,se.target.value),onBlur:se=>a(G.key,se.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main",placeholder:G.placeholderZh||""})]},G.key)})]})}return null})(),M.type==="quiz"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"随堂测验配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"测验题目 (Question)"}),e.jsx("textarea",{value:u.question||"",onChange:p=>x("question",p.target.value),onBlur:p=>a("question",p.target.value),className:"w-full h-20 p-2 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main resize-none font-medium leading-relaxed",placeholder:"编写问题描述..."})]}),(u.options||[]).length>0&&e.jsxs("div",{className:"bg-amber-500/10 border border-amber-500/30 rounded-lg p-2.5",children:[e.jsx("label",{className:"block text-xs text-amber-500 font-bold mb-1.5",children:"⚠️ 正确答案 (Correct Answer)"}),e.jsxs("select",{value:F===null?"":String(F),onChange:p=>{const $=p.target.value,I=$===""?null:Number($);g(So(I,A))},className:`w-full px-2 py-1.5 border rounded-lg text-xs font-medium focus:outline-none focus:ring-1 focus:ring-amber-500 cursor-pointer ${F!==null?"border-green-500/40 bg-green-500/10 text-green-600":"border-amber-500/40 bg-surface text-main"}`,children:[e.jsx("option",{value:"",children:"-- 请选择正确答案 --"}),A.map((p,$)=>e.jsxs("option",{value:String($),children:[L($),". ",p]},$))]}),F===null&&e.jsx("p",{className:"text-xs text-amber-500 mt-1",children:"未设置正确答案将无法自动判分"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-xs text-muted font-semibold",children:"选项列表 (Options)"}),e.jsx("div",{className:"space-y-1.5 max-h-48 overflow-y-auto pr-1",children:(u.options||[]).map((p,$)=>{const G="ABCDEFGHIJKLMNOPQRSTUVWXYZ"[$]||$+1;return e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-bold text-main bg-surface-secondary rounded px-1.5 py-1 text-center shrink-0 min-w-[22px]",children:G}),e.jsx("input",{type:"text",value:p||"",onChange:le=>te($,le.target.value),onBlur:le=>U($,le.target.value),className:"flex-1 px-2 py-1 border border-theme rounded-lg text-xs font-medium bg-surface text-main"}),e.jsx("button",{onClick:()=>E($),title:"删除选项",className:"text-muted hover:text-rose-500 hover:bg-rose-500/10 p-1 rounded-md shrink-0 transition-colors cursor-pointer",children:e.jsx(bt,{size:13})})]},$)})}),e.jsxs("button",{onClick:ue,className:"w-full mt-2 py-1 bg-surface-secondary hover:bg-surface-secondary text-main font-bold border border-theme rounded-lg flex items-center justify-center gap-1 transition-all text-xs cursor-pointer",children:[e.jsx(Qt,{size:12})," 添加选项"]})]})]}),M.type==="assignment"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"作业选项配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"作业任务标题 (Title)"}),e.jsx("input",{type:"text",value:u.title||"",onChange:p=>x("title",p.target.value),onBlur:p=>a("title",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-semibold focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main",placeholder:"作业名..."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"详细作业要求描述"}),e.jsx("textarea",{value:u.description||"",onChange:p=>x("description",p.target.value),onBlur:p=>a("description",p.target.value),className:"w-full h-24 p-2 border border-theme rounded-lg text-xs focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main resize-none font-medium leading-relaxed",placeholder:"请输入详细的作业指南..."})]}),e.jsx(jo,{lessonId:f,classId:T||H||void 0,elementId:M.id,value:u.assignmentId||"",draftTitle:u.title||"",draftDescription:u.description||"",onChange:p=>{x("assignmentId",p),a("assignmentId",p)}}),u.assignmentId?e.jsx(No,{assignmentId:String(u.assignmentId)},String(u.assignmentId)):null]}),(M.type==="code-sandbox"||M.type==="html-applet")&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsxs("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5 flex justify-between items-center",children:[e.jsx("span",{children:"动态运行代码定制"}),M.type==="html-applet"&&e.jsx("span",{className:"text-xs bg-primary-theme-light text-primary-theme px-1.5 py-0.5 rounded-full font-bold",children:"HTML Applet"})]}),M.type==="html-applet"&&e.jsxs("div",{className:"space-y-3 border-b border-theme pb-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-primary-theme font-bold mb-1",children:"选择互动网络课件 (ZIP/HTML):"}),e.jsxs("select",{value:u.coursewareUuid||"",onChange:p=>{const $=p.target.value;g({coursewareUuid:$,resourceId:""})},className:"w-full text-xs p-2 bg-surface-secondary border border-theme hover:border-primary-theme rounded-lg text-main focus:outline-none focus:ring-1 focus:ring-primary-theme transition-all font-semibold",children:[e.jsx("option",{value:"",children:"-- 使用自定义沙箱代码 --"}),Z.map(p=>e.jsxs("option",{value:p.uuid,children:["📁 [互动课件] ",p.name]},p.id))]})]}),e.jsxs("div",{className:"bg-surface-secondary p-2.5 rounded-xl border border-theme text-xs text-muted space-y-2",children:[e.jsx("span",{className:"font-bold text-main block",children:"上传新课件 (自动生成独立运行实例):"}),e.jsxs("label",{className:"w-full flex flex-col items-center justify-center p-3 bg-indigo-50 hover:bg-indigo-100 border border-dashed border-indigo-300 hover:border-indigo-400 rounded-lg cursor-pointer text-center transition-all",children:[e.jsx("span",{className:"font-bold text-indigo-700 text-xs",children:"✨ 上传互动网络课件 (.zip / .html)"}),e.jsx("span",{className:"text-xs text-indigo-500 mt-0.5",children:"支持多文件打包 ZIP 或单页 HTML,自动接入 LMS Bridge"}),e.jsx("input",{type:"file",accept:".zip,.html,.htm",className:"hidden",onChange:async p=>{const $=p.target.files?.[0];if(!$)return;const I=new FileReader;I.onload=async G=>{const le=G.target?.result;try{const se=await fetch("/api/courseware/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:$.name.replace(/\.[^/.]+$/,""),filename:$.name,base64Data:le})});if(se.ok){const ve=await se.json();ve.need_select_entry?(O(ve.candidates),he({uuid:ve.uuid,name:ve.name}),K(!0)):(g({coursewareUuid:ve.uuid,resourceId:""}),J({force:!0}))}else{const ve=await se.json();alert("上传失败: "+(ve.error||se.statusText))}}catch(se){console.error("Courseware upload failed:",se)}},I.readAsDataURL($)}})]})]})]}),(!u.coursewareUuid||M.type==="code-sandbox")&&e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-slate-400 font-semibold mb-1",children:"沙箱程序代码 (Source Code)"}),e.jsx("textarea",{value:u.code||"",onChange:p=>x("code",p.target.value),onBlur:p=>a("code",p.target.value),className:"w-full h-48 p-3 border border-slate-300 rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500 bg-slate-900 text-slate-100 resize-none leading-relaxed",placeholder:"// 编写交互沙箱代码..."})]})]}),M.type==="math-graph"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"函数解析拟合"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"函数表达式 y = f(x)"}),e.jsx("input",{type:"text",value:u.equation||"",onChange:p=>x("equation",p.target.value),onBlur:p=>a("equation",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"}),e.jsxs("p",{className:"text-xs text-muted mt-1 leading-snug",children:["支持标准 JS 表达式。 示例:",e.jsx("br",{}),"• ",e.jsx("code",{className:"bg-surface-secondary px-1 rounded",children:"Math.sin(x)"})," 正负弦波形",e.jsx("br",{}),"• ",e.jsx("code",{className:"bg-surface-secondary px-1 rounded",children:"Math.cos(x) * x"})," 振幅衰减"]})]})]}),M.type==="presentation"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"幻灯片 Markdown 文案"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"Markdown 源代码"}),e.jsx("textarea",{value:u.markdown||"",onChange:p=>x("markdown",p.target.value),onBlur:p=>a("markdown",p.target.value),className:"w-full h-64 p-2.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme resize-none font-medium leading-relaxed bg-surface text-main",placeholder:"修改 Markdown 内容..."})]})]}),M.type==="text"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"文字属性管理"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"文本内容"}),e.jsx("input",{type:"text",value:u.text||"",onChange:p=>x("text",p.target.value),onBlur:p=>a("text",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-medium focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"文字大小 (FontSize)"}),e.jsx("input",{type:"number",min:"10",max:"100",value:u.fontSize||16,onChange:p=>x("fontSize",parseInt(p.target.value)||10),onBlur:p=>w("fontSize",p.target.value),className:"w-full px-2 py-1.5 border border-theme rounded-lg text-xs font-mono focus:outline-none focus:ring-1 focus:ring-primary-theme bg-surface text-main"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"文字填充颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.color||"#000000",onChange:p=>x("color",p.target.value),onBlur:p=>a("color",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.color||"#000000"})]})]})]}),(M.type==="rectangle"||M.type==="shape")&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"矩形样式配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"外边框颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.stroke||"#000000",onChange:p=>x("stroke",p.target.value),onBlur:p=>a("stroke",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.stroke||"#000000"})]})]})]}),M.type==="circle"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"圆形样式配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"外边框颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.stroke||"#000000",onChange:p=>x("stroke",p.target.value),onBlur:p=>a("stroke",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.stroke||"#000000"})]})]})]}),M.type==="pen"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"线条样式配置"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"折线颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.color||"#000000",onChange:p=>x("color",p.target.value),onBlur:p=>a("color",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.color||"#000000"})]})]})]}),M.type==="highlighter"&&e.jsxs("div",{className:"bg-surface p-3 rounded-xl border border-theme shadow-sm space-y-3",children:[e.jsx("h4",{className:"font-bold text-main text-xs border-b border-theme pb-1.5",children:"高亮荧光标记 (Highlighter)"}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:"荧光笔颜色"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"color",value:u.color||"#facc15",onChange:p=>x("color",p.target.value),onBlur:p=>a("color",p.target.value),className:"w-8 h-8 rounded border border-theme cursor-pointer shrink-0 bg-surface"}),e.jsx("span",{className:"font-mono text-xs text-muted",children:u.color||"#facc15"})]})]})]}),e.jsx("div",{className:"text-xs text-muted text-center select-none pt-2 font-medium",children:"提示:属性在失焦或修改时自动同步,多端可见。"})]}),e.jsxs("div",{className:"p-3 border-t border-slate-200 bg-white flex flex-col gap-2 shrink-0",children:[e.jsx("button",{onClick:q,disabled:y,className:"w-full py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-bold transition-all shadow-sm hover:shadow active:scale-[0.98] cursor-pointer flex items-center justify-center gap-1.5 text-xs",children:y?e.jsxs(e.Fragment,{children:[e.jsx(Ve,{size:13,className:"animate-spin"}),"正在保存..."]}):e.jsxs(e.Fragment,{children:[e.jsx(_n,{size:13}),"保存"]})}),e.jsxs("div",{role:"status","aria-live":"polite",className:"min-h-[16px] text-center",children:[v==="saved"&&e.jsxs("span",{"data-testid":"save-feedback-success",className:"inline-flex items-center gap-1 text-xs font-bold text-emerald-600",children:[e.jsx(ua,{size:12}),"已保存"]}),v==="failed"&&e.jsxs("span",{"data-testid":"save-feedback-error",className:"inline-flex items-center gap-1 text-xs font-bold text-red-600",children:[e.jsx(Dt,{size:12}),"保存失败,请重试"]})]}),e.jsxs("button",{onClick:()=>{W(r),l(null)},className:"w-full py-2 bg-red-50 hover:bg-red-105 text-red-650 rounded-lg font-semibold transition-all flex items-center justify-center gap-1.5 border border-red-200 cursor-pointer text-xs",children:[e.jsx(bt,{size:13}),"删除当前组件"]})]})]})},$o=({isVisible:t})=>t?e.jsxs("div",{className:"absolute inset-0 flex flex-col items-center justify-center pointer-events-none select-none text-muted p-6 z-0",children:[e.jsx("div",{className:"w-16 h-16 rounded-2xl bg-primary-theme-light border border-theme flex items-center justify-center mb-3 shadow-2xs",children:e.jsx(Zt,{className:"w-7 h-7 text-primary-theme animate-pulse"})}),e.jsx("p",{className:"font-bold text-sm text-main mb-1",children:"交互式备课白板"}),e.jsx("p",{className:"text-xs text-muted max-w-sm text-center",children:"从左侧组件库拖拽组件至此处,或使用顶部工具栏插入画笔、几何图形与 AI 助教"})]}):null,To=24;function Po({elementId:t,type:r,lessonId:l,readOnly:i=!1,dismissible:o=!0,onExit:d,renderContent:u}){n.useEffect(()=>{if(!o)return;const w=g=>{g.key==="Escape"&&d()};return window.addEventListener("keydown",w),()=>window.removeEventListener("keydown",w)},[d,o]);const[x,a]=n.useState(()=>({width:typeof window>"u"?1024:window.innerWidth,height:typeof window>"u"?768:window.innerHeight}));return n.useEffect(()=>{const w=()=>a({width:window.innerWidth,height:window.innerHeight});return window.addEventListener("resize",w),()=>window.removeEventListener("resize",w)},[]),e.jsxs("div",{"data-testid":"browser-fullscreen-host","data-element-id":t,"data-element-type":r,"data-dismissible":o?"true":"false",style:{pointerEvents:"auto",zIndex:Ja},className:"fixed inset-0 bg-white dark:bg-slate-950 flex flex-col",children:[o?e.jsxs("button",{type:"button","data-testid":"browser-fullscreen-exit",onClick:d,className:"fixed top-4 right-4 z-[100001] px-3 py-2 rounded-xl bg-slate-900/85 hover:bg-slate-900 text-slate-100 text-xs font-bold flex items-center gap-1.5 shadow-2xl backdrop-blur-md border border-white/15 transition-colors cursor-pointer",title:"退出全屏(Esc)",children:[e.jsx(kn,{size:14}),"退出全屏"]}):e.jsx("span",{className:"fixed top-4 right-4 z-[100001] px-3 py-2 rounded-xl bg-slate-900/85 text-slate-200 text-xs font-bold flex items-center gap-1.5 shadow-2xl border border-white/10 select-none",title:i?"教师已开启全班专注锁定":"由教师端控制,无法在本地退出",children:i?"🔒 教师同步视图":"教师同步视图"}),e.jsx("div",{"data-testid":"browser-fullscreen-content",className:"flex-1 min-h-0 overflow-auto",style:{width:x.width,height:x.height},children:u(x)}),e.jsx("span",{hidden:!0,"data-lesson-id":l})]})}function pn({width:t,height:r,children:l}){return t<=0||r<=0?null:e.jsx(yn,{"data-testid":"widget-fullscreen-stage",width:t,height:r,style:{backgroundColor:"transparent"},children:e.jsx(wn,{children:l})})}const Do={quiz:"📝 随堂测验",timer:"⏱ 计时器",assignment:"📋 作业","code-sandbox":"💻 代码沙箱","html-applet":"🌐 交互课件",rollcall:"🎲 随机点名",presentation:"📽 演示文稿","math-graph":"📐 数学图形",text:"📝 文本"},Eo=({containerSize:t,browserFullscreenElementId:r,isRemoteBrowserFullscreen:l,isBrowserFullscreenDismissible:i,browserFullscreen:o,effectiveFullscreenElementId:d,isRemoteFullscreen:u,isFullscreenDismissible:x,applyFullscreen:a,safeElements:w,lessonId:g,readOnly:D,renderElement:W,children:k})=>{if(t.width<=0||t.height<=0)return null;if(r){const z=w.find(j=>j.id===r);if(!z)return l?e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center bg-slate-900/80 backdrop-blur-xs text-white",children:[e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-400 mb-3"}),e.jsx("p",{className:"text-xs font-medium text-slate-200",children:"正在同步教师端的浏览器全屏组件..."})]}):null;const m=Ue(z);return e.jsx(Po,{elementId:r,type:z.type,data:m,lessonId:g,readOnly:D,dismissible:i,onExit:()=>void o.exit(),renderContent:j=>e.jsx(pn,{width:j.width,height:j.height,children:W(z,{fullscreen:{width:j.width,height:j.height,padding:To}})})})}if(d){const z=w.find(j=>j.id===d);if(!z)return u?e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center bg-slate-900/60 backdrop-blur-xs text-white",children:[e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-400 mb-3"}),e.jsx("p",{className:"text-xs font-medium text-slate-200",children:"正在同步教师端全屏组件..."})]}):null;const m=Ue(z);return e.jsx(Li,{type:z.type,title:Do[z.type]||z.type,data:m,containerSize:t,dismissible:x,onClose:()=>a(null),lessonId:g,elementId:z.id,readOnly:D,renderContent:j=>e.jsx(pn,{width:j.width,height:j.height,children:W(z,{fullscreen:{width:j.width,height:j.height,padding:0}})})})}return e.jsx(e.Fragment,{children:k})},_o=({autoTileEnabled:t,readOnly:r,tilingSplitters:l,activeSplitterDrag:i,activeDropZoneAction:o,handleSplitterPointerDown:d})=>!t||r?null:e.jsxs(e.Fragment,{children:[l.length>0&&e.jsx("div",{className:"absolute inset-0 pointer-events-none z-30",children:l.map(u=>{const x=u.orientation==="horizontal",a=i?.splitter.id===u.id;return e.jsxs("div",{"data-testid":`splitter-${u.orientation}-${u.id}`,className:`absolute pointer-events-auto group flex items-center justify-center select-none ${x?"cursor-row-resize":"cursor-col-resize"}`,style:{left:`${u.x}px`,top:`${u.y}px`,width:`${x?u.length:u.thickness}px`,height:`${x?u.thickness:u.length}px`},onPointerDown:w=>d(w,u),title:x?"拖动调整上下分割高度":"拖动调整左右分割宽度",children:[e.jsx("div",{className:`rounded-full transition-all duration-150 ${x?`w-full h-1 my-auto ${a?"bg-indigo-500 h-1.5 shadow-md":"bg-transparent group-hover:bg-indigo-400/80 group-hover:h-1.5"}`:`h-full w-1 mx-auto ${a?"bg-indigo-500 w-1.5 shadow-md":"bg-transparent group-hover:bg-indigo-400/80 group-hover:w-1.5"}`}`}),e.jsx("div",{className:`absolute rounded-full transition-all duration-150 flex items-center justify-center ${a?"bg-indigo-600 text-white scale-110 shadow-lg":"opacity-0 group-hover:opacity-100 bg-white/95 dark:bg-slate-800/95 text-indigo-600 shadow border border-indigo-200 dark:border-indigo-700"} ${x?"w-8 h-3.5":"h-8 w-3.5"}`,children:e.jsxs("div",{className:`flex ${x?"flex-row gap-0.5":"flex-col gap-0.5"}`,children:[e.jsx("div",{className:"w-1 h-1 rounded-full bg-current opacity-70"}),e.jsx("div",{className:"w-1 h-1 rounded-full bg-current opacity-70"}),e.jsx("div",{className:"w-1 h-1 rounded-full bg-current opacity-70"})]})})]},u.id)})}),o&&o.type!=="swap"&&e.jsx("div",{"data-testid":"directional-split-preview",className:"absolute pointer-events-none rounded-2xl border-3 border-dashed border-indigo-500 bg-indigo-500/20 backdrop-blur-[2px] shadow-2xl flex items-center justify-center transition-all duration-150 z-40 animate-in fade-in zoom-in-95",style:{left:`${o.previewRect.x}px`,top:`${o.previewRect.y}px`,width:`${o.previewRect.width}px`,height:`${o.previewRect.height}px`},children:e.jsx("div",{className:"bg-indigo-600 text-white text-xs md:text-sm font-bold px-4 py-2 rounded-full shadow-lg flex items-center gap-2 select-none animate-bounce",children:e.jsx("span",{children:o.label})})})]}),Ro={quiz:{width:340,height:380},timer:{width:280,height:200},assignment:{width:340,height:400},rollcall:{width:340,height:420},"html-applet":{width:400,height:300},"code-sandbox":{width:400,height:320},"math-graph":{width:400,height:350},presentation:{width:600,height:400},plugin:{width:500,height:400}};function jt(t,r){const l=Ro[t];return l?{width:r?.width||l.width,height:r?.height||l.height}:{width:r?.width||300,height:r?.height||300}}function Ao({containerSize:t,safeElements:r,getCurrentPageElements:l,onElementUpdate:i,lessonId:o,readOnly:d,setLocalGeometry:u,localGeometryRef:x,localGeometryVersion:a,currentPage:w,activeSegmentId:g,pages:D,tileSplitPreferenceRef:W,setIsSyncing:k}){const[z,m]=n.useState(!1),[j,y]=n.useState(null),f=n.useRef(null);n.useEffect(()=>{f.current=j},[j]);const T=n.useCallback(async(v,P,C)=>{if(!i||t.width<=0||t.height<=0)return;const M=v.filter(I=>Qe(I.type));if(M.length===0)return;const q=[],X=new Map,A=new Map;let F=P??W.current;for(const I of M){const G=Ue(I,null);if(!G)continue;!F&&G.tileStackDir&&(F=G.tileStackDir);const le=Zs(I,G,jt(I.type,G));if(le)if(q.push(le),X.set(I.id,G),C){const se=C.indexOf(I.id);A.set(I.id,se>=0?se:void 0)}else A.set(I.id,typeof G.tileOrder=="number"?G.tileOrder:void 0)}if(q.length===0)return;const L=Pa(q,A),p=Sa(L,t,{stackDirection:F});if(p.length===0)return;let $=!1;k(!0);try{for(let I=0;I<L.length;I+=1){const G=L[I],le=X.get(G.id);if(!le)continue;const se=Ma(G,p[I]),ve=Qs(G.shape);if(er(le,se,ve)&&le.tileOrder===I&&le.tileStackDir===F)continue;$=!0,u(G.id,se);const Le={...le,...se,tileOrder:I,tileStackDir:F};le.__preTile||(Le.__preTile=za(G)),Le.__tiled=se;const ze=v.find(ye=>ye.id===G.id)||r.find(ye=>ye.id===G.id);ze&&(ze.data=JSON.stringify(Le)),await i(G.id,Le)}if(!$)return;ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}},[i,t,r,o,u,W,k]),H=n.useCallback(async(v,P)=>{const C=l().filter(M=>Qe(M.type));await T(C,v,P)},[l,T]),Z=n.useCallback(async(v,P)=>{if(!i||v===P)return;const C=r.find(Ce=>Ce.id===v),M=r.find(Ce=>Ce.id===P);if(!C||!M)return;const q=Ue(C,null),X=Ue(M,null);if(!q||!X)return;const A=at(q,C.type==="circle"?"circle":"rect"),F=at(X,M.type==="circle"?"circle":"rect"),L=x.current.get(v),p=x.current.get(P),$={...A,...L||{}},I={...F,...p||{}},G=l().filter(Ce=>Qe(Ce.type)),le=G.findIndex(Ce=>Ce.id===v),se=G.findIndex(Ce=>Ce.id===P),ve=typeof q.tileOrder=="number"?q.tileOrder:le>=0?le:0,Le=typeof X.tileOrder=="number"?X.tileOrder:se>=0?se:1,ze={...q,...I,tileOrder:Le},ye={...X,...$,tileOrder:ve};q.__preTile||(ze.__preTile=at(q,C.type==="circle"?"circle":"rect")),X.__preTile||(ye.__preTile=at(X,M.type==="circle"?"circle":"rect")),ze.__tiled=I,ye.__tiled=$,u(v,I),u(P,$),k(!0);try{await Promise.all([i(v,ze),i(P,ye)]),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}},[i,r,l,u,x,o,k]),J=n.useCallback(async()=>{if(!i)return;const v=[];for(const P of r){const C=Ue(P,null);if(!C||!C.__preTile)continue;const{__preTile:M,__tiled:q,tileOrder:X,...A}=C,F=Qs(P.type==="circle"?"circle":"rect"),L=!q||er(C,q,F);v.push({id:P.id,patch:L?{...A,...M}:A})}if(v.length!==0){k(!0);try{for(const{id:P,patch:C}of v){const M=C.radius!==void 0?"circle":"rect";u(P,at(C,M)),await i(P,C)}ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}}},[i,r,o,u,k]),O=n.useCallback(async(v,P,C)=>{if(!i||v===P)return;const q=l().filter(L=>Qe(L.type)).map(L=>{const p=Ue(L),$=jt(L.type,p),I=x.current.get(L.id);return{id:L.id,x:I?.x??p.x??0,y:I?.y??p.y??0,width:I?.width??p.width??$.width,height:I?.height??p.height??$.height}}),X=12,A={x:X,y:X,width:Math.max(0,t.width-X*2),height:Math.max(0,t.height-X*2)},F=Ra(v,P,C,q,A);if(Object.keys(F).length!==0){k(!0);try{for(const[L,p]of Object.entries(F)){const $=q.find(I=>I.id===L);$&&u(L,Object.assign({x:$.x,y:$.y,width:$.width,height:$.height},p))}await Promise.all(Object.entries(F).map(async([L,p])=>{const $=r.find(ve=>ve.id===L);if(!$)return;const I=Ue($,{}),G=$.type==="circle"?"circle":"rect",se={...at(I,G),...p};u(L,se),await i(L,{...I,...p,__tiled:se})})),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}}},[i,r,l,t,u,x,o,k]),he=n.useCallback(()=>{z&&J(),m(!z)},[z,J]),K=n.useMemo(()=>z?l().filter(P=>Qe(P.type)).map(P=>{let C={};try{C=JSON.parse(P.data)}catch{}const M=jt(P.type,C),q=x.current.get(P.id);return{id:P.id,x:q?.x??C.x??0,y:q?.y??C.y??0,width:q?.width??C.width??M.width,height:q?.height??C.height??M.height}}):[],[z,r,w,g,D,a,l,x]),ue=n.useMemo(()=>!z||K.length<2?[]:Da(K),[z,K]),E=n.useCallback((v,P)=>{if(d)return;v.preventDefault(),v.stopPropagation();const C=P.orientation==="horizontal"?v.clientY:v.clientX;y({splitter:P,startPointerPos:C,initialBoxes:K})},[d,K]),te=n.useRef(H);n.useEffect(()=>{te.current=H},[H]);const U=n.useMemo(()=>z?l().filter(v=>Qe(v.type)).map(v=>v.id).join("|"):"",[z,r,w,g,D,l]);return n.useEffect(()=>{!z||!U||te.current()},[z,U]),n.useEffect(()=>{if(!z||t.width<=0||t.height<=0)return;const v=setTimeout(()=>{te.current()},250);return()=>clearTimeout(v)},[z,t.width,t.height]),n.useEffect(()=>{if(!j)return;const v=C=>{if(!f.current)return;const{splitter:M,startPointerPos:q,initialBoxes:X}=f.current,L=(M.orientation==="horizontal"?C.clientY:C.clientX)-q,p=Ea(M,L,X);for(const[$,I]of Object.entries(p)){const G=X.find(le=>le.id===$);G&&u($,{x:G.x,y:G.y,width:G.width,height:G.height,...I})}},P=async()=>{if(!f.current)return;const{splitter:C,startPointerPos:M,initialBoxes:q}=f.current;if(C.orientation==="horizontal"&&window.event&&window.event.clientY,y(null),i&&q.length>0){k(!0);try{await Promise.all(q.map(async A=>{const F=r.find(L=>L.id===A.id);if(F)try{const L=JSON.parse(F.data),p=x.current.get(A.id);p&&await i(A.id,{...L,...p,__tiled:p})}catch{}})),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:o},timestamp:Date.now(),correlationId:o})}finally{k(!1)}}};return window.addEventListener("pointermove",v),window.addEventListener("pointerup",P),()=>{window.removeEventListener("pointermove",v),window.removeEventListener("pointerup",P)}},[j,i,r,o,u,x,k]),{autoTileEnabled:z,setAutoTileEnabled:m,handleToggleAutoTile:he,currentTilingBoxes:K,tilingSplitters:ue,activeSplitterDrag:j,setActiveSplitterDrag:y,activeSplitterDragRef:f,handleSplitterPointerDown:E,applyAutoTiling:H,applyAutoTilingForElements:T,swapTileElements:Z,restoreAutoTiling:J,insertTileInDirection:O}}const Fo=({showEntrySelector:t,setShowEntrySelector:r,zipUploadInfo:l,zipCandidates:i,handlePropsUpdate:o,fetchCoursewares:d})=>!t||!l?null:e.jsx("div",{className:"absolute inset-0 bg-neutral-900/40 backdrop-blur-[2px] flex items-center justify-center z-[9999] p-4 font-sans",children:e.jsxs("div",{className:"bg-white rounded-xl shadow-2xl overflow-hidden max-w-sm w-full border border-gray-100 flex flex-col scale-100 pointer-events-auto",children:[e.jsxs("div",{className:"px-5 py-4 border-b border-gray-150/60 bg-gray-50 flex justify-between items-center shrink-0",children:[e.jsx("h3",{className:"font-bold text-gray-800 text-sm",children:"选择课件入口页面"}),e.jsx("button",{onClick:()=>r(!1),className:"text-gray-400 hover:text-gray-650 transition-colors text-xl font-light cursor-pointer",children:"×"})]}),e.jsxs("div",{className:"p-5 flex-1 min-h-0 space-y-3",children:[e.jsx("p",{className:"text-xs text-gray-600 leading-relaxed font-medium",children:"ZIP压缩包中含有多个HTML文件,请选择一个作为课件入口:"}),e.jsx("div",{className:"max-h-60 overflow-y-auto border border-gray-200 rounded-lg p-2 bg-gray-50 space-y-1",children:i.map(u=>e.jsxs("button",{onClick:async()=>{try{const x=await fetch("/api/courseware/confirm",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({uuid:l.uuid,name:l.name,entry:u})});if(x.ok){const a=await x.json();o({coursewareUuid:a.uuid,resourceId:""}),r(!1),d({force:!0})}}catch(x){console.error("Failed to confirm entry point:",x)}},className:"w-full text-left p-2 rounded hover:bg-indigo-50 hover:text-indigo-700 text-xs font-semibold font-mono truncate transition-all cursor-pointer",children:["📄 ",u]},u))})]}),e.jsx("div",{className:"px-5 py-3 border-t border-gray-100 bg-gray-50 flex justify-end gap-2 text-xs shrink-0",children:e.jsx("button",{onClick:()=>r(!1),className:"px-4 py-2 text-gray-500 hover:bg-gray-100 rounded-lg transition-colors font-medium border border-gray-200 cursor-pointer",children:"取消"})})]})}),Lo=({isOpen:t,onClose:r,element:l,coursewares:i=[],fetchCoursewares:o,onApplyTemporary:d,onSavePermanent:u})=>{const x=rr.useMemo(()=>{if(!l?.data)return{title:"Interactive Courseware"};try{return typeof l.data=="string"?JSON.parse(l.data):l.data}catch{return{title:"Interactive Courseware"}}},[l]),[a,w]=n.useState(x.title||"Interactive Courseware"),[g,D]=n.useState(x.coursewareUuid||""),[W,k]=n.useState(x.code||""),[z,m]=n.useState(!0),[j,y]=n.useState(!1),[f,T]=n.useState(null);if(n.useEffect(()=>{t&&l&&(w(x.title||"Interactive Courseware"),D(x.coursewareUuid||""),k(x.code||""),m(!0),T(null))},[t,l,x]),n.useEffect(()=>{if(!t)return;const J=O=>{O.key==="Escape"&&r()};return window.addEventListener("keydown",J),()=>window.removeEventListener("keydown",J)},[t,r]),!t||!l)return null;const H=async J=>{y(!0),T(null);try{const O=new FileReader;O.onload=async he=>{const K=he.target?.result;try{const ue=await fetch("/api/courseware/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:J.name.replace(/\.[^/.]+$/,""),filename:J.name,base64Data:K})}),E=await ue.json();ue.ok&&E.uuid?(D(E.uuid),o&&await o({force:!0})):T(E.error||"课件上传失败")}catch(ue){T(ue.message||"网络异常")}finally{y(!1)}},O.readAsDataURL(J)}catch(O){T(O.message||"读取文件失败"),y(!1)}},Z=async()=>{const J={...x,title:a.trim()||"Interactive Courseware",coursewareUuid:g||void 0,code:g?void 0:W};z?d(l.id,J):u&&await u(l.id,J),r()};return e.jsx("div",{className:"fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/60 backdrop-blur-xs select-none animate-in fade-in duration-150",onPointerDown:J=>{J.target===J.currentTarget&&r()},role:"dialog","aria-modal":"true","aria-labelledby":"courseware-props-modal-title",children:e.jsxs("div",{className:"w-full max-w-xl bg-surface border border-theme rounded-2xl shadow-2xl flex flex-col overflow-hidden text-main font-sans animate-in zoom-in-95 duration-150",onPointerDown:J=>J.stopPropagation(),children:[e.jsxs("div",{className:"px-5 py-4 border-b border-theme bg-surface-secondary/50 flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2.5",children:[e.jsx("span",{className:"p-2 rounded-xl bg-primary-theme/10 text-primary-theme border border-primary-theme/20",children:e.jsx(or,{size:18})}),e.jsxs("div",{children:[e.jsx("h3",{id:"courseware-props-modal-title",className:"text-sm font-bold text-main leading-tight",children:"课堂课件属性临时调整"}),e.jsx("p",{className:"text-xs text-muted mt-0.5",children:"实时调节互动课件展示属性与数据源"})]})]}),e.jsx("button",{onClick:r,className:"p-1.5 rounded-lg text-muted hover:text-main hover:bg-surface-secondary transition-colors cursor-pointer",title:"关闭窗口",children:e.jsx(es,{size:16})})]}),e.jsxs("div",{className:"p-5 space-y-4 max-h-[75vh] overflow-y-auto",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-semibold text-muted mb-1.5",children:"课件展示标题"}),e.jsx("input",{type:"text",value:a,onChange:J=>w(J.target.value),placeholder:"请输入课件窗口标题...",className:"w-full px-3 py-2 text-xs bg-surface border border-theme hover:border-primary-theme/60 rounded-xl focus:outline-none focus:ring-2 focus:ring-primary-theme/20 text-main transition-all font-medium"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("label",{className:"block text-xs font-semibold text-muted",children:"关联课件源 (选择现有课件包或使用独立代码)"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("select",{value:g,onChange:J=>D(J.target.value),className:"flex-1 px-3 py-2 text-xs bg-surface border border-theme hover:border-primary-theme/60 rounded-xl focus:outline-none focus:ring-1 focus:ring-primary-theme text-main font-medium",children:[e.jsx("option",{value:"",children:"-- 使用下方手写 HTML/JS 代码 --"}),i.map(J=>e.jsxs("option",{value:J.uuid,children:["📦 [互动课件] ",J.name]},J.id||J.uuid))]}),e.jsxs("label",{className:`px-3 py-2 text-xs rounded-xl border border-primary-theme/30 bg-primary-theme/5 hover:bg-primary-theme/10 text-primary-theme font-semibold flex items-center gap-1.5 transition-colors cursor-pointer shrink-0 ${j?"opacity-50 pointer-events-none":""}`,title:"上传本地互动课件包 (.zip / .html)",children:[j?e.jsx(Et,{size:13,className:"animate-spin"}):e.jsx(ys,{size:13}),e.jsx("span",{children:j?"正在上传...":"上传新课件"}),e.jsx("input",{type:"file",accept:".zip,.html,.htm",className:"hidden",onChange:J=>{const O=J.target.files?.[0];O&&H(O)}})]})]}),f&&e.jsxs("div",{className:"p-2.5 rounded-lg bg-rose-500/10 border border-rose-500/20 text-rose-500 text-xs flex items-center gap-2",children:[e.jsx(Dt,{size:14,className:"shrink-0"}),e.jsx("span",{children:f})]}),!g&&e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsxs("span",{className:"text-2xs text-muted flex items-center gap-1 font-semibold",children:[e.jsx(xa,{size:12}),"自定义沙箱代码 (HTML / JavaScript):"]}),e.jsx("span",{className:"text-2xs text-muted/80",children:"已自动注入 LMS Bridge SDK"})]}),e.jsx("textarea",{rows:5,value:W,onChange:J=>k(J.target.value),placeholder:"<!DOCTYPE html><html><body><h1>互动演示</h1>...</body></html>",className:"w-full px-3 py-2 text-xs font-mono bg-surface-secondary/70 border border-theme rounded-xl focus:outline-none focus:ring-1 focus:ring-primary-theme text-main"})]})]}),e.jsx("div",{className:"p-3.5 rounded-xl border border-emerald-500/30 bg-emerald-500/5 space-y-2",children:e.jsxs("label",{className:"flex items-start gap-2.5 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:z,onChange:J=>m(J.target.checked),className:"mt-0.5 rounded border-emerald-400 text-emerald-600 focus:ring-emerald-500 cursor-pointer"}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("span",{className:"text-xs font-bold text-emerald-800 dark:text-emerald-300 flex items-center gap-1.5",children:[e.jsx(ha,{size:14,className:"text-emerald-600"}),"仅在本次课堂临时生效(推荐,不覆盖课程设置中的课件内容)"]}),e.jsx("p",{className:"text-2xs text-emerald-700/80 dark:text-emerald-400/80 mt-0.5",children:z?"当前修改仅即时同步给本堂课的学生设备,不会修改原教案数据库,其他平行班级复用不受影响。":"警告:已取消临时保护,点击应用后将直接持久化更新原课程教案中的课件配置!"})]})]})})]}),e.jsxs("div",{className:"px-5 py-3 border-t border-theme bg-surface-secondary/30 flex items-center justify-between",children:[e.jsx("span",{className:"text-xs text-muted",children:z?"⚡ 即时生效,安全无污染":"💾 将同步写回课程数据库"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:r,className:"px-3.5 py-1.5 rounded-xl text-xs font-semibold text-muted hover:text-main hover:bg-surface-secondary border border-transparent transition-colors cursor-pointer",children:"取消"}),e.jsxs("button",{type:"button",onClick:Z,className:"px-4 py-1.5 rounded-xl text-xs font-bold bg-primary-theme hover:bg-primary-theme/90 text-white shadow-sm flex items-center gap-1.5 transition-transform active:scale-95 cursor-pointer",children:[e.jsx(_n,{size:13}),e.jsx("span",{children:z?"临时应用至本课":"保存并更新课程"})]})]})]})]})})},fs="ABCDEFGHIJKLMNOPQRSTUVWXYZ",Bo=({data:t,lessonId:r,elementId:l})=>{const[i,o]=n.useState({}),[d,u]=n.useState(null),[x,a]=n.useState(null),[w,g]=n.useState(!1),[D,W]=n.useState(null),[k,z]=n.useState(t.submissions||{});n.useEffect(()=>{z(t.submissions||{})},[t.submissions]),n.useEffect(()=>{if(!d||d.role==="student"||!r)return;let F=!1;return fetch(`/api/lessons/${encodeURIComponent(r)}/quiz-submissions`).then(L=>L.ok?L.json():null).then(L=>{if(F||!L?.quizzes)return;const p=L.quizzes.find($=>$.elementId===(l||t.id));p?.submissions&&z($=>({...$,...p.submissions}))}).catch(()=>{}),()=>{F=!0}},[d,r,l]),n.useEffect(()=>{let F=!1;return fetch("/api/students?pageSize=all").then(p=>p.ok?p.json():{data:[]}).then(p=>{if(F)return;const $=Bi(p),I={};for(const G of $)I[G.id]=G.name;o(I)}).catch(()=>{}),(async()=>{try{let p=await fetch("/api/auth/session").catch(()=>null);if((!p||!p.ok)&&(p=await fetch("/api/auth/me").catch(()=>null)),p&&p.ok&&!F){const $=await p.json(),I=$.session||$;I&&typeof I=="object"&&!Array.isArray(I)&&I.role&&u({id:I.id||I.userId,role:I.role,studentId:I.studentId||I.userId||I.id})}}catch{}})(),()=>{F=!0}},[]);const m=Object.entries(k),j=Bn(t),y=j===null?void 0:j,f=D?.correctIndex??y,T=typeof t.passScore=="number"?t.passScore:60,H=d?.studentId||d?.id,Z=H?k[H]:null,J=typeof window<"u"&&(new URLSearchParams(window.location?.search||"").get("mode")==="student_live"||(window.location?.hash||"").includes("student_live")),O=d?.role==="student"||J,he=!!Z||!!D,K=!O||he,ue=F=>{if(typeof F=="number"&&!isNaN(F))return F;if(typeof F=="string"){const L=parseFloat(F);return isNaN(L)?null:L}return null},E=Array.isArray(t.options)?t.options.map(F=>String(F)):[],te=F=>{const L=sr(F,E);return L===null?void 0:L},U=async()=>{if(x===null||w)return;g(!0);const F=fs[x]||String(x),L=x;try{const p=r||"current",$=l||t.id||"quiz",I=await fetch(`/api/lessons/${encodeURIComponent(p)}/quiz-submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elementId:$,answer:L})}),G=await I.json().catch(()=>null);if(I.ok&&G?.success){W({isCorrect:G.isCorrect,score:G.score,answer:F,correctIndex:typeof G.correctIndex=="number"?G.correctIndex:void 0});const le=G.studentId||H||"me";z(se=>({...se,[le]:{answer:x,score:G.score,time:Date.now()}})),window.dispatchEvent(new CustomEvent("openlearn:segment-gate-changed",{detail:{lessonId:p}}))}}catch{}finally{g(!1)}},v=m.map(([F,L])=>{const p=te(L),$=ue(L.score),I=p!==void 0&&f!==void 0?p===f:$!==null?$>=T:!1;return{sid:F,v:L,answerIdx:p,scoreNum:$,isCorrect:I}}),P=m.length,C=v.filter(F=>F.isCorrect).length,M=P>0?Math.round(C/P*100):0,q=v.map(F=>F.scoreNum).filter(F=>F!==null),X=q.length>0?q.reduce((F,L)=>F+L,0)/q.length:null,A=F=>{if(F==null)return"-";const L=typeof F=="number"?F:Number(F),p=isNaN(L)?new Date(String(F)):new Date(L);return isNaN(p.getTime())?"-":p.toLocaleTimeString()};return e.jsxs("div",{className:"max-w-2xl mx-auto space-y-6",children:[e.jsx("h3",{className:"text-xl font-bold text-gray-800","data-testid":"quiz-question",children:t.question}),D&&e.jsxs("div",{"data-testid":"quiz-feedback",className:`p-4 rounded-xl border flex items-center justify-between text-sm font-bold ${D.isCorrect?"bg-emerald-50 border-emerald-300 text-emerald-800":"bg-rose-50 border-rose-300 text-rose-800"}`,children:[e.jsx("span",{children:D.isCorrect?`🎉 回答正确!得分:${D.score} 分`:`❌ 回答错误。得分:${D.score} 分`}),e.jsx("span",{className:"text-xs font-normal",children:"提交已实时同步至教师大屏"})]}),e.jsx("div",{className:"flex flex-col gap-3",children:(t.options||[]).map((F,L)=>{const p=x===L,$=f===L;let I="bg-gray-50 border-gray-200 text-gray-700";return K&&$?I="bg-green-50 border-green-300 text-green-800":p?I="bg-indigo-50 border-indigo-400 text-indigo-900 ring-2 ring-indigo-200 shadow-xs":O&&!he&&(I="bg-white hover:bg-gray-50 border-gray-200 text-gray-800 cursor-pointer"),e.jsxs("div",{"data-testid":`quiz-option-${L}`,onClick:()=>{O&&!he&&a(L)},className:`px-5 py-4 text-left rounded-xl text-base border-2 transition-all ${I}`,children:[e.jsxs("span",{className:"font-bold text-indigo-600 mr-3",children:[fs[L],"."]}),F,K&&$&&e.jsx("span",{className:"ml-2 text-xs font-bold text-green-600",children:"✓ 正确答案"})]},L)})}),O&&!he&&e.jsx("div",{className:"pt-2 flex justify-end",children:e.jsx("button",{"data-testid":"quiz-submit-btn",disabled:x===null||w,onClick:U,className:"px-6 py-2.5 bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed text-white font-bold text-sm rounded-xl shadow-sm transition-all cursor-pointer",children:w?"提交中...":"提交答案"})}),!O&&(P===0?e.jsx("div",{className:"mt-4 p-4 bg-gray-50 rounded-xl text-center text-sm text-gray-400",children:"暂无学生提交"}):e.jsxs("div",{className:"mt-4 space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-4 gap-3","data-testid":"quiz-summary",children:[e.jsxs("div",{className:"bg-gray-50 rounded-xl p-3 text-center",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"提交"}),e.jsx("div",{className:"text-xl font-bold text-gray-700","data-testid":"quiz-stat-submitted",children:P})]}),e.jsxs("div",{className:"bg-green-50 rounded-xl p-3 text-center",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"通过"}),e.jsx("div",{className:"text-xl font-bold text-green-600","data-testid":"quiz-stat-passed",children:C})]}),e.jsxs("div",{className:"bg-indigo-50 rounded-xl p-3 text-center",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"通过率"}),e.jsxs("div",{className:"text-xl font-bold text-indigo-600",children:[M,"%"]})]}),e.jsxs("div",{className:"bg-amber-50 rounded-xl p-3 text-center",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"均分"}),e.jsx("div",{className:"text-xl font-bold text-amber-600",children:X!==null?X.toFixed(1):"-"})]})]}),e.jsx("div",{className:"overflow-x-auto border border-gray-200 rounded-xl",children:e.jsxs("table",{className:"w-full text-sm","data-testid":"quiz-submissions-table",children:[e.jsx("thead",{className:"bg-gray-50 text-gray-500 text-xs uppercase",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2 text-left",children:"学生"}),e.jsx("th",{className:"px-4 py-2 text-left",children:"答案"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"得分"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"提交时间"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-100",children:v.map(({sid:F,v:L,answerIdx:p,scoreNum:$,isCorrect:I})=>{const G=p!==void 0&&p>=0&&p<fs.length?fs[p]:"-",le=$!==null?$:I?100:0,se=i[F]||F;return e.jsxs("tr",{className:"hover:bg-gray-50","data-testid":`quiz-row-${F}`,children:[e.jsx("td",{className:"px-4 py-2 font-medium text-gray-700",children:se}),e.jsxs("td",{className:`px-4 py-2 font-mono ${I?"text-green-600 font-bold":"text-red-500"}`,children:[G,I?" ✓":""]}),e.jsx("td",{className:`px-4 py-2 text-right font-mono font-bold ${le>=T?"text-green-600":"text-gray-600"}`,children:le}),e.jsx("td",{className:"px-4 py-2 text-right text-gray-500 text-xs",children:A(L.time??L.timestamp)})]},F)})})]})})]}))]})};qi.registerHostBuiltin("quiz",Bo);const Wo=80,nt=({title:t="教师已开启全班专注锁定,当前为只读演示视图"})=>e.jsx("div",{"data-testid":"whiteboard-readonly-lock-cover",className:"absolute inset-0 z-50 bg-transparent cursor-not-allowed select-none",style:{pointerEvents:"auto"},onClick:r=>{r.stopPropagation(),r.preventDefault()},onPointerDown:r=>{r.stopPropagation(),r.preventDefault()},onMouseDown:r=>{r.stopPropagation(),r.preventDefault()},onTouchStart:r=>{r.stopPropagation(),r.preventDefault()},title:t});let it={data:[],ts:0,inflight:null};const Ho=[{id:"page-0",title:"P1 · 引入导入",order:0},{id:"page-1",title:"P2 · 核心讲解",order:1},{id:"page-2",title:"P3 · 互动练习",order:2}],bn=4,il=n.forwardRef(({lessonId:t,elements:r,onElementAdd:l,onElementUpdate:i,onElementDelete:o,onClearBoard:d,onRefresh:u,enableAutoAI:x,activeSegmentId:a,onSegmentSync:w,initialPage:g,classroomTools:D,onExecuteTool:W,userRole:k="teacher",isEditMode:z=!0,readOnly:m=!1,classId:j,studentId:y,studentName:f,broadcastFullscreen:T=!1,fullscreenBroadcastClassId:H=null,followRemoteFullscreen:Z=!1,onFullscreenSync:J,hidePageBar:O=!1,onPagesStateChange:he,onElementDragChange:K,onElementDropCheck:ue},E)=>{const[te,U]=n.useState({}),v=n.useMemo(()=>{const s=Array.isArray(r)?r:[];return Object.keys(te).length===0?s:s.map(h=>te[h.id]||h)},[r,te]),P=Wi(s=>s.theme),C=Hi(s=>s.scale)/100;n.useEffect(()=>{dn.setTheme(P)},[P]);const M=dn.getTokens(),q=P==="dark"||P==="chalkboard",X=jn(s=>s.extensionPoints.get("whiteboard.renderer")),[A,F]=n.useState("cursor"),[L,p]=n.useState("#facc15"),[$,I]=n.useState(0),[G,le]=n.useState(!0),[se,ve]=n.useState(null),Le=n.useRef(null);n.useEffect(()=>{Le.current=se},[se]);const ze=n.useRef(null),[ye,Ce]=n.useState(null),xt=n.useRef(null);n.useEffect(()=>{xt.current=ye},[ye]);const re=n.useRef(null),[ge,_]=n.useState(void 0),b=n.useRef(ge);n.useEffect(()=>{b.current=ge},[ge]);const[V,ae]=n.useState(!1),[Q,oe]=n.useState(Ho),[_e,Ge]=n.useState(!1),[gt,Wt]=n.useState(null),[Ht,ss]=n.useState(""),[Wn,lr]=n.useState(null);n.useEffect(()=>{he?.({pages:Q,currentPage:$})},[Q,$,he]),n.useEffect(()=>{const s=v.find(h=>h.type==="page_meta");if(s){const h=Ue(s);Array.isArray(h?.pages)&&h.pages.length>0&&oe(h.pages)}},[r]);const cr=n.useRef(!1);n.useEffect(()=>{if(cr.current||!Array.isArray(Q)||Q.length===0)return;const s=Number(g);Number.isFinite(s)&&s>0&&s<Q.length&&I(s),cr.current=!0},[Q]);const dr=n.useCallback(s=>An(s,$,Q),[Q,$]),ur=n.useMemo(()=>Wa(v,$,Q,a),[v,$,Q,a]),ht=n.useCallback(()=>ur,[ur]),_t=n.useRef(null),Ns=n.useRef(null);n.useEffect(()=>(Ns.current=null,()=>{_t.current&&(clearTimeout(_t.current),_t.current=null)}),[t]);const Hn=n.useCallback(s=>{k!=="teacher"||!t||Ns.current!==s&&(_t.current&&clearTimeout(_t.current),_t.current=setTimeout(()=>{fetch(`/api/classroom/sessions/${encodeURIComponent(t)}/view-state`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({currentPage:s})}).then(h=>{h.ok?Ns.current=s:h.status===429&&console.warn("[InteractiveWhiteboard] view-state rate-limited (HTTP 429), skipping transient update.")}).catch(()=>{})},500))},[k,t]);n.useEffect(()=>{m&&(me(null),Me(null),F("cursor"),ot(null),ks(!1),Ss(null))},[m]);const Xt=s=>{const h=v.find(c=>c.type==="page_meta");h&&i?i(h.id,{pages:s}):l&&l("page_meta",{pages:s}),Ne.current&&Ne.current.emit("whiteboard-update",{roomId:t,type:"page-meta-update",payload:{pages:s}})},xr=s=>{I(s),lr(null),Ne.current&&Ne.current.emit("whiteboard-update",{roomId:t,type:"page-change",payload:{page:s}}),Hn(s)},hr=s=>{const{newPages:h,newIndex:c}=Ha(Q,s);oe(h),I(c),Xt(h),Ne.current&&Ne.current.emit("whiteboard-update",{roomId:t,type:"page-change",payload:{page:c}})},mr=(s,h)=>{if(!h.trim()){Wt(null);return}const c=Xa(Q,s,h);oe(c),Xt(c),Wt(null),ss("")},fr=s=>{const h=Q[s];if(!h)return;const c=Oa(Q,s);if(!c)return;const{newPages:N,newIndex:R,newPage:B}=c;oe(N),I(R),Xt(N),v.filter(ne=>ne.type!=="page_meta"&&(()=>{try{const xe=JSON.parse(ne.data);return(xe.page??0)===s||xe.pageId===h.id}catch{return s===0}})()).forEach(ne=>{try{const xe=JSON.parse(ne.data);l&&l(ne.type,{...xe,page:R,pageId:B.id,x:(xe.x??100)+20,y:(xe.y??100)+20})}catch(xe){console.error("Failed duplicating page element:",xe)}})},pr=s=>{if(Q.length<=1){Ie({title:"无法删除",message:"至少需要保留一个白板页面!",type:"alert",onConfirm:()=>{}});return}const h=Q[s],c=v.filter(R=>R.type!=="page_meta"&&(()=>{try{const B=JSON.parse(R.data);return(B.page??0)===s||B.pageId===h.id}catch{return s===0}})()),N=()=>{o&&c.forEach(ee=>o(ee.id));const R=Q.filter((ee,ne)=>ne!==s).map((ee,ne)=>({...ee,order:ne}));oe(R);const B=Math.min($,R.length-1);I(B),Xt(R)};c.length>0?Ie({title:"确认删除白板页面",message:`页面 [${h.title}] 包含 ${c.length} 个组件,删除页面将同时清理该页面的组件,是否确定删除?`,type:"confirm",onConfirm:N}):N()},br=(s,h)=>{const c=Ia(Q,s,h);if(!c)return;const{newPages:N,targetIndex:R}=c;oe(N),$===s?I(R):$===R&&I(s),Xt(N)},[Re,ot]=n.useState(null),[gr,ks]=n.useState(!1),Xn=n.useRef(null),[rs,yr]=n.useState({width:0,height:0}),[wr,jr]=n.useState({width:0,height:0}),Te=n.useRef(null),[Cs,we]=n.useState(!1),Ne=n.useRef(null),[On,vr]=n.useState({}),[Xo,Oo]=n.useState({}),[Io,qo]=n.useState({}),[Yo,Jo]=n.useState({}),[In,Nr]=n.useState({});n.useEffect(()=>{if(!t)return;let s=!1;return fetch(`/api/lessons/${encodeURIComponent(t)}/quiz-counts`).then(h=>h.ok?h.json():null).then(h=>{if(!h?.quizzes||s)return;const c={};for(const N of h.quizzes)c[N.elementId]=N.submissionCount;Nr(c)}).catch(()=>{}),()=>{s=!0}},[t]),ga({types:["quiz.answered"]},s=>{!s.elementId||s.lessonId!==t||Nr(h=>({...h,[s.elementId]:(h[s.elementId]??0)+1}))});const[qn,Ss]=n.useState(null),[Yn,Jn]=n.useState(null),kr=nn(s=>s.remoteFullscreenElementId),vt=Z&&!!kr,lt=vt?kr:qn,Un=!vt,Cr=nn(s=>s.remoteBrowserFullscreenElementId),ns=Z&&!!Cr,Rt=ns?Cr:Yn,Gn=!ns,Nt=Ua({elementId:Rt,enableNativeFullscreen:!ns,onChange:s=>{Jn(s),T&&Ne.current&&Ne.current.emit("teacher-broadcast-fullscreen",{classId:H,lessonId:t,elementId:s,mode:"browser"})}});n.useEffect(()=>{Rt&&!v.some(s=>s.id===Rt)&&Nt.exit()},[Rt,v,Nt]);const Sr=n.useRef(J);n.useEffect(()=>{Sr.current=J},[J]);const mt=s=>{Ss(s),J?.(s),T&&Ne.current&&Ne.current.emit("teacher-broadcast-fullscreen",{classId:H,lessonId:t,elementId:s,mode:"board"})};n.useEffect(()=>{if(T)return()=>{Sr.current?.(null);const s={classId:H,lessonId:t,elementId:null};Ne.current?.emit("teacher-broadcast-fullscreen",{...s,mode:"board"}),Ne.current?.emit("teacher-broadcast-fullscreen",{...s,mode:"browser"})}},[T,H,t]);const is=!!lt&&!v.some(s=>s.id===lt),Ot=n.useRef(null);n.useEffect(()=>{if(!is||!vt){Ot.current=null;return}if(Ot.current==null){Ot.current=Date.now();return}Date.now()-Ot.current>=3e3&&(Ot.current=null,Xi.getState().clearRemoteFullscreen())},[is,vt]),n.useEffect(()=>{!is||vt||(Ss(null),J?.(null),T&&Ne.current&&Ne.current.emit("teacher-broadcast-fullscreen",{classId:H,lessonId:t,elementId:null}))},[is,vt,T,H,t,J]);const[It,qt]=n.useState(null),Be=n.useRef(new Map),[zs,kt]=n.useState(0),ct=n.useCallback((s,h)=>{Be.current.set(s,h),kt(c=>c+1)},[]),zr=n.useCallback(s=>{Be.current.delete(s)&&kt(h=>h+1)},[]);n.useEffect(()=>{Be.current.clear(),kt(s=>s+1)},[t]),n.useEffect(()=>{if(Be.current.size!==0){for(const s of r){const h=Be.current.get(s.id);if(!h)continue;const c=Ue(s,null);if(!c){Be.current.delete(s.id);continue}const N=Object.keys(h);er(c,h,N)&&Be.current.delete(s.id)}kt(s=>s+1)}},[r]);const Mr=n.useRef(void 0),{autoTileEnabled:Oe,handleToggleAutoTile:Vn,tilingSplitters:Kn,activeSplitterDrag:Zn,handleSplitterPointerDown:Qn,applyAutoTiling:$r,applyAutoTilingForElements:At,swapTileElements:Tr,insertTileInDirection:Pr}=Ao({containerSize:rs,safeElements:v,getCurrentPageElements:ht,onElementUpdate:i,lessonId:t,readOnly:m,setLocalGeometry:ct,localGeometryRef:Be,localGeometryVersion:zs,currentPage:$,activeSegmentId:a,pages:Q,tileSplitPreferenceRef:b,setIsSyncing:we});n.useEffect(()=>{Mr.current=At,ze.current=Tr,re.current=Pr},[At,Tr,Pr]);const Dr=n.useMemo(()=>{const s=[];for(const h of ht())try{const c=Ue(h),N=Be.current.get(h.id),R=jt(h.type,c);s.push({x:N?.x??(Number.isFinite(c.x)?c.x:0),y:N?.y??(Number.isFinite(c.y)?c.y:0),width:N?.width??(Number.isFinite(c.width)?c.width:R.width),height:N?.height??(Number.isFinite(c.height)?c.height:R.height)})}catch{}return Fa(s)},[ht,zs]),Er=n.useMemo(()=>La(wr,Dr,Wo),[wr,Dr]),Ke=n.useCallback((s,h)=>{const c=Te.current;if(!c)return null;const N=c.getBoundingClientRect();return Ba(s,h,N,{scrollLeft:c.scrollLeft,scrollTop:c.scrollTop})},[]),Se=n.useRef(null),ke=n.useRef(null),Ct=n.useRef(null),[fe,_r]=n.useState(null),me=s=>{k==="teacher"&&_r(s)},[Ft,ei]=n.useState(null),Me=s=>{k==="teacher"&&ei(s)},[Rr,Ar]=n.useState(null),[St,Ms]=n.useState(null),Yt=n.useRef(null),[ti,Ie]=n.useState(null),[si,Fr]=n.useState(""),[Lr,$s]=n.useState(null),[zt,dt]=n.useState(null),[as,Mt]=n.useState(null),[Ts,Br]=n.useState(null),[Wr,Ps]=n.useState({}),[Hr,Ds]=n.useState({}),[Xr,Es]=n.useState([]),[ri,ni]=n.useState([]),[ii,ai]=n.useState(null),[oi,Or]=n.useState(!1),Jt=n.useRef(null),Ut=async s=>{const h=Date.now();if(!s?.force&&it.data.length>0&&h-it.ts<3e4){Es(it.data);return}if(it.inflight&&!s?.force){const R=await it.inflight;Es(R);return}const N=(async()=>{try{const R=await fetch("/api/courseware");if(R.ok){const B=await R.json();return it={data:Array.isArray(B)?B:[],ts:Date.now(),inflight:null},Es(it.data),it.data}}catch(R){console.error("Error fetching coursewares:",R)}finally{it.inflight=null}return it.data})();it.inflight=N,await N};n.useEffect(()=>{if(fe){const s=v.find(h=>h.id===fe);s?(s.type==="html-applet"?Jt.current!==fe&&(Jt.current=fe,Ut()):Jt.current=null,dt(Ue(s,{}))):(Jt.current=null,dt(null),Mt(null))}else Jt.current=null,dt(null),Mt(null)},[fe,r]);const $t=async s=>{const h=v.find(ee=>ee.id===fe);if(!h)return"noop";const N={...Ue(h,{}),...s},R=h.data,B=JSON.stringify(N);if(R!==B&&(Ps(ee=>{const ne=ee[h.id]?[...ee[h.id]]:[];return ne.length>=30&&ne.shift(),ne.push(R),{...ee,[h.id]:ne}}),Ds(ee=>({...ee,[h.id]:[]}))),i){we(!0);try{return await i(h.id,N),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u(),"saved"}catch(ee){return console.error("更新属性失败:",ee),"failed"}finally{we(!1)}}return"noop"},li=(s,h)=>{const c=v.find(R=>R.id===s);if(!c)return;const N=JSON.stringify(h);U(R=>({...R,[s]:{...c,data:N}})),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,temporary:!0},timestamp:Date.now(),correlationId:t})},ci=async(s,h)=>{if(U(c=>{const N={...c};return delete N[s],N}),i){we(!0);try{await i(s,h),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s},timestamp:Date.now(),correlationId:t}),u&&u()}catch(c){console.error("保存课件属性失败:",c)}finally{we(!1)}}},di=async()=>{if(!fe)return;const s=v.find(B=>B.id===fe);if(!s)return;const h=Wr[fe]||[];if(h.length===0)return;const c=h[h.length-1],N=h.slice(0,h.length-1),R=s.data;if(Ds(B=>{const ee=B[fe]?[...B[fe]]:[];return ee.push(R),{...B,[fe]:ee}}),Ps(B=>({...B,[fe]:N})),i){we(!0);try{const B=JSON.parse(c);dt(B),await i(fe,B),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}catch(B){console.error("撤销修改失败:",B)}finally{we(!1)}}},ui=async()=>{if(!fe)return;const s=v.find(B=>B.id===fe);if(!s)return;const h=Hr[fe]||[];if(h.length===0)return;const c=h[h.length-1],N=h.slice(0,h.length-1),R=s.data;if(Ps(B=>{const ee=B[fe]?[...B[fe]]:[];return ee.push(R),{...B,[fe]:ee}}),Ds(B=>({...B,[fe]:N})),i){we(!0);try{const B=JSON.parse(c);dt(B),await i(fe,B),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}catch(B){console.error("重做修改失败:",B)}finally{we(!1)}}},xi=(s,h)=>{dt(c=>c&&{...c,[s]:h})},hi=(s,h)=>{$t({[s]:h})},Ir=s=>{dt(h=>h&&{...h,...s}),$t(s)},mi=(s,h)=>{const c=parseFloat(h);isNaN(c)||$t({[s]:c})},fi=(s,h)=>{dt(c=>{if(!c)return c;const N=[...c.options||[]];return N[s]=h,{...c,options:N}})},pi=(s,h)=>{if(!zt)return;const c=[...zt.options||[]];c[s]=h,$t({options:c})},bi=()=>{if(!zt)return;const s=zt.options||[],c="ABCDEFGHIJKLMNOPQRSTUVWXYZ"[s.length]||`Option ${s.length+1}`,N=[...s,`选项 ${c}`];dt(R=>R&&{...R,options:N}),$t({options:N})},gi=s=>{if(!zt)return;const h=(zt.options||[]).filter((c,N)=>N!==s);dt(c=>c&&{...c,options:h}),$t({options:h})};n.useEffect(()=>{const s=()=>{Me(null)};return window.addEventListener("click",s),()=>window.removeEventListener("click",s)},[]);const os=n.useRef(K);n.useEffect(()=>{os.current=K},[K]);const qr=n.useRef(ue);n.useEffect(()=>{qr.current=ue},[ue]);const _s=(s,h,c)=>{if(k!=="teacher")return;s.preventDefault();const N=Be.current.get(h),R=N?.x??c.x??0,B=N?.y??c.y??0,ee={id:h,initialX:R,initialY:B,currentX:R,currentY:B,startPointerX:s.clientX,startPointerY:s.clientY,data:{...c,...N??{},x:R,y:B}};Se.current=ee,qt(ee);const ne=v.find(xe=>xe.id===h);os.current?.({elementId:h,elementType:ne?.type||"unknown",elementData:ee.data,clientX:s.clientX,clientY:s.clientY,initialPage:$,initialSegmentId:ee.data.segmentId||a})},Rs=s=>{},As=async s=>{},ls=(s,h,c,N,R,B,ee)=>{if(k!=="teacher")return;s.preventDefault(),s.stopPropagation();const ne={id:h,corner:c,startX:s.clientX,startY:s.clientY,initialX:N,initialY:R,initialWidth:B,initialHeight:ee},xe={id:h,x:N,y:R,width:B,height:ee};ke.current=ne,Ct.current=xe,Ar(ne),Ms(xe)},cs=s=>{},ds=async s=>{};n.useEffect(()=>{if(!It)return;const s=c=>{if(!Se.current)return;const N=c.clientX-Se.current.startPointerX,R=c.clientY-Se.current.startPointerY,B=Se.current.initialX,ee=Se.current.initialY;Se.current.currentX=B+N,Se.current.currentY=ee+R,qt({...Se.current});const ne=v.find(xe=>xe.id===Se.current?.id);if(os.current?.({elementId:Se.current.id,elementType:ne?.type||"unknown",elementData:Se.current.data,clientX:c.clientX,clientY:c.clientY,initialPage:$,initialSegmentId:Se.current.data?.segmentId||a}),Oe){const xe=Ke(c.clientX,c.clientY);if(xe){const pe=xe.x,je=xe.y,Pe=[];let De=0;for(const Ee of ht())if(Qe(Ee.type)&&(De+=1,Ee.id!==Se.current.id))try{const Lt=JSON.parse(Ee.data),$e=Zs(Ee,Lt,jt(Ee.type,Lt));if(!$e)continue;const Ae=Be.current.get(Ee.id);Pe.push({id:Ee.id,x:Ae?.x??$e.x,y:Ae?.y??$e.y,width:Ae?.width??$e.width,height:Ae?.height??$e.height})}catch{}const et=Ta({x:pe,y:je},Pe);if(et){const Lt={x:12,y:12,width:Math.max(0,rs.width-24),height:Math.max(0,rs.height-24)},$e=_a(et,{x:pe,y:je},Lt,De);Ce($e),Le.current!==et.id&&ve(et.id)}else Ce(null),Le.current!==null&&ve(null)}}},h=async c=>{if(!Se.current)return;const N=Se.current.currentX,R=Se.current.currentY,B=Se.current.id,ee=Se.current.data,ne=Se.current.startPointerX,xe=Se.current.startPointerY,pe=Math.abs(c.clientX-ne)>bn||Math.abs(c.clientY-xe)>bn,je=pe?qr.current?.(c,B):!1;os.current?.(null);const Pe=xt.current;if(Ce(null),ve(null),!pe||je){Se.current=null,qt(null);return}if(Oe){Se.current=null,qt(null),Pe&&Pe.targetId&&Pe.targetId!==B?Pe.type==="swap"?ze.current?.(B,Pe.targetId):re.current?.(B,Pe.targetId,Pe.type):$r();return}const De=Be.current.get(B),et={...at(ee,ee?.radius!==void 0?"circle":"rect"),...De??{},x:N,y:R};if(ct(B,et),Se.current=null,qt(null),i){we(!0);try{await i(B,{...ee,...De??{},x:N,y:R}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}catch(Ee){console.error("Drag end update error:",Ee),De?ct(B,De):zr(B)}finally{we(!1)}}};return window.addEventListener("pointermove",s),window.addEventListener("pointerup",h),()=>{window.removeEventListener("pointermove",s),window.removeEventListener("pointerup",h)}},[It,i,t,ct,Oe,ht]),n.useEffect(()=>{if(!Rr||!St)return;const s=c=>{if(!ke.current||!Ct.current)return;const N=c.clientX-ke.current.startX,R=c.clientY-ke.current.startY;let B=ke.current.initialX,ee=ke.current.initialY,ne=ke.current.initialWidth,xe=ke.current.initialHeight;const pe=150,je=100,{corner:Pe}=ke.current;if(Pe==="bottom-right")ne=Math.max(pe,ke.current.initialWidth+N),xe=Math.max(je,ke.current.initialHeight+R);else if(Pe==="bottom-left"){const De=ke.current.initialWidth-N;De>=pe&&(ne=De,B=ke.current.initialX+N),xe=Math.max(je,ke.current.initialHeight+R)}else if(Pe==="top-right"){ne=Math.max(pe,ke.current.initialWidth+N);const De=ke.current.initialHeight-R;De>=je&&(xe=De,ee=ke.current.initialY+R)}else if(Pe==="top-left"){const De=ke.current.initialWidth-N;De>=pe&&(ne=De,B=ke.current.initialX+N);const et=ke.current.initialHeight-R;et>=je&&(xe=et,ee=ke.current.initialY+R)}Ct.current={id:ke.current.id,x:B,y:ee,width:ne,height:xe},Ms({...Ct.current})},h=async c=>{if(!ke.current||!Ct.current)return;const{id:N}=ke.current,{x:R,y:B,width:ee,height:ne}=Ct.current,xe=v.find(De=>De.id===N);let pe={};if(xe)try{pe=JSON.parse(xe.data)}catch{}const je=Be.current.get(N),Pe={...at(pe,pe?.radius!==void 0?"circle":"rect"),...je??{},x:R,y:B,width:ee,height:ne};if(ct(N,Pe),ke.current=null,Ct.current=null,Ar(null),Ms(null),xe&&i)try{we(!0),await i(N,{...pe,...je??{},x:R,y:B,width:ee,height:ne}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}catch(De){console.error("Resize end update error:",De),je?ct(N,je):zr(N)}finally{we(!1)}};return window.addEventListener("pointermove",s),window.addEventListener("pointerup",h),()=>{window.removeEventListener("pointermove",s),window.removeEventListener("pointerup",h)}},[Rr,St,r,i,t,ct]);const Tt=s=>{m||Ie({type:"confirm",title:"删除组件",message:"您确定要从白板中删除这个组件或图形吗?该操作不可撤销。",onConfirm:async()=>{we(!0);try{if(Be.current.delete(s),kt(h=>h+1),Oe){const h=ht().filter(c=>c.id!==s&&Qe(c.type));h.length>0&&await Mr.current?.(h)}o?await o(s):await fetch(`/api/lessons/${t}/whiteboard/${s}`,{method:"DELETE"}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u(),me(null)}catch(h){console.error("Delete element failed:",h)}finally{we(!1),Ie(null)}}})},yi=()=>{m||Ie({type:"confirm",title:"清空白板",message:"您确定要清空画布上的所有组件、图形和线条吗?此操作将永久清空白板且不可逆!",onConfirm:async()=>{we(!0);try{d?await d():await fetch(`/api/lessons/${t}/whiteboard`,{method:"DELETE"}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u(),me(null)}catch(s){console.error("Clear board failed:",s)}finally{we(!1),Ie(null)}}})},wi=()=>{m||Ie({type:"confirm",title:"重置白板",message:"您确定要将白板重置为开始上课的状态吗?您在白板上做的所有临时修改都将被重置。",onConfirm:async()=>{we(!0);try{await fetch(`/api/lessons/${t}/whiteboard/reset`,{method:"POST"}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u(),me(null)}catch(s){console.error("Reset board failed:",s)}finally{we(!1),Ie(null)}}})};n.useEffect(()=>{const s=h=>{const c=h.target,N=c.tagName==="INPUT"||c.tagName==="TEXTAREA"||c.isContentEditable;if((h.key==="Delete"||h.key==="Backspace")&&fe&&(N||(Tt(fe),me(null))),Oe&&fe&&!N&&h.altKey){let R=null;if(h.key==="ArrowLeft"||h.key==="h"||h.key==="H"?R="left":h.key==="ArrowRight"||h.key==="l"||h.key==="L"?R="right":h.key==="ArrowUp"||h.key==="k"||h.key==="K"?R="up":(h.key==="ArrowDown"||h.key==="j"||h.key==="J")&&(R="down"),R){const B=[];let ee=null;for(const ne of ht())if(Qe(ne.type))try{const xe=JSON.parse(ne.data),pe=Zs(ne,xe,jt(ne.type,xe));if(!pe)continue;const je=Be.current.get(ne.id),Pe={id:ne.id,x:je?.x??pe.x,y:je?.y??pe.y,width:je?.width??pe.width,height:je?.height??pe.height};B.push(Pe),ne.id===fe&&(ee=Pe)}catch{}if(ee&&B.length>1){const ne=$a(ee,B,R);ne&&(h.preventDefault(),h.stopPropagation(),h.shiftKey?ze.current?.(fe,ne.id):me(ne.id))}}}};return window.addEventListener("keydown",s),()=>window.removeEventListener("keydown",s)},[fe,Oe,ht]);const Yr=()=>{Yt.current&&clearTimeout(Yt.current),x&&(Yt.current=setTimeout(async()=>{we(!0);try{(await fetch(`/api/lessons/${t}/ai-tutor`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elements:v.map(h=>({type:h.type,data:JSON.parse(h.data)}))})})).ok&&(ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u())}catch(s){console.error(s)}finally{we(!1)}},6e4))};n.useEffect(()=>(Yr(),()=>{Yt.current&&clearTimeout(Yt.current)}),[r]),n.useEffect(()=>{const s=Oi();Ne.current=s,s.emit("join-room",t);const h=c=>{c.type==="temp-draw"?vr(N=>({...N,[c.userId]:c.payload})):c.type==="temp-end"?vr(N=>{const R={...N};return delete R[c.userId],R}):c.type==="refresh"?u&&u():c.type==="segment-change"?w&&c.payload?.segmentId&&w(c.payload.segmentId):c.type==="page-change"?typeof c.payload?.page=="number"&&I(c.payload.page):c.type==="page-meta-update"&&Array.isArray(c.payload?.pages)&&oe(c.payload.pages)};return Ne.current.on("whiteboard-sync",h),()=>{Ne.current?.off("whiteboard-sync",h)}},[t,u,w]),n.useEffect(()=>{if(!Te.current)return;const s=new ResizeObserver(c=>{for(let N of c)Te.current&&(yr({width:Te.current.offsetWidth,height:Te.current.offsetHeight}),jr({width:Te.current.clientWidth,height:Te.current.clientHeight}))});s.observe(Te.current);const h=()=>{Te.current&&(yr({width:Te.current.offsetWidth,height:Te.current.offsetHeight}),jr({width:Te.current.clientWidth,height:Te.current.clientHeight}))};return h(),window.addEventListener("resize",h),()=>{s.disconnect(),window.removeEventListener("resize",h)}},[]);const ji=s=>{if(m)return;if(Yr(),Me(null),A==="cursor"){s.target===s.target.getStage()&&me(null);return}if(Cs)return;ks(!0);const h=s.target.getStage().getPointerPosition();if(A==="pen"){const c=q?"#f8fafc":"black";ot({type:"pen",points:[h.x,h.y],color:c})}else if(A==="highlighter")ot({type:"highlighter",points:[h.x,h.y],color:L});else if(A==="rect"){const c=q?"#818cf8":"blue";ot({type:"rectangle",x:h.x,y:h.y,width:0,height:0,stroke:c})}else if(A==="circle"){const c=q?"#4ade80":"green";ot({type:"circle",x:h.x,y:h.y,radius:0,stroke:c})}else if(A==="text"){const c=q?"#f8fafc":"black";ot({type:"text",x:h.x,y:h.y,text:"Click to edit...",fontSize:16,color:c})}},vi=s=>{if(!gr||!Re)return;const h=s.target.getStage().getPointerPosition();if(Re.type==="pen"||Re.type==="highlighter")ot({...Re,points:Re.points.concat([h.x,h.y])});else if(Re.type==="rectangle")ot({...Re,width:h.x-Re.x,height:h.y-Re.y});else if(Re.type==="circle"){const c=Math.sqrt(Math.pow(h.x-Re.x,2)+Math.pow(h.y-Re.y,2));ot({...Re,radius:c})}},Ni=async()=>{if(!gr||!Re)return;ks(!1);const s={...Re,page:$,segmentId:a};ot(null),we(!0);try{await l(s.type,s),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}finally{we(!1)}};n.useEffect(()=>{!Ne.current||!Ne.current.id||(Re?Ne.current.emit("whiteboard-update",{roomId:t,type:"temp-draw",userId:Ne.current.id,payload:{...Re,page:$,segmentId:a}}):Ne.current.emit("whiteboard-update",{roomId:t,type:"temp-end",userId:Ne.current.id}))},[Re,t,$,a]),n.useEffect(()=>{a&&Ne.current&&Ne.current.emit("whiteboard-update",{roomId:t,type:"segment-change",payload:{segmentId:a}})},[a,t]);const Jr=s=>{if(!s)return null;const h=s.page??0,c=Q[$];return!(s.pageId&&c?.id?s.pageId===c.id:h===$)||a&&s.segmentId&&s.segmentId!==a?null:s.type==="pen"?e.jsx(us,{points:s.points,stroke:s.color,strokeWidth:4,tension:.5,lineCap:"round",lineJoin:"round"}):s.type==="highlighter"?e.jsx(us,{points:s.points,stroke:s.color||"#facc15",strokeWidth:18,tension:.5,lineCap:"round",lineJoin:"round",opacity:.5}):s.type==="rectangle"?e.jsx(en,{x:s.x,y:s.y,width:s.width,height:s.height,stroke:s.stroke}):s.type==="circle"?e.jsx(tn,{x:s.x,y:s.y,radius:s.radius,stroke:s.stroke}):s.type==="text"?e.jsx(sn,{x:s.x,y:s.y,text:s.text,fontSize:Math.round((s.fontSize||16)*C),fill:s.color}):null},ki=()=>Jr(Re?{...Re,page:$,segmentId:a}:null),Ci=()=>Object.values(On).map((s,h)=>e.jsx(rr.Fragment,{children:Jr(s)},h)),Ur=(s,h)=>{try{const c=Ue(s),N=Be.current.get(s.id),R=It?.id===s.id,B=St?.id===s.id,ee=N?.x??c.x??0,ne=N?.y??c.y??0,xe=B?St.x:R?It.currentX:ee,pe=B?St.y:R?It.currentY:ne,je=S=>jt(S,c).width,Pe=S=>jt(S,c).height,De=B?St.width:N?.width??c.width??je(s.type),et=B?St.height:c.isMinimized?36:N?.height??c.height??Pe(s.type),Ee=h?.fullscreen,Lt=!!Ee,$e=Ee?Ee.padding:xe,Ae=Ee?Ee.padding:pe,He=Ee?Math.max(240,Ee.width-Ee.padding*2):De,Xe=Ee?Math.max(180,Ee.height-Ee.padding*2):et,qe=fe===s.id,Ti=Oe&&se===s.id,Ze=!m&&!qe?"group hover:ring-2 hover:ring-indigo-400/80 hover:shadow-2xl transition-all duration-150":"group transition-all duration-150",tt=()=>Ti&&ye?.type==="swap"?e.jsx("div",{className:"absolute -inset-1.5 z-50 rounded-xl border-2 border-dashed border-blue-500 bg-blue-500/20 pointer-events-none flex items-center justify-center backdrop-blur-[1px] animate-pulse shadow-xl",children:e.jsx("div",{className:"bg-blue-600 text-white text-xs font-semibold px-2.5 py-1 rounded-full shadow flex items-center gap-1.5 select-none",children:e.jsx("span",{children:"⇄ 松开对调位置"})})}):m||c.isMinimized?null:qe?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"absolute -inset-1 border-2 border-indigo-500 rounded-lg pointer-events-none z-50 shadow-md animate-pulse duration-1000 animate-in fade-in"}),Oe&&e.jsxs("div",{className:"absolute -top-7 left-0 z-50 bg-indigo-700/90 text-white text-[10px] font-mono px-2 py-0.5 rounded shadow pointer-events-none select-none flex items-center gap-1.5 backdrop-blur",children:[e.jsx("span",{children:"Alt+Shift+方向键 对调"}),e.jsx("span",{className:"text-indigo-300",children:"|"}),e.jsx("span",{children:"Alt+方向键 换焦"})]}),!Oe&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"absolute -top-1.5 -left-1.5 w-3.5 h-3.5 bg-white border-2 border-indigo-600 rounded-full cursor-nwse-resize z-50 hover:bg-indigo-50 hover:scale-110 transition-transform shadow",onPointerDown:S=>ls(S,s.id,"top-left",$e,Ae,He,Xe),onPointerMove:cs,onPointerUp:ds}),e.jsx("div",{className:"absolute -top-1.5 -right-1.5 w-3.5 h-3.5 bg-white border-2 border-indigo-600 rounded-full cursor-nesw-resize z-50 hover:bg-indigo-50 hover:scale-110 transition-transform shadow",onPointerDown:S=>ls(S,s.id,"top-right",$e,Ae,He,Xe),onPointerMove:cs,onPointerUp:ds}),e.jsx("div",{className:"absolute -bottom-1.5 -left-1.5 w-3.5 h-3.5 bg-white border-2 border-indigo-600 rounded-full cursor-nesw-resize z-50 hover:bg-indigo-50 hover:scale-110 transition-transform shadow",onPointerDown:S=>ls(S,s.id,"bottom-left",$e,Ae,He,Xe),onPointerMove:cs,onPointerUp:ds}),e.jsx("div",{className:"absolute -bottom-1.5 -right-1.5 w-3.5 h-3.5 bg-white border-2 border-indigo-600 rounded-full cursor-nwse-resize z-50 hover:bg-indigo-50 hover:scale-110 transition-transform shadow",onPointerDown:S=>ls(S,s.id,"bottom-right",$e,Ae,He,Xe),onPointerMove:cs,onPointerUp:ds})]})]}):e.jsx("div",{className:"absolute -inset-1 border-2 border-transparent group-hover:border-indigo-400/80 rounded-xl pointer-events-none transition-all duration-150 z-20"}),ft=(S,Y,ie="default",be)=>({title:c.title||S,icon:Y,hidden:Lt,readOnly:m,isMinimized:!!c.isMinimized,isMaximized:lt===s.id,isPropertiesOpen:as===s.id||Ts===s.id,themeColor:ie,extraActions:be,onPointerDown:Fe=>!m&&_s(Fe,s.id,c),onPointerMove:m?void 0:Rs,onPointerUp:m?void 0:As,onOpenProperties:()=>{!z&&s.type==="html-applet"?(Ut(),Br(s.id)):(me(s.id),Mt(Fe=>Fe===s.id?null:s.id))},onMinimize:async()=>{i&&(await i(s.id,{...c,isMinimized:!0}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{lt===s.id&&mt(null),c.isMinimized&&i&&(await i(s.id,{...c,isMinimized:!1}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>mt(s.id),onBrowserFullscreen:()=>void Nt.enter(s.id),onDelete:()=>Tt(s.id)});if(s.type==="plugin"){const S=k==="teacher",Y=(S?c.teacherWidgetId:c.studentWidgetId)??(S?c.studentWidgetId:c.teacherWidgetId),ie=S?"teacher.dashboard.widget":"student.view";return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:be=>{m||(me(s.id),be.stopPropagation())},onContextMenu:be=>{if(m){be.preventDefault(),be.stopPropagation();return}const Fe=Ke(be.clientX,be.clientY);Fe&&Me({x:Fe.x,y:Fe.y,elementId:s.id})},className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(un,{...ft("Plugin Component",e.jsx(Ws,{size:13,className:"text-indigo-600"}),"indigo"),contentClassName:"flex-grow bg-white overflow-auto relative min-h-0 p-2",children:e.jsx(Ga,{pluginId:c.pluginId,slot:ie,widgetId:Y,elementId:s.id,lessonId:t,classId:j,studentId:y,studentName:f})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id)}if(s.type==="hello-world")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},className:`bg-transparent relative rounded-lg ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(io,{...Object.assign({elementId:s.id,data:c,readOnly:m},ft("Hello World 插件",e.jsx(Zt,{size:11,className:"text-amber-500 animate-pulse"}),"slate"),{onElementUpdate:i,lessonId:t})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id);if(s.type==="rollcall")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`bg-transparent relative rounded-lg ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(Va,{...Object.assign({elementId:s.id,data:c,lessonId:t,classId:H||c&&c.classId,readOnly:m,userRole:k},ft("随机点名助手 (分层抽问 Fair Picker)",e.jsx(Zt,{size:13,className:"animate-pulse text-amber-400"}),"indigo"),{onElementUpdate:i})}),m&&e.jsx(nt,{}),tt()]})})},s.id);if(s.type==="quiz"){const S=Array.isArray(c.options)?c.options:[],Y=In[s.id]??Object.keys(c.submissions||{}).length;return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:ie=>{m||(me(s.id),ie.stopPropagation())},onContextMenu:ie=>{if(m){ie.preventDefault(),ie.stopPropagation();return}const be=Ke(ie.clientX,ie.clientY);be&&Me({x:be.x,y:be.y,elementId:s.id})},"data-testid":`whiteboard-quiz-${s.id}`,className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative select-none ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(ut,{...ft("随堂测验 (Interactive Quiz)",e.jsx(Js,{size:13,className:"text-indigo-500"}),"indigo"),onMaximize:()=>mt(s.id),onBrowserFullscreen:()=>void Nt.enter(s.id)}),!c.isMinimized&&e.jsxs("div",{className:"p-4 text-center flex-1 overflow-y-auto flex flex-col justify-between min-h-0",children:[e.jsxs("div",{className:"text-left space-y-2",children:[e.jsx("p",{className:"font-semibold text-gray-800 text-xs line-clamp-2",title:c.question,children:c.question||"随堂测验题目"}),S.length>0&&e.jsx("div",{className:"space-y-1",children:S.slice(0,4).map((ie,be)=>e.jsxs("div",{className:"text-[11px] text-gray-600 bg-gray-50 border border-gray-100 rounded px-2 py-0.5 truncate text-left",children:[e.jsxs("span",{className:"font-bold text-indigo-500 mr-1.5",children:[String.fromCharCode(65+be),"."]}),ie]},be))})]}),e.jsx("div",{className:"pt-2",children:e.jsx("button",{"data-testid":"quiz-open-fullscreen",className:"w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-1.5 rounded transition-colors text-xs shadow-sm cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-1.5",disabled:m,onClick:()=>{m||mt(s.id)},children:e.jsx("span",{children:Y>0?`进入测验 (${Y} 人已交)`:"点击全屏答题 / 查看"})})})]}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id)}if(s.type==="assignment")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative select-none ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(ut,{...ft("Assignment Upload Task",e.jsx(js,{size:13,className:"text-orange-500"}),"orange")}),!c.isMinimized&&e.jsxs("div",{className:"p-4 text-center flex-1 overflow-y-auto flex flex-col justify-center min-h-0",children:[e.jsx("p",{className:"font-semibold text-gray-800 mb-1 text-xs",children:c.title}),e.jsx("p",{className:"text-xs text-gray-500 mb-3 line-clamp-3",children:c.description}),e.jsx("button",{"data-testid":"assignment-submit-button",className:"w-full bg-orange-600 hover:bg-orange-700 text-white font-medium py-1.5 rounded transition-colors text-xs shadow-sm cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",disabled:m,onClick:()=>{if(m)return;const S=typeof c.assignmentId=="string"?c.assignmentId:"";if(S){$s(S);return}(async()=>{try{const ie=await(await fetch(`/api/assignments?lessonId=${encodeURIComponent(t||"")}`)).json().catch(()=>null),be=Array.isArray(ie?.assignments)?ie.assignments:[],Fe=be.find(Ye=>Ye?.status==="published")||be[0];if(Fe?.id){$s(String(Fe.id));return}Ie({type:"alert",title:"尚未发布作业",message:"教师还没有发布本课节的作业,请稍后再试。",onConfirm:()=>Ie(null)})}catch(Y){Ie({type:"alert",title:"无法加载作业",message:Y?.message?String(Y.message):"请检查网络后重试。",onConfirm:()=>Ie(null)})}})()},children:c.assignmentId?"提交作业":"Upload File"})]}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id);if(s.type==="html-applet")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(un,{...ft(c.title||"Interactive Courseware",e.jsx(or,{size:13,className:"text-primary-theme"}),"default"),contentClassName:"flex-1 bg-white overflow-hidden relative min-h-0",children:e.jsx(Ii,{data:c,lessonId:t,elementId:s.id,className:"w-full h-full border-none"})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id);if(s.type==="pen"){const S=fe===s.id;return e.jsx(us,{id:s.id,points:c.points,stroke:S?M.selectionBorder||"#3b82f6":c.color&&c.color!=="black"&&c.color!=="#000000"?c.color:q?"#f8fafc":c.color||"black",strokeWidth:S?6:4,tension:.5,lineCap:"round",lineJoin:"round",draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=c.points.map((Je,Fs)=>Fs%2===0?Je+be:Je+Fe);i&&(await i(s.id,{...c,points:Ye}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="highlighter"){const S=fe===s.id;return e.jsx(us,{id:s.id,points:c.points,stroke:S?"#3b82f6":c.color||"#facc15",strokeWidth:S?24:18,tension:.5,lineCap:"round",lineJoin:"round",opacity:.5,draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=c.points.map((Je,Fs)=>Fs%2===0?Je+be:Je+Fe);i&&(await i(s.id,{...c,points:Ye}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="rectangle"||s.type==="shape"&&c.shape==="rect"){const S=fe===s.id;return e.jsx(en,{id:s.id,x:N?.x??c.x,y:N?.y??c.y,width:N?.width??c.width,height:N?.height??c.height,fill:c.fill||"transparent",stroke:S?"#3b82f6":c.stroke||"blue",strokeWidth:S?3:1,draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=(N?.x??c.x)+be,Je=(N?.y??c.y)+Fe;i&&(ct(s.id,{...at(c,"rect"),...N??{},x:Ye,y:Je}),await i(s.id,{...c,x:Ye,y:Je}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="circle"||s.type==="shape"&&c.shape==="circle"){const S=fe===s.id;return e.jsx(tn,{id:s.id,x:N?.x??c.x,y:N?.y??c.y,radius:N?.radius??c.radius,fill:c.fill||"transparent",stroke:S?"#3b82f6":c.stroke||"green",strokeWidth:S?3:1,draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=(N?.x??c.x)+be,Je=(N?.y??c.y)+Fe;i&&(ct(s.id,{...at(c,"circle"),...N??{},x:Ye,y:Je}),await i(s.id,{...c,x:Ye,y:Je}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="text"){const S=fe===s.id;return e.jsx(sn,{id:s.id,x:N?.x??c.x,y:N?.y??c.y,text:c.text,fontSize:Math.round((c.fontSize||16)*C),fill:S?M.selectionBorder||"#3b82f6":c.color&&c.color!=="black"&&c.color!=="#000000"?c.color:q?"#f8fafc":c.color||"black",fontStyle:S?"bold":"normal",draggable:k==="teacher"&&A==="cursor",onClick:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onTap:Y=>{A==="cursor"&&(Y.cancelBubble=!0,me(S?null:s.id))},onDragEnd:async Y=>{const ie=Y.target,be=ie.x(),Fe=ie.y();ie.x(0),ie.y(0);const Ye=(N?.x??c.x)+be,Je=(N?.y??c.y)+Fe;i&&(ct(s.id,{...at(c,"rect"),...N??{},x:Ye,y:Je}),await i(s.id,{...c,x:Ye,y:Je}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="code-sandbox")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`relative rounded-lg shadow-xl ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(so,{elementId:s.id,data:c,readOnly:m,isMinimized:!!c.isMinimized,isMaximized:lt===s.id,isPropertiesOpen:as===s.id,onOpenProperties:()=>{me(s.id),Mt(S=>S===s.id?null:s.id)},onMinimize:async()=>{i&&(await i(s.id,{...c,isMinimized:!0}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{lt===s.id&&mt(null),c.isMinimized&&i&&(await i(s.id,{...c,isMinimized:!1}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>mt(s.id),onBrowserFullscreen:()=>void Nt.enter(s.id),onElementUpdate:i?async(S,Y)=>{await i(S,Y),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0,onPointerDown:S=>!m&&_s(S,s.id,c),onPointerMove:m?void 0:Rs,onPointerUp:m?void 0:As,onDelete:()=>Tt(s.id)}),m&&e.jsx(nt,{}),tt()]})})},s.id);if(s.type==="math-graph")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`relative rounded-lg shadow-xl ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(no,{elementId:s.id,data:c,readOnly:m,isMinimized:!!c.isMinimized,isMaximized:lt===s.id,isPropertiesOpen:as===s.id,onOpenProperties:()=>{me(s.id),Mt(S=>S===s.id?null:s.id)},onMinimize:async()=>{i&&(await i(s.id,{...c,isMinimized:!0}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{lt===s.id&&mt(null),c.isMinimized&&i&&(await i(s.id,{...c,isMinimized:!1}),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>mt(s.id),onBrowserFullscreen:()=>void Nt.enter(s.id),onElementUpdate:i?async(S,Y)=>{await i(S,Y),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0,onPointerDown:S=>!m&&_s(S,s.id,c),onPointerMove:m?void 0:Rs,onPointerUp:m?void 0:As,onDelete:()=>Tt(s.id)}),m&&e.jsx(nt,{}),tt()]})})},s.id);if(s.type==="presentation")return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:S=>{m||(me(s.id),S.stopPropagation())},onContextMenu:S=>{if(m){S.preventDefault(),S.stopPropagation();return}const Y=Ke(S.clientX,S.clientY);Y&&Me({x:Y.x,y:Y.y,elementId:s.id})},className:`bg-white border border-gray-305 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative select-none ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(ut,{...ft("Interactive Presentation",e.jsx(gs,{size:13,className:"text-purple-600"}),"purple")}),!c.isMinimized&&e.jsx("div",{className:"flex-1 min-h-0 relative bg-white",style:{pointerEvents:m?"none":"auto"},children:e.jsx(uo,{elementId:s.id,data:c,userRole:k,onElementUpdate:i?async(S,Y)=>{await i(S,Y),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id);const Pt=s.type==="whiteboard.renderer"?c.rendererType||c.type||"whiteboard.renderer":s.type,Qr=X?.find(S=>{const Y=S;return Y.targetType===Pt||S.id===Pt||S.route===Pt||`${S.pluginId}/${S.id}`===Pt||Y.slotProps?.elementType===Pt||Y.slotProps?.targetType===Pt});if(Qr){const S=!!c.frameless,Y=!!(c.hideTitleBar||S);return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:ie=>{m||(me(s.id),ie.stopPropagation())},onContextMenu:ie=>{if(m){ie.preventDefault(),ie.stopPropagation();return}const be=Ke(ie.clientX,ie.clientY);be&&Me({x:be.x,y:be.y,elementId:s.id})},className:S?`overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[!Y&&e.jsx(ut,{...ft(c.title||Qr.label||s.type,e.jsx(Ws,{size:13,className:"text-indigo-600"}),"indigo")}),!c.isMinimized&&e.jsx("div",{className:`flex-1 overflow-hidden relative min-h-0 ${S?"":"bg-white"}`,style:{pointerEvents:m?"none":"auto"},children:e.jsx(We,{slot:"whiteboard.renderer",slotProps:{element:s,elementId:s.id,elementType:Pt,data:c,width:He,height:Xe,isSelected:qe,readOnly:m,userRole:k,lessonId:t,onElementUpdate:i?async(ie,be)=>{await i(ie,be),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0}})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id)}const Gt=bs.get(s.type);if(Gt){const S=Gt.component;return e.jsx(st,{children:e.jsx(rt,{divProps:{style:{position:"absolute",top:`${Ae}px`,left:`${$e}px`,pointerEvents:"none",zIndex:qe?20:10}},children:e.jsxs("div",{onPointerDown:Y=>{m||(me(s.id),Y.stopPropagation())},onContextMenu:Y=>{if(m){Y.preventDefault(),Y.stopPropagation();return}const ie=Ke(Y.clientX,Y.clientY);ie&&Me({x:ie.x,y:ie.y,elementId:s.id})},className:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ze}`,style:{pointerEvents:m?"none":"auto",userSelect:m?"none":"auto",width:`${He}px`,height:`${Xe}px`},children:[e.jsx(ut,{...ft(Gt.labelZh||s.type,e.jsx(Ws,{size:13,className:"text-indigo-600"}),"indigo")}),!c.isMinimized&&e.jsx("div",{className:"flex-1 bg-white overflow-hidden relative min-h-0",style:{pointerEvents:m?"none":"auto"},children:S?e.jsx(S,{elementId:s.id,lessonId:t,data:c,userRole:k,onElementUpdate:i?async(Y,ie)=>{await i(Y,ie),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0}):e.jsxs("div",{className:"w-full h-full flex flex-col items-center justify-center p-4 text-center text-gray-500 select-none",children:[e.jsx("div",{className:"font-semibold text-gray-700",children:Gt.labelZh}),e.jsx("div",{className:"text-xs mt-1 text-gray-400",children:Gt.descriptionZh}),c.title&&e.jsx("div",{className:"mt-2 text-xs bg-gray-100 px-2 py-1 rounded",children:c.title})]})}),m&&e.jsx(nt,{}),!c.isMinimized&&tt()]})})},s.id)}}catch(c){console.error(c)}return null},Gr=s=>{s.preventDefault(),s.dataTransfer.dropEffect="copy",V||ae(!0)},Vr=s=>{s.preventDefault(),s.dataTransfer.dropEffect="copy",ae(!0)},Si=s=>{s.preventDefault(),s.currentTarget.contains(s.relatedTarget)||ae(!1)},Kr=(s,h,c,N)=>{const R={x:c,y:N,page:$,segmentId:a},ee=bs.get(s)?.defaultData||{},xe=X?.find(pe=>{const je=pe;return je.targetType===s||pe.id===s||pe.route===s||`${pe.pluginId}/${pe.id}`===s||je.slotProps?.elementType===s||je.slotProps?.targetType===s})?.slotProps?.defaultData||{};switch(s){case"code-sandbox":return{...R,code:h.code??"console.log('Hello Sandbox!');"};case"math-graph":return{...R,equation:h.equation??"Math.sin(x)"};case"presentation":return{...R,markdown:h.markdown??`# Title Slide
|
|
64
64
|
---
|
|
65
|
-
## Slide 2`,width:600,height:400,slideX:0,slideY:0};case"quiz":return{...R,question:h.question??"New Quiz",options:Array.isArray(h.options)?h.options:["A","B","C","D"]};case"html-applet":return{...R,title:h.title??"",code:h.code??"",coursewareUuid:h.coursewareUuid??void 0,resourceId:h.resourceId??void 0};case"assignment":return{...R,title:h.title??"New Assignment",description:h.description??""};case"hello-world":return R;case"rollcall":return{...R,allStudents:[]};default:return{...R,...ee,...xe,...h}}},zi=async(s,h)=>{if(!Te.current)return;const c=Te.current.getBoundingClientRect(),N=Math.round(c.width/2+Te.current.scrollLeft),R=Math.round(c.height/2+Te.current.scrollTop);we(!0);try{await l(s,Vr(s,h,N,R)),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}catch(B){console.error("addElementAtCenter error",B)}finally{we(!1)}},Mi=n.useCallback(async(s,h)=>{if(h<0||h>=Q.length)return;const c=v.find(R=>R.id===s);if(!c)return;const N=Q[h];try{const R=JSON.parse(c.data),B=typeof R.page=="number"?R.page:$,ee={...R,page:h,pageId:N?.id};if(delete ee.__tiled,delete ee.tileOrder,c.data=JSON.stringify(ee),Be.current.delete(s),kt(ne=>ne+1),i&&await i(s,ee),Oe){const ne=v.filter(xe=>{if(xe.id===s||!Qe(xe.type))return!1;try{const pe=JSON.parse(xe.data);return!((typeof pe.page=="number"?pe.page:0)!==B||a&&pe.segmentId&&pe.segmentId!==a)}catch{return B===0}});ne.length>0&&await At(ne)}me(null),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,targetPage:h},timestamp:Date.now(),correlationId:t})}catch(R){console.error("Failed to move element to page:",R)}},[Q,v,$,a,Oe,At,i,t]),$i=n.useCallback(async(s,h)=>{const c=v.find(N=>N.id===s);if(c)try{const N=JSON.parse(c.data),R=N.segmentId??a,B={...N,segmentId:h};if(delete B.__tiled,delete B.tileOrder,c.data=JSON.stringify(B),Be.current.delete(s),kt(ee=>ee+1),i&&await i(s,B),Oe){const ee=v.filter(ne=>{if(ne.id===s||!Qe(ne.type))return!1;try{return!((JSON.parse(ne.data).segmentId??"")!==(R??"")||!cr(ne))}catch{return!1}});ee.length>0&&await At(ee)}me(null),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,targetSegmentId:h},timestamp:Date.now(),correlationId:t})}catch(N){console.error("Failed to move element to segment:",N)}},[v,a,cr,Oe,At,i,t]);n.useImperativeHandle(E,()=>({addElementAtCenter:zi,applyAutoTiling:Mr,switchPage:ur,addPage:xr,deletePage:fr,renamePage:hr,duplicatePage:mr,movePage:pr,moveElementToPage:Mi,moveElementToSegment:$i}));const Kr=async s=>{s.preventDefault(),s.stopPropagation();try{let h=s.dataTransfer.getData("application/json");if(h||(h=s.dataTransfer.getData("text/plain")),h||(h=s.dataTransfer.getData("text")),h||(h=s.dataTransfer.getData("Text")),console.log("Whiteboard drop triggered. Payload:",h),!h)return;let c;try{c=JSON.parse(h)}catch(ee){console.error("Failed to parse drop JSON payload:",ee);return}if(typeof c!="object"||!c)return;if(!Te.current){console.warn("containerRef.current is not loaded on drop");return}const N=Te.current.getBoundingClientRect();let R=s.clientX-N.left+Te.current.scrollLeft,B=s.clientY-N.top+Te.current.scrollTop;console.log(`Adding whiteboard element of type ${c.type} at (${R}, ${B})`),we(!0);try{await l(c.type,Vr(c.type,c,R,B)),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}finally{we(!1)}}catch(h){console.error("Drop error",h)}};return e.jsxs("div",{className:"flex-1 flex flex-row min-h-0 overflow-hidden bg-app",children:[e.jsxs("div",{className:"flex-1 flex flex-col min-h-0 bg-app relative min-w-0",onDragOver:Ur,onDragEnter:Gr,onDrop:Kr,children:[!m&&e.jsx(xo,{tool:A,setTool:F,setSelectedShapeId:me,highlighterColor:L,setHighlighterColor:p,onElementAdd:l,currentPage:$,activeSegmentId:a,lessonId:t,safeElements:v,selectedShapeId:fe,showGrid:G,setShowGrid:le,autoTileEnabled:Oe,onToggleAutoTile:Vn,readOnly:m,userRole:k,isSyncing:Cs,setIsSyncing:we,handleClearBoard:yi,handleResetBoard:wi,handleElementDelete:Tt,setDialog:Ie,setDialogInput:Ar,onRefresh:u,classroomTools:D,onExecuteTool:W}),e.jsxs("div",{ref:Te,"data-testid":"whiteboard-canvas-viewport",className:"flex-1 rounded-xl border border-theme/80 relative overflow-auto w-full shadow-inner transition-colors",style:{backgroundImage:G?`radial-gradient(${M.gridDot} 1.2px, transparent 1.2px)`:"none",backgroundSize:"24px 24px",backgroundColor:M.background},onDragOver:Ur,onDragEnter:Gr,onDragLeave:Si,onDrop:async s=>{ae(!1),await Kr(s)},children:[V&&e.jsxs("div",{className:"absolute inset-0 border-2 border-dashed border-indigo-500 bg-indigo-500/10 backdrop-blur-[2px] rounded-2xl flex flex-col items-center justify-center text-indigo-600 font-bold text-sm z-30 animate-in fade-in pointer-events-none",children:[e.jsx(Qt,{size:32,className:"mb-2 text-indigo-600 animate-bounce"}),e.jsx("span",{children:"释放鼠标将组件放入当前白板页面"})]}),e.jsx($o,{isVisible:v.filter(s=>{if(s.type==="page_meta")return!1;try{const h=JSON.parse(s.data),c=h.page??0,N=Q[$];return!(!(h.pageId&&N?.id?h.pageId===N.id:c===$)||a&&h.segmentId&&h.segmentId!==a)}catch{return $===0}}).length===0&&!lt&&!Rt}),e.jsxs("div",{"data-testid":"whiteboard-stage-host",className:"absolute inset-0 w-full h-full",style:{pointerEvents:V||m?"none":"auto"},children:[e.jsx(Eo,{containerSize:rs,browserFullscreenElementId:Rt,isRemoteBrowserFullscreen:ns,isBrowserFullscreenDismissible:Gn,browserFullscreen:Nt,effectiveFullscreenElementId:lt,isRemoteFullscreen:vt,isFullscreenDismissible:Un,applyFullscreen:mt,safeElements:v,lessonId:t,readOnly:m,renderElement:Jr,children:e.jsx(gn,{width:Dr.width,height:Dr.height,onMouseDown:ji,onMousemove:vi,onMouseup:Ni,onContextMenu:s=>{s.evt.preventDefault();const h=Ke(s.evt.clientX,s.evt.clientY);if(h){const{x:c,y:N}=h,B=s.target.id();B?(me(B),Me({x:c,y:N,elementId:B})):Me({x:c,y:N})}},ref:Xn,className:"w-full h-full cursor-crosshair",children:e.jsxs(yn,{children:[ht().map(s=>Jr(s)),ki(),Ci()]})})}),e.jsx(_o,{autoTileEnabled:Oe,readOnly:m,tilingSplitters:Kn,activeSplitterDrag:Zn,activeDropZoneAction:ye,handleSplitterPointerDown:Qn}),!m&&Ft&&e.jsx("div",{style:{left:`${Ft.x}px`,top:`${Ft.y}px`,pointerEvents:"auto"},className:"absolute bg-surface rounded-lg shadow-2xl border border-theme py-1.5 w-44 z-40 font-sans text-sm animate-in fade-in zoom-in-95 duration-100 text-main",onClick:s=>s.stopPropagation(),onContextMenu:s=>s.preventDefault(),children:Ft.elementId?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"px-3 py-1 text-xs text-muted font-bold uppercase tracking-wider select-none",children:"组件选项"}),e.jsxs("button",{onClick:()=>{const s=Ft.elementId;s&&(me(s),Mt(s)),Me(null)},className:"w-full px-3 py-1.5 flex items-center gap-2 text-left text-main hover:bg-surface-secondary transition-colors text-xs font-semibold cursor-pointer",children:[e.jsx(jn,{size:14}),"配置组件属性"]}),e.jsxs("button",{onClick:()=>{const s=Ft.elementId;s&&(Tt(s),fe===s&&me(null)),Me(null)},className:"w-full px-3 py-1.5 flex items-center gap-2 text-left text-rose-500 hover:bg-rose-500/10 transition-colors text-xs font-semibold cursor-pointer",children:[e.jsx(bt,{size:14}),"删除此组件"]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"px-3 py-1 text-xs text-muted font-bold uppercase tracking-wider select-none",children:"白板操作"}),e.jsxs("button",{onClick:()=>{F("cursor"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="cursor"?"text-primary-theme":"text-main"}`,children:[e.jsx(zn,{size:14}),"选择工具 (Cursor)"]}),e.jsxs("button",{onClick:()=>{F("pen"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="pen"?"text-primary-theme":"text-main"}`,children:[e.jsx(Mn,{size:14}),"画笔工具 (Pen)"]}),e.jsxs("button",{onClick:()=>{F("highlighter"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="highlighter"?"text-primary-theme":"text-main"}`,children:[e.jsx($n,{size:14}),"高亮荧光笔 (Highlighter)"]}),e.jsxs("button",{onClick:()=>{F("rect"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="rect"?"text-primary-theme":"text-main"}`,children:[e.jsx(nr,{size:14}),"矩形工具 (Rectangle)"]}),e.jsxs("button",{onClick:()=>{F("circle"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="circle"?"text-primary-theme":"text-main"}`,children:[e.jsx(Tn,{size:14}),"圆形工具 (Circle)"]}),e.jsxs("button",{onClick:()=>{F("text"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="text"?"text-primary-theme":"text-main"}`,children:[e.jsx(Pn,{size:14}),"文本工具 (Text)"]})]})}),e.jsx("div",{className:"absolute inset-0 pointer-events-none z-20 overflow-hidden",children:e.jsx(We,{slot:"whiteboard.canvas.widget",slotProps:{lessonId:t,classId:j,userRole:k,readOnly:m}})}),e.jsx("div",{className:"absolute bottom-4 left-4 z-30 pointer-events-auto flex items-center gap-2",children:e.jsx(We,{slot:"whiteboard.dock.plugin",slotProps:{lessonId:t,classId:j,userRole:k,readOnly:m}})})]}),!m&&!O&&e.jsx(ho,{pages:Q,currentPage:$,showPageDrawer:_e,setShowPageDrawer:Ge,editingPageIdx:gt,setEditingPageIdx:Wt,editingPageTitle:Ht,setEditingPageTitle:ss,activeMenuPageIdx:Wn,setActiveMenuPageIdx:or,safeElements:v,handleSwitchPage:ur,handleRenamePage:hr,handleDuplicatePage:mr,handleMovePage:pr,handleDeletePage:fr,handleAddPage:xr})]}),e.jsx(mo,{dialog:ti,dialogInput:si,setDialogInput:Ar,setDialog:Ie}),Fr&&e.jsx(yo,{assignmentId:Fr,onClose:()=>$s(null),lang:"zh"}),e.jsx(Fo,{showEntrySelector:oi,setShowEntrySelector:Xr,zipUploadInfo:ii,zipCandidates:ri,handlePropsUpdate:Or,fetchCoursewares:Ut}),e.jsx(Lo,{isOpen:!!Ts,onClose:()=>Lr(null),element:v.find(s=>s.id===Ts)||null,coursewares:Hr,fetchCoursewares:Ut,onApplyTemporary:li,onSavePermanent:ci})]}),k==="teacher"&&t&&e.jsx(ya,{lessonId:t,defaultCollapsed:!0}),e.jsx(Mo,{isEditMode:z,selectedShapeId:fe,setSelectedShapeId:me,activePropertiesElementId:as,setActivePropertiesElementId:Mt,safeElements:v,editingProperties:zt,handleLocalPropChange:xi,handlePropBlur:hi,handleNumericPropBlur:mi,handlePropsUpdate:Or,handleUpdateElementData:$t,handleElementDelete:Tt,handleUndoProp:di,handleRedoProp:ui,propertyUndoStack:Br,propertyRedoStack:Wr,isSyncing:Cs,lessonId:t,classId:j,fullscreenBroadcastClassId:H,coursewares:Hr,fetchCoursewares:Ut,setZipCandidates:ni,setZipUploadInfo:ai,setShowEntrySelector:Xr,handleAddOption:bi,handleRemoveOption:gi,handleOptionChangeLocal:fi,handleOptionBlur:pi})]})});export{Ho as DEFAULT_WHITEBOARD_PAGES,pn as DRAG_ACTIVATION_THRESHOLD_PX,il as InteractiveWhiteboard};
|
|
65
|
+
## Slide 2`,width:600,height:400,slideX:0,slideY:0};case"quiz":return{...R,question:h.question??"New Quiz",options:Array.isArray(h.options)?h.options:["A","B","C","D"]};case"html-applet":return{...R,title:h.title??"",code:h.code??"",coursewareUuid:h.coursewareUuid??void 0,resourceId:h.resourceId??void 0};case"assignment":return{...R,title:h.title??"New Assignment",description:h.description??""};case"hello-world":return R;case"rollcall":return{...R,allStudents:[]};default:return{...R,...ee,...xe,...h}}},zi=async(s,h)=>{if(!Te.current)return;const c=Te.current.getBoundingClientRect(),N=Math.round(c.width/2+Te.current.scrollLeft),R=Math.round(c.height/2+Te.current.scrollTop);we(!0);try{await l(s,Kr(s,h,N,R)),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}catch(B){console.error("addElementAtCenter error",B)}finally{we(!1)}},Mi=n.useCallback(async(s,h)=>{if(h<0||h>=Q.length)return;const c=v.find(R=>R.id===s);if(!c)return;const N=Q[h];try{const R=JSON.parse(c.data),B=typeof R.page=="number"?R.page:$,ee={...R,page:h,pageId:N?.id};if(delete ee.__tiled,delete ee.tileOrder,c.data=JSON.stringify(ee),Be.current.delete(s),kt(ne=>ne+1),i&&await i(s,ee),Oe){const ne=v.filter(xe=>{if(xe.id===s||!Qe(xe.type))return!1;try{const pe=JSON.parse(xe.data);return!((typeof pe.page=="number"?pe.page:0)!==B||a&&pe.segmentId&&pe.segmentId!==a)}catch{return B===0}});ne.length>0&&await At(ne)}me(null),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,targetPage:h},timestamp:Date.now(),correlationId:t})}catch(R){console.error("Failed to move element to page:",R)}},[Q,v,$,a,Oe,At,i,t]),$i=n.useCallback(async(s,h)=>{const c=v.find(N=>N.id===s);if(c)try{const N=JSON.parse(c.data),R=N.segmentId??a,B={...N,segmentId:h};if(delete B.__tiled,delete B.tileOrder,c.data=JSON.stringify(B),Be.current.delete(s),kt(ee=>ee+1),i&&await i(s,B),Oe){const ee=v.filter(ne=>{if(ne.id===s||!Qe(ne.type))return!1;try{return!((JSON.parse(ne.data).segmentId??"")!==(R??"")||!dr(ne))}catch{return!1}});ee.length>0&&await At(ee)}me(null),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,targetSegmentId:h},timestamp:Date.now(),correlationId:t})}catch(N){console.error("Failed to move element to segment:",N)}},[v,a,dr,Oe,At,i,t]);n.useImperativeHandle(E,()=>({addElementAtCenter:zi,applyAutoTiling:$r,switchPage:xr,addPage:hr,deletePage:pr,renamePage:mr,duplicatePage:fr,movePage:br,moveElementToPage:Mi,moveElementToSegment:$i}));const Zr=async s=>{s.preventDefault(),s.stopPropagation();try{let h=s.dataTransfer.getData("application/json");if(h||(h=s.dataTransfer.getData("text/plain")),h||(h=s.dataTransfer.getData("text")),h||(h=s.dataTransfer.getData("Text")),console.log("Whiteboard drop triggered. Payload:",h),!h)return;let c;try{c=JSON.parse(h)}catch(ee){console.error("Failed to parse drop JSON payload:",ee);return}if(typeof c!="object"||!c)return;if(!Te.current){console.warn("containerRef.current is not loaded on drop");return}const N=Te.current.getBoundingClientRect();let R=s.clientX-N.left+Te.current.scrollLeft,B=s.clientY-N.top+Te.current.scrollTop;console.log(`Adding whiteboard element of type ${c.type} at (${R}, ${B})`),we(!0);try{await l(c.type,Kr(c.type,c,R,B)),ce.publish({id:de(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}finally{we(!1)}}catch(h){console.error("Drop error",h)}};return e.jsxs("div",{className:"flex-1 flex flex-row min-h-0 overflow-hidden bg-app",children:[e.jsxs("div",{className:"flex-1 flex flex-col min-h-0 bg-app relative min-w-0",onDragOver:Gr,onDragEnter:Vr,onDrop:Zr,children:[!m&&e.jsx(xo,{tool:A,setTool:F,setSelectedShapeId:me,highlighterColor:L,setHighlighterColor:p,onElementAdd:l,currentPage:$,activeSegmentId:a,lessonId:t,safeElements:v,selectedShapeId:fe,showGrid:G,setShowGrid:le,autoTileEnabled:Oe,onToggleAutoTile:Vn,readOnly:m,userRole:k,isSyncing:Cs,setIsSyncing:we,handleClearBoard:yi,handleResetBoard:wi,handleElementDelete:Tt,setDialog:Ie,setDialogInput:Fr,onRefresh:u,classroomTools:D,onExecuteTool:W}),e.jsxs("div",{ref:Te,"data-testid":"whiteboard-canvas-viewport",className:"flex-1 rounded-xl border border-theme/80 relative overflow-auto w-full shadow-inner transition-colors",style:{backgroundImage:G?`radial-gradient(${M.gridDot} 1.2px, transparent 1.2px)`:"none",backgroundSize:"24px 24px",backgroundColor:M.background},onDragOver:Gr,onDragEnter:Vr,onDragLeave:Si,onDrop:async s=>{ae(!1),await Zr(s)},children:[V&&e.jsxs("div",{className:"absolute inset-0 border-2 border-dashed border-indigo-500 bg-indigo-500/10 backdrop-blur-[2px] rounded-2xl flex flex-col items-center justify-center text-indigo-600 font-bold text-sm z-30 animate-in fade-in pointer-events-none",children:[e.jsx(Qt,{size:32,className:"mb-2 text-indigo-600 animate-bounce"}),e.jsx("span",{children:"释放鼠标将组件放入当前白板页面"})]}),e.jsx($o,{isVisible:v.filter(s=>{if(s.type==="page_meta")return!1;try{const h=JSON.parse(s.data),c=h.page??0,N=Q[$];return!(!(h.pageId&&N?.id?h.pageId===N.id:c===$)||a&&h.segmentId&&h.segmentId!==a)}catch{return $===0}}).length===0&&!lt&&!Rt}),e.jsxs("div",{"data-testid":"whiteboard-stage-host",className:"absolute inset-0 w-full h-full",style:{pointerEvents:V||m?"none":"auto"},children:[e.jsx(Eo,{containerSize:rs,browserFullscreenElementId:Rt,isRemoteBrowserFullscreen:ns,isBrowserFullscreenDismissible:Gn,browserFullscreen:Nt,effectiveFullscreenElementId:lt,isRemoteFullscreen:vt,isFullscreenDismissible:Un,applyFullscreen:mt,safeElements:v,lessonId:t,readOnly:m,renderElement:Ur,children:e.jsx(yn,{width:Er.width,height:Er.height,onMouseDown:ji,onMousemove:vi,onMouseup:Ni,onContextMenu:s=>{s.evt.preventDefault();const h=Ke(s.evt.clientX,s.evt.clientY);if(h){const{x:c,y:N}=h,B=s.target.id();B?(me(B),Me({x:c,y:N,elementId:B})):Me({x:c,y:N})}},ref:Xn,className:"w-full h-full cursor-crosshair",children:e.jsxs(wn,{children:[ht().map(s=>Ur(s)),ki(),Ci()]})})}),e.jsx(_o,{autoTileEnabled:Oe,readOnly:m,tilingSplitters:Kn,activeSplitterDrag:Zn,activeDropZoneAction:ye,handleSplitterPointerDown:Qn}),!m&&Ft&&e.jsx("div",{style:{left:`${Ft.x}px`,top:`${Ft.y}px`,pointerEvents:"auto"},className:"absolute bg-surface rounded-lg shadow-2xl border border-theme py-1.5 w-44 z-40 font-sans text-sm animate-in fade-in zoom-in-95 duration-100 text-main",onClick:s=>s.stopPropagation(),onContextMenu:s=>s.preventDefault(),children:Ft.elementId?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"px-3 py-1 text-xs text-muted font-bold uppercase tracking-wider select-none",children:"组件选项"}),e.jsxs("button",{onClick:()=>{const s=Ft.elementId;s&&(me(s),Mt(s)),Me(null)},className:"w-full px-3 py-1.5 flex items-center gap-2 text-left text-main hover:bg-surface-secondary transition-colors text-xs font-semibold cursor-pointer",children:[e.jsx(vn,{size:14}),"配置组件属性"]}),e.jsxs("button",{onClick:()=>{const s=Ft.elementId;s&&(Tt(s),fe===s&&me(null)),Me(null)},className:"w-full px-3 py-1.5 flex items-center gap-2 text-left text-rose-500 hover:bg-rose-500/10 transition-colors text-xs font-semibold cursor-pointer",children:[e.jsx(bt,{size:14}),"删除此组件"]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"px-3 py-1 text-xs text-muted font-bold uppercase tracking-wider select-none",children:"白板操作"}),e.jsxs("button",{onClick:()=>{F("cursor"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="cursor"?"text-primary-theme":"text-main"}`,children:[e.jsx(Mn,{size:14}),"选择工具 (Cursor)"]}),e.jsxs("button",{onClick:()=>{F("pen"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="pen"?"text-primary-theme":"text-main"}`,children:[e.jsx($n,{size:14}),"画笔工具 (Pen)"]}),e.jsxs("button",{onClick:()=>{F("highlighter"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="highlighter"?"text-primary-theme":"text-main"}`,children:[e.jsx(Tn,{size:14}),"高亮荧光笔 (Highlighter)"]}),e.jsxs("button",{onClick:()=>{F("rect"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="rect"?"text-primary-theme":"text-main"}`,children:[e.jsx(nr,{size:14}),"矩形工具 (Rectangle)"]}),e.jsxs("button",{onClick:()=>{F("circle"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="circle"?"text-primary-theme":"text-main"}`,children:[e.jsx(Pn,{size:14}),"圆形工具 (Circle)"]}),e.jsxs("button",{onClick:()=>{F("text"),Me(null)},className:`w-full px-3 py-1.5 flex items-center gap-2 text-left text-xs font-medium hover:bg-surface-secondary transition-colors cursor-pointer ${A==="text"?"text-primary-theme":"text-main"}`,children:[e.jsx(Dn,{size:14}),"文本工具 (Text)"]})]})}),e.jsx("div",{className:"absolute inset-0 pointer-events-none z-20 overflow-hidden",children:e.jsx(We,{slot:"whiteboard.canvas.widget",slotProps:{lessonId:t,classId:j,userRole:k,readOnly:m}})}),e.jsx("div",{className:"absolute bottom-4 left-4 z-30 pointer-events-auto flex items-center gap-2",children:e.jsx(We,{slot:"whiteboard.dock.plugin",slotProps:{lessonId:t,classId:j,userRole:k,readOnly:m}})})]}),!m&&!O&&e.jsx(ho,{pages:Q,currentPage:$,showPageDrawer:_e,setShowPageDrawer:Ge,editingPageIdx:gt,setEditingPageIdx:Wt,editingPageTitle:Ht,setEditingPageTitle:ss,activeMenuPageIdx:Wn,setActiveMenuPageIdx:lr,safeElements:v,handleSwitchPage:xr,handleRenamePage:mr,handleDuplicatePage:fr,handleMovePage:br,handleDeletePage:pr,handleAddPage:hr})]}),e.jsx(mo,{dialog:ti,dialogInput:si,setDialogInput:Fr,setDialog:Ie}),Lr&&e.jsx(yo,{assignmentId:Lr,onClose:()=>$s(null),lang:"zh"}),e.jsx(Fo,{showEntrySelector:oi,setShowEntrySelector:Or,zipUploadInfo:ii,zipCandidates:ri,handlePropsUpdate:Ir,fetchCoursewares:Ut}),e.jsx(Lo,{isOpen:!!Ts,onClose:()=>Br(null),element:v.find(s=>s.id===Ts)||null,coursewares:Xr,fetchCoursewares:Ut,onApplyTemporary:li,onSavePermanent:ci})]}),k==="teacher"&&t&&e.jsx(ya,{lessonId:t,defaultCollapsed:!0}),e.jsx(Mo,{isEditMode:z,selectedShapeId:fe,setSelectedShapeId:me,activePropertiesElementId:as,setActivePropertiesElementId:Mt,safeElements:v,editingProperties:zt,handleLocalPropChange:xi,handlePropBlur:hi,handleNumericPropBlur:mi,handlePropsUpdate:Ir,handleUpdateElementData:$t,handleElementDelete:Tt,handleUndoProp:di,handleRedoProp:ui,propertyUndoStack:Wr,propertyRedoStack:Hr,isSyncing:Cs,lessonId:t,classId:j,fullscreenBroadcastClassId:H,coursewares:Xr,fetchCoursewares:Ut,setZipCandidates:ni,setZipUploadInfo:ai,setShowEntrySelector:Or,handleAddOption:bi,handleRemoveOption:gi,handleOptionChangeLocal:fi,handleOptionBlur:pi})]})});export{Ho as DEFAULT_WHITEBOARD_PAGES,bn as DRAG_ACTIVATION_THRESHOLD_PX,il as InteractiveWhiteboard};
|