完整性更新
Some checks failed
CI / build-and-test (push) Failing after 3m50s
CI / deploy (push) Has been skipped

现在已经实现了大部分基础功能
This commit is contained in:
SpecialX
2026-01-08 11:14:03 +08:00
parent 0da2eac0b4
commit 57807def37
155 changed files with 26421 additions and 1036 deletions

View File

@@ -0,0 +1,164 @@
# 学校基础数据模块School实现文档与更新记录
**日期**: 2026-01-07
**作者**: Frontend Team
**状态**: 已实现
## 1. 范围
本文档覆盖管理端「School」域的基础数据维护页面Schools / Departments / Academic Year / Grades并记录相关实现约束与关键更新遵循 [003_frontend_engineering_standards.md](file:///c:/Users/xiner/Desktop/CICD/docs/architecture/003_frontend_engineering_standards.md) 的工程规范Vertical Slice、Server/Client 边界、质量门禁)。
## 2. 路由入口Admin
School 域路由位于 `src/app/(dashboard)/admin/school/*`,均显式声明 `export const dynamic = "force-dynamic"` 以避免构建期预渲染触发数据库访问。
- `/admin/school`:入口重定向到 Classes当前落点不在 `school` 模块内)
实现:[page.tsx](file:///c:/Users/xiner/Desktop/CICD/src/app/(dashboard)/admin/school/page.tsx)
- `/admin/school/schools`:学校维护(增删改)
实现:[page.tsx](file:///c:/Users/xiner/Desktop/CICD/src/app/(dashboard)/admin/school/schools/page.tsx)
- `/admin/school/departments`:部门维护(增删改)
实现:[page.tsx](file:///c:/Users/xiner/Desktop/CICD/src/app/(dashboard)/admin/school/departments/page.tsx)
- `/admin/school/academic-year`:学年维护(增删改 + 设为当前学年)
实现:[page.tsx](file:///c:/Users/xiner/Desktop/CICD/src/app/(dashboard)/admin/school/academic-year/page.tsx)
- `/admin/school/grades`:年级维护(增删改 + 指派年级组长/教研组长)
实现:[page.tsx](file:///c:/Users/xiner/Desktop/CICD/src/app/(dashboard)/admin/school/grades/page.tsx)
- `/admin/school/grades/insights`:年级维度作业统计(跨班级聚合)
实现:[page.tsx](file:///c:/Users/xiner/Desktop/CICD/src/app/(dashboard)/admin/school/grades/insights/page.tsx)
## 3. 模块结构Vertical Slice
School 模块位于 `src/modules/school`
```
src/modules/school/
├── components/
│ ├── schools-view.tsx
│ ├── departments-view.tsx
│ ├── academic-year-view.tsx
│ └── grades-view.tsx
├── actions.ts
├── data-access.ts
├── schema.ts
└── types.ts
```
边界约束:
- `data-access.ts` 包含 `import "server-only"`,仅用于服务端查询与 DTO 组装。
- `actions.ts` 包含 `"use server"`,写操作统一通过 Server Actions 并 `revalidatePath`
- `components/*` 为 Client 交互层表单、Dialog、筛选、行级操作调用 Server Actions 并用 `sonner` toast 反馈。
## 4. 数据访问data-access.ts
实现:[data-access.ts](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/data-access.ts)
- `getSchools(): Promise<SchoolListItem[]>`
- `getDepartments(): Promise<DepartmentListItem[]>`
- `getAcademicYears(): Promise<AcademicYearListItem[]>`
- `getGrades(): Promise<GradeListItem[]>`
- join `schools` 获取 `school.name`
- 收集 `gradeHeadId/teachingHeadId` 并批量查询 `users` 以组装 `StaffOption`
- `getStaffOptions(): Promise<StaffOption[]>`
- 角色过滤 `teacher/admin`
- 排序 `name/email`,用于 Select 列表可用性
- `getGradesForStaff(staffId: string): Promise<GradeListItem[]>`
- 用于按负责人(年级组长/教研组长)反查关联年级
返回 DTO 类型定义位于:[types.ts](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/types.ts)
## 5. 写操作actions.ts
实现:[actions.ts](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/actions.ts)
通用约束:
- 输入校验:统一使用 [schema.ts](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/schema.ts) 的 Zod schema
- 返回结构:统一使用 [ActionState](file:///c:/Users/xiner/Desktop/CICD/src/shared/types/action-state.ts)
- 刷新策略:对目标页面路径执行 `revalidatePath`
Departments
- `createDepartmentAction(formData)`
- `updateDepartmentAction(departmentId, formData)`
- `deleteDepartmentAction(departmentId)`
Academic Year
- `createAcademicYearAction(formData)`
- `updateAcademicYearAction(academicYearId, formData)`
- `deleteAcademicYearAction(academicYearId)`
-`isActive=true` 时,通过事务把其它学年置为非激活,保证唯一激活学年
Schools
- `createSchoolAction(formData)`
- `updateSchoolAction(schoolId, formData)`
- `deleteSchoolAction(schoolId)`
- 删除后会同时刷新 `/admin/school/schools``/admin/school/grades`
Grades
- `createGradeAction(formData)`
- `updateGradeAction(gradeId, formData)`
- `deleteGradeAction(gradeId)`
## 6. UI 组件components/*
Schools
- 实现:[schools-view.tsx](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/components/schools-view.tsx)
- 交互:列表 + Dialog 表单(新增/编辑)+ 删除确认AlertDialog
Departments
- 实现:[departments-view.tsx](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/components/departments-view.tsx)
- 交互:列表 + Dialog 表单(新增/编辑)+ 删除确认AlertDialog
Academic Year
- 实现:[academic-year-view.tsx](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/components/academic-year-view.tsx)
- 交互:列表 + Dialog 表单(新增/编辑)+ 删除确认AlertDialog+ 设为当前学年isActive
Grades
- 实现:[grades-view.tsx](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/components/grades-view.tsx)
- 交互:列表展示 + URL 驱动筛选(搜索/学校/负责人/排序)+ Dialog 表单(新增/编辑)+ 删除确认AlertDialog
- 负责人指派:
- 年级组长gradeHeadId
- 教研组长teachingHeadId
## 7. 关键交互与规则Grades
页面入口RSC 组装)在服务端并发拉取三类数据:
- 年级列表:`getGrades()`
- 学校选项:`getSchools()`
- 负责人候选:`getStaffOptions()`
实现:[page.tsx](file:///c:/Users/xiner/Desktop/CICD/src/app/(dashboard)/admin/school/grades/page.tsx)
### 7.1 URL State筛选/排序)
Grades 列表页的筛选状态 URL 化(`nuqs`
- `q`:关键字(匹配 grade/school
- `school`:学校过滤(`all` 或具体 schoolId
- `head`:负责人过滤(全部 / 两者缺失 / 缺年级组长 / 缺教研组长)
- `sort`:排序(默认/名称/更新时间等)
实现:[grades-view.tsx](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/components/grades-view.tsx)
### 7.2 表单校验
Grades 的新增/编辑表单在客户端做轻量校验:
- 必填:`schoolId``name`
- `order`:非负整数
- 去重:同一学校下年级名称不允许重复(忽略大小写 + 规范化空格)
说明:
- 服务端写入前仍会经过 `UpsertGradeSchema` 校验schema.ts避免仅依赖客户端校验。
### 7.3 负责人选择Radix Select
Radix Select 约束:`SelectItem``value` 不能为 `""`(空字符串),否则会触发运行时错误。
当前实现策略:
- UI 中 “未设置” 选项使用占位值 `__none__`
-`onValueChange` 中将 `__none__` 映射回 `""` 存入本地表单 state
- 提交时依旧传递空字符串,由 `UpsertGradeSchema` 将其归一为 `null`
实现:[grades-view.tsx](file:///c:/Users/xiner/Desktop/CICD/src/modules/school/components/grades-view.tsx)
## 2. 更新记录2026-01-07
- 修复 Add Grades 弹窗报错:将 4 处 `<SelectItem value=\"\">` 替换为占位值 `__none__`,并在 `onValueChange` 中映射回 `\"\"`,保持“可清空选择/显示 placeholder”的行为不变。
- 修复新建年级按钮不可用:创建/编辑表单在状态变化时触发实时校验更新,避免校验状态滞后导致提交被禁用。
- 质量门禁:本地通过 `npm run lint``npm run typecheck`