Files
IOT_SIM/web/src/editor/works.ts
T
xuyueandClaude Opus 5.5 7cec273d58 第 2 阶段:账号与班级,作品保存在服务器
- SQLite(bun:sqlite,编号迁移):班级、用户、会话(只存令牌哈希)、作品
- 登录取代统一访问口令:老师账号由配置设定;接口和 WebSocket 都要登录;按 IP 限制输错次数
- 班级管理页:建班、改名、删除(有学生时不能删);上传 CSV 名单导入(兼容 GBK / UTF-8,
  识别表头,标出被 Excel 变成科学计数法的学号),密码留空生成 6 位数字;查看、重置密码,
  导出带密码的名单
- 学生作品自动保存到服务器(按账号和实验),显示保存状态;离开页面前立即保存
- 前端加路由:登录页、实验页、班级管理页
- 部署:TEACHER_PASSWORD 必填,数据库放在数据卷

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 17:36:11 +08:00

22 lines
822 B
TypeScript

// 学生的作品保存在服务器上(按账号),换电脑登录也能接着做。
// key 标识是哪个实验,如 "sample:p2-t1-LED显示屏"。
import type { SourceFile } from '@iot/shared'
import { api } from '../api'
export const sampleWorkKey = (sampleId: string) => `sample:${sampleId}`
const url = (key: string) => `/api/works/${encodeURIComponent(key)}`
export async function loadWork(key: string): Promise<SourceFile[] | null> {
return (await api<{ files: SourceFile[] } | null>('GET', url(key)))?.files ?? null
}
/** keepalive:页面关闭时也把请求发出去 */
export async function saveWork(key: string, files: SourceFile[], keepalive = false) {
await api('PUT', url(key), { files }, { keepalive })
}
export async function deleteWork(key: string) {
await api('DELETE', url(key))
}