diff --git a/AGENTS.md b/AGENTS.md index f86161c..4b77b69 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -32,7 +32,7 @@ CI(`ci.yml`)对每个指向 main 的 PR 跑以下全部检查。 - 安装:`npm ci` - lint:`npm run lint` - 类型检查:`npm run typecheck`(`tsc --noEmit`;lint 和测试的 TS 转译都不做类型检查,类型错误只有这一步拦得住) -- 测试:`npm test`,先 `vinext build` 生产构建,再跑 `tests/**/*.test.mjs`。 +- 测试:`npm test`,先 `vinext build` 生产构建,再跑 `tests/**/*.test.mjs`。CI 跑在 UTC,断言渲染出的日期或时分时,测试数据用 `new Date(年, 月, 日, 时, 分)` 按本地时间构造,不要写死带时区的字符串;本地可用 `TZ=UTC npm test` 复查。 - 本地开发:`npm run dev`,后端地址见 `frontend/.env.example`(默认 `http://127.0.0.1:18080`)。 **提交信息检查**(在仓库根目录下) @@ -64,6 +64,7 @@ CI(`ci.yml`)对每个指向 main 的 PR 跑以下全部检查。 - 角色导航以 `app/lib/roles.ts` 的 `navItemsForRole` 为准;`tests/rendered-html.test.mjs` 里有一份对照,改导航时两处一起改。 - 筛选项(下拉选项、标签列表)不要从当前页、已筛选的列表数据里推导:换页或加筛选后选项会消失。由后端单独接口提供,例如设备类别用 `GET /api/equipment/categories`。测试要覆盖「筛选后」和「数据在第一页之外」两种情况。 - 设备名录这类只用来装饰行的数据,不要和页面自己的数据放进同一个 `Promise.all`:名录失败会连带已经成功的行一起丢掉。用 `page.tsx` 的 `settle` 单独等待,失败时行回退到编号并单独提示;测试要覆盖「主数据成功、名录失败」。 +- 给 `.solid-button`、`.ghost-button` 这类通用类加页面专属尺寸时,选择器要带上父级(如 `.login-card .login-submit`):单个类名写在通用样式前面会按源码顺序被覆盖。jsdom 的 `getComputedStyle` 不算优先级,测不出这种覆盖,要断言样式时用 `tests/css-cascade.mjs` 的 `cascadedValue`。 - 菜单、下拉层等浮层不要渲染在 `overflow` 滚动容器里(表格外层的 `.table-scroll` 会裁掉纵向溢出),用 portal 挂到 `body` 再按触发按钮定位,参照 `EquipmentView` 的 `MoreMenu`。测试至少覆盖一行、两行和末行三种情况。 ## 编辑方式 diff --git a/frontend/app/components/LoginView.tsx b/frontend/app/components/LoginView.tsx index 5f1eacf..9a5eaf1 100644 --- a/frontend/app/components/LoginView.tsx +++ b/frontend/app/components/LoginView.tsx @@ -1,9 +1,25 @@ import type { FormEvent } from "react"; import type { ToastState } from "../lib/types"; +import { Icon, type IconName } from "./icons"; +import { roleStyle } from "./roleTag"; import { Brand, Toast } from "./ui"; type LoginState = { username: string; password: string }; +/** Seeded demo accounts (DemoUserInitializer); a card fills the form so the visitor can sign in at once. */ +export const DEMO_ACCOUNTS = [ + { role: "STUDENT", label: "学生", note: "查看设备,提交预约与报修", username: "student", password: "student123" }, + { role: "TEACHER", label: "教师", note: "审批预约,管理实验设备", username: "teacher", password: "teacher123" }, + { role: "TECHNICIAN", label: "维修员", note: "接单处理,跟踪工单进度", username: "technician", password: "tech123" }, + { role: "ADMIN", label: "管理员", note: "全局管理、支付对账与审计", username: "admin", password: "admin123" }, +] as const; + +const STORY_POINTS: { icon: IconName; text: string }[] = [ + { icon: "box", text: "设备状态一眼看清" }, + { icon: "calendar", text: "预约冲突实时拦截" }, + { icon: "wrench", text: "故障进度全程追踪" }, +]; + export function LoginView({ login, busy, toast, onLoginChange, onSubmit, onDemo }: { login: LoginState; busy: boolean; @@ -13,37 +29,45 @@ export function LoginView({ login, busy, toast, onLoginChange, onSubmit, onDemo onDemo: (username: string, password: string) => void; }) { return
-
- -
- LAB OPERATIONS GRID / 2026 -

设备预约与维护,
一张工作台搞定。

-

用清晰的排期、设备状态和维修进度,让实验室每天都按计划运转。

-
-
-
01 / 排期预约冲突实时拦截
-
02 / 设备运行状态一眼识别
-
03 / 维修故障进度全程追踪
-
-
-
- -
- SECURE ACCESS / 安全访问 -

进入设备运行台

-

使用实验室账号进入对应角色空间

- - - -
快速体验角色
-
- - - - -
-
-
+
+
+
+