From 6a18bdf2e421e4e6187f9776336a81a33d35a94c Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Wed, 28 Oct 2026 12:58:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=9C=BA=E6=88=BF=E7=9A=84?= =?UTF-8?q?=20Chrome=2094=EF=BC=9A=E6=89=93=E5=8C=85=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E6=94=B9=E6=88=90=20Chrome=20/=20Edge=2094=EF=BC=9Bpolyfills.t?= =?UTF-8?q?s=20=E8=A1=A5=20crypto.randomUUID=EF=BC=88http=20=E6=89=93?= =?UTF-8?q?=E5=BC=80=E6=97=B6=E6=B2=A1=E6=9C=89=EF=BC=89=E3=80=81structure?= =?UTF-8?q?dClone=EF=BC=88=E5=8F=AA=E5=A4=8D=E5=88=B6=E6=99=AE=E9=80=9A?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=EF=BC=89=E3=80=81findLast=20/=20findLastInde?= =?UTF-8?q?x=EF=BC=9Bvite.config.ts=20=E5=8A=A0=E5=B0=8F=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=EF=BC=8C=E6=8A=8A=E4=BB=A3=E7=A0=81=E5=9D=97=E4=B9=8B=E9=97=B4?= =?UTF-8?q?=E7=9A=84=20import("./X.js")=20=E6=94=B9=E6=88=90=20/assets/=20?= =?UTF-8?q?=E5=BC=80=E5=A4=B4=E7=9A=84=E7=BB=9D=E5=AF=B9=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=EF=BC=88Chrome=2094=20=E6=9C=89=E6=97=B6=E7=9B=B8=E5=AF=B9?= =?UTF-8?q?=E7=BD=91=E9=A1=B5=E5=9C=B0=E5=9D=80=E8=A7=A3=E6=9E=90=EF=BC=8C?= =?UTF-8?q?=E6=8B=BF=E5=88=B0=E9=A6=96=E9=A1=B5=20HTML=20=E4=B8=80?= =?UTF-8?q?=E7=89=87=E7=A9=BA=E7=99=BD=EF=BC=89=EF=BC=8C=E6=94=B9=E8=BF=87?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81=E5=9D=97=E6=8D=A2=E6=96=B0=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=90=8D=EF=BC=9B=E5=AE=B9=E5=99=A8=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=94=B9=E6=88=90=20ResizeObserver=20=E9=87=8F=E5=AE=BD?= =?UTF-8?q?=E5=BA=A6=E5=8A=A0=20class=EF=BC=88=E5=AE=9E=E8=AE=AD=E5=8F=B0?= =?UTF-8?q?=E4=B8=89=E6=A1=A3=E5=B8=83=E5=B1=80=E3=80=81=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8=E7=AA=84=E6=97=B6=E9=9A=90=E8=97=8F=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=EF=BC=89=EF=BC=9B:has()=20=E6=94=B9=E6=88=90=20class=EF=BC=88?= =?UTF-8?q?=E5=8F=AA=E8=AF=BB=E3=80=81=E7=A6=81=E7=94=A8=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E6=A1=86=E7=81=B0=E5=BA=95=EF=BC=8C=E6=B2=A1=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E7=9A=84=E5=88=86=E7=BB=84=E6=A1=86=EF=BC=89=E3=80=82=E6=97=A7?= =?UTF-8?q?=E6=B5=8F=E8=A7=88=E5=99=A8=E6=8F=90=E7=A4=BA=E6=94=B9=E6=88=90?= =?UTF-8?q?=2094=20=E4=BB=A5=E4=B8=8A=EF=BC=8C=E8=AE=BE=E8=AE=A1=E6=96=B9?= =?UTF-8?q?=E6=A1=88=E8=AE=B0=E5=BD=95=E5=AE=9E=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/设计方案.md | 3 +- web/src/designer/FormDesigner.vue | 9 ++--- web/src/main.ts | 1 + web/src/polyfills.ts | 47 +++++++++++++++++++++++++ web/src/scene/TrainingBoard.vue | 57 +++++++++++++++++-------------- web/src/winforms/ControlView.vue | 11 ++++-- web/src/winforms/winforms.css | 8 ++--- web/vite.config.ts | 35 +++++++++++++++++-- 8 files changed, 130 insertions(+), 41 deletions(-) create mode 100644 web/src/polyfills.ts diff --git a/docs/设计方案.md b/docs/设计方案.md index 3882108..8a3653b 100644 --- a/docs/设计方案.md +++ b/docs/设计方案.md @@ -326,13 +326,14 @@ flowchart TB - **手动备份与恢复**:`deploy/backup.sh` 把平台数据库和每个学生的库(SQLite 一致读取)导出到宿主机的 `backups/<日期时间>/`;`deploy/restore.sh` 先备份现在的数据,再停平台、替换(删掉旧库的 -wal 文件)、启动。本机 Docker 实测备份、改数据、恢复后数据回到备份时的样子。 - **WebSocket 心跳与断线重连**:线上前面的 Nginx Proxy Manager 默认 60 秒没数据就断开 WebSocket(本机用默认配置的 nginx 实测),学生的窗体开着一分钟不操作,程序就被结束、点了没反应。服务器改为 30 秒没收到数据就发 ping(Bun 的 idleTimeout),经 nginx 空闲 150 秒仍连着。连接意外断开时(部署重启、网络抖动),运行区显示"正在重新连接…",清掉已经失效的窗体,按 1、2、4…最长 10 秒的间隔自动重连;连上后提示"刚才的程序已经结束,请重新运行",实训台恢复。 - **登录失败的限制**:原来按 IP 计数、任何人登录成功就清零,学生用自己的账号登录一次就能接着猜同学的 6 位数字密码。改为同一个账号 10 分钟输错 10 次只锁这个账号(同班其他人不受影响),同一 IP 10 分钟 300 次(登录成功不清零)。 - - **旧浏览器提示**:网页按 Chrome / Edge 107 以上打包,机房的旧浏览器或 360 浏览器的兼容模式会一片空白。index.html 里用老写法的一段脚本:网页程序有语法错误时说明浏览器太旧、怎么切换极速模式,并显示浏览器版本字符串方便老师排查;15 秒还没显示出来时提示正在加载。 + - **旧浏览器提示**:网页按 Chrome / Edge 94 以上打包(机房电脑是 Chrome 94,见 2026-10-28),更旧的浏览器或 360 浏览器的兼容模式会一片空白。index.html 里用老写法的一段脚本:网页程序有语法错误时说明浏览器太旧、怎么切换极速模式,并显示浏览器版本字符串方便老师排查;15 秒还没显示出来时提示正在加载。 - **使用说明**(`/help`,没登录也能看):学生部分讲登录、自由练习和作业、设计器、运行、实训台、自己检查和提交、数据库;老师登录后多出建班导入名单、布置作业、评阅和成绩、上课前后的注意事项;最后是常见问题。登录页和各页顶栏都有入口,在新标签页打开,不打断正在做的事;可以直接打印。 - **首次打开的下载量**:实验页第一次打开约 1.5 MB(压缩后,代码编辑器 Monaco 占 1 MB),之后浏览器长期缓存。全班 45 人同时第一次打开约 70 MB,服务器公网带宽 5 Mbps 时要近 2 分钟。 - 2026-10-26:**任务说明**。每个实验一份 `task.md`(任务目标、界面和控件名表格、实现步骤、和书上不一样的地方、在平台上怎么试),用自己的话精简写,详细过程标出书页,不照搬书上原文。工具栏"评价项"改成"**任务**":右侧面板上面是任务说明,下面是评价项和"自己检查";面板不遮挡页面、可以拖宽,开着也能搭界面、写代码;第一次打开一个实验(或作业)时自动打开(记在浏览器里)。渲染用自己写的 Markdown 子集(标题、段落、两级列表、表格、提示框、加粗、代码),先转义全部 HTML。布置作业时任务说明随作业保存,老师可以改写;以前布置的作业用实验现在的说明。测试检查任务说明表格里的控件名都在示例的 Designer.cs 里。先写了项目 3 任务 2、项目 6 任务 2 两份样板,随后补齐其余 21 份(23 个实验全部有说明)。 - 2026-10-26:**窗体改名**。23 个示例里 11 个的主窗体不叫 Form1(Login、frm_analog、frm_LED、frm_control、Main),学生的空白工程却只有 Form1,以前属性窗口改不了窗体名(项目 8 任务 2 的评分还要找 Main 窗体)。现在选中窗体可以改"名称":和 VS 一样,类名、构造函数、各文件里的 `new X()` 和 X 类型的变量都改(跳过字符串和注释),Designer.cs 里窗体的块头注释和 `this.Name` 也改,两个文件跟着改名;事件处理方法名(如 Form1_Load)和窗体标题不变。改名不进设计器的撤销历史。任务说明里提示先改名再双击窗体生成 Load 事件。 - 2026-10-26:代码用 **bun fmt** 格式化,格式写在 `bunfig.toml`(不写分号、单引号、一行最长 160,和原来的写法一致);`docs/教材摘要/` 是书上的摘录,不格式化。 +- 2026-10-28:**兼容机房的 Chrome 94**。用 Chromium 94 实测,打开 http 地址时实验页报 `crypto.randomUUID is not a function`(这个函数只在 https 和 localhost 下有);还时好时坏地一片空白:Chrome 94 在 Promise 回调里调用 `import()`(Vite 的预加载就是这样)时,有时把 `import("./X.js")` 相对于网页地址解析,请求 `/X.js` 拿到首页 HTML。改法:打包目标改成 Chrome / Edge 94;`web/src/polyfills.ts` 补上 `crypto.randomUUID`、`structuredClone`(只复制普通数据)、`findLast` / `findLastIndex`;`vite.config.ts` 的小插件在 Vite 找完预加载依赖之后把代码块之间的 `import("./X.js")` 改成 `import("/assets/X.js")`,改过的代码块换新文件名(不用缓存里的旧文件);容器查询(Chrome 105)改成 ResizeObserver 量宽度加 class(实训台的三档布局、设计器窄时隐藏提示文字);`:has()`(Chrome 105)改成 class(只读和禁用的文本框灰底、没标题的分组框)。Monaco 自带的几条 `:has()`、`color-mix()` 样式在 Chrome 94 里不生效,只影响 Markdown 悬停提示里的复选框等细节。实测 Chrome 94 经 http 打开登录、实验页(设计器改属性、代码补全、运行程序)、数据库、班级管理、使用说明,各页面直接打开 5 遍都正常。 ## 技术风险与待确认事项 diff --git a/web/src/designer/FormDesigner.vue b/web/src/designer/FormDesigner.vue index c921020..f21b6fe 100644 --- a/web/src/designer/FormDesigner.vue +++ b/web/src/designer/FormDesigner.vue @@ -529,7 +529,7 @@ const noop = () => {}
- 拖动工具箱里的控件到窗体上;双击控件生成事件处理方法;Delete 删除