openlearn-next 0.7.12 → 0.7.16

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.
Files changed (111) hide show
  1. package/README.md +1 -1
  2. package/cli-data.mjs +2 -2
  3. package/cli-doctor.mjs +2 -1
  4. package/dist/assets/{AcademicYearFilter-Dm3no4Nb.js → AcademicYearFilter-pCzZgimU.js} +1 -1
  5. package/dist/assets/ActivityWorkspaceWidget-KJQdLnvf.js +1 -0
  6. package/dist/assets/AdminDirectoryView-DDxX8RO2.js +5 -0
  7. package/dist/assets/AssessmentCenter-D5cVUqvy.js +1 -0
  8. package/dist/assets/{AssignmentFilePreview-dVhnTYmq.js → AssignmentFilePreview-DK29gdpQ.js} +2 -2
  9. package/dist/assets/BatchPickerModal-Cw4OZqOJ.js +1 -0
  10. package/dist/assets/ClassesView-Czx7hU2V.js +32 -0
  11. package/dist/assets/ClassroomCountdownWidget-BeAM37Cq.js +2 -0
  12. package/dist/assets/CloudDriveModal-GNZzWVCP.js +1 -0
  13. package/dist/assets/ComputerLabView-C_0c7sjz.js +1 -0
  14. package/dist/assets/CourseManagement-DzLB0Xmp.js +1 -0
  15. package/dist/assets/CourseWizardModal-DmQu237c.js +3 -0
  16. package/dist/assets/CoursewareHubPanel-Xn5WbXg9.js +1 -0
  17. package/dist/assets/Dashboard-CX83FUeF.js +8 -0
  18. package/dist/assets/ExportWeightModal-C0SuUhHM.js +1 -0
  19. package/dist/assets/HelpTour-D8hVFA6N.js +1 -0
  20. package/dist/assets/HelpView-C0PP_51D.js +204 -0
  21. package/dist/assets/ImportLessonsModal-p8Uc1U_h.js +1 -0
  22. package/dist/assets/{ImportModal-Ct0I5cAL.js → ImportModal-DNaPHV0I.js} +2 -2
  23. package/dist/assets/InteractiveCoursewareViewer-D9YTgasv.js +1 -0
  24. package/dist/assets/InteractiveWhiteboard-CHYQfRjR.js +19 -0
  25. package/dist/assets/LazyCourseware-dtuOSiyR.js +2 -0
  26. package/dist/assets/LazyWhiteboard-DuBKAh4-.js +2 -0
  27. package/dist/assets/LessonEditorView-BgI7C_FK.js +1 -0
  28. package/dist/assets/LiveClassroomView-CJK_WMqD.js +67 -0
  29. package/dist/assets/NotificationDetailModal-BVYuS4uR.js +1 -0
  30. package/dist/assets/PluginView-CpWjy0Xf.js +66 -0
  31. package/dist/assets/ProcessLogsModal-D-Ez_YZA.js +1 -0
  32. package/dist/assets/QuizGeneratorModal-Lf5QMvkq.js +1 -0
  33. package/dist/assets/RevealPresentationWrapper-Dnf4v72i.js +48 -0
  34. package/dist/assets/StudentAssignmentEvalPanel-C-7YSfEQ.js +1 -0
  35. package/dist/assets/StudentAssignmentView-LuMaNpq8.js +1 -0
  36. package/dist/assets/StudentLessonView-DUG8I1Zy.js +1 -0
  37. package/dist/assets/StudentView-mMwGPiiF.js +2 -0
  38. package/dist/assets/SystemResourceLibraryModal-LUDNOwgW.js +1 -0
  39. package/dist/assets/TeacherView-ofB-3SEJ.js +2 -0
  40. package/dist/assets/TimetableView-DrZbyCOQ.js +6 -0
  41. package/dist/assets/{UTIF-BtQhea94.js → UTIF-DbcUtUKZ.js} +1 -1
  42. package/dist/assets/index-CG-g_9my.css +1 -0
  43. package/dist/assets/index-CLtQGl25.js +169 -0
  44. package/dist/assets/{index.es-CijVATXs.js → index.es-D1mLdmCj.js} +1 -1
  45. package/dist/assets/keyboard-Rs007iOv.js +1 -0
  46. package/dist/assets/{pluginParsers-DD3QL1Xl.js → pluginParsers-C46aCYkl.js} +1 -1
  47. package/dist/assets/student-workspace-BFPfR77J.js +1 -0
  48. package/dist/assets/{vendor-charts-skggaP9D.js → vendor-charts-CK-CU_m7.js} +1 -1
  49. package/dist/assets/{vendor-icons-CaXLq01o.js → vendor-icons-__JLt-CP.js} +2 -2
  50. package/dist/assets/{vendor-konva-BOuJWFuE.js → vendor-konva-DGELdczq.js} +1 -1
  51. package/dist/assets/{vendor-motion-BFAPOs-b.js → vendor-motion-DtyD8eRQ.js} +1 -1
  52. package/dist/assets/{vendor-pdf-DVWGghIL.js → vendor-pdf-DNexfcCO.js} +3 -3
  53. package/dist/assets/{vendor-pptx-BqU7v5zS.js → vendor-pptx-ByQkJ0Xi.js} +178 -178
  54. package/dist/assets/{vendor-react-DHoBZpn2.js → vendor-react-lfWn1oGs.js} +1 -1
  55. package/dist/assets/{vendor-utils-BxOuk3id.js → vendor-utils-CsoI4M9x.js} +1 -1
  56. package/dist/cli-migrator.cjs +23 -7
  57. package/dist/index.html +10 -6
  58. package/dist/server.cjs +16125 -9457
  59. package/docs_plugin_guide.md +1023 -0
  60. package/migrations/046_logout_clear_site_data.sql +9 -0
  61. package/migrations/047_third_party_theme_system.sql +55 -0
  62. package/migrations/048_file_storage_extension.sql +63 -0
  63. package/migrations/049_ai_personas.sql +25 -0
  64. package/migrations/050_ai_persona_governance.sql +11 -0
  65. package/migrations/051_community_registry_url.sql +9 -0
  66. package/migrations/052_community_install_enabled.sql +12 -0
  67. package/migrations/053_runtime_admin_policies.sql +28 -0
  68. package/migrations/054_user_onboarding_tour_status.sql +10 -0
  69. package/migrations/055_classroom_collab_whiteboard.sql +27 -0
  70. package/migrations/056_public_student_lookup.sql +9 -0
  71. package/migrations/README.md +59 -48
  72. package/migrations/schema-golden.json +98 -2
  73. package/package.json +8 -6
  74. package/scripts/assert-node-runtime.mjs +4 -3
  75. package/dist/assets/ActivityWorkspaceWidget-TtBuNORs.js +0 -1
  76. package/dist/assets/AdminDirectoryView-D03WOMc-.js +0 -5
  77. package/dist/assets/AssessmentCenter-MUvoJySb.js +0 -1
  78. package/dist/assets/BatchPickerModal-QALdhrX6.js +0 -1
  79. package/dist/assets/ClassesView-CKwlRz-A.js +0 -32
  80. package/dist/assets/ClassroomCountdownWidget-DyWyForY.js +0 -2
  81. package/dist/assets/CloudDriveModal-C8UAn3MO.js +0 -1
  82. package/dist/assets/ComputerLabView-E5b3XTkk.js +0 -1
  83. package/dist/assets/CourseManagement-3jSlq7lV.js +0 -1
  84. package/dist/assets/CourseWizardModal-BAkW5VJX.js +0 -3
  85. package/dist/assets/CoursewareHubPanel-BkjcusjZ.js +0 -1
  86. package/dist/assets/Dashboard-Ha2fZAqD.js +0 -8
  87. package/dist/assets/ExportWeightModal-D2Y13384.js +0 -1
  88. package/dist/assets/HelpTour-DBq2otcV.js +0 -1
  89. package/dist/assets/HelpView-BVLRnMxl.js +0 -204
  90. package/dist/assets/ImportLessonsModal-CQlq4b81.js +0 -1
  91. package/dist/assets/InteractiveCoursewareViewer-DGKh1gO8.js +0 -1
  92. package/dist/assets/InteractiveWhiteboard-BbZlYpRu.js +0 -65
  93. package/dist/assets/LazyCourseware-zONqinCM.js +0 -2
  94. package/dist/assets/LazyWhiteboard-BV98LEZ8.js +0 -2
  95. package/dist/assets/LessonEditorView-LXRkKxdY.js +0 -1
  96. package/dist/assets/LiveClassroomView-TaHtHWkY.js +0 -63
  97. package/dist/assets/NotificationDetailModal-BF_-pn0c.js +0 -1
  98. package/dist/assets/PluginView-sVMPXae9.js +0 -77
  99. package/dist/assets/ProcessLogsModal-D97xLgnL.js +0 -1
  100. package/dist/assets/QuizGeneratorModal-CNY8ISjR.js +0 -1
  101. package/dist/assets/StudentAssignmentEvalPanel-CUmM5DbT.js +0 -1
  102. package/dist/assets/StudentAssignmentView-B-1MtwKj.js +0 -1
  103. package/dist/assets/StudentLessonView-CqrcvVND.js +0 -1
  104. package/dist/assets/StudentView-Bi9kgSrN.js +0 -2
  105. package/dist/assets/SystemResourceLibraryModal-DDALKrJC.js +0 -1
  106. package/dist/assets/TeacherView-C5JmoKHk.js +0 -2
  107. package/dist/assets/TimetableView-BOLB-kZC.js +0 -6
  108. package/dist/assets/index-Bc9003lB.js +0 -131
  109. package/dist/assets/index-D4aq9poS.css +0 -1
  110. package/dist/assets/student-workspace-C4UgD58C.js +0 -1
  111. package/dist/assets/vendor-reveal-DcQQzuI9.css +0 -1
@@ -0,0 +1,19 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/RevealPresentationWrapper-Dnf4v72i.js","assets/vendor-react-lfWn1oGs.js","assets/vendor-utils-CsoI4M9x.js","assets/vendor-icons-__JLt-CP.js","assets/index-CLtQGl25.js","assets/vendor-motion-DtyD8eRQ.js","assets/vendor-pptx-DIWdXF1L.css","assets/index-CG-g_9my.css"])))=>i.map(i=>d[i]);
2
+ import{_ as _i}from"./vendor-pdf-DNexfcCO.js";import{r as a,j as e,b as gn,R as ss}from"./vendor-react-lfWn1oGs.js";import{S as yn,L as wn,G as et,H as tt,a as ir,R as Qs,C as en,T as tn}from"./vendor-konva-DGELdczq.js";import{av as Rt,e as vn,N as Ri,i as Ai,f as Ar,aw as Fi,ax as Li,ay as ar,q as oe,U as le,az as Wi,E as ze,s as Bi,aA as dr,aB as Hi,aC as Oi,a9 as Xi,n as Yi,b as qi,aD as Ji,aE as rn,aF as Ii,aG as Gi,aH as Ui,aI as Vi}from"./index-CLtQGl25.js";import{cq as jn,aq as Ki,bK as ns,v as Zi,cr as Qi,ah as jt,M as Nn,T as is,f as it,_ as Yt,w as Jr,a5 as kn,cs as ea,ab as ta,h as Ir,R as $t,aF as Cn,y as Sn,aE as zn,P as Fr,ct as Mn,a_ as Tn,bN as Pn,bL as Dn,ap as $n,j as En,av as as,ci as ra,b2 as Gr,bM as sa,ai as na,b1 as Lr,ad as ia,J as sn,ak as nn,o as Wr,ar as qt,X as Jt,O as os,U as Ur,k as It,n as aa,d as Vr,Q as oa,aH as la,a7 as ca,C as At,u as da,af as Kr,cu as _n,cv as ua,bB as ha,cw as xa,cx as ma,aj as Rn,a as pa,c5 as fa,aB as ba,aA as Br}from"./vendor-icons-__JLt-CP.js";import{i as ga}from"./keyboard-Rs007iOv.js";import{A as An}from"./AssignmentFilePreview-DK29gdpQ.js";import"./vendor-utils-CsoI4M9x.js";import"./vendor-pptx-ByQkJ0Xi.js";import"./vendor-charts-CK-CU_m7.js";import"./vendor-motion-DtyD8eRQ.js";function ya(t={},r={}){const{replay:o=0,maxItems:i=50}=r,[n,d]=a.useState(()=>o>0?Rt.query(t,{limit:o}):[]),l=a.useRef(t);l.current=t;const u=a.useCallback(c=>{d(j=>{const b=[c,...j];return b.length>i&&(b.length=i),b})},[i]);return a.useEffect(()=>(o>0?d(Rt.query(t,{limit:o})):d([]),Rt.subscribe(l.current,u)),[JSON.stringify(t),o,u]),n}function wa(t,r,o={}){const i=a.useRef(r);i.current=r;const n=a.useRef(t);n.current=t,a.useEffect(()=>Rt.subscribe(n.current,l=>i.current(l),o),[JSON.stringify(t),o.replay])}function va({lessonId:t,defaultCollapsed:r=!0}){const[o,i]=a.useState(r),[n,d]=a.useState(""),[l,u]=a.useState(""),[c,j]=a.useState(!1),b=a.useMemo(()=>({lessonId:t,types:n?[n]:void 0,sources:l?[l]:void 0}),[t,n,l]),$=ya(b,{replay:100,maxItems:100}),M=a.useMemo(()=>$,[$,c]),N=a.useMemo(()=>Rt.stats(),[$]),z=a.useMemo(()=>Object.keys(N.byType).sort(),[N]);return e.jsx("div",{"data-testid":"whiteboard-event-panel",className:"fixed bottom-4 right-4 z-50",style:{maxWidth:380},children:o?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:["🔔 事件流 (",$.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:()=>j(x=>!x),"data-testid":"whiteboard-event-panel-pause",className:`px-2 py-1 rounded ${c?"bg-amber-100 text-amber-700":"bg-gray-100 text-gray-600"}`,children:c?"继续":"暂停"}),e.jsx("button",{type:"button",onClick:()=>Rt.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:n,onChange:x=>d(x.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:["全部类型 (",N.total,")"]}),z.map(x=>e.jsxs("option",{value:x,children:[x," (",N.byType[x]??0,")"]},x))]}),e.jsxs("select",{value:l,onChange:x=>u(x.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:M.length===0?e.jsx("div",{className:"text-center text-gray-400 py-4",children:"暂无事件"}):M.map(x=>e.jsx(ja,{event:x},x.id))})]})})}function ja({event:t}){const[r,o]=a.useState(!1),i=new Date(t.timestamp).toLocaleTimeString(),n=t.type==="courseware.submitted",d=n&&typeof t.payload.score=="number"&&typeof t.payload.total=="number"?` · ${t.payload.score}/${t.payload.total}`:"",l=n&&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:()=>o(u=>!u),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 ${l?"text-green-600":n?"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 hr=8,Na=8,ka=["page_meta","pen","highlighter"];function Ve(t){return!ka.includes(t)}function yt(t,r=0){const o=typeof t=="number"?t:Number(t);return Number.isFinite(o)?o:r}function ur(t){return{x:t.x,y:t.y,width:Math.max(0,t.width),height:Math.max(0,t.height)}}function Ca(t,r,o=0,i){if(r<=0)return[];if(r===1)return[ur(t)];const n=[ur(t)];for(;n.length<r;){let d=0,l=-1;for(let j=0;j<n.length;j+=1){const b=n[j];if(n.length>=2&&i&&(i==="bottom-full"&&b.y>t.y+1||i==="top-full"&&b.y<=t.y+1||i==="right-full"&&b.x>t.x+1||i==="left-full"&&b.x<=t.x+1))continue;const $=b.width*b.height,M=Math.max(b.width,b.height),N=$*1e4+M;N>=l&&(l=N,d=j)}const u=n.splice(d,1)[0];let c=u.width>=u.height;if(n.length===0&&i&&(i==="bottom-full"||i==="top-full"?c=!1:(i==="left-full"||i==="right-full")&&(c=!0)),c){const j=u.width/2,b={x:u.x,y:u.y,width:j,height:u.height},$={x:u.x+j,y:u.y,width:u.width-j,height:u.height};n.splice(d,0,b,$)}else{const j=u.height/2,b={x:u.x,y:u.y,width:u.width,height:j},$={x:u.x,y:u.y+j,width:u.width,height:u.height-j};n.splice(d,0,b,$)}}return n.sort((d,l)=>Math.abs(d.y-l.y)>1?d.y-l.y:d.x-l.x)}function Sa(t,r,o,i="fill",n=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)}:za(t,r,o,n)}function za(t,r,o,i=1/0){const n=r>0?r:t.width,d=o>0?o:t.height;if(n<=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 l=Math.min(t.width/n,t.height/d,i),u=n*l,c=d*l;return{id:"",x:t.x+(t.width-u)/2,y:t.y+(t.height-c)/2,width:u,height:c}}function Ma(t,r,o={}){const i=o.gap??hr,n=o.padding??Na,d=o.fillMode??"fill",l=o.maxScale??1/0;if(t.length===0)return[];if(r.width<=0||r.height<=0)return[];const u=ur({x:n,y:n,width:r.width-n*2,height:r.height-n*2});if(u.width<=0||u.height<=0)return[];const c=Ca(u,t.length,0,o.stackDirection),j=Math.max(0,i)/2;return t.map((b,$)=>{const M=c[$];if(!M)return{id:b.id,x:b.x,y:b.y,width:b.width,height:b.height};const N=ur({x:M.x+j,y:M.y+j,width:M.width-j*2,height:M.height-j*2}),z=Sa(N,b.width,b.height,d,l);return{id:b.id,x:z.x,y:z.y,width:z.width,height:z.height}})}function Zr(t,r,o){if(!Ve(t.type))return null;const i=yt(r?.x),n=yt(r?.y);if(t.type==="circle"){const d=o.width>0?o.width/2:24,l=yt(r?.radius)>0?yt(r.radius):d;return{id:t.id,x:i,y:n,width:l*2,height:l*2,shape:"circle"}}return{id:t.id,x:i,y:n,width:yt(r?.width)>0?yt(r.width):o.width,height:yt(r?.height)>0?yt(r.height):o.height}}function Qr(t="rect"){return t==="circle"?["x","y","radius"]:["x","y","width","height"]}function nt(t,r="rect"){const o={};for(const i of Qr(r)){const n=Number(t?.[i]);o[i]=Number.isFinite(n)?n:0}return o}function Ta(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 es(t,r,o,i=.5){const n=d=>Number.isFinite(Number(d))?Number(d):0;return o.every(d=>Math.abs(n(t?.[d])-n(r?.[d]))<i)}function Pa(t,r){if(t.shape==="circle"){const o=Math.max(1,Math.min(r.width,r.height)/2);return{x:r.x+r.width/2,y:r.y+r.height/2,radius:o}}return{x:r.x,y:r.y,width:r.width,height:r.height}}function Da(t,r,o){const i=r.filter(c=>c.id!==t.id);if(i.length===0)return null;const n=t.x+t.width/2,d=t.y+t.height/2;let l=null,u=1/0;for(const c of i){const j=c.x+c.width/2,b=c.y+c.height/2,$=j-n,M=b-d;if(o==="left"&&$>=-1||o==="right"&&$<=1||o==="up"&&M>=-1||o==="down"&&M<=1)continue;const N=o==="left"||o==="right",z=Math.abs(N?$:M),x=Math.abs(N?M:$);let p=0;if(N){const E=Math.max(t.y,c.y),L=Math.min(t.y+t.height,c.y+c.height);p=Math.max(0,L-E)}else{const E=Math.max(t.x,c.x),L=Math.min(t.x+t.width,c.x+c.width);p=Math.max(0,L-E)}const g=p>0?1/(p+1):x*2.5,v=z+x*1.5+g*10;v<u&&(u=v,l=c)}return l}function $a(t,r,o){for(const i of r)if(i.id!==o&&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 Ea(t,r){return[...t].sort((o,i)=>{const n=r?.get(o.id),d=r?.get(i.id);return typeof n=="number"&&typeof d=="number"?n-d:typeof n=="number"?-1:typeof d=="number"?1:Math.abs(o.y-i.y)>10?o.y-i.y:o.x-i.x})}function _a(t,r=hr,o=100){const i=[],n=t.length;if(n<2)return i;for(let d=0;d<n;d+=1){const l=t[d];for(let u=0;u<n;u+=1){if(d===u)continue;const c=t[u],j=l.y+l.height+r;if(Math.abs(c.y-j)<=3){const b=Math.max(l.x,c.x),M=Math.min(l.x+l.width,c.x+c.width)-b;if(M>20){const N=l.y+l.height;i.push({id:`h-split-${l.id}-${c.id}`,orientation:"horizontal",x:b,y:N,length:M,thickness:Math.max(r,8),firstIds:[l.id],secondIds:[c.id],minPos:l.y+o,maxPos:c.y+c.height-o-r,currentPos:N})}}}}for(let d=0;d<n;d+=1){const l=t[d];for(let u=0;u<n;u+=1){if(d===u)continue;const c=t[u],j=l.x+l.width+r;if(Math.abs(c.x-j)<=3){const b=Math.max(l.y,c.y),M=Math.min(l.y+l.height,c.y+c.height)-b;if(M>20){const N=l.x+l.width;i.push({id:`v-split-${l.id}-${c.id}`,orientation:"vertical",x:N,y:b,length:M,thickness:Math.max(r,8),firstIds:[l.id],secondIds:[c.id],minPos:l.x+o,maxPos:c.x+c.width-o-r,currentPos:N})}}}}return i}function Ra(t,r,o){const n=Math.max(t.minPos,Math.min(t.maxPos,t.currentPos+r))-t.currentPos;if(Math.abs(n)<.5)return{};const d={},l=t.orientation==="horizontal";for(const u of t.firstIds){const c=o.find(j=>j.id===u);c&&(l?d[u]={height:Math.max(20,c.height+n)}:d[u]={width:Math.max(20,c.width+n)})}for(const u of t.secondIds){const c=o.find(j=>j.id===u);c&&(l?d[u]={y:c.y+n,height:Math.max(20,c.height-n)}:d[u]={x:c.x+n,width:Math.max(20,c.width-n)})}return d}function Aa(t,r,o,i=2,n=hr){const d=(r.x-t.x)/t.width,l=(r.y-t.y)/t.height,c=i<=2&&o!==void 0?{x:o.x??0,y:o.y??0,width:o.width,height:o.height}:t,j=Math.max(40,(c.height-n)/2),b=Math.max(40,(c.width-n)/2);return l<.25?{type:"split-top",targetId:t.id,label:"↑ 上方分割插入",previewRect:{x:c.x,y:c.y,width:c.width,height:j}}:l>.75?{type:"split-bottom",targetId:t.id,label:"↓ 下方分割插入",previewRect:{x:c.x,y:c.y+j+n,width:c.width,height:j}}:d<.25?{type:"split-left",targetId:t.id,label:"← 左侧分割插入",previewRect:{x:c.x,y:c.y,width:b,height:c.height}}:d>.75?{type:"split-right",targetId:t.id,label:"→ 右侧分割插入",previewRect:{x:c.x+b+n,y:c.y,width:b,height:c.height}}:{type:"swap",targetId:t.id,label:"⇄ 松开对调位置",previewRect:{x:t.x,y:t.y,width:t.width,height:t.height}}}function Fa(t,r,o,i,n,d=hr){if(t===r)return{};const l=i.find(p=>p.id===t),u=i.find(p=>p.id===r);if(!l||!u)return{};const c={};if(i.length<=2&&n){const p=n.x??0,g=n.y??0,v=n.width,E=n.height,L=Math.max(40,(E-d)/2),O=Math.max(40,(v-d)/2);return o==="split-bottom"?(c[r]={x:p,y:g,width:v,height:L},c[t]={x:p,y:g+L+d,width:v,height:L}):o==="split-top"?(c[t]={x:p,y:g,width:v,height:L},c[r]={x:p,y:g+L+d,width:v,height:L}):o==="split-right"?(c[r]={x:p,y:g,width:O,height:E},c[t]={x:p+O+d,y:g,width:O,height:E}):o==="split-left"&&(c[t]={x:p,y:g,width:O,height:E},c[r]={x:p+O+d,y:g,width:O,height:E}),c}const j=Math.abs(u.x-l.x)<=4&&Math.abs(u.width-l.width)<=4&&(Math.abs(u.y+u.height+d-l.y)<=4||Math.abs(l.y+l.height+d-u.y)<=4),b=Math.abs(u.y-l.y)<=4&&Math.abs(u.height-l.height)<=4&&(Math.abs(u.x+u.width+d-l.x)<=4||Math.abs(l.x+l.width+d-u.x)<=4);if(j){const p=Math.min(l.y,u.y),g=l.height+u.height+d;if(o==="split-top"){const v=Math.max(40,(g-d)/2);return c[t]={x:u.x,y:p,width:u.width,height:v},c[r]={x:u.x,y:p+v+d,width:u.width,height:v},c}if(o==="split-bottom"){const v=Math.max(40,(g-d)/2);return c[r]={x:u.x,y:p,width:u.width,height:v},c[t]={x:u.x,y:p+v+d,width:u.width,height:v},c}if(o==="split-left"){const v=Math.max(40,(u.width-d)/2);return c[t]={x:u.x,y:p,width:v,height:g},c[r]={x:u.x+v+d,y:p,width:v,height:g},c}if(o==="split-right"){const v=Math.max(40,(u.width-d)/2);return c[r]={x:u.x,y:p,width:v,height:g},c[t]={x:u.x+v+d,y:p,width:v,height:g},c}}if(b){const p=Math.min(l.x,u.x),g=l.width+u.width+d;if(o==="split-left"){const v=Math.max(40,(g-d)/2);return c[t]={x:p,y:u.y,width:v,height:u.height},c[r]={x:p+v+d,y:u.y,width:v,height:u.height},c}if(o==="split-right"){const v=Math.max(40,(g-d)/2);return c[r]={x:p,y:u.y,width:v,height:u.height},c[t]={x:p+v+d,y:u.y,width:v,height:u.height},c}if(o==="split-top"){const v=Math.max(40,(u.height-d)/2);return c[t]={x:p,y:u.y,width:g,height:v},c[r]={x:p,y:u.y+v+d,width:g,height:v},c}if(o==="split-bottom"){const v=Math.max(40,(u.height-d)/2);return c[r]={x:p,y:u.y,width:g,height:v},c[t]={x:p,y:u.y+v+d,width:g,height:v},c}}const $=i.filter(p=>p.id!==t&&p.id!==r),M=$.find(p=>Math.abs(p.x-l.x)<=4&&Math.abs(p.width-l.width)<=4&&(Math.abs(p.y+p.height+d-l.y)<=4||Math.abs(l.y+l.height+d-p.y)<=4)),N=$.find(p=>Math.abs(p.y-l.y)<=4&&Math.abs(p.height-l.height)<=4&&(Math.abs(p.x+p.width+d-l.x)<=4||Math.abs(l.x+l.width+d-p.x)<=4));if(M){const p=Math.min(M.y,l.y),g=M.height+l.height+d;c[M.id]={x:M.x,y:p,width:M.width,height:g}}else if(N){const p=Math.min(N.x,l.x),g=N.width+l.width+d;c[N.id]={x:p,y:N.y,width:g,height:N.height}}const z=Math.max(40,(u.height-d)/2),x=Math.max(40,(u.width-d)/2);return o==="split-top"?(c[t]={x:u.x,y:u.y,width:u.width,height:z},c[r]={x:u.x,y:u.y+z+d,width:u.width,height:z}):o==="split-bottom"?(c[r]={x:u.x,y:u.y,width:u.width,height:z},c[t]={x:u.x,y:u.y+z+d,width:u.width,height:z}):o==="split-left"?(c[t]={x:u.x,y:u.y,width:x,height:u.height},c[r]={x:u.x+x+d,y:u.y,width:x,height:u.height}):o==="split-right"&&(c[r]={x:u.x,y:u.y,width:x,height:u.height},c[t]={x:u.x+x+d,y:u.y,width:x,height:u.height}),c}const La=1e3,wt=new Map;function Le(t,r){const o=r!==void 0?r:{};if(!t)return o;const i=typeof t=="string"?t:t.data;if(!i||typeof i!="string")return i||o;if(wt.has(i)){const n=wt.get(i);return wt.delete(i),wt.set(i,n),n}try{const n=JSON.parse(i);if(wt.size>=La){const d=wt.keys().next().value;d!==void 0&&wt.delete(d)}return wt.set(i,n),n}catch(n){return console.warn("[parseElementData] Failed to parse element data:",n,i),o}}function ct(t,r=0){const o=typeof t=="number"?t:Number(t);return Number.isFinite(o)?o:r}function Wa(t){let r=0,o=0;for(const i of t){const n=ct(i?.x),d=ct(i?.y),l=Math.max(0,ct(i?.width)),u=Math.max(0,ct(i?.height));r=Math.max(r,n+l),o=Math.max(o,d+u)}return{maxX:r,maxY:o}}function Ba(t,r,o=0,i=0){const n=Math.max(0,ct(o)),d=Math.max(0,ct(t?.width)),l=Math.max(0,ct(t?.height)),u=Math.max(0,ct(i)),c=Math.ceil(Math.max(0,ct(r?.maxX))+n),j=Math.ceil(Math.max(0,ct(r?.maxY))+n);let b=c>d,$=j>l;const M=(N,z)=>{const x=Math.max(0,d-(z?u:0)),p=Math.max(0,l-(N?u:0));return{canvas:{width:Math.max(x,c),height:Math.max(p,j)},overflowX:c>x,overflowY:j>p}};for(let N=0;N<3;N++){const z=M(b,$);if(z.overflowX===b&&z.overflowY===$)return z;b=z.overflowX,$=z.overflowY}return M(b,$)}function Ha(t,r,o,i){return{x:t-o.left+(i?.scrollLeft||0),y:r-o.top+(i?.scrollTop||0)}}function Oa(){return typeof HTMLElement<"u"&&Object.hasOwn(HTMLElement.prototype,"popover")}function Xa(){return typeof CSS<"u"&&typeof CSS.supports=="function"&&CSS.supports("position-area: block-end")}function Ya(){return typeof Element<"u"&&"startViewTransition"in Element.prototype}function qa(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function an(t,r){const o=()=>{try{gn.flushSync(r)}catch{r()}};if(!t||!Ya()||qa()){r();return}const i=t;if(typeof i.startViewTransition!="function"){r();return}try{i.startViewTransition(o)?.ready?.catch?.(()=>{})}catch{r()}}function on(t,r,o,i,n,d,l=8){const u=Math.max(l,n-o-l),c=Math.max(l,d-i-l);return{left:Math.min(Math.max(l,t),u),top:Math.min(Math.max(l,r),c)}}function Ja(t=document){if(typeof t>"u"||!t.body)return 0;const r=t.createElement("div");r.style.cssText="position:absolute;top:-9999px;width:100px;height:100px;overflow:scroll;visibility:hidden;pointer-events:none",t.body.appendChild(r);const o=r.offsetWidth-r.clientWidth;return r.remove(),Number.isFinite(o)&&o>0?o:0}function ln(t){const r=getComputedStyle(t),o=(parseFloat(r.borderLeftWidth)||0)+(parseFloat(r.borderRightWidth)||0),i=(parseFloat(r.borderTopWidth)||0)+(parseFloat(r.borderBottomWidth)||0);return{width:Math.max(0,t.offsetWidth-o),height:Math.max(0,t.offsetHeight-i)}}class Ia{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 o=this.getTokens();this.listeners.forEach(i=>{try{i(o,r)}catch(n){console.error("[ThemeManager] Error in theme change listener:",n)}})}getTheme(){return this.currentTheme}registerCustomTokens(r,o){this.customTokens.set(r,o),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 Ia;function dt({title:t,icon:r,hidden:o=!1,readOnly:i=!1,isMinimized:n=!1,isMaximized:d=!1,isPropertiesOpen:l=!1,themeColor:u="default",onPointerDown:c,onPointerMove:j,onPointerUp:b,onOpenProperties:$,onMinimize:M,onRestore:N,onMaximize:z,onBrowserFullscreen:x,onDelete:p,extraActions:g}){const v=()=>{switch(u){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 o?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 ${v()} ${i?"cursor-default":"cursor-move"}`,onPointerDown:c,onPointerMove:j,onPointerUp:b,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:E=>E.stopPropagation(),children:[g,$&&e.jsx("button",{type:"button",onClick:$,className:`p-1 rounded-lg transition-all cursor-pointer flex items-center justify-center ${l?"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})}),M&&e.jsx("button",{type:"button",onClick:M,disabled:n,className:`p-1 rounded-lg transition-all flex items-center justify-center ${n?"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(Ki,{size:12})}),N&&e.jsx("button",{type:"button",onClick:N,className:`p-1 rounded-lg transition-all flex items-center justify-center ${n||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(ns,{size:11,className:n||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(Zi,{size:11})}),x&&e.jsx("button",{type:"button","data-testid":"widget-titlebar-browser-fullscreen",onClick:x,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(Qi,{size:11})}),p&&e.jsx("button",{type:"button",onClick:p,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(jt,{size:12})})]})]})}const Ga=1e5;function dn({children:t,onMaximize:r,onBrowserFullscreen:o,isBrowserFullscreen:i=!1,browserFullscreenDismissible:n=!0,contentClassName:d="flex-1 min-h-0 overflow-auto",...l}){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:[n&&o&&e.jsxs("button",{type:"button","data-testid":"widget-frame-exit-browser-fullscreen",onClick:o,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:u,icon:c,readOnly:j,isMinimized:b,isMaximized:$,isPropertiesOpen:M,themeColor:N,extraActions:z,...x}=l;return e.jsxs("div",{"data-widget-frame":"true",className:"w-full h-full flex flex-col min-h-0",children:[e.jsx(dt,{title:u,icon:c,readOnly:j,isMinimized:b,isMaximized:$,isPropertiesOpen:M,themeColor:N,extraActions:z,...x,onMaximize:r,onBrowserFullscreen:o}),!b&&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 Hr(){return typeof document>"u"?!1:!!(document.fullscreenElement||document.webkitFullscreenElement)}function Ua({elementId:t,enableNativeFullscreen:r=!0,onChange:o}){const i=un(),[n,d]=a.useState(!1),l=a.useRef(t);l.current=t;const u=a.useRef(o);u.current=o,a.useEffect(()=>()=>{Hr()&&document.exitFullscreen?.()?.catch?.(()=>{})},[]),a.useEffect(()=>{if(typeof document>"u")return;const b=()=>{const $=Hr();d($),!$&&l.current&&u.current&&u.current(null)};return document.addEventListener("fullscreenchange",b),document.addEventListener("webkitfullscreenchange",b),()=>{document.removeEventListener("fullscreenchange",b),document.removeEventListener("webkitfullscreenchange",b)}},[]);const c=a.useCallback(async b=>{if(u.current?.(b),!!r&&un())try{const $=document.documentElement;await($.requestFullscreen?.()??$.webkitRequestFullscreen?.()),d(!0)}catch($){console.warn("[BrowserFullscreen] native fullscreen rejected:",$)}},[r]),j=a.useCallback(async()=>{if(u.current?.(null),Hr())try{await document.exitFullscreen?.()}catch(b){console.warn("[BrowserFullscreen] exit failed:",b)}d(!1)},[]);return{nativeSupported:i,nativeActive:n,enter:c,exit:j}}function Va({pluginId:t,slot:r,widgetId:o,elementId:i,lessonId:n,classId:d,studentId:l,studentName:u}){const j=vn(z=>z.extensionPoints).get(r)||[],b=j.find(z=>z.id===o)??j.find(z=>z.pluginId===t&&z.id===o),$=!!b&&typeof b.component=="function"&&b.component!==Ri,M=a.useRef(null);if(a.useEffect(()=>{b&&M.current&&!$&&(M.current.innerHTML="",b.render&&Promise.resolve(b.render(M.current,{elementId:i,lessonId:n})).catch(console.error))},[b,$,t,o,i,n]),!o)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(is,{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(!b)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(it,{size:16,className:"animate-spin mb-1"}),e.jsxs("span",{children:["组件 [",o,"] 正在加载或未启用..."]})]});if($)return ss.createElement(b.component,{elementId:i,lessonId:n});const N=b.slotProps?.view||b.view;return N?e.jsx(Ai,{pluginId:b.pluginId,view:String(N),label:b.label,slot:r,lessonId:n,classId:d,studentId:l,studentName:u,variant:"panel"}):e.jsx("div",{ref:M,className:"w-full h-full min-h-0"})}function Ka({elementId:t,data:r,lessonId:o,classId:i,onElementUpdate:n,onPointerDown:d,onPointerMove:l,onPointerUp:u,onDelete:c,readOnly:j=!1,userRole:b="teacher",isMinimized:$=!1,isMaximized:M=!1,hidden:N=!1,onBrowserFullscreen:z,isPropertiesOpen:x=!1,onOpenProperties:p,onMinimize:g,onRestore:v,onMaximize:E}){const L=Ar(re=>re.classes)||[],O=Ar(re=>re.onlineStudentIds),W=Ar(re=>re.activeStudentLessons),[F,de]=a.useState(i||r.classId||(L[0]?.id??"")),[B,ne]=a.useState(()=>Array.isArray(r.candidates)&&r.candidates.length>0?r.candidates:Array.isArray(r.allStudents)&&r.allStudents.length>0?r.allStudents:i||r.classId||o?[]:[{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}]),[A,ee]=a.useState(!!(i||r.classId)),[J,C]=a.useState(r.pickerMode||"fair_all"),[_,S]=a.useState(r.difficulty||"intermediate"),[D,G]=a.useState(r.selectedStudent||null),[ie,V]=a.useState(!1),[H,Y]=a.useState(null),[m,w]=a.useState(r.evaluation||null),y=a.useMemo(()=>JSON.stringify([r.pickedTime??null,r.selectedStudent?.id??null,r.evaluation?.rating??null,r.evaluation?.submitted??null]),[r.pickedTime,r.selectedStudent,r.evaluation]),k=a.useRef(null),K=a.useRef(r);K.current=r;const Z=a.useRef([]),ce=a.useMemo(()=>o?(O||[]).filter(re=>W?.[re]===o).slice().sort().join("\0"):"",[o,O,W]);a.useEffect(()=>{r.pickedTime!=null&&k.current!==y&&(k.current=y,G(r.selectedStudent??null),w(r.evaluation??null),V(!1),Y(null))},[y,r.pickedTime,r.selectedStudent,r.evaluation]),a.useEffect(()=>{if(!F)return;let re=!0;ee(!0);const we=`/api/classes/${F}/picker-candidates${o?`?lessonId=${encodeURIComponent(o)}`:""}`;return fetch(we).then(Me=>{if(!Me.ok)throw new Error("Failed to load class picker candidates");return Me.json()}).then(Me=>{!re||!Array.isArray(Me)||(Me.length>0||o)&&ne(Me)}).catch(Me=>{console.warn("[RollCallWrapper] candidates fallback:",Me)}).finally(()=>{re&&ee(!1)}),()=>{re=!1}},[F,o,ce]);const $e=a.useMemo(()=>Fi(B,{onlineStudentIds:O,activeStudentLessons:W,lessonId:o}),[B,O,W,o]),ye=a.useMemo(()=>{if(J==="fair_all")return $e;const{filtered:re}=Li($e,_);return re},[$e,J,_]);Z.current=ye;const he=()=>{if(Z.current.length===0||ie)return;V(!0),w(null);let re=0;const we=16,R=setInterval(()=>{const Q=Z.current;if(Q.length===0){clearInterval(R),V(!1),Y(null);return}const pe=Math.floor(Math.random()*Q.length);if(Y(Q[pe]),re++,re>=we){clearInterval(R);const ue=Z.current;if(ue.length===0){V(!1),Y(null);return}const fe=Wi(ue),Ie=fe?fe.student:ue[0];G(Ie),V(!1),Y(null),ne(ut=>ut.map(Xe=>Xe.id===Ie.id?{...Xe,lesson_picked_count:(Xe.lesson_picked_count||0)+1}:Xe)),n&&n(t,{...K.current,classId:F,pickerMode:J,difficulty:_,selectedStudent:Ie,pickedTime:new Date().toISOString(),status:"picked",evaluation:null}),oe.publish({id:le(),type:"rollcall.picked",source:"rollcall.picker",payload:{elementId:t,studentId:Ie.id,studentName:Ie.name,classId:F,lessonId:o},timestamp:Date.now()})}},70)},Ee=b==="teacher"||b==="administrator",ve=async re=>{if(!D||m?.submitted)return;const we=ar[re],Me={rating:re,score:we.score,rewardCoins:we.rewardCoins,submitted:!0};w(Me),ne(R=>R.map(Q=>Q.id===D.id?{...Q,total_reward_coins:(Q.total_reward_coins||0)+we.rewardCoins}:Q));try{await fetch("/api/rollcalls/evaluate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:`rollcall-${t}-${D.id}-${Date.now()}`,studentId:D.id,studentName:D.name,classId:F,lessonId:o,rating:re,score:we.score,rewardCoins:we.rewardCoins,difficulty:J==="tiered"?_:"intermediate"})})}catch(R){console.error("[RollCallWrapper] evaluate rollcall failed:",R)}n&&n(t,{...K.current,evaluation:Me}),oe.publish({id:le(),type:"rollcall.evaluated",source:"rollcall.picker",payload:{elementId:t,studentId:D.id,rating:re,rewardCoins:we.rewardCoins,score:we.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:j?"none":"auto"},children:[e.jsx(dt,{title:"随机点名助手 (分层抽问 Fair Picker)",icon:e.jsx(Yt,{size:13,className:"animate-pulse text-amber-400"}),readOnly:j,isMinimized:$,isMaximized:M,hidden:N,onBrowserFullscreen:z,isPropertiesOpen:x,themeColor:"indigo",onPointerDown:d,onPointerMove:l,onPointerUp:u,onOpenProperties:p,onMinimize:g,onRestore:v,onMaximize:E,onDelete:c,extraActions:L.length>1&&Ee?e.jsx("div",{className:"relative mr-1",onPointerDown:re=>re.stopPropagation(),children:e.jsx("select",{value:F,onChange:re=>de(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:L.map(re=>e.jsx("option",{value:re.id,className:"bg-slate-900 text-white",children:re.name},re.id))})}):null}),!$&&e.jsxs(e.Fragment,{children:[Ee&&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:()=>C("fair_all"),className:`px-2 py-0.5 rounded text-xs font-medium transition-all ${J==="fair_all"?"bg-indigo-600 text-white shadow-2xs font-bold":"text-indigo-300 hover:text-white"}`,children:"全员公平"}),e.jsx("button",{onClick:()=>C("tiered"),className:`px-2 py-0.5 rounded text-xs font-medium transition-all ${J==="tiered"?"bg-purple-600 text-white shadow-2xs font-bold":"text-indigo-300 hover:text-white"}`,children:"分层抽问"})]}),J==="tiered"&&e.jsx("div",{className:"flex items-center gap-1",children:["basic","intermediate","advanced"].map(re=>{const we=re==="basic"?"基础":re==="intermediate"?"进阶":"拔高",Me=re==="basic"?"bg-emerald-600 text-white":re==="intermediate"?"bg-blue-600 text-white":"bg-amber-600 text-white";return e.jsx("button",{onClick:()=>S(re),className:`px-1.5 py-0.5 rounded text-xs font-medium transition-all ${_===re?`${Me} font-bold shadow-2xs`:"text-indigo-400 hover:text-white"}`,children:we},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:ie?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(Jr,{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:H?.name||"..."}),e.jsxs("div",{className:"text-xs text-indigo-400/80 font-mono",children:["学号: ",H?.student_number||"---"]})]}):D?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:D.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:["学号 ",D.student_number||D.id]}),e.jsx("span",{children:"•"}),e.jsxs("span",{children:["已回答 ",D.lesson_picked_count||0," 次"]}),D.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(ea,{size:10}),D.total_reward_coins]})]})]}),e.jsx("div",{className:"mt-2 pt-2 border-t border-indigo-900/50 w-full",onPointerDown:re=>re.stopPropagation(),children:m?.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(ta,{size:14,className:"text-emerald-400"}),e.jsxs("span",{className:"font-bold text-emerald-300",children:["已评定: ",ar[m.rating].badge," ",ar[m.rating].label]}),e.jsxs("span",{className:"text-amber-300 font-bold flex items-center gap-0.5",children:["+",m.rewardCoins," 金币"]})]}):Ee?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 we=ar[re];return e.jsxs("button",{onClick:()=>void ve(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:we.badge}),e.jsx("span",{className:"text-2xs font-semibold",children:we.label}),e.jsxs("span",{className:"text-3xs text-amber-300 font-mono",children:["+",we.rewardCoins,"币"]})]},re)})})]}):null})]}):ye.length===0&&!A?e.jsxs("div",{className:"text-center space-y-1.5 px-3","data-testid":"rollcall-no-present-students",children:[e.jsx(Ir,{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(Ir,{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:he,disabled:ie||ye.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(Jr,{size:12,className:ie?"animate-spin":""}),e.jsx("span",{children:ie?"加权滚轮运转中...":D?"抽取下一位学生":"开始随机点名"})]}),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:["候选池:",ye.length," 人"]}),e.jsx("span",{children:"•"}),e.jsx("span",{children:J==="fair_all"?"全员公平":`分层: ${_}`}),A&&e.jsx($t,{size:9,className:"animate-spin text-indigo-400"})]}),!A&&ye.length===0&&D&&e.jsx("p",{className:"text-2xs text-amber-200/90 text-center leading-relaxed","data-testid":"rollcall-no-present-students",children:"当前课堂没有在场学生。只会抽取已经进入本节课的学生,离开后不会再被点到。"})]})]})]})]})}const ts="Pure computation only. No page session, cookies, document, or LMS API.",Za="openlearn-code-sandbox",Qa=["'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(`
3
+ `),eo=[" })();",' 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(`
4
+ `);function to(t){return`${Qa}
5
+ ${t}
6
+ ${eo}`}function ro(t){const r=/(^|[^.\w$])import\s*\(/m.test(t),o=/(^|\n)\s*import\s+[\w*{]/m.test(t);return r||o?`Error: ${ts}`:null}function so({elementId:t,data:r,onElementUpdate:o,onPointerDown:i,onPointerMove:n,onPointerUp:d,onDelete:l,readOnly:u=!1,isMinimized:c=!1,isMaximized:j=!1,hidden:b=!1,isPropertiesOpen:$=!1,onOpenProperties:M,onMinimize:N,onRestore:z,onMaximize:x,onBrowserFullscreen:p}){const[g,v]=a.useState(r.code||"console.log('Hello from sandbox!');"),[E,L]=a.useState(""),O=a.useRef(null);a.useEffect(()=>()=>{const B=O.current;B&&(B.settled=!0,B.timer!==void 0&&clearTimeout(B.timer),B.worker.terminate(),URL.revokeObjectURL(B.url),O.current=null)},[]),a.useEffect(()=>{r.code!==void 0&&r.code!==g&&v(r.code)},[r.code]);const W=()=>{const B=O.current;!B||B.settled||(B.settled=!0,B.timer!==void 0&&clearTimeout(B.timer),B.worker.terminate(),URL.revokeObjectURL(B.url),O.current=null)},F=()=>{const B=ro(g);if(B){W(),L(B);return}W(),L(`Running. ${ts}`);const ne=URL.createObjectURL(new Blob([to(g)],{type:"application/javascript"}));let A;try{A=new Worker(ne)}catch(C){URL.revokeObjectURL(ne);const _=C instanceof Error?C.message:String(C);L(`Failed to start the sandbox: ${_}`);return}const ee={worker:A,url:ne,settled:!1},J=C=>{ee.settled||(ee.settled=!0,ee.timer!==void 0&&clearTimeout(ee.timer),A.terminate(),URL.revokeObjectURL(ne),O.current===ee&&(O.current=null),L(C))};ee.timer=setTimeout(()=>{J("Execution timed out (3000ms limit). Worker terminated.")},3e3),O.current=ee,A.onmessage=C=>{const _=C.data;!_||_.source!==Za||(_.success?J(_.logs||"Code executed successfully (no output)"):J((_.logs?_.logs+`
7
+ `:"")+"Error: "+(_.error||"unknown error")))},A.onerror=C=>{J(`Worker Error: ${C.message||"unknown error"}`)}},de=()=>{o&&g!==r.code&&o(t,{...r,code:g})};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:u?"none":"auto"},children:[e.jsx(dt,{title:r.title||"JS Sandbox",icon:e.jsx(Cn,{size:13,className:"text-emerald-500"}),readOnly:u,isMinimized:c,isMaximized:j,hidden:b,isPropertiesOpen:$,themeColor:"default",onPointerDown:i,onPointerMove:n,onPointerUp:d,onOpenProperties:M,onMinimize:N,onRestore:z,onMaximize:x,onBrowserFullscreen:p,onDelete:l,extraActions:u?null:e.jsx("button",{type:"button",onClick:F,onPointerDown:B=>B.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"})}),!c&&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:ts}),e.jsx("textarea",{value:g,onChange:B=>v(B.target.value),onBlur:de,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:B=>{B.stopPropagation()},onKeyDown:B=>{B.stopPropagation()}}),E&&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:E})]})]})}function no(t,r){const o=(t||"").trim();if(!o)return NaN;if(/[;={}\[\]'"`\\&|<>?!]|constructor|prototype|__proto__|window|document|fetch|eval|import|require|process/i.test(o))throw new Error("表达式包含不安全字符");const n=o.replace(/Math\./gi,"").toLowerCase(),d=[];let l=0;for(;l<n.length;){const g=n[l];if(/\s/.test(g)){l++;continue}if(/[0-9.]/.test(g)){let v="";for(;l<n.length&&/[0-9.]/.test(n[l]);)v+=n[l++];d.push(v);continue}if(/[a-z]/.test(g)){let v="";for(;l<n.length&&/[a-z]/.test(n[l]);)v+=n[l++];d.push(v);continue}if("+-*/^%()".includes(g)){d.push(g),l++;continue}throw new Error(`不支持的符号: ${g}`)}let u=0;const c=()=>d[u],j=g=>{const v=d[u++];if(g&&v!==g)throw new Error(`预期 '${g}',但得到 '${v}'`);return v},b=()=>$(),$=()=>{let g=M();for(;c()==="+"||c()==="-";){const v=j(),E=M();g=v==="+"?g+E:g-E}return g},M=()=>{let g=N();for(;c()==="*"||c()==="/"||c()==="%";){const v=j(),E=N();v==="*"?g*=E:v==="/"?g=E===0?NaN:g/E:g%=E}return g},N=()=>{let g=z();for(;c()==="^";){j();const v=N();g=Math.pow(g,v)}return g},z=()=>c()==="-"?(j(),-z()):c()==="+"?(j(),z()):x(),x=()=>{const g=c();if(!g)throw new Error("意外的表达式结尾");if(g==="("){j("(");const E=b();return j(")"),E}if(/^[0-9.]+$/.test(g))return j(),parseFloat(g);if(g==="x")return j(),r;if(g==="pi")return j(),Math.PI;if(g==="e")return j(),Math.E;const v=j();if(c()==="("){j("(");const E=b();switch(j(")"),v){case"sin":return Math.sin(E);case"cos":return Math.cos(E);case"tan":return Math.tan(E);case"sqrt":return Math.sqrt(E);case"abs":return Math.abs(E);case"log":return Math.log(E);case"exp":return Math.exp(E);case"round":return Math.round(E);case"floor":return Math.floor(E);case"ceil":return Math.ceil(E);default:throw new Error(`未知的数学函数: ${v}`)}}throw new Error(`未知的数学标识符: ${g}`)},p=b();if(u<d.length)throw new Error(`多余语法: ${d.slice(u).join(" ")}`);return p}function io({elementId:t,data:r,onElementUpdate:o,onPointerDown:i,onPointerMove:n,onPointerUp:d,onDelete:l,readOnly:u=!1,isMinimized:c=!1,isMaximized:j=!1,hidden:b=!1,isPropertiesOpen:$=!1,onOpenProperties:M,onMinimize:N,onRestore:z,onMaximize:x,onBrowserFullscreen:p}){const[g,v]=a.useState(r.equation||"sin(x)"),[E,L]=a.useState(""),[O,W]=a.useState(""),[F,de]=a.useState({width:400,height:300}),B=a.useRef(null);a.useEffect(()=>{r.equation!==void 0&&r.equation!==g&&v(r.equation)},[r.equation]),a.useEffect(()=>{if(!B.current)return;const A=new ResizeObserver(ee=>{for(const J of ee)de({width:J.contentRect.width||400,height:J.contentRect.height||300})});return A.observe(B.current),()=>A.disconnect()},[]),a.useEffect(()=>{try{const A=[],ee=F.width/2,J=F.height/2;for(let C=-10;C<=10;C+=.2){const _=C,S=no(g,_);if(typeof S!="number"||isNaN(S))continue;const D=ee+_*20,G=J-S*20;A.push(`${D},${G}`)}L(A.join(" ")),W("")}catch(A){W(A.message)}},[g,F]);const ne=()=>{o&&g!==r.equation&&o(t,{...r,equation:g})};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:u?"none":"auto"},children:[e.jsx(dt,{title:r.title||"Math Graph Sandbox",icon:e.jsx(Sn,{size:13,className:"text-indigo-500"}),readOnly:u,isMinimized:c,isMaximized:j,hidden:b,isPropertiesOpen:$,themeColor:"default",onPointerDown:i,onPointerMove:n,onPointerUp:d,onOpenProperties:M,onMinimize:N,onRestore:z,onMaximize:x,onBrowserFullscreen:p,onDelete:l}),!c&&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:g,disabled:u,onChange:A=>v(A.target.value),onBlur:ne,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:A=>A.stopPropagation(),onKeyDown:A=>A.stopPropagation()}),O&&e.jsx("div",{className:"text-red-500 text-xs mt-1",children:O})]}),e.jsx("div",{className:"flex-1 relative overflow-hidden bg-white min-h-0",ref:B,children:e.jsxs("svg",{width:F.width,height:F.height,viewBox:`0 0 ${F.width} ${F.height}`,className:"absolute top-0 left-0",children:[e.jsx("line",{x1:F.width/2,y1:"0",x2:F.width/2,y2:F.height,stroke:"#e5e7eb",strokeWidth:"1"}),e.jsx("line",{x1:"0",y1:F.height/2,x2:F.width,y2:F.height/2,stroke:"#e5e7eb",strokeWidth:"1"}),E&&e.jsx("polyline",{points:E,fill:"none",stroke:"#6366f1",strokeWidth:"2",strokeLinejoin:"round"})]})})]})]})}function ao({elementId:t,data:r,onElementUpdate:o,onPointerDown:i,onPointerMove:n,onPointerUp:d,onDelete:l,lessonId:u,readOnly:c=!1,isMinimized:j=!1,isMaximized:b=!1,hidden:$=!1,onBrowserFullscreen:M,isPropertiesOpen:N=!1,onOpenProperties:z,onMinimize:x,onRestore:p,onMaximize:g}){const[v,E]=a.useState(!1),L=async()=>{E(!0);try{await fetch("/api/commands",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({commandType:"hello.say",payload:{lessonId:u,username:"World",shout:!0}})})}catch(O){console.error("Failed to trigger hello.say command:",O)}finally{E(!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:c?"none":"auto"},children:[e.jsx(dt,{title:"Hello World 插件",icon:e.jsx(Yt,{size:11,className:"text-amber-500 animate-pulse"}),readOnly:c,isMinimized:j,isMaximized:b,hidden:$,onBrowserFullscreen:M,isPropertiesOpen:N,themeColor:"slate",onPointerDown:i,onPointerMove:n,onPointerUp:d,onOpenProperties:z,onMinimize:x,onRestore:p,onMaximize:g,onDelete:l}),!j&&e.jsx("div",{className:"flex-1 p-2 flex items-center justify-center bg-slate-50/20",children:e.jsxs("button",{onClick:L,disabled:v,onPointerDown:O=>O.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(zn,{size:11,className:v?"animate-spin":""}),e.jsx("span",{children:v?"输出中...":"点击输出"})]})})]})}const oo=({tool:t,setTool:r,setSelectedShapeId:o,highlighterColor:i,setHighlighterColor:n,onElementAdd:d,currentPage:l,activeSegmentId:u,lessonId:c,safeElements:j,selectedShapeId:b,showGrid:$,setShowGrid:M,autoTileEnabled:N=!1,onToggleAutoTile:z,readOnly:x=!1,userRole:p="teacher",isSyncing:g,setIsSyncing:v,handleClearBoard:E,handleResetBoard:L,handleElementDelete:O,setDialog:W,setDialogInput:F,onRefresh:de,classroomTools:B=[],onExecuteTool:ne})=>{const A=a.useId().replace(/:/g,""),ee=`--wb-plugin-anchor-${A}`,J=`wb-plugin-popover-${A}`,C=Oa()&&Xa(),[_,S]=a.useState(!1),D=a.useRef(null),G=a.useRef(null),[ie,V]=a.useState(null);a.useEffect(()=>{const y=G.current;if(!C||!y)return;const k=K=>{S(K.newState==="open")};return y.addEventListener("toggle",k),()=>y.removeEventListener("toggle",k)},[C]);const H=a.useCallback(()=>{if(C)return;const y=D.current?.getBoundingClientRect();y&&V({top:y.bottom+6,left:Math.max(8,Math.min(y.left,window.innerWidth-340))}),S(k=>!k)},[C]);a.useEffect(()=>{if(C||!_)return;const y=()=>S(!1);return window.addEventListener("scroll",y,!0),window.addEventListener("resize",y),()=>{window.removeEventListener("scroll",y,!0),window.removeEventListener("resize",y)}},[_,C]);const Y=a.useCallback(y=>{S(!1),G.current?.hidePopover?.(),ne?.(y)},[ne]),m=e.jsxs(e.Fragment,{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(Fr,{size:11,className:"text-primary-theme"}),B.length>0?`互动工具 · ${B.length} 个插件`:"互动工具"]}),B.length>0?B.map(y=>e.jsxs("button",{onClick:()=>Y(y),disabled:!c,title:y.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(Fr,{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:y.name}),e.jsx("span",{className:"block text-2xs text-muted truncate mt-0.5",children:y.description||y.name})]})]},`${y.pluginId}/${y.id}`)):e.jsx("div",{className:"px-2 py-3 text-xs text-muted italic text-center",children:"暂无可用的互动工具。请在应用商店启用插件。"})]}),w=C?e.jsx("div",{id:J,ref:G,popover:"auto",className:"wb-anchored-popover w-[320px] max-h-[420px] overflow-y-auto bg-surface border border-theme rounded-xl shadow-xl p-2 font-sans text-main",style:{positionAnchor:ee},children:m}):_&&ie?gn.createPortal(e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"fixed inset-0 z-[9998]",onPointerDown:()=>S(!1)}),e.jsx("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:ie.top,left:ie.left},children:m})]}),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"),o(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(Tn,{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(Pn,{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(y=>e.jsx("button",{onClick:()=>n(y.hex),className:`w-3 h-3 rounded-full border transition-all ${i===y.hex?"ring-2 ring-primary-theme scale-110 border-white":"border-transparent"}`,style:{backgroundColor:y.hex},title:y.label},y.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(ns,{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(Dn,{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($n,{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(ze,{slot:"anchor:whiteboard-toolbar:presentation",placement:"before"}),e.jsx("button",{onClick:()=>{F(`# Title Slide
8
+ ---
9
+ ## Slide 2`),W({type:"prompt",title:"添加演示文稿",message:"请输入演示文稿的 Markdown 内容 (使用 --- 拆分新幻灯片):",placeholder:`# Title Slide
10
+ ---
11
+ ## Slide 2`,onConfirm:async y=>{const k=y||`# Title Slide
12
+ ---
13
+ ## Slide 2`;v(!0);try{await d("presentation",{markdown:k,x:50,y:50,width:600,height:400,slideX:0,slideY:0,page:l,segmentId:u}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:c},timestamp:Date.now(),correlationId:c})}finally{v(!1),W(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(En,{size:14})}),e.jsx(ze,{slot:"anchor:whiteboard-toolbar:presentation",placement:"after"}),e.jsx(ze,{slot:"anchor:whiteboard-toolbar:code-sandbox",placement:"before"}),e.jsx("button",{onClick:async()=>{v(!0);try{await d("code-sandbox",{code:"console.log('Hello Sandbox!');",x:100,y:100,page:l,segmentId:u}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:c},timestamp:Date.now(),correlationId:c})}finally{v(!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(Cn,{size:14})}),e.jsx(ze,{slot:"anchor:whiteboard-toolbar:code-sandbox",placement:"after"}),e.jsx(ze,{slot:"anchor:whiteboard-toolbar:math-graph",placement:"before"}),e.jsx("button",{onClick:async()=>{v(!0);try{await d("math-graph",{equation:"Math.sin(x)",x:100,y:150,page:l,segmentId:u}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:c},timestamp:Date.now(),correlationId:c})}finally{v(!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(Sn,{size:14})}),e.jsx(ze,{slot:"anchor:whiteboard-toolbar:math-graph",placement:"after"}),e.jsx(ze,{slot:"anchor:whiteboard-toolbar:courseware",placement:"before"}),e.jsx("button",{onClick:async()=>{v(!0);try{await d("html-applet",{code:`<!-- Interactive Web Courseware -->
14
+ <div style='padding:20px; text-align:center;'>
15
+ <h2>Interactive Web Courseware</h2>
16
+ <p>可在右侧属性栏中选择本地 ZIP/HTML 部署包。</p>
17
+ </div>`,x:100,y:150,page:l,segmentId:u}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:c},timestamp:Date.now(),correlationId:c})}finally{v(!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(as,{size:14})}),e.jsx(ze,{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(ze,{slot:"anchor:whiteboard-toolbar:rollcall",placement:"before"}),e.jsx("button",{onClick:async()=>{v(!0);try{await d("rollcall",{title:"随机点名助手",x:120,y:120,page:l,segmentId:u}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:c},timestamp:Date.now(),correlationId:c})}finally{v(!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(ze,{slot:"anchor:whiteboard-toolbar:rollcall",placement:"after"})]}),e.jsx(ze,{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:D,type:"button",popoverTarget:C?J:void 0,onClick:H,style:C?{anchorName:ee}:void 0,className:`relative w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${_?"bg-primary-theme text-white shadow-2xs":"text-primary-theme hover:bg-primary-theme-light"} ${B.length===0?"opacity-50":""}`,title:"互动工具 (插件扩展)",children:[e.jsx(Fr,{size:14}),B.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:B.length})]})}),w,e.jsx(ze,{slot:"anchor:whiteboard-toolbar:ai-tutor",placement:"before"}),e.jsx("button",{onClick:async()=>{v(!0);try{(await fetch(`/api/lessons/${c}/ai-tutor`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elements:j.map(k=>({type:k.type,data:JSON.parse(k.data)}))})})).ok?(oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:c},timestamp:Date.now(),correlationId:c}),de&&de()):W({type:"alert",title:"AI 辅导提示",message:"无法获取 AI 授课助手的帮助,请稍后再试。",onConfirm:()=>W(null)})}finally{v(!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(zn,{size:14})}),e.jsx(ze,{slot:"anchor:whiteboard-toolbar:ai-tutor",placement:"after"})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0 ml-auto",children:[e.jsx(ze,{slot:"anchor:whiteboard-toolbar:grid",placement:"before"}),e.jsx("button",{onClick:()=>M(y=>!y),className:`w-7 h-7 flex items-center justify-center rounded-lg transition-all cursor-pointer ${$?"text-primary-theme bg-primary-theme-light":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:$?"关闭网格背景":"开启网格背景",children:e.jsx(ra,{size:14})}),e.jsx(ze,{slot:"anchor:whiteboard-toolbar:grid",placement:"after"}),!x&&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 ${N?"text-primary-theme bg-primary-theme-light":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:N?"关闭自动平铺,恢复自由布局":"开启自动平铺(i3 式镶嵌布局)",children:e.jsx(Gr,{size:14})}),N&&e.jsx("span",{className:"text-2xs font-semibold text-primary-theme whitespace-nowrap",title:"当前为自动平铺模式,新组件会自动落入下一个格子",children:"平铺中"})]}),b&&e.jsxs("button",{onClick:()=>{O(b),o(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(jt,{size:12}),e.jsx("span",{className:"hidden sm:inline",children:"删除"})]}),p!=="student"?e.jsx("button",{onClick:E,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(sa,{size:14})}):e.jsx("button",{onClick:L,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(na,{size:14})}),g&&e.jsx(it,{size:13,className:"text-primary-theme animate-spin ml-0.5"})]})]})},lo=({pages:t,currentPage:r,activeSegmentId:o,showPageDrawer:i,setShowPageDrawer:n,editingPageIdx:d,setEditingPageIdx:l,editingPageTitle:u,setEditingPageTitle:c,activeMenuPageIdx:j,setActiveMenuPageIdx:b,safeElements:$,handleSwitchPage:M,handleRenamePage:N,handleDuplicatePage:z,handleMovePage:x,handleDeletePage:p,handleAddPage:g})=>{const v=a.useMemo(()=>t.map((L,O)=>({page:L,globalIdx:O})).filter(({page:L})=>!o||!L.segmentId||L.segmentId===o),[t,o]),E=v.findIndex(({globalIdx:L})=>L===r);return 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:()=>n(!i),className:`p-1.5 rounded-full transition-colors cursor-pointer flex items-center gap-1 text-xs font-medium ${i?"bg-primary-theme-light text-primary-theme":"text-muted hover:bg-surface-secondary hover:text-main"}`,title:"页面大纲与预览 (Pages Outline)",children:[e.jsx(Gr,{size:15}),e.jsxs("span",{className:"hidden sm:inline text-xs font-semibold",children:["大纲 (",v.length,")"]})]}),e.jsx("div",{className:"h-4 w-px bg-border-theme mx-0.5"}),e.jsx("button",{onClick:()=>{E>0&&M(v[E-1].globalIdx)},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:E<=0,title:"上一页",children:e.jsx(Lr,{size:16})}),e.jsx("div",{className:"flex items-center gap-1 max-w-[500px] overflow-x-auto no-scrollbar py-0.5",children:v.map(({page:L,globalIdx:O},W)=>{const F=O===r,de=d===O;return e.jsxs("div",{className:"relative group flex items-center",children:[de?e.jsx("input",{type:"text",autoFocus:!0,value:u,onChange:B=>c(B.target.value),onKeyDown:B=>{ga(B)&&(B.preventDefault(),N(O,u)),B.key==="Escape"&&l(null)},onBlur:()=>N(O,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:()=>M(O),onDoubleClick:()=>{l(O),c(L.title)},className:`px-3 py-1 rounded-full text-xs font-bold transition-all cursor-pointer flex items-center gap-1 border ${F?"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:L.title})}),e.jsx("button",{onClick:B=>{B.stopPropagation(),b(j===O?null:O)},className:`p-0.5 rounded-full hover:bg-black/10 transition-colors ml-[-4px] z-10 ${F?"text-white/80 hover:text-white":"text-muted hover:text-main"}`,title:"页面选项",children:e.jsx(ia,{size:12})}),j===O&&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:B=>B.stopPropagation(),children:[e.jsxs("button",{onClick:()=>{l(O),c(L.title),b(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(sn,{size:13})," 重命名"]}),e.jsxs("button",{onClick:()=>{z(O),b(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(nn,{size:13})," 复制页面"]}),W>0&&e.jsxs("button",{onClick:()=>{x(O,"left"),b(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(Lr,{size:13})," 向左移动"]}),W<v.length-1&&e.jsxs("button",{onClick:()=>{x(O,"right"),b(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(Wr,{size:13})," 向右移动"]}),e.jsx("div",{className:"my-1 border-t border-theme"}),e.jsxs("button",{onClick:()=>{p(O),b(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(jt,{size:13})," 删除页面"]})]})]},L.id||O)})}),e.jsx("button",{onClick:()=>g(),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:()=>{E>=0&&E<v.length-1&&M(v[E+1].globalIdx)},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:E===-1||E>=v.length-1,title:"下一页",children:e.jsx(Wr,{size:16})}),e.jsx("div",{className:"empty:hidden flex items-center gap-1 ml-0.5 pl-1 border-l border-theme",children:e.jsx(ze,{slot:"whiteboard.pagebar.action",slotProps:{pages:t,currentPage:r,activeSegmentId:o,onSwitchPage:M}})})]}),i&&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:()=>n(!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:L=>L.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(Gr,{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:["共 ",v.length," 页"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"empty:hidden flex items-center gap-1.5",children:e.jsx(ze,{slot:"whiteboard.page_drawer.action",slotProps:{pages:t,currentPage:r,activeSegmentId:o,onCloseDrawer:()=>n(!1)}})}),e.jsxs("button",{onClick:()=>g(),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:()=>n(!1),className:"p-1.5 hover:bg-surface-secondary rounded-full text-muted hover:text-main transition-colors cursor-pointer",children:e.jsx(Jt,{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:v.map(({page:L,globalIdx:O},W)=>{const F=O===r,de=$.filter(B=>B.type!=="page_meta"&&(()=>{try{const ne=JSON.parse(B.data);return o&&ne.segmentId&&ne.segmentId!==o?!1:(ne.page??0)===O||ne.pageId===L.id}catch{return O===0}})()).length;return e.jsxs("div",{onClick:()=>{M(O),n(!1)},className:`relative flex flex-col p-3 rounded-xl border-2 transition-all cursor-pointer group bg-surface ${F?"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 ${F?"bg-primary-theme text-white":"bg-surface-secondary text-muted"}`,children:["P",W+1]}),F&&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(os,{size:24,className:F?"text-primary-theme":"text-subtle"}),e.jsxs("span",{className:"text-xs text-muted font-medium mt-1",children:[de," 个组件/笔画"]})]}),e.jsx("div",{className:"font-bold text-xs text-main truncate mb-1",title:L.title,children:L.title}),e.jsxs("div",{className:"flex items-center justify-between pt-2 border-t border-theme text-muted text-xs",onClick:B=>B.stopPropagation(),children:[e.jsx("button",{onClick:()=>{l(O),c(L.title)},className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"重命名",children:e.jsx(sn,{size:13})}),e.jsx("button",{onClick:()=>z(O),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"复制页面",children:e.jsx(nn,{size:13})}),W>0&&e.jsx("button",{onClick:()=>x(O,"left"),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"向左移",children:e.jsx(Lr,{size:13})}),W<v.length-1&&e.jsx("button",{onClick:()=>x(O,"right"),className:"hover:text-primary-theme p-1 rounded hover:bg-surface-secondary transition-colors",title:"向右移",children:e.jsx(Wr,{size:13})}),e.jsx("button",{onClick:()=>p(O),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(jt,{size:13})})]})]},L.id||O)})})]})})]})},co=({dialog:t,dialogInput:r,setDialogInput:o,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:n=>o(n.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:n=>n.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(n){console.error("Dialog action error:",n)}},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,Or=[{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}],Xr=[{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 uo(t){if(!Number.isFinite(t)||t<=0)return"0 B";const r=["B","KB","MB","GB"],o=Math.min(r.length-1,Math.floor(Math.log(t)/Math.log(1024)));return`${(t/1024**o).toFixed(o===0?0:1)} ${r[o]}`}function Yr(t){if(!t)return"—";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return"—"}}function hn(t,r,o){const i=String.fromCharCode(65+t%26);return o?`${r?"匿名同学":"待评同学"} ${i}`:`${r?"Anonymous":"Peer"} ${i}`}function ho({assignmentId:t,tasks:r,onSubmitted:o,onToast:i,lang:n="zh"}){const d=n==="zh",[l,u]=a.useState(null),[c,j]=a.useState({}),[b,$]=a.useState(""),[M,N]=a.useState(""),[z,x]=a.useState(!1),[p,g]=a.useState(null),[v,E]=a.useState(null),[L,O]=a.useState(null),W=Math.max(0,r.findIndex(S=>S.taskId===l)),F=r[W],de=a.useCallback((S,D,G)=>{if(i){i(S,D,G);return}E(D?`${S}:${D}`:S)},[i]);a.useEffect(()=>{const S=r[W];S&&($(S.review?String(S.review.score):""),N(S.review?.comment||""),j({}),g(null),E(null))},[W,r]);const B=a.useMemo(()=>{if(Or.filter(G=>c[G.key]).length===0)return null;const D=Or.reduce((G,ie)=>{const V=Xr.find(H=>H.key===c[ie.key]);return G+ie.weight*(V?.factor??Xr[1].factor)},0);return Math.round(D)},[c]),ne=b.trim()===""?B:Math.round(Number(b)),A=F?.dueAt!==null&&F?.dueAt!==void 0&&Date.now()>Number(F.dueAt),ee=r.filter(S=>S.review).length,J=(S,D)=>{j(G=>{const ie={...G};return ie[S]===D?delete ie[S]:ie[S]=D,ie}),$("")},C=a.useCallback(async()=>{if(z||!F||A)return;const S=ne;if(S===null||!Number.isFinite(S)||S<0||S>100){g(d?"请给出 0-100 的互评分数":"Score must be between 0 and 100");return}if(!F.submissionId){g(d?"该互评任务缺少提交物信息,请刷新后重试":"Missing submission for this task");return}x(!0),g(null);try{const D=await fetch(`/api/assignments/${encodeURIComponent(t)}/peer-review`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({submissionId:F.submissionId,score:S,comment:M.trim(),taskId:F.taskId})}),G=await D.json().catch(()=>null);if(!D.ok||G?.success===!1)throw new Error(G?.error||`HTTP ${D.status}`);de(F.review?d?"互评已更新":"Review updated":d?"互评已提交":"Review submitted",d?`已给 ${hn(W,F.anonymous,d)} 打 ${S} 分`:"","success"),await o?.()}catch(D){g(D?.message||(d?"提交失败":"submit failed"))}finally{x(!1)}},[W,F,t,M,A,de,o,ne,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(Ur,{size:13}),d?"老师还没有给你分配互评任务。":"No peer review task assigned yet."]});const _=F?.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(Ur,{size:13})," ",d?"互评任务":"Peer review",e.jsx("span",{className:"font-normal text-muted",children:d?`已完成 ${ee} / ${r.length}`:`${ee} / ${r.length} done`})]}),F?.dueAt?e.jsxs("span",{className:`text-[11px] ${A?"text-red-600":"text-muted"}`,children:[d?"互评截止":"Due"," ",Yr(F.dueAt),A?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((S,D)=>{const G=D===W;return e.jsxs("button",{type:"button",onClick:()=>u(S.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 ${G?"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(D,S.anonymous,d)}),S.review?e.jsxs("span",{className:"inline-flex items-center gap-1 text-emerald-600 shrink-0",children:[e.jsx(It,{size:11})," ",S.review.score]}):e.jsx("span",{className:"text-[11px] text-amber-600 shrink-0",children:d?"待评":"todo"})]},S.taskId)})}),e.jsxs("div",{className:"rounded-xl border border-theme bg-surface p-3 space-y-3",children:[F?.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(is,{size:12,className:"mt-0.5 shrink-0"}),d?"该作者在你评价后又更新了提交,建议复核后再提交一次。":"The author resubmitted after your review."]}),_?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?`第 ${_.version} 版`:`v${_.version}`}),e.jsx("span",{children:Yr(_.submittedAt)}),_.isLate&&e.jsx("span",{className:"text-amber-600",children:d?"迟交":"late"})]}),_.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:_.textContent}):e.jsx("div",{className:"text-[11px] text-muted",children:d?"该同学没有留下文本作答。":"No text answer."}),(()=>{const S=Bi(_.linkUrl);return S?e.jsxs("a",{href:S,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1 text-xs text-orange-600 hover:underline break-all",children:[e.jsx(aa,{size:11})," ",_.linkUrl]}):null})(),_.files.length>0&&e.jsx("div",{className:"space-y-1",children:_.files.map(S=>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:()=>O({id:S.id,original_name:S.original_name,size:S.size,mime:S.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(Vr,{size:12,className:"shrink-0"}),e.jsx("span",{className:"truncate",children:S.original_name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:uo(S.size)})]}),e.jsx("a",{href:`/api/assignments/${encodeURIComponent(t)}/files/${encodeURIComponent(S.id)}`,target:"_blank",rel:"noreferrer",className:"shrink-0 text-muted hover:text-orange-600",title:d?"下载":"Download",children:e.jsx(oa,{size:12})})]},S.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"}),Or.map(S=>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?S.zh:S.en,e.jsxs("span",{className:"ml-1 text-[10px]",children:["(",S.weight,")"]})]}),Xr.map(D=>{const G=c[S.key]===D.key;return e.jsx("button",{type:"button",disabled:A,onClick:()=>J(S.key,D.key),className:`px-1.5 py-0.5 rounded border text-[11px] transition-colors disabled:opacity-50 ${G?"border-orange-300 bg-orange-50 text-main":"border-theme text-muted hover:bg-surface-secondary"}`,children:d?D.zh:D.en},D.key)})]},S.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:b,disabled:A,placeholder:B===null?"":String(B),onChange:S=>{$(S.target.value),j({})},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"})]}),B!==null&&b.trim()===""&&e.jsx("span",{className:"text-[11px] text-muted",children:d?`量规建议 ${B} 分`:`Rubric suggests ${B}`})]}),e.jsx("textarea",{value:M,disabled:A,onChange:S=>N(S.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"}),p&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:p}),v&&e.jsx("div",{className:"text-[11px] text-emerald-600 break-all",children:v}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-[11px] text-muted",children:F?.review?d?`已评 ${F.review.score} 分 · ${Yr(F.review.submittedAt)}`:`Reviewed ${F.review.score}`:d?"同学之间双盲互评,作者看不到是谁评的":"Double-blind review"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{type:"button",disabled:z||A,onClick:()=>{$(F?.review?String(F.review.score):""),N(F?.review?.comment||""),j({}),g(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($t,{size:11})," ",d?"重填":"Reset"]}),e.jsxs("button",{type:"button",disabled:z||A,onClick:()=>void C(),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(it,{size:12,className:"animate-spin"}):null,A?d?"互评已截止":"Closed":F?.review?d?"更新互评":"Update":d?"提交互评":"Submit"]})]})]})]})]}),L&&e.jsx(An,{assignmentId:t,file:L,lang:n,onClose:()=>O(null)})]})}const xo=".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",qr=50*1024*1024;function or(t){if(!Number.isFinite(t)||t<=0)return"0 B";const r=["B","KB","MB","GB"],o=Math.min(r.length-1,Math.floor(Math.log(t)/Math.log(1024)));return`${(t/1024**o).toFixed(o===0?0:1)} ${r[o]}`}function xn(t){if(!t)return"—";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return"—"}}function mo(t){try{const r=typeof t?.files_json=="string"?JSON.parse(t.files_json):t?.files_json;return Array.isArray(r)?r.filter(o=>o&&typeof o.fileId=="string").map(o=>({fileId:String(o.fileId),name:String(o.name??o.fileId),size:Number(o.size??0)})):[]}catch{return[]}}function po({assignmentId:t,onClose:r,onToast:o,lang:i="zh"}){const n=i==="zh",[d,l]=a.useState(!0),[u,c]=a.useState(null),[j,b]=a.useState(null),[$,M]=a.useState([]),[N,z]=a.useState([]),[x,p]=a.useState(""),[g,v]=a.useState(""),[E,L]=a.useState(!1),[O,W]=a.useState(null),[F,de]=a.useState(null),[B,ne]=a.useState(!1),[A,ee]=a.useState("submit"),[J,C]=a.useState(null),[_,S]=a.useState(null),D=a.useRef(new Map),G=a.useRef(new Map),ie=a.useRef(null),V=a.useCallback((R,Q,pe)=>{if(o){o(R,Q,pe);return}C({text:Q?`${R}:${Q}`:R,type:pe==="error"?"warning":pe})},[o]),H=a.useCallback((R,Q)=>{z(pe=>pe.map(ue=>ue.key===R?{...ue,...Q}:ue))},[]),Y=a.useCallback(async(R=!1)=>{R||l(!0),c(null);try{const[Q,pe]=await Promise.all([fetch(`/api/assignments/${encodeURIComponent(t)}`),fetch(`/api/assignments/${encodeURIComponent(t)}/files`)]),ue=await Q.json().catch(()=>null);if(!Q.ok||ue?.success===!1)throw new Error(ue?.error||`HTTP ${Q.status}`);b(ue);const fe=await pe.json().catch(()=>null),Ie=Array.isArray(fe?.files)?fe.files:[];M(Ie.filter(ut=>!ut.version_id))}catch(Q){c(Q?.message||"load failed")}finally{R||l(!1)}},[t]);a.useEffect(()=>{Y()},[Y]),a.useEffect(()=>{const R=G.current;return()=>{R.forEach(Q=>{try{Q.abort()}catch{}}),R.clear()}},[]);const m=a.useCallback(R=>new Promise(Q=>{const pe=D.current.get(R);if(!pe){H(R,{status:"error",error:n?"文件已失效,请重新选择":"file expired"}),Q();return}const ue=new XMLHttpRequest;G.current.set(R,ue),ue.open("POST",`/api/assignments/${encodeURIComponent(t)}/files`,!0),ue.setRequestHeader("X-File-Name",encodeURIComponent(pe.name)),ue.setRequestHeader("Content-Type","application/octet-stream"),ue.upload.onprogress=fe=>{fe.lengthComputable&&H(R,{progress:Math.round(fe.loaded/fe.total*100)})},ue.onload=()=>{G.current.delete(R);let fe=null;try{fe=JSON.parse(ue.responseText||"{}")}catch{fe=null}ue.status>=200&&ue.status<300&&fe?.success!==!1&&fe?.file?.id?(H(R,{status:"done",progress:100,fileId:fe.file.id}),M(Ie=>[{id:fe.file.id,original_name:fe.file.name??pe.name,size:fe.file.size??pe.size,uploaded_at:Date.now()},...Ie])):H(R,{status:"error",error:fe?.error||`HTTP ${ue.status}`}),Q()},ue.onerror=()=>{G.current.delete(R),H(R,{status:"error",error:n?"网络错误":"network error"}),Q()},ue.onabort=()=>{G.current.delete(R),Q()},H(R,{status:"uploading",progress:0,error:void 0}),ue.send(pe)}),[t,H,n]),w=a.useCallback(R=>{if(!R.length)return;const Q=Date.now(),pe=[],ue=[];R.forEach((fe,Ie)=>{if(fe.size<=0){ue.push(`${fe.name}(${n?"空文件":"empty"})`);return}if(fe.size>qr){ue.push(`${fe.name}(${n?"超过":"over"} ${or(qr)})`);return}const ut=`${Q}-${Ie}-${fe.name}`;D.current.set(ut,fe),pe.push({key:ut,name:fe.name,size:fe.size,status:"queued",progress:0})}),ue.length&&V(n?"部分文件未加入":"Some files skipped",ue.join("、"),"warning"),pe.length&&(z(fe=>[...fe,...pe]),(async()=>{for(const fe of pe)await m(fe.key)})())},[V,m,n]),y=a.useCallback(R=>{m(R)},[m]),k=a.useCallback(R=>{try{G.current.get(R)?.abort()}catch{}D.current.delete(R),z(Q=>Q.filter(pe=>pe.key!==R))},[]),K=a.useCallback(async R=>{try{const Q=await fetch(`/api/assignments/${encodeURIComponent(t)}/files/${R}`,{method:"DELETE"}),pe=await Q.json().catch(()=>null);if(!Q.ok||pe?.success===!1){V(n?"删除失败":"Delete failed",pe?.error||`HTTP ${Q.status}`,"error");return}M(ue=>ue.filter(fe=>fe.id!==R))}catch(Q){V(n?"删除失败":"Delete failed",Q?.message||"","error")}},[t,V,n]),Z=a.useMemo(()=>{const R=$.map(ue=>ue.id),Q=new Set(R),pe=[];for(const ue of N)ue.status!=="done"||!ue.fileId||Q.has(ue.fileId)||(Q.add(ue.fileId),pe.push(ue.fileId));return[...R,...pe]},[$,N]),ce=N.some(R=>R.status==="uploading"),$e=Z.length>0||x.trim().length>0||g.trim().length>0,ye=a.useCallback(async()=>{if(!(E||ce)){L(!0),W(null);try{const R=await fetch(`/api/assignments/${encodeURIComponent(t)}/submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({fileIds:Z,textContent:x.trim()||void 0,linkUrl:g.trim()||void 0})}),Q=await R.json().catch(()=>null);if(!R.ok||Q?.success===!1)throw new Error(Q?.error||`HTTP ${R.status}`);de(Number(Q?.version)||1),z([]),D.current.clear(),p(""),V(n?"提交成功":"Submitted",n?`已生成第 ${Q?.version??1} 版提交`:"","success"),await Y(!0)}catch(R){W(R?.message||"submit failed")}finally{L(!1)}}},[t,Z,Y,V,E,x,ce,n]),he=j?.assignment,Ee=Array.isArray(j?.versions)?j.versions:[],ve=j?.grade,re=j?.stats,we=Array.isArray(j?.peerReviewTasks)?j.peerReviewTasks:[],Me=we.filter(R=>!R.review||R.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:R=>R.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(la,{size:14,className:"text-orange-600 shrink-0"}),e.jsx("h3",{className:"font-bold text-main text-sm truncate",children:he?.title||(n?"课堂作业":"Assignment")})]}),he&&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:he.status==="published"?n?"已发布":"published":he.status}),he.due_at?e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(ca,{size:10})," ",n?"截止":"Due"," ",xn(he.due_at)]}):null,he.allow_late?e.jsx("span",{children:n?"允许迟交":"late allowed"}):null,re?e.jsx("span",{children:n?`已提交 ${re.submissionCount}`:`${re.submissionCount} submitted`}):null]})]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[e.jsx("button",{onClick:()=>void Y(!0),className:"p-1.5 rounded-lg text-muted hover:text-main hover:bg-surface-secondary transition-colors",title:n?"刷新":"Refresh",children:e.jsx($t,{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:n?"关闭":"Close",children:e.jsx(Jt,{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:()=>ee("submit"),className:`px-2.5 py-1.5 text-xs rounded-t-lg border-b-2 transition-colors ${A==="submit"?"border-orange-500 text-main font-medium":"border-transparent text-muted hover:text-main"}`,children:n?"我的提交":"My submission"}),we.length>0&&e.jsxs("button",{type:"button",onClick:()=>ee("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 ${A==="peer"?"border-orange-500 text-main font-medium":"border-transparent text-muted hover:text-main"}`,children:[n?"互评任务":"Peer review",e.jsx("span",{className:"text-[11px]",children:Me>0?`${we.length-Me}/${we.length}`:we.length}),Me>0&&e.jsx("span",{className:"px-1 rounded-full bg-amber-100 text-amber-700 text-[10px]",children:n?`待评 ${Me}`:`${Me} 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(it,{size:14,className:"animate-spin"})," ",n?"加载中…":"Loading…"]}):u?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(At,{size:14,className:"mt-0.5 shrink-0"}),e.jsxs("div",{children:[e.jsx("div",{className:"font-semibold",children:n?"无法加载作业":"Failed to load assignment"}),e.jsx("div",{className:"mt-0.5 break-all",children:u})]})]}):A==="peer"?e.jsx(ho,{assignmentId:t,tasks:we,onSubmitted:()=>Y(!0),onToast:o,lang:i}):e.jsxs(e.Fragment,{children:[he?.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:he.description}):null,ve?e.jsxs("div",{className:"rounded-xl border border-theme px-3 py-2 text-xs flex items-center gap-2",children:[e.jsx(da,{size:14,className:"text-amber-500 shrink-0"}),ve.status==="confirmed"?e.jsxs("span",{className:"text-main",children:[n?"最终成绩":"Final score",":",e.jsx("span",{className:"font-bold text-amber-600 ml-1",children:ve.calculated_final_score})]}):e.jsx("span",{className:"text-muted",children:n?"成绩待教师确认":"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:n?"作业文件":"Files"}),e.jsxs("span",{className:"text-[11px] text-muted",children:[n?"单个不超过":"max"," ",or(qr)]})]}),e.jsxs("div",{onDragOver:R=>{R.preventDefault(),ne(!0)},onDragLeave:()=>ne(!1),onDrop:R=>{R.preventDefault(),ne(!1);const Q=Array.from(R.dataTransfer?.files||[]);Q.length&&w(Q)},onClick:()=>ie.current?.click(),className:`rounded-xl border-2 border-dashed px-3 py-4 text-center cursor-pointer transition-colors ${B?"border-orange-400 bg-orange-50":"border-theme hover:border-orange-300"}`,children:[e.jsx(Kr,{size:16,className:"mx-auto text-muted"}),e.jsx("div",{className:"mt-1 text-xs text-main font-medium",children:n?"点击选择文件,或拖拽到此处":"Click to choose files, or drop them here"}),e.jsx("div",{className:"text-[11px] text-muted mt-0.5",children:n?"支持文档、图片、压缩包与常见代码文件":"documents, images, archives, source files"}),e.jsx("input",{ref:ie,type:"file",multiple:!0,accept:xo,className:"hidden",onChange:R=>{const Q=Array.from(R.target.files||[]);Q.length&&w(Q),R.target.value=""}})]}),$.length>0&&e.jsx("ul",{className:"mt-2 space-y-1",children:$.map(R=>e.jsxs("li",{className:"flex items-center gap-2 rounded-lg border border-theme px-2 py-1.5 text-xs",children:[e.jsx(os,{size:12,className:"text-muted shrink-0"}),e.jsx("span",{className:"flex-1 truncate text-main",children:R.original_name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:or(R.size)}),e.jsx("button",{onClick:()=>S({id:R.id,original_name:R.original_name,size:R.size}),className:"p-1 rounded text-muted hover:text-primary-theme hover:bg-surface-secondary",title:n?"预览":"Preview","aria-label":n?`预览 ${R.original_name}`:`Preview ${R.original_name}`,"data-testid":"assignment-pending-file-preview",children:e.jsx(Vr,{size:12})}),e.jsx("button",{onClick:()=>void K(R.id),className:"p-1 rounded text-orange-600 hover:text-red-500 hover:bg-surface-secondary",title:n?"移除":"Remove",children:e.jsx(jt,{size:12})})]},R.id))}),N.length>0&&e.jsx("ul",{className:"mt-2 space-y-1",children:N.map(R=>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:[R.status==="done"?e.jsx(It,{size:12,className:"text-emerald-600 shrink-0"}):R.status==="error"?e.jsx(At,{size:12,className:"text-red-500 shrink-0"}):e.jsx(it,{size:12,className:"animate-spin text-muted shrink-0"}),e.jsx("span",{className:"flex-1 truncate text-main",children:R.name}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:or(R.size)}),R.status==="error"&&e.jsx("button",{onClick:()=>y(R.key),className:"p-1 rounded text-primary-theme hover:bg-surface-secondary",title:n?"重试":"Retry",children:e.jsx($t,{size:12})}),e.jsx("button",{onClick:()=>k(R.key),className:"p-1 rounded text-muted hover:text-main hover:bg-surface-secondary",title:n?"从列表移除":"Remove from list",children:e.jsx(Jt,{size:12})})]}),R.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:`${R.progress}%`}})}),R.status==="error"&&R.error?e.jsx("div",{className:"mt-0.5 text-[11px] text-red-600 break-all",children:R.error}):null]},R.key))})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"assignment-submit-text",className:"block text-xs font-semibold text-main mb-1",children:n?"文字作答(可选)":"Text answer (optional)"}),e.jsx("textarea",{id:"assignment-submit-text",name:"text_content",value:x,onChange:R=>p(R.target.value),className:"w-full min-h-20 p-2 border border-theme rounded-lg text-xs bg-surface text-main field-sizing-auto focus:outline-none focus:ring-1 focus:ring-orange-400",placeholder:n?"可直接粘贴代码或说明…":"Paste code or notes…"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"assignment-submit-link",className:"block text-xs font-semibold text-main mb-1",children:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(_n,{size:11})," ",n?"作品链接(可选)":"Link (optional)"]})}),e.jsx("input",{id:"assignment-submit-link",name:"link_url",type:"url",spellCheck:!1,autoCapitalize:"none",value:g,onChange:R=>v(R.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://"})]})]}),Ee.length>0&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-semibold text-main mb-1.5",children:n?`提交历史(共 ${Ee.length} 版)`:`Submission history (${Ee.length})`}),e.jsx("ul",{className:"space-y-1",children:Ee.map(R=>{const Q=mo(R);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",R.version]}),e.jsx("span",{className:"flex-1 truncate text-muted",children:R.text_content||R.link_url||"—"}),Q.length>0&&e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:n?`${Q.length} 个附件`:`${Q.length} file(s)`}),e.jsx("span",{className:"text-[11px] text-muted shrink-0",children:xn(R.created_at||R.submitted_at)})]}),Q.length>0&&e.jsx("ul",{className:"mt-1 flex flex-wrap gap-1",children:Q.map(pe=>e.jsx("li",{children:e.jsxs("button",{onClick:()=>S({id:pe.fileId,original_name:pe.name,size:pe.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:n?"预览":"Preview","data-testid":"assignment-version-file-preview",children:[e.jsx(Vr,{size:11,className:"shrink-0"}),e.jsx("span",{className:"max-w-[160px] truncate",children:pe.name})]})},pe.fileId))})]},R.id)})})]}),F!==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(It,{size:14,className:"shrink-0"}),n?`已提交第 ${F} 版`:`Version ${F} submitted`]}),O&&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(At,{size:14,className:"mt-0.5 shrink-0"}),e.jsx("span",{className:"break-all",children:O})]})]})}),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:J?e.jsx("span",{className:J.type==="warning"?"text-amber-700":"text-emerald-700",children:J.text}):n?`本次将提交 ${Z.length} 个附件${x.trim()?" + 文本":""}${g.trim()?" + 链接":""}`:`${Z.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:n?"关闭":"Close"}),e.jsxs("button",{onClick:()=>void ye(),disabled:E||ce||!$e,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:[E?e.jsx(it,{size:12,className:"animate-spin"}):e.jsx(Kr,{size:12}),E?n?"提交中…":"Submitting…":n?"提交作业":"Submit"]})]})]})]}),_&&e.jsx(An,{assignmentId:t,file:_,lang:i,onClose:()=>S(null)})]})}function fo(t){if(!t)return"";const r=t<1e12?t*1e3:t;try{return new Date(r).toLocaleString()}catch{return""}}function bo({lessonId:t,classId:r,elementId:o,value:i,draftTitle:n,draftDescription:d,disabled:l,onChange:u,onToast:c,lang:j="zh"}){const b=j==="zh",[$,M]=a.useState(!1),[N,z]=a.useState([]),[x,p]=a.useState(null),[g,v]=a.useState(null),[E,L]=a.useState(!1),[O,W]=a.useState(null),F=a.useCallback((J,C,_)=>{if(c){c(J,C,_);return}W({text:C?`${J}:${C}`:J,type:_})},[c]),de=a.useCallback(async(J=!1)=>{if(t){J||M(!0),v(null);try{const C=await fetch(`/api/assignments?lessonId=${encodeURIComponent(t)}`),_=await C.json().catch(()=>null);if(!C.ok||_?.success===!1)throw new Error(_?.error||`HTTP ${C.status}`);z(Array.isArray(_?.assignments)?_.assignments:[])}catch(C){v(C?.message||"load failed")}finally{J||M(!1)}}},[t]),B=a.useCallback(async()=>{if(!i){p(null);return}try{const J=await fetch(`/api/assignments/${encodeURIComponent(i)}`),C=await J.json().catch(()=>null);J.ok&&C?.success!==!1&&p(C.assignment||null)}catch{}},[i]);a.useEffect(()=>{de()},[de]),a.useEffect(()=>{B()},[B]);const ne=a.useCallback(async()=>{if(!(E||!t)){L(!0);try{const J=await fetch("/api/assignments",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({title:n?.trim()||(b?"课堂作业":"Class assignment"),description:d?.trim()||"",lessonId:t,classId:r||void 0,elementId:o||void 0,status:"published"})}),C=await J.json().catch(()=>null);if(!J.ok||C?.success===!1)throw new Error(C?.error||`HTTP ${J.status}`);const _=C?.assignment||C?.result?.assignment,S=_?.id||C?.assignmentId||C?.result?.assignmentId||C?.id;if(!S)throw new Error(b?"服务端未返回作业 ID":"no assignment id returned");p(_||{id:S,title:n,status:"published"}),await de(!0),u(String(S),_),F(b?"已创建并绑定作业":"Assignment created",b?"学生端可以开始提交了":"","success")}catch(J){F(b?"创建作业失败":"Create failed",J?.message||"","error")}finally{L(!1)}}},[r,E,d,n,o,t,de,F,u,b]),A=a.useCallback(J=>{if(!J){u(null),p(null);return}const C=N.find(_=>String(_.id)===J);p(C||null),u(J,C)},[u,N]),ee=x?.title||N.find(J=>String(J.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(_n,{size:11})," ",b?"绑定作业中心":"Assignment binding"]}),e.jsx("button",{type:"button",onClick:()=>void de(!0),disabled:$,className:"p-1 rounded text-muted hover:text-main hover:bg-surface transition-colors",title:b?"刷新":"Refresh",children:$?e.jsx(it,{size:11,className:"animate-spin"}):e.jsx($t,{size:11})})]}),i&&ee?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(It,{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:ee}),e.jsx("div",{className:"text-[11px] text-muted truncate",children:[x?.status,x?.due_at?`${b?"截止":"due"} ${fo(x.due_at)}`:""].filter(Boolean).join(" · ")})]}),e.jsx("button",{type:"button",disabled:l,onClick:()=>A(""),className:"p-1 rounded text-muted hover:text-red-500 hover:bg-surface transition-colors shrink-0",title:b?"解除绑定":"Unbind",children:e.jsx(ua,{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(At,{size:12,className:"mt-0.5 text-amber-600 shrink-0"}),e.jsx("span",{className:"text-[11px] text-amber-800",children:b?"尚未绑定作业:学生端只能看到提示、无法提交。请选择已有作业或直接新建。":"Not bound yet — students cannot submit."})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:i||"",disabled:l,onChange:J=>A(J.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:b?"— 选择本课时的作业 —":"— select assignment —"}),N.map(J=>e.jsxs("option",{value:J.id,children:[J.title||J.id,J.status?` (${J.status})`:""]},J.id))]}),e.jsxs("button",{type:"button",disabled:l||E||!t,onClick:()=>void ne(),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:[E?e.jsx(it,{size:11,className:"animate-spin"}):e.jsx(qt,{size:11}),b?"新建":"New"]})]}),g&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:g}),O&&e.jsx("div",{className:`text-[11px] break-all ${O.type==="success"?"text-emerald-600":O.type==="error"?"text-red-600":"text-amber-700"}`,children:O.text}),N.length===0&&!$&&!g&&e.jsx("div",{className:"text-[11px] text-muted",children:b?"本课时还没有作业,点「新建」即可。":"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 go(){const t=new Date(Date.now()+2592e5),r=o=>String(o).padStart(2,"0");return`${t.getFullYear()}-${r(t.getMonth()+1)}-${r(t.getDate())}T${r(t.getHours())}:${r(t.getMinutes())}`}function yo({assignmentId:t,progress:r,onAssigned:o,onToast:i,lang:n="zh"}){const d=n==="zh",[l,u]=a.useState(!1),[c,j]=a.useState(r||null),[b,$]=a.useState(!1),[M,N]=a.useState(!1),[z,x]=a.useState("2"),[p,g]=a.useState(""),[v,E]=a.useState(null),[L,O]=a.useState(null),W=a.useCallback((A,ee,J)=>{if(i){i(A,ee,J);return}O(ee?`${A}:${ee}`:A)},[i]),F=a.useCallback(async()=>{if(r){j(r);return}$(!0),E(null);try{const A=await fetch(`/api/assignments/${encodeURIComponent(t)}`),ee=await A.json().catch(()=>null);if(!A.ok||ee?.success===!1)throw new Error(ee?.error||`HTTP ${A.status}`);j(ee?.peerProgress||null)}catch(A){E(A?.message||"load failed")}finally{$(!1)}},[t,r]);a.useEffect(()=>{F()},[F]);const de=a.useCallback(async()=>{if(!M){N(!0),E(null);try{const A=Math.max(1,Math.min(10,Math.round(Number(z)||2))),ee=p?new Date(p).getTime():void 0,J=await fetch(`/api/assignments/${encodeURIComponent(t)}/assign-peer-reviews`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({reviewerCount:A,dueAt:ee&&Number.isFinite(ee)?ee:void 0})}),C=await J.json().catch(()=>null);if(!J.ok||C?.success===!1)throw new Error(C?.error||`HTTP ${J.status}`);W(d?"互评已分配":"Peer reviews assigned",d?`新增 ${C?.created??0} 个互评任务,覆盖 ${C?.submissions??0} 份提交(重复分配不会重复建任务)`:"","success"),u(!0),await F(),await o?.()}catch(A){W(d?"分配互评失败":"Assign failed",A?.message||"","error")}finally{N(!1)}}},[t,M,p,F,W,o,z,d]),B=(c?.reviewers||[]).filter(A=>A.pending>0),ne=c?.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(Ur,{size:11})," ",d?"互评进度":"Peer review",c?e.jsx("span",{className:"font-normal text-muted",children:d?`${c.completed} / ${c.tasks} 已完成`:`${c.completed} / ${c.tasks} done`}):null,ne>0?e.jsx("span",{className:"px-1 rounded-full bg-amber-100 text-amber-700 text-[10px]",children:d?`${ne} 项待复核`:`${ne} flags`}):null]}),e.jsxs("div",{className:"flex items-center gap-1 shrink-0",children:[e.jsx("button",{type:"button",onClick:()=>void F(),disabled:b,className:"p-1 rounded text-muted hover:text-main hover:bg-surface transition-colors",title:d?"刷新":"Refresh",children:b?e.jsx(it,{size:11,className:"animate-spin"}):e.jsx($t,{size:11})}),e.jsx("button",{type:"button",onClick:()=>u(A=>!A),className:"px-1.5 py-0.5 rounded text-[11px] text-muted hover:text-main hover:bg-surface transition-colors",children:l?d?"收起":"Hide":d?"展开":"Show"})]})]}),c?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?`提交 ${c.submissions}`:`${c.submissions} subs`}),e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface border border-theme",children:d?`任务 ${c.tasks}`:`${c.tasks} tasks`}),e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-surface border border-theme",children:d?`待完成 ${c.pending}`:`${c.pending} pending`})]}):e.jsx("div",{className:"text-[11px] text-muted",children:d?"暂无互评数据。":"No peer review data."}),c&&c.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:A=>x(A.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:p,placeholder:go(),onChange:A=>g(A.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:M,onClick:()=>void de(),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:[M?e.jsx(it,{size:11,className:"animate-spin"}):e.jsx(Jr,{size:11}),d?"随机分配互评":"Assign"]})]}),v&&e.jsx("div",{className:"text-[11px] text-red-600 break-all",children:v}),L&&e.jsx("div",{className:"text-[11px] text-emerald-600 break-all",children:L}),l&&c&&e.jsxs("div",{className:"space-y-2",children:[c.flags.length>0?e.jsx("div",{className:"space-y-1",children:c.flags.map((A,ee)=>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(is,{size:11,className:"mt-0.5 shrink-0"}),e.jsxs("span",{className:"break-all",children:[e.jsx("span",{className:"font-medium",children:d?mn[A.type]?.zh||A.type:mn[A.type]?.en||A.type}),":",A.detail]})]},`${A.type}-${A.reviewerId||ee}-${ee}`))}):e.jsxs("div",{className:"text-[11px] text-emerald-600 inline-flex items-center gap-1",children:[e.jsx(It,{size:11})," ",d?"暂未发现异常,互评进度正常。":"No anomaly detected."]}),c.reviewers.length>0&&e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-[11px] font-medium text-main",children:d?`互评人(${B.length} 人还有待评)`:"Reviewers"}),e.jsx("div",{className:"max-h-40 overflow-y-auto space-y-0.5",children:c.reviewers.map(A=>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:A.name}),e.jsx("span",{className:A.pending>0?"text-amber-700 shrink-0":"text-emerald-600 shrink-0",children:d?`已评 ${A.submitted} · 待评 ${A.pending}`:`${A.submitted} done · ${A.pending} todo`})]},A.studentId))})]})]})]})}const wo="ABCDEFGHIJKLMNOPQRSTUVWXYZ";function vo(t){const r=t?.options;return Array.isArray(r)?r.map(o=>typeof o=="string"?o:o==null?"":String(o)):[]}function cr(t,r){if(typeof t=="number")return Number.isInteger(t)&&t>=0&&(r===0||t<r)?t:null;if(typeof t=="string"){const o=t.trim();if(!/^\d+$/.test(o))return null;const i=Number(o);return r===0||i<r?i:null}return null}function Fn(t,r){const o=t.trim().toUpperCase();if(o.length!==1)return null;const i=wo.indexOf(o);return i<0?null:r===0||i<r?i:null}function Ln(t,r){const o=t.trim();if(!o)return null;const i=r.findIndex(l=>l.trim()===o);if(i>=0)return i;const n=o.toLowerCase(),d=r.findIndex(l=>l.trim().toLowerCase()===n);return d>=0?d:null}function Wn(t){if(!t)return null;const r=vo(t),o=cr(t.correctIndex,r.length);if(o!==null)return o;const i=t.correctAnswer;if(i==null)return null;if(typeof i=="number")return cr(i,r.length);const n=String(i);if(!n.trim())return null;const d=Ln(n,r);if(d!==null)return d;const l=Fn(n,r.length);return l!==null?l:cr(n,r.length)}function rs(t,r){if(t!==null&&typeof t=="object"){const n=t,d=rs(n.optionIndex,r);return d!==null?d:rs(n.answer,r)}if(t==null)return null;const o=cr(t,r.length);if(o!==null)return o;if(typeof t!="string"||!t.trim())return null;const i=Fn(t,r.length);return i!==null?i:Ln(t,r)}function jo(t,r){return t===null||t<0||t>=r.length?{correctIndex:null,correctAnswer:null}:{correctIndex:t,correctAnswer:r[t]??null}}const No=["plugin","hello-world","rollcall","quiz","assignment","html-applet","code-sandbox","math-graph","presentation"],ko=({isEditMode:t,selectedShapeId:r,setSelectedShapeId:o,activePropertiesElementId:i,setActivePropertiesElementId:n,safeElements:d,editingProperties:l,handleLocalPropChange:u,handlePropBlur:c,handleNumericPropBlur:j,handlePropsUpdate:b,handleUpdateElementData:$,handleElementDelete:M,handleUndoProp:N,handleRedoProp:z,propertyUndoStack:x,propertyRedoStack:p,isSyncing:g,lessonId:v,classId:E,fullscreenBroadcastClassId:L,coursewares:O,fetchCoursewares:W,setZipCandidates:F,setZipUploadInfo:de,setShowEntrySelector:B,handleAddOption:ne,handleRemoveOption:A,handleOptionChangeLocal:ee,handleOptionBlur:J})=>{const[C,_]=a.useState(null),S=a.useRef(null);if(a.useEffect(()=>()=>{S.current&&clearTimeout(S.current)},[]),!t||!r||!l)return null;const D=d.find(m=>m.id===r);if(!D)return null;const G=async()=>{const m=await $(l),w=m==="saved"||m==="failed"?m:null;w&&(S.current&&clearTimeout(S.current),_(w),S.current=setTimeout(()=>_(null),w==="failed"?5e3:2500))},ie=No.includes(D.type)||dr.has(D.type);if(ie&&i!==r)return null;const V=Array.isArray(l.options)?l.options.map(m=>String(m)):[],H=Wn(l),Y=m=>"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[m]||String(m+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:m=>m.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(ha,{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:N,disabled:(x[r]||[]).length===0,className:`p-1 rounded-lg transition-all flex items-center justify-center gap-1 border border-transparent select-none cursor-pointer ${(x[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(xa,{size:13}),(x[r]||[]).length>0&&e.jsx("span",{className:"text-xs font-bold text-muted",children:(x[r]||[]).length})]}),e.jsxs("button",{onClick:z,disabled:(p[r]||[]).length===0,className:`p-1 rounded-lg transition-all flex items-center justify-center gap-1 border border-transparent select-none cursor-pointer ${(p[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(ma,{size:13}),(p[r]||[]).length>0&&e.jsx("span",{className:"text-xs font-bold text-muted",children:(p[r]||[]).length})]}),e.jsx("div",{className:"h-4 w-px bg-border-theme mx-0.5 shrink-0"}),e.jsx("button",{onClick:()=>{n(null),o(null)},className:"text-muted hover:text-main hover:bg-surface-secondary p-1 rounded-full transition-all cursor-pointer",title:"关闭属性编辑器",children:e.jsx(Jt,{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:D.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:D.id,children:D.id})]})]}),!ie&&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:"尺寸"}),D.type!=="pen"&&D.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(l.width??300),onChange:m=>u("width",parseFloat(m.target.value)||50),onBlur:m=>j("width",m.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(l.height??300),onChange:m=>u("height",parseFloat(m.target.value)||50),onBlur:m=>j("height",m.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"})]})]}),D.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(l.radius??50),onChange:m=>u("radius",parseFloat(m.target.value)||5),onBlur:m=>j("radius",m.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 m=Hi.get(D.type);if(m)return e.jsx(m,{elementId:D.id,elementType:D.type,data:l,updateData:b,lessonId:v,onClose:()=>o(null)});const w=dr.get(D.type);if(w){const y=w.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:[w.labelZh," 配置"]}),e.jsx("span",{className:"text-xs text-muted font-normal",children:"插件扩展"})]}),y.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:l.title||"",onChange:k=>u("title",k.target.value),onBlur:k=>c("title",k.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:"组件标题..."})]}):y.map(k=>{const K=l[k.key]??"";return k.kind==="textarea"?e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:k.labelZh}),e.jsx("textarea",{value:K,onChange:Z=>u(k.key,Z.target.value),onBlur:Z=>c(k.key,Z.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:k.placeholderZh||""})]},k.key):k.kind==="select"?e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:k.labelZh}),e.jsxs("select",{value:K,onChange:Z=>{u(k.key,Z.target.value),c(k.key,Z.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:"请选择..."}),(k.options||[]).map(Z=>e.jsx("option",{value:Z.value,children:Z.label},Z.value))]})]},k.key):e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-muted font-semibold mb-1",children:k.labelZh}),e.jsx("input",{type:"text",value:K,onChange:Z=>u(k.key,Z.target.value),onBlur:Z=>c(k.key,Z.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:k.placeholderZh||""})]},k.key)})]})}return null})(),D.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:l.question||"",onChange:m=>u("question",m.target.value),onBlur:m=>c("question",m.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:"编写问题描述..."})]}),(l.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:H===null?"":String(H),onChange:m=>{const w=m.target.value,y=w===""?null:Number(w);b(jo(y,V))},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 ${H!==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:"-- 请选择正确答案 --"}),V.map((m,w)=>e.jsxs("option",{value:String(w),children:[Y(w),". ",m]},w))]}),H===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:(l.options||[]).map((m,w)=>{const k="ABCDEFGHIJKLMNOPQRSTUVWXYZ"[w]||w+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:k}),e.jsx("input",{type:"text",value:m||"",onChange:K=>ee(w,K.target.value),onBlur:K=>J(w,K.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:()=>A(w),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(jt,{size:13})})]},w)})}),e.jsxs("button",{onClick:ne,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})," 添加选项"]})]})]}),D.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:l.title||"",onChange:m=>u("title",m.target.value),onBlur:m=>c("title",m.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:l.description||"",onChange:m=>u("description",m.target.value),onBlur:m=>c("description",m.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(bo,{lessonId:v,classId:E||L||void 0,elementId:D.id,value:l.assignmentId||"",draftTitle:l.title||"",draftDescription:l.description||"",onChange:m=>{u("assignmentId",m),c("assignmentId",m)}}),l.assignmentId?e.jsx(yo,{assignmentId:String(l.assignmentId)},String(l.assignmentId)):null]}),(D.type==="code-sandbox"||D.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:"动态运行代码定制"}),D.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"})]}),D.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:l.coursewareUuid||"",onChange:m=>{const w=m.target.value;b({coursewareUuid:w,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:"-- 使用自定义沙箱代码 --"}),O.map(m=>e.jsxs("option",{value:m.uuid,children:["📁 [互动课件] ",m.name]},m.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 m=>{const w=m.target.files?.[0];if(!w)return;const y=new FileReader;y.onload=async k=>{const K=k.target?.result;try{const Z=await fetch("/api/courseware/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:w.name.replace(/\.[^/.]+$/,""),filename:w.name,base64Data:K})});if(Z.ok){const ce=await Z.json();ce.need_select_entry?(F(ce.candidates),de({uuid:ce.uuid,name:ce.name}),B(!0)):(b({coursewareUuid:ce.uuid,resourceId:""}),W({force:!0}))}else{const ce=await Z.json();alert("上传失败: "+(ce.error||Z.statusText))}}catch(Z){console.error("Courseware upload failed:",Z)}},y.readAsDataURL(w)}})]})]})]}),(!l.coursewareUuid||D.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:l.code||"",onChange:m=>u("code",m.target.value),onBlur:m=>c("code",m.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:"// 编写交互沙箱代码..."})]})]}),D.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:l.equation||"",onChange:m=>u("equation",m.target.value),onBlur:m=>c("equation",m.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"})," 振幅衰减"]})]})]}),D.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:l.markdown||"",onChange:m=>u("markdown",m.target.value),onBlur:m=>c("markdown",m.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 内容..."})]})]}),D.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:l.text||"",onChange:m=>u("text",m.target.value),onBlur:m=>c("text",m.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:l.fontSize||16,onChange:m=>u("fontSize",parseInt(m.target.value)||10),onBlur:m=>j("fontSize",m.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:l.color||"#000000",onChange:m=>u("color",m.target.value),onBlur:m=>c("color",m.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:l.color||"#000000"})]})]})]}),(D.type==="rectangle"||D.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:l.stroke||"#000000",onChange:m=>u("stroke",m.target.value),onBlur:m=>c("stroke",m.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:l.stroke||"#000000"})]})]})]}),D.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:l.stroke||"#000000",onChange:m=>u("stroke",m.target.value),onBlur:m=>c("stroke",m.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:l.stroke||"#000000"})]})]})]}),D.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:l.color||"#000000",onChange:m=>u("color",m.target.value),onBlur:m=>c("color",m.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:l.color||"#000000"})]})]})]}),D.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:l.color||"#facc15",onChange:m=>u("color",m.target.value),onBlur:m=>c("color",m.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:l.color||"#facc15"})]})]})]}),e.jsx("div",{className:"empty:hidden space-y-3",children:e.jsx(ze,{slot:"whiteboard.properties.addon",slotProps:{elementId:D.id,elementType:D.type,data:l,updateData:b,lessonId:v,isSyncing:g}})}),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:G,disabled:g,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:g?e.jsxs(e.Fragment,{children:[e.jsx(it,{size:13,className:"animate-spin"}),"正在保存..."]}):e.jsxs(e.Fragment,{children:[e.jsx(Rn,{size:13}),"保存"]})}),e.jsxs("div",{role:"status","aria-live":"polite",className:"min-h-[16px] text-center",children:[C==="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(pa,{size:12}),"已保存"]}),C==="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(At,{size:12}),"保存失败,请重试"]})]}),e.jsxs("button",{onClick:()=>{M(r),o(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(jt,{size:13}),"删除当前组件"]})]})]})},Co=({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(Yt,{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,So=24;function zo({elementId:t,type:r,lessonId:o,readOnly:i=!1,dismissible:n=!0,onExit:d,renderContent:l}){a.useEffect(()=>{if(!n)return;const j=b=>{b.key==="Escape"&&d()};return window.addEventListener("keydown",j),()=>window.removeEventListener("keydown",j)},[d,n]);const[u,c]=a.useState(()=>({width:typeof window>"u"?1024:window.innerWidth,height:typeof window>"u"?768:window.innerHeight}));return a.useEffect(()=>{const j=()=>c({width:window.innerWidth,height:window.innerHeight});return window.addEventListener("resize",j),()=>window.removeEventListener("resize",j)},[]),e.jsxs("div",{"data-testid":"browser-fullscreen-host","data-element-id":t,"data-element-type":r,"data-dismissible":n?"true":"false",style:{pointerEvents:"auto",zIndex:Ga},className:"fixed inset-0 bg-white dark:bg-slate-950 flex flex-col",children:[n?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:u.width,height:u.height},children:l(u)}),e.jsx("span",{hidden:!0,"data-lesson-id":o})]})}function pn({width:t,height:r,children:o}){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:o})})}const Mo={quiz:"📝 随堂测验",timer:"⏱ 计时器",assignment:"📋 作业","code-sandbox":"💻 代码沙箱","html-applet":"🌐 交互课件",rollcall:"🎲 随机点名",presentation:"📽 演示文稿","math-graph":"📐 数学图形",text:"📝 文本"},To=({containerSize:t,browserFullscreenElementId:r,isRemoteBrowserFullscreen:o,isBrowserFullscreenDismissible:i,browserFullscreen:n,effectiveFullscreenElementId:d,isRemoteFullscreen:l,isFullscreenDismissible:u,applyFullscreen:c,safeElements:j,lessonId:b,readOnly:$,renderElement:M,children:N})=>{if(t.width<=0||t.height<=0)return null;if(r){const z=j.find(p=>p.id===r);if(!z)return o?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 x=Le(z);return e.jsx(zo,{elementId:r,type:z.type,data:x,lessonId:b,readOnly:$,dismissible:i,onExit:()=>void n.exit(),renderContent:p=>e.jsx(pn,{width:p.width,height:p.height,children:M(z,{fullscreen:{width:p.width,height:p.height,padding:So}})})})}if(d){const z=j.find(p=>p.id===d);if(!z)return l?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 x=Le(z);return e.jsx(Oi,{type:z.type,title:Mo[z.type]||z.type,data:x,containerSize:t,dismissible:u,onClose:()=>c(null),lessonId:b,elementId:z.id,readOnly:$,renderContent:p=>e.jsx(pn,{width:p.width,height:p.height,children:M(z,{fullscreen:{width:p.width,height:p.height,padding:0}})})})}return e.jsx(e.Fragment,{children:N})},Po=({autoTileEnabled:t,readOnly:r,tilingSplitters:o,activeSplitterDrag:i,activeDropZoneAction:n,handleSplitterPointerDown:d})=>!t||r?null:e.jsxs(e.Fragment,{children:[o.length>0&&e.jsx("div",{className:"absolute inset-0 pointer-events-none z-30",children:o.map(l=>{const u=l.orientation==="horizontal",c=i?.splitter.id===l.id;return e.jsxs("div",{"data-testid":`splitter-${l.orientation}-${l.id}`,className:`absolute pointer-events-auto group flex items-center justify-center select-none ${u?"cursor-row-resize":"cursor-col-resize"}`,style:{left:`${l.x}px`,top:`${l.y}px`,width:`${u?l.length:l.thickness}px`,height:`${u?l.thickness:l.length}px`},onPointerDown:j=>d(j,l),title:u?"拖动调整上下分割高度":"拖动调整左右分割宽度",children:[e.jsx("div",{className:`rounded-full transition-all duration-150 ${u?`w-full h-1 my-auto ${c?"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 ${c?"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 ${c?"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"} ${u?"w-8 h-3.5":"h-8 w-3.5"}`,children:e.jsxs("div",{className:`flex ${u?"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"})]})})]},l.id)})}),n&&n.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:`${n.previewRect.x}px`,top:`${n.previewRect.y}px`,width:`${n.previewRect.width}px`,height:`${n.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:n.label})})})]}),Do={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 vt(t,r){const o=Do[t];return o?{width:r?.width||o.width,height:r?.height||o.height}:{width:r?.width||300,height:r?.height||300}}function $o({containerSize:t,safeElements:r,getCurrentPageElements:o,onElementUpdate:i,lessonId:n,readOnly:d,setLocalGeometry:l,localGeometryRef:u,localGeometryVersion:c,currentPage:j,activeSegmentId:b,pages:$,tileSplitPreferenceRef:M,setIsSyncing:N}){const[z,x]=a.useState(!1),[p,g]=a.useState(null),v=a.useRef(null);a.useEffect(()=>{v.current=p},[p]);const E=a.useCallback(async(C,_,S)=>{if(!i||t.width<=0||t.height<=0)return;const D=C.filter(y=>Ve(y.type));if(D.length===0)return;const G=[],ie=new Map,V=new Map;let H=_??M.current;for(const y of D){const k=Le(y,null);if(!k)continue;!H&&k.tileStackDir&&(H=k.tileStackDir);const K=Zr(y,k,vt(y.type,k));if(K)if(G.push(K),ie.set(y.id,k),S){const Z=S.indexOf(y.id);V.set(y.id,Z>=0?Z:void 0)}else V.set(y.id,typeof k.tileOrder=="number"?k.tileOrder:void 0)}if(G.length===0)return;const Y=Ea(G,V),m=Ma(Y,t,{stackDirection:H});if(m.length===0)return;let w=!1;N(!0);try{for(let y=0;y<Y.length;y+=1){const k=Y[y],K=ie.get(k.id);if(!K)continue;const Z=Pa(k,m[y]),ce=Qr(k.shape);if(es(K,Z,ce)&&K.tileOrder===y&&K.tileStackDir===H)continue;w=!0,l(k.id,Z);const $e={...K,...Z,tileOrder:y,tileStackDir:H};K.__preTile||($e.__preTile=Ta(k)),$e.__tiled=Z;const ye=C.find(he=>he.id===k.id)||r.find(he=>he.id===k.id);ye&&(ye.data=JSON.stringify($e)),await i(k.id,$e)}if(!w)return;oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:n},timestamp:Date.now(),correlationId:n})}finally{N(!1)}},[i,t,r,n,l,M,N]),L=a.useCallback(async(C,_)=>{const S=o().filter(D=>Ve(D.type));await E(S,C,_)},[o,E]),O=a.useCallback(async(C,_)=>{if(!i||C===_)return;const S=r.find(Ee=>Ee.id===C),D=r.find(Ee=>Ee.id===_);if(!S||!D)return;const G=Le(S,null),ie=Le(D,null);if(!G||!ie)return;const V=nt(G,S.type==="circle"?"circle":"rect"),H=nt(ie,D.type==="circle"?"circle":"rect"),Y=u.current.get(C),m=u.current.get(_),w={...V,...Y||{}},y={...H,...m||{}},k=o().filter(Ee=>Ve(Ee.type)),K=k.findIndex(Ee=>Ee.id===C),Z=k.findIndex(Ee=>Ee.id===_),ce=typeof G.tileOrder=="number"?G.tileOrder:K>=0?K:0,$e=typeof ie.tileOrder=="number"?ie.tileOrder:Z>=0?Z:1,ye={...G,...y,tileOrder:$e},he={...ie,...w,tileOrder:ce};G.__preTile||(ye.__preTile=nt(G,S.type==="circle"?"circle":"rect")),ie.__preTile||(he.__preTile=nt(ie,D.type==="circle"?"circle":"rect")),ye.__tiled=y,he.__tiled=w,l(C,y),l(_,w),N(!0);try{await Promise.all([i(C,ye),i(_,he)]),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:n},timestamp:Date.now(),correlationId:n})}finally{N(!1)}},[i,r,o,l,u,n,N]),W=a.useCallback(async()=>{if(!i)return;const C=[];for(const _ of r){const S=Le(_,null);if(!S||!S.__preTile)continue;const{__preTile:D,__tiled:G,tileOrder:ie,...V}=S,H=Qr(_.type==="circle"?"circle":"rect"),Y=!G||es(S,G,H);C.push({id:_.id,patch:Y?{...V,...D}:V})}if(C.length!==0){N(!0);try{for(const{id:_,patch:S}of C){const D=S.radius!==void 0?"circle":"rect";l(_,nt(S,D)),await i(_,S)}oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:n},timestamp:Date.now(),correlationId:n})}finally{N(!1)}}},[i,r,n,l,N]),F=a.useCallback(async(C,_,S)=>{if(!i||C===_)return;const G=o().filter(Y=>Ve(Y.type)).map(Y=>{const m=Le(Y),w=vt(Y.type,m),y=u.current.get(Y.id);return{id:Y.id,x:y?.x??m.x??0,y:y?.y??m.y??0,width:y?.width??m.width??w.width,height:y?.height??m.height??w.height}}),ie=12,V={x:ie,y:ie,width:Math.max(0,t.width-ie*2),height:Math.max(0,t.height-ie*2)},H=Fa(C,_,S,G,V);if(Object.keys(H).length!==0){N(!0);try{for(const[Y,m]of Object.entries(H)){const w=G.find(y=>y.id===Y);w&&l(Y,Object.assign({x:w.x,y:w.y,width:w.width,height:w.height},m))}await Promise.all(Object.entries(H).map(async([Y,m])=>{const w=r.find(ce=>ce.id===Y);if(!w)return;const y=Le(w,{}),k=w.type==="circle"?"circle":"rect",Z={...nt(y,k),...m};l(Y,Z),await i(Y,{...y,...m,__tiled:Z})})),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:n},timestamp:Date.now(),correlationId:n})}finally{N(!1)}}},[i,r,o,t,l,u,n,N]),de=a.useCallback(()=>{z&&W(),x(!z)},[z,W]),B=a.useMemo(()=>z?o().filter(_=>Ve(_.type)).map(_=>{let S={};try{S=JSON.parse(_.data)}catch{}const D=vt(_.type,S),G=u.current.get(_.id);return{id:_.id,x:G?.x??S.x??0,y:G?.y??S.y??0,width:G?.width??S.width??D.width,height:G?.height??S.height??D.height}}):[],[z,r,j,b,$,c,o,u]),ne=a.useMemo(()=>!z||B.length<2?[]:_a(B),[z,B]),A=a.useCallback((C,_)=>{if(d)return;C.preventDefault(),C.stopPropagation();const S=_.orientation==="horizontal"?C.clientY:C.clientX;g({splitter:_,startPointerPos:S,initialBoxes:B})},[d,B]),ee=a.useRef(L);a.useEffect(()=>{ee.current=L},[L]);const J=a.useMemo(()=>z?o().filter(C=>Ve(C.type)).map(C=>C.id).join("|"):"",[z,r,j,b,$,o]);return a.useEffect(()=>{!z||!J||ee.current()},[z,J]),a.useEffect(()=>{if(!z||t.width<=0||t.height<=0)return;const C=setTimeout(()=>{ee.current()},250);return()=>clearTimeout(C)},[z,t.width,t.height]),a.useEffect(()=>{if(!p)return;const C=S=>{if(!v.current)return;const{splitter:D,startPointerPos:G,initialBoxes:ie}=v.current,Y=(D.orientation==="horizontal"?S.clientY:S.clientX)-G,m=Ra(D,Y,ie);for(const[w,y]of Object.entries(m)){const k=ie.find(K=>K.id===w);k&&l(w,{x:k.x,y:k.y,width:k.width,height:k.height,...y})}},_=async()=>{if(!v.current)return;const{splitter:S,startPointerPos:D,initialBoxes:G}=v.current;if(S.orientation==="horizontal"&&window.event&&window.event.clientY,g(null),i&&G.length>0){N(!0);try{await Promise.all(G.map(async V=>{const H=r.find(Y=>Y.id===V.id);if(H)try{const Y=JSON.parse(H.data),m=u.current.get(V.id);m&&await i(V.id,{...Y,...m,__tiled:m})}catch{}})),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:n},timestamp:Date.now(),correlationId:n})}finally{N(!1)}}};return window.addEventListener("pointermove",C),window.addEventListener("pointerup",_),()=>{window.removeEventListener("pointermove",C),window.removeEventListener("pointerup",_)}},[p,i,r,n,l,u,N]),{autoTileEnabled:z,setAutoTileEnabled:x,handleToggleAutoTile:de,currentTilingBoxes:B,tilingSplitters:ne,activeSplitterDrag:p,setActiveSplitterDrag:g,activeSplitterDragRef:v,handleSplitterPointerDown:A,applyAutoTiling:L,applyAutoTilingForElements:E,swapTileElements:O,restoreAutoTiling:W,insertTileInDirection:F}}const Eo=({showEntrySelector:t,setShowEntrySelector:r,zipUploadInfo:o,zipCandidates:i,handlePropsUpdate:n,fetchCoursewares:d})=>!t||!o?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(l=>e.jsxs("button",{onClick:async()=>{try{const u=await fetch("/api/courseware/confirm",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({uuid:o.uuid,name:o.name,entry:l})});if(u.ok){const c=await u.json();n({coursewareUuid:c.uuid,resourceId:""}),r(!1),d({force:!0})}}catch(u){console.error("Failed to confirm entry point:",u)}},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:["📄 ",l]},l))})]}),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:"取消"})})]})}),_o=({isOpen:t,onClose:r,element:o,coursewares:i=[],fetchCoursewares:n,onApplyTemporary:d,onSavePermanent:l})=>{const u=ss.useMemo(()=>{if(!o?.data)return{title:"Interactive Courseware"};try{return typeof o.data=="string"?JSON.parse(o.data):o.data}catch{return{title:"Interactive Courseware"}}},[o]),[c,j]=a.useState(u.title||"Interactive Courseware"),[b,$]=a.useState(u.coursewareUuid||""),[M,N]=a.useState(u.code||""),[z,x]=a.useState(!0),[p,g]=a.useState(!1),[v,E]=a.useState(null);if(a.useEffect(()=>{t&&o&&(j(u.title||"Interactive Courseware"),$(u.coursewareUuid||""),N(u.code||""),x(!0),E(null))},[t,o,u]),a.useEffect(()=>{if(!t)return;const W=F=>{F.key==="Escape"&&r()};return window.addEventListener("keydown",W),()=>window.removeEventListener("keydown",W)},[t,r]),!t||!o)return null;const L=async W=>{g(!0),E(null);try{const F=new FileReader;F.onload=async de=>{const B=de.target?.result;try{const ne=await fetch("/api/courseware/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:W.name.replace(/\.[^/.]+$/,""),filename:W.name,base64Data:B})}),A=await ne.json();ne.ok&&A.uuid?($(A.uuid),n&&await n({force:!0})):E(A.error||"课件上传失败")}catch(ne){E(ne.message||"网络异常")}finally{g(!1)}},F.readAsDataURL(W)}catch(F){E(F.message||"读取文件失败"),g(!1)}},O=async()=>{const W={...u,title:c.trim()||"Interactive Courseware",coursewareUuid:b||void 0,code:b?void 0:M};z?d(o.id,W):l&&await l(o.id,W),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:W=>{W.target===W.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:W=>W.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(as,{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(Jt,{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:c,onChange:W=>j(W.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:b,onChange:W=>$(W.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(W=>e.jsxs("option",{value:W.uuid,children:["📦 [互动课件] ",W.name]},W.id||W.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 ${p?"opacity-50 pointer-events-none":""}`,title:"上传本地互动课件包 (.zip / .html)",children:[p?e.jsx($t,{size:13,className:"animate-spin"}):e.jsx(Kr,{size:13}),e.jsx("span",{children:p?"正在上传...":"上传新课件"}),e.jsx("input",{type:"file",accept:".zip,.html,.htm",className:"hidden",onChange:W=>{const F=W.target.files?.[0];F&&L(F)}})]})]}),v&&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(At,{size:14,className:"shrink-0"}),e.jsx("span",{children:v})]}),!b&&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(fa,{size:12}),"自定义沙箱代码 (HTML / JavaScript):"]}),e.jsx("span",{className:"text-2xs text-muted/80",children:"已自动注入 LMS Bridge SDK"})]}),e.jsx("textarea",{rows:5,value:M,onChange:W=>N(W.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:W=>x(W.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(ba,{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:O,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(Rn,{size:13}),e.jsx("span",{children:z?"临时应用至本课":"保存并更新课程"})]})]})]})]})})};function Ro({lessonId:t}){const[r,o]=a.useState({});return a.useEffect(()=>{if(!t)return;let i=!1;return fetch(`/api/lessons/${encodeURIComponent(t)}/quiz-counts`).then(n=>n.ok?n.json():null).then(n=>{if(!n?.quizzes||i)return;const d={};for(const l of n.quizzes)d[l.elementId]=l.submissionCount;o(d)}).catch(()=>{}),()=>{i=!0}},[t]),wa({types:["quiz.answered"]},i=>{!i.elementId||i.lessonId!==t||o(n=>({...n,[i.elementId]:(n[i.elementId]??0)+1}))}),{quizCounts:r,setQuizCounts:o}}const fn=[{id:"page-0",title:"P1 · 引入导入",order:0},{id:"page-1",title:"P2 · 核心讲解",order:1},{id:"page-2",title:"P3 · 互动练习",order:2}];function Bn(t,r,o){if(t.type==="page_meta")return!1;try{const i=JSON.parse(t.data),n=i.page??0,d=o[r];return i.pageId&&d?.id?i.pageId===d.id:n===r}catch{return r===0}}function Ao(t,r,o,i){const n=o[r];return i&&n?.segmentId&&n.segmentId!==i?[]:t.filter(d=>{if(!Bn(d,r,o))return!1;try{const l=JSON.parse(d.data);return!(i&&l.segmentId&&l.segmentId!==i)}catch{return r===0}})}function Fo(t,r,o=Date.now(),i){const n=t.length,d={id:`page-${o}-${n}`,title:r||`P${n+1} · 备课页面`,order:n,...i?{segmentId:i}:{}};return{newPages:[...t,d],newIndex:n,newPage:d}}function Lo(t,r,o){const i=o.trim();return i?t.map((n,d)=>d===r?{...n,title:i}:n):t}function Wo(t,r,o=Date.now()){const i=t[r];if(!i)return null;const n=r+1,d={id:`page-${o}-${n}`,title:`${i.title} (副本)`,order:n,...i.segmentId?{segmentId:i.segmentId}:{}};return{newPages:[...t.slice(0,n),d,...t.slice(n).map(u=>({...u,order:u.order+1}))],newIndex:n,newPage:d}}function Bo(t,r,o){const i=o==="left"?r-1:r+1;if(i<0||i>=t.length)return null;const n=[...t],d=n[r];return n[r]=n[i],n[i]=d,n.forEach((l,u)=>{l.order=u}),{newPages:n,targetIndex:i}}function Ho({elements:t,safeElements:r,initialPage:o,activeSegmentId:i,lessonId:n,userRole:d,socketRef:l,onElementAdd:u,onElementUpdate:c,onElementDelete:j,onPagesStateChange:b,setDialog:$}){const[M,N]=a.useState(()=>{const w=(Array.isArray(t)?t:[]).find(y=>y.type==="page_meta");if(w){const y=Le(w);if(Array.isArray(y?.pages)&&y.pages.length>0)return y.pages}return fn}),[z,x]=a.useState(()=>{const w=Number(o);if(Number.isFinite(w)&&w>=0)return w;if(i){const y=(Array.isArray(t)?t:[]).find(ce=>ce.type==="page_meta"),k=y?Le(y):null,Z=(Array.isArray(k?.pages)&&k.pages.length>0?k.pages:fn).findIndex(ce=>ce.segmentId===i);if(Z!==-1)return Z}return 0}),[p,g]=a.useState(!1),[v,E]=a.useState(null),[L,O]=a.useState(""),[W,F]=a.useState(null),de=a.useRef(null);a.useEffect(()=>{const w=de.current;w?.currentPage===z&&JSON.stringify(w.pages)===JSON.stringify(M)||(de.current={pages:M,currentPage:z},b?.({pages:M,currentPage:z}))},[M,z,b]),a.useEffect(()=>{const w=r.find(y=>y.type==="page_meta");if(w){const y=Le(w);Array.isArray(y?.pages)&&y.pages.length>0&&N(k=>JSON.stringify(k)===JSON.stringify(y.pages)?k:y.pages)}},[r]);const B=a.useRef(Number.isFinite(Number(o))&&Number(o)>=0);a.useEffect(()=>{if(B.current||!Array.isArray(M)||M.length===0||o==null)return;const w=Number(o);Number.isFinite(w)&&w>0&&w<M.length&&x(w),B.current=!0},[M,o]);const ne=a.useCallback(w=>Bn(w,z,M),[M,z]),A=a.useMemo(()=>Ao(r,z,M,i),[r,z,M,i]),ee=a.useCallback(()=>A,[A]),J=a.useRef(null),C=a.useRef(null);a.useEffect(()=>(C.current=null,()=>{J.current&&(clearTimeout(J.current),J.current=null)}),[n]);const _=a.useCallback(w=>{d!=="teacher"||!n||C.current!==w&&(J.current&&clearTimeout(J.current),J.current=setTimeout(()=>{fetch(`/api/classroom/sessions/${encodeURIComponent(n)}/view-state`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({currentPage:w})}).then(y=>{y.ok?C.current=w:y.status===429&&console.warn("[InteractiveWhiteboard] view-state rate-limited (HTTP 429), skipping transient update.")}).catch(()=>{})},500))},[d,n]),S=a.useCallback(w=>{const y=r.find(k=>k.type==="page_meta");y&&c?c(y.id,{pages:w}):u&&u("page_meta",{pages:w}),l.current?.emit&&l.current.emit("whiteboard-update",{roomId:n,type:"page-meta-update",payload:{pages:w}})},[r,c,u,l,n]),D=a.useRef(!1),G=a.useCallback(w=>{D.current=!0,x(w),F(null),l.current?.emit&&l.current.emit("whiteboard-update",{roomId:n,type:"page-change",payload:{page:w}}),_(w)},[l,n,_]),ie=a.useCallback(w=>{const{newPages:y,newIndex:k}=Fo(M,w,Date.now(),i);N(y),x(k),S(y),l.current?.emit&&l.current.emit("whiteboard-update",{roomId:n,type:"page-change",payload:{page:k}})},[M,i,S,l,n]),V=a.useCallback((w,y)=>{if(!y.trim()){E(null);return}const k=Lo(M,w,y);N(k),S(k),E(null),O("")},[M,S]),H=a.useCallback(w=>{const y=M[w];if(!y)return;const k=Wo(M,w);if(!k)return;const{newPages:K,newIndex:Z,newPage:ce}=k;N(K),x(Z),S(K),r.filter(ye=>ye.type!=="page_meta"&&(()=>{try{const he=JSON.parse(ye.data);return(he.page??0)===w||he.pageId===y.id}catch{return w===0}})()).forEach(ye=>{try{const he=JSON.parse(ye.data);u&&u(ye.type,{...he,page:Z,pageId:ce.id,x:(he.x??100)+20,y:(he.y??100)+20})}catch(he){console.error("Failed duplicating page element:",he)}})},[M,S,r,u]),Y=a.useCallback(w=>{if(M.length<=1){$({title:"无法删除",message:"至少需要保留一个白板页面!",type:"alert",onConfirm:()=>{}});return}const y=M[w],k=r.filter(Z=>Z.type!=="page_meta"&&(()=>{try{const ce=JSON.parse(Z.data);return(ce.page??0)===w||ce.pageId===y.id}catch{return w===0}})()),K=()=>{j&&k.forEach($e=>j($e.id));const Z=M.filter(($e,ye)=>ye!==w).map(($e,ye)=>({...$e,order:ye}));N(Z);const ce=Math.min(z,Z.length-1);x(ce),S(Z)};k.length>0?$({title:"确认删除白板页面",message:`页面 [${y.title}] 包含 ${k.length} 个组件,删除页面将同时清理该页面的组件,是否确定删除?`,type:"confirm",onConfirm:K}):K()},[M,r,j,z,S,$]),m=a.useCallback((w,y)=>{const k=Bo(M,w,y);if(!k)return;const{newPages:K,targetIndex:Z}=k;N(K),z===w?x(Z):z===Z&&x(w),S(K)},[M,z,S]);return{pages:M,setPages:N,currentPage:z,setCurrentPage:x,showPageDrawer:p,setShowPageDrawer:g,editingPageIdx:v,setEditingPageIdx:E,editingPageTitle:L,setEditingPageTitle:O,activeMenuPageIdx:W,setActiveMenuPageIdx:F,belongsToCurrentPage:ne,currentPageElements:A,getCurrentPageElements:ee,persistPageChange:_,savePagesConfig:S,handleSwitchPage:G,handleAddPage:ie,handleRenamePage:V,handleDuplicatePage:H,handleDeletePage:Y,handleMovePage:m,programmaticPageSwitchRef:D}}function Oo({lessonId:t,currentPage:r,activeSegmentId:o,whiteboardRenderers:i,containerRef:n,setIsSyncing:d,onElementAdd:l,onRefresh:u}){const[c,j]=a.useState(!1),b=a.useCallback(p=>{p.preventDefault(),p.dataTransfer.dropEffect="copy",j(!0)},[]),$=a.useCallback(p=>{p.preventDefault(),p.dataTransfer.dropEffect="copy",j(!0)},[]),M=a.useCallback(p=>{p.preventDefault(),p.currentTarget.contains(p.relatedTarget)||j(!1)},[]),N=a.useCallback((p,g,v,E)=>{const L={x:v,y:E,page:r,segmentId:o},W=dr.get(p)?.defaultData||{},B=i?.find(ne=>{const A=ne;return A.targetType===p||ne.id===p||A.route===p||`${ne.pluginId}/${ne.id}`===p||A.slotProps?.elementType===p||A.slotProps?.targetType===p})?.slotProps?.defaultData||{};switch(p){case"code-sandbox":return{...L,code:g.code??"console.log('Hello Sandbox!');"};case"math-graph":return{...L,equation:g.equation??"Math.sin(x)"};case"presentation":return{...L,markdown:g.markdown??`# Title Slide
18
+ ---
19
+ ## Slide 2`,width:600,height:400,slideX:0,slideY:0};case"quiz":return{...L,question:g.question??"New Quiz",options:Array.isArray(g.options)?g.options:["A","B","C","D"]};case"html-applet":return{...L,title:g.title??"",code:g.code??"",coursewareUuid:g.coursewareUuid??void 0,resourceId:g.resourceId??void 0};case"assignment":return{...L,title:g.title??"New Assignment",description:g.description??""};case"hello-world":return L;case"rollcall":return{...L,allStudents:[]};default:return{...L,...W,...B,...g}}},[r,o,i]),z=a.useCallback(async(p,g)=>{if(!n.current)return;const v=n.current.getBoundingClientRect(),E=Math.round(v.width/2+n.current.scrollLeft),L=Math.round(v.height/2+n.current.scrollTop);d(!0);try{await l(p,N(p,g,E,L)),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}catch(O){console.error("addElementAtCenter error",O)}finally{d(!1)}},[n,d,l,N,t,u]),x=a.useCallback(async p=>{p.preventDefault(),p.stopPropagation();try{let g=p.dataTransfer.getData("application/json");if(g||(g=p.dataTransfer.getData("text/plain")),g||(g=p.dataTransfer.getData("text")),g||(g=p.dataTransfer.getData("Text")),!g)return;let v;try{v=JSON.parse(g)}catch(W){console.error("Failed to parse drop JSON payload:",W);return}if(typeof v!="object"||!v)return;if(!n.current){console.warn("containerRef.current is not loaded on drop");return}const E=n.current.getBoundingClientRect(),L=p.clientX-E.left+n.current.scrollLeft,O=p.clientY-E.top+n.current.scrollTop;d(!0);try{const W=typeof v.type=="string"?v.type:"";await l(W,N(W,v,L,O)),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),u&&u()}finally{d(!1)}}catch(g){console.error("Drop error",g)}},[n,d,l,N,t,u]);return{isDragOverBoard:c,setIsDragOverBoard:j,handleWhiteboardDragOver:b,handleWhiteboardDragEnter:$,handleWhiteboardDragLeave:M,buildElementData:N,addElementAtCenter:z,handleWhiteboardDrop:x}}const lr="ABCDEFGHIJKLMNOPQRSTUVWXYZ",Xo=({data:t,lessonId:r,elementId:o})=>{const[i,n]=a.useState({}),[d,l]=a.useState(null),[u,c]=a.useState(null),[j,b]=a.useState(!1),[$,M]=a.useState(null),[N,z]=a.useState(t.submissions||{});a.useEffect(()=>{z(t.submissions||{})},[t.submissions]),a.useEffect(()=>{if(!d||d.role==="student"||!r)return;let H=!1;return fetch(`/api/lessons/${encodeURIComponent(r)}/quiz-submissions`).then(Y=>Y.ok?Y.json():null).then(Y=>{if(H||!Y?.quizzes)return;const m=Y.quizzes.find(w=>w.elementId===(o||t.id));m?.submissions&&z(w=>({...w,...m.submissions}))}).catch(()=>{}),()=>{H=!0}},[d,r,o]),a.useEffect(()=>{let H=!1;return fetch("/api/students?pageSize=all").then(m=>m.ok?m.json():{data:[]}).then(m=>{if(H)return;const w=Xi(m),y={};for(const k of w)y[k.id]=k.name;n(y)}).catch(()=>{}),(async()=>{try{let m=await fetch("/api/auth/session").catch(()=>null);if((!m||!m.ok)&&(m=await fetch("/api/auth/me").catch(()=>null)),m&&m.ok&&!H){const w=await m.json(),y=w.session||w;y&&typeof y=="object"&&!Array.isArray(y)&&y.role&&l({id:y.id||y.userId,role:y.role,studentId:y.studentId||y.userId||y.id})}}catch{}})(),()=>{H=!0}},[]);const x=Object.entries(N),p=Wn(t),g=p===null?void 0:p,v=$?.correctIndex??g,E=typeof t.passScore=="number"?t.passScore:60,L=d?.studentId||d?.id,O=L?N[L]:null,W=typeof window<"u"&&(new URLSearchParams(window.location?.search||"").get("mode")==="student_live"||(window.location?.hash||"").includes("student_live")),F=d?.role==="student"||W,de=!!O||!!$,B=!F||de,ne=H=>{if(typeof H=="number"&&!isNaN(H))return H;if(typeof H=="string"){const Y=parseFloat(H);return isNaN(Y)?null:Y}return null},A=Array.isArray(t.options)?t.options.map(H=>String(H)):[],ee=H=>{const Y=rs(H,A);return Y===null?void 0:Y},J=async()=>{if(u===null||j)return;b(!0);const H=lr[u]||String(u),Y=u;try{const m=r||"current",w=o||t.id||"quiz",y=await fetch(`/api/lessons/${encodeURIComponent(m)}/quiz-submit`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elementId:w,answer:Y})}),k=await y.json().catch(()=>null);if(y.ok&&k?.success){M({isCorrect:k.isCorrect,score:k.score,answer:H,correctIndex:typeof k.correctIndex=="number"?k.correctIndex:void 0});const K=k.studentId||L||"me";z(Z=>({...Z,[K]:{answer:u,score:k.score,time:Date.now()}})),window.dispatchEvent(new CustomEvent("openlearn:segment-gate-changed",{detail:{lessonId:m}}))}}catch{}finally{b(!1)}},C=x.map(([H,Y])=>{const m=ee(Y),w=ne(Y.score),y=m!==void 0&&v!==void 0?m===v:w!==null?w>=E:!1;return{sid:H,v:Y,answerIdx:m,scoreNum:w,isCorrect:y}}),_=x.length,S=C.filter(H=>H.isCorrect).length,D=_>0?Math.round(S/_*100):0,G=C.map(H=>H.scoreNum).filter(H=>H!==null),ie=G.length>0?G.reduce((H,Y)=>H+Y,0)/G.length:null,V=H=>{if(H==null)return"-";const Y=typeof H=="number"?H:Number(H),m=isNaN(Y)?new Date(String(H)):new Date(Y);return isNaN(m.getTime())?"-":m.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}),$&&e.jsxs("div",{"data-testid":"quiz-feedback",className:`p-4 rounded-xl border flex items-center justify-between text-sm font-bold ${$.isCorrect?"bg-emerald-50 border-emerald-300 text-emerald-800":"bg-rose-50 border-rose-300 text-rose-800"}`,children:[e.jsx("span",{children:$.isCorrect?`🎉 回答正确!得分:${$.score} 分`:`❌ 回答错误。得分:${$.score} 分`}),e.jsx("span",{className:"text-xs font-normal",children:"提交已实时同步至教师大屏"})]}),e.jsx("div",{className:"flex flex-col gap-3",children:(t.options||[]).map((H,Y)=>{const m=u===Y,w=v===Y;let y="bg-gray-50 border-gray-200 text-gray-700";return B&&w?y="bg-green-50 border-green-300 text-green-800":m?y="bg-indigo-50 border-indigo-400 text-indigo-900 ring-2 ring-indigo-200 shadow-xs":F&&!de&&(y="bg-white hover:bg-gray-50 border-gray-200 text-gray-800 cursor-pointer"),e.jsxs("div",{"data-testid":`quiz-option-${Y}`,onClick:()=>{F&&!de&&c(Y)},className:`px-5 py-4 text-left rounded-xl text-base border-2 transition-all ${y}`,children:[e.jsxs("span",{className:"font-bold text-indigo-600 mr-3",children:[lr[Y],"."]}),H,B&&w&&e.jsx("span",{className:"ml-2 text-xs font-bold text-green-600",children:"✓ 正确答案"})]},Y)})}),F&&!de&&e.jsx("div",{className:"pt-2 flex justify-end",children:e.jsx("button",{"data-testid":"quiz-submit-btn",disabled:u===null||j,onClick:J,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:j?"提交中...":"提交答案"})}),!F&&(_===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:_})]}),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:S})]}),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:[D,"%"]})]}),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:ie!==null?ie.toFixed(1):"-"})]})]}),e.jsx(Yi,{labelledBy:"quiz-submissions-caption",className:"border border-gray-200 rounded-xl",children:e.jsxs("table",{className:"responsive-data-table w-full text-sm","data-testid":"quiz-submissions-table","data-stack-mobile":"true",children:[e.jsx("caption",{id:"quiz-submissions-caption",className:"sr-only",children:"测验提交成绩明细"}),e.jsx("thead",{className:"bg-gray-50 text-gray-500 text-xs uppercase",children:e.jsxs("tr",{children:[e.jsx("th",{scope:"col",className:"px-4 py-2 text-left",children:"学生"}),e.jsx("th",{scope:"col",className:"px-4 py-2 text-left",children:"答案"}),e.jsx("th",{scope:"col",className:"px-4 py-2 text-right",children:"得分"}),e.jsx("th",{scope:"col",className:"px-4 py-2 text-right",children:"提交时间"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-100",children:C.map(({sid:H,v:Y,answerIdx:m,scoreNum:w,isCorrect:y})=>{const k=m!==void 0&&m>=0&&m<lr.length?lr[m]:"-",K=w!==null?w:y?100:0,Z=i[H]||H;return e.jsxs("tr",{className:"hover:bg-gray-50","data-testid":`quiz-row-${H}`,children:[e.jsx("th",{scope:"row","data-label":"学生",className:"px-4 py-2 font-medium text-gray-700 text-left",children:Z}),e.jsxs("td",{"data-label":"答案",className:`px-4 py-2 font-mono ${y?"text-green-600 font-bold":"text-red-500"}`,children:[k,y?" ✓":""]}),e.jsx("td",{"data-label":"得分",className:`px-4 py-2 text-right font-mono font-bold ${K>=E?"text-green-600":"text-gray-600"}`,children:K}),e.jsx("td",{"data-label":"提交时间",className:"px-4 py-2 text-right text-gray-500 text-xs",children:V(Y.time??Y.timestamp)})]},H)})})]})})]}))]})},Yo=a.lazy(()=>_i(()=>import("./RevealPresentationWrapper-Dnf4v72i.js"),__vite__mapDeps([0,1,2,3,4,5,6,7])).then(t=>({default:t.RevealPresentationWrapper})));Vi.registerHostBuiltin("quiz",Xo);const qo=80,rt=({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 st={data:[],ts:0,inflight:null};const nl=[{id:"page-0",title:"P1 · 引入导入",order:0},{id:"page-1",title:"P2 · 核心讲解",order:1},{id:"page-2",title:"P3 · 互动练习",order:2}],bn=4,il=a.forwardRef(({lessonId:t,elements:r,onElementAdd:o,onElementUpdate:i,onElementDelete:n,onClearBoard:d,onRefresh:l,enableAutoAI:u,activeSegmentId:c,onSegmentSync:j,initialPage:b,classroomTools:$,onExecuteTool:M,userRole:N="teacher",isEditMode:z=!0,readOnly:x=!1,classId:p,studentId:g,studentName:v,broadcastFullscreen:E=!1,fullscreenBroadcastClassId:L=null,followRemoteFullscreen:O=!1,onFullscreenSync:W,hidePageBar:F=!1,onPagesStateChange:de,onElementDragChange:B,onElementDropCheck:ne},A)=>{const[ee,J]=a.useState({}),C=a.useMemo(()=>{const s=Array.isArray(r)?r:[];return Object.keys(ee).length===0?s:s.map(f=>ee[f.id]||f)},[r,ee]),_=qi(s=>s.theme),S=Ji(s=>s.scale)/100;a.useEffect(()=>{cn.setTheme(_)},[_]);const D=cn.getTokens(),G=_==="dark"||_==="chalkboard",ie=vn(s=>s.extensionPoints.get("whiteboard.renderer")),[V,H]=a.useState("cursor"),[Y,m]=a.useState("#facc15"),w=a.useRef(null),[y,k]=a.useState(!1),K=a.useRef(null),[Z,ce]=a.useState(null),[$e,ye]=a.useState(""),{pages:he,setPages:Ee,currentPage:ve,setCurrentPage:re,showPageDrawer:we,setShowPageDrawer:Me,editingPageIdx:R,setEditingPageIdx:Q,editingPageTitle:pe,setEditingPageTitle:ue,activeMenuPageIdx:fe,setActiveMenuPageIdx:Ie,belongsToCurrentPage:ut,getCurrentPageElements:Xe,handleSwitchPage:xr,handleAddPage:ls,handleRenamePage:cs,handleDuplicatePage:ds,handleDeletePage:us,handleMovePage:hs,programmaticPageSwitchRef:xs}=Ho({elements:r,safeElements:C,initialPage:b,activeSegmentId:c,lessonId:t,userRole:N,socketRef:K,onElementAdd:o,onElementUpdate:i,onElementDelete:n,onPagesStateChange:de,setDialog:ce}),[ms,Hn]=a.useState(!0),[mr,pr]=a.useState(null),fr=a.useRef(null);a.useEffect(()=>{fr.current=mr},[mr]);const br=a.useRef(null),[Gt,gr]=a.useState(null),ps=a.useRef(null);a.useEffect(()=>{ps.current=Gt},[Gt]);const fs=a.useRef(null),[yr,Jo]=a.useState(void 0),bs=a.useRef(yr);a.useEffect(()=>{bs.current=yr},[yr]),a.useEffect(()=>{x&&(me(null),Ce(null),H("cursor"),at(null),wr(!1),vr(null))},[x]);const[_e,at]=a.useState(null),[gs,wr]=a.useState(!1),On=a.useRef(null),[mt,ys]=a.useState({width:0,height:0}),[ws,vs]=a.useState({width:0,height:0}),[js,Xn]=a.useState(0),[Yn,Ns]=a.useState({}),{quizCounts:qn}=Ro({lessonId:t}),[Jn,vr]=a.useState(null),[In,Gn]=a.useState(null),ks=rn(s=>s.remoteFullscreenElementId),Nt=O&&!!ks,Ke=Nt?ks:Jn,Un=!Nt,Cs=rn(s=>s.remoteBrowserFullscreenElementId),Ut=O&&!!Cs,kt=Ut?Cs:In,Vn=!Ut,Ct=Ua({elementId:kt,enableNativeFullscreen:!Ut,onChange:s=>{Gn(s),E&&K.current&&K.current.emit("teacher-broadcast-fullscreen",{classId:L,lessonId:t,elementId:s,mode:"browser"})}});a.useEffect(()=>{kt&&!C.some(s=>s.id===kt)&&Ct.exit()},[kt,C,Ct]);const Ss=a.useRef(W);a.useEffect(()=>{Ss.current=W},[W]);const ht=s=>{vr(s),W?.(s),E&&K.current&&K.current.emit("teacher-broadcast-fullscreen",{classId:L,lessonId:t,elementId:s,mode:"board"})};a.useEffect(()=>{if(E)return()=>{Ss.current?.(null);const s={classId:L,lessonId:t,elementId:null};K.current?.emit("teacher-broadcast-fullscreen",{...s,mode:"board"}),K.current?.emit("teacher-broadcast-fullscreen",{...s,mode:"browser"})}},[E,L,t]);const Vt=!!Ke&&!C.some(s=>s.id===Ke),Ft=a.useRef(null);a.useEffect(()=>{if(!Vt||!Nt){Ft.current=null;return}if(Ft.current==null){Ft.current=Date.now();return}Date.now()-Ft.current>=3e3&&(Ft.current=null,Ii.getState().clearRemoteFullscreen())},[Vt,Nt]),a.useEffect(()=>{!Vt||Nt||(vr(null),W?.(null),E&&K.current&&K.current.emit("teacher-broadcast-fullscreen",{classId:L,lessonId:t,elementId:null}))},[Vt,Nt,E,L,t,W]);const[Lt,Wt]=a.useState(null),Fe=a.useRef(new Map),[jr,St]=a.useState(0),ot=a.useCallback((s,f)=>{Fe.current.set(s,f),St(h=>h+1)},[]),zs=a.useCallback(s=>{Fe.current.delete(s)&&St(f=>f+1)},[]);a.useEffect(()=>{Fe.current.clear(),St(s=>s+1)},[t]),a.useEffect(()=>{if(Fe.current.size!==0){for(const s of r){const f=Fe.current.get(s.id);if(!f)continue;const h=Le(s,null);if(!h){Fe.current.delete(s.id);continue}const P=Object.keys(f);es(h,f,P)&&Fe.current.delete(s.id)}St(s=>s+1)}},[r]);const Ms=a.useRef(void 0),{autoTileEnabled:We,handleToggleAutoTile:Ts,tilingSplitters:Kn,activeSplitterDrag:Zn,handleSplitterPointerDown:Qn,applyAutoTiling:Ps,applyAutoTilingForElements:Et,swapTileElements:Ds,insertTileInDirection:$s}=$o({containerSize:mt,safeElements:C,getCurrentPageElements:Xe,onElementUpdate:i,lessonId:t,readOnly:x,setLocalGeometry:ot,localGeometryRef:Fe,localGeometryVersion:jr,currentPage:ve,activeSegmentId:c,pages:he,tileSplitPreferenceRef:bs,setIsSyncing:k});a.useEffect(()=>{Ms.current=Et,br.current=Ds,fs.current=$s},[Et,Ds,$s]);const Es=a.useMemo(()=>{const s=[];for(const f of Xe())try{const h=Le(f),P=Fe.current.get(f.id),I=vt(f.type,h);s.push({x:P?.x??(Number.isFinite(h.x)?h.x:0),y:P?.y??(Number.isFinite(h.y)?h.y:0),width:P?.width??(Number.isFinite(h.width)?h.width:I.width),height:P?.height??(Number.isFinite(h.height)?h.height:I.height)})}catch{}return Wa(s)},[Xe,jr]),Kt=a.useMemo(()=>Ba(ws,Es,qo,js).canvas,[ws,Es,js]),Ge=a.useCallback((s,f)=>{const h=w.current;if(!h)return null;const P=h.getBoundingClientRect();return Ha(s,f,P,{scrollLeft:h.scrollLeft,scrollTop:h.scrollTop})},[]),ke=a.useRef(null),je=a.useRef(null),zt=a.useRef(null),[xe,_s]=a.useState(null),me=s=>{N==="teacher"&&_s(s)},[Oe,ei]=a.useState(null),Ce=s=>{N==="teacher"&&ei(s)},[Rs,As]=a.useState(null),[Mt,Nr]=a.useState(null),Bt=a.useRef(null),[Fs,kr]=a.useState(null),[Tt,lt]=a.useState(null),[Zt,pt]=a.useState(null),[Cr,Ls]=a.useState(null),[Ws,Sr]=a.useState({}),[Bs,zr]=a.useState({}),[Hs,Mr]=a.useState([]),[ti,ri]=a.useState([]),[si,ni]=a.useState(null),[ii,Os]=a.useState(!1),Ht=a.useRef(null),Ot=async s=>{const f=Date.now();if(!s?.force&&st.data.length>0&&f-st.ts<3e4){Mr(st.data);return}if(st.inflight&&!s?.force){const I=await st.inflight;Mr(I);return}const P=(async()=>{try{const I=await fetch("/api/courseware");if(I.ok){const X=await I.json();return st={data:Array.isArray(X)?X:[],ts:Date.now(),inflight:null},Mr(st.data),st.data}}catch(I){console.error("Error fetching coursewares:",I)}finally{st.inflight=null}return st.data})();st.inflight=P,await P};a.useEffect(()=>{if(xe){const s=C.find(f=>f.id===xe);s?(s.type==="html-applet"?Ht.current!==xe&&(Ht.current=xe,Ot()):Ht.current=null,lt(Le(s,{}))):(Ht.current=null,lt(null),pt(null))}else Ht.current=null,lt(null),pt(null)},[xe,r]);const Pt=async s=>{const f=C.find(U=>U.id===xe);if(!f)return"noop";const P={...Le(f,{}),...s},I=f.data,X=JSON.stringify(P);if(I!==X&&(Sr(U=>{const se=U[f.id]?[...U[f.id]]:[];return se.length>=30&&se.shift(),se.push(I),{...U,[f.id]:se}}),zr(U=>({...U,[f.id]:[]}))),i){k(!0);try{return await i(f.id,P),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),l&&l(),"saved"}catch(U){return console.error("更新属性失败:",U),"failed"}finally{k(!1)}}return"noop"},ai=(s,f)=>{const h=C.find(I=>I.id===s);if(!h)return;const P=JSON.stringify(f);J(I=>({...I,[s]:{...h,data:P}})),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,temporary:!0},timestamp:Date.now(),correlationId:t})},oi=async(s,f)=>{if(J(h=>{const P={...h};return delete P[s],P}),i){k(!0);try{await i(s,f),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s},timestamp:Date.now(),correlationId:t}),l&&l()}catch(h){console.error("保存课件属性失败:",h)}finally{k(!1)}}},li=async()=>{if(!xe)return;const s=C.find(X=>X.id===xe);if(!s)return;const f=Ws[xe]||[];if(f.length===0)return;const h=f[f.length-1],P=f.slice(0,f.length-1),I=s.data;if(zr(X=>{const U=X[xe]?[...X[xe]]:[];return U.push(I),{...X,[xe]:U}}),Sr(X=>({...X,[xe]:P})),i){k(!0);try{const X=JSON.parse(h);lt(X),await i(xe,X),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),l&&l()}catch(X){console.error("撤销修改失败:",X)}finally{k(!1)}}},ci=async()=>{if(!xe)return;const s=C.find(X=>X.id===xe);if(!s)return;const f=Bs[xe]||[];if(f.length===0)return;const h=f[f.length-1],P=f.slice(0,f.length-1),I=s.data;if(Sr(X=>{const U=X[xe]?[...X[xe]]:[];return U.push(I),{...X,[xe]:U}}),zr(X=>({...X,[xe]:P})),i){k(!0);try{const X=JSON.parse(h);lt(X),await i(xe,X),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),l&&l()}catch(X){console.error("重做修改失败:",X)}finally{k(!1)}}},di=(s,f)=>{lt(h=>h&&{...h,[s]:f})},ui=(s,f)=>{Pt({[s]:f})},Xs=s=>{lt(f=>f&&{...f,...s}),Pt(s)},hi=(s,f)=>{const h=parseFloat(f);isNaN(h)||Pt({[s]:h})},xi=(s,f)=>{lt(h=>{if(!h)return h;const P=[...h.options||[]];return P[s]=f,{...h,options:P}})},mi=(s,f)=>{if(!Tt)return;const h=[...Tt.options||[]];h[s]=f,Pt({options:h})},pi=()=>{if(!Tt)return;const s=Tt.options||[],h="ABCDEFGHIJKLMNOPQRSTUVWXYZ"[s.length]||`Option ${s.length+1}`,P=[...s,`选项 ${h}`];lt(I=>I&&{...I,options:P}),Pt({options:P})},fi=s=>{if(!Tt)return;const f=(Tt.options||[]).filter((h,P)=>P!==s);lt(h=>h&&{...h,options:f}),Pt({options:f})};a.useEffect(()=>{const s=()=>{Ce(null)};return window.addEventListener("click",s),()=>window.removeEventListener("click",s)},[]);const Qt=a.useRef(B);a.useEffect(()=>{Qt.current=B},[B]);const Ys=a.useRef(ne);a.useEffect(()=>{Ys.current=ne},[ne]);const Tr=(s,f,h)=>{if(N!=="teacher")return;s.preventDefault();const P=Fe.current.get(f),I=P?.x??h.x??0,X=P?.y??h.y??0,U={id:f,initialX:I,initialY:X,currentX:I,currentY:X,startPointerX:s.clientX,startPointerY:s.clientY,data:{...h,...P??{},x:I,y:X}};ke.current=U,Wt(U);const se=C.find(ae=>ae.id===f);Qt.current?.({elementId:f,elementType:se?.type||"unknown",elementData:U.data,clientX:s.clientX,clientY:s.clientY,initialPage:ve,initialSegmentId:U.data.segmentId||c})},Pr=s=>{},Dr=async s=>{},er=(s,f,h,P,I,X,U)=>{if(N!=="teacher")return;s.preventDefault(),s.stopPropagation();const se={id:f,corner:h,startX:s.clientX,startY:s.clientY,initialX:P,initialY:I,initialWidth:X,initialHeight:U},ae={id:f,x:P,y:I,width:X,height:U};je.current=se,zt.current=ae,As(se),Nr(ae)},tr=s=>{},rr=async s=>{};a.useEffect(()=>{if(!Lt)return;const s=h=>{if(!ke.current)return;const P=h.clientX-ke.current.startPointerX,I=h.clientY-ke.current.startPointerY,X=ke.current.initialX,U=ke.current.initialY;ke.current.currentX=X+P,ke.current.currentY=U+I,Wt({...ke.current});const se=C.find(ae=>ae.id===ke.current?.id);if(Qt.current?.({elementId:ke.current.id,elementType:se?.type||"unknown",elementData:ke.current.data,clientX:h.clientX,clientY:h.clientY,initialPage:ve,initialSegmentId:ke.current.data?.segmentId||c}),We){const ae=Ge(h.clientX,h.clientY);if(ae){const ge=ae.x,Ne=ae.y,Te=[];let Pe=0;for(const De of Xe())if(Ve(De.type)&&(Pe+=1,De.id!==ke.current.id))try{const _t=JSON.parse(De.data),Se=Zr(De,_t,vt(De.type,_t));if(!Se)continue;const Re=Fe.current.get(De.id);Te.push({id:De.id,x:Re?.x??Se.x,y:Re?.y??Se.y,width:Re?.width??Se.width,height:Re?.height??Se.height})}catch{}const Ze=$a({x:ge,y:Ne},Te);if(Ze){const _t={x:12,y:12,width:Math.max(0,mt.width-24),height:Math.max(0,mt.height-24)},Se=Aa(Ze,{x:ge,y:Ne},_t,Pe);gr(Se),fr.current!==Ze.id&&pr(Ze.id)}else gr(null),fr.current!==null&&pr(null)}}},f=async h=>{if(!ke.current)return;const P=ke.current.currentX,I=ke.current.currentY,X=ke.current.id,U=ke.current.data,se=ke.current.startPointerX,ae=ke.current.startPointerY,ge=Math.abs(h.clientX-se)>bn||Math.abs(h.clientY-ae)>bn,Ne=ge?Ys.current?.(h,X):!1;Qt.current?.(null);const Te=ps.current;if(gr(null),pr(null),!ge||Ne){ke.current=null,Wt(null);return}if(We){ke.current=null,Wt(null),Te&&Te.targetId&&Te.targetId!==X?Te.type==="swap"?br.current?.(X,Te.targetId):fs.current?.(X,Te.targetId,Te.type):Ps();return}const Pe=Fe.current.get(X),Ze={...nt(U,U?.radius!==void 0?"circle":"rect"),...Pe??{},x:P,y:I};if(ot(X,Ze),ke.current=null,Wt(null),i){k(!0);try{await i(X,{...U,...Pe??{},x:P,y:I}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}catch(De){console.error("Drag end update error:",De),Pe?ot(X,Pe):zs(X)}finally{k(!1)}}};return window.addEventListener("pointermove",s),window.addEventListener("pointerup",f),()=>{window.removeEventListener("pointermove",s),window.removeEventListener("pointerup",f)}},[Lt,i,t,ot,We,Xe]),a.useEffect(()=>{if(!Rs||!Mt)return;const s=h=>{if(!je.current||!zt.current)return;const P=h.clientX-je.current.startX,I=h.clientY-je.current.startY;let X=je.current.initialX,U=je.current.initialY,se=je.current.initialWidth,ae=je.current.initialHeight;const ge=150,Ne=100,{corner:Te}=je.current;if(Te==="bottom-right")se=Math.max(ge,je.current.initialWidth+P),ae=Math.max(Ne,je.current.initialHeight+I);else if(Te==="bottom-left"){const Pe=je.current.initialWidth-P;Pe>=ge&&(se=Pe,X=je.current.initialX+P),ae=Math.max(Ne,je.current.initialHeight+I)}else if(Te==="top-right"){se=Math.max(ge,je.current.initialWidth+P);const Pe=je.current.initialHeight-I;Pe>=Ne&&(ae=Pe,U=je.current.initialY+I)}else if(Te==="top-left"){const Pe=je.current.initialWidth-P;Pe>=ge&&(se=Pe,X=je.current.initialX+P);const Ze=je.current.initialHeight-I;Ze>=Ne&&(ae=Ze,U=je.current.initialY+I)}zt.current={id:je.current.id,x:X,y:U,width:se,height:ae},Nr({...zt.current})},f=async h=>{if(!je.current||!zt.current)return;const{id:P}=je.current,{x:I,y:X,width:U,height:se}=zt.current,ae=C.find(Pe=>Pe.id===P);let ge={};if(ae)try{ge=JSON.parse(ae.data)}catch{}const Ne=Fe.current.get(P),Te={...nt(ge,ge?.radius!==void 0?"circle":"rect"),...Ne??{},x:I,y:X,width:U,height:se};if(ot(P,Te),je.current=null,zt.current=null,As(null),Nr(null),ae&&i)try{k(!0),await i(P,{...ge,...Ne??{},x:I,y:X,width:U,height:se}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}catch(Pe){console.error("Resize end update error:",Pe),Ne?ot(P,Ne):zs(P)}finally{k(!1)}};return window.addEventListener("pointermove",s),window.addEventListener("pointerup",f),()=>{window.removeEventListener("pointermove",s),window.removeEventListener("pointerup",f)}},[Rs,Mt,r,i,t,ot]);const ft=s=>{x||ce({type:"confirm",title:"删除组件",message:"您确定要从白板中删除这个组件或图形吗?该操作不可撤销。",onConfirm:async()=>{k(!0);try{if(Fe.current.delete(s),St(f=>f+1),We){const f=Xe().filter(h=>h.id!==s&&Ve(h.type));f.length>0&&await Ms.current?.(f)}n?await n(s):await fetch(`/api/lessons/${t}/whiteboard/${s}`,{method:"DELETE"}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),l&&l(),me(null)}catch(f){console.error("Delete element failed:",f)}finally{k(!1),ce(null)}}})},bi=()=>{x||ce({type:"confirm",title:"清空白板",message:"您确定要清空画布上的所有组件、图形和线条吗?此操作将永久清空白板且不可逆!",onConfirm:async()=>{k(!0);try{d?await d():await fetch(`/api/lessons/${t}/whiteboard`,{method:"DELETE"}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),l&&l(),me(null)}catch(s){console.error("Clear board failed:",s)}finally{k(!1),ce(null)}}})},gi=()=>{x||ce({type:"confirm",title:"重置白板",message:"您确定要将白板重置为开始上课的状态吗?您在白板上做的所有临时修改都将被重置。",onConfirm:async()=>{k(!0);try{await fetch(`/api/lessons/${t}/whiteboard/reset`,{method:"POST"}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),l&&l(),me(null)}catch(s){console.error("Reset board failed:",s)}finally{k(!1),ce(null)}}})};a.useEffect(()=>{const s=f=>{const h=f.target,P=h.tagName==="INPUT"||h.tagName==="TEXTAREA"||h.isContentEditable;if((f.key==="Delete"||f.key==="Backspace")&&xe&&(P||(ft(xe),me(null))),We&&xe&&!P&&f.altKey){let I=null;if(f.key==="ArrowLeft"||f.key==="h"||f.key==="H"?I="left":f.key==="ArrowRight"||f.key==="l"||f.key==="L"?I="right":f.key==="ArrowUp"||f.key==="k"||f.key==="K"?I="up":(f.key==="ArrowDown"||f.key==="j"||f.key==="J")&&(I="down"),I){const X=[];let U=null;for(const se of Xe())if(Ve(se.type))try{const ae=JSON.parse(se.data),ge=Zr(se,ae,vt(se.type,ae));if(!ge)continue;const Ne=Fe.current.get(se.id),Te={id:se.id,x:Ne?.x??ge.x,y:Ne?.y??ge.y,width:Ne?.width??ge.width,height:Ne?.height??ge.height};X.push(Te),se.id===xe&&(U=Te)}catch{}if(U&&X.length>1){const se=Da(U,X,I);se&&(f.preventDefault(),f.stopPropagation(),f.shiftKey?br.current?.(xe,se.id):me(se.id))}}}};return window.addEventListener("keydown",s),()=>window.removeEventListener("keydown",s)},[xe,We,Xe]);const qs=()=>{Bt.current&&clearTimeout(Bt.current),u&&(Bt.current=setTimeout(async()=>{k(!0);try{(await fetch(`/api/lessons/${t}/ai-tutor`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({elements:C.map(f=>({type:f.type,data:JSON.parse(f.data)}))})})).ok&&(oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}),l&&l())}catch(s){console.error(s)}finally{k(!1)}},6e4))};a.useEffect(()=>(qs(),()=>{Bt.current&&clearTimeout(Bt.current)}),[r]),a.useEffect(()=>{const s=Gi();K.current=s,s.emit("join-room",t);const f=h=>{h.type==="temp-draw"?Ns(P=>({...P,[h.userId]:h.payload})):h.type==="temp-end"?Ns(P=>{const I={...P};return delete I[h.userId],I}):h.type==="refresh"?l&&l():h.type==="segment-change"?j&&h.payload?.segmentId&&j(h.payload.segmentId):h.type==="page-change"?typeof h.payload?.page=="number"&&re(h.payload.page):h.type==="page-meta-update"&&Array.isArray(h.payload?.pages)&&Ee(P=>JSON.stringify(P)===JSON.stringify(h.payload.pages)?P:h.payload.pages)};return K.current.on("whiteboard-sync",f),()=>{K.current?.off("whiteboard-sync",f)}},[t,l,j]),a.useEffect(()=>{if(!w.current)return;const s=new ResizeObserver(P=>{for(let I of P)if(w.current){const X=ln(w.current),U=X.width,se=X.height;ys(ae=>{if(U===0&&se===0&&ae.width>0&&ae.height>0)return ae;const ge=w.current.offsetWidth,Ne=w.current.offsetHeight;return ae.width===ge&&ae.height===Ne?ae:{width:ge,height:Ne}}),vs(ae=>U===0&&se===0&&ae.width>0&&ae.height>0||ae.width===U&&ae.height===se?ae:{width:U,height:se})}});s.observe(w.current);const f=()=>{if(w.current){const P=ln(w.current),I=P.width,X=P.height;ys(U=>{if(I===0&&X===0&&U.width>0&&U.height>0)return U;const se=w.current.offsetWidth,ae=w.current.offsetHeight;return U.width===se&&U.height===ae?U:{width:se,height:ae}}),vs(U=>I===0&&X===0&&U.width>0&&U.height>0||U.width===I&&U.height===X?U:{width:I,height:X})}},h=Ja();return Xn(P=>P===h?P:h),f(),window.addEventListener("resize",f),()=>{s.disconnect(),window.removeEventListener("resize",f)}},[]);const yi=s=>{if(x)return;if(qs(),Ce(null),V==="cursor"){s.target===s.target.getStage()&&me(null);return}if(y)return;wr(!0);const f=s.target.getStage().getPointerPosition();if(V==="pen"){const h=G?"#f8fafc":"black";at({type:"pen",points:[f.x,f.y],color:h})}else if(V==="highlighter")at({type:"highlighter",points:[f.x,f.y],color:Y});else if(V==="rect"){const h=G?"#818cf8":"blue";at({type:"rectangle",x:f.x,y:f.y,width:0,height:0,stroke:h})}else if(V==="circle"){const h=G?"#4ade80":"green";at({type:"circle",x:f.x,y:f.y,radius:0,stroke:h})}else if(V==="text"){const h=G?"#f8fafc":"black";at({type:"text",x:f.x,y:f.y,text:"Click to edit...",fontSize:16,color:h})}},wi=s=>{if(!gs||!_e)return;const f=s.target.getStage().getPointerPosition();if(_e.type==="pen"||_e.type==="highlighter")at({..._e,points:_e.points.concat([f.x,f.y])});else if(_e.type==="rectangle")at({..._e,width:f.x-_e.x,height:f.y-_e.y});else if(_e.type==="circle"){const h=Math.sqrt(Math.pow(f.x-_e.x,2)+Math.pow(f.y-_e.y,2));at({..._e,radius:h})}},vi=async()=>{if(!gs||!_e)return;wr(!1);const s={..._e,page:ve,segmentId:c};at(null),k(!0);try{await o(s.type,s),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}finally{k(!1)}};a.useEffect(()=>{!K.current||!K.current.id||(_e?K.current.emit("whiteboard-update",{roomId:t,type:"temp-draw",userId:K.current.id,payload:{..._e,page:ve,segmentId:c}}):K.current.emit("whiteboard-update",{roomId:t,type:"temp-end",userId:K.current.id}))},[_e,t,ve,c]),a.useEffect(()=>{c&&K.current&&K.current.emit("whiteboard-update",{roomId:t,type:"segment-change",payload:{segmentId:c}})},[c,t]);const $r=a.useRef(c);a.useEffect(()=>{if(xs.current){xs.current=!1,$r.current=c;return}const s=$r.current;if($r.current=c,!c||s===c||!Array.isArray(he)||he.length===0)return;const f=he[ve];if(f?.segmentId&&f.segmentId!==c){const h=he.findIndex(P=>P.segmentId===c);h!==-1&&re(h)}},[c,he,ve]);const Js=s=>{if(!s)return null;const f=s.page??0,h=he[ve];return!(s.pageId&&h?.id?s.pageId===h.id:f===ve)||c&&s.segmentId&&s.segmentId!==c?null:s.type==="pen"?e.jsx(ir,{points:s.points,stroke:s.color,strokeWidth:4,tension:.5,lineCap:"round",lineJoin:"round"}):s.type==="highlighter"?e.jsx(ir,{points:s.points,stroke:s.color||"#facc15",strokeWidth:18,tension:.5,lineCap:"round",lineJoin:"round",opacity:.5}):s.type==="rectangle"?e.jsx(Qs,{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)*S),fill:s.color}):null},ji=()=>Js(_e?{..._e,page:ve,segmentId:c}:null),Ni=()=>Object.values(Yn).map((s,f)=>e.jsx(ss.Fragment,{children:Js(s)},f)),ki=a.useCallback(async(s,f)=>{await i?.(s,f),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})},[i,t]),Is=(s,f)=>{try{const h=Le(s),P=Fe.current.get(s.id),I=Lt?.id===s.id,X=Mt?.id===s.id,U=P?.x??h.x??0,se=P?.y??h.y??0,ae=X?Mt.x:I?Lt.currentX:U,ge=X?Mt.y:I?Lt.currentY:se,Ne=T=>vt(T,h).width,Te=T=>vt(T,h).height,Pe=X?Mt.width:P?.width??h.width??Ne(s.type),Ze=X?Mt.height:h.isMinimized?36:P?.height??h.height??Te(s.type),De=f?.fullscreen,_t=!!De,Se=De?De.padding:ae,Re=De?De.padding:ge,Be=De?Math.max(240,De.width-De.padding*2):Pe,He=De?Math.max(180,De.height-De.padding*2):Ze,Ye=xe===s.id,Ei=We&&mr===s.id,Ue=!x&&!Ye?"group hover:ring-2 hover:ring-indigo-400/80 hover:shadow-2xl transition-all duration-150":"group transition-all duration-150",Qe=()=>Ei&&Gt?.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:"⇄ 松开对调位置"})})}):x||h.isMinimized?null:Ye?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"}),We&&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+方向键 换焦"})]}),!We&&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:T=>er(T,s.id,"top-left",Se,Re,Be,He),onPointerMove:tr,onPointerUp:rr}),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:T=>er(T,s.id,"top-right",Se,Re,Be,He),onPointerMove:tr,onPointerUp:rr}),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:T=>er(T,s.id,"bottom-left",Se,Re,Be,He),onPointerMove:tr,onPointerUp:rr}),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:T=>er(T,s.id,"bottom-right",Se,Re,Be,He),onPointerMove:tr,onPointerUp:rr})]})]}):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"}),xt=(T,q,te="default",be)=>({title:h.title||T,icon:q,hidden:_t,readOnly:x,isMinimized:!!h.isMinimized,isMaximized:Ke===s.id,isPropertiesOpen:Zt===s.id||Cr===s.id,themeColor:te,extraActions:be,onPointerDown:Ae=>!x&&Tr(Ae,s.id,h),onPointerMove:x?void 0:Pr,onPointerUp:x?void 0:Dr,onOpenProperties:()=>{!z&&s.type==="html-applet"?(Ot(),Ls(s.id)):(me(s.id),pt(Ae=>Ae===s.id?null:s.id))},onMinimize:async()=>{i&&(await i(s.id,{...h,isMinimized:!0}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{Ke===s.id&&ht(null),h.isMinimized&&i&&(await i(s.id,{...h,isMinimized:!1}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>ht(s.id),onBrowserFullscreen:()=>void Ct.enter(s.id),onDelete:()=>ft(s.id)});if(s.type==="plugin"){const T=N==="teacher",q=(T?h.teacherWidgetId:h.studentWidgetId)??(T?h.studentWidgetId:h.teacherWidgetId),te=T?"teacher.dashboard.widget":"student.view";return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:be=>{x||(me(s.id),be.stopPropagation())},onContextMenu:be=>{if(x){be.preventDefault(),be.stopPropagation();return}const Ae=Ge(be.clientX,be.clientY);Ae&&Ce({x:Ae.x,y:Ae.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 ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(dn,{...xt("Plugin Component",e.jsx(Br,{size:13,className:"text-indigo-600"}),"indigo"),contentClassName:"wb-widget-container flex-grow bg-white overflow-auto relative min-h-0 p-2",children:e.jsx(Va,{pluginId:h.pluginId,slot:te,widgetId:q,elementId:s.id,lessonId:t,classId:p,studentId:g,studentName:v})}),x&&e.jsx(rt,{}),!h.isMinimized&&Qe()]})})},s.id)}if(s.type==="hello-world")return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:T=>{x||(me(s.id),T.stopPropagation())},className:`bg-transparent relative rounded-lg ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(ao,{...Object.assign({elementId:s.id,data:h,readOnly:x},xt("Hello World 插件",e.jsx(Yt,{size:11,className:"text-amber-500 animate-pulse"}),"slate"),{onElementUpdate:i,lessonId:t})}),x&&e.jsx(rt,{}),!h.isMinimized&&Qe()]})})},s.id);if(s.type==="rollcall")return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:T=>{x||(me(s.id),T.stopPropagation())},onContextMenu:T=>{if(x){T.preventDefault(),T.stopPropagation();return}const q=Ge(T.clientX,T.clientY);q&&Ce({x:q.x,y:q.y,elementId:s.id})},className:`bg-transparent relative rounded-lg ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(Ka,{...Object.assign({elementId:s.id,data:h,lessonId:t,classId:L||h&&h.classId,readOnly:x,userRole:N},xt("随机点名助手 (分层抽问 Fair Picker)",e.jsx(Yt,{size:13,className:"animate-pulse text-amber-400"}),"indigo"),{onElementUpdate:i})}),x&&e.jsx(rt,{}),Qe()]})})},s.id);if(s.type==="quiz"){const T=Array.isArray(h.options)?h.options:[],q=qn[s.id]??Object.keys(h.submissions||{}).length;return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:te=>{x||(me(s.id),te.stopPropagation())},onContextMenu:te=>{if(x){te.preventDefault(),te.stopPropagation();return}const be=Ge(te.clientX,te.clientY);be&&Ce({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 ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(dt,{...xt("随堂测验 (Interactive Quiz)",e.jsx(Ir,{size:13,className:"text-indigo-500"}),"indigo"),onMaximize:()=>ht(s.id),onBrowserFullscreen:()=>void Ct.enter(s.id)}),!h.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:h.question,children:h.question||"随堂测验题目"}),T.length>0&&e.jsx("div",{className:"space-y-1",children:T.slice(0,4).map((te,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),"."]}),te]},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:x,onClick:()=>{x||ht(s.id)},children:e.jsx("span",{children:q>0?`进入测验 (${q} 人已交)`:"点击全屏答题 / 查看"})})})]}),x&&e.jsx(rt,{}),!h.isMinimized&&Qe()]})})},s.id)}if(s.type==="assignment")return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:T=>{x||(me(s.id),T.stopPropagation())},onContextMenu:T=>{if(x){T.preventDefault(),T.stopPropagation();return}const q=Ge(T.clientX,T.clientY);q&&Ce({x:q.x,y:q.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 ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(dt,{...xt("Assignment Upload Task",e.jsx(os,{size:13,className:"text-orange-500"}),"orange")}),!h.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:h.title}),e.jsx("p",{className:"text-xs text-gray-500 mb-3 line-clamp-3",children:h.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:x,onClick:()=>{if(x)return;const T=typeof h.assignmentId=="string"?h.assignmentId:"";if(T){kr(T);return}(async()=>{try{const te=await(await fetch(`/api/assignments?lessonId=${encodeURIComponent(t||"")}`)).json().catch(()=>null),be=Array.isArray(te?.assignments)?te.assignments:[],Ae=be.find(qe=>qe?.status==="published")||be[0];if(Ae?.id){kr(String(Ae.id));return}ce({type:"alert",title:"尚未发布作业",message:"教师还没有发布本课节的作业,请稍后再试。",onConfirm:()=>ce(null)})}catch(q){ce({type:"alert",title:"无法加载作业",message:q?.message?String(q.message):"请检查网络后重试。",onConfirm:()=>ce(null)})}})()},children:h.assignmentId?"提交作业":"Upload File"})]}),x&&e.jsx(rt,{}),!h.isMinimized&&Qe()]})})},s.id);if(s.type==="html-applet")return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:T=>{x||(me(s.id),T.stopPropagation())},onContextMenu:T=>{if(x){T.preventDefault(),T.stopPropagation();return}const q=Ge(T.clientX,T.clientY);q&&Ce({x:q.x,y:q.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 ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(dn,{...xt(h.title||"Interactive Courseware",e.jsx(as,{size:13,className:"text-primary-theme"}),"default"),contentClassName:"flex-1 bg-white overflow-hidden relative min-h-0",children:e.jsx(Ui,{data:h,lessonId:t,elementId:s.id,className:"w-full h-full border-none"})}),x&&e.jsx(rt,{}),!h.isMinimized&&Qe()]})})},s.id);if(s.type==="pen"){const T=xe===s.id;return e.jsx(ir,{id:s.id,points:h.points,stroke:T?D.selectionBorder||"#3b82f6":h.color&&h.color!=="black"&&h.color!=="#000000"?h.color:G?"#f8fafc":h.color||"black",strokeWidth:T?6:4,tension:.5,lineCap:"round",lineJoin:"round",draggable:N==="teacher"&&V==="cursor",onClick:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onTap:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onDragEnd:async q=>{const te=q.target,be=te.x(),Ae=te.y();te.x(0),te.y(0);const qe=h.points.map((Je,Rr)=>Rr%2===0?Je+be:Je+Ae);i&&(await i(s.id,{...h,points:qe}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="highlighter"){const T=xe===s.id;return e.jsx(ir,{id:s.id,points:h.points,stroke:T?"#3b82f6":h.color||"#facc15",strokeWidth:T?24:18,tension:.5,lineCap:"round",lineJoin:"round",opacity:.5,draggable:N==="teacher"&&V==="cursor",onClick:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onTap:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onDragEnd:async q=>{const te=q.target,be=te.x(),Ae=te.y();te.x(0),te.y(0);const qe=h.points.map((Je,Rr)=>Rr%2===0?Je+be:Je+Ae);i&&(await i(s.id,{...h,points:qe}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="rectangle"||s.type==="shape"&&h.shape==="rect"){const T=xe===s.id;return e.jsx(Qs,{id:s.id,x:P?.x??h.x,y:P?.y??h.y,width:P?.width??h.width,height:P?.height??h.height,fill:h.fill||"transparent",stroke:T?"#3b82f6":h.stroke||"blue",strokeWidth:T?3:1,draggable:N==="teacher"&&V==="cursor",onClick:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onTap:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onDragEnd:async q=>{const te=q.target,be=te.x(),Ae=te.y();te.x(0),te.y(0);const qe=(P?.x??h.x)+be,Je=(P?.y??h.y)+Ae;i&&(ot(s.id,{...nt(h,"rect"),...P??{},x:qe,y:Je}),await i(s.id,{...h,x:qe,y:Je}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="circle"||s.type==="shape"&&h.shape==="circle"){const T=xe===s.id;return e.jsx(en,{id:s.id,x:P?.x??h.x,y:P?.y??h.y,radius:P?.radius??h.radius,fill:h.fill||"transparent",stroke:T?"#3b82f6":h.stroke||"green",strokeWidth:T?3:1,draggable:N==="teacher"&&V==="cursor",onClick:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onTap:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onDragEnd:async q=>{const te=q.target,be=te.x(),Ae=te.y();te.x(0),te.y(0);const qe=(P?.x??h.x)+be,Je=(P?.y??h.y)+Ae;i&&(ot(s.id,{...nt(h,"circle"),...P??{},x:qe,y:Je}),await i(s.id,{...h,x:qe,y:Je}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="text"){const T=xe===s.id;return e.jsx(tn,{id:s.id,x:P?.x??h.x,y:P?.y??h.y,text:h.text,fontSize:Math.round((h.fontSize||16)*S),fill:T?D.selectionBorder||"#3b82f6":h.color&&h.color!=="black"&&h.color!=="#000000"?h.color:G?"#f8fafc":h.color||"black",fontStyle:T?"bold":"normal",draggable:N==="teacher"&&V==="cursor",onClick:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onTap:q=>{V==="cursor"&&(q.cancelBubble=!0,me(T?null:s.id))},onDragEnd:async q=>{const te=q.target,be=te.x(),Ae=te.y();te.x(0),te.y(0);const qe=(P?.x??h.x)+be,Je=(P?.y??h.y)+Ae;i&&(ot(s.id,{...nt(h,"rect"),...P??{},x:qe,y:Je}),await i(s.id,{...h,x:qe,y:Je}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))}},s.id)}if(s.type==="code-sandbox")return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:T=>{x||(me(s.id),T.stopPropagation())},onContextMenu:T=>{if(x){T.preventDefault(),T.stopPropagation();return}const q=Ge(T.clientX,T.clientY);q&&Ce({x:q.x,y:q.y,elementId:s.id})},className:`relative rounded-lg shadow-xl ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(so,{elementId:s.id,data:h,readOnly:x,isMinimized:!!h.isMinimized,isMaximized:Ke===s.id,isPropertiesOpen:Zt===s.id,onOpenProperties:()=>{me(s.id),pt(T=>T===s.id?null:s.id)},onMinimize:async()=>{i&&(await i(s.id,{...h,isMinimized:!0}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{Ke===s.id&&ht(null),h.isMinimized&&i&&(await i(s.id,{...h,isMinimized:!1}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>ht(s.id),onBrowserFullscreen:()=>void Ct.enter(s.id),onElementUpdate:i?async(T,q)=>{await i(T,q),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0,onPointerDown:T=>!x&&Tr(T,s.id,h),onPointerMove:x?void 0:Pr,onPointerUp:x?void 0:Dr,onDelete:()=>ft(s.id)}),x&&e.jsx(rt,{}),Qe()]})})},s.id);if(s.type==="math-graph")return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:T=>{x||(me(s.id),T.stopPropagation())},onContextMenu:T=>{if(x){T.preventDefault(),T.stopPropagation();return}const q=Ge(T.clientX,T.clientY);q&&Ce({x:q.x,y:q.y,elementId:s.id})},className:`relative rounded-lg shadow-xl ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(io,{elementId:s.id,data:h,readOnly:x,isMinimized:!!h.isMinimized,isMaximized:Ke===s.id,isPropertiesOpen:Zt===s.id,onOpenProperties:()=>{me(s.id),pt(T=>T===s.id?null:s.id)},onMinimize:async()=>{i&&(await i(s.id,{...h,isMinimized:!0}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onRestore:async()=>{Ke===s.id&&ht(null),h.isMinimized&&i&&(await i(s.id,{...h,isMinimized:!1}),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t}))},onMaximize:()=>ht(s.id),onBrowserFullscreen:()=>void Ct.enter(s.id),onElementUpdate:i?async(T,q)=>{await i(T,q),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0,onPointerDown:T=>!x&&Tr(T,s.id,h),onPointerMove:x?void 0:Pr,onPointerUp:x?void 0:Dr,onDelete:()=>ft(s.id)}),x&&e.jsx(rt,{}),Qe()]})})},s.id);if(s.type==="presentation")return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:T=>{x||(me(s.id),T.stopPropagation())},onContextMenu:T=>{if(x){T.preventDefault(),T.stopPropagation();return}const q=Ge(T.clientX,T.clientY);q&&Ce({x:q.x,y:q.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 ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(dt,{...xt("Interactive Presentation",e.jsx(En,{size:13,className:"text-purple-600"}),"purple")}),!h.isMinimized&&e.jsx("div",{className:"flex-1 min-h-0 relative bg-white",style:{pointerEvents:x?"none":"auto"},children:e.jsx(a.Suspense,{fallback:e.jsx("div",{className:"absolute inset-0 flex items-center justify-center bg-white","data-testid":"presentation-loading",children:e.jsx("div",{className:"animate-spin rounded-full h-6 w-6 border-b-2 border-purple-500"})}),children:e.jsx(Yo,{elementId:s.id,data:h,userRole:N,onElementUpdate:i?ki:void 0})})}),x&&e.jsx(rt,{}),!h.isMinimized&&Qe()]})})},s.id);const Dt=s.type==="whiteboard.renderer"?h.rendererType||h.type||"whiteboard.renderer":s.type,Zs=ie?.find(T=>{const q=T;return q.targetType===Dt||T.id===Dt||T.route===Dt||`${T.pluginId}/${T.id}`===Dt||q.slotProps?.elementType===Dt||q.slotProps?.targetType===Dt});if(Zs){const T=!!h.frameless,q=!!(h.hideTitleBar||T);return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:te=>{x||(me(s.id),te.stopPropagation())},onContextMenu:te=>{if(x){te.preventDefault(),te.stopPropagation();return}const be=Ge(te.clientX,te.clientY);be&&Ce({x:be.x,y:be.y,elementId:s.id})},className:T?`overflow-hidden flex flex-col font-sans text-sm relative ${Ue}`:`bg-white border border-gray-300 rounded-lg shadow-xl overflow-hidden flex flex-col font-sans text-sm relative ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[!q&&e.jsx(dt,{...xt(h.title||Zs.label||s.type,e.jsx(Br,{size:13,className:"text-indigo-600"}),"indigo")}),!h.isMinimized&&e.jsx("div",{className:`wb-widget-container flex-1 overflow-hidden relative min-h-0 ${T?"":"bg-white"}`,style:{pointerEvents:x?"none":"auto"},children:e.jsx(ze,{slot:"whiteboard.renderer",slotProps:{element:s,elementId:s.id,elementType:Dt,data:h,width:Be,height:He,isSelected:Ye,readOnly:x,userRole:N,lessonId:t,classId:p,onElementUpdate:i?async(te,be)=>{await i(te,be),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t},timestamp:Date.now(),correlationId:t})}:void 0}})}),x&&e.jsx(rt,{}),!h.isMinimized&&Qe()]})})},s.id)}const Xt=dr.get(s.type);if(Xt){const T=Xt.component;return e.jsx(et,{children:e.jsx(tt,{divProps:{style:{position:"absolute",top:`${Re}px`,left:`${Se}px`,pointerEvents:"none",zIndex:Ye?20:10}},children:e.jsxs("div",{onPointerDown:q=>{x||(me(s.id),q.stopPropagation())},onContextMenu:q=>{if(x){q.preventDefault(),q.stopPropagation();return}const te=Ge(q.clientX,q.clientY);te&&Ce({x:te.x,y:te.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 ${Ue}`,style:{pointerEvents:x?"none":"auto",userSelect:x?"none":"auto",width:`${Be}px`,height:`${He}px`},children:[e.jsx(dt,{...xt(Xt.labelZh||s.type,e.jsx(Br,{size:13,className:"text-indigo-600"}),"indigo")}),!h.isMinimized&&e.jsx("div",{className:"wb-widget-container flex-1 bg-white overflow-hidden relative min-h-0",style:{pointerEvents:x?"none":"auto"},children:T?e.jsx(T,{elementId:s.id,lessonId:t,data:h,userRole:N,onElementUpdate:i?async(q,te)=>{await i(q,te),oe.publish({id:le(),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:Xt.labelZh}),e.jsx("div",{className:"text-xs mt-1 text-gray-400",children:Xt.descriptionZh}),h.title&&e.jsx("div",{className:"mt-2 text-xs bg-gray-100 px-2 py-1 rounded",children:h.title})]})}),x&&e.jsx(rt,{}),!h.isMinimized&&Qe()]})})},s.id)}}catch(h){console.error(h)}return null},{isDragOverBoard:Gs,setIsDragOverBoard:Ci,handleWhiteboardDragOver:Us,handleWhiteboardDragEnter:Vs,handleWhiteboardDragLeave:Si,addElementAtCenter:zi,handleWhiteboardDrop:Ks}=Oo({lessonId:t,currentPage:ve,activeSegmentId:c,whiteboardRenderers:ie,containerRef:w,setIsSyncing:k,onElementAdd:o,onRefresh:l}),Mi=a.useCallback(async(s,f)=>{if(f<0||f>=he.length)return;const h=C.find(I=>I.id===s);if(!h)return;const P=he[f];try{const I=JSON.parse(h.data),X=typeof I.page=="number"?I.page:ve,U={...I,page:f,pageId:P?.id};if(delete U.__tiled,delete U.tileOrder,h.data=JSON.stringify(U),Fe.current.delete(s),St(se=>se+1),i&&await i(s,U),We){const se=C.filter(ae=>{if(ae.id===s||!Ve(ae.type))return!1;try{const ge=JSON.parse(ae.data);return!((typeof ge.page=="number"?ge.page:0)!==X||c&&ge.segmentId&&ge.segmentId!==c)}catch{return X===0}});se.length>0&&await Et(se)}me(null),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,targetPage:f},timestamp:Date.now(),correlationId:t})}catch(I){console.error("Failed to move element to page:",I)}},[he,C,ve,c,We,Et,i,t]),Ti=a.useCallback(async(s,f)=>{const h=C.find(P=>P.id===s);if(h)try{const P=JSON.parse(h.data),I=P.segmentId??c,X={...P,segmentId:f};if(delete X.__tiled,delete X.tileOrder,h.data=JSON.stringify(X),Fe.current.delete(s),St(U=>U+1),i&&await i(s,X),We){const U=C.filter(se=>{if(se.id===s||!Ve(se.type))return!1;try{return!((JSON.parse(se.data).segmentId??"")!==(I??"")||!ut(se))}catch{return!1}});U.length>0&&await Et(U)}me(null),oe.publish({id:le(),type:"whiteboard.element_updated",source:"whiteboard",payload:{lessonId:t,elementId:s,targetSegmentId:f},timestamp:Date.now(),correlationId:t})}catch(P){console.error("Failed to move element to segment:",P)}},[C,c,ut,We,Et,i,t]);a.useImperativeHandle(A,()=>({addElementAtCenter:zi,applyAutoTiling:Ps,switchPage:xr,addPage:ls,deletePage:us,renamePage:cs,duplicatePage:ds,movePage:hs,moveElementToPage:Mi,moveElementToSegment:Ti}));const Pi=a.useCallback(s=>{an(w.current,()=>{xr(s)})},[xr]),Di=a.useCallback(()=>{an(w.current,()=>{Ts()})},[Ts]),sr=!!(Ke||kt),bt=!x&&xe&&!Oe&&!sr?C.find(s=>s.id===xe):void 0,gt=bt?Le(bt):null,Er=bt&&gt?on(Number(gt.x??40),Number(gt.y??40)>52?Number(gt.y??40)-44:Number(gt.y??40)+Number(gt.height??120)+8,260,40,mt.width||1e3,mt.height||800):null,_r=Oe?on(Oe.x,Oe.y,176,Oe.elementId?220:280,mt.width||1e3,mt.height||800):null,nr=Oe?.elementId?C.find(s=>s.id===Oe.elementId)??null:null,$i=nr?Le(nr):null;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:Us,onDragEnter:Vs,onDrop:Ks,children:[!x&&e.jsx(oo,{tool:V,setTool:H,setSelectedShapeId:me,highlighterColor:Y,setHighlighterColor:m,onElementAdd:o,currentPage:ve,activeSegmentId:c,lessonId:t,safeElements:C,selectedShapeId:xe,showGrid:ms,setShowGrid:Hn,autoTileEnabled:We,onToggleAutoTile:Di,readOnly:x,userRole:N,isSyncing:y,setIsSyncing:k,handleClearBoard:bi,handleResetBoard:gi,handleElementDelete:ft,setDialog:ce,setDialogInput:ye,onRefresh:l,classroomTools:$,onExecuteTool:M}),e.jsxs("div",{ref:w,"data-testid":"whiteboard-canvas-viewport","data-wb-readonly":x?"true":"false","data-wb-layout":We?"tiled":"free",className:"wb-scoped-transition-root wb-canvas-scope flex-1 min-h-0 min-w-0 rounded-xl border border-theme/80 relative overflow-auto w-full shadow-inner transition-colors",style:{backgroundImage:ms?`radial-gradient(${D.gridDot} 1.2px, transparent 1.2px)`:"none",backgroundSize:"24px 24px",backgroundColor:D.background,"--wb-readonly":x?"true":"false","--wb-layout":We?"tiled":"free","--wb-density":x?"compact":"comfortable"},onDragOver:Us,onDragEnter:Vs,onDragLeave:Si,onDrop:async s=>{Ci(!1),await Ks(s)},children:[e.jsx("div",{"data-testid":"whiteboard-stage-sizer","aria-hidden":"true",className:"pointer-events-none",style:{width:Kt.width,height:Kt.height}}),Gs&&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(Co,{isVisible:C.filter(s=>{if(s.type==="page_meta")return!1;try{const f=JSON.parse(s.data),h=f.page??0,P=he[ve];return!(!(f.pageId&&P?.id?f.pageId===P.id:h===ve)||c&&f.segmentId&&f.segmentId!==c)}catch{return ve===0}}).length===0&&!Ke&&!kt}),e.jsxs("div",{"data-testid":"whiteboard-stage-host",className:"absolute inset-0 w-full h-full",style:{pointerEvents:Gs||x?"none":"auto"},children:[e.jsx(To,{containerSize:mt,browserFullscreenElementId:kt,isRemoteBrowserFullscreen:Ut,isBrowserFullscreenDismissible:Vn,browserFullscreen:Ct,effectiveFullscreenElementId:Ke,isRemoteFullscreen:Nt,isFullscreenDismissible:Un,applyFullscreen:ht,safeElements:C,lessonId:t,readOnly:x,renderElement:Is,children:e.jsx(yn,{width:Kt.width,height:Kt.height,onMouseDown:yi,onMousemove:wi,onMouseup:vi,onContextMenu:s=>{s.evt.preventDefault();const f=Ge(s.evt.clientX,s.evt.clientY);if(f){const{x:h,y:P}=f,X=s.target.id();X?(me(X),Ce({x:h,y:P,elementId:X})):Ce({x:h,y:P})}},ref:On,className:"w-full h-full cursor-crosshair",children:e.jsxs(wn,{children:[Xe().map(s=>Is(s)),ji(),Ni()]})})}),e.jsx(Po,{autoTileEnabled:We,readOnly:x,tilingSplitters:Kn,activeSplitterDrag:Zn,activeDropZoneAction:Gt,handleSplitterPointerDown:Qn}),bt&&gt&&Er&&e.jsx("div",{"data-testid":"whiteboard-selection-toolbar",style:{left:`${Er.left}px`,top:`${Er.top}px`,pointerEvents:"auto"},className:"empty:hidden absolute z-30 flex items-center gap-1 bg-surface/95 backdrop-blur-md border border-theme rounded-xl shadow-lg px-1.5 py-1 text-main",onClick:s=>s.stopPropagation(),onPointerDown:s=>s.stopPropagation(),children:e.jsx(ze,{slot:"whiteboard.selection.toolbar",slotProps:{element:bt,elementId:bt.id,elementType:bt.type,data:gt,lessonId:t,classId:p,onElementUpdate:i,onOpenProperties:()=>pt(bt.id),onDelete:ft}})}),!x&&Oe&&_r&&e.jsxs("div",{style:{left:`${_r.left}px`,top:`${_r.top}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:[Oe.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=Oe.elementId;s&&(me(s),pt(s)),Ce(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=Oe.elementId;s&&(ft(s),xe===s&&me(null)),Ce(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(jt,{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:()=>{H("cursor"),Ce(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 ${V==="cursor"?"text-primary-theme":"text-main"}`,children:[e.jsx(Mn,{size:14}),"选择工具 (Cursor)"]}),e.jsxs("button",{onClick:()=>{H("pen"),Ce(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 ${V==="pen"?"text-primary-theme":"text-main"}`,children:[e.jsx(Tn,{size:14}),"画笔工具 (Pen)"]}),e.jsxs("button",{onClick:()=>{H("highlighter"),Ce(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 ${V==="highlighter"?"text-primary-theme":"text-main"}`,children:[e.jsx(Pn,{size:14}),"高亮荧光笔 (Highlighter)"]}),e.jsxs("button",{onClick:()=>{H("rect"),Ce(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 ${V==="rect"?"text-primary-theme":"text-main"}`,children:[e.jsx(ns,{size:14}),"矩形工具 (Rectangle)"]}),e.jsxs("button",{onClick:()=>{H("circle"),Ce(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 ${V==="circle"?"text-primary-theme":"text-main"}`,children:[e.jsx(Dn,{size:14}),"圆形工具 (Circle)"]}),e.jsxs("button",{onClick:()=>{H("text"),Ce(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 ${V==="text"?"text-primary-theme":"text-main"}`,children:[e.jsx($n,{size:14}),"文本工具 (Text)"]})]}),e.jsx("div",{className:"empty:hidden border-t border-theme mt-1 pt-1",children:e.jsx(ze,{slot:"whiteboard.context_menu",slotProps:{target:Oe.elementId?"element":"canvas",element:nr,elementId:Oe.elementId??null,elementType:nr?.type??null,data:$i,point:{x:Oe.x,y:Oe.y},lessonId:t,classId:p,onElementUpdate:i,onClose:()=>Ce(null)}})})]}),e.jsx("div",{className:"absolute inset-0 pointer-events-none z-20 overflow-hidden",inert:sr?!0:void 0,children:e.jsx(ze,{slot:"whiteboard.canvas.widget",slotProps:{lessonId:t,classId:p,userRole:N,readOnly:x}})}),e.jsx("div",{className:"absolute bottom-4 left-4 z-30 pointer-events-auto flex items-center gap-2",inert:sr?!0:void 0,children:e.jsx(ze,{slot:"whiteboard.dock.plugin",slotProps:{lessonId:t,classId:p,userRole:N,readOnly:x}})})]}),!x&&!F&&e.jsx("div",{inert:sr?!0:void 0,children:e.jsx(lo,{pages:he,currentPage:ve,activeSegmentId:c,showPageDrawer:we,setShowPageDrawer:Me,editingPageIdx:R,setEditingPageIdx:Q,editingPageTitle:pe,setEditingPageTitle:ue,activeMenuPageIdx:fe,setActiveMenuPageIdx:Ie,safeElements:C,handleSwitchPage:Pi,handleRenamePage:cs,handleDuplicatePage:ds,handleMovePage:hs,handleDeletePage:us,handleAddPage:ls})})]}),e.jsx(co,{dialog:Z,dialogInput:$e,setDialogInput:ye,setDialog:ce}),Fs&&e.jsx(po,{assignmentId:Fs,onClose:()=>kr(null),lang:"zh"}),e.jsx(Eo,{showEntrySelector:ii,setShowEntrySelector:Os,zipUploadInfo:si,zipCandidates:ti,handlePropsUpdate:Xs,fetchCoursewares:Ot}),e.jsx(_o,{isOpen:!!Cr,onClose:()=>Ls(null),element:C.find(s=>s.id===Cr)||null,coursewares:Hs,fetchCoursewares:Ot,onApplyTemporary:ai,onSavePermanent:oi})]}),N==="teacher"&&t&&e.jsx(va,{lessonId:t,defaultCollapsed:!0}),e.jsx(ko,{isEditMode:z,selectedShapeId:xe,setSelectedShapeId:me,activePropertiesElementId:Zt,setActivePropertiesElementId:pt,safeElements:C,editingProperties:Tt,handleLocalPropChange:di,handlePropBlur:ui,handleNumericPropBlur:hi,handlePropsUpdate:Xs,handleUpdateElementData:Pt,handleElementDelete:ft,handleUndoProp:li,handleRedoProp:ci,propertyUndoStack:Ws,propertyRedoStack:Bs,isSyncing:y,lessonId:t,classId:p,fullscreenBroadcastClassId:L,coursewares:Hs,fetchCoursewares:Ot,setZipCandidates:ri,setZipUploadInfo:ni,setShowEntrySelector:Os,handleAddOption:pi,handleRemoveOption:fi,handleOptionChangeLocal:xi,handleOptionBlur:mi})]})});export{nl as DEFAULT_WHITEBOARD_PAGES,bn as DRAG_ACTIVATION_THRESHOLD_PX,il as InteractiveWhiteboard};