diff --git a/runtime/Sim.WinForms/Resources/README.md b/runtime/Sim.WinForms/Resources/README.md index 501d895..19be07f 100644 --- a/runtime/Sim.WinForms/Resources/README.md +++ b/runtime/Sim.WinForms/Resources/README.md @@ -2,6 +2,6 @@ 学生在"项目资源"里添加的图片和声音(`Properties.Resources.xxx`),名字和尺寸与教材一致,全部由平台自绘或合成(不使用教材配套资料里的素材)。 -- `gallery/`:发布给运行器和网页的文件,`index.json` 是清单(名字、文件、中文说明、类型)。 +- `gallery/`:发布给运行器和网页的文件,`index.json` 是清单(名字、文件、中文说明、类型;图片还有编号 key 和两倍图 hidpi,由 `build-gallery.sh` 写入)。`name.png` 是原尺寸,学生程序读到的就是它;`name.2x.png` 只给高分辨率屏幕的浏览器显示用,宽高仍按原尺寸。 - `svg/`:图片的源文件;`project8.py` 生成项目 8 的那些 SVG。改了以后运行 `python3 project8.py && sh build-gallery.sh` 重新生成 PNG(需要 rsvg-convert 和思源黑体)。 - `gallery/ring.mp3`:用 ffmpeg 合成的门铃声(叮—咚),命令见提交记录。 diff --git a/runtime/Sim.WinForms/Resources/build-gallery.sh b/runtime/Sim.WinForms/Resources/build-gallery.sh index 32adb61..e218232 100644 --- a/runtime/Sim.WinForms/Resources/build-gallery.sh +++ b/runtime/Sim.WinForms/Resources/build-gallery.sh @@ -1,6 +1,23 @@ #!/bin/sh -# 把 svg/ 下的素材渲染成 gallery/ 下的 PNG(尺寸取 SVG 自己的 width / height)。需要 rsvg-convert 和思源黑体等中文字体。 +# 把 svg/ 下的素材渲染成 gallery/ 下的 PNG:name.png 是原尺寸(学生程序读到的图片,宽高和教材一致), +# name.2x.png 是两倍尺寸(只给高分辨率屏幕的浏览器显示用)。然后把每张图的编号(原尺寸 PNG 的 SHA-1, +# 和运行器给图片的编号相同)和两倍图的文件名写进 gallery/index.json。需要 rsvg-convert 和思源黑体等中文字体。 cd "$(dirname "$0")" for f in svg/*.svg; do - rsvg-convert "$f" -o "gallery/$(basename "$f" .svg).png" + name=$(basename "$f" .svg) + rsvg-convert "$f" -o "gallery/$name.png" + rsvg-convert -z 2 "$f" -o "gallery/$name.2x.png" done +python3 - <<'PY' +import hashlib, json, os +items = json.load(open("gallery/index.json", encoding="utf-8")) +for item in items: + if item["kind"] != "image": + continue + item["key"] = hashlib.sha1(open(f"gallery/{item['file']}", "rb").read()).hexdigest() + hidpi = item["file"].replace(".png", ".2x.png") + if os.path.exists(f"gallery/{hidpi}"): + item["hidpi"] = hidpi +lines = ",\n".join(" " + json.dumps(i, ensure_ascii=False) for i in items) +open("gallery/index.json", "w", encoding="utf-8").write(f"[\n{lines}\n]\n") +PY diff --git a/runtime/Sim.WinForms/Resources/gallery/arrow_left_normal.2x.png b/runtime/Sim.WinForms/Resources/gallery/arrow_left_normal.2x.png new file mode 100644 index 0000000..00aa9ae Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/arrow_left_normal.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/arrow_right_normal.2x.png b/runtime/Sim.WinForms/Resources/gallery/arrow_right_normal.2x.png new file mode 100644 index 0000000..341a4ff Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/arrow_right_normal.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/bg_from1.2x.png b/runtime/Sim.WinForms/Resources/gallery/bg_from1.2x.png new file mode 100644 index 0000000..f6ece1d Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/bg_from1.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/bg_from2.2x.png b/runtime/Sim.WinForms/Resources/gallery/bg_from2.2x.png new file mode 100644 index 0000000..03ab4e7 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/bg_from2.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/bg_home.2x.png b/runtime/Sim.WinForms/Resources/gallery/bg_home.2x.png new file mode 100644 index 0000000..2b27ce7 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/bg_home.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/btn_arrow_down_normal.2x.png b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_down_normal.2x.png new file mode 100644 index 0000000..e318af1 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_down_normal.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/btn_arrow_down_press.2x.png b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_down_press.2x.png new file mode 100644 index 0000000..9de4c3b Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_down_press.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/btn_arrow_left_normal.2x.png b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_left_normal.2x.png new file mode 100644 index 0000000..1a3b91b Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_left_normal.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/btn_arrow_left_press.2x.png b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_left_press.2x.png new file mode 100644 index 0000000..ee62ad7 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_left_press.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/btn_arrow_right_normal.2x.png b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_right_normal.2x.png new file mode 100644 index 0000000..b25f29e Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_right_normal.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/btn_arrow_right_press.2x.png b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_right_press.2x.png new file mode 100644 index 0000000..4e00a8f Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_right_press.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/btn_arrow_up_normal.2x.png b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_up_normal.2x.png new file mode 100644 index 0000000..bc1c03f Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_up_normal.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/btn_arrow_up_press.2x.png b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_up_press.2x.png new file mode 100644 index 0000000..0c63238 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/btn_arrow_up_press.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/day_01.2x.png b/runtime/Sim.WinForms/Resources/gallery/day_01.2x.png new file mode 100644 index 0000000..fb2bf3e Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/day_01.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/day_02.2x.png b/runtime/Sim.WinForms/Resources/gallery/day_02.2x.png new file mode 100644 index 0000000..55f0225 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/day_02.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/ico_title.2x.png b/runtime/Sim.WinForms/Resources/gallery/ico_title.2x.png new file mode 100644 index 0000000..887ff05 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/ico_title.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/icon_02.2x.png b/runtime/Sim.WinForms/Resources/gallery/icon_02.2x.png new file mode 100644 index 0000000..25e32e4 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/icon_02.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/icon_03.2x.png b/runtime/Sim.WinForms/Resources/gallery/icon_03.2x.png new file mode 100644 index 0000000..3752de7 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/icon_03.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/icon_04.2x.png b/runtime/Sim.WinForms/Resources/gallery/icon_04.2x.png new file mode 100644 index 0000000..dc44c5e Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/icon_04.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/icon_monitor.2x.png b/runtime/Sim.WinForms/Resources/gallery/icon_monitor.2x.png new file mode 100644 index 0000000..fc15ab1 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/icon_monitor.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/index.json b/runtime/Sim.WinForms/Resources/gallery/index.json index 3f1d233..e4b331e 100644 --- a/runtime/Sim.WinForms/Resources/gallery/index.json +++ b/runtime/Sim.WinForms/Resources/gallery/index.json @@ -1,27 +1,27 @@ [ - { "name": "switch_on", "file": "switch_on.png", "label": "开关:开", "kind": "image" }, - { "name": "switch_off", "file": "switch_off.png", "label": "开关:关", "kind": "image" }, - { "name": "ring", "file": "ring.mp3", "label": "铃声", "kind": "audio" }, - { "name": "ico_title", "file": "ico_title.png", "label": "标题:智慧校园", "kind": "image" }, - { "name": "bg_home", "file": "bg_home.png", "label": "主界面背景:校园", "kind": "image" }, - { "name": "icon_02", "file": "icon_02.png", "label": "图标:校园环境", "kind": "image" }, - { "name": "icon_03", "file": "icon_03.png", "label": "图标:校园安防", "kind": "image" }, - { "name": "icon_04", "file": "icon_04.png", "label": "图标:退出", "kind": "image" }, - { "name": "day_01", "file": "day_01.png", "label": "路灯场景:亮灯", "kind": "image" }, - { "name": "day_02", "file": "day_02.png", "label": "路灯场景:灭灯", "kind": "image" }, - { "name": "bg_from1", "file": "bg_from1.png", "label": "面板背景(宽)", "kind": "image" }, - { "name": "bg_from2", "file": "bg_from2.png", "label": "面板背景(窄)", "kind": "image" }, - { "name": "icon_monitor", "file": "icon_monitor.png", "label": "监控:无画面", "kind": "image" }, - { "name": "panel_video_ctrl", "file": "panel_video_ctrl.png", "label": "监控:方向盘底座", "kind": "image" }, - { "name": "btn_arrow_up_normal", "file": "btn_arrow_up_normal.png", "label": "方向键:上", "kind": "image" }, - { "name": "btn_arrow_up_press", "file": "btn_arrow_up_press.png", "label": "方向键:上(按下)", "kind": "image" }, - { "name": "btn_arrow_down_normal", "file": "btn_arrow_down_normal.png", "label": "方向键:下", "kind": "image" }, - { "name": "btn_arrow_down_press", "file": "btn_arrow_down_press.png", "label": "方向键:下(按下)", "kind": "image" }, - { "name": "btn_arrow_left_normal", "file": "btn_arrow_left_normal.png", "label": "方向键:左", "kind": "image" }, - { "name": "btn_arrow_left_press", "file": "btn_arrow_left_press.png", "label": "方向键:左(按下)", "kind": "image" }, - { "name": "btn_arrow_right_normal", "file": "btn_arrow_right_normal.png", "label": "方向键:右", "kind": "image" }, - { "name": "btn_arrow_right_press", "file": "btn_arrow_right_press.png", "label": "方向键:右(按下)", "kind": "image" }, - { "name": "arrow_left_normal", "file": "arrow_left_normal.png", "label": "翻页:上一张", "kind": "image" }, - { "name": "arrow_right_normal", "file": "arrow_right_normal.png", "label": "翻页:下一张", "kind": "image" }, - { "name": "windowstate_closed_hover", "file": "windowstate_closed_hover.png", "label": "关闭按钮", "kind": "image" } + {"name": "switch_on", "file": "switch_on.png", "label": "开关:开", "kind": "image", "key": "6e660e1ff6fc2ff3167919bc386c300112bbce72", "hidpi": "switch_on.2x.png"}, + {"name": "switch_off", "file": "switch_off.png", "label": "开关:关", "kind": "image", "key": "5d748b614084e878d6189d22f27813477cb8f4d9", "hidpi": "switch_off.2x.png"}, + {"name": "ring", "file": "ring.mp3", "label": "铃声", "kind": "audio"}, + {"name": "ico_title", "file": "ico_title.png", "label": "标题:智慧校园", "kind": "image", "key": "8a4db5ad7bc26136ae48056d6e71fa077e36e80f", "hidpi": "ico_title.2x.png"}, + {"name": "bg_home", "file": "bg_home.png", "label": "主界面背景:校园", "kind": "image", "key": "e56bcc13f7128dec305b6012b255d63fb0f94450", "hidpi": "bg_home.2x.png"}, + {"name": "icon_02", "file": "icon_02.png", "label": "图标:校园环境", "kind": "image", "key": "fa6a1eaa87c87913803c77f928fa9c16b7f4bf6d", "hidpi": "icon_02.2x.png"}, + {"name": "icon_03", "file": "icon_03.png", "label": "图标:校园安防", "kind": "image", "key": "d085064a505544968278a85233b7d9ac23661169", "hidpi": "icon_03.2x.png"}, + {"name": "icon_04", "file": "icon_04.png", "label": "图标:退出", "kind": "image", "key": "c853d74ecab64a9ee85bdf24ccfa63e80123cce3", "hidpi": "icon_04.2x.png"}, + {"name": "day_01", "file": "day_01.png", "label": "路灯场景:亮灯", "kind": "image", "key": "05065abdb4538906bd7c86e940ab5fb02d51469d", "hidpi": "day_01.2x.png"}, + {"name": "day_02", "file": "day_02.png", "label": "路灯场景:灭灯", "kind": "image", "key": "470d523e90e188fe5c423d8cffeae6993d5528ff", "hidpi": "day_02.2x.png"}, + {"name": "bg_from1", "file": "bg_from1.png", "label": "面板背景(宽)", "kind": "image", "key": "7a8c0a16fcab37b28a66e041024b25341cc69462", "hidpi": "bg_from1.2x.png"}, + {"name": "bg_from2", "file": "bg_from2.png", "label": "面板背景(窄)", "kind": "image", "key": "52497df301d2b7e4eac0c297ce2316ef24863c47", "hidpi": "bg_from2.2x.png"}, + {"name": "icon_monitor", "file": "icon_monitor.png", "label": "监控:无画面", "kind": "image", "key": "23e6f1efc0f382c17d8a091b76531a3b5879349d", "hidpi": "icon_monitor.2x.png"}, + {"name": "panel_video_ctrl", "file": "panel_video_ctrl.png", "label": "监控:方向盘底座", "kind": "image", "key": "396443a1d8c141942c0f447e0c69786cf6ad3350", "hidpi": "panel_video_ctrl.2x.png"}, + {"name": "btn_arrow_up_normal", "file": "btn_arrow_up_normal.png", "label": "方向键:上", "kind": "image", "key": "3c8b75ad465c8a61d0279facc233a0c64b62205a", "hidpi": "btn_arrow_up_normal.2x.png"}, + {"name": "btn_arrow_up_press", "file": "btn_arrow_up_press.png", "label": "方向键:上(按下)", "kind": "image", "key": "51e1b9926d2bd611e3fda74a01231b46a930c460", "hidpi": "btn_arrow_up_press.2x.png"}, + {"name": "btn_arrow_down_normal", "file": "btn_arrow_down_normal.png", "label": "方向键:下", "kind": "image", "key": "caf46f81c15aaca788462ebc47e58df299f097d9", "hidpi": "btn_arrow_down_normal.2x.png"}, + {"name": "btn_arrow_down_press", "file": "btn_arrow_down_press.png", "label": "方向键:下(按下)", "kind": "image", "key": "88c1bea8d6fad99b14658d8265a88b04bc595006", "hidpi": "btn_arrow_down_press.2x.png"}, + {"name": "btn_arrow_left_normal", "file": "btn_arrow_left_normal.png", "label": "方向键:左", "kind": "image", "key": "a38beb2373154d0474ad1715035aec5e2adf8c3f", "hidpi": "btn_arrow_left_normal.2x.png"}, + {"name": "btn_arrow_left_press", "file": "btn_arrow_left_press.png", "label": "方向键:左(按下)", "kind": "image", "key": "47bd7a8ffc077130a8ceca627383a4647729c638", "hidpi": "btn_arrow_left_press.2x.png"}, + {"name": "btn_arrow_right_normal", "file": "btn_arrow_right_normal.png", "label": "方向键:右", "kind": "image", "key": "e69e459f54d67e2c52128015bd6cfcf0e800a893", "hidpi": "btn_arrow_right_normal.2x.png"}, + {"name": "btn_arrow_right_press", "file": "btn_arrow_right_press.png", "label": "方向键:右(按下)", "kind": "image", "key": "afb1f5fe5a14b7cef298a7d4c67c4cece9e01170", "hidpi": "btn_arrow_right_press.2x.png"}, + {"name": "arrow_left_normal", "file": "arrow_left_normal.png", "label": "翻页:上一张", "kind": "image", "key": "5a9036955f791f0c41ba52afffb5ecc640d137f1", "hidpi": "arrow_left_normal.2x.png"}, + {"name": "arrow_right_normal", "file": "arrow_right_normal.png", "label": "翻页:下一张", "kind": "image", "key": "62c53dfb3acf291ef07d6e52fcb989cd48c020b9", "hidpi": "arrow_right_normal.2x.png"}, + {"name": "windowstate_closed_hover", "file": "windowstate_closed_hover.png", "label": "关闭按钮", "kind": "image", "key": "e361965dbd881dc21511208ce11f649517e8ddb6", "hidpi": "windowstate_closed_hover.2x.png"} ] diff --git a/runtime/Sim.WinForms/Resources/gallery/panel_video_ctrl.2x.png b/runtime/Sim.WinForms/Resources/gallery/panel_video_ctrl.2x.png new file mode 100644 index 0000000..db41bbb Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/panel_video_ctrl.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/switch_off.2x.png b/runtime/Sim.WinForms/Resources/gallery/switch_off.2x.png new file mode 100644 index 0000000..cf30e1b Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/switch_off.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/switch_on.2x.png b/runtime/Sim.WinForms/Resources/gallery/switch_on.2x.png new file mode 100644 index 0000000..d1e486c Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/switch_on.2x.png differ diff --git a/runtime/Sim.WinForms/Resources/gallery/windowstate_closed_hover.2x.png b/runtime/Sim.WinForms/Resources/gallery/windowstate_closed_hover.2x.png new file mode 100644 index 0000000..eaaebf8 Binary files /dev/null and b/runtime/Sim.WinForms/Resources/gallery/windowstate_closed_hover.2x.png differ diff --git a/server/src/app.ts b/server/src/app.ts index 850bca1..f96d067 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -80,7 +80,8 @@ export function createApp(db: Database, gradingQueue: GradingQueue, aiQueue: AiQ if (!/^[\w.-]+$/.test(name)) return c.notFound() const file = Bun.file(`${dirname(config.runnerDll)}/Resources/gallery/${name}`) if (!(await file.exists())) return c.notFound() - return new Response(file, { headers: { 'Cache-Control': 'public, max-age=3600' } }) + // 清单随部署更新(新素材、图片编号),每次都向服务器确认;图片缓存一小时 + return new Response(file, { headers: { 'Cache-Control': name === 'index.json' ? 'no-cache' : 'public, max-age=3600' } }) }) // 其余接口都要先登录(请求头 Authorization: Bearer <令牌>) diff --git a/web/src/designer/ResourcesDialog.vue b/web/src/designer/ResourcesDialog.vue index 119ec14..d3f1d04 100644 --- a/web/src/designer/ResourcesDialog.vue +++ b/web/src/designer/ResourcesDialog.vue @@ -45,13 +45,20 @@ function save() {

勾选要加入项目的图片和声音(平台素材库,名字和教材一致)。代码里写 Properties.Resources.名字,图片框的"图片"属性也可以直接选。

-