文档最终交付:完成最终项目文档与Human Portal交付层

This commit is contained in:
wangzhibiao committed 2026-09-15 11:59:00 +08:00
1 parent fc08f8a2bd
commit 82da706006
35 files changed
+6700 -87

No files matched your search

+74 -34
View File
@@ -1,59 +1,91 @@
# RailwaySystem 智慧培训系统
RailwaySystem 是一套面向铁路职工与业务学员的一站式智慧培训管理系统。系统基于 Spring Boot 2.5、若依(RuoYi-Vue)底座、Vue 2.6 与国产人大金仓(KingbaseES)数据库构建,全面覆盖从学员档案、师资管理、开班排课、报到考勤、宿舍分配、门禁授权到动态考核与综合画像的全流程业务闭环。
> **当前交付候选版本 (Final Candidate)**:`5a49b2e2988bf23ca2a70568264c05b24dfda1b6`
> **远程基线分支**:`origin/feat/cicd-pipeline`
> **自动化测试覆盖**:后端单元与契约测试 154/154 PASS,核心业务主链集成用例 6/6 PASS,Kingbase 物理断言 11/11 PASS,端到端浏览器真实验收 PASS (0 阻断 / 0 异常 / Swagger 连通)。
---
## 📚 文档中心快速导航
## 📖 项目简介
本项目文档实行**业务需求与技术架构分层治理**:
| 文档中心 | 目录入口 | 核心重点内容 | 适用角色 |
| :--- | :--- | :--- | :--- |
| **业务与产品需求中心** | [doc/README.md](doc/README.md) | ★★★ [PRD V1.0 业务需求基线](doc/RailwaySystem%20智慧培训系统一期%20PRD%20V1.0.md)(正式冻结基线,32章全景规范)、原始甲供资料、历史版本演进 | 产品经理、业务方、测试、全栈开发 |
| **技术架构与系统审计中心** | [docs/README.md](docs/README.md) | ★★★ [Phase 0 真实基线与审计总结](docs/codebase-audit/17_phase0_summary.md)、18 篇全景代码与数据库实测快照报告 | 架构师、后端研发、前端研发、DBA |
RailwaySystem 是一套专为铁路职工与业务学员量身打造的一站式智慧培训管理系统。系统基于 Spring Boot 2.5、若依(RuoYi-Vue)企业级底座、Vue 2.6 前端框架以及国产人大金仓(KingbaseES)高安全数据库构建。系统全面贯穿从基础教务资源维护、开班计划编排、学员批量建档、现场开班报到、课次冲突检测、多模式考勤打卡、自动结训归档到多维学情画像与综合分析的全业务生命周期。
---
## 🛠 技术栈
## 🛠 技术架构栈
- **后端架构**:Java 8+ / Spring Boot 2.5 / Spring Security / MyBatis / PageHelper / RuoYi-Vue
- **核心培训业务模块**:`ruoyi-train`(独立封装教务、排课、考勤、计划、住宿等完整业务域逻辑与应用服务)
- **系统管理与支撑底座**:`ruoyi-system`、`ruoyi-framework`、`ruoyi-common`、`ruoyi-admin`
- **前端架构**:Vue 2.6 / Vue Router / Vuex / Element UI / Axios / ECharts
- **数据库底座**:国产人大金仓 **KingbaseES V009R003C018**(MySQL 兼容模式,JDBC 驱动 8.6.0)
- **缓存与会话**:Redis 6+
- **交互工程**:`build_ui`(当前 Final Candidate 实际构建和部署使用的 Vue 前端工程)
- **历史资产**:`RuoYi-Vue/ruoyi-ui`(若依原始/历史前端资产,不作为当前 Final Browser Acceptance 主构建源)
- **数据存储与持久化**:
- **国产主库**:人大金仓 **KingbaseES V009R003C018**(MySQL 兼容模式,驱动版本 `com.kingbase:kingbase8:8.6.0`)
- **缓存与会话**:Redis 6+(支持密码预检与分布式缓存)
- **发布与数据库增量 (Release DB Delta)**:
- 当前增量版本:`CURRENT_RELEASE_DB_DELTA = 3`(包括 `001_sys_oper_log_cost_time.sql`、`002_legacy_analytics_permissions.sql`、`003_report_attendance_action_permissions.sql`)
---
## 🔄 核心业务闭环主链
系统严格遵循业务不变量与领域模型设计,构建了从教务准备到结业归档的标准业务闭环:
```mermaid
flowchart TD
A["基础资源准备<br/>(教师/学员/课程/教室/场地/宿舍)"] --> B["培训计划 (Plan)<br/>创建开班计划 · 0:草稿"]
B --> C["本期课程 (PlanCourse)<br/>绑定课程、教师与学时"]
C --> D["参训学员 (Enrollment)<br/>名单批量导入 · 0:待报到"]
D --> E["开班发布 (Plan Publish)<br/>锁定计划配置 · 1:进行中"]
E --> F1["现场报到 (Report)<br/>人脸/刷卡/扫码核验<br/>状态更新为 1:已报到"]
E --> F2["课次排课 (Scheduling)<br/>四维时段冲突预检<br/>(教师/教室/场地/本班)"]
F1 --> G["课次考勤 (Attendance)<br/>签到/签退打卡,教师代签与请假修正留痕"]
F2 --> G
G --> H["培训结训 (Completion)<br/>计划置为 2:已结束,在读学员批量联动为 4:已完成"]
H --> I["学情分析 (Analytics - Read Only)<br/>报到统计、考勤汇总、学习时长与综合能力画像"]
```
*(注:学员宿舍安排作为生活保障支线,电子班牌作为现场多媒体与打卡硬件设备支撑)*
---
## 🧭 文档中心导航
本项目采用**人类可读文档层(Human Documentation Layer)与技术契约事实源(Contract Sources)分层治理**:
| 入口推荐 | 文档位置 | 说明与适用对象 |
| :--- | :--- | :--- |
| 🌟 **视觉化展示门户 (推荐首先访问)** | [docs/visual/index.html](docs/visual/index.html) | **纯静态可离线浏览**。面向评审专家、客户与业务方的交互式展示门户,含业务流程拓扑、系统架构图、14 大模块导览与质量看板。 |
| 📚 **人类操作手册与架构白皮书** | [docs/handbook/](docs/handbook/) | 面向项目经理、开发与测试人员的系统级手册(涵盖项目总览、业务流程、架构设计、数据模型、模块指南与部署运维)。 |
| 📑 **综合验收与测试报告** | [docs/reports/](docs/reports/) | 包含自动化集成测试报告、发版说明 (Release Notes) 与浏览器端到端验收记录。 |
| 📋 **业务需求基线中心** | [doc/README.md](doc/README.md) | ★★★ [PRD V1.0 业务需求基线](doc/RailwaySystem%20智慧培训系统一期%20PRD%20V1.0.md)(正式冻结基线,32章全景规范)、原始甲供资料、历史版本演进。 |
| 🔒 **冻结技术契约 (Source of Truth)** | [docs/api-v2/](docs/api-v2/)<br>[docs/database-v2/](docs/database-v2/) | 开发与 Agent 技术事实源。包含冻结的 REST API 契约、DTO/VO 字典、21 张物理表字段规范与权限错误码。 |
| 📋 **技术文档全景索引** | [docs/README.md](docs/README.md) | 技术文档中心主索引,提供面向不同角色(业务/研发/测试/历史审计)的精确导读。 |
---
## 🚀 快速启动指南
### 1. 运行前置条件
1. **Java**:JDK 8、11 或 17+
2. **Node.js**:Node 16+(系统已兼容适配 Node 22/OpenSSL 3.x)
3. **Redis**:本地启动 Redis 服务(默认端口 `6379`,无密码)
4. **网络/跳板机**:数据库部署在内网(`192.168.139.218:4321`),通过 Tailscale 跳板机节点 `100.70.157.41`(账号 `wzb`)建立端口转发隧道。
### 2. 一键启动(推荐)
项目根目录下已提供一键启动脚本 [start-local.sh](start-local.sh):
### 1. 环境准备
- **JDK**:Java 8、11 或 17+
- **Node.js**:Node 16+(已兼容 Node 22 与 OpenSSL 3.x)
- **Redis**:本地启动 Redis 6+ 服务(默认端口 `6379`,无密码)
- **数据库**:KingbaseES 8.6.0(通过跳板机隧道转发 `127.0.0.1:4321` 直连)
### 2. 一键本地启动(开发模式)
项目根目录下提供了全自动化本地启动脚本 [start-local.sh](start-local.sh):
```bash
cd /Users/wzb/Desktop/项目/RailwaySystem
./start-local.sh
```
脚本将自动执行:
- 检查并唤醒本地 Redis;
- 检查并建立针对 Kingbase 数据库的跳板机 SSH 端口转发(`127.0.0.1:4321`);
- 清理历史冲突端口,启动 Spring Boot 后端(端口 `8090`);
- 启动前端开发服务器(端口 `8080`)。
该脚本将自动唤醒本地 Redis、建立 Kingbase SSH 隧道、启动 Spring Boot 后端(端口 `8090`)以及启动前端工程(端口 `8080`)。
### 3. 系统默认访问入口
- **前端应用界面**:[http://localhost:8080](http://localhost:8080)
- **后端接口服务**:[http://localhost:8090](http://localhost:8090)
- **默认管理员账号**:`admin`
- **默认密码**:`admin123`
- **前端系统界面**:[http://localhost:8080](http://localhost:8080)(本地开发) / `http://192.168.139.230:8082`(生产部署环境)
- **后端 API 服务**:[http://localhost:8090](http://localhost:8090)(本地开发) / `http://192.168.139.230:8092`(生产部署环境)
- **初始管理账号**:`admin` / `admin123`
---
@@ -73,8 +105,16 @@ RailwaySystem/
│ ├── src/api/ # 前端 Axios 接口层(含 train 培训业务接口)
│ ├── src/views/train/ # 培训业务页面视图(学员、排课、宿舍、考勤等)
│ └── package.json # 前端依赖与 Webpack 构建配置
├── deploy/ # 生产部署、平滑重启脚本与 Nginx 示例配置
├── doc/ # 业务与产品需求中心(PRD V1.0、原始资料与归档)
└── docs/ # 技术架构、发布门禁与代码审计中心(包含 V2 架构、API/DB 规范与验收证据)
├── docs/ # 技术架构、发布门禁、Human Documentation 与代码审计中心
│ ├── visual/ # 视觉化交互展示门户(8 篇可离线全景架构与流程展示)
│ ├── handbook/ # 人类操作白皮书与开发指南(01~09 全景手册)
│ ├── reports/ # 验收测试报告与发版说明
│ ├── _meta/ # 发布准备度、门禁清单与最终浏览器验收证据
│ ├── api-v2/ # REST API 契约与 DTO/VO 字典
│ └── database-v2/ # 数据库 V2 物理模型与迁移断言
└── scripts/ # 驱动预检与质量断言脚本
```
---
+104 -53
View File
@@ -1,66 +1,117 @@
# RailwaySystem 技术架构与代码审计中心(docs)
# RailwaySystem 文档中心总导航
> **说明**:本目录为 RailwaySystem 智慧培训系统的技术架构设计、代码审计、数据库实测核验及运行环境全景知识库。
>
> **业务基线指针**:所有技术方案与数据库重构均服务于业务需求,业务判断请严格参阅 [doc/RailwaySystem 智慧培训系统一期 PRD V1.0.md](file:///Users/wzb/Desktop/项目/RailwaySystem/doc/RailwaySystem 智慧培训系统一期 PRD V1.0.md) 以及 [doc/README.md](file:///Users/wzb/Desktop/项目/RailwaySystem/doc/README.md)。
> **当前工程基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
> **数据库增量版本**:`CURRENT_RELEASE_DB_DELTA = 3` (增量迁移 `001_sys_oper_log_cost_time.sql`、`002_legacy_analytics_permissions.sql`、`003_report_attendance_action_permissions.sql` 已就绪;`007_dicts.sql` 明确严禁执行)
> **质量状态速览**:后端单元测试与契约测试 154 PASS,核心场景集成 6/6 PASS,110 次真实 HTTP 请求零 500 错误,Kingbase 物理断言 11/11 PASS,端到端浏览器自动化真实验收全量 PASS(Console 0 阻断,Swagger UI 正常连通)。
---
## 核心技术现状速览(Phase 0 审计结论)
## 🧭 角色化阅读路线
1. **工程架构**:前后端分离架构,后端基于 Spring Boot 2.5 + 若依 (RuoYi-Vue) 单体增强,前端基于 Vue 2.6 + Element UI。
2. **数据库底座**:国产人大金仓 **KingbaseES V009R003C018**(JDBC 驱动 8.6.0,`database_mode=mysql`)。通过跳板机隧道(`127.0.0.1:4321` -> `192.168.139.218:4321`)直连生产实例。
3. **数据库实测**:14 张培训业务表全部就绪,除 `train_teacher` 含有 1 条真实教师记录外,其余 13 张表数据量为 0,具备低包袱重构升级条件。
4. **接口连通性**:已针对 Controller 增加路由别名,涵盖培训管理 14 组业务接口的探测全部达到 HTTP 200 连通。
5. **系统启动**:已在工程根目录提供一键启动脚本 [start-local.sh](file:///Users/wzb/Desktop/项目/RailwaySystem/start-local.sh),集成跳板机隧道打通、本地 Redis 唤醒、Mac 端口清理与前后端一键并发启动。
为了帮助不同背景的读者快速找到权威资料,本文档中心提供以下角色导航路径:
```mermaid
graph TD
Entry["RailwaySystem 访问入口选择"]
subgraph R1["评审 / 领导 / 汇报"]
V["离线交互门户<br/>visual/index.html"]
H1["项目全景总览<br/>handbook/01"]
end
subgraph R2["业务 / 教务员"]
H2["业务主链规范<br/>handbook/02"]
H5["14大业务模块指南<br/>handbook/05"]
PRD["业务需求PRD<br/>../doc/README.md"]
end
subgraph R3["开发 / 架构师"]
H3["系统架构设计<br/>handbook/03"]
H4["数据模型总览<br/>handbook/04"]
H6["API与权限清单<br/>handbook/06"]
API["API V2 事实源<br/>api-v2/"]
end
subgraph R4["测试 / 交付团队"]
H7["质量保障报告<br/>handbook/07"]
TR["综合测试报告<br/>reports/final-test-report.md"]
BR["浏览器验收报告<br/>reports/browser-acceptance-report.md"]
DEP["部署与发版说明<br/>reports/release-notes.md"]
end
Entry --> R1
Entry --> R2
Entry --> R3
Entry --> R4
```
---
## 代码与数据全景审计报告清单(`codebase-audit/`)
### A. 第一次阅读(推荐入口)
本目录下的 [codebase-audit/](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/) 包含完整的 19 篇技术审计报告,记录了对工程现状、源码实现、数据库实际 schema 与权限体系的详尽核验:
### 1. 核心综述与基线标准
- [18_phase05_runtime_fix.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/18_phase05_runtime_fix.md) —— ★★★ **Phase 0.5 基础运行修复与端到端验证审计报告(Kingbase schema与生成器适配)**
- [17_phase0_summary.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/17_phase0_summary.md) —— ★★★ **Phase 0 工程与数据库真实基线总结(进入下一阶段前必读)**
- [11_executive_summary.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/11_executive_summary.md) —— 全景代码审计执行摘要
- [12_baseline_classification.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/12_baseline_classification.md) —— 真实代码基线与工程资产可信度分级
- [00_project_overview.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/00_project_overview.md) —— 项目整体技术概况与组件关系
- [01_project_tree.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/01_project_tree.md) —— 项目工程目录结构全貌
### 2. 数据库与数据建模实测
- [13_live_database_snapshot.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/13_live_database_snapshot.md) —— 实时 KingbaseES 数据库实例只读核验快照
- [14_database_code_diff.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/14_database_code_diff.md) —— 实时数据库与当前代码及 PRD V1.0 业务对象的差异比对
- [16_kingbase_readonly_compatibility.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/16_kingbase_readonly_compatibility.md) —— KingbaseES MySQL 模式兼容性实测报告
- [03_database_current_state.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/03_database_current_state.md) —— 数据库静态结构与设计状态分析
### 3. 后端服务与 API 盘点
- [04_api_inventory.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/04_api_inventory.md) —— 后端 Controller 接口现状盘点与路由清单
- [02_training_modules_inventory.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/02_training_modules_inventory.md) —— 培训业务模块 Java 代码资产详尽盘点
- [09_reusable_ruoyi_capabilities.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/09_reusable_ruoyi_capabilities.md) —— 若依(RuoYi)底座可复用框架能力分析
### 4. 前端组件与页面现状
- [05_frontend_inventory.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/05_frontend_inventory.md) —— 前端 Vue 页面、路由及 API 请求层盘点
### 5. 安全、权限与运行配置
- [15_live_permission_snapshot.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/15_live_permission_snapshot.md) —— 生产菜单、角色、权限关系实时状态核验
- [06_security_and_permissions.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/06_security_and_permissions.md) —— 权限体系与若依安全拦截机制分析
- [07_runtime_and_environment.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/07_runtime_and_environment.md) —— 运行环境依赖、配置项与本地部署条件
- [08_git_status.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/08_git_status.md) —— Git 提交历史与版本分支演化
### 6. 业务与技术差距分析
- [10_gap_and_conflict_analysis.md](file:///Users/wzb/Desktop/项目/RailwaySystem/docs/codebase-audit/10_gap_and_conflict_analysis.md) —— 现状与预期目标的差距与冲突分析
如果您是**第一次接触本项目**,或者需要向老师、主管、客户汇报系统成果:
* 🌟 **强力推荐直达离线交互门户**:[visual/index.html](visual/index.html)
* **特点**:无需启动后端服务或数据库,双击即可在任意现代浏览器中离线打开。
* **内容**:提供深色工业风大屏质感,涵盖系统业务主链 SVG 交互拓扑、系统六层分层架构图、14 大核心业务模块互动矩阵、核心指标 KPI 仪表盘与发版准备度看板。
* 📖 **快速阅读项目总览白皮书**:[handbook/01-project-overview.md](handbook/01-project-overview.md)
* 专为人类读者编写,通俗阐述系统解决的教务痛点、服务对象、关键特性与一期交付边界。
---
## 关联子模块技术文档
### B. 业务人员与教务管理路径
- Kingbase 兼容模式专题核验:
- [kingbase_compatibility_audit.md](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/docs/kingbase_compatibility_audit.md)
- [kingbase_fact_check.md](file:///Users/wzb/Desktop/项目/RailwaySystem/RuoYi-Vue/docs/kingbase_fact_check.md)
关注业务流程、业务规则、状态流转与功能说明的读者,请查阅:
1. [handbook/02-business-process.md](handbook/02-business-process.md) —— **核心业务全流程与状态机规范**(开班计划、报到核验、四维排课冲突预检、考勤打卡与结训联动)。
2. [handbook/05-module-guide.md](handbook/05-module-guide.md) —— **14 大业务模块详细指南**(教师、学员、课程、教室、场地、宿舍、开班、报到、排课、考勤、班牌、统计等)。
3. [../doc/README.md (业务需求中心与 PRD V1.0)](../doc/README.md) —— **业务需求最高事实源**(包含正式冻结的 PRD V1.0 原文与原始资料索引)。
---
### C. 开发人员与架构师路径
参与系统编码、功能扩展与架构审计的研发人员,请查阅:
1. [handbook/03-system-architecture.md](handbook/03-system-architecture.md) —— **系统技术架构设计**(Spring Boot 2.5 + 若依增强单体、`ruoyi-train` 核心模块、Kingbase 兼容适配模式)。
2. [handbook/04-data-model-overview.md](handbook/04-data-model-overview.md) —— **数据模型总览**(核心实体关系与关键表结构设计)。
3. [handbook/06-api-and-permission-overview.md](handbook/06-api-and-permission-overview.md) —— **API 与权限体系速览**(核心操作端点、RBAC 菜单权限与专用业务 Action)。
4. [handbook/08-deployment-and-release.md](handbook/08-deployment-and-release.md) —— **部署与运维手册**(本地快速启动与生产多环境部署要求)。
5. [handbook/deployment/kingbase-jdbc-provisioning.md](handbook/deployment/kingbase-jdbc-provisioning.md) —— **Kingbase JDBC 8.6.0 依赖供应指南**。
---
### D. 测试与质量验收路径
负责功能验收、回归测试与质量审计的人员,请查阅:
1. [reports/final-test-report.md](reports/final-test-report.md) —— **Final Candidate 自动化测试与场景集成最终报告**(154 单元测试 + 6 大场景全 PASS 证据)。
2. [reports/browser-acceptance-report.md](reports/browser-acceptance-report.md) —— **端到端浏览器自动化验收报告**(真实环境验收通过:**PASS**,0 阻断,Swagger 连通)。
3. [reports/release-notes.md](reports/release-notes.md) —— **发版说明与变更记录**。
4. [_meta/core-business-test-matrix.md](_meta/core-business-test-matrix.md) —— **核心业务场景集成自动化测试矩阵**。
---
### E. Agent 与技术契约事实源(Contract Sources)
本目录下的底层契约目录为系统自动代码生成、契约测试和 Agent 审计的**最高技术事实源(Source of Truth)**,已正式冻结,保持原路径不移动:
1. [api-v2/](api-v2/) —— **API V2 契约体系**:
- `00_readme.md`:API 体系总览与 REST 规范
- `01_api_design_principles.md` ~ `05_module_d_score_learning_statistics_api.md`:各业务域端点定义
- `06_dto_vo_catalog.md`:DTO/VO 字段定义字典
- `08_transaction_and_invariants.md`:强事务与 6 大跨表业务不变量
- `10_permission_and_error_codes.md`:权限字符串与 40001~50001 业务错误码字典
2. [database-v2/](database-v2/) —— **数据库 V2 物理迁移与表结构事实源**:
- `01_table_inventory.md`:21 张物理表字段、约束、主外键最终定义
- `05_execution_contract.md`:数据库物理迁移执行契约与验证门禁
3. [issues-v1/](issues-v1/) —— **任务分解与验收条件**:
- `02_p0_issue_backlog.md`:P0 核心任务与 AC 验收条件定义
- `06_acceptance_matrix.md`:AC 验收标准对应自动化用例矩阵
4. [development/](development/) —— 各 Issue 实施过程记录与验收报告。
5. [_meta/documentation-audit.md](_meta/documentation-audit.md) —— D.0 文档现状审计与资产盘点报告。
---
### F. 历史过程资料归档(Historical Snapshots)
> ⚠️ **重要提示**:以下目录记录的是项目研发演进早期的阶段性快照或原始素材,**仅作为工程审计与技术溯源参考,不代表当前 Final Candidate 的代码与数据库现状**:
* [codebase-audit/](codebase-audit/):**Phase 0 历史代码审计快照**(基于历史 Commit `e12eda05`,记录了重构前旧单体结构与旧 14 张表实测状态,已被 Database V2 与 API V2 替代)。
* [../doc/raw_materials/](../doc/raw_materials/):早期甲供原始需求与数据表草案。
* [../doc/archive/](../doc/archive/):一期 PRD V0.9、早期决策与假设讨论稿。
* [../doc/wxy_doc/](../doc/wxy_doc/):早期技术原型与开发说明书草案。
+79
View File
@@ -0,0 +1,79 @@
# RailwaySystem 文档现状审计与资产盘点报告 (Documentation Audit)
> **文档定位**:正式归档 D.0 Documentation Current-State Audit 审计事实、文档分类、重复集群与未来归档治理建议。
> **基线版本**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
> **审计原则**:本轮只读取并形成审计建议,**绝对不物理搬迁、不重命名底层契约目录**。
---
## 1. docs 目录盘点与结构统计
经对工程当前 HEAD 进行全面只读扫描:
* **`docs/` 目录内 Markdown 文档总数**:**70 份**(加根目录与 `doc/` 历史中心共 85 份)。
* **目录分布明细**:
* `docs/README.md` (1 篇)
* `docs/_meta/` (2 篇:核心场景测试矩阵与分析模块适配审计)
* `docs/api-v2/` (14 篇:00~13 冻结的 API REST 契约、DTO/VO、权限与错误码)
* `docs/database-v2/` (14 篇:00~13 21张物理表清单、迁移计划、Gate验证记录)
* `docs/issues-v1/` (10 篇:00~09 Wave 波次编排、P0 Issue 待办、AC 验收矩阵)
* `docs/development/` (8 篇:各 Issue 实施与 Smoke 验证记录)
* `docs/generator-v2/` (1 篇:Kingbase 序列识别补丁说明)
* `docs/handbook/deployment/` (1 篇:Kingbase JDBC 驱动供应指南)
* `docs/codebase-audit/` (19 篇:00~18 历史 Phase 0 代码与数据库实测快照)
---
## 2. 文档分类与成熟度分布
对现有文档按业务性质进行深度分类统计:
| 文档分类类型 | 数量 | 典型代表文件与说明 |
| :--- | :---: | :--- |
| **A. HUMAN_READABLE** | 3 篇 | 根目录 `README.md`、`doc/README.md`、`doc/PRD V1.0.md`(面向人类与评审)。 |
| **B. AGENT_TECHNICAL** | 28 篇 | `issues-v1/` 波次分配、`api-v2/` 服务边界与设计原则、`generator-v2/` 补丁。 |
| **C. CONTRACT_SOURCE** | 16 篇 | **技术最高事实源**:`api-v2/` 接口定义、`database-v2/01_table_inventory.md`、`PRD V1.0`。 |
| **D. TEST_EVIDENCE** | 16 篇 | `_meta/core-business-test-matrix.md`、`database-v2/` 门禁报告、`development/issue-*` 报告。 |
| **E. RELEASE_DEPLOYMENT**| 4 篇 | `kingbase-jdbc-provisioning.md`、`database-v2/02_migration_plan.md` 等。 |
| **F. HISTORICAL** | 28 篇 | `codebase-audit/` 全套 19 篇、`doc/raw_materials/`、`doc/archive/`。 |
| **G. DUPLICATE** | 5组集群 | 涉及 15+ 篇文档(详见第 4 节)。 |
| **H. STALE (过时内容)** | 22 篇 | 旧 `docs/README.md`、`codebase-audit/` 19 篇、早期未采纳草案。 |
| **I. UNKNOWN** | 0 篇 | 经过逐行读取,全部文档的来历与用途均已明确,无未知孤儿文档。 |
---
## 3. 旧入口与信息架构缺陷诊断
1. **入口断头路**:旧版 `docs/README.md` 仅列出了 `codebase-audit/`,使新人误以为旧代码就是当前状态,后续完成的 `api-v2`、`database-v2` 等核心技术资产完全隐形。
2. **同名目录混淆**:根目录下同时存在 `doc/` 和 `docs/`,缺乏上层导航协调。
3. **技术文档机翻味过重**:大量的 Gate 验证记录与 Issue 过程文档充斥着 Agent 执行日志格式,人类可读性较差。
---
## 4. 五大重复集群与 Source of Truth 认定 (Duplication Clusters)
| 重复集群主题 | 涉及文档清单 | 认定的权威事实源 (Source of Truth) |
| :--- | :--- | :--- |
| **Cluster 1:数据库 V2 表结构与字段** | • `doc/RailwaySystem 数据库 V2 字段设计...`<br>• `docs/database-v2/01_table_inventory.md`<br>• `docs/api-v2/06_dto_vo_catalog.md` | **[docs/database-v2/01_table_inventory.md](../database-v2/01_table_inventory.md)**<br>*(物理建表以当前 V2 SQL 为准)* |
| **Cluster 2:P0 业务规则与验收标准** | • `docs/issues-v1/02_p0_issue_backlog.md`<br>• `docs/issues-v1/06_acceptance_matrix.md`<br>• `docs/development/issue-*.md` | **[docs/issues-v1/02_p0_issue_backlog.md](../issues-v1/02_p0_issue_backlog.md)** 与 **[docs/issues-v1/06_acceptance_matrix.md](../issues-v1/06_acceptance_matrix.md)** |
| **Cluster 3:本地启动与环境搭建** | • `README.md`<br>• `docs/codebase-audit/07_runtime_and_environment.md`<br>• `docs/database-v2/00_readme.md` | 根目录 **[README.md](../../README.md)** |
| **Cluster 4:权限字符与错误码** | • `docs/api-v2/10_permission_and_error_codes.md`<br>• `docs/issues-v1/02_p0_issue_backlog.md` | **[docs/api-v2/10_permission_and_error_codes.md](../api-v2/10_permission_and_error_codes.md)** |
| **Cluster 5:排课冲突预检规则** | • `docs/api-v2/03_module_b_plan_enrollment_schedule_api.md`<br>• `docs/issues-v1/02_p0_issue_backlog.md` | **[docs/api-v2/03_module_b_plan_enrollment_schedule_api.md](../api-v2/03_module_b_plan_enrollment_schedule_api.md)** |
---
## 5. 历史目录界定与未来归档建议
为保证 CI/CD 与自动化工具链路不被破坏,**本轮严禁执行物理文件迁移**。未来版本建议做如下轻量归档:
1. **明确 Historical 标记**:
- 将 `docs/codebase-audit/`(19 篇)在索引中统一声明为“Phase 0 历史代码快照”,防止新同学误读。
- 将 `doc/raw_materials/` 与 `doc/archive/` 保持在历史资料区。
2. **禁止擅自替代冻结契约**:
- 严禁创建 `03_contracts/` 目录强行替代原有的 `api-v2/` 和 `database-v2/`,新增的 Human Handbook 必须建立在现有契约之上。
---
## 6. 技术参考链接 (Technical References)
* 文档中心总导航:[docs/README.md](../README.md)
* 人类操作手册:[docs/handbook/01-project-overview.md](../handbook/01-project-overview.md)
* 核心测试矩阵:[docs/_meta/core-business-test-matrix.md](core-business-test-matrix.md)
+107
View File
@@ -0,0 +1,107 @@
# 01. RailwaySystem 项目全景总览
> **文档定位**:面向评审专家、业务主管、系统管理员及新入职人员的业务与系统总览手册。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 系统建设背景与解决的问题
铁路运输体系对从业人员的专业技能、作业标准与应急处置能力有着极其严苛的要求,常态化、规范化的职工培训是保障铁路行车安全的基石。然而,在传统的铁路职工培训与教务管理实践中,普遍存在以下业务痛点:
1. **教务协同链条割裂**:开班计划、学员名单、师资配置、教室安排分散在不同表格或独立系统中,排课冲突(如同一名教师或教室在同一时间被多班复用)频发,依赖人工协调效率低下。
2. **学员档案与敏感信息保护不足**:学员来自全国各铁路局集团公司,身份证号、手机号等关键个人隐私直接明文存储,存在合规与信息安全泄露隐患。
3. **现场考勤与打卡真实性难以保证**:以往多采用纸质签到或事后手工补录,存在代签、漏签问题;同时,缺乏针对具体课次(上午/下午不同课程)的精准到课统计。
4. **后勤保障与教务脱钩**:学员集中面授期间的宿舍分配往往滞后,男女混住风险、床位超额入住等情况难以在教务源头进行有效拦截。
5. **学情考核与画像不够多维**:传统的固定单一分数无法真实衡量学员在理论考试、实操演练、课堂出勤及自学时长等维度的综合素质。
**RailwaySystem 智慧培训系统**正是为了解决上述问题而研发的一体化数字化教务中枢,旨在打造一个规范、高效、安全、智能的铁路全生命周期培训管理平台。
---
## 2. 核心用户角色与使用场景
系统围绕铁路职工培训的实际业务场景,为四类典型用户提供针对性服务:
| 用户角色 | 核心使用场景 | 核心关注价值 |
| :--- | :--- | :--- |
| **教务管理员 (Admin)** | 编制年度/月度培训班计划、批量导入参训学员名单、调度教室与实训场地、统筹宿舍分配、监控全校开班运行状态。 | 全局资源统筹无冲突、批量操作高效、敏感数据安全合规。 |
| **授课教师 (Teacher)** | 查看个人授课日程表、查看本堂课应到/实到学员花名册、现场核验与代签补卡、登记课后学员考核成绩。 | 课表清晰直观、打卡操作便捷、考勤修正留痕可追溯。 |
| **参训学员 (Student)** | 凭身份证/人脸/动态码完成开班现场报到、按课次完成出勤打卡、查询个人住宿房间、查阅培训课程得分与学时。 | 报到极速通行、个人信息受保护、培训档案清晰透明。 |
| **管理决策者 (Leader)** | 查阅各期培训班综合报表、出勤率合格率分布、职工学时积累与多维能力画像,为岗位评定与人才选拔提供数据支撑。 | 数据真实权威、多维画像全面、决策有据可依。 |
---
## 3. 系统核心业务模块布局
系统在一期建设中构建了覆盖全业务流程的 14 大核心功能模块:
```mermaid
graph TD
subgraph M1["基础资源主数据"]
T["教师档案管理"]
S["学员主数据建档"]
C["培训课程资源库"]
CR["理论教室信息"]
TS["实训演练基地"]
end
subgraph M2["教务与计划管理"]
P["开班计划编制"]
PC["本期课程绑定"]
E["参训名单导入"]
L["课次编排排课"]
SC["四维冲突智能预检"]
end
subgraph M3["现场执行与后勤"]
R["开班现场报到 (人脸/刷卡/扫码)"]
A["课次考勤打卡 (签到/签退/修正)"]
D["宿舍楼栋与床位分配 (防混住)"]
B["电子班牌物联终端展示"]
end
subgraph M4["考核分析与成果"]
AN["报到/考勤统计分析"]
DU["学习时长精准累计"]
PT["学员多维能力画像"]
end
M1 --> M2
M2 --> M3
M3 --> M4
```
---
## 4. 一期核心成果与交付边界
截至当前 **Final Candidate** 基线,系统已达成以下建设成果:
1. **业务闭环 100% 贯通**:从教务准备、开班发布、现场报到、智能排课、课堂考勤、计划结训到学情分析,全流程 10 个正式业务环节实现数据无缝流转与状态联动。
2. **跨表业务不变量强管控**:
- **学员敏感数据防护**:学员身份证号在数据库落库时采用不可逆散列 + 安全加密存储,界面与接口统一进行掩码脱敏(仅显示后 4 位)。
- **四维排课防冲突算法**:教师时段冲突、教室占用冲突、实训场地占用冲突及同一班级课次重叠在编排时实时预检,确保教学资源不出现撞车。
- **严格宿舍防混住校验**:男性学员严禁分入女寝,女性学员严禁分入男寝,且严格受限于房间核定容纳人数。
- **结训联动流转**:培训计划完结时,一键自动批量将班级在读学员状态联动更新为“已完成”,杜绝人工遗漏。
3. **国产化适配与平滑升级**:
- 全面完成国产人大金仓数据库(KingbaseES V009R003C018)的生产级适配与 21 张物理表重构。
- 建立了严谨的发布增量迁移机制(`CURRENT_RELEASE_DB_DELTA = 3`),确保数据迁移的安全可控。
---
## 5. 关键系统特性
* **严密的权限安全体系**:基于 RBAC 标准模型,对数据查询、导出、报到确认及考勤调整等敏感操作进行细粒度权限控制,所有人工代签与状态修正强制写入审计流水留痕。
* **高鲁棒性的业务接口**:全系统定义了统一的业务错误码体系(40001~50001),杜绝系统级 500 异常直接暴露给前端用户,提供友好的业务提示。
* **工业级自动化质量门禁**:后端测试套件(154 项单元与契约测试、6 大场景核心闭环测试)全部通过,真实 API 请求 0 报错,数据库无脏数据残留。
---
## 6. 技术参考链接 (Technical References)
* 业务需求最高基线:[业务需求中心与 PRD V1.0](../../doc/README.md)
* 系统业务全流程与状态机:[02-business-process.md](02-business-process.md)
* 系统技术架构设计:[03-system-architecture.md](03-system-architecture.md)
* 核心 API 契约总览:[docs/api-v2/00_readme.md](../api-v2/00_readme.md)
* 数据库物理模型清单:[docs/database-v2/01_table_inventory.md](../database-v2/01_table_inventory.md)
+173
View File
@@ -0,0 +1,173 @@
# 02. RailwaySystem 业务全流程与状态机规范
> **文档定位**:详细阐述 RailwaySystem 智慧培训系统一期的业务流转闭环、核心业务规则、状态机生命周期及分层控制机制。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 一期业务全景主链与支线
系统在一期实现中,建立了清晰的“准备阶段 → 编排阶段 → 执行阶段 → 结业归档”业务闭环:
```mermaid
flowchart TD
subgraph S1["一、资源准备阶段"]
A["基础主数据录入<br/>(教师档案、学员建档、课程库录入、教室与实训场地、宿舍就绪)"]
end
subgraph S2["二、计划与编排阶段"]
B["创建培训计划 (Plan)<br/>状态: 0:草稿"]
B1["绑定本期课程 (PlanCourse)<br/>配置教师与学时"]
B2["录入参训学员 (Enrollment)<br/>状态: 0:待报到"]
C["发布培训计划 (Plan Publish)<br/>状态流转: 1:进行中"]
B --> B1
B --> B2
B1 --> C
B2 --> C
end
subgraph S3["三、培训执行阶段"]
D1["开班报到环节 (Report)<br/>人脸/刷卡/扫码核验<br/>状态: 0:待报到 &rarr; 1:已报到"]
D2["课次排课环节 (Scheduling)<br/>四维时段防重叠预检<br/>(教师/教室/场地/本班)"]
E["课次考勤环节 (Attendance)<br/>学员打卡 / 教师代签修正 (manual_flag=1)<br/>考勤结论: 0缺勤 / 1正常 / 2迟到 / 3早退 / 4请假"]
D1 --> E
D2 --> E
end
subgraph S4["四、结训与分析阶段"]
F["培训结训流转 (Completion)<br/>计划状态: 2:已结束<br/>正常在读学员自动联动: 4:已完成 (退训保护)"]
G["多维学情分析 (Analytics - Read Only)<br/>报到统计 / 考勤分析 / 学时统计 / 学员画像"]
F --> G
end
A --> B
C --> D1
C --> D2
E --> F
```
### 辅助支线与硬件支撑
* **生活后勤支线 (Accommodation)**:在学员名单录入后至现场报到前,管理员依据参训人员的住宿需求(`accommodationRequired=1`),按照严格性别隔离策略分配宿舍床位,并可触发门禁授权。
* **教学硬件支撑 (Electronic Board)**:电子班牌安装于理论教室或实训场地,作为现场多媒体终端,动态展示教室日程、授课教师、课次信息,并支持学员刷卡/人脸交互。
---
## 2. 核心状态机生命周期规范
### 2.1 参训档案状态机 (`Enrollment Status`)
参训记录(`train_enrollment`)记录学员在特定培训班中的履历状态,其合法值域严格定义为 **0 ~ 4**:
```mermaid
stateDiagram-v2
[*] --> 待报到 : 名单导入 (0)
待报到 --> 已报到 : 现场核验通过 (1)
待报到 --> 请假 : 人工请假 (2)
待报到 --> 退训 : 退训登记 (3)
已报到 --> 请假 : 人工请假 (2)
已报到 --> 退训 : 退训登记 (3)
已报到 --> 已完成 : 结训批量联动 (4)
请假 --> 已报到 : 销假复课 (1)
退训 --> [*] : 永久排除联动
已完成 --> [*] : 结业归档
```
| 状态码 | 状态名称 | 业务含义 | 触发时机与流转说明 |
| :---: | :--- | :--- | :--- |
| **0** | **待报到** | 学员已被录入开班名单,等待开班现场核验 | 批量导入或手工新增学员入班时的初始状态。 |
| **1** | **已报到** | 学员已到校并在现场核验身份成功 | 执行开班报到动作(人脸/刷卡/二维码/人工)后更新。 |
| **2** | **请假** | 学员因特殊情况无法全程到课或中途请假 | 管理员在参训名单中人工调整学员状态。 |
| **3** | **退训** | 学员因故中途退出本期培训 | 管理员操作退训,该学员将被排除在结训联动更新之外。 |
| **4** | **已完成** | 学员顺利修完本期培训,达到结训要求 | 培训计划结训(`completePlan`)时,系统自动联动批量更新。 |
### 2.2 课次考勤状态机 (`Attendance Status`)
课次考勤记录(`train_student_checkin`)记录学员在具体某节课上的考勤结论,其合法值域严格定义为 **0 ~ 4**:
| 状态码 | 状态名称 | 业务判定标准与规则 |
| :---: | :--- | :--- |
| **0** | **缺勤** | 课次已结束,学员既无打卡流水,亦无请假备案(系统默认或代签缺勤)。 |
| **1** | **正常** | 在规定宽限时间内完成签到,并在课次结束后准时完成签退。 |
| **2** | **迟到** | 签到时间晚于课次开始时间与系统设定的宽限期。 |
| **3** | **早退** | 签退时间早于课次法定结束时间。 |
| **4** | **请假** | 针对本堂课次提交了有效公假/病假申请,或由授课教师代签标注为请假。 |
> ⚠️ **禁令与口径红线**:
> 1. 严禁出现 `attendance_status = 5`(已证实为早期文档误将若依字典排序序号 `dict_sort=5` 当作字典取值)。
> 2. 严禁使用旧材料中的 `4 = 缺勤`(当前正式标准中 `0 = 缺勤`,`4 = 请假`)。
> 3. 严禁在报到表中使用旧的 `report_status`(报到状态统一归口至 `train_enrollment.enrollment_status`,报到流水只记录身份核验结果 `verify_result`)。
### 2.3 报到核验方式 (`Report Way`)
现场报到动作记录(`train_class_report`)中支持的核验方式包括:
* `1`:**人脸识别**(通过智能平板/闸机比对学员底库照片)
* `2`:**身份证刷卡**(读取实体二代身份证或员工卡)
* `3`:**二维码核验**(学员手机出示动态身份凭证核销)
* `4`:**人工录入**(由管理员或班主任核验纸质凭证后人工确认)
---
## 3. 排课编排与智能冲突检测机制 (Scheduling)
排课模块在编排具体课次(`train_lesson`)时,引入了实时四维防重叠检测算法,在业务上明确区分为**软警告 (Warning Conflict)** 与 **硬阻断 (Hard Block)**:
### 3.1 四维检测范围
1. **教师时间重叠**:同一教师在同一时间段内,严禁在不同培训班同时授课。
2. **理论教室占用**:同一间教室在同一时间段内,严禁被两个不同课次同时占用。
3. **实训场地占用**:同一个实训演练场地在同一时段内,严禁排入重叠的实操课程。
4. **本班自身课次重叠**:同一个培训班内部,课次起止时间不允许自身交叉重叠。
### 3.2 冲突级别与处理策略
* **软警告冲突 (Warning Conflict)**:
- 当检测到潜在的时间安排冲突(如跨班共享场地预警或紧凑排期),前端预检接口将返回详细冲突说明与冲突列表。
- **业务处理原则**:前端向操作员弹出确认对话框:
- 若用户点击“取消”:不向服务器发送保存请求,排课操作中止;
- 若用户核实无误点击“确认继续”:向服务器发送标准的保存请求,正常落库保存。
- **接口规范**:正式排课接口**禁止任何 `force`、`ignoreConflict` 或 `overrideConflict` 传参**,后端始终执行确定性的安全校验。
- **浏览器真实交互验收事实**:
- **Warning Cancel 验证**:触发冲突警告弹窗后点击取消,不产生网络保存,实测 **PASS**;
- **Warning Confirm/Save 验证**:触发冲突警告弹窗后点击确认继续,标准 POST 成功落库保存,实测 **PASS**;
- **Lesson Detail GET 调用事实**:排课流程中 `Lesson detail GET: NOT CALLED`(课表采用聚合查询,无需高频单个课次明细往返)。
* **硬阻断规则 (Hard Block - 绝对禁止保存)**:
- 起止时间非法(如开始时间晚于或等于结束时间);
- 培训班计划已锁定或已结训(禁止在已封账计划中变更课次);
- 理论教室与实训场地二者均未选,或二者同时被选中(必须严格二选一 XOR 互斥);
- 课次绑定的课程不属于当前开班计划(杜绝错链);
- 课次已有学员产生出勤打卡流水(杜绝课后篡改排课时间或删除课次)。
---
## 4. 报到与考勤的分层架构设计
在系统实现中,报到与考勤严格遵循“**只读分析查询 (Read-Only Analytics)**”与“**专用业务动作 (Write Actions)**”的分离原则:
### 4.1 开班报到分层与术语规范
1. **术语与界面标签一致性区分**:
- **UI 菜单标签 (`UI_MENU_LABEL`)**:前端侧边栏菜单当前显示为 **“开班签到”**(位于【统计分析】目录下,对应数据库 `sys_menu.menu_name = '开班签到'`);
- **业务术语与契约 (`BUSINESS_TERM`)**:在业务模型、应用服务(`EnrollmentAppService.confirmReport`)与冻结契约中,标准业务术语统一为 **“开班报到 / Report Confirm”**。文档与汇报中保持此明确区分,系统不随意修改 UI 既有菜单。
2. **报到分析与流水查询 (`/train/report`)**:
- 定位:**只读查询与数据导出 (Read-Only Analytics)**。
- 展现:开班签到全局列表、按班级检索报到记录、导出 Excel 报表。在真实浏览器验收中验证为 **PASS / Read Only**。
3. **现场报到确认动作 (`confirmReport`)**:
- 定位:**专用业务操作 (Write Action)**。
- UI 入口:位于【开班计划管理】页面中,进入具体班级的【参训人员列表 (EnrollmentPanel)】,点击单条学员的【报到】操作按钮。
- 实测验证:端到端真实调用 `POST /train/enrollments/{enrollmentId}/report`,返回 200 OK,学员状态由 `0:待报到` 成功更新为 `1:已报到`(**PASS**)。
### 4.2 课程考勤分层与设备路由
1. **考勤分析与统计看板 (`/train/checkin`)**:
- 定位:**只读全局看板与历史数据分析 (Read-Only Analytics)**。
- 展现:历史打卡明细检索、按学员/课次查询考勤结论、导出出勤报表。浏览器验收实测为 **PASS / Read Only**。
2. **考勤打卡与调整动作 (Attendance Actions)**:
- 定位:**面向课堂现场与授课教师的专用高安全 Action 接口**。
- 接口包括:
- `POST /train/lessons/{lessonId}/attendance/checkin`(学员签到/签退打卡)
- `POST /train/lessons/{lessonId}/attendance/adjust`(教师代签与请假修正,强制打上 `manual_flag = 1` 审计标记)
- **界面客观说明**:在当前的桌面后台管理大页面中,考勤以花名册展示为主;现场签到主要面向移动扫码终端、班牌设备接口及教师工作台,当前正式后台大页面并未冗余放置打卡模拟按钮。
3. **电子班牌前端路由事实 (`BOARD_FRONTEND_ROUTE`)**:
- 在真实浏览器验收中,电子班牌前端页面路由为 **`/equip/board`**(挂载于“教学设施 (equip)”目录下的“电子班牌 (board)”页面,组件为 `train/board`),后端接口路由保持为 `/train/board`。浏览器验收实测为 **PASS**。
---
## 5. 技术参考链接 (Technical References)
* 核心服务与事务边界定义:[docs/api-v2/08_transaction_and_invariants.md](../api-v2/08_transaction_and_invariants.md)
* 核心业务主链集成测试矩阵:[docs/_meta/core-business-test-matrix.md](../_meta/core-business-test-matrix.md)
* 模块指南与用户角色:[05-module-guide.md](05-module-guide.md)
* 质量保障与验收报告:[07-testing-and-acceptance.md](07-testing-and-acceptance.md)
+100
View File
@@ -0,0 +1,100 @@
# 03. RailwaySystem 系统架构设计
> **文档定位**:阐述 RailwaySystem 的整体软件技术架构、系统分层设计、模块交互拓扑及国产化底座适配机制。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 整体架构与技术选型
RailwaySystem 采用现代企业级“前后端分离”单体增强架构,在兼顾交付敏捷性与开发效率的同时,针对铁路行业高安全、国产化底座的要求进行了深度加固:
```mermaid
graph TD
subgraph UI["前端展示层 (build_ui)"]
Vue["Vue 2.6 + Element UI + Axios + Vue Router + Vuex + ECharts"]
end
subgraph Admin["API 网关与接入层 (ruoyi-admin)"]
Ctrl["Spring MVC 控制器 / Token 鉴权 / 日志切面 / 全局异常捕获映射 / Swagger UI"]
end
subgraph Train["培训核心业务层 (ruoyi-train)"]
S1["PlanAppService (开班计划)"]
S2["EnrollmentAppService (名单/报到)"]
S3["SchedulingAppService (排课四维预检)"]
S4["AttendanceAppService (考勤打卡/代签)"]
S5["基础资源服务 (教师/学员/场地/宿舍)"]
end
subgraph Base["系统支撑底座 (ruoyi-system / framework / common)"]
RBAC["用户与角色权限 (RBAC)"]
Menu["系统菜单 (sys_menu)"]
Log["操作日志 (sys_oper_log)"]
Dict["字典配置 (sys_dict_data)"]
end
subgraph Persistence["数据持久层 (MyBatis / PageHelper)"]
Mapper["XML 动态 SQL 映射器"]
Domain["领域实体 (Domain Entities)"]
end
subgraph Storage["国产高安全主库 (KingbaseES V9)"]
KB[("人大金仓数据库 (MySQL兼容模式)<br/>21张物理表 / BIGINT IDENTITY 序列 / 强约束与索引")]
end
UI -->|HTTP / RESTful JSON| Admin
Admin --> Train
Admin --> Base
Train --> Persistence
Base --> Persistence
Persistence -->|JDBC 8.6.0| Storage
```
---
## 2. 核心模块解耦:`ruoyi-train` 业务域划分
为了彻底解决传统若依架构中业务代码与系统基础代码杂糅的问题,项目进行了模块级重构,将所有铁路培训业务彻底独立为 **`ruoyi-train`** Maven 子模块:
| 模块名称 | 职责定位 | 包含的核心能力与服务 |
| :--- | :--- | :--- |
| **`ruoyi-train`** | **培训业务核心领域** | 1. 教学资源(教师、学员、课程、教室、场地、宿舍、班牌);<br/>2. 开班计划与课程绑定(`PlanAppService`, `TrainPlanCourseService`);<br/>3. 学员参训档案与报到流水(`EnrollmentAppService`);<br/>4. 课次排课与四维防重叠检测(`SchedulingAppService`);<br/>5. 课次打卡与教师代签(`AttendanceAppService`)。 |
| **`ruoyi-admin`** | **Web 交互与接口暴露** | 声明 RESTful 控制器(Controller)、Swagger 注解、请求入参校验及权限注解 `@ss.hasPermi`。 |
| **`ruoyi-framework`**| **底层工程基础设施** | Spring Security 拦截器、JWT 令牌校验机制、Druid 数据源监控配置。 |
| **`ruoyi-system`** | **通用权限与元数据底座** | 用户、角色、系统菜单(`sys_menu`)、字典数据(`sys_dict_data`)的底层管理。 |
| **`ruoyi-common`** | **通用工具与异常常量** | 基础实体基类、业务状态枚举、统一响应对象 `AjaxResult`。 |
---
## 3. 国产数据库适配:人大金仓 KingbaseES
系统底层数据库运行于国产人大金仓 **KingbaseES V009R003C018** 之上,采用 `database_mode=mysql` 兼容模式:
1. **驱动治理与供应规范**:
- 采用官方商用驱动 `com.kingbase:kingbase8:8.6.0`。
- 驱动 JAR 文件通过受控构建脚本预检并置入 Maven 本地仓库,规避二进制污染与许可证风险。
2. **主键生成策略适配**:
- 传统若依在 MySQL 下依赖 `AUTO_INCREMENT`。在 Kingbase 适配中,全量 21 张表升级为统一的 `BIGINT IDENTITY` 自增序列或应用层 32 位 UUID,并定制了代码生成器自增识别补丁。
3. **高安全与事务隔离**:
- 全面支持事务隔离级别,在结训联动(`completePlan`)等关键业务场景中保证强事务一致性,任何异常即刻全量回滚。
---
## 4. 关键架构设计原则
1. **确定性安全校验**:
- 跨表核心规则由后端领域服务与数据库物理约束双重守门,杜绝前端单边绕过。
2. **敏感信息脱敏与散列存盘**:
- 学员身份证等关键数据进行哈希散列与密文存盘,对外接口响应强制执行末4位掩码数据脱敏。
3. **只读分析模型与写操作严格隔离**:
- 报表导出、打卡历史检索采用只读聚合映射(Read Model);报到核验、考勤打卡、代签修正走独立写操作(Write Action)管道,实现读写职责清晰分离。
---
## 5. 技术参考链接 (Technical References)
* 核心服务边界划分:[docs/api-v2/07_service_boundary.md](../api-v2/07_service_boundary.md)
* 事务边界与不变量:[docs/api-v2/08_transaction_and_invariants.md](../api-v2/08_transaction_and_invariants.md)
* 数据库物理模型事实源:[docs/database-v2/01_table_inventory.md](../database-v2/01_table_inventory.md)
* Kingbase 驱动供应指南:[deployment/kingbase-jdbc-provisioning.md](deployment/kingbase-jdbc-provisioning.md)
+79
View File
@@ -0,0 +1,79 @@
# 04. RailwaySystem 数据模型总览
> **文档定位**:面向技术人员与数据管理者的领域数据模型概览,重点梳理 10 大核心业务实体及其关联关系。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 核心实体领域关系拓扑
系统底层数据模型围绕“**开班计划**”为核心驱动中枢,建立了学员、课程、师资与空间资源的网状关联模型:
```mermaid
graph TD
Plan["开班计划 (train_class_plan)<br/>主键: plan_id (UUID 32位)"]
Course["标准课程库 (train_course)<br/>主键: c_id (自增序列)"]
PlanCourse["本期课程绑定 (train_plan_course)<br/>主键: plan_course_id (自增序列)"]
Student["学员主档 (train_student)<br/>主键: s_id (UUID 32位)"]
Enrollment["参训档案 (train_enrollment)<br/>主键: enrollment_id (自增序列)"]
Lesson["排课课次 (train_lesson)<br/>主键: lesson_id (自增序列)"]
Classroom["理论教室 (train_classroom_info)<br/>主键: class_room_id (UUID 32位)"]
Site["实训场地 (train_training_site)<br/>主键: site_id (UUID 32位)"]
Board["电子班牌 (train_electronic_board)<br/>主键: board_id (UUID 32位)"]
Report["现场报到流水 (train_class_report)<br/>主键: report_id (自增序列)"]
Checkin["课次考勤打卡 (train_student_checkin)<br/>主键: checkin_id (自增序列)"]
Plan -->|1:N 课程绑定| PlanCourse
Course -->|1:N 课程实例| PlanCourse
Plan -->|1:N 班级档案| Enrollment
Student -->|1:N 参训履历| Enrollment
PlanCourse -->|1:N 安排课次| Lesson
Plan -->|1:N 课表从属| Lesson
Enrollment -->|1:N 核验流水| Report
Enrollment -->|1:N 课堂考勤| Checkin
Lesson -->|1:N 考勤记录| Checkin
Classroom -.->|XOR 互斥场地| Lesson
Site -.->|XOR 互斥场地| Lesson
Classroom -->|1:N 设备绑定| Board
```
---
## 2. 十大核心业务实体职责说明
| 核心实体表名 | 对应领域概念 | 核心业务主键 | 核心职责与外键关联 |
| :--- | :--- | :--- | :--- |
| **`train_class_plan`** | 开班计划 | `plan_id` (UUID 32位) | 承载培训班全生命周期(名称、起止日期、计划状态、报到截止时间、核定人数)。 |
| **`train_course`** | 标准课程库 | `c_id` (自增序列) | 培训课程标准资产库(课程编码、课程名、建议课时、状态)。 |
| **`train_plan_course`** | 本期课程绑定 | `plan_course_id` (自增序列) | 记录特定开班计划选用的课程,外键关联 `plan_id` 与 `c_id`,并绑定授课教师 `t_id`。 |
| **`train_student`** | 学员主数据档案 | `s_id` (UUID 32位) | 学员基础档案,含脱敏姓名、散列与加密存储的身份证号、联系电话及单位名称。 |
| **`train_enrollment`** | 参训履历档案 | `enrollment_id` (自增序列) | 记录学员参与特定培训班的报名档案,外键关联 `plan_id` 与 `student_id`,维护参训状态。 |
| **`train_lesson`** | 具体课次安排 | `lesson_id` (自增序列) | 记录排课课次,外键关联 `plan_id`、`plan_course_id`、`t_id` 及场地(教室或实训场地互斥)。 |
| **`train_classroom_info`**| 理论教室 | `class_room_id` (UUID 32位)| 教学空间实体,定义容纳人数、多媒体配置及可用状态。 |
| **`train_training_site`** | 实训演练基地 | `site_id` (UUID 32位) | 室外或专业实操演练基地,外键关联课次,与教室互斥。 |
| **`train_class_report`** | 现场开班报到流水 | `report_id` (自增序列) | 记录学员现场报到核验事件,外键关联 `enrollment_id`,记录核验方式与时间。 |
| **`train_student_checkin`**| 课次考勤打卡记录 | `checkin_id` (自增序列) | 唯一约束 `UNIQUE(enrollment_id, lesson_id)`,记录打卡时间、考勤状态及人工修正标志。 |
| **`train_electronic_board`**| 电子班牌物联终端 | `board_id` (UUID 32位) | 外键关联 `class_room_id`,记录设备序列号 `board_sn`、IP 地址及通信端点。 |
---
## 3. 关键物理约束与完整性保证
1. **唯一性约束防重叠**:
- 同一培训班内同一学员只能有一条有效档案:`uq_train_enrollment(plan_id, student_id)`。
- 同一学员在同一课次只能产生一条考勤结论:`uq_train_student_checkin(enrollment_id, lesson_id)`。
- 电子班牌硬件序列号全局唯一:`uq_train_electronic_board_sn(board_sn)`。
2. **空间场地 XOR 互斥**:
- 课次表(`train_lesson`)中通过数据库检查约束 `chk_lesson_venue` 强制保证理论教室 `class_room_id` 与实训场地 `site_id` 必须二选一填报,杜绝孤立课次或双重占用。
3. **时间逻辑有效性约束**:
- 课次起止时间强制满足 `lesson_end_time > lesson_start_time`。
---
## 4. 全量物理表事实源链接
关于系统全部 21 张物理表的完整字段清单、数据类型、索引策略与外键级联定义,请直接查阅冻结事实源:
* 📚 **[docs/database-v2/01_table_inventory.md](../database-v2/01_table_inventory.md)**(21 张物理表全景字段字典)
* 📑 **[docs/database-v2/03_constraint_index_review.md](../database-v2/03_constraint_index_review.md)**(数据库约束与索引优化审查)
+159
View File
@@ -0,0 +1,159 @@
# 05. RailwaySystem 14 大核心业务模块详细指南
> **文档定位**:从人类视角系统化解析系统的 14 大业务功能模块,涵盖模块定位、主要用户、核心能力与业务规则。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 基础资源域模块
### 1.1 Teacher (教师档案管理)
* **业务定位**:全校师资人才库与授课教师资质管理中枢。
* **主要用户**:教务管理员。
* **主要功能**:教师基础档案维护(工号、姓名、职称、联系电话、所属单位、擅长专业领域)。
* **关键规则**:教师联系电话(`t_phone`)全局唯一;已排入课次的教师在授课周期内禁止物理删除。
* **关联模块**:为开班课程绑定(PlanCourse)与课次排课(Scheduling)提供师资实体。
* **实测验收状态**:**IMPLEMENTED / Teacher PASS**(浏览器端到端表单录入、手机号重复校验与列表渲染全部通过)。
### 1.2 Student (学员主数据档案)
* **业务定位**:参训职工统一身份与成长履历主数据中心。
* **主要用户**:教务管理员、人事培训主管。
* **主要功能**:学员建档、信息检索、所属铁路局与站段维护、敏感信息脱敏与哈希存储。
* **关键规则**:身份证号执行安全哈希与密文存储,界面与接口脱敏只显后 4 位;停用状态的学员(`status=0`)禁止编入任何开班计划。
* **关联模块**:为参训名单录入(Enrollment)提供学员主档。
* **实测验收状态**:**IMPLEMENTED / Student PASS**(建档正常、末4位脱敏掩码生效、页面与表单校验通过)。
### 1.3 Course (培训标准课程库)
* **业务定位**:铁路标准化教学大纲与课程资产管理。
* **主要用户**:教务规划人员。
* **主要功能**:课程新建、课程编码维护、标准课时设定、课程状态启用/停用。
* **关键规则**:课程编码(`c_code`)全局唯一;启用状态的课程才允许被开班计划引用。
* **关联模块**:为计划课程配置(PlanCourse)提供标准课程源。
* **实测验收状态**:**IMPLEMENTED / Course PASS**。
### 1.4 Classroom (理论教室管理)
* **业务定位**:教学楼宇内的实体理论教室与多媒体研讨室统筹。
* **主要用户**:后勤与教务调度员。
* **主要功能**:教室编号、标准座位容纳量、安装多媒体设备标注、使用状态流转。
* **关键规则**:核定容纳量用于排课时的班级规模预警;每个教室可物理挂接 0 到 N 台电子班牌。
* **关联模块**:为排课(Scheduling)提供理论场地,与电子班牌(Board)形成 1:N 映射。
* **实测验收状态**:**IMPLEMENTED / Classroom PASS**(教室增删改查与容量维护通过)。
### 1.5 Site (实训演练基地)
* **业务定位**:机车检修、调度沙盘、铁道信号等室外/特种实操基地。
* **主要用户**:实训指导员、教务调度员。
* **主要功能**:演练场地登记、实操工位核定、场地状态维护。
* **关键规则**:排课时与理论教室互斥二选一,同一时段同一场地禁止两个班级并发占用。
* **关联模块**:为排课(Scheduling)提供实操场地资源。
* **实测验收状态**:**IMPLEMENTED / Site PASS**(场地维护与互斥排课约束通过)。
### 1.6 Dormitory (宿舍房间与门禁)
* **业务定位**:学员集中面授期间的生活后勤与宿位资源保障。
* **主要用户**:宿舍管理员、教务后勤人员。
* **主要功能**:楼宇房间登记、核定床位数、房间性别属性(男寝/女寝/混合)设定、门禁授权同步。
* **关键规则**:严格性别隔离(男学员严禁分入女寝,女学员严禁分入男寝);严禁超额入住。
* **关联模块**:与学员参训档案(Enrollment)关联,根据学员住宿需求提供宿位分配支撑。
* **实测验收状态**:**IMPLEMENTED / Dormitory PASS**。
---
## 2. 教务编排域模块
### 2.1 Plan (开班计划管理)
* **业务定位**:整个培训业务的大脑中枢,驱动培训生命周期的全流程流转。
* **主要用户**:培训主管、班主任、教务管理员。
* **主要功能**:开班计划拟定、周期设定、报到截止时限配置、发布开班、一键结训流转。
* **关键规则**:计划生命周期状态机(0草稿 -> 1进行中 -> 2已结束);发布后锁定核心信息;结训时强事务批量联动更新学员履历为“已完成”。
* **关联模块**:核心枢纽,聚合 PlanCourse、Enrollment、Lesson 等一切教务活动。
* **实测验收状态**:**IMPLEMENTED / Plan PASS**(32位UUID主键生成、初始0:草稿、发布与结训流转正常)。
### 2.2 PlanCourse (计划本期课程绑定)
* **业务定位**:开班计划的具体教学方案,解决一期多门课程与师资配置问题。
* **主要用户**:教务管理员。
* **主要功能**:向培训班添加课程、指定授课教师、配置本班专属考核要求与学时。
* **关键规则**:同一计划内同一课程不允许重复绑定。
* **关联模块**:上接 Plan 与 Course,下为 Lesson 排课提供课程教师关联基准。
* **实测验收状态**:**IMPLEMENTED / PlanCourse PASS**(课程绑定、教师关联及学时自动联动通过)。
### 2.3 Enrollment (参训人员名单管理)
* **业务定位**:学员与具体培训班的正式参训契约与学籍管理。
* **主要用户**:班主任、教务管理员。
* **主要功能**:批量导入学员名单、单条增删、指定住宿需求、维护参训状态。
* **关键规则**:同一学员不可重复报名同一班级;招生人数受限于计划容量上限;状态支持 0待报到、1已报到、2请假、3退训、4已完成。
* **关联模块**:连接 Student 与 Plan,是开班报到与课次考勤的核心主表。
* **实测验收状态**:**IMPLEMENTED / Enrollment PASS**(名单导入、容量拦截、初始待报到通过)。
### 2.4 Scheduling (课次编排与冲突检测)
* **业务定位**:教务日历化排课引擎,保障教学资源高效有序运转。
* **主要用户**:排课调度员、教师。
* **主要功能**:编排具体课次(日期、起止时段)、选择教室/场地、时段失焦四维冲突实时预检。
* **关键规则**:严格区分 Warning 与 Hard Block;警告级别若用户确认则允许落库保存,接口禁止任何 `force/override` 参数;起止时间与二选一场地属于硬阻断。
* **关联模块**:依赖 PlanCourse、Classroom、Site,为 Attendance 考勤打卡提供课次载体。
* **实测验收状态**:**IMPLEMENTED / Scheduling PASS**
- Warning Cancel = `PASS`
- Warning Confirm/Save = `PASS`
- 接口合规:严格禁止且未出现 `force` / `ignoreConflict` / `overrideConflict` 旁路参数
- 课次详情查询:`Lesson detail GET: NOT CALLED`(规范约定无需调用)
---
## 3. 现场执行与硬件支撑模块
### 3.1 Report (开班报到 / 界面标签: 开班签到)
* **业务定位**:学员报到第一现场的身份快速核验与通道管理。
* **主要用户**:现场接待员、报到学员。
* **界面与术语区分**:前端菜单显示为 **“开班签到”** (`UI_MENU_LABEL = 开班签到`),业务模型与动作定义统一为 **“开班报到 / Report Confirm”** (`BUSINESS_TERM = 开班报到`)。
* **主要功能**:支持人脸识别、身份证刷卡、二维码与人工核验;记录报到时间与核验结论。
* **关键规则**:报到成功强事务联动参训档案流转为“已报到”;分层设计(查询导出与专用报到 Action 解耦)。
* **实测验收状态**:**IMPLEMENTED / PASS**(已在真实浏览器环境验证 `POST /train/enrollments/{id}/report` 200 OK,状态由待报到流转为已报到)。
### 3.2 Attendance (课次考勤打卡)
* **业务定位**:课堂出勤精细化管理,真实记录每堂课的出勤状况。
* **主要用户**:授课教师、参训学员。
* **主要功能**:支持签到打卡、签退打卡、任课教师课堂代签与事假修正。
* **关键规则**:考勤状态严格规范为 0缺勤、1正常、2迟到、3早退、4请假;教师代签与修正强制标记 `manual_flag=1` 留痕;已有出勤记录的课次锁定禁止篡改时间。
* **当前状态**:**IMPLEMENTED / PASS**(全局考勤分析为只读模型,专用 Action 契约完备)。
### 3.3 Board (电子班牌物联终端)
* **业务定位**:教室内智能多媒体终端,实现日程轮播与打卡通信。
* **主要用户**:教室学员、现场巡考人员。
* **前端正式路由**:**`/equip/board`** (`BOARD_FRONTEND_ROUTE = /equip/board`,位于教学设施目录下,后端 API 保持为 `/train/board`)。
* **主要功能**:班牌设备注册、序列号登记、绑定安装教室、心跳与在线状态维护。
* **关键规则**:后端自动生成 UUID 标识;设备在线状态由通信更新,禁止人工在表单篡改;逻辑软删除保护。
* **关联模块**:外键绑定 Classroom 教室实体。
* **实测验收状态**:**IMPLEMENTED / PASS**(浏览器实际访问 `/equip/board` 正常加载渲染,增删改查闭环)。
---
## 4. 学情分析域模块
### 4.1 Analytics (学情综合分析与画像)
* **业务定位**:多维度教务数据沉淀与大数据智能画像中枢。
* **主要用户**:培训管理者、教务处领导。
* **包含能力**:
1. **开班报到统计 (Report Analytics)**:全局报到记录检索与导出;
2. **课次考勤分析 (Attendance Checkin Analytics)**:出勤明细分析与缺勤统计;
3. **自主学习时长统计 (Duration Analytics)**:综合学时与系统课时完成度累计;
4. **学员综合能力画像 (Student Portrait)**:学员雷达图、技能标签与成长轨迹。
* **当前交付状态客观说明**:
- **V2 Read Model 架构**:四大只读数据分析模型与前端界面已全部完成(**IMPLEMENTED**),并通过了权限对齐(`002_legacy_analytics_permissions.sql`);
- **高级跨期多维聚合计分 (Advanced Aggregation)**:属于二期深度分析规划(**NOT IN CURRENT CORE ACCEPTANCE**),核心验收以当前 V2 只读分析与报表导出为准。
* **实测验收状态**:
- 报到统计 (Report Analytics):`PASS / Read Only`
- 考勤分析 (Checkin Analytics):`PASS / Read Only`
- 学时统计 (Duration):`PASS / Read Only`
- 学员画像 (Portrait):`PASS / Read Only`
* **系统工具与审计事实**:
- 操作日志 (OperLog):`PASS`
- 系统工具正常可见:表单构建、代码生成、系统接口(Swagger UI 连通)
- 角色分配机制:`RBAC_ROLE_ASSIGNMENT: ENVIRONMENT_CONFIGURATION`
- 验收数据保留策略:`Browser acceptance created/changed data: KEEP_FOR_AUDIT`(文档阶段严格保留用于审计回溯,不予清理)
---
## 5. 技术参考链接 (Technical References)
* 业务需求最高基线:[业务需求中心与 PRD V1.0](../../doc/README.md)
* 核心业务主链规范:[02-business-process.md](02-business-process.md)
* API 端点清单:[06-api-and-permission-overview.md](06-api-and-permission-overview.md)
* 自动化测试验证矩阵:[07-testing-and-acceptance.md](07-testing-and-acceptance.md)
@@ -0,0 +1,77 @@
# 06. RailwaySystem API 与权限体系总览
> **文档定位**:面向前端开发、集成团队及安全审计人员,系统梳理核心业务 API 契约、专用写操作(Write Actions)及 RBAC 权限体系。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 核心业务 API 端点分组
系统提供遵循 RESTful 规范的标准化 API 接口体系,统一由 `ruoyi-admin` 暴露,业务逻辑封装于 `ruoyi-train`。各业务域核心端点如下:
### 1.1 基础教务资源接口
* **教师管理**:`GET /train/teacher/list`, `POST /train/teacher`, `PUT /train/teacher`, `DELETE /train/teacher/{ids}`
* **学员主档**:`GET /train/student/list`, `POST /train/student`, `PUT /train/student`, `GET /train/student/{id}` (敏感信息脱敏)
* **课程资源**:`GET /train/course/list`, `POST /train/course`, `PUT /train/course`
* **教学空间**:`GET /train/classroom/list`, `POST /train/classroom`, `GET /train/training-site/list`, `POST /train/training-site`
* **宿舍生活**:`GET /train/dormitory/list`, `POST /train/dormitory`, `GET /train/dormitory/{id}/occupants` (住户查询)
* **电子班牌**:`GET /train/board/list`, `POST /train/board`, `PUT /train/board`, `DELETE /train/board/{id}` (后端 API 路径为 `/train/board`,对应前端页面路由为 `/equip/board`)
### 1.2 开班计划与排课编排接口
* **开班计划**:
* `POST /train/plans` —— 创建开班计划(状态置为 0:草稿)
* `GET /train/plans/{id}` —— 查询开班计划详情
* `POST /train/plans/{id}/complete` —— **一键结训强事务操作**(计划状态更新为 2,联动更新在读学员参训状态为 4)
* **本期课程**:`POST /train/plans/{id}/courses`, `GET /train/plans/{id}/courses`
* **学员报名**:`POST /train/plans/{id}/enrollments` (名单录入), `PUT /train/enrollments/{id}/status` (状态调整)
* **课次编排**:
* `POST /train/lessons/check-conflict` —— **四维排课冲突实时预检**(失焦调用,返回 `LessonConflictVO`)
* `POST /train/plans/{id}/lessons` —— 新增课次(标准 POST 保存,严格禁止 `force` / `ignoreConflict` / `overrideConflict` 旁路参数;排课流程中 `Lesson detail GET: NOT CALLED`)
* `GET /train/plans/{id}/timetable` —— 培训班可视化课表视图
### 1.3 系统管理与在线接口工具
* **系统接口 (Swagger UI)**:
* 真实系统入口:`系统工具 → 系统接口`
* 接口健康状况:Swagger UI 正常渲染,`v3/api-docs = 200`,`swagger-resources = 200`,无 502 坏网关,无死链
* **系统工具其他可见项**:表单构建、代码生成正常可见可用
---
## 2. 专用写操作 (Core Write Actions)
针对现场高频、高安全核验的业务场景,系统设计了专用的写操作端点:
| 业务动作 | HTTP 动词与 URL 路径 | 核心业务行为与事务约束 | 所需安全权限 |
| :--- | :--- | :--- | :--- |
| **开班现场报到** | `POST /train/plans/{planId}/enrollments/{enrollmentId}/report`<br>*(或 `/train/enrollments/{enrollmentId}/report`)* | 核验报到时效,写入报到流水 `train_class_report`,联动将参训档案 `enrollment_status` 置为 1 (已报到)。 | `train:report:confirm` |
| **课次签到打卡** | `POST /train/lessons/{lessonId}/attendance/checkin`<br>*(或 `/train/attendance/sign-in`)* | 记录学员课次签到时间戳,校验是否超出允许时段,生成或更新考勤结论。 | `train:attendance:checkin` |
| **课次签退打卡** | `POST /train/attendance/sign-out` | 记录学员法定签退时间戳,结合签到时间自动核算考勤最终结论(正常/早退)。 | `train:attendance:checkin` |
| **教师代签/请假修正**| `POST /train/lessons/{lessonId}/attendance/adjust`<br>*(或 `PUT /train/attendance/{checkinId}`)* | 教师或管理员人工修正考勤结论(0~4),强制将 `manual_flag` 置为 1 留痕存盘。 | `train:attendance:edit` |
---
## 3. RBAC 权限体系与菜单治理
系统全面对齐若依标准的“用户—角色—菜单”基于角色的访问控制(RBAC)架构:
### 3.1 核心业务权限标识符
* 报到模块:`train:report:list` (查询), `train:report:export` (导出), `train:report:confirm` (现场确认)
* 考勤模块:`train:attendance:list` (查询), `train:attendance:export` (导出), `train:attendance:checkin` (打卡), `train:attendance:edit` (代签调整)
* 学时分析:`train:learning:list`, `train:learning:export`
* 学员画像:`train:portrait:query`, `train:portrait:export`
### 3.2 发布增量 003 权限补齐机制
在最新的数据库迁移脚本 `003_report_attendance_action_permissions.sql` 中:
1. **菜单项创建**:脚本自动向 `public.sys_menu` 表中注入了 `train:report:confirm` (ID: 2181)、`train:attendance:checkin` (ID: 2182) 与 `train:attendance:edit` (ID: 2183) 三项按钮级权限记录;
2. **角色绑定规范说明**:
- `003` 脚本只负责在数据库中安全声明这三项可授权的原子能力项;
- **角色与菜单的绑定(`sys_role_menu`)属于环境运行时配置(ENVIRONMENT_CONFIGURATION)**,管理员可根据各局各院校的实际管理制度,在前端【系统管理 -> 角色管理】中将上述权限灵活分配给“班主任”、“任课教师”或“考勤监督员”等业务角色。
---
## 4. 技术参考链接 (Technical References)
* API V2 契约总纲:[docs/api-v2/00_readme.md](../api-v2/00_readme.md)
* 全量 DTO/VO 字典:[docs/api-v2/06_dto_vo_catalog.md](../api-v2/06_dto_vo_catalog.md)
* 权限与全量错误码定义:[docs/api-v2/10_permission_and_error_codes.md](../api-v2/10_permission_and_error_codes.md)
* 报到与考勤权限迁移验证:[docs/reports/release-notes.md](../reports/release-notes.md)
@@ -0,0 +1,89 @@
# 07. RailwaySystem 质量保障与自动化测试报告
> **文档定位**:面向质量审计人员、技术评测专家及交付团队的系统化测试与验收报告。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 质量保障体系全景
RailwaySystem 建立了多层次的自动化测试与质量防护网络,确保从底层数据模型、服务契约、端到端接口到真实物理数据库的全链路正确性:
```mermaid
graph TD
L1["端到端浏览器验收 (E2E)<br/>Playwright 真实 UI 验收 · 0 阻断 / 0 个 500 · <b>PASS</b>"]
L2["核心业务场景集成 Gate (Scenario)<br/>6 大场景真实 HTTP 110 次请求全链路闭环 · <b>PASS</b>"]
L3["应用服务与契约测试 (Unit / Contract)<br/>154 项测试用例全覆盖 · 业务不变量与状态机转换 · <b>PASS</b>"]
L4["数据库物理断言与清理门禁 (DB Gate)<br/>11 项 Kingbase 物理表断言 · 0 脏数据残留 · <b>PASS</b>"]
L4 --> L3
L3 --> L2
L2 --> L1
```
---
## 2. 核心测试指标汇总看板
| 验证维度 | 衡量指标 | 目标要求 | 实测结果 | 门禁结论 |
| :--- | :--- | :---: | :---: | :---: |
| **后端单元与契约测试** | Maven Test Suite 执行用例数 | 100% 通过 | **154 / 154 PASS** | ✅ **通过** |
| **核心业务场景集成** | 真实业务链路场景套件 (Scenarios) | 全部通过 | **6 / 6 PASS** | ✅ **通过** |
| **真实 HTTP 接口探测**| 实际发起网络交互请求总数 | 覆盖主链路 | **110 次** | ✅ **就绪** |
| **服务端异常率** | HTTP 500 系统内部崩溃错误数 | 严格为 0 | **0 异常** | ✅ **通过** |
| **Kingbase 物理数据断言**| 数据库真实记录状态与约束断言 | 100% 一致 | **11 / 11 PASS** | ✅ **通过** |
| **环境清理与残留检验**| 测试数据回滚与物理删除验证 | 零残留 | **Cleaned (Residue: 0)**| ✅ **通过** |
| **端到端浏览器验收** | Playwright 真实交互验收套件 | 全流程通行 | **PASS** *(0 阻断 / 0 个 500)* | ✅ **通过** |
| **Swagger 接口文档平台** | 接口定义与 UI 正常加载探测 | 无 502/死链 | **PASS** *(入口: 系统工具→系统接口)* | ✅ **通过** |
---
## 3. 六大核心场景集成测试覆盖 (Scenarios)
针对铁路教务的最核心闭环,集成测试套件对以下六大关键业务场景进行了真实环境端到端验证:
1. **基础资源初始化与唯一性校验**:
- 教师档案录入(手机号唯一拦截 `40001`)、学员建档(敏感信息脱敏与哈希存储)、课程库建立与教室/实训场地可用性验证。
2. **开班计划拟定与课程师资绑定**:
- 创建 32 位 UUID 标识的开班计划(初始强制为 0:草稿)、绑定计划专属课程与授课教师、计划学时自动汇总。
3. **学员批量报名与容纳上限拦截**:
- 正常学员入班生成参训履历(初始 0:待报到);重复报名强行拦截(`40030 ENROLLMENT_ALREADY_EXISTS`);计划招生超额硬阻断(`40031 ENROLLMENT_CAPACITY_EXCEEDED`);停用学员拒绝报名。
4. **四维排课防重叠智能检测**:
- 课次编排预检;教师授课时间冲突检测(`40040`);场地与班级课次重叠软警告(Warning 不阻断,用户确认后正常保存);场地 XOR 互斥与起止时间非法硬拦截。
5. **现场开班报到与多模式核验**:
- 现场身份核验(人脸/刷卡/扫码/人工),写入报到流水,强事务联动参训档案流转为 1:已报到。
6. **结训联动与历史状态保护**:
- 计划结训触发强事务流转(计划置为 2:已结束);活动在读学员(状态为 0 或 1)自动流转为 4:已完成;历史退训学员(状态为 3)受到严格保护不被误覆盖。
---
## 4. 浏览器真实验收与 Swagger 验证结果
针对 Final Candidate 基线(Tested HEAD: `5a49b2e2988bf23ca2a70568264c05b24dfda1b6`)的端到端真实浏览器验收已全部完成,达成 `FINAL_BROWSER_ACCEPTANCE = PASS`:
* **Browser 交互状态**:`PASS`(Console blocker: `0`,HTTP 500: `0`)
* **Swagger 接口平台**:`PASS`
- 真实系统入口:`系统工具 → 系统接口`
- Swagger UI:正常加载,`v3/api-docs = 200`,`swagger-resources = 200`,无 502,无死链
* **主数据模块 (Master Data)**:Teacher PASS、Student PASS、Classroom PASS、Site PASS 均通过
* **核心业务模块 (Business)**:Plan PASS、PlanCourse PASS、Enrollment PASS 均通过
* **报到核验 (Report Confirm)**:`PASS`,真实调用 `POST /train/enrollments/{enrollmentId}/report` 返回 200 OK,待报到 → 已报到
* **排课冲突处理 (Scheduling)**:
- Warning Cancel = `PASS`
- Warning Confirm/Save = `PASS`
- 逻辑中严格禁止且无 `force` / `ignoreConflict` / `overrideConflict` 旁路
- 课次详情 GET 查询:`Lesson detail GET: NOT CALLED`
* **电子班牌 (Board)**:`PASS`(前端路由:`/equip/board`)
* **统计分析报表 (Analytics)**:Report Analytics、Checkin Analytics、Duration、Portrait 均为 `PASS / Read Only`
* **系统操作日志 (OperLog)**:`PASS`
* **系统工具实际可见**:表单构建、代码生成、系统接口
* **角色分配管理**:`RBAC_ROLE_ASSIGNMENT: ENVIRONMENT_CONFIGURATION`
* **验收数据审计策略**:`Browser acceptance created/changed data: KEEP_FOR_AUDIT`(文档验收阶段留存用于审计追溯,不执行清理)
---
## 5. 技术参考链接 (Technical References)
* 核心测试矩阵明细:[docs/_meta/core-business-test-matrix.md](../_meta/core-business-test-matrix.md)
* 最终测试综合报告:[docs/reports/final-test-report.md](../reports/final-test-report.md)
* 浏览器端到端验收进度:[docs/reports/browser-acceptance-report.md](../reports/browser-acceptance-report.md)
+102
View File
@@ -0,0 +1,102 @@
# 08. RailwaySystem 部署与发布指南
> **文档定位**:面向运维工程师、发布主管及系统管理员的生产与测试环境部署、数据库迁移及服务维护手册。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 目标运行环境标准
系统在多环境部署中遵循标准化的网络拓扑与端口规划:
```mermaid
flowchart LR
subgraph Clients["客户端层"]
Web["PC 浏览器 (Admin/教师/学员)"]
BoardDev["物联网终端 (电子班牌)"]
end
subgraph ReverseProxy["反向代理与静态托管 (端口 8082)"]
Nginx["Nginx Web 服务<br/>静态托管 build_ui / SSL 443 / 8082"]
end
subgraph AppCluster["业务应用服务 (端口 8092)"]
SpringBoot["Spring Boot 容器 (ruoyi-admin)<br/>JVM 4GB+ / 端口 8092"]
end
subgraph DataTier["国产数据库与缓存层"]
KB[("人大金仓 KingbaseES V9<br/>端口 54321 / 4321")]
Redis[("Redis 缓存服务<br/>端口 6379")]
end
Web -->|HTTP / HTTPS| Nginx
BoardDev -->|HTTP API| Nginx
Nginx -->|反向代理 /prod-api| SpringBoot
SpringBoot -->|JDBC 8.6.0| KB
SpringBoot -->|Jedis / Lettuce| Redis
```
| 组件名称 | 本地开发环境端口 | 集成与验收测试环境端口 | 生产环境建议规范 |
| :--- | :---: | :---: | :--- |
| **后端 API 服务 (Spring Boot)** | `8090` | **`8092`** | 8090~8099 负载均衡集群,JVM 内存建议分配 4GB+ |
| **前端交互应用 (Vue/Nginx)** | `8080` | **`8082`** | Nginx 反向代理(443/80),开启 Gzip 压缩与静态缓存 |
| **KingbaseES 国产主库** | `127.0.0.1:4321` (SSH隧道)| 直连实例 `54321` / `4321` | 国产人大金仓数据库实例,标准单主库配置 |
| **Redis 缓存服务** | `6379` (无密码) | `6379` (带密码预检) | 标准 Redis 缓存服务,用于 Token 校验与验证码防重放 |
---
## 2. 发布增量迁移规范 (Release DB Delta)
在系统从初始 V2 物理结构演进到当前 Final Candidate 的过程中,形成了正式的发布增量迁移序列:
> **正式发布增量版本**:`CURRENT_RELEASE_DB_DELTA = 3`
### 2.1 正式 Delta 脚本清单
1. **Delta 001** —— `RuoYi-Vue/sql/system/kingbase/001_sys_oper_log_cost_time.sql`
- 作用:补齐 Kingbase 系统操作日志表中的消耗时间(`cost_time`)统计字段,保障运维监控正常运行。
2. **Delta 002** —— `RuoYi-Vue/sql/system/kingbase/002_legacy_analytics_permissions.sql`
- 作用:将旧分析模块菜单权限与 V2 契约精准对齐,建立只读报表查询与导出安全屏障。
3. **Delta 003** —— `RuoYi-Vue/sql/system/kingbase/003_report_attendance_action_permissions.sql`
- 作用:向 `public.sys_menu` 表声明开班现场报到确认(`train:report:confirm`)、课次考勤打卡(`train:attendance:checkin`)与考勤人工修正(`train:attendance:edit`)三项按钮级原子权限。
### 2.2 字典初始化红线警示
* ⚠️ **`007_dicts.sql` 明确执行禁令**:
- **`DO NOT EXECUTE`**:该脚本包含了大量未经环境幂等校验的历史字典初始数据,若盲目物理执行会污染生产 `sys_dict_data` 主键并引发唯一性冲突。在当前发布版本中严格禁止在生产库物理执行!
---
## 3. 标准发布与升级步骤
生产升级必须遵循受控操作规程:
```bash
# 步骤 1:拉取受控发布分支最新代码
git checkout feat/cicd-pipeline
git pull origin feat/cicd-pipeline
# 步骤 2:驱动依赖与环境预检
bash scripts/bootstrap/check-kingbase-jdbc.sh
# 步骤 3:数据库增量应用 (仅执行当前 Delta 001/002/003)
ksql -U SYSTEM -d training -f RuoYi-Vue/sql/system/kingbase/001_sys_oper_log_cost_time.sql
ksql -U SYSTEM -d training -f RuoYi-Vue/sql/system/kingbase/002_legacy_analytics_permissions.sql
ksql -U SYSTEM -d training -f RuoYi-Vue/sql/system/kingbase/003_report_attendance_action_permissions.sql
# 步骤 4:后端服务编译打包与启动 (8092 目标端口)
mvn clean package -DskipTests
java -Xms2048m -Xmx4096m -jar RuoYi-Vue/ruoyi-admin/target/ruoyi-admin.jar --server.port=8092 &
# 步骤 5:前端静态资源编译并由 Nginx 承载 (8082 目标端口)
cd build_ui
npm run build:prod
# 部署至 Nginx html 目录,加载 deploy/nginx.conf.example 配置
```
---
## 4. 技术参考链接 (Technical References)
* Kingbase JDBC 驱动依赖说明:[deployment/kingbase-jdbc-provisioning.md](deployment/kingbase-jdbc-provisioning.md)
* 发版说明与变更记录:[docs/reports/release-notes.md](../reports/release-notes.md)
* 部署验收与就绪报告:[docs/reports/deployment-report.md](../reports/deployment-report.md)
* 数据库物理模型清单:[docs/database-v2/01_table_inventory.md](../database-v2/01_table_inventory.md)
+51
View File
@@ -0,0 +1,51 @@
# 09. RailwaySystem 当前系统状态全貌
> **文档定位**:面向全员的项目交付状态与版本基线综合看板,透明展示当前工程指标、未决事项与后续演进路线。
> **当前基线**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
---
## 1. 核心状态综合看板 (Status Dashboard)
| 审计维度 | 状态指标 | 当前权威事实 | 阶段状态 |
| :--- | :--- | :--- | :---: |
| **Git 代码基线** | Final Candidate HEAD | `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` | ✅ **已冻结** |
| **代码主干分支** | 远程交付集成分支 | `origin/feat/cicd-pipeline` | ✅ **已同步** |
| **后端单元/契约测试**| Maven 测试套件用例 | **154 / 154 PASS** | ✅ **全通过** |
| **核心业务场景套件**| 真实集成场景用例 | **6 / 6 PASS** | ✅ **全通过** |
| **真实 HTTP 请求验证**| 自动化链路真实网络交互 | **110 次**,0 次 500 内部异常 | ✅ **高稳定** |
| **Kingbase 物理落库断言**| 真实数据库记录完整性验证 | **11 / 11 PASS** | ✅ **全通过** |
| **发布数据库增量**| Release DB Delta 序列 | **CURRENT_RELEASE_DB_DELTA = 3** (`001`, `002`, `003`) | ✅ **已就绪** |
| **环境残留与回滚**| 测试后自动物理清理校验 | **PASS (Residue: 0)** | ✅ **无污染** |
| **端到端浏览器验收**| Playwright 真实 UI 验收 (0 阻断 / 0 个 500) | **FINAL_BROWSER_ACCEPTANCE = PASS** | ✅ **全通过** |
| **Swagger 接口在线探测**| 接口文档服务 (系统工具→系统接口) | **PASS** (v3/api-docs=200, resources=200) | ✅ **已验证** |
| **正式生产部署就绪度**| 线上集群部署验证 | **FORMAL_DEPLOYMENT = PENDING** | ⏳ **待发布** |
---
## 2. 业务功能完备性矩阵速览
根据当前代码与测试验证,14 大业务模块实现覆盖情况如下:
* **全面闭环实现 (IMPLEMENTED & VERIFIED PASS)**:
- 基础资源:教师管理 (Teacher PASS)、学员主档 (Student PASS)、标准课程库 (Course PASS)、理论教室 (Classroom PASS)、实训场地 (Site PASS)、宿舍房间 (Dormitory PASS)
- 教务管理:开班计划 (Plan PASS)、本期课程 (PlanCourse PASS)、参训名单 (Enrollment PASS)、排课与冲突预检 (Scheduling PASS,Warning Cancel/Confirm 双通过,无 force/ignoreConflict 旁路)
- 现场执行:开班现场报到 (Report Confirm PASS,状态待报到→已报到)、课次考勤打卡与调整 (Attendance)、电子班牌管理 (Board PASS,前端路由 `/equip/board`)
- 系统运维与审计:操作日志 (OperLog PASS)、系统工具正常可见(表单构建、代码生成、系统接口)
* **只读分析模型已完成 (PARTIAL - V2 Read Model 就绪 & 验证 PASS)**:
- 统计分析 (Analytics):报到统计 (Report Analytics PASS)、考勤明细分析 (Checkin Analytics PASS)、学时完成度 (Duration PASS)、学员多维画像 (Portrait PASS) 的只读查询与数据导出已全部通过(Read Only 验证);高级跨期聚合计分(Advanced Aggregation)明确标记为二期规划,不纳入门禁阻断。
---
## 3. 下一阶段演进路线图 (Next Steps)
1. **生产集群环境部署验证**:在目标生产端口(8092/8082)执行预发布部署演练,产出 [docs/reports/deployment-report.md](../reports/deployment-report.md)。
2. **正式发版与交付**:基于当前稳定的 Final Candidate 生成正式 Release 标签,组织向最终客户及评审专家的成果汇报。
---
## 4. 技术参考链接 (Technical References)
* 视觉化展示门户:[docs/visual/index.html](../visual/index.html)
* 最终测试综合报告:[docs/reports/final-test-report.md](../reports/final-test-report.md)
* 发版说明:[docs/reports/release-notes.md](../reports/release-notes.md)
* 架构白皮书:[03-system-architecture.md](03-system-architecture.md)
+107
View File
@@ -0,0 +1,107 @@
# RailwaySystem 端到端浏览器自动化验收报告
> **文档定位**:记录基于 Playwright 的真实前端界面全流程交互、端到端用户路径及跨模块联动验收结果。
> **基线版本**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
> **执行状态**:✅ **FINAL_BROWSER_ACCEPTANCE = PASS**
> **Swagger 接口平台状态**:✅ **PASS** *(系统工具 → 系统接口,v3/api-docs=200,swagger-resources=200)*
> **HTTP 500 异常**:**0** | **Console 阻断错误**:**0**
---
## 1. 验收测试目标与用例矩阵实测结果
本验收套件模拟真实教务员、任课教师及学员在现代浏览器中的实际交互操作,覆盖以下核心验收阶段,全部通过验证:
```mermaid
flowchart TD
subgraph Phase1["阶段一:系统鉴权与档案"]
TC1["TC-E2E-01: 管理员登录与鉴权 (PASS)"]
TC2["TC-E2E-02: 基础教务档案录入 (PASS)"]
TC1 --> TC2
end
subgraph Phase2["阶段二:教务编排与名单"]
TC3["TC-E2E-03: 计划拟定与课程绑定 (PASS)"]
TC4["TC-E2E-04: 名单导入与报到动作 (PASS)"]
TC5["TC-E2E-05: 排课与四维冲突拦截 (PASS)"]
TC2 --> TC3
TC3 --> TC4
TC3 --> TC5
end
subgraph Phase3["阶段三:现场物联与审计"]
TC6["TC-E2E-06: 考勤花名册与班牌交互 (PASS)"]
TC7["TC-E2E-07: 统计分析与画像只读 (PASS)"]
TC8["TC-E2E-08: 系统工具与操作日志审计 (PASS)"]
TC4 --> TC6
TC5 --> TC6
TC6 --> TC7
TC7 --> TC8
end
```
| 验收阶段编号 | 验收场景与核心交互路径 | 实测结果 | 关键检查点 |
| :---: | :--- | :---: | :--- |
| **TC-E2E-01** | 系统管理与管理员登录流程 (含验证码与菜单权限加载) | ✅ **PASS** | 验证码刷新、Token 存储、`sys_menu` 路由动态加载 |
| **TC-E2E-02** | 基础教务档案录入 (教师/学员/教室/场地表单与列表渲染) | ✅ **PASS** | 教师手机号唯一、学员身份证掩码脱敏(后4位) |
| **TC-E2E-03** | 开班计划拟定与课程师资绑定 (计划生命周期流转) | ✅ **PASS** | 32位UUID主键、初始状态 0:草稿、学时自动联动 |
| **TC-E2E-04** | 参训名单批量导入与报到动作 (Enrollment 面板交互) | ✅ **PASS** | 实际调用 `/report` 接口 200 OK,待报到 → 已报到 |
| **TC-E2E-05** | 可视化课表排课与四维冲突弹窗拦截 (Timetable 交互) | ✅ **PASS** | Warning Cancel/Confirm 均正常,无 force 违规旁路 |
| **TC-E2E-06** | 课次考勤花名册与电子班牌呈现 (Board 交互) | ✅ **PASS** | 前端路由 `/equip/board` 正常渲染,代签 manual_flag |
| **TC-E2E-07** | 统计分析与画像只读报表 (Analytics Read Only 交互) | ✅ **PASS** | 报到、考勤、学时、画像报表只读查询与导出 |
| **TC-E2E-08** | 系统工具与操作日志审计留痕 (OperLog 校验) | ✅ **PASS** | 表单构建、代码生成、系统接口正常可见,日志落库 |
---
## 2. 核心模块真实验收客观记录
### 2.1 Swagger 接口平台在线验收
* **验收结论**:`PASS`
* **真实系统入口**:`系统工具 → 系统接口`
* **接口服务探测**:Swagger UI 正常渲染,`v3/api-docs` 返回 200,`swagger-resources` 返回 200,无 502 坏网关,无死链。
### 2.2 基础主数据模块 (Master Data)
* **Teacher**:`PASS`(教师档案增删改查、手机号唯一性校验)
* **Student**:`PASS`(学员建档、脱敏掩码显示、状态正常)
* **Classroom**:`PASS`(理论教室容量、门牌与状态管理)
* **Site**:`PASS`(实训场地类型、容量与占用管理)
### 2.3 教务核心业务 (Business)
* **Plan**:`PASS`(32位UUID计划拟定、生命周期状态初始为 0:草稿)
* **PlanCourse**:`PASS`(课程绑定、教师关联、学时自动联动计算)
* **Enrollment**:`PASS`(参训入班、容量校验、初始 0:待报到)
### 2.4 开班报到核验 (Report Confirm)
* **验收结论**:`PASS`
* **实际调用验证**:`POST /train/enrollments/{enrollmentId}/report` 返回 200 OK,学员状态由 `待报到 (0)` 成功流转为 `已报到 (1)`。
* **术语与界面说明**:前端菜单显示为 `UI_MENU_LABEL = 开班签到`,业务模型与契约术语为 `BUSINESS_TERM = 开班报到`。
### 2.5 排课与四维冲突处理 (Scheduling)
* **Warning 取消交互**:`Warning Cancel = PASS`(取消后保持原排课状态不变)
* **Warning 确认保存交互**:`Warning Confirm/Save = PASS`(用户确认后成功入库,未破坏时间唯一性不变量)
* **合规要求**:排课业务逻辑中严格禁止且未出现 `force`、`ignoreConflict`、`overrideConflict` 旁路违规参数。
* **课次详情查询**:`Lesson detail GET: NOT CALLED`(遵循契约规范,不发起多余查询)。
### 2.6 电子班牌 (Board)
* **验收结论**:`PASS`
* **正式前端路由**:`BOARD_FRONTEND_ROUTE = /equip/board`(菜单路径:教学设施 → 电子班牌;后端对应 API 路由为 `/train/board`)。
### 2.7 统计分析与学员画像 (Analytics)
* **报到统计 (Report Analytics)**:`PASS / Read Only`
* **考勤统计 (Checkin Analytics)**:`PASS / Read Only`
* **学时完成度 (Duration)**:`PASS / Read Only`
* **学员多维画像 (Portrait)**:`PASS / Read Only`
### 2.8 运维与系统工具 (OperLog & System Tools)
* **操作日志 (OperLog)**:`PASS`(所有写操作审计日志落库完整)
* **系统工具可见项**:实际可见「表单构建」、「代码生成」、「系统接口」
* **角色分配管理**:`RBAC_ROLE_ASSIGNMENT: ENVIRONMENT_CONFIGURATION`
* **数据保留策略**:`Browser acceptance created/changed data: KEEP_FOR_AUDIT`(浏览器验收过程中产生及流转的数据全量保留用于审计追溯,文档阶段不执行清理)。
---
## 4. 技术参考链接 (Technical References)
* 综合测试报告:[final-test-report.md](final-test-report.md)
* 核心业务测试矩阵:[docs/_meta/core-business-test-matrix.md](../_meta/core-business-test-matrix.md)
* 业务主链规范:[docs/handbook/02-business-process.md](../handbook/02-business-process.md)
+60
View File
@@ -0,0 +1,60 @@
# RailwaySystem 部署与发布准备度报告
> **文档定位**:记录目标环境部署、Nginx 反向代理配置、生产数据库迁移执行状态及服务健康检查结果。
> **基线版本**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
> **发布增量基线**:`CURRENT_RELEASE_DB_DELTA = 3`
> **当前部署状态**:⏳ **PENDING** *(等待最终测试门禁收敛后统一执行部署)*
---
## 1. 目标发布环境规格
```mermaid
flowchart TD
subgraph Env["生产目标环境 (8092/8082)"]
FE["前端 Web (Nginx 静态托管)<br/>端口 8082<br/>健康检查: HTTP 200"]
BE["后端 API (Spring Boot)<br/>端口 8092<br/>健康检查: GET /login"]
DB[("国产主库 KingbaseES<br/>端口 4321 / 54321<br/>健康检查: Druid连接池")]
RD[("缓存 Redis<br/>端口 6379<br/>健康检查: AUTH & PING")]
FE -->|/prod-api 代理| BE
BE --> DB
BE --> RD
end
```
| 服务组件 | 部署端口 | 运行载体 | 环境健康检查目标 | 准备状态 |
| :--- | :---: | :--- | :--- | :---: |
| **后端 API 服务** | `8092` | Spring Boot 2.5 (JAR) | `GET /login -> HTTP 200` | ⏳ PENDING |
| **前端 Web 交互** | `8082` | Nginx 1.20+ (静态承载) | HTTP 200 访问正常 | ⏳ PENDING |
| **国产主数据库** | `4321` | KingbaseES 8.6.0 | JDBC 连接池探测正常 (Druid) | ✅ 就绪 |
| **会话与缓存服务**| `6379` | Redis 6.2+ | `AUTH & PING -> PONG` | ✅ 就绪 |
---
## 2. 数据库迁移准备度与增量核实
1. **增量 Delta 脚本就绪情况**:
- [x] `001_sys_oper_log_cost_time.sql` —— 消耗时间字段补齐(就绪)
- [x] `002_legacy_analytics_permissions.sql` —— 分析权限对齐(就绪)
- [x] `003_report_attendance_action_permissions.sql` —— 报到与考勤写操作权限(就绪)
2. **安全红线核实**:
- 确认生产发布中**严禁执行 `007_dicts.sql`**,避免字典主键唯一性碰撞。
---
## 3. 部署验证检查清单 (Deployment Checklist)
* [ ] 后端 JAR 包编译打包无误(`mvn clean package -DskipTests`)
* [ ] 目标端口 `8092` 进程无冲突占用
* [ ] 前端打包产物构建无报错(`npm run build:prod`)
* [ ] Nginx 反向代理配置加载完成(`/api` 代理至 `8092`)
* [ ] 初始超级管理员账号 `admin` 登录鉴权通过
---
## 4. 技术参考链接 (Technical References)
* 部署与发布手册:[docs/handbook/08-deployment-and-release.md](../handbook/08-deployment-and-release.md)
* 发版说明:[release-notes.md](release-notes.md)
* 最终测试综合报告:[final-test-report.md](final-test-report.md)
+68
View File
@@ -0,0 +1,68 @@
# RailwaySystem Final Candidate 综合测试验收报告
> **文档定位**:全方位记录当前交付候选版本在单元、契约、场景集成、物理数据库及清理门禁等方面的最终测试验收结果。
> **基线版本**:Final Candidate `5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
> **报告生成时间**:2026-09-15
> **总体验收结论**:✅ **CORE BACKEND & INTEGRATION ACCEPTANCE PASS**
---
## 1. 测试执行概况
本轮测试在完全模拟生产的 KingbaseES 国产高安全数据库与真实 Spring Boot 容器环境下执行,涵盖了应用服务单元测试、API 契约测试、跨模块业务场景端到端集成测试及物理落库断言。
```mermaid
graph LR
T1["后端单元/契约测试<br/>154/154 PASS"] --> T2["业务场景集成<br/>6/6 PASS"]
T2 --> T3["HTTP API探测<br/>110次 0次500 PASS"]
T3 --> T4["Kingbase物理断言<br/>11/11 PASS"]
T4 --> T5["环境清理门禁<br/>0残留 PASS"]
style T1 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style T2 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style T3 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style T4 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style T5 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
```
| 测试大项 | 执行用例数 | 通过数 | 失败数 | 结论 |
| :--- | :---: | :---: | :---: | :---: |
| **1. 后端应用服务与契约测试 (Maven)** | 154 | 154 | 0 | ✅ **PASS** |
| **2. 核心业务主链场景套件 (Scenarios)** | 6 | 6 | 0 | ✅ **PASS** |
| **3. 真实网络 HTTP API 探测调用** | 110 | 110 | 0 | ✅ **PASS** |
| **4. 服务端 500 异常捕获率** | - | - | 0 | ✅ **PASS (0 异常)** |
| **5. Kingbase 物理表持久化断言** | 11 | 11 | 0 | ✅ **PASS** |
| **6. 数据物理清理与零残留门禁 (Cleanup)** | - | - | - | ✅ **PASS (Residue: 0)** |
---
## 2. 核心业务场景集成测试明细 (6/6 PASS)
| 编号 | 测试场景名称 | 涉及核心接口与操作 | 物理数据库断言与验证点 | 实测结果 |
| :---: | :--- | :--- | :--- | :---: |
| **SC-01** | **完整正向业务闭环全链 (Happy Path Full Business Chain)** | `POST /train/teacher`<br>`POST /train/course`<br>`POST /train/classroom`<br>`POST /train/plans`<br>`POST /train/plans/{id}/courses`<br>`POST /train/plans/{id}/enrollments`<br>`POST /train/plans/{id}/lessons`<br>`GET /train/plans/{id}/timetable`<br>`POST /train/plans/{id}/complete` | 基础资源就绪 → 拟定32位UUID计划 → 课程与师资绑定 → 学员报名入班(初始0) → 排课课次落库 → 课表聚合查询 → 计划结训联动在读学员状态流转至4且记录complete_time。 | **PASS** |
| **SC-02** | **学员报名异常规则与状态区分 (Enrollment Validation)** | `POST /train/plans/{id}/enrollments`<br>`PUT /train/enrollments/{id}/status` | 1. 同一计划重复报名触发唯一索引拦截 (`40030`);<br>2. 招生容量上限超限拦截 (`40031`);<br>3. 不存在学员与停用学员 (`status=0`) 拒绝入班;<br>4. 独立维护学员主档状态与班级参训状态。 | **PASS** |
| **SC-03** | **排课预检 Warning 与 Hard Block 硬阻断 (Scheduling)** | `POST /train/lessons/check-conflict`<br>`POST /train/plans/{id}/lessons` | 1. 教师冲突硬检,教室/场地/班级重叠 Warning 预警且不硬阻断保存;<br>2. 严格禁止 force/override 参数;<br>3. 非法起止时间倒挂拦截 (`40010`);<br>4. 场地 XOR 互斥硬阻断;<br>5. 已结束计划锁定排课 (`40012`)。 | **PASS** |
| **SC-04** | **电子班牌绑定与课表降级映射 (Electronic Board)** | `POST /train/board`<br>`GET /train/classroom/{id}`<br>`GET /train/plans/{id}/timetable`<br>`DELETE /train/board/{id}` | 1. 自动生成32位UUID主键,默认在线状态 `board_status=0`;<br>2. 教室详情返回绑定班牌数组 (0/1/N);<br>3. 课表 `boardSn` 降级规则:0块为null,1块为对应SN,>1块降级为null;<br>4. 逻辑删除置 `del_flag='2'`。 | **PASS** |
| **SC-05** | **结训生命周期与退训学员保护 (Plan Completion Lifecycle)** | `POST /train/plans/{id}/complete`<br>`GET /train/plans/{id}`<br>`GET /train/enrollments/{id}` | 1. 计划状态更新为 `2:已结束`;<br>2. 本班在读活动学员 (状态0/1) 自动联动更新为 `4:已完成` 且写入 `complete_time`;<br>3. 历史退训学员 (状态3) 保持不变,杜绝误覆盖。 | **PASS** |
| **SC-06** | **现场报到与课堂考勤完整闭环 (Report & Attendance Lifecycle)** | `POST /train/enrollments/{id}/report`<br>`POST /train/attendance/sign-in`<br>`POST /train/attendance/sign-out`<br>`PUT /train/attendance/{checkinId}` | 1. 报到确认返回 `reportId`,学员状态强事务流转为 `1:已报到` 且写入 `join_time`;<br>2. 重复报到拦截 (`40050`);<br>3. 签到签退幂等性防覆盖(保持初次时间);<br>4. 人工考勤调整自动留痕 `manual_flag=1`。 | **PASS** |
---
## 3. 数据库断言与环境清理验证
在场景集成套件执行期间与执行完毕后,执行了针对底层 Kingbase 物理库的直接核查:
1. **落库断言 (11/11 PASS)**:
- 验证了教师主键持久化、学员密文与哈希完整性、开班计划状态标记、参训档案唯一性、课次场地互斥、报到流水完整性、结训联动更新记录数等 11 项关键 SQL 校验,准确率 100%。
2. **物理清理门禁 (PASS, Residue: 0)**:
- 测试套件在验证完毕后,触发受控清理机制,物理删除全部测试生成的临时学员、课次与开班计划;
- 最终执行扫描确认:**测试产生的数据残留为 0,生产数据库保持完全纯净**。
---
## 4. 技术参考链接 (Technical References)
* 核心测试矩阵事实源:[docs/_meta/core-business-test-matrix.md](../_meta/core-business-test-matrix.md)
* 业务流程与状态机:[docs/handbook/02-business-process.md](../handbook/02-business-process.md)
* 浏览器端到端验收报告:[browser-acceptance-report.md](browser-acceptance-report.md)
* 发版说明:[release-notes.md](release-notes.md)
+83
View File
@@ -0,0 +1,83 @@
# RailwaySystem v1.0 Final Candidate 发版说明 (Release Notes)
> **发版版本号**:v1.0.0-final-candidate
> **Git 提交基线**:`5a49b2e2988bf23ca2a70568264c05b24dfda1b6` (`origin/feat/cicd-pipeline`)
> **发布日期**:2026-09-15
> **发布增量状态**:`CURRENT_RELEASE_DB_DELTA = 3`
> **整体就绪度**:后端核心与场景集成通过(154/154 PASS,6/6 Scenarios PASS);端到端浏览器验收与 Swagger 探测 `PASS`(0 阻断 / 0 个 500);正式部署 `FORMAL_DEPLOYMENT = PENDING`。
---
## 1. 版本核心特性亮点
本版本作为 RailwaySystem 智慧培训系统的首个完整正式交付候选版本,全面实现了从基础资源、开班计划、学员名单、现场报到、智能排课、课堂考勤到结训归档的全流程数字化闭环:
1. **教务排课四维智能冲突检测**:
- 实现了对授课教师、理论教室、实训演练基地及本班课次的时间重叠实时失焦预检;
- 建立明确的 Warning 机制,警告不阻断正常保存,彻底消除非法 `force/override` 参数。
2. **敏感个人信息脱敏与散列存储**:
- 全面落地学员二代身份证号的散列索引 + 密文存盘机制,前端全链路脱敏只显后 4 位。
3. **开班报到与考勤动作正式对齐**:
- 现场报到支持人脸、刷卡、扫码与人工多模式核验,成功后强事务联动参训档案流转为“已报到”;
- 课次考勤支持打卡、任课教师代签与事假人工调整,状态严格统一为 0缺勤、1正常、2迟到、3早退、4请假,代签自动置位 `manual_flag=1`。
4. **强事务驱动的一键结训联动**:
- 计划结训时自动将班内正常参训在读学员批量更新为“已完成”,并严密保护历史退训学员状态防误覆盖。
5. **国产人大金仓数据库与架构解耦**:
- 全量 21 张表完成 KingbaseES V9 物理重构与序列自增补丁适配;
- 后端核心业务彻底收敛至独立模块 `ruoyi-train`,实现架构高内聚。
---
## 2. 数据库增量发布说明 (Database Delta)
当前版本包含针对底层数据库的 3 个正式发布增量脚本:
* **Delta 001**:`RuoYi-Vue/sql/system/kingbase/001_sys_oper_log_cost_time.sql`
- 修复 Kingbase 操作日志中缺少 `cost_time` 字段的问题。
* **Delta 002**:`RuoYi-Vue/sql/system/kingbase/002_legacy_analytics_permissions.sql`
- 收敛 Legacy Analytics 接口与 V2 只读契约,补齐报表只读查询与导出权限。
* **Delta 003**:`RuoYi-Vue/sql/system/kingbase/003_report_attendance_action_permissions.sql`
- 补齐现场开班报到确认(`train:report:confirm`)、课次打卡(`train:attendance:checkin`)与考勤调整(`train:attendance:edit`)三项原子动作权限。
> ⚠️ **数据库禁令提醒**:
> `007_dicts.sql` 明确标记为 `DO NOT EXECUTE`,生产环境严禁执行。
---
## 3. 质量门禁与当前验收状态
```mermaid
graph LR
G1["1. 单元与契约测试<br/>154/154 PASS"] --> G2["2. 核心场景集成<br/>6/6 PASS"]
G2 --> G3["3. 物理数据库断言<br/>11/11 PASS (0残留)"]
G3 --> G4["4. 浏览器端到端验收<br/>0阻断 / 0个500 PASS"]
G4 --> G5["5. Swagger接口文档<br/>无502 / 无死链 PASS"]
G5 --> G6["6. 生产集群部署<br/>FORMAL_DEPLOYMENT: PENDING"]
style G1 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style G2 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style G3 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style G4 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style G5 fill:#1a3a2a,stroke:#52c41a,stroke-width:2px;
style G6 fill:#3a2e1a,stroke:#faad14,stroke-width:2px;
```
| 质量验证项 | 当前状态 | 备注说明 |
| :--- | :---: | :--- |
| **后端单元与契约测试 (154 项)** | **PASS** | 154 / 154 全部通过 |
| **核心业务场景集成套件 (6 大场景)** | **PASS** | 6 / 6 全闭环通过 |
| **真实 HTTP 请求链路探测 (110 次)** | **PASS** | 零 500 异常 |
| **Kingbase 物理数据完整性断言 (11 项)**| **PASS** | 11 / 11 吻合 |
| **测试环境物理数据清理 (Residue)** | **PASS** | 0 脏数据残留 (Cleaned) |
| **端到端浏览器自动化验收** | **PASS** | Console 0 阻断,0 个 500 异常 |
| **Swagger 在线文档服务探测** | **PASS** | 真实入口:系统工具→系统接口,UI加载正常 |
| **目标生产环境集群部署** | **PENDING** | 等待生产发布窗口统一执行 |
---
## 4. 技术参考链接 (Technical References)
* 综合测试报告:[final-test-report.md](final-test-report.md)
* 部署与准备度报告:[deployment-report.md](deployment-report.md)
* 浏览器端到端验收报告:[browser-acceptance-report.md](browser-acceptance-report.md)
* 人类手册:[docs/handbook/01-project-overview.md](../handbook/01-project-overview.md)
+280
View File
@@ -0,0 +1,280 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>系统架构与技术栈 - RailwaySystem 铁路智慧培训管理系统</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%231d4ed8' d='M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4z'/></svg>">
<link rel="stylesheet" href="assets/docs.css">
<style>
/* 架构图专属容器与样式 */
.arch-canvas-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-lg);
padding: 2rem;
box-shadow: var(--shadow-card);
margin-bottom: 2.5rem;
}
.arch-svg-wrap {
width: 100%;
overflow-x: auto;
padding: 0.5rem 0;
}
.arch-svg {
min-width: 980px;
width: 100%;
height: auto;
display: block;
}
/* 架构分层文字卡片 */
.arch-layer-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 1.25rem;
margin-top: 1.5rem;
}
</style>
</head>
<body>
<!-- 顶部主导航 -->
<nav class="navbar">
<div class="nav-brand-wrap">
<a href="index.html" class="nav-brand">
<svg viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></svg>
<div>
<div class="brand-title">RailwaySystem</div>
<div class="brand-sub">铁路智慧培训管理系统</div>
</div>
</a>
<span class="brand-pill">Final Candidate · 待正式部署</span>
</div>
<ul class="nav-menu">
<li><a href="index.html" class="nav-link">首页</a></li>
<li><a href="business-flow.html" class="nav-link">业务</a></li>
<li><a href="architecture.html" class="nav-link active">系统</a></li>
<li><a href="testing.html" class="nav-link">质量</a></li>
<li><a href="release-status.html" class="nav-link">发布</a></li>
<li><a href="modules.html" class="nav-link">14大业务模块清单</a></li>
<li><a href="data-model.html" class="nav-link">实体关系模型(ER)</a></li>
<li><a href="deployment.html" class="nav-link">部署拓扑与脚本Delta</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer" class="nav-handbook-link">&gt; 查阅部署发布手册</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/README.md" target="_blank" rel="noopener noreferrer" class="nav-back-link">&larr; 文档中心</a></li>
</ul>
</nav>
<!-- 页面主体容器 -->
<main class="page-container">
<header class="page-hero">
<div class="hero-pretitle">Technical System Architecture</div>
<h1 class="hero-title-main">分层系统架构与技术栈</h1>
<p class="hero-lead-text">
真实还原系统分层架构拓扑:中心纵向贯穿浏览器前端、API安全鉴权、培训业务领域层、持久层及人大金仓数据库;侧边协同缓存与系统工具,并严格区分当前实现的 Web 班牌与预留的外部硬件适配器。
</p>
</header>
<!-- 真正架构图 SVG 容器 -->
<section class="arch-canvas-card">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 0.75rem;">
<div>
<h2 style="font-size: 1.25rem; font-weight: 700; color: var(--navy-900);">系统全局分层拓扑与通信边界</h2>
<p style="font-size: 0.82rem; color: var(--text-muted); margin-top: 0.2rem;">实线代表已上线的当前实现;虚线代表规划中的预留扩展接口</p>
</div>
<div style="display: flex; gap: 0.85rem; align-items: center; font-size: 0.8rem;">
<span style="display: inline-flex; align-items: center; gap: 4px;"><span style="width: 12px; height: 12px; background: #eff6ff; border: 1.5px solid #1d4ed8; border-radius: 2px;"></span> 当前实现 (IMPLEMENTED)</span>
<span style="display: inline-flex; align-items: center; gap: 4px;"><span style="width: 12px; height: 12px; background: #faf5ff; border: 1.5px dashed #a855f7; border-radius: 2px;"></span> 预留接口 (RESERVED)</span>
</div>
</div>
<div class="arch-svg-wrap">
<svg class="arch-svg" viewBox="0 0 1020 620" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="arrow" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
<path d="M0,1 L7,4 L0,7 Z" fill="#475569" />
</marker>
<marker id="arrow-blue" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
<path d="M0,1 L7,4 L0,7 Z" fill="#1d4ed8" />
</marker>
<marker id="arrow-purple" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
<path d="M0,1 L7,4 L0,7 Z" fill="#a855f7" />
</marker>
</defs>
<!-- 1. 接入层 (Browser / Frontend) -->
<g id="layer-client">
<rect x="260" y="20" width="500" height="70" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="2" />
<text x="510" y="48" text-anchor="middle" font-size="14" font-weight="700" fill="#0f172a">Browser / Frontend (浏览器客户端)</text>
<text x="510" y="70" text-anchor="middle" font-size="11" fill="#64748b">Vue 2.6 · Element UI · Axios · 路由动态加载 sys_menu · Web 电子班牌路由 (/equip/board)</text>
</g>
<!-- Client -> API & Security -->
<line x1="510" y1="90" x2="510" y2="130" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<text x="525" y="115" font-size="11" fill="#64748b">HTTP / JSON (RESTful API)</text>
<!-- 2. API & Security 层 -->
<g id="layer-api-security">
<rect x="260" y="130" width="500" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="2" />
<text x="510" y="158" text-anchor="middle" font-size="14" font-weight="700" fill="#0f172a">API & Security (接口网关与安全中枢)</text>
<text x="510" y="180" text-anchor="middle" font-size="11" fill="#334155">Spring Security 过滤器链 · JWT 无状态令牌解析 · RBAC 角色权限验证 (@PreAuthorize)</text>
<text x="510" y="198" text-anchor="middle" font-size="10" fill="#64748b">统一异常捕获 (GlobalExceptionHandler) · 身份证脱敏过滤器 (末4位掩码)</text>
</g>
<!-- 侧边左 1: Redis 缓存 -->
<g id="pillar-redis">
<rect x="40" y="130" width="180" height="180" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="130" y="160" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">Redis 缓存支撑</text>
<text x="130" y="185" text-anchor="middle" font-size="11" fill="#64748b">端口: 6379 (DB 0)</text>
<line x1="55" y1="200" x2="205" y2="200" stroke="#e2e8f0" stroke-width="1" />
<text x="65" y="225" font-size="11" fill="#334155">• 用户登录 Token 缓存</text>
<text x="65" y="250" font-size="11" fill="#334155">• 验证码防重放缓存</text>
<text x="65" y="275" font-size="11" fill="#334155">• 权限路由元数据</text>
</g>
<!-- API <-> Redis -->
<line x1="260" y1="170" x2="220" y2="170" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)" />
<!-- 侧边右 1: 系统工具与审计 -->
<g id="pillar-tools">
<rect x="800" y="130" width="180" height="180" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="890" y="160" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">System Tools & 审计</text>
<text x="890" y="185" text-anchor="middle" font-size="11" fill="#64748b">系统工具与合规底座</text>
<line x1="815" y1="200" x2="965" y2="200" stroke="#e2e8f0" stroke-width="1" />
<text x="825" y="225" font-size="11" fill="#334155">• Swagger 接口平台</text>
<text x="825" y="250" font-size="11" fill="#334155">• 操作日志 (OperLog)</text>
<text x="825" y="275" font-size="11" fill="#334155">• 表单构建与代码生成</text>
</g>
<!-- API <-> Tools -->
<line x1="760" y1="170" x2="800" y2="170" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)" />
<!-- API & Security -> Training Domain -->
<line x1="510" y1="210" x2="510" y2="250" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 3. Training Domain 业务领域层 -->
<g id="layer-domain">
<rect x="260" y="250" width="500" height="150" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="2" />
<text x="510" y="278" text-anchor="middle" font-size="14" font-weight="700" fill="#0f172a">Training Domain (核心教务业务领域层)</text>
<!-- 子模块框 1 -->
<rect x="280" y="295" width="220" height="42" rx="4" fill="#f8fafc" stroke="#e2e8f0" />
<text x="390" y="315" text-anchor="middle" font-size="11" font-weight="600" fill="#0f172a">主数据服务 (Master Data)</text>
<text x="390" y="329" text-anchor="middle" font-size="9" fill="#64748b">教师/学员/课程/教室/场地</text>
<!-- 子模块框 2 -->
<rect x="520" y="295" width="220" height="42" rx="4" fill="#f8fafc" stroke="#e2e8f0" />
<text x="630" y="315" text-anchor="middle" font-size="11" font-weight="600" fill="#0f172a">排课调度引擎 (Scheduling)</text>
<text x="630" y="329" text-anchor="middle" font-size="9" fill="#64748b">四维预检 / Warning / 场地XOR</text>
<!-- 子模块框 3 -->
<rect x="280" y="345" width="220" height="42" rx="4" fill="#f8fafc" stroke="#e2e8f0" />
<text x="390" y="365" text-anchor="middle" font-size="11" font-weight="600" fill="#0f172a">现场执行服务 (Execution)</text>
<text x="390" y="379" text-anchor="middle" font-size="9" fill="#64748b">报到强事务 / 考勤打卡幂等性</text>
<!-- 子模块框 4 -->
<rect x="520" y="345" width="220" height="42" rx="4" fill="#f8fafc" stroke="#e2e8f0" />
<text x="630" y="365" text-anchor="middle" font-size="11" font-weight="600" fill="#0f172a">结训流转服务 (Completion)</text>
<text x="630" y="379" text-anchor="middle" font-size="9" fill="#64748b">Plan状态流转 / 退训保护不变量</text>
</g>
<!-- 侧边右 2: 班牌物联与外部适配器 -->
<g id="pillar-adapter">
<rect x="800" y="335" width="180" height="150" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="890" y="362" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">电子班牌与物联适配</text>
<line x1="815" y1="375" x2="965" y2="375" stroke="#e2e8f0" stroke-width="1" />
<rect x="815" y="388" width="150" height="36" rx="4" fill="#eff6ff" stroke="#bfdbfe" />
<text x="890" y="405" text-anchor="middle" font-size="10" font-weight="700" fill="#1d4ed8">当前实现 (CURRENT)</text>
<text x="890" y="418" text-anchor="middle" font-size="9" fill="#1e40af">Web 班牌路由 / 降级映射</text>
<rect x="815" y="432" width="150" height="36" rx="4" fill="#faf5ff" stroke="#d8b4fe" stroke-dasharray="3 3" />
<text x="890" y="449" text-anchor="middle" font-size="10" font-weight="700" fill="#7e22ce">预留接口 (RESERVED)</text>
<text x="890" y="462" text-anchor="middle" font-size="9" fill="#6b21a8">硬件闸机 / 班牌外部协议</text>
</g>
<!-- Domain <-> Adapter -->
<line x1="760" y1="370" x2="800" y2="370" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)" />
<!-- Training Domain -> Persistence -->
<line x1="510" y1="400" x2="510" y2="440" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 4. Persistence 持久层 -->
<g id="layer-persistence">
<rect x="260" y="440" width="500" height="65" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="2" />
<text x="510" y="468" text-anchor="middle" font-size="14" font-weight="700" fill="#0f172a">Persistence (数据持久层与连接池)</text>
<text x="510" y="490" text-anchor="middle" font-size="11" fill="#64748b">MyBatis 3.5 · PageHelper 分页插件 · Alibaba Druid 数据库连接池 (单主库配置)</text>
</g>
<!-- Persistence -> Kingbase -->
<line x1="510" y1="505" x2="510" y2="535" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 5. 存储层: KingbaseES -->
<g id="layer-kingbase">
<rect x="230" y="540" width="560" height="60" rx="8" fill="#ecfdf5" stroke="#059669" stroke-width="1.5" />
<text x="510" y="562" text-anchor="middle" font-size="14" font-weight="700" fill="#065f46">KingbaseES (生产主库)</text>
<text x="510" y="584" text-anchor="middle" font-size="11" fill="#047857">KingbaseES V009R003C018 (JDBC依赖 8.6.0) · 物理外键与唯一索引保障 · 21张业务表</text>
</g>
</svg>
</div>
</section>
<!-- 架构核心能力说明分块 -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">架构设计原则与关键实现边界</h2>
<p class="section-subtitle">明确当前生产可用能力与后续规划接口的边界,坚守工程事实真实性。</p>
</div>
</div>
<div class="arch-layer-grid">
<div class="standard-card">
<div class="card-top">
<h3 class="card-title">安全鉴权与敏感数据保护</h3>
<span class="badge badge-pass">CURRENT</span>
</div>
<p class="card-body-text">
<strong>无状态 JWT 机制</strong>:采用标准 Bearer Token 进行会话保持,服务端通过 Redis 维护令牌白名单;
<br><strong>脱敏治理</strong>:学员身份证在落库时保存散列与哈希,前端统一返回末4位掩码,杜绝明文传输;
<br><strong>权限管控</strong>:依托 RuoYi 标准注解 <code>@PreAuthorize</code> 实现按钮级权限拦截。
</p>
</div>
<div class="standard-card">
<div class="card-top">
<h3 class="card-title">排课预检与强一致性保护</h3>
<span class="badge badge-pass">CURRENT</span>
</div>
<p class="card-body-text">
<strong>四维防重叠预检</strong>:将教师时间冲突作为阻断校验,教室/场地/班级重叠作为 Warning 预警由教务员决策;
<br><strong>零旁路保存</strong>:标准 POST 保存禁止 <code>force/override</code> 参数,保障排课合规;
<br><strong>场地 XOR 互斥</strong>:物理保证教室与实训场地二选一,不可并存或两空。
</p>
</div>
<div class="standard-card">
<div class="card-top">
<h3 class="card-title">物联网设备与外部适配器边界</h3>
<span class="badge badge-reserved">区分已实现 vs 预留</span>
</div>
<p class="card-body-text">
<strong>当前实现</strong>:提供标准 RESTful API 及 Web 电子班牌路由 <code>/equip/board</code>,课表根据教室班牌数量 (0/1/N) 智能映射 <code>boardSn</code>;
<br><strong>预留扩展 (RESERVED)</strong>:物理硬件人脸打卡闸机适配协议、专属嵌入式班牌通讯协议预留接口规范,暂未接入实际物理硬件。
</p>
</div>
</div>
</section>
</main>
<!-- 页脚 -->
<footer class="site-footer">
<p>RailwaySystem 铁路智慧培训管理系统 · 交付候选版 (Final Candidate)</p>
<p style="margin-top: 0.35rem; color: var(--text-muted);">
架构设计规范 · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/03-system-architecture.md" target="_blank" rel="noopener noreferrer">查阅架构设计详细手册</a>
</p>
</footer>
<script src="assets/docs.js"></script>
</body>
</html>
File diff suppressed because it is too large. Load diff
+105
View File
@@ -0,0 +1,105 @@
/**
* RailwaySystem - Visual Portal Common Interactive Engine v2.0
* 纯静态 · 离线友好 · 零网络 CDN 依赖
*/
const GITLAB_DOCS_BASE = "http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/";
document.addEventListener('DOMContentLoaded', () => {
// 1. 导航栏高亮当前页面
const currentPath = window.location.pathname.split('/').pop() || 'index.html';
document.querySelectorAll('.nav-link, .dropdown-item a').forEach(link => {
const href = link.getAttribute('href');
if (href === currentPath || (currentPath === '' && href === 'index.html')) {
link.classList.add('active');
}
});
// 2. 文档跳转拦截与 GitLab 自动重定向保护
document.querySelectorAll('a').forEach(anchor => {
const href = anchor.getAttribute('href');
if (href && href.includes('.md')) {
anchor.setAttribute('target', '_blank');
anchor.setAttribute('rel', 'noopener noreferrer');
// 如果仍有相对路径,自动转换为 GitLab 远程在线路径
if (!href.startsWith('http://') && !href.startsWith('https://')) {
let cleanRel = href.replace(/^(\.\.\/)+/, '');
if (!cleanRel.startsWith('docs/')) {
cleanRel = 'docs/' + cleanRel;
}
anchor.setAttribute('href', GITLAB_DOCS_BASE + cleanRel);
}
}
});
// 3. 抽屉 (Drawer) 机制
const drawerBackdrop = document.getElementById('drawer-backdrop');
const drawerCloseBtn = document.getElementById('drawer-close-btn');
window.openDrawer = function(title, contentHtml) {
const drawerTitle = document.getElementById('drawer-title');
const drawerBody = document.getElementById('drawer-body');
if (drawerTitle) drawerTitle.textContent = title;
if (drawerBody) drawerBody.innerHTML = contentHtml;
if (drawerBackdrop) {
drawerBackdrop.classList.add('active');
document.body.style.overflow = 'hidden';
}
};
window.closeDrawer = function() {
if (drawerBackdrop) {
drawerBackdrop.classList.remove('active');
document.body.style.overflow = '';
}
};
if (drawerCloseBtn) {
drawerCloseBtn.addEventListener('click', window.closeDrawer);
}
if (drawerBackdrop) {
drawerBackdrop.addEventListener('click', (e) => {
if (e.target === drawerBackdrop) {
window.closeDrawer();
}
});
}
// ESC 键关闭抽屉或弹窗
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
window.closeDrawer();
window.closeModal && window.closeModal();
}
});
// 4. 手风琴折叠面板 (Accordion)
document.querySelectorAll('.accordion-header').forEach(header => {
header.addEventListener('click', () => {
const item = header.closest('.accordion-item');
if (item) {
item.classList.toggle('open');
}
});
});
// 5. 选项卡 (Tabs) 切换
document.querySelectorAll('.tab-trigger').forEach(tab => {
tab.addEventListener('click', () => {
const tabGroup = tab.getAttribute('data-tab-group');
const targetId = tab.getAttribute('data-target');
// 切换触发器状态
document.querySelectorAll(`.tab-trigger[data-tab-group="${tabGroup}"]`).forEach(t => t.classList.remove('active'));
tab.classList.add('active');
// 切换内容面板
document.querySelectorAll(`.tab-panel[data-tab-group="${tabGroup}"]`).forEach(p => p.style.display = 'none');
const targetPanel = document.getElementById(targetId);
if (targetPanel) {
targetPanel.style.display = 'block';
}
});
});
});
+688
View File
@@ -0,0 +1,688 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>业务全景与状态机 - RailwaySystem 铁路智慧培训管理系统</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%231d4ed8' d='M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4z'/></svg>">
<link rel="stylesheet" href="assets/docs.css">
<style>
/* 业务流图专属容器与样式 */
.flow-diagram-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-lg);
padding: 2rem;
box-shadow: var(--shadow-card);
margin-bottom: 2.5rem;
}
.flow-canvas-wrap {
width: 100%;
overflow-x: auto;
padding: 1rem 0;
}
.flow-svg {
min-width: 980px;
width: 100%;
height: auto;
display: block;
}
/* 节点可点击交互效果 */
.flow-node {
cursor: pointer;
transition: transform 0.15s ease, filter 0.15s ease;
}
.flow-node:hover {
filter: drop-shadow(0 4px 8px rgba(30, 64, 175, 0.18));
}
.flow-node:hover rect {
stroke: var(--rail-blue);
stroke-width: 2px;
}
.flow-node text {
pointer-events: none;
user-select: none;
}
/* 节点卡片速览网格 */
.flow-step-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.25rem;
margin-top: 1.5rem;
}
.step-clickable-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.25rem;
cursor: pointer;
box-shadow: var(--shadow-card);
transition: all 0.2s ease;
display: flex;
flex-direction: column;
}
.step-clickable-card:hover {
border-color: var(--rail-blue-border);
transform: translateY(-2px);
box-shadow: var(--shadow-card-hover);
}
.step-clickable-card.side-branch {
border-left: 4px solid #0284c7;
background: #fcfdfe;
}
.step-clickable-card.support-layer {
border-left: 4px solid #6366f1;
background: #fbfbfe;
}
</style>
</head>
<body>
<!-- 顶部主导航 -->
<nav class="navbar">
<div class="nav-brand-wrap">
<a href="index.html" class="nav-brand">
<svg viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></svg>
<div>
<div class="brand-title">RailwaySystem</div>
<div class="brand-sub">铁路智慧培训管理系统</div>
</div>
</a>
<span class="brand-pill">Final Candidate · 待正式部署</span>
</div>
<ul class="nav-menu">
<li><a href="index.html" class="nav-link">首页</a></li>
<li><a href="business-flow.html" class="nav-link active">业务</a></li>
<li><a href="architecture.html" class="nav-link">系统</a></li>
<li><a href="testing.html" class="nav-link">质量</a></li>
<li><a href="release-status.html" class="nav-link">发布</a></li>
<li><a href="modules.html" class="nav-link">14大业务模块清单</a></li>
<li><a href="data-model.html" class="nav-link">实体关系模型(ER)</a></li>
<li><a href="deployment.html" class="nav-link">部署拓扑与脚本Delta</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer" class="nav-handbook-link">&gt; 查阅部署发布手册</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/README.md" target="_blank" rel="noopener noreferrer" class="nav-back-link">&larr; 文档中心</a></li>
</ul>
</nav>
<!-- 页面主体容器 -->
<main class="page-container">
<header class="page-hero">
<div class="hero-pretitle">Business Process Architecture</div>
<h1 class="hero-title-main">业务全景流程与状态机</h1>
<p class="hero-lead-text">
主视觉聚焦于基础资源编排至结训考核的线性主脉络,解耦呈现后勤住宿支线与电子班牌硬件支撑层。点击任意节点可展开查看其状态机、业务约束与技术契约。
</p>
</header>
<!-- 流程图视觉卡片 -->
<section class="flow-diagram-card">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 0.75rem;">
<div>
<h2 style="font-size: 1.25rem; font-weight: 700; color: var(--navy-900);">全业务生命周期协同拓扑</h2>
<p style="font-size: 0.82rem; color: var(--text-muted); margin-top: 0.2rem;">点击拓扑节点查看抽屉详情,支持键盘 ESC 快速退出</p>
</div>
<div style="display: flex; gap: 0.85rem; align-items: center; font-size: 0.8rem;">
<span style="display: inline-flex; align-items: center; gap: 4px;"><span style="width: 12px; height: 12px; background: #eff6ff; border: 1px solid #1d4ed8; border-radius: 2px;"></span> 主干链路</span>
<span style="display: inline-flex; align-items: center; gap: 4px;"><span style="width: 12px; height: 12px; background: #f0f9ff; border: 1px solid #0284c7; border-radius: 2px;"></span> 住宿支线</span>
<span style="display: inline-flex; align-items: center; gap: 4px;"><span style="width: 12px; height: 12px; background: #eef2ff; border: 1px solid #6366f1; border-radius: 2px;"></span> 班牌支撑</span>
</div>
</div>
<div class="flow-canvas-wrap">
<svg class="flow-svg" viewBox="0 0 1120 420" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="arrow-blue" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
<path d="M0,1 L7,4 L0,7 Z" fill="#1d4ed8" />
</marker>
<marker id="arrow-cyan" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
<path d="M0,1 L7,4 L0,7 Z" fill="#0284c7" />
</marker>
<marker id="arrow-purple" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
<path d="M0,1 L7,4 L0,7 Z" fill="#6366f1" />
</marker>
</defs>
<!-- 区域背景标注 -->
<rect x="10" y="20" width="1100" height="150" rx="12" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1" stroke-dasharray="4 4" />
<text x="25" y="42" font-size="12" font-weight="700" fill="#64748b">CORE TRAINING LIFECYCLE (核心业务主脉络)</text>
<rect x="420" y="195" width="240" height="95" rx="8" fill="#f0f9ff" stroke="#bae6fd" stroke-width="1" />
<text x="435" y="218" font-size="11" font-weight="700" fill="#0284c7">LOGISTICS BRANCH (后勤住宿支线)</text>
<rect x="420" y="310" width="460" height="95" rx="8" fill="#eef2ff" stroke="#c7d2fe" stroke-width="1" />
<text x="435" y="333" font-size="11" font-weight="700" fill="#6366f1">FACILITIES LAYER (电子班牌显示支撑层)</text>
<!-- 主干流程连接线 -->
<!-- 1 -> 2 -->
<line x1="115" y1="95" x2="145" y2="95" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 2 -> 3 -->
<line x1="245" y1="95" x2="275" y2="95" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 3 -> 4 -->
<line x1="375" y1="95" x2="405" y2="95" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 4 -> 5 -->
<line x1="505" y1="95" x2="535" y2="95" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 5 -> 6 -->
<line x1="635" y1="95" x2="665" y2="95" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 6 -> 7 -->
<line x1="765" y1="95" x2="795" y2="95" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 7 -> 8 -->
<line x1="895" y1="95" x2="925" y2="95" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 8 -> 9 -->
<line x1="1025" y1="95" x2="1045" y2="95" stroke="#1d4ed8" stroke-width="2" marker-end="url(#arrow-blue)" />
<!-- 支线与支撑连接线 -->
<!-- 4 -> 住宿支线 -->
<path d="M 455 125 L 455 235 L 475 235" fill="none" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="3 3" marker-end="url(#arrow-cyan)" />
<!-- 5 -> 班牌支撑 -->
<path d="M 585 125 L 585 350 L 595 350" fill="none" stroke="#6366f1" stroke-width="1.8" stroke-dasharray="3 3" marker-end="url(#arrow-purple)" />
<!-- 班牌 -> 7 课次 -->
<path d="M 720 350 L 720 125" fill="none" stroke="#6366f1" stroke-width="1.8" stroke-dasharray="3 3" marker-end="url(#arrow-purple)" />
<!-- 节点 1: 基础资源 -->
<g class="flow-node" onclick="handleNodeClick('resource')">
<rect x="25" y="65" width="90" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="70" y="92" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">1. 基础资源</text>
<text x="70" y="110" text-anchor="middle" font-size="10" fill="#64748b">师资/教室/场地</text>
</g>
<!-- 节点 2: 开班计划 -->
<g class="flow-node" onclick="handleNodeClick('plan')">
<rect x="155" y="65" width="90" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="200" y="92" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">2. 开班计划</text>
<text x="200" y="110" text-anchor="middle" font-size="10" fill="#64748b">拟定班期/容量</text>
</g>
<!-- 节点 3: 本期课程 -->
<g class="flow-node" onclick="handleNodeClick('course')">
<rect x="285" y="65" width="90" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="330" y="92" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">3. 本期课程</text>
<text x="330" y="110" text-anchor="middle" font-size="10" fill="#64748b">师资绑定/学时</text>
</g>
<!-- 节点 4: 参训人员 -->
<g class="flow-node" onclick="handleNodeClick('enrollment')">
<rect x="415" y="65" width="90" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="460" y="92" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">4. 参训人员</text>
<text x="460" y="110" text-anchor="middle" font-size="10" fill="#64748b">名单导入/防超限</text>
</g>
<!-- 节点 5: 排课准备 -->
<g class="flow-node" onclick="handleNodeClick('scheduling')">
<rect x="545" y="65" width="90" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="590" y="92" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">5. 排课准备</text>
<text x="590" y="110" text-anchor="middle" font-size="10" fill="#64748b">四维预检/XOR互斥</text>
</g>
<!-- 节点 6: 开班报到 -->
<g class="flow-node" onclick="handleNodeClick('report')">
<rect x="675" y="65" width="90" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="720" y="92" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">6. 开班报到</text>
<text x="720" y="110" text-anchor="middle" font-size="10" fill="#64748b">现场核验/状态联动</text>
</g>
<!-- 节点 7: 正式培训 -->
<g class="flow-node" onclick="handleNodeClick('training')">
<rect x="805" y="65" width="90" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="850" y="92" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">7. 正式培训</text>
<text x="850" y="110" text-anchor="middle" font-size="10" fill="#64748b">课表执行/课次授课</text>
</g>
<!-- 节点 8: 课程考勤 -->
<g class="flow-node" onclick="handleNodeClick('attendance')">
<rect x="935" y="65" width="90" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="980" y="92" text-anchor="middle" font-size="13" font-weight="700" fill="#0f172a">8. 课程考勤</text>
<text x="980" y="110" text-anchor="middle" font-size="10" fill="#64748b">签到签退/留痕修正</text>
</g>
<!-- 节点 9: 结训与分析 -->
<g class="flow-node" onclick="handleNodeClick('completion')">
<rect x="1055" y="65" width="45" height="60" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.5" />
<text x="1077" y="92" text-anchor="middle" font-size="11" font-weight="700" fill="#0f172a">9.结训</text>
<text x="1077" y="110" text-anchor="middle" font-size="9" fill="#64748b">保护</text>
</g>
<!-- 支线节点: 后勤住宿 -->
<g class="flow-node" onclick="handleNodeClick('dormitory')">
<rect x="485" y="225" width="160" height="55" rx="8" fill="#ffffff" stroke="#0284c7" stroke-width="1.5" />
<text x="565" y="250" text-anchor="middle" font-size="12" font-weight="700" fill="#0284c7">后勤住宿准备 (支线)</text>
<text x="565" y="268" text-anchor="middle" font-size="10" fill="#64748b">住宿标记 · 房间分配 · 入住</text>
</g>
<!-- 支撑层节点: 电子班牌 -->
<g class="flow-node" onclick="handleNodeClick('board')">
<rect x="585" y="340" width="280" height="55" rx="8" fill="#ffffff" stroke="#6366f1" stroke-width="1.5" />
<text x="725" y="363" text-anchor="middle" font-size="12" font-weight="700" fill="#4f46e5">电子班牌终端映射 (支撑层)</text>
<text x="725" y="381" text-anchor="middle" font-size="10" fill="#64748b">UUID主键 · 教室绑定0/1/N · 课表降级</text>
</g>
</svg>
</div>
</section>
<!-- 节点图文卡片清单(供直观速查与点击唤起抽屉) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">业务主链环节与支线速览</h2>
<p class="section-subtitle">点击任意卡片即可在右侧展开该环节的角色、规则约束、状态机流转与物理接口。</p>
</div>
</div>
<div class="flow-step-grid">
<div class="step-clickable-card" onclick="handleNodeClick('resource')">
<div class="card-top">
<span class="badge badge-pass">环节 1 · 主干</span>
<span class="card-code">Master Data</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">基础资源录入与治理</h3>
<p class="card-body-text">建立教师、学员主档、标准化课程、理论教室与演练场地。强校验手机号唯一性与脱敏存储。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">点击查看规则 &rarr;</div>
</div>
<div class="step-clickable-card" onclick="handleNodeClick('plan')">
<div class="card-top">
<span class="badge badge-pass">环节 2 · 主干</span>
<span class="card-code">Plan Lifecycle</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">开班计划拟定</h3>
<p class="card-body-text">生成 32 位 UUID 计划,强制初始状态为 0:草稿。校验起止日期有效性与招生容量。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">点击查看规则 &rarr;</div>
</div>
<div class="step-clickable-card" onclick="handleNodeClick('course')">
<div class="card-top">
<span class="badge badge-pass">环节 3 · 主干</span>
<span class="card-code">Plan Courses</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">本期课程与师资绑定</h3>
<p class="card-body-text">建立计划与课程的 N:M 关联,指定主讲教师,系统自动汇总开班总学时并保持数据一致性。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">点击查看规则 &rarr;</div>
</div>
<div class="step-clickable-card" onclick="handleNodeClick('enrollment')">
<div class="card-top">
<span class="badge badge-pass">环节 4 · 主干</span>
<span class="card-code">Enrollment Guard</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">参训人员入班与防超额</h3>
<p class="card-body-text">学员初始参训状态为 0:待报到。严格校验容量上限 (40031) 及重复报名拦截 (40030)。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">点击查看规则 &rarr;</div>
</div>
<div class="step-clickable-card" onclick="handleNodeClick('scheduling')">
<div class="card-top">
<span class="badge badge-pass">环节 5 · 主干</span>
<span class="card-code">Scheduling Engine</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">排课四维冲突预检</h3>
<p class="card-body-text">智能检测教师时段、场地占用与班级重叠。支持 Warning 级别确认保存,硬阻断场地 XOR 互斥。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">点击查看规则 &rarr;</div>
</div>
<div class="step-clickable-card" onclick="handleNodeClick('report')">
<div class="card-top">
<span class="badge badge-pass">环节 6 · 主干</span>
<span class="card-code">Report Confirm</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">现场开班报到确认</h3>
<p class="card-body-text">核验报到时限与资格,强事务联动学员状态至 1:已报到,并记录精确报到时间,防重复报到。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">点击查看规则 &rarr;</div>
</div>
<div class="step-clickable-card" onclick="handleNodeClick('attendance')">
<div class="card-top">
<span class="badge badge-pass">环节 8 · 主干</span>
<span class="card-code">Attendance Actions</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">课堂考勤打卡与审计</h3>
<p class="card-body-text">签到签退幂等性保证,重复签到签退保留初次时间。人工代签/补签自动记录 manual_flag=1 审计留痕。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">点击查看规则 &rarr;</div>
</div>
<div class="step-clickable-card" onclick="handleNodeClick('completion')">
<div class="card-top">
<span class="badge badge-pass">环节 9 · 主干</span>
<span class="card-code">Plan Complete</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">结训流转与退训保护</h3>
<p class="card-body-text">计划流转为 2:已结束,在读活动学员自动批量流转为 4:已完成。历史退训记录严格锁定防破坏。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">点击查看规则 &rarr;</div>
</div>
<div class="step-clickable-card side-branch" onclick="handleNodeClick('dormitory')">
<div class="card-top">
<span class="badge badge-info">支线 · 后勤</span>
<span class="card-code">Accommodation</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">后勤住宿管理支线</h3>
<p class="card-body-text">学员报名时勾选 accommodationRequired 触发宿舍分配,管理房间可用床位与入住注销。</p>
<div style="font-size: 0.78rem; color: var(--rail-cyan); font-weight: 600;">点击查看支线 &rarr;</div>
</div>
<div class="step-clickable-card support-layer" onclick="handleNodeClick('board')">
<div class="card-top">
<span class="badge badge-neutral" style="color: #6366f1; background: #eef2ff; border-color: #c7d2fe;">支撑 · 物联</span>
<span class="card-code">Electronic Board</span>
</div>
<h3 class="card-title" style="margin-bottom: 0.4rem;">电子班牌显示支撑层</h3>
<p class="card-body-text">教室绑定 0/1/N 班牌关系,课表 timetable 智能降级映射 boardSn,支持逻辑删除保护。</p>
<div style="font-size: 0.78rem; color: #6366f1; font-weight: 600;">点击查看支撑 &rarr;</div>
</div>
</div>
</section>
</main>
<!-- 侧边抽屉组件 (Drawer) -->
<div class="drawer-backdrop" id="drawer-backdrop">
<div class="drawer-panel">
<div class="drawer-header">
<h3 class="drawer-title" id="drawer-title">节点详情</h3>
<button class="drawer-close" id="drawer-close-btn" type="button" aria-label="关闭">&times;</button>
</div>
<div class="drawer-body" id="drawer-body">
<!-- 动态注入内容 -->
</div>
</div>
</div>
<footer class="site-footer">
<p>RailwaySystem 铁路智慧培训管理系统 · 交付候选版 (Final Candidate)</p>
<p style="margin-top: 0.35rem; color: var(--text-muted);">
业务流程与状态机规范 · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/02-business-process.md" target="_blank" rel="noopener noreferrer">查阅业务流程详细手册</a>
</p>
</footer>
<script src="assets/docs.js"></script>
<script>
// 抽屉详情字典库 (据实编写,无扩写)
const nodeDetails = {
resource: {
title: "1. 基础资源录入与治理 (Master Data)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>教务管理员</strong>:在开学或开班前,统一录入师资档案(姓名、职称、联系电话)、学员主档、标准课程库以及校区空间(理论教室、实训演练基地)。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">关键业务规则与约束</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>教师手机号唯一性</strong>:同一手机号不可重复录入,重复时触发业务错误拦截(40001)。</li>
<li><strong>学员脱敏与哈希保护</strong>:学员身份证存储密文与哈希,列表及详情接口仅返回末4位脱敏掩码,避免明文泄露。</li>
<li><strong>空间互斥 XOR 属性</strong>:理论教室与实训场地在底层物理模型中属于独立实体,供后续排课互斥引用。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>POST /train/teacher
POST /train/student
POST /train/course
POST /train/classroom
POST /train/training-site</code></pre>
</div>
<div class="drawer-section">
<div class="drawer-section-title">物理数据模型</div>
<p><code>train_teacher</code>, <code>train_student</code>, <code>train_course</code>, <code>train_classroom_info</code>, <code>train_training_site</code></p>
</div>
`
},
plan: {
title: "2. 培训班计划拟定 (Training Plan)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>培训主管 / 教务科</strong>:拟定开班方案,录入培训班名称、起止日期、报到截止日期、计划招生人数上限及办班地点。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">状态机与业务约束</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>主键生成</strong>:后端自动生成全局唯一的 32 位 UUID 主键。</li>
<li><strong>初始状态机</strong>:创建成功后,计划状态强制为 <code>0:草稿 (DRAFT)</code>。</li>
<li><strong>时间窗口校验</strong>:起始时间必须小于结束时间,且报到截止时间不得晚于培训起始时间。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>POST /train/plans
GET /train/plans/{id}
PUT /train/plans/{id}</code></pre>
</div>
<div class="drawer-section">
<div class="drawer-section-title">物理数据模型</div>
<p><code>train_class_plan</code> (字段: <code>plan_id</code>, <code>plan_name</code>, <code>plan_status</code>, <code>start_time</code>, <code>end_time</code>, <code>recruit_num</code>)</p>
</div>
`
},
course: {
title: "3. 计划课程与师资绑定 (Plan Courses)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>教务排课员</strong>:为处于草稿状态的培训班指定本期教学大纲中的课程清单,并指派授课教师。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">关键业务规则</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>关联一致性</strong>:支持批量绑定 <code>cIds</code>,生成 <code>train_plan_course</code> 映射。</li>
<li><strong>学时汇总</strong>:系统根据所选课程的 <code>c_duration</code> 自动累加该班期总课时。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>POST /train/plans/{id}/courses
GET /train/plans/{id}/courses</code></pre>
</div>
<div class="drawer-section">
<div class="drawer-section-title">物理数据模型</div>
<p><code>train_plan_course</code> (字段: <code>plan_course_id</code>, <code>plan_id</code>, <code>c_id</code>, <code>t_id</code>, <code>remark</code>)</p>
</div>
`
},
enrollment: {
title: "4. 学员入班与招生容量守卫 (Enrollment)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>站段劳资 / 培训管理员</strong>:根据各站段参训名单,将合格在册学员批量或逐一报名单录入培训班。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">状态机与安全拦截规则</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>初始参训状态</strong>:入班成功后,参训状态初始为 <code>0:待报到 (PENDING)</code>。</li>
<li><strong>同一计划重复报名拦截</strong>:严格唯一索引拦截,返回业务码 <code>40030: ENROLLMENT_ALREADY_EXISTS</code>。</li>
<li><strong>计划招生容量超限拦截</strong>:入班人数达到 <code>recruit_num</code> 上限时,拦截返回 <code>40031: ENROLLMENT_CAPACITY_EXCEEDED</code>。</li>
<li><strong>停用学员拦截</strong>:若学员主档状态为 <code>status=0</code>,拒绝入班。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>POST /train/plans/{id}/enrollments
GET /train/plans/{id}/enrollments
PUT /train/enrollments/{id}/status</code></pre>
</div>
<div class="drawer-section">
<div class="drawer-section-title">物理数据模型</div>
<p><code>train_enrollment</code> (字段: <code>enrollment_id</code>, <code>plan_id</code>, <code>student_id</code>, <code>enrollment_status</code>, <code>accommodation_required</code>)</p>
</div>
`
},
scheduling: {
title: "5. 排课四维冲突预检与保存 (Scheduling)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>教务排课员</strong>:在开课前编制课次(Lesson),安排上课时段、授课教师及教学空间。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">排课预检与硬阻断规则</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>四维冲突预检</strong>:检测教师时段冲突 (TEACHER)、教室占用 (CLASSROOM Warning)、场地占用 (SITE Warning) 及班级课次重叠 (PLAN_OVERLAP Warning)。</li>
<li><strong>Warning 非硬阻断</strong>:教室、场地与班级重叠为 Warning 级别,管理员确认后标准 POST 正常保存,禁止任何旁路 force 参数。</li>
<li><strong>场地 XOR 互斥硬阻断</strong>:<code>venue_type</code> 严格控制理论教室与实训场地二选一,不可同时传或同时为空。</li>
<li><strong>非法时间硬阻断</strong>:起止时间倒挂拦截(40010);已结束计划禁止排课(40012)。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>POST /train/lessons/check-conflict
POST /train/plans/{id}/lessons
GET /train/plans/{id}/timetable</code></pre>
</div>
<div class="drawer-section">
<div class="drawer-section-title">物理数据模型</div>
<p><code>train_lesson</code> (字段: <code>lesson_id</code>, <code>plan_course_id</code>, <code>venue_type</code>, <code>class_room_id</code>, <code>site_id</code>, <code>start_time</code>, <code>end_time</code>)</p>
</div>
`
},
report: {
title: "6. 现场开班报到确认 (Report Confirm)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>基地教务值班员 / 学员</strong>:学员到达培训基地现场,通过刷卡、人脸或人工核验完成开班报到。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">报到状态联动与防重复机制</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>状态强事务流转</strong>:调用报到确认接口后,生成 <code>train_class_report</code> 记录,同时将学员在 <code>train_enrollment</code> 的状态由 <code>0:待报到</code> 更新为 <code>1:已报到</code>,并写入 <code>join_time</code>。</li>
<li><strong>重复报到拦截</strong>:已报到学员再次报到时直接拦截,返回业务错误码 <code>40050</code>。</li>
<li><strong>报到时限校验</strong>:超过计划设定的 <code>report_deadline</code> 需由管理员特别确认。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>POST /train/enrollments/{enrollmentId}/report
GET /train/report/list</code></pre>
</div>
<div class="drawer-section">
<div class="drawer-section-title">物理数据模型</div>
<p><code>train_class_report</code> (字段: <code>report_id</code>, <code>enrollment_id</code>, <code>report_time</code>, <code>report_way</code>, <code>verify_note</code>)</p>
</div>
`
},
training: {
title: "7. 正式培训与课表执行 (Training Execution)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>任课教师 / 学员</strong>:依照课表安排,在指定理论教室或实训场地开展教学。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">业务支持特性</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>课表聚合视图</strong>:<code>GET /train/plans/{id}/timetable</code> 统一映射聚合 <code>courseName</code>, <code>teacherName</code>, <code>venueName</code> 及 <code>boardSn</code>。</li>
<li><strong>现场物联呈现</strong>:教室门口电子班牌实时显示当前课程与教师信息。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>GET /train/plans/{id}/timetable</code></pre>
</div>
`
},
attendance: {
title: "8. 课程考勤打卡与审计留痕 (Attendance)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>授课教师 / 随班班主任</strong>:跟踪学员课次到课率,处理签到、签退及异常请假补签。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">考勤幂等性与审计规范</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>签到签退幂等性</strong>:重复请求签到或签退时,保持首次打卡时间 <code>signInTime / signOutTime</code>,杜绝覆盖。</li>
<li><strong>人工代签留痕</strong>:管理员或教师人工修改考勤状态时,系统自动置 <code>manual_flag = 1</code>,记录修改人与修改备注供合规追溯。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>POST /train/attendance/sign-in
POST /train/attendance/sign-out
PUT /train/attendance/{checkinId}
GET /train/attendance/list</code></pre>
</div>
<div class="drawer-section">
<div class="drawer-section-title">物理数据模型</div>
<p><code>train_student_checkin</code> (字段: <code>checkin_id</code>, <code>enrollment_id</code>, <code>lesson_id</code>, <code>sign_in_time</code>, <code>sign_out_time</code>, <code>manual_flag</code>)</p>
</div>
`
},
completion: {
title: "9. 结训生命周期与退训保护 (Plan Completion)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">核心业务角色与职责</div>
<p><strong>教务科主管</strong>:培训周期结束、考核完毕后,发起班期正式结训动作。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">强事务联动与退训保护不变量</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>计划状态变更</strong>:<code>train_class_plan.plan_status</code> 由 <code>1:进行中</code> 变更为 <code>2:已结束</code>。</li>
<li><strong>在读活动学员自动完成</strong>:状态为 <code>0:待报到</code> 或 <code>1:已报到</code> 的学员,参训状态自动批量流转为 <code>4:已完成</code>,且 <code>complete_time</code> 真实写入。</li>
<li><strong>历史退训学员状态防误覆盖 (核心保护)</strong>:提前申请退训的学员 (<code>enrollmentStatus = 3</code>) 状态严格保持为 3,<code>complete_time</code> 保持为空,严禁被批量完成逻辑覆盖。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口契约</div>
<pre><code>POST /train/plans/{id}/complete</code></pre>
</div>
`
},
dormitory: {
title: "后勤住宿管理支线 (Accommodation)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">业务定位与流程衔接</div>
<p><strong>后勤宿管人员</strong>:作为核心教学的辅助支线,在学员报名时由 <code>accommodationRequired = 1</code> 触发,分配基地宿舍床位,结训时同步退宿交接。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口与数据表</div>
<pre><code>GET /train/dormitory/list
POST /train/dormitory/check-in
POST /train/dormitory/check-out</code></pre>
<p>物理表:<code>train_dormitory_info</code>, <code>train_accommodation</code></p>
</div>
`
},
board: {
title: "电子班牌显示支撑层 (Electronic Board)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物联设备支撑定位</div>
<p><strong>设备管理与现场终端</strong>:作为教学排课的呈现层,将物理班牌与教室绑定,并在课表及前端路由 <code>/equip/board</code> 中输出信息。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">核心验证规则与降级逻辑</div>
<ul style="padding-left: 1.25rem; line-height: 1.8;">
<li><strong>UUID 主键生成</strong>:自动生成 32 位 UUID 主键,默认在线状态 <code>board_status = 0</code>。</li>
<li><strong>教室绑定 0/1/N 映射</strong>:<code>GET /train/classroom/{id}</code> 准确返回绑定的班牌数组。</li>
<li><strong>课表 boardSn 智能降级规则</strong>:
<br>· 教室未绑板:<code>boardSn = null</code>;
<br>· 教室恰好绑 1 块板:<code>boardSn = 班牌序列号</code>;
<br>· 教室绑定 >1 块板:<code>boardSn = null</code> (避免多板歧义降级)。
</li>
<li><strong>逻辑删除保障</strong>:执行删除后,底层置 <code>del_flag = '2'</code>,常规查询接口不可见。</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">技术接口与物理表</div>
<pre><code>POST /train/board
GET /train/board/list
DELETE /train/board/{id}</code></pre>
<p>物理表:<code>train_electronic_board</code> (主键 <code>board_id</code> 32 位 UUID)</p>
</div>
`
}
};
function handleNodeClick(nodeKey) {
const data = nodeDetails[nodeKey];
if (!data) return;
window.openDrawer(data.title, data.html);
}
</script>
</body>
</html>
+658
View File
@@ -0,0 +1,658 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>核心数据模型与实体关系 (ER) - RailwaySystem 铁路智慧培训管理系统</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%231d4ed8' d='M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4z'/></svg>">
<link rel="stylesheet" href="assets/docs.css">
<style>
/* ER 关系图视觉容器 */
.er-canvas-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-lg);
padding: 2rem;
box-shadow: var(--shadow-card);
margin-bottom: 2.5rem;
}
.er-svg-wrap {
width: 100%;
overflow-x: auto;
padding: 0.5rem 0;
}
.er-svg {
min-width: 960px;
width: 100%;
height: auto;
display: block;
}
.er-entity {
cursor: pointer;
transition: all 0.15s ease;
}
.er-entity:hover {
filter: drop-shadow(0 4px 10px rgba(30, 64, 175, 0.2));
}
.er-entity:hover rect.entity-box {
stroke: var(--rail-blue);
stroke-width: 2px;
}
/* 实体网格卡片 */
.entity-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 1.25rem;
margin-top: 1.5rem;
}
.entity-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.25rem;
box-shadow: var(--shadow-card);
cursor: pointer;
transition: all 0.2s ease;
display: flex;
flex-direction: column;
}
.entity-card:hover {
border-color: var(--border-medium);
box-shadow: var(--shadow-card-hover);
transform: translateY(-2px);
}
</style>
</head>
<body>
<!-- 顶部主导航 -->
<nav class="navbar">
<div class="nav-brand-wrap">
<a href="index.html" class="nav-brand">
<svg viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></svg>
<div>
<div class="brand-title">RailwaySystem</div>
<div class="brand-sub">铁路智慧培训管理系统</div>
</div>
</a>
<span class="brand-pill">Final Candidate · 待正式部署</span>
</div>
<ul class="nav-menu">
<li><a href="index.html" class="nav-link">首页</a></li>
<li><a href="business-flow.html" class="nav-link">业务</a></li>
<li><a href="architecture.html" class="nav-link">系统</a></li>
<li><a href="testing.html" class="nav-link">质量</a></li>
<li><a href="release-status.html" class="nav-link">发布</a></li>
<li><a href="modules.html" class="nav-link">14大业务模块清单</a></li>
<li><a href="data-model.html" class="nav-link active">实体关系模型(ER)</a></li>
<li><a href="deployment.html" class="nav-link">部署拓扑与脚本Delta</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer" class="nav-handbook-link">&gt; 查阅部署发布手册</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/README.md" target="_blank" rel="noopener noreferrer" class="nav-back-link">&larr; 文档中心</a></li>
</ul>
</nav>
<!-- 页面主体容器 -->
<main class="page-container">
<header class="page-hero">
<div class="hero-pretitle">Entity Relationship & Persistence</div>
<h1 class="hero-title-main">核心业务实体关系模型 (ER)</h1>
<p class="hero-lead-text">
聚焦于 10 大核心教务实体的关联拓扑与物理约束。杜绝平铺冗长数据库大表,点击任意实体卡片或图谱节点即可查看物理表名、PK主键生成机制、外键引用与唯一性约束。
</p>
</header>
<!-- 简化 ER 关系图 SVG 容器 -->
<section class="er-canvas-card">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 0.75rem;">
<div>
<h2 style="font-size: 1.25rem; font-weight: 700; color: var(--navy-900);">10 大核心教务实体关系拓扑</h2>
<p style="font-size: 0.82rem; color: var(--text-muted); margin-top: 0.2rem;">点击实体节点展开物理表与约束细节</p>
</div>
<div style="font-size: 0.8rem; color: var(--text-muted);">
<span>1:N 一对多关联</span> · <span>N:M 多对多关联</span> · <span>XOR 互斥排他</span>
</div>
</div>
<div class="er-svg-wrap">
<svg class="er-svg" viewBox="0 0 1000 520" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="er-arrow" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
<path d="M0,1 L7,4 L0,7 Z" fill="#1d4ed8" />
</marker>
</defs>
<!-- 关系连线 -->
<!-- Plan -> PlanCourse (1:N) -->
<line x1="420" y1="100" x2="490" y2="100" stroke="#1d4ed8" stroke-width="2" marker-end="url(#er-arrow)" />
<text x="455" y="90" text-anchor="middle" font-size="10" fill="#64748b">1:N</text>
<!-- Course -> PlanCourse (1:N) -->
<line x1="720" y1="100" x2="650" y2="100" stroke="#1d4ed8" stroke-width="2" marker-end="url(#er-arrow)" />
<text x="685" y="90" text-anchor="middle" font-size="10" fill="#64748b">1:N</text>
<!-- Plan -> Enrollment (1:N) -->
<line x1="340" y1="140" x2="340" y2="210" stroke="#1d4ed8" stroke-width="2" marker-end="url(#er-arrow)" />
<text x="355" y="180" font-size="10" fill="#64748b">1:N</text>
<!-- Student -> Enrollment (1:N) -->
<line x1="170" y1="250" x2="260" y2="250" stroke="#1d4ed8" stroke-width="2" marker-end="url(#er-arrow)" />
<text x="215" y="240" text-anchor="middle" font-size="10" fill="#64748b">1:N</text>
<!-- PlanCourse -> Lesson (1:N) -->
<line x1="570" y1="140" x2="570" y2="210" stroke="#1d4ed8" stroke-width="2" marker-end="url(#er-arrow)" />
<text x="585" y="180" font-size="10" fill="#64748b">1:N</text>
<!-- Classroom -> Lesson (1:N, XOR) -->
<line x1="780" y1="220" x2="650" y2="240" stroke="#1d4ed8" stroke-width="1.5" stroke-dasharray="3 3" marker-end="url(#er-arrow)" />
<text x="720" y="225" font-size="10" fill="#64748b">XOR</text>
<!-- Site -> Lesson (1:N, XOR) -->
<line x1="780" y1="280" x2="650" y2="260" stroke="#1d4ed8" stroke-width="1.5" stroke-dasharray="3 3" marker-end="url(#er-arrow)" />
<text x="720" y="280" font-size="10" fill="#64748b">XOR</text>
<!-- Enrollment -> Report (1:1) -->
<line x1="340" y1="290" x2="340" y2="360" stroke="#1d4ed8" stroke-width="2" marker-end="url(#er-arrow)" />
<text x="355" y="330" font-size="10" fill="#64748b">1:1</text>
<!-- Enrollment -> Checkin (1:N) -->
<line x1="410" y1="280" x2="490" y2="380" stroke="#1d4ed8" stroke-width="1.5" marker-end="url(#er-arrow)" />
<!-- Lesson -> Checkin (1:N) -->
<line x1="570" y1="290" x2="570" y2="360" stroke="#1d4ed8" stroke-width="2" marker-end="url(#er-arrow)" />
<text x="585" y="330" font-size="10" fill="#64748b">1:N</text>
<!-- 1. Plan 实体 -->
<g class="er-entity" onclick="showEntityDetail('plan')">
<rect class="entity-box" x="260" y="60" width="160" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="260" y="60" width="160" height="26" rx="8" fill="#eff6ff" />
<text x="340" y="78" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">Plan (培训计划)</text>
<text x="275" y="102" font-size="11" fill="#334155">PK: plan_id (UUID)</text>
<text x="275" y="122" font-size="10" fill="#64748b">plan_status, recruit_num</text>
</g>
<!-- 2. PlanCourse 实体 -->
<g class="er-entity" onclick="showEntityDetail('plancourse')">
<rect class="entity-box" x="490" y="60" width="160" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="490" y="60" width="160" height="26" rx="8" fill="#eff6ff" />
<text x="570" y="78" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">PlanCourse (计划课程)</text>
<text x="505" y="102" font-size="11" fill="#334155">PK: plan_course_id</text>
<text x="505" y="122" font-size="10" fill="#64748b">FK: plan_id, c_id, t_id</text>
</g>
<!-- 3. Course 实体 -->
<g class="er-entity" onclick="showEntityDetail('course')">
<rect class="entity-box" x="720" y="60" width="150" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="720" y="60" width="150" height="26" rx="8" fill="#eff6ff" />
<text x="795" y="78" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">Course (课程大纲)</text>
<text x="735" y="102" font-size="11" fill="#334155">PK: c_id</text>
<text x="735" y="122" font-size="10" fill="#64748b">c_code (UK), c_duration</text>
</g>
<!-- 4. Student 实体 -->
<g class="er-entity" onclick="showEntityDetail('student')">
<rect class="entity-box" x="20" y="210" width="150" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="20" y="210" width="150" height="26" rx="8" fill="#eff6ff" />
<text x="95" y="228" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">Student (学员档案)</text>
<text x="35" y="252" font-size="11" fill="#334155">PK: s_id (UUID)</text>
<text x="35" y="272" font-size="10" fill="#64748b">id_card_last4, status</text>
</g>
<!-- 5. Enrollment 实体 -->
<g class="er-entity" onclick="showEntityDetail('enrollment')">
<rect class="entity-box" x="260" y="210" width="160" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="260" y="210" width="160" height="26" rx="8" fill="#eff6ff" />
<text x="340" y="228" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">Enrollment (参训名单)</text>
<text x="275" y="252" font-size="11" fill="#334155">PK: enrollment_id</text>
<text x="275" y="272" font-size="10" fill="#64748b">UK(plan_id, student_id)</text>
</g>
<!-- 6. Lesson 实体 -->
<g class="er-entity" onclick="showEntityDetail('lesson')">
<rect class="entity-box" x="490" y="210" width="160" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="490" y="210" width="160" height="26" rx="8" fill="#eff6ff" />
<text x="570" y="228" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">Lesson (排课课次)</text>
<text x="505" y="252" font-size="11" fill="#334155">PK: lesson_id</text>
<text x="505" y="272" font-size="10" fill="#64748b">venue_type (XOR互斥)</text>
</g>
<!-- 7. Classroom 实体 -->
<g class="er-entity" onclick="showEntityDetail('classroom')">
<rect class="entity-box" x="780" y="195" width="160" height="55" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="780" y="195" width="160" height="22" rx="8" fill="#eff6ff" />
<text x="860" y="211" text-anchor="middle" font-size="11" font-weight="700" fill="#1e40af">Classroom (理论教室)</text>
<text x="795" y="235" font-size="10" fill="#334155">PK: class_room_id, capacity</text>
</g>
<!-- 8. Site 实体 -->
<g class="er-entity" onclick="showEntityDetail('site')">
<rect class="entity-box" x="780" y="265" width="160" height="55" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="780" y="265" width="160" height="22" rx="8" fill="#eff6ff" />
<text x="860" y="281" text-anchor="middle" font-size="11" font-weight="700" fill="#1e40af">Site (实训场地)</text>
<text x="795" y="305" font-size="10" fill="#334155">PK: site_id (UUID), capacity</text>
</g>
<!-- 9. Report 实体 -->
<g class="er-entity" onclick="showEntityDetail('report')">
<rect class="entity-box" x="260" y="360" width="160" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="260" y="360" width="160" height="26" rx="8" fill="#eff6ff" />
<text x="340" y="378" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">Report (现场报到)</text>
<text x="275" y="402" font-size="11" fill="#334155">PK: report_id</text>
<text x="275" y="422" font-size="10" fill="#64748b">FK: enrollment_id, time</text>
</g>
<!-- 10. Checkin 实体 -->
<g class="er-entity" onclick="showEntityDetail('checkin')">
<rect class="entity-box" x="490" y="360" width="160" height="80" rx="8" fill="#ffffff" stroke="#1d4ed8" stroke-width="1.5" />
<rect x="490" y="360" width="160" height="26" rx="8" fill="#eff6ff" />
<text x="570" y="378" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">Checkin (课堂考勤)</text>
<text x="505" y="402" font-size="11" fill="#334155">PK: checkin_id</text>
<text x="505" y="422" font-size="10" fill="#64748b">FK: enrollment_id, lesson_id</text>
</g>
</svg>
</div>
</section>
<!-- 实体卡片速查网格 (点击展开 Drawer) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">10 大核心实体物理映射与核心约束</h2>
<p class="section-subtitle">点击卡片可快速展开物理表结构、主键生成机制与外键约束详情。</p>
</div>
</div>
<div class="entity-grid">
<div class="entity-card" onclick="showEntityDetail('plan')">
<div class="card-top">
<span class="badge badge-pass">实体 1</span>
<span class="card-code">train_class_plan</span>
</div>
<h3 class="card-title">培训班计划 (ClassPlan)</h3>
<p class="card-body-text">主键为 32 位 UUID,严格维护起止时间窗口与生命周期状态(0草稿/1进行中/2已结束)。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('plancourse')">
<div class="card-top">
<span class="badge badge-pass">实体 2</span>
<span class="card-code">train_plan_course</span>
</div>
<h3 class="card-title">计划绑定课程 (PlanCourse)</h3>
<p class="card-body-text">班级与课程 N:M 映射枢纽,关联授课教师,外键依赖计划与课程主表。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('course')">
<div class="card-top">
<span class="badge badge-pass">实体 3</span>
<span class="card-code">train_course</span>
</div>
<h3 class="card-title">课程主档 (Course)</h3>
<p class="card-body-text">课程编码全局唯一(c_code),维护理论学时与实操学时,供开班总学时累加。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('enrollment')">
<div class="card-top">
<span class="badge badge-pass">实体 4</span>
<span class="card-code">train_enrollment</span>
</div>
<h3 class="card-title">参训报名名单 (Enrollment)</h3>
<p class="card-body-text">物理唯一约束 uk_plan_student 杜绝重复入班,维护学员在班级的参训状态流转。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('student')">
<div class="card-top">
<span class="badge badge-pass">实体 5</span>
<span class="card-code">train_student</span>
</div>
<h3 class="card-title">学员基础档案 (Student)</h3>
<p class="card-body-text">32位UUID主键,身份证密文哈希存储与末4位掩码展示,维护学员主档状态(1正常/0停用)。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('lesson')">
<div class="card-top">
<span class="badge badge-pass">实体 6</span>
<span class="card-code">train_lesson</span>
</div>
<h3 class="card-title">排课课次 (Lesson)</h3>
<p class="card-body-text">上课时段与师资配置,严格校验场地 XOR 互斥约束,禁止跨计划绑定课程。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('classroom')">
<div class="card-top">
<span class="badge badge-pass">实体 7</span>
<span class="card-code">train_classroom_info</span>
</div>
<h3 class="card-title">理论教室 (Classroom)</h3>
<p class="card-body-text">主键 class_room_id,维护物理容量上限与可用状态,支撑 0/1/N 电子班牌挂载。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('site')">
<div class="card-top">
<span class="badge badge-pass">实体 8</span>
<span class="card-code">train_training_site</span>
</div>
<h3 class="card-title">实训演练场地 (Site)</h3>
<p class="card-body-text">主键 32 位 UUID,维护专业演练场地类型与最大容量,排课中参与场地互斥冲突校验。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('report')">
<div class="card-top">
<span class="badge badge-pass">实体 9</span>
<span class="card-code">train_class_report</span>
</div>
<h3 class="card-title">现场开班报到流水 (Report)</h3>
<p class="card-body-text">学员现场核验凭证,外键强关联 enrollment_id,报到成功强事务联动学员参训状态为已报到。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
<div class="entity-card" onclick="showEntityDetail('checkin')">
<div class="card-top">
<span class="badge badge-pass">实体 10</span>
<span class="card-code">train_student_checkin</span>
</div>
<h3 class="card-title">课次考勤打卡 (StudentCheckin)</h3>
<p class="card-body-text">记录学员课次打卡时间,保障签到签退幂等性防覆盖,人工代签自动置 manual_flag=1 审计留痕。</p>
<div style="font-size: 0.78rem; color: var(--rail-blue); font-weight: 600;">查看物理定义 &rarr;</div>
</div>
</div>
</section>
<!-- 完整 21 表事实源引导 (不平铺冗长表格,提供事实源折叠与指引) -->
<section class="content-section" style="margin-bottom: 0;">
<div class="accordion-item">
<div class="accordion-header">
<div class="accordion-title-group">
<span class="badge badge-neutral">完整 21 张物理业务表</span>
<span style="font-size: 0.95rem; font-weight: 600; color: var(--navy-900);">查看系统全量数据表归属与数据库事实源索引</span>
</div>
<svg class="accordion-arrow" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>
</div>
<div class="accordion-body">
<p style="margin-bottom: 1rem; color: var(--text-secondary);">
系统一期由 <strong>21 张培训业务表</strong> (<code>train_*</code>) 与 <strong>8 张平台底座权限审计表</strong> (<code>sys_*</code>) 构成,表清单契约与 DDL 严格冻结于 <code>docs/database-v2/</code> 目录下:
</p>
<div class="data-table-wrap">
<table class="data-table">
<thead>
<tr>
<th>表分类</th>
<th>物理表清单</th>
<th>职责描述</th>
<th>事实源文件</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>基础资料表 (9)</strong></td>
<td><code>train_teacher</code>, <code>train_student</code>, <code>train_course</code>, <code>train_resource</code>, <code>train_course_resource</code>, <code>train_classroom_info</code>, <code>train_training_site</code>, <code>train_electronic_board</code>, <code>train_dormitory_info</code></td>
<td>师资、学员、课程、统一资源、教室、场地、班牌设备、宿舍房间基础信息</td>
<td><code>docs/database-v2/01_table_inventory.md</code></td>
</tr>
<tr>
<td><strong>培训组织表 (4)</strong></td>
<td><code>train_class_plan</code>, <code>train_plan_course</code>, <code>train_enrollment</code>, <code>train_lesson</code></td>
<td>开班计划、课程绑定、参训报名名单、教学活动课次核心教务编排</td>
<td><code>docs/database-v2/01_table_inventory.md</code></td>
</tr>
<tr>
<td><strong>培训执行表 (4)</strong></td>
<td><code>train_accommodation</code>, <code>train_dorm_auth</code>, <code>train_class_report</code>, <code>train_student_checkin</code></td>
<td>学员住宿安排、门禁授权同步、现场报到核验、课次打卡考勤流水</td>
<td><code>docs/database-v2/01_table_inventory.md</code></td>
</tr>
<tr>
<td><strong>培训结果表 (4)</strong></td>
<td><code>train_score_item</code>, <code>train_student_score</code>, <code>train_study_duration</code>, <code>train_student_portrait</code></td>
<td>考核项配置、学员单项成绩、自主学时、学员全期画像评估 (只读模型 PASS)</td>
<td><code>docs/database-v2/01_table_inventory.md</code></td>
</tr>
<tr>
<td><strong>系统底座表 (8)</strong></td>
<td><code>sys_user</code>, <code>sys_role</code>, <code>sys_menu</code>, <code>sys_dept</code>, <code>sys_oper_log</code>, <code>sys_logininfor</code>, <code>sys_dict_type</code>, <code>sys_dict_data</code></td>
<td>RBAC 鉴权、路由菜单、操作审计日志与系统字典底座</td>
<td><code>docs/database-v2/00_init_ruoyi_sys.sql</code></td>
</tr>
</tbody>
</table>
</div>
<div style="margin-top: 1rem;">
<a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/04-data-model-overview.md" target="_blank" rel="noopener noreferrer" class="btn btn-secondary" style="font-size: 0.82rem;">查阅数据库全量设计手册 &rarr;</a>
</div>
</div>
</div>
</section>
</main>
<!-- 侧边抽屉组件 (Drawer) -->
<div class="drawer-backdrop" id="drawer-backdrop">
<div class="drawer-panel">
<div class="drawer-header">
<h3 class="drawer-title" id="drawer-title">实体定义</h3>
<button class="drawer-close" id="drawer-close-btn" type="button" aria-label="关闭">&times;</button>
</div>
<div class="drawer-body" id="drawer-body">
<!-- 动态注入实体详情 -->
</div>
</div>
</div>
<!-- 页脚 -->
<footer class="site-footer">
<p>RailwaySystem 铁路智慧培训管理系统 · 交付候选版 (Final Candidate)</p>
<p style="margin-top: 0.35rem; color: var(--text-muted);">
数据模型与实体关系 · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/04-data-model-overview.md" target="_blank" rel="noopener noreferrer">查阅数据模型手册</a>
</p>
</footer>
<script src="assets/docs.js"></script>
<script>
const entityDict = {
plan: {
title: "实体定义: ClassPlan (培训班主档计划)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_class_plan</code></p>
<p><strong>主键</strong>:<code>plan_id VARCHAR(32)</code>(后端自动生成 32 位 UUID,全局唯一)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">核心业务字段与类型</div>
<ul style="padding-left:1.2rem; line-height:1.8;">
<li><code>plan_name VARCHAR(100)</code>:培训班名称</li>
<li><code>plan_status INT</code>:0:草稿, 1:进行中, 2:已结束</li>
<li><code>start_time TIMESTAMP</code>:培训开始时间</li>
<li><code>end_time TIMESTAMP</code>:培训结束时间</li>
<li><code>report_deadline TIMESTAMP</code>:现场报到截止时间</li>
<li><code>recruit_num INT</code>:招生容量上限(硬拦截依据)</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">核心关联与业务约束</div>
<p>作为教务编排的根实体,下游一对多关联 <code>train_plan_course</code>、<code>train_enrollment</code>;结训时通过强事务批量完成关联活动学员。</p>
</div>
`
},
plancourse: {
title: "实体定义: PlanCourse (计划绑定课程)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_plan_course</code></p>
<p><strong>主键</strong>:<code>plan_course_id BIGINT</code>(自增/序列主键)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">核心关联外键</div>
<ul style="padding-left:1.2rem; line-height:1.8;">
<li><code>plan_id VARCHAR(32)</code>:所属培训计划外键</li>
<li><code>c_id BIGINT</code>:绑定课程大纲外键</li>
<li><code>t_id VARCHAR(32)</code>:指派主讲教师外键</li>
</ul>
</div>
<div class="drawer-section">
<div class="drawer-section-title">核心约束</div>
<p>作为排课课次 <code>train_lesson</code> 的唯一课程依赖,排课时强校验课次所属计划与 <code>plan_course_id</code> 严格一致,严禁跨计划错链。</p>
</div>
`
},
course: {
title: "实体定义: Course (课程大纲主档)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_course</code></p>
<p><strong>主键</strong>:<code>c_id BIGINT</code>(主键标识)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">唯一约束与核心字段</div>
<ul style="padding-left:1.2rem; line-height:1.8;">
<li><code>c_code VARCHAR(64) UNIQUE</code>:课程编码全局唯一</li>
<li><code>c_name VARCHAR(100)</code>:课程名称</li>
<li><code>c_duration INT</code>:标准课时数(大于 0)</li>
<li><code>status INT</code>:1:可用, 0:停用</li>
</ul>
</div>
`
},
enrollment: {
title: "实体定义: Enrollment (参训报名档案)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_enrollment</code></p>
<p><strong>主键</strong>:<code>enrollment_id BIGINT</code>(自增/序列主键)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">核心唯一约束 (防重复报名)</div>
<p><code>UNIQUE KEY uk_plan_student (plan_id, student_id)</code>:数据库层面强制杜绝同一学员在同一班级重复入班。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">参训状态机字段</div>
<p><code>enrollment_status INT</code>:0:待报到, 1:已报到, 2:请假, 3:退训, 4:已完成</p>
<p><code>complete_time TIMESTAMP</code>:结训完成时间(退训学员保持为空,受防破坏保护)</p>
</div>
`
},
student: {
title: "实体定义: Student (学员基础档案)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_student</code></p>
<p><strong>主键</strong>:<code>s_id VARCHAR(32)</code>(32 位 UUID)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">敏感信息脱敏与存储安全</div>
<ul style="padding-left:1.2rem; line-height:1.8;">
<li><code>id_card_ciphertext VARCHAR(255)</code>:身份证密文</li>
<li><code>id_card_hash VARCHAR(64)</code>:身份证哈希索引(用于精确检索)</li>
<li><code>id_card_last4 VARCHAR(4)</code>:末4位掩码(接口返回显示)</li>
<li><code>status INT</code>:1:正常, 0:停用(停用学员禁止报名)</li>
</ul>
</div>
`
},
lesson: {
title: "实体定义: Lesson (排课课次)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_lesson</code></p>
<p><strong>主键</strong>:<code>lesson_id BIGINT</code>(自增主键)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">场地互斥约束 (Venue XOR)</div>
<p><code>venue_type INT</code> (1:理论教室, 2:实训场地)。物理业务逻辑强校验 <code>class_room_id</code> 与 <code>site_id</code> 满足二选一严格互斥,不可同时为空或同时赋值。</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">时间与状态约束</div>
<p>必须满足 <code>start_time &lt; end_time</code>,且计划结训后强阻断新增或修改课次。</p>
</div>
`
},
classroom: {
title: "实体定义: Classroom (理论教室)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_classroom_info</code></p>
<p><strong>主键</strong>:<code>class_room_id VARCHAR(32)</code></p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">字段与物联扩展</div>
<p><code>room_name VARCHAR(100)</code>:教室门牌名称</p>
<p><code>capacity INT</code>:标准座位容量</p>
<p>支持下游一对多绑定 <code>train_electronic_board</code> 电子班牌终端。</p>
</div>
`
},
site: {
title: "实体定义: TrainingSite (实训演练场地)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_training_site</code></p>
<p><strong>主键</strong>:<code>site_id VARCHAR(32)</code>(32 位 UUID)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">专业场地特征</div>
<p><code>site_name VARCHAR(100)</code>:场地名称(如信号演练场、机务整备场)</p>
<p><code>capacity INT</code>:最大容纳实训人数</p>
<p>排课预检中触发 <code>SITE</code> 级别 Warning 预警。</p>
</div>
`
},
report: {
title: "实体定义: ClassReport (开班报到流水)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_class_report</code></p>
<p><strong>主键</strong>:<code>report_id BIGINT</code>(自增主键)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">强事务联动与防重约束</div>
<p><code>enrollment_id BIGINT</code>:外键关联参训记录。</p>
<p>报到动作自动流转 <code>enrollment_status = 1</code>,若已报到则强行拦截防重复报到 (40050)。</p>
</div>
`
},
checkin: {
title: "实体定义: StudentCheckin (课次考勤打卡)",
html: `
<div class="drawer-section">
<div class="drawer-section-title">物理表与主键</div>
<p><strong>物理表名</strong>:<code>train_student_checkin</code></p>
<p><strong>主键</strong>:<code>checkin_id BIGINT</code>(自增主键)</p>
</div>
<div class="drawer-section">
<div class="drawer-section-title">幂等性与人工审计标志</div>
<ul style="padding-left:1.2rem; line-height:1.8;">
<li><code>sign_in_time TIMESTAMP</code>:首次签到时间(重复签到保持首次不变)</li>
<li><code>sign_out_time TIMESTAMP</code>:首次签退时间(重复签退保持首次不变)</li>
<li><code>manual_flag INT</code>:0:自动打卡, 1:人工代签/补签(审计标志)</li>
</ul>
</div>
`
}
};
function showEntityDetail(key) {
const data = entityDict[key];
if (!data) return;
window.openDrawer(data.title, data.html);
}
</script>
</body>
</html>
+328
View File
@@ -0,0 +1,328 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>部署拓扑与发布增量 Delta - RailwaySystem 铁路智慧培训管理系统</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%231d4ed8' d='M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4z'/></svg>">
<link rel="stylesheet" href="assets/docs.css">
<style>
/* 拓扑图与部署专属样式 */
.topology-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-lg);
padding: 2rem;
box-shadow: var(--shadow-card);
margin-bottom: 2.5rem;
}
.topology-svg-wrap {
width: 100%;
overflow-x: auto;
padding: 0.5rem 0;
}
.topology-svg {
min-width: 800px;
width: 100%;
height: auto;
display: block;
}
/* 007 醒目但不占屏的警示条 */
.warning-alert-bar {
background: #fef2f2;
border: 1px solid #fecaca;
border-left: 4px solid #dc2626;
border-radius: var(--radius-md);
padding: 1rem 1.25rem;
margin-bottom: 2rem;
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
flex-wrap: wrap;
}
.warning-tag-box {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-size: 0.8rem;
font-weight: 700;
color: #dc2626;
background: #fee2e2;
padding: 0.2rem 0.6rem;
border-radius: var(--radius-sm);
white-space: nowrap;
}
/* Delta 脚本卡片 */
.delta-summary-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.5rem;
box-shadow: var(--shadow-card);
margin-bottom: 1.5rem;
}
</style>
</head>
<body>
<!-- 顶部主导航 -->
<nav class="navbar">
<div class="nav-brand-wrap">
<a href="index.html" class="nav-brand">
<svg viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></svg>
<div>
<div class="brand-title">RailwaySystem</div>
<div class="brand-sub">铁路智慧培训管理系统</div>
</div>
</a>
<span class="brand-pill">Final Candidate · 待正式部署</span>
</div>
<ul class="nav-menu">
<li><a href="index.html" class="nav-link">首页</a></li>
<li><a href="business-flow.html" class="nav-link">业务</a></li>
<li><a href="architecture.html" class="nav-link">系统</a></li>
<li><a href="testing.html" class="nav-link">质量</a></li>
<li><a href="release-status.html" class="nav-link">发布</a></li>
<li><a href="modules.html" class="nav-link">14大业务模块清单</a></li>
<li><a href="data-model.html" class="nav-link">实体关系模型(ER)</a></li>
<li><a href="deployment.html" class="nav-link active">部署拓扑与脚本Delta</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer" class="nav-handbook-link">&gt; 查阅部署发布手册</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/README.md" target="_blank" rel="noopener noreferrer" class="nav-back-link">&larr; 文档中心</a></li>
</ul>
</nav>
<!-- 页面主体容器 -->
<main class="page-container">
<header class="page-hero">
<div class="hero-pretitle">Production Deployment & Delta</div>
<h1 class="hero-title-main">生产部署拓扑与脚本 Delta</h1>
<p class="hero-lead-text">
默认仅呈现生产目标极简标准拓扑链路:User &rarr; Frontend (8082) &rarr; Backend (8092) &rarr; Kingbase / Redis。复杂的开发隧道端口与迁移文件名折叠收录于技术细节中。
</p>
</header>
<!-- 1. 007 脚本警示条 -->
<div class="warning-alert-bar">
<div style="display: flex; align-items: center; gap: 0.75rem;">
<span class="warning-tag-box">DO NOT EXECUTE 严禁执行</span>
<div style="font-size: 0.88rem; color: #991b1b;">
<strong>历史业务字典脚本 (RuoYi-Vue/sql/train/v2/007_dicts.sql) 本次发布严禁执行!</strong> 该脚本作为历史 V2 字典初始化资产存档,当前发布不包含且无需执行。
</div>
</div>
<span class="badge badge-danger">仅执行增量 001~003</span>
</div>
<!-- 2. 生产目标标准拓扑 (极简 4 层纵向链) -->
<section class="topology-card">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 0.75rem;">
<div>
<h2 style="font-size: 1.25rem; font-weight: 700; color: var(--navy-900);">生产目标部署标准拓扑 (Production Topology)</h2>
<p style="font-size: 0.82rem; color: var(--text-muted); margin-top: 0.2rem;">纯粹生产网络走向,无中间干扰项</p>
</div>
<span class="badge badge-pass">标准四层链路</span>
</div>
<div class="topology-svg-wrap">
<svg class="topology-svg" viewBox="0 0 800 380" style="width: 100%; height: auto; max-width: 800px; display: block; margin: 0 auto;">
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="6" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 1 L 10 5 L 0 9 z" fill="#64748b"/>
</marker>
</defs>
<!-- 1. Client Browser -->
<g>
<rect x="250" y="20" width="300" height="52" rx="8" fill="#f8fafc" stroke="#94a3b8" stroke-width="1.5"/>
<text x="400" y="52" text-anchor="middle" font-size="14" font-weight="700" fill="#0f172a">终端客户端浏览器 (Client Browser)</text>
</g>
<!-- Link 1 -> 2 -->
<line x1="400" y1="72" x2="400" y2="108" stroke="#64748b" stroke-width="1.5" marker-end="url(#arrow)"/>
<text x="410" y="94" font-size="11" fill="#64748b">HTTPS / HTTP (80/443)</text>
<!-- 2. Frontend Nginx / Dist -->
<g>
<rect x="230" y="110" width="340" height="56" rx="8" fill="#eff6ff" stroke="#3b82f6" stroke-width="1.5"/>
<text x="400" y="135" text-anchor="middle" font-size="13" font-weight="700" fill="#1d4ed8">生产前端静态容器 (Nginx 反向代理)</text>
<text x="400" y="153" text-anchor="middle" font-size="11" fill="#2563eb">目标端口: 8082 · Vue 2.6 SPA 编译产物</text>
</g>
<!-- Link 2 -> 3 -->
<line x1="400" y1="166" x2="400" y2="202" stroke="#64748b" stroke-width="1.5" marker-end="url(#arrow)"/>
<text x="410" y="188" font-size="11" fill="#64748b">/prod-api/ 反向代理</text>
<!-- 3. Backend Spring Boot -->
<g>
<rect x="230" y="204" width="340" height="56" rx="8" fill="#f0fdf4" stroke="#10b981" stroke-width="1.5"/>
<text x="400" y="229" text-anchor="middle" font-size="13" font-weight="700" fill="#047857">生产后端单体服务 (Spring Boot 2.5.15)</text>
<text x="400" y="247" text-anchor="middle" font-size="11" fill="#059669">目标端口: 8092 · RuoYi-Vue 业务核心 JAR</text>
</g>
<!-- Link 3 -> 4 Databases -->
<line x1="350" y1="260" x2="280" y2="284" stroke="#64748b" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="450" y1="260" x2="520" y2="284" stroke="#64748b" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- 4a. KingbaseES -->
<g>
<rect x="170" y="286" width="220" height="60" rx="8" fill="#fef2f2" stroke="#ef4444" stroke-width="1.5"/>
<text x="280" y="310" text-anchor="middle" font-size="13" font-weight="700" fill="#991b1b">KingbaseES (生产主库)</text>
<text x="280" y="330" text-anchor="middle" font-size="11" fill="#b91c1c">V009R003C018 · 21张业务表</text>
</g>
<!-- 4b. Redis -->
<g>
<rect x="410" y="286" width="220" height="60" rx="8" fill="#f0f9ff" stroke="#0284c7" stroke-width="1.5"/>
<text x="520" y="310" text-anchor="middle" font-size="13" font-weight="700" fill="#0369a1">Redis (缓存与会话)</text>
<text x="520" y="330" text-anchor="middle" font-size="11" fill="#0284c7">Token 校验 · 验证码防重放</text>
</g>
</svg>
</div>
</section>
<!-- 3. Release Delta (3 required migrations) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">发布数据库增量变更 (Release Delta)</h2>
<p class="section-subtitle">本次生产升级仅需依次执行 3 个幂等增量脚本,保障历史业务数据零丢失。</p>
</div>
<span class="badge badge-pass">3 Required Migrations</span>
</div>
<div class="delta-summary-card">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.85rem; flex-wrap: wrap; gap: 0.5rem;">
<h3 style="font-size: 1.05rem; font-weight: 700; color: var(--navy-900);">3 Required Migrations (必须且仅执行)</h3>
<span class="badge badge-pass">DELTA = 3</span>
</div>
<p style="font-size: 0.88rem; color: var(--text-secondary); line-height: 1.7; margin-bottom: 1rem;">
生产环境已具备完整基础 Schema,本次升级严格限定于 3 个增量脚本,顺序执行即可完成日志耗时字段补齐、分析域权限闭环与报到考勤写权限补全:
</p>
<!-- 手风琴展开具体的 001/002/003 脚本细节 -->
<div class="accordion-item">
<div class="accordion-header">
<div class="accordion-title-group">
<span class="badge badge-pass">001</span>
<span style="font-size: 0.92rem; font-weight: 600; color: var(--navy-900);">001_sys_oper_log_cost_time.sql (操作日志耗时字段补丁)</span>
</div>
<svg class="accordion-arrow" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>
</div>
<div class="accordion-body">
<p><strong>作用</strong>:为系统操作日志表 <code>sys_oper_log</code> 补齐缺失的 <code>cost_time</code> 耗时字段 (<code>BIGINT DEFAULT 0</code>),对已有存量记录执行补偿归零初始化。</p>
<p><strong>执行方式</strong>:<code>\i RuoYi-Vue/sql/system/kingbase/001_sys_oper_log_cost_time.sql</code></p>
</div>
</div>
<div class="accordion-item">
<div class="accordion-header">
<div class="accordion-title-group">
<span class="badge badge-pass">002</span>
<span style="font-size: 0.92rem; font-weight: 600; color: var(--navy-900);">002_legacy_analytics_permissions.sql (分析域菜单与RBAC导出权限闭环)</span>
</div>
<svg class="accordion-arrow" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>
</div>
<div class="accordion-body">
<p><strong>作用</strong>:为培训分析域四大报表页面(Report、Checkin、Duration、Portrait)注入规范的 RBAC 导出权限与按钮(分配 menu_id 2177~2180),并校验父级菜单与防孤儿角色映射。</p>
<p><strong>执行方式</strong>:<code>\i RuoYi-Vue/sql/system/kingbase/002_legacy_analytics_permissions.sql</code></p>
</div>
</div>
<div class="accordion-item">
<div class="accordion-header">
<div class="accordion-title-group">
<span class="badge badge-pass">003</span>
<span style="font-size: 0.92rem; font-weight: 600; color: var(--navy-900);">003_report_attendance_action_permissions.sql (报到与考勤动作权限闭环)</span>
</div>
<svg class="accordion-arrow" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>
</div>
<div class="accordion-body">
<p><strong>作用</strong>:补齐现场报到确认 (<code>train:report:confirm</code> 2181)、考勤打卡录入 (<code>train:attendance:checkin</code> 2182) 与状态修改 (<code>train:attendance:edit</code> 2183) 动作权限,确保强写操作受到权限拦截保护。</p>
<p><strong>执行方式</strong>:<code>\i RuoYi-Vue/sql/system/kingbase/003_report_attendance_action_permissions.sql</code></p>
</div>
</div>
</div>
</section>
<!-- 4. 技术细节折叠手风琴 (Technical Details) -->
<section class="content-section" style="margin-bottom: 0;">
<div class="section-header">
<div>
<h2 class="section-title">技术底层细节与开发环境映射 (Technical Details)</h2>
<p class="section-subtitle">收录研发跳板机隧道、调试端口、心跳探测契约与运维排障细节。</p>
</div>
</div>
<div class="accordion-item">
<div class="accordion-header">
<div class="accordion-title-group">
<span class="badge badge-neutral">端口与隧道映射</span>
<span style="font-size: 0.95rem; font-weight: 600; color: var(--navy-900);">查看开发/测试/生产各环境端口配置与真实心跳探测契约</span>
</div>
<svg class="accordion-arrow" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>
</div>
<div class="accordion-body">
<div class="data-table-wrap">
<table class="data-table">
<thead>
<tr>
<th>组件名称</th>
<th>生产标准端口</th>
<th>本地/研发测试端口</th>
<th>健康心跳探测规范</th>
<th>备注说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>前端 Web 应用</strong></td>
<td><code>8082</code></td>
<td><code>8080</code> (开发 dev-server)</td>
<td><code>GET / (HTTP 200)</code></td>
<td>Vue 2.6 单页应用,Nginx 反向代理</td>
</tr>
<tr>
<td><strong>后端 API 服务</strong></td>
<td><code>8092</code></td>
<td><code>8090 / 8094</code> (独立实例)</td>
<td><code>GET /login (HTTP 200)</code></td>
<td>Spring Boot JAR,无 actuator 依赖,探测登录接口</td>
</tr>
<tr>
<td><strong>KingbaseES 主库</strong></td>
<td>物理直连端口</td>
<td><code>127.0.0.1:4321</code> (SSH隧道)</td>
<td><code>SELECT 1 FROM DUAL</code></td>
<td>通过安全跳板机建立隧道映射进行集成验证</td>
</tr>
<tr>
<td><strong>Redis 缓存</strong></td>
<td><code>6379</code></td>
<td><code>127.0.0.1:6379</code></td>
<td><code>PING -&gt; PONG</code></td>
<td>存储用户 JWT 令牌与防重放临时验证码</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
</main>
<!-- 页脚 -->
<footer class="site-footer">
<p>RailwaySystem 铁路智慧培训管理系统 · 交付候选版 (Final Candidate)</p>
<p style="margin-top: 0.35rem; color: var(--text-muted);">
部署拓扑与 Delta 规范 · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer">查阅部署手册</a> · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/reports/deployment-report.md" target="_blank" rel="noopener noreferrer">查阅部署报告</a>
</p>
</footer>
<script src="assets/docs.js"></script>
</body>
</html>
View File
Whitespace-only changes.
+601
View File
@@ -0,0 +1,601 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RailwaySystem 铁路智慧培训管理系统 - 数字化交付门户</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%231d4ed8' d='M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4z'/></svg>">
<link rel="stylesheet" href="assets/docs.css">
<style>
/* 首页专属轻量样式 */
.home-hero-badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
background: #eff6ff;
border: 1px solid #bfdbfe;
color: #1d4ed8;
padding: 0.3rem 0.85rem;
border-radius: var(--radius-full);
font-size: 0.82rem;
font-weight: 600;
margin-bottom: 1.25rem;
}
.hero-status-strip {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-top: 1.5rem;
}
.status-pill-item {
display: inline-flex;
align-items: center;
gap: 0.45rem;
padding: 0.35rem 0.85rem;
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-full);
font-size: 0.82rem;
font-weight: 500;
color: var(--text-secondary);
box-shadow: var(--shadow-subtle);
}
.status-pill-item .dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.status-pill-item .dot.green { background: var(--pass-color); }
.status-pill-item .dot.amber { background: var(--pending-color); }
/* 业务生命周期水平流程条 */
.lifecycle-flow-wrap {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.75rem 1.5rem;
box-shadow: var(--shadow-card);
overflow-x: auto;
}
.lifecycle-track {
display: flex;
align-items: center;
justify-content: space-between;
min-width: 860px;
position: relative;
}
.lifecycle-step {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
position: relative;
flex: 1;
}
.lifecycle-num {
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--rail-blue-subtle);
border: 2px solid var(--rail-blue-border);
color: var(--rail-blue);
font-size: 0.85rem;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0.5rem;
z-index: 2;
}
.lifecycle-step.active .lifecycle-num {
background: var(--rail-blue);
border-color: var(--rail-blue);
color: #ffffff;
}
.lifecycle-name {
font-size: 0.88rem;
font-weight: 600;
color: var(--navy-900);
margin-bottom: 0.2rem;
}
.lifecycle-sub {
font-size: 0.74rem;
color: var(--text-muted);
}
.lifecycle-connector {
position: absolute;
top: 16px;
left: 6%;
right: 6%;
height: 2px;
background: var(--border-light);
z-index: 1;
}
/* 管理问题与解决方案两列卡片 */
.problem-solution-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.5rem;
box-shadow: var(--shadow-card);
}
.pain-point-list {
list-style: none;
margin-top: 1rem;
}
.pain-point-item {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.65rem 0;
border-bottom: 1px dashed var(--border-light);
font-size: 0.88rem;
}
.pain-point-item:last-child {
border-bottom: 0;
}
.point-tag {
flex-shrink: 0;
font-size: 0.72rem;
font-weight: 700;
padding: 0.15rem 0.45rem;
border-radius: var(--radius-xs);
}
.point-tag.pain {
background: #fef2f2;
color: #dc2626;
border: 1px solid #fecaca;
}
.point-tag.solve {
background: #ecfdf5;
color: #059669;
border: 1px solid #a7f3d0;
}
/* 当前阶段时间线横条 */
.stage-progress-bar {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.5rem;
box-shadow: var(--shadow-card);
}
.stage-item {
padding: 0.75rem;
border-left: 3px solid var(--border-medium);
}
.stage-item.completed {
border-left-color: var(--pass-color);
}
.stage-item.current {
border-left-color: var(--pending-color);
background: #fffbeb;
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.stage-title {
font-size: 0.95rem;
font-weight: 700;
color: var(--navy-900);
margin-bottom: 0.25rem;
}
.stage-desc {
font-size: 0.78rem;
color: var(--text-muted);
}
</style>
</head>
<body>
<!-- 顶部主导航 -->
<nav class="navbar">
<div class="nav-brand-wrap">
<a href="index.html" class="nav-brand">
<svg viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></svg>
<div>
<div class="brand-title">RailwaySystem</div>
<div class="brand-sub">铁路智慧培训管理系统</div>
</div>
</a>
<span class="brand-pill">Final Candidate · 待正式部署</span>
</div>
<ul class="nav-menu">
<li><a href="index.html" class="nav-link active">首页</a></li>
<li><a href="business-flow.html" class="nav-link">业务</a></li>
<li><a href="architecture.html" class="nav-link">系统</a></li>
<li><a href="testing.html" class="nav-link">质量</a></li>
<li><a href="release-status.html" class="nav-link">发布</a></li>
<li><a href="modules.html" class="nav-link">14大业务模块清单</a></li>
<li><a href="data-model.html" class="nav-link">实体关系模型(ER)</a></li>
<li><a href="deployment.html" class="nav-link">部署拓扑与脚本Delta</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer" class="nav-handbook-link">&gt; 查阅部署发布手册</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/README.md" target="_blank" rel="noopener noreferrer" class="nav-back-link">&larr; 文档中心</a></li>
</ul>
</nav>
<!-- 页面主体容器 -->
<main class="page-container">
<!-- 1. Hero 第一屏:克制、高层、清晰定位 -->
<header class="page-hero">
<div class="home-hero-badge">
<span>一期核心交付工程</span>
<span>·</span>
<span>候选发布版 (Final Candidate)</span>
</div>
<h1 class="hero-title-main">RailwaySystem 铁路智慧培训管理系统</h1>
<p class="hero-lead-text">
面向铁路培训基地,覆盖培训计划、课程编排、参训管理、现场报到、排课考勤和统计分析的一期智慧培训平台。
</p>
<!-- 状态指示条:只展示关键交付态,不展示底层细节 -->
<div class="hero-status-strip">
<div class="status-pill-item">
<span class="dot green"></span>
<span>Final Candidate 已冻结</span>
</div>
<div class="status-pill-item">
<span class="dot green"></span>
<span>核心教务闭环全线通过</span>
</div>
<div class="status-pill-item">
<span class="dot green"></span>
<span>浏览器端到端验收 PASS</span>
</div>
<div class="status-pill-item">
<span class="dot amber"></span>
<span>待正式生产部署 (PENDING)</span>
</div>
</div>
</header>
<!-- 2. 项目解决什么问题 (重点解决的管理问题 vs 解决方案) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">项目解决什么问题</h2>
<p class="section-subtitle">针对铁路职工培训中教务协同、排课冲突防范、报到考勤核验及结训生命周期管理等核心业务场景,提供一整套数字化闭环解决方案。</p>
</div>
</div>
<div class="card-grid-2">
<div class="problem-solution-card">
<h3 style="font-size: 1.05rem; font-weight: 700; color: #991b1b; margin-bottom: 0.5rem; display: flex; align-items: center; gap: 0.5rem;">
<span>一期重点解决的管理问题</span>
</h3>
<ul class="pain-point-list">
<li class="pain-point-item">
<span class="point-tag pain">问题 1</span>
<div><strong>基础资源分散孤立</strong>:教师资质、学员档案、专用实训场地与理论教室各自维护,无法全局联动。</div>
</li>
<li class="pain-point-item">
<span class="point-tag pain">问题 2</span>
<div><strong>教务排课冲突严重</strong>:师资时间重叠、教室重复占用无预警,现场调课成本极高。</div>
</li>
<li class="pain-point-item">
<span class="point-tag pain">问题 3</span>
<div><strong>现场报到与考勤手工化</strong>:纸质签到核验慢,代签漏签难以追溯,无法与学员参训状态强联动。</div>
</li>
<li class="pain-point-item">
<span class="point-tag pain">问题 4</span>
<div><strong>培训结训生命周期断层</strong>:结训后学员状态需人工逐一变更,历史退训记录容易被批量操作误覆盖。</div>
</li>
</ul>
</div>
<div class="problem-solution-card">
<h3 style="font-size: 1.05rem; font-weight: 700; color: #166534; margin-bottom: 0.5rem; display: flex; align-items: center; gap: 0.5rem;">
<span>RailwaySystem 本期落地解决方案</span>
</h3>
<ul class="pain-point-list">
<li class="pain-point-item">
<span class="point-tag solve">方案 1</span>
<div><strong>统一主数据与脱敏机制</strong>:教室与实训场地二选一互斥建模,学员敏感信息脱敏显示与哈希安全存储。</div>
</li>
<li class="pain-point-item">
<span class="point-tag solve">方案 2</span>
<div><strong>四维排课防重叠与冲突预检</strong>:教师硬冲突拦截,教室/场地/计划重叠分级 Warning 预警,管理员确认即保存。</div>
</li>
<li class="pain-point-item">
<span class="point-tag solve">方案 3</span>
<div><strong>现场报到确认与课次考勤联动</strong>:报到动作自动流转学员状态至已报到;课次签到签退幂等性保护,人工修正全程留痕。</div>
</li>
<li class="pain-point-item">
<span class="point-tag solve">方案 4</span>
<div><strong>计划一键结训与历史保护机制</strong>:强事务批量流转在读学员状态为已完成,精准锁定历史退训学员状态防破坏。</div>
</li>
</ul>
</div>
</div>
</section>
<!-- 3. 业务生命周期可视化 -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">业务生命周期可视化</h2>
<p class="section-subtitle">贯穿铁路职工进入培训基地至结训考核离校的全过程,主干链路紧密衔接,支撑后勤与现场设施协同。</p>
</div>
<a href="business-flow.html" class="btn btn-secondary" style="font-size: 0.82rem; padding: 0.35rem 0.85rem;">查看业务全景 &rarr;</a>
</div>
<div class="lifecycle-flow-wrap">
<div class="lifecycle-track">
<div class="lifecycle-connector"></div>
<div class="lifecycle-step active">
<div class="lifecycle-num">1</div>
<div class="lifecycle-name">基础资源</div>
<div class="lifecycle-sub">教师/场地/课程</div>
</div>
<div class="lifecycle-step active">
<div class="lifecycle-num">2</div>
<div class="lifecycle-name">开班计划</div>
<div class="lifecycle-sub">拟定班期与容量</div>
</div>
<div class="lifecycle-step active">
<div class="lifecycle-num">3</div>
<div class="lifecycle-name">绑定课程</div>
<div class="lifecycle-sub">师资与学时配置</div>
</div>
<div class="lifecycle-step active">
<div class="lifecycle-num">4</div>
<div class="lifecycle-name">学员报名</div>
<div class="lifecycle-sub">入班与容量防超额</div>
</div>
<div class="lifecycle-step active">
<div class="lifecycle-num">5</div>
<div class="lifecycle-name">排课与准备</div>
<div class="lifecycle-sub">防重叠排课/住宿</div>
</div>
<div class="lifecycle-step active">
<div class="lifecycle-num">6</div>
<div class="lifecycle-name">现场报到</div>
<div class="lifecycle-sub">核验确认状态流转</div>
</div>
<div class="lifecycle-step active">
<div class="lifecycle-num">7</div>
<div class="lifecycle-name">教学与考勤</div>
<div class="lifecycle-sub">签到/班牌呈现</div>
</div>
<div class="lifecycle-step active">
<div class="lifecycle-num">8</div>
<div class="lifecycle-name">结训联动</div>
<div class="lifecycle-sub">自动完成/退训保护</div>
</div>
<div class="lifecycle-step">
<div class="lifecycle-num">9</div>
<div class="lifecycle-name">统计分析</div>
<div class="lifecycle-sub">只读查询与画像</div>
</div>
</div>
</div>
</section>
<!-- 4. 4大能力域 (功能矩阵) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">4 大核心能力域</h2>
<p class="section-subtitle">清晰划分系统业务职责边界,高内聚低耦合,覆盖资源管理、教务排产、现场执行与分析洞察。</p>
</div>
<a href="modules.html" class="btn btn-secondary" style="font-size: 0.82rem; padding: 0.35rem 0.85rem;">查看14大模块 &rarr;</a>
</div>
<div class="card-grid-4">
<!-- 能力域 1 -->
<div class="standard-card">
<div class="card-top">
<div class="card-title-wrap">
<div class="card-icon-box">资</div>
<div>
<h3 class="card-title">培训资源域</h3>
<span class="card-code">Master Data</span>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="card-body-text">
统一维护师资库、学员主档、课程库、理论教室、实训演练基地以及后勤宿舍。提供敏感个人信息脱敏及手机号唯一性强校验。
</p>
<div class="card-footer-action">
<span style="color: var(--text-muted);">涵盖 6 个基础模块</span>
<a href="modules.html#group-resource">查看资源详情 &rarr;</a>
</div>
</div>
<!-- 能力域 2 -->
<div class="standard-card">
<div class="card-top">
<div class="card-title-wrap">
<div class="card-icon-box">编</div>
<div>
<h3 class="card-title">教务编排域</h3>
<span class="card-code">Scheduling Core</span>
</div>
</div>
<span class="badge badge-pass">VERIFIED</span>
</div>
<p class="card-body-text">
实现开班计划编制、课程师资绑定、参训名单导入与招生容量硬拦截。搭载智能排课冲突预检机制,支持 Warning 级灵活排考确认。
</p>
<div class="card-footer-action">
<span style="color: var(--text-muted);">涵盖 4 个教务模块</span>
<a href="modules.html#group-scheduling">查看编排规则 &rarr;</a>
</div>
</div>
<!-- 能力域 3 -->
<div class="standard-card">
<div class="card-top">
<div class="card-title-wrap">
<div class="card-icon-box">执</div>
<div>
<h3 class="card-title">现场执行域</h3>
<span class="card-code">Execution & IoT</span>
</div>
</div>
<span class="badge badge-pass">VERIFIED</span>
</div>
<p class="card-body-text">
支撑开班现场报到核验与参训状态流转,处理课堂签到与签退幂等性,提供人工代签留痕审计,并通过 Web 班牌路由呈现课表与状态。
</p>
<div class="card-footer-action">
<span style="color: var(--text-muted);">涵盖 3 个执行模块</span>
<a href="modules.html#group-execution">查看现场交互 &rarr;</a>
</div>
</div>
<!-- 能力域 4 -->
<div class="standard-card">
<div class="card-top">
<div class="card-title-wrap">
<div class="card-icon-box">析</div>
<div>
<h3 class="card-title">数据分析域</h3>
<span class="card-code">Analytics & Reports</span>
</div>
</div>
<span class="badge badge-pass">V2 READ MODEL · PASS</span>
</div>
<p class="card-body-text">
聚合生成报到率、考勤打卡统计、学员课时完成度及多维能力画像报表。当前版本提供完整只读与导出能力,保持独立架构隔离。
</p>
<div class="card-footer-action">
<span style="color: var(--text-muted);">涵盖 1 个分析模块</span>
<a href="modules.html#group-analytics">查看分析模型 &rarr;</a>
</div>
</div>
</div>
</section>
<!-- 5. 真实质量防御成果 (真实数据指标) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">分层质量防御与全链路验收</h2>
<p class="section-subtitle">从离线单元逻辑、跨模块端到端集成、物理数据库落库校验到浏览器真实交互的四级防护体系。</p>
</div>
<a href="testing.html" class="btn btn-secondary" style="font-size: 0.82rem; padding: 0.35rem 0.85rem;">查看测试矩阵 &rarr;</a>
</div>
<div class="kpi-banner">
<div class="kpi-item">
<div class="kpi-num">154 / 154</div>
<div class="kpi-label">后端单元测试</div>
<div class="kpi-sub">Maven Surefire 全量通过</div>
</div>
<div class="kpi-item">
<div class="kpi-num">6 / 6</div>
<div class="kpi-label">核心业务场景套件</div>
<div class="kpi-sub">SC-01 ~ SC-06 闭环通过</div>
</div>
<div class="kpi-item">
<div class="kpi-num">110</div>
<div class="kpi-label">真实 HTTP 请求</div>
<div class="kpi-sub">服务端 500 异常 = 0</div>
</div>
<div class="kpi-item">
<div class="kpi-num">11 / 11</div>
<div class="kpi-label">物理数据库断言</div>
<div class="kpi-sub">Kingbase 实体完整性校验</div>
</div>
<div class="kpi-item">
<div class="kpi-num">0</div>
<div class="kpi-label">浏览器阻断异常</div>
<div class="kpi-sub">控制台 Console Error = 0</div>
</div>
</div>
</section>
<!-- 6. 发布进度状态追踪条 (当前 Stage 4 待生产部署) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">发布执行状态追踪</h2>
<p class="section-subtitle">开发、测试与验证均已圆满收官,当前进入生产部署待执行阶段。</p>
</div>
<a href="release-status.html" class="btn btn-secondary" style="font-size: 0.82rem; padding: 0.35rem 0.85rem;">查看发布看板 &rarr;</a>
</div>
<div class="stage-progress-bar">
<div class="stage-item completed">
<div style="font-size: 0.72rem; color: var(--pass-color); font-weight: 700; text-transform: uppercase;">Stage 1 · COMPLETED</div>
<div class="stage-title">代码与接口开发</div>
<div class="stage-desc">核心业务与 V2 接口全部冻结完成。</div>
</div>
<div class="stage-item completed">
<div style="font-size: 0.72rem; color: var(--pass-color); font-weight: 700; text-transform: uppercase;">Stage 2 · COMPLETED</div>
<div class="stage-title">全层级质量验证</div>
<div class="stage-desc">154个单元测试及6大核心场景门禁均通过。</div>
</div>
<div class="stage-item completed">
<div style="font-size: 0.72rem; color: var(--pass-color); font-weight: 700; text-transform: uppercase;">Stage 3 · COMPLETED</div>
<div class="stage-title">浏览器端到端验收</div>
<div class="stage-desc">真实浏览器端到端交互验收通过,无控制台阻断错误。</div>
</div>
<div class="stage-item current">
<div style="font-size: 0.72rem; color: var(--pending-color); font-weight: 700; text-transform: uppercase;">Stage 4 · PENDING</div>
<div class="stage-title">正式生产部署</div>
<div class="stage-desc">执行 001~003 数据库迁移增量脚本与环境烟测。</div>
</div>
</div>
</section>
<!-- 7. 进入详细页面快捷入口 -->
<section class="content-section" style="margin-bottom: 0;">
<div class="section-header">
<div>
<h2 class="section-title">系统详细交付文档导航</h2>
<p class="section-subtitle">点击直达对应交付模块,查看架构拓扑、数据实体设计、测试事实与部署细节。</p>
</div>
</div>
<div class="card-grid-3">
<div class="standard-card">
<h3 class="card-title" style="margin-bottom: 0.5rem;"><a href="business-flow.html">业务主链与状态机 &rarr;</a></h3>
<p class="card-body-text">深入了解培训计划、学员参训、现场报到确认及考勤状态机流转规则与业务硬阻断。</p>
</div>
<div class="standard-card">
<h3 class="card-title" style="margin-bottom: 0.5rem;"><a href="architecture.html">系统架构与技术栈 &rarr;</a></h3>
<p class="card-body-text">查看分层架构图、数据库交互、无状态安全鉴权及外部电子班牌适配器接口设计。</p>
</div>
<div class="standard-card">
<h3 class="card-title" style="margin-bottom: 0.5rem;"><a href="testing.html">质量门禁与场景测试 &rarr;</a></h3>
<p class="card-body-text">查阅真实 SCENARIO-01~06 自动化集成测试详情、数据库只读断言与浏览器实测证据。</p>
</div>
</div>
</section>
</main>
<!-- 页脚 -->
<footer class="site-footer">
<p>RailwaySystem 铁路智慧培训管理系统 · 交付候选版 (Final Candidate)</p>
<p style="margin-top: 0.35rem; color: var(--text-muted);">
基于真实代码与测试契约自动生成 · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/01-project-overview.md" target="_blank" rel="noopener noreferrer">查阅项目总览手册</a>
</p>
</footer>
<script src="assets/docs.js"></script>
</body>
</html>
+563
View File
@@ -0,0 +1,563 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>业务模块清单 (14大模块) - RailwaySystem 铁路智慧培训管理系统</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%231d4ed8' d='M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4z'/></svg>">
<link rel="stylesheet" href="assets/docs.css">
<style>
/* 模块分类卡片样式 */
.module-group-section {
margin-bottom: 2.75rem;
}
.group-header-badge {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-size: 0.78rem;
font-weight: 700;
padding: 0.2rem 0.6rem;
border-radius: var(--radius-sm);
margin-bottom: 0.5rem;
}
.module-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
gap: 1.25rem;
margin-top: 1rem;
}
@media (max-width: 768px) {
.module-grid { grid-template-columns: 1fr; }
}
.module-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.25rem 1.35rem;
box-shadow: var(--shadow-card);
transition: border-color 0.15s ease, box-shadow 0.15s ease;
display: flex;
flex-direction: column;
}
.module-card:hover {
border-color: var(--border-medium);
box-shadow: var(--shadow-card-hover);
}
.module-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 0.65rem;
}
.module-title-box {
display: flex;
align-items: center;
gap: 0.65rem;
}
.module-icon {
width: 38px;
height: 38px;
border-radius: var(--radius-sm);
background: var(--rail-blue-subtle);
color: var(--rail-blue);
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 1.1rem;
flex-shrink: 0;
}
.module-name-zh {
font-size: 1.05rem;
font-weight: 600;
color: var(--navy-900);
}
.module-name-en {
font-family: var(--font-mono);
font-size: 0.75rem;
color: var(--text-muted);
}
.module-summary {
font-size: 0.88rem;
color: var(--text-secondary);
line-height: 1.65;
margin-bottom: 0.85rem;
flex: 1;
}
/* 规则详情折叠器 (HTML5 details) */
details.rule-collapse {
border-top: 1px dashed var(--border-light);
padding-top: 0.65rem;
margin-top: auto;
}
details.rule-collapse summary {
cursor: pointer;
font-size: 0.8rem;
font-weight: 600;
color: var(--rail-blue);
user-select: none;
outline: none;
list-style: none;
display: flex;
align-items: center;
justify-content: space-between;
}
details.rule-collapse summary::-webkit-details-marker {
display: none;
}
details.rule-collapse summary::after {
content: '▾';
font-size: 0.9rem;
transition: transform 0.2s ease;
}
details.rule-collapse[open] summary::after {
transform: rotate(180deg);
}
.rule-content {
padding: 0.75rem 0 0.25rem;
font-size: 0.82rem;
line-height: 1.7;
color: var(--text-secondary);
}
.rule-item {
margin-bottom: 0.4rem;
}
.rule-item strong {
color: var(--navy-900);
}
</style>
</head>
<body>
<!-- 顶部主导航 -->
<nav class="navbar">
<div class="nav-brand-wrap">
<a href="index.html" class="nav-brand">
<svg viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></svg>
<div>
<div class="brand-title">RailwaySystem</div>
<div class="brand-sub">铁路智慧培训管理系统</div>
</div>
</a>
<span class="brand-pill">Final Candidate · 待正式部署</span>
</div>
<ul class="nav-menu">
<li><a href="index.html" class="nav-link">首页</a></li>
<li><a href="business-flow.html" class="nav-link">业务</a></li>
<li><a href="architecture.html" class="nav-link">系统</a></li>
<li><a href="testing.html" class="nav-link">质量</a></li>
<li><a href="release-status.html" class="nav-link">发布</a></li>
<li><a href="modules.html" class="nav-link active">14大业务模块清单</a></li>
<li><a href="data-model.html" class="nav-link">实体关系模型(ER)</a></li>
<li><a href="deployment.html" class="nav-link">部署拓扑与脚本Delta</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer" class="nav-handbook-link">&gt; 查阅部署发布手册</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/README.md" target="_blank" rel="noopener noreferrer" class="nav-back-link">&larr; 文档中心</a></li>
</ul>
</nav>
<!-- 页面主体容器 -->
<main class="page-container">
<header class="page-hero">
<div class="hero-pretitle">Functional Domain Architecture</div>
<h1 class="hero-title-main">14 大核心业务模块清单</h1>
<p class="hero-lead-text">
按照能力域严格分为培训资源、教务编排、现场执行与数据分析 4 大分组。默认仅呈现模块标识与一句话作用,点击可展开详细业务规则与物理表。
</p>
</header>
<!-- 分组 1: 培训资源 (6个模块) -->
<section class="module-group-section" id="group-resource">
<div class="section-header">
<div>
<span class="group-header-badge" style="background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe;">Domain 1</span>
<h2 class="section-title">培训资源域 (Master Data)</h2>
<p class="section-subtitle">支撑智慧培训基地的基础人、货、场与生活主数据设施。</p>
</div>
<span class="badge badge-pass">6 模块全部实现</span>
</div>
<div class="module-grid">
<!-- 1. Teacher -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">师</div>
<div>
<div class="module-name-zh">教师管理</div>
<div class="module-name-en">Teacher</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">维护培训师资档案、所属专业领域、职称与联系方式,支撑课程主讲人指派。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>唯一性规则</strong>:教师手机号全局唯一,重复录入强行拦截 (40001)。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_teacher</code> (主键 <code>t_id</code>)</div>
<div class="rule-item"><strong>实测结论</strong>:页面访问、列表查询、手机号防重复验证通过。</div>
</div>
</details>
</div>
<!-- 2. Student -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">学</div>
<div>
<div class="module-name-zh">学员档案</div>
<div class="module-name-en">Student</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">统一管理铁路职工参训人员主档,维护所属铁路局、站段、工种及敏感身份证安全脱敏。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>脱敏与安全</strong>:身份证散列存盘,对外接口仅返回末4位脱敏掩码,杜绝明文暴露。</div>
<div class="rule-item"><strong>主档状态</strong>:维护 <code>status=1:正常</code> 与 <code>status=0:停用</code>,停用学员严禁报名。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_student</code> (主键 <code>s_id</code> 为 32 位 UUID)</div>
</div>
</details>
</div>
<!-- 3. Course -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">课</div>
<div>
<div class="module-name-zh">课程管理</div>
<div class="module-name-en">Course</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">标准化课程库管理,定义课程编码、理论与实操学时、课程类别及教材大纲。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>业务约束</strong>:课程编码全局唯一;学时 <code>c_duration</code> 必须大于 0。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_course</code> (主键 <code>c_id</code>)</div>
<div class="rule-item"><strong>实测结论</strong>:课程建档、课时汇总与状态维护通过。</div>
</div>
</details>
</div>
<!-- 4. Classroom -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">室</div>
<div>
<div class="module-name-zh">理论教室</div>
<div class="module-name-en">Classroom</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">管理基地理论教学教室,设定容纳人数、楼层门牌号并关联挂载电子班牌终端。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>容量约束</strong>:容量非空且大于 0,作为排课选址基础参考。</div>
<div class="rule-item"><strong>班牌绑定</strong>:支持绑定 0/1/N 块电子班牌,详情接口实时映射。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_classroom_info</code> (主键 <code>class_room_id</code>)</div>
</div>
</details>
</div>
<!-- 5. Site -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">场</div>
<div>
<div class="module-name-zh">实训场地</div>
<div class="module-name-en">Training Site</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">管理机务、电务、工务、供电等室外实训演练基地,支持大型特种设备实训排产。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>互斥规则</strong>:在排课中与理论教室满足严格 XOR 互斥逻辑。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_training_site</code> (主键 <code>site_id</code> 为 32 位 UUID)</div>
<div class="rule-item"><strong>实测结论</strong>:场地创建、容量校验与排课占用预警验证通过。</div>
</div>
</details>
</div>
<!-- 6. Dormitory -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">宿</div>
<div>
<div class="module-name-zh">后勤宿舍</div>
<div class="module-name-en">Dormitory</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">提供基地学员宿舍楼栋、房号与床位分配管理,联动学员报名中的住宿需求。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>业务联动</strong>:由报名表 <code>accommodation_required = 1</code> 驱动床位分配。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_dormitory_info</code> (主键 <code>dorm_id</code>), <code>train_accommodation</code></div>
<div class="rule-item"><strong>实测结论</strong>:宿舍主数据维护及入住状态管理正常。</div>
</div>
</details>
</div>
</div>
</section>
<!-- 分组 2: 教务编排 (4个模块) -->
<section class="module-group-section" id="group-scheduling">
<div class="section-header">
<div>
<span class="group-header-badge" style="background: #f0fdf4; color: #166534; border: 1px solid #bbf7d0;">Domain 2</span>
<h2 class="section-title">教务编排域 (Scheduling Core)</h2>
<p class="section-subtitle">负责计划拟定、课程师资绑定、参训名单导入及四维排课防重叠调度。</p>
</div>
<span class="badge badge-pass">4 模块全部实现</span>
</div>
<div class="module-grid">
<!-- 7. Plan -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">计</div>
<div>
<div class="module-name-zh">培训计划</div>
<div class="module-name-en">Training Plan</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">拟定培训班方案,维护班级周期、报到截止日、计划招生人数上限及全生命周期状态流转。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>状态流转</strong>:<code>0:草稿</code> &rarr; <code>1:进行中</code> &rarr; <code>2:已结束</code>。</div>
<div class="rule-item"><strong>结训保护</strong>:结训时 Plan 置为 2,锁定排课变更,批量完成活动学员。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_class_plan</code> (主键 <code>plan_id</code> 32 位 UUID)</div>
</div>
</details>
</div>
<!-- 8. PlanCourse -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">纲</div>
<div>
<div class="module-name-zh">计划课程</div>
<div class="module-name-en">Plan Course</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">构建培训计划与课程的关联映射,指派授课教师,自动汇总开班总学时。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>关联一致性</strong>:作为排课 Lesson 的外键依赖,禁止跨计划引用。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_plan_course</code> (主键 <code>plan_course_id</code>)</div>
<div class="rule-item"><strong>实测结论</strong>:课程批量绑定与学时自动联动通过。</div>
</div>
</details>
</div>
<!-- 9. Enrollment -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">名</div>
<div>
<div class="module-name-zh">参训管理</div>
<div class="module-name-en">Enrollment</div>
</div>
</div>
<span class="badge badge-pass">IMPLEMENTED</span>
</div>
<p class="module-summary">管理学员入班名单、招生容量防超额守卫,并维护学员在班级的参训状态流转。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>双重硬拦截</strong>:重复报名拦截 (40030);招生容量上限拦截 (40031)。</div>
<div class="rule-item"><strong>参训状态机</strong>:<code>0:待报到</code> &rarr; <code>1:已报到</code> &rarr; <code>2:请假</code> &rarr; <code>3:退训</code> &rarr; <code>4:已完成</code>。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_enrollment</code> (主键 <code>enrollment_id</code>)</div>
</div>
</details>
</div>
<!-- 10. Scheduling -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">排</div>
<div>
<div class="module-name-zh">排课调度</div>
<div class="module-name-en">Scheduling</div>
</div>
</div>
<span class="badge badge-pass">VERIFIED</span>
</div>
<p class="module-summary">编制每日具体课次,集成四维冲突预检机制,输出可视化聚合日课表视图。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>四维冲突预检</strong>:教师冲突硬检;教室/场地/班级重叠 Warning 提示并允许确认保存。</div>
<div class="rule-item"><strong>合规要求</strong>:严格禁止任何 force / override 违规旁路参数。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_lesson</code> (主键 <code>lesson_id</code>)</div>
</div>
</details>
</div>
</div>
</section>
<!-- 分组 3: 现场执行 (3个模块) -->
<section class="module-group-section" id="group-execution">
<div class="section-header">
<div>
<span class="group-header-badge" style="background: #fefce8; color: #854d0e; border: 1px solid #fef08a;">Domain 3</span>
<h2 class="section-title">现场执行域 (Execution & IoT)</h2>
<p class="section-subtitle">支撑学员现场核验报到、课堂考勤打卡留痕与电子班牌终端信息交互。</p>
</div>
<span class="badge badge-pass">3 模块全部通过验证</span>
</div>
<div class="module-grid">
<!-- 11. Report -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">到</div>
<div>
<div class="module-name-zh">开班报到</div>
<div class="module-name-en">Class Report</div>
</div>
</div>
<span class="badge badge-pass">VERIFIED</span>
</div>
<p class="module-summary">学员到校开班报到身份核验,强事务联动流转报名状态至已报到,防重复报到。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>强事务联动</strong>:报到写入 <code>train_class_report</code>,同时联动更新 <code>enrollment_status = 1</code> 且记录 <code>join_time</code>。</div>
<div class="rule-item"><strong>重复报到防范</strong>:已报到学员再次报到触发拦截 (40050)。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_class_report</code> (主键 <code>report_id</code>)</div>
</div>
</details>
</div>
<!-- 12. Attendance -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">勤</div>
<div>
<div class="module-name-zh">课次考勤</div>
<div class="module-name-en">Attendance</div>
</div>
</div>
<span class="badge badge-pass">VERIFIED</span>
</div>
<p class="module-summary">处理课次签到与签退打卡,保证首次打卡时间幂等性,支持人工代签审计留痕。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>打卡幂等性</strong>:重复调用签到或签退时,严格保持首次 <code>signInTime/signOutTime</code> 不变。</div>
<div class="rule-item"><strong>人工代签留痕</strong>:后台调整考勤自动置 <code>manual_flag = 1</code>,记录调整人与备注。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_student_checkin</code> (主键 <code>checkin_id</code>)</div>
</div>
</details>
</div>
<!-- 13. Board -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon">牌</div>
<div>
<div class="module-name-zh">电子班牌</div>
<div class="module-name-en">Electronic Board</div>
</div>
</div>
<span class="badge badge-pass">VERIFIED</span>
</div>
<p class="module-summary">管理挂载在教室的电子显示终端,在课表中提供智能降级映射与物联页面呈现。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>课表降级规则</strong>:0 块板为 null,恰好 1 块板为对应 SN,>1 块板降级为 null。</div>
<div class="rule-item"><strong>前端路由</strong>:前端正式路由为 <code>/equip/board</code>,对应后端接口 <code>/train/board</code>。</div>
<div class="rule-item"><strong>物理表名</strong>:<code>train_electronic_board</code> (主键 <code>board_id</code> 32 位 UUID)</div>
</div>
</details>
</div>
</div>
</section>
<!-- 分组 4: 统计分析 (1个模块/4个子视图) -->
<section class="module-group-section" id="group-analytics" style="margin-bottom: 0;">
<div class="section-header">
<div>
<span class="group-header-badge" style="background: #fdf4ff; color: #86198f; border: 1px solid #f5d0fe;">Domain 4</span>
<h2 class="section-title">数据分析域 (Analytics & Reports)</h2>
<p class="section-subtitle">聚合教务执行过程数据,提供只读统计报表与画像导出,保持架构隔离。</p>
</div>
<span class="badge badge-pass">V2 READ MODEL · PASS</span>
</div>
<div class="module-grid">
<!-- 14. Analytics -->
<div class="module-card">
<div class="module-header">
<div class="module-title-box">
<div class="module-icon" style="background: #fdf4ff; color: #86198f;">析</div>
<div>
<div class="module-name-zh">统计分析与报表</div>
<div class="module-name-en">Analytics</div>
</div>
</div>
<span class="badge badge-pass">V2 READ MODEL · PASS</span>
</div>
<p class="module-summary">涵盖报到率统计、考勤打卡统计、学员课时完成度及综合画像等只读报表展示与数据导出。</p>
<details class="rule-collapse">
<summary>查看详细规则与模型</summary>
<div class="rule-content">
<div class="rule-item"><strong>架构隔离</strong>:当前版本已完成 V2 Read Model 接入,提供稳定的只读查询与导出能力,保持数据库单向读取。</div>
<div class="rule-item"><strong>涵盖视图</strong>:Report 报到报表、Checkin 考勤报表、Duration 学时统计、Portrait 画像表 4 个视图均通过验收。</div>
<div class="rule-item"><strong>演进规划</strong>:高级画像算法模型与多维统计扩展标为 <code>RESERVED / FUTURE EXTENSION</code>。</div>
</div>
</details>
</div>
</div>
</section>
</main>
<!-- 页脚 -->
<footer class="site-footer">
<p>RailwaySystem 铁路智慧培训管理系统 · 交付候选版 (Final Candidate)</p>
<p style="margin-top: 0.35rem; color: var(--text-muted);">
模块架构指南 · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/05-module-guide.md" target="_blank" rel="noopener noreferrer">查阅模块详细指南手册</a>
</p>
</footer>
<script src="assets/docs.js"></script>
</body>
</html>
+290
View File
@@ -0,0 +1,290 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>发版进度看板与门禁状态 - RailwaySystem 铁路智慧培训管理系统</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%231d4ed8' d='M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4z'/></svg>">
<link rel="stylesheet" href="assets/docs.css">
<style>
/* 发版进度专属样式 */
.release-meta-strip {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.25rem 1.5rem;
margin-bottom: 2rem;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 1rem;
box-shadow: var(--shadow-card);
}
</style>
</head>
<body>
<!-- 顶部主导航 -->
<nav class="navbar">
<div class="nav-brand-wrap">
<a href="index.html" class="nav-brand">
<svg viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></svg>
<div>
<div class="brand-title">RailwaySystem</div>
<div class="brand-sub">铁路智慧培训管理系统</div>
</div>
</a>
<span class="brand-pill">Final Candidate · 待正式部署</span>
</div>
<ul class="nav-menu">
<li><a href="index.html" class="nav-link">首页</a></li>
<li><a href="business-flow.html" class="nav-link">业务</a></li>
<li><a href="architecture.html" class="nav-link">系统</a></li>
<li><a href="testing.html" class="nav-link">质量</a></li>
<li><a href="release-status.html" class="nav-link active">发布</a></li>
<li><a href="modules.html" class="nav-link">14大业务模块清单</a></li>
<li><a href="data-model.html" class="nav-link">实体关系模型(ER)</a></li>
<li><a href="deployment.html" class="nav-link">部署拓扑与脚本Delta</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer" class="nav-handbook-link">&gt; 查阅部署发布手册</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/README.md" target="_blank" rel="noopener noreferrer" class="nav-back-link">&larr; 文档中心</a></li>
</ul>
</nav>
<!-- 页面主体容器 -->
<main class="page-container">
<header class="page-hero">
<div class="hero-pretitle">Delivery Pipeline & Release Stepper</div>
<h1 class="hero-title-main">发版进度与门禁流水线看板</h1>
<p class="hero-lead-text">
采用清晰直观的发布进度步进器 (Progress Stepper) 替代传统大表格,准确呈现从代码冻结、测试门禁、文档就绪到待执行生产部署的完整阶段状态。
</p>
</header>
<!-- 交付版本元数据条 -->
<div class="release-meta-strip">
<div style="display: flex; align-items: center; gap: 0.75rem;">
<span class="badge badge-pass">交付候选阶段</span>
<span style="font-size: 0.95rem; font-weight: 700; color: var(--navy-900);">Final Candidate 交付版本</span>
</div>
<div style="display: flex; flex-wrap: wrap; gap: 1.5rem; font-size: 0.84rem; color: var(--text-muted);">
<span>基线 HEAD:<strong style="color: var(--navy-800); font-family: var(--font-mono);">5a49b2e2</strong></span>
<span>代码冻结:<strong style="color: var(--navy-800);">已完成 (FROZEN)</strong></span>
<span>质量门禁:<strong style="color: var(--pass-color);">100% 通过</strong></span>
<span>生产部署:<strong style="color: var(--pending-color);">待执行 (PENDING)</strong></span>
</div>
</div>
<!-- 核心发版步进器 (Progress Stepper) -->
<section class="stepper-container">
<div class="stepper-list">
<!-- Step 1: Code Freeze -->
<div class="step-row done">
<div class="step-indicator">
<div class="step-circle">✓</div>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">1. 代码与接口契约冻结 (Code Freeze)</div>
<span class="badge badge-pass">DONE</span>
</div>
<p class="step-desc">
后端 ruoyi-train 业务主干、前端 Vue 路由及 docs/api-v2 接口契约全面封版冻结,基线锁定于 commit <code>5a49b2e2</code>。
</p>
</div>
</div>
<!-- Step 2: Unit Test -->
<div class="step-row done">
<div class="step-indicator">
<div class="step-circle">✓</div>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">2. 后端单元与契约测试门禁 (Unit & Contract Test)</div>
<span class="badge badge-pass">DONE</span>
</div>
<p class="step-desc">
执行 <code>mvn test</code> 极速离线门禁,154 个测试用例全部一次性通过 (0 Failures, 0 Errors, 0 Skipped)。
</p>
</div>
</div>
<!-- Step 3: Integration Test -->
<div class="step-row done">
<div class="step-indicator">
<div class="step-circle">✓</div>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">3. 核心业务场景端到端集成测试 (Integration Scenarios)</div>
<span class="badge badge-pass">DONE</span>
</div>
<p class="step-desc">
运行 <code>scripts/qa/core-business-scenario-runner.py</code>,完成 110 次真实 HTTP 请求,SC-01~06 六大场景全部 PASS,HTTP 500 = 0,Kingbase 11项物理断言全部 PASS,自动化残留数据归零 (Residue = 0)。
</p>
</div>
</div>
<!-- Step 4: Browser Acceptance -->
<div class="step-row done">
<div class="step-indicator">
<div class="step-circle">✓</div>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">4. 浏览器端到端真实交互验收 (Browser Acceptance)</div>
<span class="badge badge-pass">DONE</span>
</div>
<p class="step-desc">
基于真实浏览器端到端实测,覆盖基础主数据录入、排课冲突 Warning 取消与确认保存、报到确认及 Web 班牌路由,控制台阻断错误为 0,实测数据保留供合规审计 (KEEP_FOR_AUDIT)。
</p>
</div>
</div>
<!-- Step 5: Swagger Platform -->
<div class="step-row done">
<div class="step-indicator">
<div class="step-circle">✓</div>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">5. 在线接口文档平台集成 (Swagger Platform)</div>
<span class="badge badge-pass">DONE</span>
</div>
<p class="step-desc">
集成入口位于「系统工具 &rarr; 系统接口」,<code>v3/api-docs</code> 与 <code>swagger-resources</code> 均正常响应 HTTP 200,支持在线调试。
</p>
</div>
</div>
<!-- Step 6: Documentation Center -->
<div class="step-row in-progress">
<div class="step-indicator">
<div class="step-circle">6</div>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">6. 交付文档体系与可视化门户重构 (Documentation)</div>
<span class="badge badge-warning">IN PROGRESS</span>
</div>
<p class="step-desc">
完成内容事实核准与 8 大可视化 HTML 门户重构,严格消除过度推断与技术扩写,构建离线可用高可读性交付系统。
</p>
</div>
</div>
<!-- Step 7: Formal Deployment -->
<div class="step-row pending">
<div class="step-indicator">
<div class="step-circle">7</div>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">7. 正式生产环境部署执行 (Formal Deployment)</div>
<span class="badge badge-neutral">PENDING</span>
</div>
<p class="step-desc">
在目标生产环境按序执行 3 个增量数据库迁移脚本 (001~003),历史业务字典 007_dicts.sql 严禁执行;启动前端 8082 与后端 8092 生产进程。
</p>
</div>
</div>
<!-- Step 8: Deployment Smoke -->
<div class="step-row pending">
<div class="step-indicator">
<div class="step-circle">8</div>
<div class="step-line"></div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">8. 生产环境自动化冒烟验证 (Deployment Smoke)</div>
<span class="badge badge-neutral">PENDING</span>
</div>
<p class="step-desc">
服务启动后对 <code>GET /login</code>、教师列表与课表查询进行线上存活性健康检查与读写冒烟校验。
</p>
</div>
</div>
<!-- Step 9: Final Release -->
<div class="step-row pending">
<div class="step-indicator">
<div class="step-circle">9</div>
</div>
<div class="step-content">
<div class="step-header-line">
<div class="step-name">9. 最终交付签收与上线归档 (Final Release)</div>
<span class="badge badge-neutral">PENDING</span>
</div>
<p class="step-desc">
完成各方验收签字与资产封存归档,正式进入生产平稳运行维护阶段。
</p>
</div>
</div>
</div>
</section>
<!-- 阶段物料与报告清单 -->
<section class="content-section" style="margin-bottom: 0;">
<div class="section-header">
<div>
<h2 class="section-title">阶段交付物与验证报告索引</h2>
<p class="section-subtitle">所有阶段均有完整的可追溯报告文件支持,严格保证过程合规。</p>
</div>
</div>
<div class="card-grid-3">
<div class="standard-card">
<div class="card-top">
<h3 class="card-title" style="font-size: 0.98rem;">综合测试报告</h3>
<span class="badge badge-pass">PASS</span>
</div>
<p class="card-body-text">详细记录 154 个单元用例、6 大场景集成及 11 项物理落库断言的执行结果与证据。</p>
<a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/reports/final-test-report.md" target="_blank" rel="noopener noreferrer">查阅报告 (final-test-report.md) &rarr;</a>
</div>
<div class="standard-card">
<div class="card-top">
<h3 class="card-title" style="font-size: 0.98rem;">浏览器端到端验收报告</h3>
<span class="badge badge-pass">PASS</span>
</div>
<p class="card-body-text">记录真实浏览器端到端模拟教务员的全流程交互、表单提交、弹窗确认与控制台检查情况。</p>
<a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/reports/browser-acceptance-report.md" target="_blank" rel="noopener noreferrer">查阅报告 (browser-acceptance.md) &rarr;</a>
</div>
<div class="standard-card">
<div class="card-top">
<h3 class="card-title" style="font-size: 0.98rem;">部署与发版说明</h3>
<span class="badge badge-neutral">READY</span>
</div>
<p class="card-body-text">提供生产环境前置条件预检、3 个必跑数据库增量脚本说明与环境冒烟指南。</p>
<a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/reports/release-notes.md" target="_blank" rel="noopener noreferrer">查阅发版说明 (release-notes.md) &rarr;</a>
</div>
</div>
</section>
</main>
<!-- 页脚 -->
<footer class="site-footer">
<p>RailwaySystem 铁路智慧培训管理系统 · 交付候选版 (Final Candidate)</p>
<p style="margin-top: 0.35rem; color: var(--text-muted);">
发版状态与交付基准 · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/reports/release-notes.md" target="_blank" rel="noopener noreferrer">查阅发版说明</a>
</p>
</footer>
<script src="assets/docs.js"></script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 KiB

+636
View File
@@ -0,0 +1,636 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>质量与验证体系 - RailwaySystem 铁路智慧培训管理系统</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%231d4ed8' d='M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4z'/></svg>">
<link rel="stylesheet" href="assets/docs.css">
<style>
/* 测试金字塔层级展示 */
.pyramid-wrap {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-lg);
padding: 2rem;
box-shadow: var(--shadow-card);
margin-bottom: 2.5rem;
}
.pyramid-layers {
display: flex;
flex-direction: column;
gap: 0.75rem;
max-width: 860px;
margin: 1.5rem auto 0;
}
.pyramid-tier {
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.pyramid-tier:hover {
transform: translateX(4px);
box-shadow: var(--shadow-card-hover);
}
.tier-4 { background: #eff6ff; border-color: #bfdbfe; margin: 0 12%; }
.tier-3 { background: #f0fdf4; border-color: #bbf7d0; margin: 0 8%; }
.tier-2 { background: #fefce8; border-color: #fef08a; margin: 0 4%; }
.tier-1 { background: #f8fafc; border-color: #e2e8f0; margin: 0 0; }
.tier-info h3 {
font-size: 0.98rem;
font-weight: 700;
color: var(--navy-900);
display: flex;
align-items: center;
gap: 0.5rem;
}
.tier-info p {
font-size: 0.82rem;
color: var(--text-secondary);
margin-top: 0.2rem;
}
/* Scenario 卡片网格 */
.scenario-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
}
@media (max-width: 900px) {
.scenario-grid { grid-template-columns: 1fr; }
.tier-4, .tier-3, .tier-2, .tier-1 { margin: 0; }
}
.scenario-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.5rem;
box-shadow: var(--shadow-card);
display: flex;
flex-direction: column;
}
.scenario-card:hover {
border-color: var(--border-medium);
box-shadow: var(--shadow-card-hover);
}
.scenario-point-list {
list-style: none;
margin: 0.85rem 0;
flex: 1;
}
.scenario-point-item {
display: flex;
align-items: flex-start;
gap: 0.5rem;
padding: 0.35rem 0;
font-size: 0.85rem;
color: var(--text-secondary);
line-height: 1.6;
}
.scenario-point-item::before {
content: '✓';
color: var(--pass-color);
font-weight: 700;
flex-shrink: 0;
}
/* 浏览器验收卡片网格 */
.browser-category-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.25rem;
}
@media (max-width: 960px) {
.browser-category-grid { grid-template-columns: 1fr; }
}
.browser-card {
background: #ffffff;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 1.25rem;
box-shadow: var(--shadow-card);
}
/* Cleanup 口径对比 */
.cleanup-box {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.25rem;
margin-top: 1rem;
}
@media (max-width: 768px) {
.cleanup-box { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<!-- 顶部主导航 -->
<nav class="navbar">
<div class="nav-brand-wrap">
<a href="index.html" class="nav-brand">
<svg viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm1.5-6H6V6h12v5z"/></svg>
<div>
<div class="brand-title">RailwaySystem</div>
<div class="brand-sub">铁路智慧培训管理系统</div>
</div>
</a>
<span class="brand-pill">Final Candidate · 待正式部署</span>
</div>
<ul class="nav-menu">
<li><a href="index.html" class="nav-link">首页</a></li>
<li><a href="business-flow.html" class="nav-link">业务</a></li>
<li><a href="architecture.html" class="nav-link">系统</a></li>
<li><a href="testing.html" class="nav-link active">质量</a></li>
<li><a href="release-status.html" class="nav-link">发布</a></li>
<li><a href="modules.html" class="nav-link">14大业务模块清单</a></li>
<li><a href="data-model.html" class="nav-link">实体关系模型(ER)</a></li>
<li><a href="deployment.html" class="nav-link">部署拓扑与脚本Delta</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/handbook/08-deployment-and-release.md" target="_blank" rel="noopener noreferrer" class="nav-handbook-link">&gt; 查阅部署发布手册</a></li>
<li><a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/README.md" target="_blank" rel="noopener noreferrer" class="nav-back-link">&larr; 文档中心</a></li>
</ul>
</nav>
<!-- 页面主体容器 -->
<main class="page-container">
<header class="page-hero">
<div class="hero-pretitle">Quality Assurance & Verification</div>
<h1 class="hero-title-main">质量指标与全层级验证矩阵</h1>
<p class="hero-lead-text">
严格基于 <code>scripts/qa/core-business-scenario-runner.py</code>、<code>docs/_meta/core-business-test-matrix.md</code> 及真实浏览器端到端验收报告生成。杜绝任何未经代码或测试证实的扩写。
</p>
</header>
<!-- 1. 顶部真实指标 Dashboard (7个精准真实KPI) -->
<div class="kpi-dashboard">
<div class="kpi-card kpi-pass">
<div class="kpi-value">154 / 154</div>
<div class="kpi-label">后端单元与契约测试</div>
<div class="kpi-sub">Maven Surefire · ALL PASS</div>
</div>
<div class="kpi-card kpi-pass">
<div class="kpi-value">6 / 6</div>
<div class="kpi-label">核心业务场景套件</div>
<div class="kpi-sub">SC-01 ~ SC-06 全部通过</div>
</div>
<div class="kpi-card kpi-info">
<div class="kpi-value">110</div>
<div class="kpi-label">真实 HTTP API 探测</div>
<div class="kpi-sub">自动化请求全量记录</div>
</div>
<div class="kpi-card kpi-pass">
<div class="kpi-value">0</div>
<div class="kpi-label">服务端 500 异常</div>
<div class="kpi-sub">HTTP 500 Count = 0</div>
</div>
<div class="kpi-card kpi-pass">
<div class="kpi-value">11 / 11</div>
<div class="kpi-label">Kingbase 持久化断言</div>
<div class="kpi-sub">实体与外键完整性无孤儿</div>
</div>
<div class="kpi-card kpi-pass">
<div class="kpi-value">PASS</div>
<div class="kpi-label">浏览器真实 UI 验收</div>
<div class="kpi-sub">Final Browser Acceptance</div>
</div>
<div class="kpi-card kpi-pass">
<div class="kpi-value">0</div>
<div class="kpi-label">控制台阻断错误</div>
<div class="kpi-sub">Console Error = 0</div>
</div>
</div>
<!-- 2. 测试金字塔 (Testing Pyramid) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">分层质量防御金字塔</h2>
<p class="section-subtitle">从离线单元逻辑、跨模块端到端集成、物理数据库落库校验到浏览器界面交互的四级防护体系。</p>
</div>
</div>
<div class="pyramid-wrap">
<div class="pyramid-layers">
<!-- 顶层: 浏览器验收 -->
<div class="pyramid-tier tier-4">
<div class="tier-info">
<h3><span>第 4 层:真实浏览器端到端验收 (Final Browser Acceptance)</span> <span class="badge badge-pass">PASS</span></h3>
<p>真实浏览器端到端交互:登录、表单建档、计划排课、冲突 Warning 弹窗确认、报到确认及 Web 班牌。</p>
</div>
<span class="card-code">Console Error: 0</span>
</div>
<!-- 第 3 层: 数据库持久化只读断言 -->
<div class="pyramid-tier tier-3">
<div class="tier-info">
<h3><span>第 3 层:Kingbase 数据库落库只读断言 (DB Assertions)</span> <span class="badge badge-pass">PASS</span></h3>
<p>11 项物理 SQL 只读断言:外键无孤儿记录、场地 XOR 互斥、逻辑删除标志、结训完成时间及退训防破坏保护。</p>
</div>
<span class="card-code">11 / 11 PASS</span>
</div>
<!-- 第 2 层: 场景集成测试套件 -->
<div class="pyramid-tier tier-2">
<div class="tier-info">
<h3><span>第 2 层:核心业务场景集成测试 (SC-01 ~ SC-06)</span> <span class="badge badge-pass">PASS</span></h3>
<p>Python 自动化套件覆盖正向全链路、报名拦截、排课预检 Warning/Block、班牌降级、结训事务及报到考勤闭环。</p>
</div>
<span class="card-code">6 / 6 PASS · 110 Requests</span>
</div>
<!-- 底层: 单元与契约测试 -->
<div class="pyramid-tier tier-1">
<div class="tier-info">
<h3><span>第 1 层:后端单元与契约测试 (Backend Unit / Contract)</span> <span class="badge badge-pass">PASS</span></h3>
<p>Maven Surefire 离线测试集,涵盖状态机流转、排课冲突算法、脱敏工具类与权限注解断言。</p>
</div>
<span class="card-code">154 / 154 PASS</span>
</div>
</div>
</div>
</section>
<!-- 3. SC-01 ~ SC-06 场景测试网格 (精简密度:3个关键事实 + 折叠详情) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">核心业务场景集成测试 (SCENARIO-01 ~ SCENARIO-06)</h2>
<p class="section-subtitle">严格对齐 <code>scripts/qa/core-business-scenario-runner.py</code> 真实代码逻辑,默认呈现关键结论,点击可查阅详细步骤。</p>
</div>
</div>
<div class="scenario-grid">
<!-- SC-01 -->
<div class="scenario-card">
<div class="card-top">
<span class="badge badge-pass">SCENARIO-01 · PASS</span>
<span class="card-code">Happy Path</span>
</div>
<h3 class="card-title">完整正向业务闭环全链</h3>
<ul class="scenario-point-list">
<li class="scenario-point-item"><strong>基础资源就绪</strong>:成功创建 Teacher、Course、Classroom 及 TrainingSite。</li>
<li class="scenario-point-item"><strong>开班排课全链</strong>:拟定计划、绑定课程师资、学员入班待报到、课表聚合正常。</li>
<li class="scenario-point-item"><strong>自动结训完成</strong>:计划流转至已结束,活动学员自动结训完成并写入 complete_time。</li>
</ul>
<details class="rule-collapse" style="margin-top: 0.6rem;">
<summary style="font-size: 0.78rem; color: var(--rail-blue); cursor: pointer; font-weight: 600;">展开 15 步详细交互验证</summary>
<div class="rule-content" style="padding-top: 0.4rem; font-size: 0.78rem; color: var(--text-secondary); line-height: 1.6;">
<div>· 开班计划采用 32 位 UUID 主键,初始状态为 0:草稿。</div>
<div>· Timetable 课表接口准确聚合课程名称、授课教师及场地名。</div>
<div>· 调用 <code>POST /train/plans/{id}/complete</code> 强事务批量流转状态。</div>
</div>
</details>
<div class="card-footer-action">
<span class="card-code">覆盖 15 步交互验证</span>
<span class="badge badge-pass">验证通过</span>
</div>
</div>
<!-- SC-02 -->
<div class="scenario-card">
<div class="card-top">
<span class="badge badge-pass">SCENARIO-02 · PASS</span>
<span class="card-code">Enrollment Rules</span>
</div>
<h3 class="card-title">学员报名异常规则与状态区分</h3>
<ul class="scenario-point-list">
<li class="scenario-point-item"><strong>重复报名拦截</strong>:同一计划重复报名触发唯一索引,准确返回 <code>40030</code>。</li>
<li class="scenario-point-item"><strong>容量超限拦截</strong>:入班人数超过计划 <code>recruit_num</code> 上限时拦截返回 <code>40031</code>。</li>
<li class="scenario-point-item"><strong>状态严格区分</strong>:学员主档状态 (正常/停用) 与参训状态机独立解耦流转。</li>
</ul>
<details class="rule-collapse" style="margin-top: 0.6rem;">
<summary style="font-size: 0.78rem; color: var(--rail-blue); cursor: pointer; font-weight: 600;">展开异常校验与拦截细节</summary>
<div class="rule-content" style="padding-top: 0.4rem; font-size: 0.78rem; color: var(--text-secondary); line-height: 1.6;">
<div>· 不存在的非法学员严格拒绝入班。</div>
<div>· 停用学员 (status=0) 严禁报名入班。</div>
<div>· 参训状态机严格维护 0待报到/1已报到/2请假/3退训/4已完成。</div>
</div>
</details>
<div class="card-footer-action">
<span class="card-code">业务错误码精准契约</span>
<span class="badge badge-pass">验证通过</span>
</div>
</div>
<!-- SC-03 -->
<div class="scenario-card">
<div class="card-top">
<span class="badge badge-pass">SCENARIO-03 · PASS</span>
<span class="card-code">Scheduling Engine</span>
</div>
<h3 class="card-title">排课预检 Warning 与 Hard Block 硬阻断</h3>
<ul class="scenario-point-list">
<li class="scenario-point-item"><strong>四维冲突预检</strong>:教师冲突硬阻断;教室/场地/班级重叠返回 Warning 提示。</li>
<li class="scenario-point-item"><strong>非阻断合规</strong>:Warning 级别由教务员确认保存,严格禁止 force 旁路参数。</li>
<li class="scenario-point-item"><strong>互斥与锁定</strong>:场地 XOR 互斥强校验;已结训计划强阻断变更 (<code>40012</code>)。</li>
</ul>
<details class="rule-collapse" style="margin-top: 0.6rem;">
<summary style="font-size: 0.78rem; color: var(--rail-blue); cursor: pointer; font-weight: 600;">展开预检机制与阻断契约</summary>
<div class="rule-content" style="padding-top: 0.4rem; font-size: 0.78rem; color: var(--text-secondary); line-height: 1.6;">
<div>· 时间倒挂阻断:startTime >= endTime 拦截返回 <code>40010</code>。</div>
<div>· 教室与场地同时为空或同时赋值强行拦截,DB 层面 <code>invalid venue XOR = 0</code>。</div>
<div>· 已结训计划禁止排课变更,返回 <code>40012: PLAN_LOCKED</code>。</div>
</div>
</details>
<div class="card-footer-action">
<span class="card-code">无 force 旁路安全参数</span>
<span class="badge badge-pass">验证通过</span>
</div>
</div>
<!-- SC-04 -->
<div class="scenario-card">
<div class="card-top">
<span class="badge badge-pass">SCENARIO-04 · PASS</span>
<span class="card-code">Electronic Board</span>
</div>
<h3 class="card-title">电子班牌绑定与课表降级映射</h3>
<ul class="scenario-point-list">
<li class="scenario-point-item"><strong>UUID 主键规范</strong>:班牌创建自动生成 32 位 UUID,默认在线状态 <code>0</code>。</li>
<li class="scenario-point-item"><strong>课表降级规则</strong>:0 块板为 null,恰好 1 块板返回对应 SN,多块板降级为 null。</li>
<li class="scenario-point-item"><strong>逻辑删除保障</strong>:调用删除置 <code>del_flag='2'</code>,业务接口隔离且物理数据保留。</li>
</ul>
<details class="rule-collapse" style="margin-top: 0.6rem;">
<summary style="font-size: 0.78rem; color: var(--rail-blue); cursor: pointer; font-weight: 600;">展开教室绑定与降级细节</summary>
<div class="rule-content" style="padding-top: 0.4rem; font-size: 0.78rem; color: var(--text-secondary); line-height: 1.6;">
<div>· 教室详情接口:0 块板返回空数组,1 块板返回长度 1,N 块板返回长度 N。</div>
<div>· 课表 boardSn 降级消除多设备展示歧义。</div>
<div>· 物理库 SQL 断言确认 <code>del_flag='2'</code> 匹配成功。</div>
</div>
</details>
<div class="card-footer-action">
<span class="card-code">板号降级语义实测</span>
<span class="badge badge-pass">验证通过</span>
</div>
</div>
<!-- SC-05 -->
<div class="scenario-card">
<div class="card-top">
<span class="badge badge-pass">SCENARIO-05 · PASS</span>
<span class="card-code">Plan Completion</span>
</div>
<h3 class="card-title">结训生命周期与退训学员保护</h3>
<ul class="scenario-point-list">
<li class="scenario-point-item"><strong>计划结训 API</strong>:调用结训接口,Plan 状态成功流转为 <code>2:已结束</code>。</li>
<li class="scenario-point-item"><strong>活动学员结训</strong>:待报到/已报到学员批量流转为 <code>4:已完成</code> 并记录时间。</li>
<li class="scenario-point-item"><strong>退训学员防覆盖</strong>:已退训学员 (<code>status=3</code>) 状态与完成时间受严格保护。</li>
</ul>
<details class="rule-collapse" style="margin-top: 0.6rem;">
<summary style="font-size: 0.78rem; color: var(--rail-blue); cursor: pointer; font-weight: 600;">展开核心不变量与事务保障</summary>
<div class="rule-content" style="padding-top: 0.4rem; font-size: 0.78rem; color: var(--text-secondary); line-height: 1.6;">
<div>· 接口契约:<code>POST /train/plans/{id}/complete</code> 强事务批量更新。</div>
<div>· 核心不变量:已退训记录 complete_time 严格保持为 null。</div>
<div>· 物理 SQL 断言证实历史退训记录零覆盖、零损坏。</div>
</div>
</details>
<div class="card-footer-action">
<span class="card-code">强事务一致性保护</span>
<span class="badge badge-pass">验证通过</span>
</div>
</div>
<!-- SC-06 -->
<div class="scenario-card">
<div class="card-top">
<span class="badge badge-pass">SCENARIO-06 · PASS</span>
<span class="card-code">Report & Attendance</span>
</div>
<h3 class="card-title">现场报到与课堂考勤完整闭环</h3>
<ul class="scenario-point-list">
<li class="scenario-point-item"><strong>现场报到确认</strong>:调用报到接口返回 reportId,参训状态流转为 <code>1:已报到</code>。</li>
<li class="scenario-point-item"><strong>考勤打卡幂等</strong>:首次记录打卡时间,重复签到签退严格保持初次时间不变。</li>
<li class="scenario-point-item"><strong>人工代签留痕</strong>:后台调整考勤自动置 <code>manual_flag = 1</code> 留存审计线索。</li>
</ul>
<details class="rule-collapse" style="margin-top: 0.6rem;">
<summary style="font-size: 0.78rem; color: var(--rail-blue); cursor: pointer; font-weight: 600;">展开接口与重复拦截细节</summary>
<div class="rule-content" style="padding-top: 0.4rem; font-size: 0.78rem; color: var(--text-secondary); line-height: 1.6;">
<div>· 报到确认接口:<code>POST /train/enrollments/{id}/report</code> 强事务写入。</div>
<div>· 重复报到防范:对已报到学员再次报到触发拦截返回 <code>40050</code>。</div>
<div>· 人工考勤接口:<code>PUT /train/attendance/{id}</code> 记录调整人与备注。</div>
</div>
</details>
<div class="card-footer-action">
<span class="card-code">幂等性与审计留痕</span>
<span class="badge badge-pass">验证通过</span>
</div>
</div>
</div>
</section>
<!-- 4. 浏览器端到端验收分类卡片 (真实客观实测事实) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">真实浏览器端到端交互验收 (Final Browser Acceptance)</h2>
<p class="section-subtitle">基于真实运行的端到端验收套件客观记录,据实描述界面打开、列表查询、表单验证与接口调用结果。</p>
</div>
</div>
<div class="browser-category-grid">
<!-- 分类 1: 基础主数据 -->
<div class="browser-card">
<div class="card-top">
<h3 class="card-title" style="font-size: 0.95rem;">基础主数据管理</h3>
<span class="badge badge-pass">PASS</span>
</div>
<ul style="padding-left: 1.15rem; font-size: 0.82rem; line-height: 1.75; color: var(--text-secondary); margin-top: 0.5rem;">
<li><strong>Teacher 教师</strong>:页面成功打开、列表查询、手机号唯一性强校验生效。</li>
<li><strong>Student 学员</strong>:建档表单校验通过,身份证末4位脱敏掩码展示正常。</li>
<li><strong>Classroom 教室</strong>:理论教室容量与状态设置正常渲染。</li>
<li><strong>TrainingSite 场地</strong>:实训场地类型与容量管理正常。</li>
</ul>
</div>
<!-- 分类 2: 核心教务编排 -->
<div class="browser-card">
<div class="card-top">
<h3 class="card-title" style="font-size: 0.95rem;">核心教务编排交互</h3>
<span class="badge badge-pass">PASS</span>
</div>
<ul style="padding-left: 1.15rem; font-size: 0.82rem; line-height: 1.75; color: var(--text-secondary); margin-top: 0.5rem;">
<li><strong>Plan 培训计划</strong>:拟定 32 位 UUID 计划,生命周期初始为草稿。</li>
<li><strong>PlanCourse 课程绑定</strong>:课程选择与师资指派正常,总学时联动累加。</li>
<li><strong>Enrollment 学员报名</strong>:入班名单展示、招生容量上限校验拦截生效。</li>
<li><strong>Timetable 可视化排课</strong>:课表渲染,冲突 Warning 取消/确认入库均正常。</li>
</ul>
</div>
<!-- 分类 3: 现场执行与系统工具 -->
<div class="browser-card">
<div class="card-top">
<h3 class="card-title" style="font-size: 0.95rem;">现场执行与系统工具</h3>
<span class="badge badge-pass">PASS</span>
</div>
<ul style="padding-left: 1.15rem; font-size: 0.82rem; line-height: 1.75; color: var(--text-secondary); margin-top: 0.5rem;">
<li><strong>开班报到确认</strong>:前端菜单「开班签到」,实际调用 <code>/report</code> 接口 200 OK,状态由待报到流转为已报到。</li>
<li><strong>电子班牌终端</strong>:前端物联路由 <code>/equip/board</code> 页面正常渲染。</li>
<li><strong>统计分析 (Analytics)</strong>:报到、考勤、学时、画像报表只读查询正常。</li>
<li><strong>系统接口平台 (Swagger)</strong>:<code>系统工具 → 系统接口</code> 在线渲染,<code>v3/api-docs</code> 返回 200。</li>
</ul>
</div>
</div>
</section>
<!-- 5. 数据清理口径澄清 (严格区分两种测试) -->
<section class="content-section">
<div class="section-header">
<div>
<h2 class="section-title">测试数据清理与审计口径规范</h2>
<p class="section-subtitle">严格区分自动化集成测试与浏览器真实验收的数据保留策略,杜绝将两者混写。</p>
</div>
</div>
<div class="cleanup-box">
<div class="standard-card" style="border-left: 4px solid var(--pass-color);">
<div class="card-top">
<h3 class="card-title" style="font-size: 0.98rem;">自动化集成测试清理 (Integration Cleanup)</h3>
<span class="badge badge-pass">0 残留 (Residue = 0)</span>
</div>
<p class="card-body-text">
<code>core-business-scenario-runner.py</code> 在测试执行过程中自动记录所创建的精确 ID 资源清单 (<code>created-resources.json</code>)。测试断言结束后,严格按逆序调用解绑与清理机制,实现:
<br>· 课次、参训名单、电子班牌精确删除;
<br>· <strong>自动化测试产生的数据残留为 0,保持数据库纯净</strong>。
</p>
</div>
<div class="standard-card" style="border-left: 4px solid var(--pending-color);">
<div class="card-top">
<h3 class="card-title" style="font-size: 0.98rem;">浏览器端到端验收数据 (Browser Acceptance Data)</h3>
<span class="badge badge-pending">保留供审计 (KEEP_FOR_AUDIT)</span>
</div>
<p class="card-body-text">
在最终浏览器真实 UI 验收中创建及流转的测试学员、开班计划、报到流水及代签考勤记录,<strong>显式全量保留在数据库中</strong>,供发布审查、合规抽检及操作日志审计核对,<strong>非 0 残留</strong>。
</p>
</div>
</div>
</section>
<!-- 6. 技术细节折叠手风琴 (Kingbase SQL 物理断言) -->
<section class="content-section" style="margin-bottom: 0;">
<div class="section-header">
<div>
<h2 class="section-title">技术底层细节与物理 SQL 断言 (展开查阅)</h2>
<p class="section-subtitle">由 DbAssertionChecker 直接在 Kingbase 物理库上执行的只读一致性核查。</p>
</div>
</div>
<div class="accordion-item">
<div class="accordion-header">
<div class="accordion-title-group">
<span class="badge badge-pass">11 项 SQL 断言通过</span>
<span style="font-size: 0.95rem; font-weight: 600; color: var(--navy-900);">查看 Kingbase 物理库只读一致性断言清单</span>
</div>
<svg class="accordion-arrow" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>
</div>
<div class="accordion-body">
<div class="data-table-wrap">
<table class="data-table">
<thead>
<tr>
<th>断言项目</th>
<th>验证逻辑与 SQL 条件</th>
<th>预期值</th>
<th>实测结果</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>duplicate enrollment</strong></td>
<td>校验同一计划内是否存在相同学员的重复报名记录</td>
<td><code>0</code></td>
<td><span class="badge badge-pass">PASS (0)</span></td>
</tr>
<tr>
<td><strong>orphan lesson</strong></td>
<td>校验是否存在未关联有效计划课程的孤立课次</td>
<td><code>0</code></td>
<td><span class="badge badge-pass">PASS (0)</span></td>
</tr>
<tr>
<td><strong>orphan enrollment</strong></td>
<td>校验是否存在未关联有效培训计划的孤立报名档案</td>
<td><code>0</code></td>
<td><span class="badge badge-pass">PASS (0)</span></td>
</tr>
<tr>
<td><strong>invalid venue XOR</strong></td>
<td>校验课次中教室与实训场地二选一互斥,严禁同时为空或同时设置</td>
<td><code>0</code></td>
<td><span class="badge badge-pass">PASS (0)</span></td>
</tr>
<tr>
<td><strong>del_flag = '2'</strong></td>
<td>电子班牌逻辑删除后底层标志位规范设置为 '2'</td>
<td><code>MATCH</code></td>
<td><span class="badge badge-pass">PASS</span></td>
</tr>
<tr>
<td><strong>Plan completion 状态联动</strong></td>
<td>结训后学员参训状态正确流转至 4 且 complete_time 真实写入</td>
<td><code>status=4, time!=null</code></td>
<td><span class="badge badge-pass">PASS</span></td>
</tr>
<tr>
<td><strong>历史退训保护</strong></td>
<td>已退训记录未被结训批量任务修改覆盖,complete_time 保持为 null</td>
<td><code>status=3, time=null</code></td>
<td><span class="badge badge-pass">PASS</span></td>
</tr>
<tr>
<td><strong>orphan report</strong></td>
<td>校验是否存在未关联有效报名记录的孤立报到流水</td>
<td><code>0</code></td>
<td><span class="badge badge-pass">PASS (0)</span></td>
</tr>
<tr>
<td><strong>orphan checkin</strong></td>
<td>校验是否存在未关联有效课次或报名的孤立考勤打卡</td>
<td><code>0</code></td>
<td><span class="badge badge-pass">PASS (0)</span></td>
</tr>
<tr>
<td><strong>manual_flag = 1</strong></td>
<td>人工修正考勤记录自动置审计标志位 manual_flag = 1</td>
<td><code>1</code></td>
<td><span class="badge badge-pass">PASS (1)</span></td>
</tr>
<tr>
<td><strong>report enrollment status</strong></td>
<td>报到流水关联的报名记录状态必须为 1(已报到) 或 4(已结训完成)</td>
<td><code>status IN (1, 4)</code></td>
<td><span class="badge badge-pass">PASS</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
</main>
<!-- 页脚 -->
<footer class="site-footer">
<p>RailwaySystem 铁路智慧培训管理系统 · 交付候选版 (Final Candidate)</p>
<p style="margin-top: 0.35rem; color: var(--text-muted);">
质量门禁与测试报告 · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/reports/final-test-report.md" target="_blank" rel="noopener noreferrer">查阅综合测试报告</a> · <a href="http://192.168.139.218:9980/sict/railwaysystem/-/blob/feat/cicd-pipeline/docs/reports/browser-acceptance-report.md" target="_blank" rel="noopener noreferrer">查阅浏览器验收报告</a>
</p>
</footer>
<script src="assets/docs.js"></script>
</body>
</html>