revert: 恢复误删文件(回退 81f500160)

This commit is contained in:
2026-06-12 16:00:06 +08:00
parent cec2f47a1f
commit a45b6e7955
925 changed files with 44427 additions and 455 deletions

168
MD/specs/BACKEND_CHECKLIST.md Executable file
View File

@@ -0,0 +1,168 @@
# 后端发布前检查清单
> **文档类型**: 技术规范
> **适用范围**: 后端开发
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
## 📋 基础检查项
### Maven编译验证
- [ ] 本地执行 `mvn compile` 编译通过无ERROR
- [ ] 执行 `mvn package -DskipTests` 打包成功
- [ ] 依赖版本无冲突(`mvn dependency:tree` 检查)
- [ ] 无编译警告(或已有书面说明可忽略)
### 构建产物验证
- [ ] JAR/WAR包生成完整大小合理
- [ ] `application.yml` 等配置文件已打包进产物
- [ ] 第三方依赖jar包完整lib目录无缺失
---
## 🔧 Spring Boot 配置检查
### 多环境配置
- [ ] `application-dev.yml`(开发)配置正确
- [ ] `application-test.yml`(测试)配置正确
- [ ] `application-prod.yml`(生产)配置正确
- [ ] 启动参数 `--spring.profiles.active` 指定正确环境
- [ ] 生产环境未启用devtools热部署
### Actuator安全
- [ ] 生产环境 `/actuator` 端点已禁用或限制访问
- [ ] `/actuator/env``/actuator/heapdump` 等敏感端点已关闭
- [ ] 健康检查端点 `/actuator/health` 返回信息已脱敏
### 启动校验
- [ ] 数据库连接池配置合理HikariCP最大/最小连接数)
- [ ] Redis/消息中间件连接配置正确
- [ ] 启动日志无ERROR级别异常
---
## 🗄️ MyBatis Plus 规范检查
### 实体-表映射
- [ ] 所有实体类标注 `@TableName`,表名与实际一致
- [ ] 主键字段标注 `@TableId(type = IdType.AUTO)` 或对应策略
- [ ] 非表字段标注 `@TableField(exist = false)`
- [ ] 字段命名符合下划线转驼峰规则
### SQL安全
- [ ] 所有查询使用参数化查询(`QueryWrapper` / `LambdaQueryWrapper`
- [ ] 禁止字符串拼接SQL`"WHERE name = '" + name + "'"`
- [ ] 批量操作使用MyBatis Plus `saveBatch` / `updateBatchById`
- [ ] 复杂SQL使用XML映射避免注解内嵌长SQL
### 事务管理
- [ ] 涉及多表写操作的方法标注 `@Transactional`
- [ ] 事务边界合理不包含外部HTTP调用
- [ ] 异常回滚配置正确(`rollbackFor = Exception.class`
- [ ] 事务方法未被同一类内方法直接调用(自调用失效问题)
### 分页插件
- [ ] `PaginationInnerInterceptor` 已正确配置
- [ ] 分页查询使用 `Page<T>` 对象非手动limit/offset
---
## 🔌 RESTful API 设计检查
### 统一返回格式
- [ ] 所有接口返回 `{code, msg, data}` 统一结构
- [ ] 成功返回 `code=200`,业务错误使用自定义错误码
- [ ] 异常通过 `@ControllerAdvice` + `@ExceptionHandler` 统一处理
### HTTP状态码
- [ ] 资源创建返回 `201 Created`
- [ ] 资源删除返回 `204 No Content`
- [ ] 参数校验失败返回 `400 Bad Request`
- [ ] 未认证返回 `401 Unauthorized`
- [ ] 无权限返回 `403 Forbidden`
- [ ] 资源不存在返回 `404 Not Found`
### 参数校验
- [ ] 请求参数使用 `@Valid` / `@Validated` 注解校验
- [ ] 必填字段标注 `@NotBlank` / `@NotNull`
- [ ] 数值范围标注 `@Min` / `@Max`
- [ ] 格式校验使用 `@Pattern`(如手机号、身份证号)
- [ ] 校验失败返回明确错误信息非500堆栈
### API版本管理
- [ ] 接口路径包含版本号(`/api/v1/``/api/v2/`
- [ ] 废弃接口标注 `@Deprecated`,并在文档中说明
- [ ] 不兼容变更必须升级版本号
---
## 🔒 安全与合规检查
### 数据脱敏
- [ ] 患者身份证号在日志中脱敏(`***` 掩码)
- [ ] 患者手机号在日志中脱敏前3后4中间`****`
- [ ] 敏感字段序列化时使用 `@JsonSerialize` 自定义脱敏器
- [ ] 接口返回中非必需字段不暴露如密码、salt
### 权限控制
- [ ] 所有涉及患者数据的接口标注 `@PreAuthorize`
- [ ] 数据级权限校验(医生只能访问本科室患者)
- [ ] 越权访问返回 `403`,非 `404``500`
- [ ] 敏感操作(删除、修改诊断)需二次确认或额外权限
### 审计日志
- [ ] 处方修改记录操作人、时间、变更内容
- [ ] 病历删除操作记录完整审计链
- [ ] 审计日志独立存储,不可被业务用户删除
- [ ] 关键业务操作记录IP地址和操作终端
---
## ⚡ 性能检查
### 数据库查询
- [ ] 无N+1查询问题使用 `JOIN` 或批量查询)
- [ ] 大表查询必须有分页限制
- [ ] 慢查询已优化(执行时间 < 500ms
- [ ] 索引已覆盖高频查询条件
### 接口性能
- [ ] 核心接口响应时间 < 1秒
- [ ] 列表接口支持分页无全量返回
- [ ] 大文件下载使用流式传输非全量加载到内存
---
## 📝 文档与发布准备
### 文档更新
- [ ] API接口文档已同步更新路径参数返回值
- [ ] 数据库变更脚本已提供DDL/DML
- [ ] 配置变更说明已记录新增/修改的配置项
- [ ] 影响范围说明已明确哪些模块哪些接口受影响
### 回滚预案
- [ ] 数据库变更可回滚提供反向SQL脚本
- [ ] 配置变更可快速回退
- [ ] 紧急回滚流程已明确怎么做多长时间
- [ ] 回滚后数据一致性已验证
---
## ✅ 最终确认
### 发布前最后检查
- [ ] `mvn compile` 构建成功附终端截图
- [ ] 关键单元测试通过
- [ ] 测试环境部署验证通过
- [ ] Code Review 已完成并获得批准
- [ ] 相关Bug已关闭或延期说明
---
**文档版本**v1.0
**最后更新**2026年4月24日
**负责人**关羽后端开发
**适用范围**HIS 系统所有后端模块his-server
**补充说明**本清单与陈琳的前端发布前检查清单对称互补共同构成HIS系统发布前完整质量保障体系

View File

@@ -0,0 +1,367 @@
# HealthLink-HIS 后端开发规范
> **文档类型**: 技术规范
> **适用范围**: 后端 Java 开发
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 一、技术栈
| 组件 | 版本 | 说明 |
|------|------|------|
| JDK | 25 | OpenJDK 25 (LTS) |
| Spring Boot | 4.0.6 | 框架核心 |
| MyBatis-Plus | 3.5.16 | ORM框架 |
| PostgreSQL | 15+ | 主数据库 |
| Redis | 7.x | 缓存/会话 |
| Maven | 3.9+ | 构建工具 |
---
## 二、项目结构
```
healthlink-his-server/
├── healthlink-his-common/ # 公共模块(枚举、常量、工具类)
├── healthlink-his-domain/ # 领域层实体、Mapper、Flyway迁移
├── healthlink-his-application/ # 应用层Controller、Service、业务逻辑
├── core-common/ # 若依公共核心
├── core-system/ # 若依系统模块
├── core-framework/ # 若依框架核心
├── core-quartz/ # 定时任务
├── core-generator/ # 代码生成
├── core-flowable/ # 工作流
└── core-admin/ # 管理后台
```
---
## 三、分层架构规范
### 3.1 Controller 层
- 路径:`com.healthlink.his.web.{module}.controller`
- 职责接收请求、参数校验、调用AppService、返回统一结果
- 禁止:直接操作数据库、编写业务逻辑
```java
@RestController
@RequestMapping("/api/v1/registration")
@Api(tags = "挂号管理")
public class RegistrationController {
@Autowired
private IRegistrationAppService registrationAppService;
@GetMapping("/list")
@PreAuthorize("@ss.hasPermi('registration:list')")
public TableDataInfo list(RegistrationQueryDto query) {
startPage();
List<RegistrationDto> list = registrationAppService.selectList(query);
return getDataTable(list);
}
}
```
### 3.2 AppService 层(应用服务)
- 路径:`com.healthlink.his.web.{module}.appservice`
- 职责编排业务流程、协调多个Service、事务管理
- 命名:`XxxAppService`(接口)+ `XxxAppServiceImpl`(实现)
### 3.3 Service 层
- 路径:`com.healthlink.his.web.{module}.service`
- 职责单表CRUD、基础业务逻辑
- 命名:`IXxxService`(接口)+ `XxxServiceImpl`(实现)
### 3.4 Mapper 层
- 路径:`com.healthlink.his.web.{module}.mapper`
- 职责数据访问、SQL映射
- 命名:`XxxMapper`(接口)+ `XxxMapper.xml`XML映射
### 3.5 Entity/Domain 层
- 路径:`com.healthlink.his.domain.{module}`
- 职责:实体定义、数据库表映射
- 命名:`Xxx`(实体类)
### 3.6 DTO 层
- 路径:`com.healthlink.his.web.{module}.dto`
- 职责:数据传输对象、查询参数、返回结果
---
## 四、命名规范
### 4.1 包命名
```
com.healthlink.his.web.{模块名}.{层级}
```
### 4.2 类命名
| 类型 | 命名规则 | 示例 |
|------|---------|------|
| Controller | `XxxController` | `RegistrationController` |
| AppService接口 | `IXxxAppService` | `IRegistrationAppService` |
| AppService实现 | `XxxAppServiceImpl` | `RegistrationAppServiceImpl` |
| Service接口 | `IXxxService` | `IRegistrationService` |
| Service实现 | `XxxServiceImpl` | `RegistrationServiceImpl` |
| Mapper | `XxxMapper` | `RegistrationMapper` |
| Entity | `Xxx` | `Registration` |
| DTO | `XxxDto` / `XxxQueryDto` | `RegistrationDto` |
| Enum | `XxxEnum` / `XxxType` | `ItemType` |
### 4.3 方法命名
| 场景 | 命名规则 | 示例 |
|------|---------|------|
| 查询列表 | `selectList` / `queryList` | `selectList(query)` |
| 查询详情 | `selectById` / `getById` | `selectById(id)` |
| 新增 | `insert` / `save` / `add` | `insert(dto)` |
| 修改 | `update` / `modify` | `update(dto)` |
| 删除 | `delete` / `remove` | `deleteById(id)` |
| 批量操作 | `batchXxx` | `batchInsert(list)` |
### 4.4 数据库命名
| 类型 | 命名规则 | 示例 |
|------|---------|------|
| 表名 | `{模块}_{功能}` 小写下划线 | `reg_registration` |
| 字段名 | 小写下划线 | `patient_id`, `create_time` |
| 主键 | `id``{表名}_id` | `registration_id` |
| 外键 | `{关联表}_id` | `patient_id` |
| 时间字段 | `create_time`, `update_time` | — |
| 软删除 | `del_flag` | — |
| 租户 | `tenant_id` | — |
---
## 五、编码规范
### 5.1 Controller 规范
```java
// ✅ 正确
@RestController
@RequestMapping("/api/v1/patient")
@Api(tags = "患者管理")
@Slf4j
public class PatientController {
@Autowired
private IPatientAppService patientAppService;
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('patient:query')")
public AjaxResult getInfo(@PathVariable Long id) {
return success(patientAppService.selectById(id));
}
@PostMapping
@PreAuthorize("@ss.hasPermi('patient:add')")
public AjaxResult add(@Validated @RequestBody PatientDto dto) {
return toAjax(patientAppService.insert(dto));
}
}
// ❌ 错误 - Controller里写业务逻辑
public AjaxResult add(@RequestBody PatientDto dto) {
// 不应该在这里写验证逻辑
if (dto.getName() == null) {
return error("名称不能为空");
}
// 不应该在这里写数据库操作
patientMapper.insert(patient);
return success();
}
```
### 5.2 Service 规范
```java
// ✅ 正确 - 事务注解
@Transactional(rollbackFor = Exception.class)
public int insert(PatientDto dto) {
Patient patient = BeanUtils.copyProperties(dto, Patient.class);
patient.setCreateTime(new Date());
patient.setCreateBy(SecurityUtils.getUsername());
return patientMapper.insert(patient);
}
// ❌ 错误 - 自调用导致事务失效
public void batchProcess(List<PatientDto> list) {
for (PatientDto dto : list) {
this.insert(dto); // 自调用,事务不生效!
}
}
```
### 5.3 Mapper 规范
```java
// ✅ 正确 - 使用LambdaQueryWrapper
public List<Patient> selectList(PatientQueryDto query) {
LambdaQueryWrapper<Patient> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(query.getName()), Patient::getName, query.getName())
.eq(Patient::getDelFlag, "0")
.orderByDesc(Patient::getCreateTime);
return patientMapper.selectList(wrapper);
}
// ❌ 错误 - 字符串拼接SQL
public List<Patient> selectList(String name) {
String sql = "SELECT * FROM patient WHERE name = '" + name + "'";
return jdbcTemplate.queryForList(sql, Patient.class);
}
```
### 5.4 统一返回格式
```java
// 成功
return AjaxResult.success(data);
return AjaxResult.success("操作成功", data);
// 失败
return AjaxResult.error("患者不存在");
return AjaxResult.error(MessageUtils.message("patient.not.found"));
// 列表
TableDataInfo dataPage = getDataTable(list);
```
---
## 六、异常处理规范
### 6.1 业务异常
```java
throw new ServiceException("患者编号不能为空");
throw new ServiceException(MessageUtils.message("patient.id.required"));
```
### 6.2 全局异常处理
- 使用 `@RestControllerAdvice` + `@ExceptionHandler`
- 不在 Controller 中 try-catch 后返回错误
- 所有异常最终返回统一格式 `{code, msg, data}`
### 6.3 日志规范
```java
// ✅ 正确
log.info("患者挂号成功: patientId={}, registrationId={}", patientId, regId);
log.error("挂号失败: patientId={}", patientId, e);
// ❌ 错误
log.info("患者身份证号: " + idCard); // 敏感信息泄露
System.out.println("debug"); // 不使用System.out
```
---
## 七、安全规范
### 7.1 数据脱敏
- 患者身份证号:`***` 掩码
- 患者手机号前3后4中间 `****`
- 密码BCrypt 加密,不可逆
### 7.2 SQL注入防护
- 所有查询使用参数化查询
- 禁止字符串拼接 SQL
- 使用 MyBatis-Plus 的 `QueryWrapper` / `LambdaQueryWrapper`
### 7.3 权限控制
- 所有接口标注 `@PreAuthorize`
- 数据级权限校验(医生只能访问本科室患者)
- 敏感操作需二次确认
---
## 八、测试规范
### 8.1 测试类型
| 类型 | 工具 | 覆盖范围 |
|------|------|---------|
| 单元测试 | JUnit 5 + Mockito | Service/工具类 |
| 接口测试 | MockMvc + SpringBootTest | Controller接口 |
| 白盒测试 | Maven编译 | 全量代码 |
| 黑盒测试 | 手动/自动化 | 核心业务流程 |
### 8.2 接口测试规范
```java
@SpringBootTest
@AutoConfigureMockMvc
public class PatientApiTest {
@Test
public void testGetPatientInfo() throws Exception {
mockMvc.perform(get("/healthlink-his/api/v1/patient/{id}", 1L)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isNotEmpty())
.andExpect(jsonPath("$.data.name").isNotEmpty());
}
}
```
### 8.3 测试数据要求
- 测试数据必须基于业务逻辑设计
- 验证业务返回内容非仅HTTP状态码
- 覆盖正常流程和异常流程
- 包含边界条件测试
---
## 九、性能规范
### 9.1 数据库查询
- 无N+1查询问题使用 `JOIN` 或批量查询)
- 大表查询必须有分页限制
- 慢查询已优化(执行时间 < 500ms
- 索引已覆盖高频查询条件
### 9.2 接口性能
- 核心接口响应时间 < 1秒
- 列表接口支持分页无全量返回
- 大文件下载使用流式传输
### 9.3 缓存使用
- 频繁查询的字典数据使用Redis缓存
- 缓存必须设置过期时间
- 数据变更时主动清除相关缓存
---
## 十、Git提交规范
### Commit Message 格式
```
<type>(<scope>): <subject>
<body>
<footer>
```
### Type 类型
| Type | 说明 |
|------|------|
| feat | 新功能 |
| fix | Bug修复 |
| docs | 文档变更 |
| style | 代码格式不影响功能 |
| refactor | 重构 |
| test | 测试相关 |
| chore | 构建/工具变更 |
### 示例
```
feat(registration): 新增患者过敏史管理功能
- 新增 PatientAllergy 实体和 Mapper
- 新增 IRegistrationAppService.getPatientAllergy()
- 新增 /api/v1/registration/allergy 接口
- Flyway迁移脚本: V2.0.1__add_patient_allergy.sql
Co-authored-by: zhangsan <zhangsan@healthlink.com>
```
---
> **文档版本**: v1.0
> **最后更新**: 2026-06-06

View File

@@ -0,0 +1,72 @@
# 床位管理模块设计文档
> **文档类型**: 业务设计
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **依据标准**: 《三级医院评审标准(2022版)》床位使用率指标
---
## 一、业务背景
床位管理直接影响医院运营效率。三甲医院评审要求床位使用率≥85%,床位周转次数达标。需要实时掌握床位状态,支持智能分配。
---
## 二、状态流转
### 2.1 床位状态机
```
空闲(0) → 占用(1) → 清洁中(2) → 空闲(0)
维修中(3) → 空闲(0)
```
| 状态 | 值 | 触发条件 | 允许操作 |
|------|-----|---------|---------|
| 空闲 | 0 | 清洁完成/新床 | 分配患者 |
| 占用 | 1 | 患者入院分配 | 患者转科/出院 |
| 清洁中 | 2 | 患者出院后 | 清洁完成→空闲 |
| 维修中 | 3 | 设备故障 | 维修完成→空闲 |
---
## 三、业务规则
| 规则编号 | 规则名称 | 规则描述 | 触发时机 |
|---------|---------|---------|---------|
| BR-001 | 床位分配校验 | 只有"空闲"状态的床位才能分配 | 入院登记时 |
| BR-002 | 科室匹配 | 床位所属科室必须与患者入院科室一致 | 入院登记时 |
| BR-003 | 出院自动清洁 | 患者出院后床位自动变为"清洁中" | 出院结算时 |
| BR-004 | 使用率统计 | 实时计算科室/全院床位使用率 | 定时任务 |
| BR-005 | 床位预约 | 支持预约指定床位(限时保留) | 预约住院时 |
---
## 四、数据模型
### 床位使用率计算公式
```
科室床位使用率 = (占用床位数 / 总床位数) × 100%
全院床位使用率 = (全院占用床位数 / 全院总床位数) × 100%
床位周转次数 = 出院人次 / 平均开放床位数
```
### 床位占用时长统计
```
平均住院天数 = Σ(出院日期 - 入院日期) / 出院人次
```
---
## 五、测试用例
| 用例编号 | 场景 | 预期结果 |
|---------|------|---------|
| TC-B001 | 正常分配 | 空闲床位→占用,状态正确 |
| TC-B002 | 分配已占用床位 | 返回"该床位已被占用" |
| TC-B003 | 出院自动清洁 | 出院后床位变为"清洁中" |
| TC-B004 | 使用率计算 | 数据准确反映实际使用情况 |
| TC-B005 | 维修中分配 | 返回"该床位维修中" |

226
MD/specs/CICD_GATEKEEPER.md Executable file
View File

@@ -0,0 +1,226 @@
# CI/CD构建门禁规范
> **文档类型**: 技术规范
> **适用范围**: CI/CD流程
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 🎯 规范目标
建立自动化质量门禁,确保每次代码提交都经过严格验证,防止低质量代码进入主干分支,提升系统稳定性和开发效率。
## 🔒 门禁层级
### 1. 提交前门禁Pre-commit
**触发时机**`git commit` 执行前
**验证内容**
- ESLint 代码规范检查
- Prettier 代码格式化
- 简单的单元测试(快速执行)
**工具配置**
- Husky + lint-staged
- 配置文件:`.husky/pre-commit`
### 2. 推送前门禁Pre-push
**触发时机**`git push` 执行前
**验证内容**
- 完整的单元测试套件
- 构建验证(`npm run build:prod`
- 集成测试(核心流程)
**工具配置**
- Husky pre-push hook
- 配置文件:`.husky/pre-push`
### 3. CI流水线门禁CI Pipeline
**触发时机**:代码推送到远程仓库后
**验证内容**
- 完整的测试套件(单元+集成+端到端)
- 代码覆盖率检查分阶段目标Q1≥30%Q2≥50%Q3≥80%
- 安全扫描SAST
- 构建产物验证
- 部署到测试环境
**工具配置**
- Spug CI/CD 流水线
- Gitea Webhook 触发
### 4. 发布前门禁Release Gate
**触发时机**:准备发布到生产环境前
**验证内容**
- 生产环境冒烟测试
- 性能基准测试
- 安全合规检查
- 回滚预案验证
## ⚙️ 具体配置要求
### ESLint 配置
```javascript
// eslint.config.js 关键配置
import globals from "globals";
import pluginVue from "eslint-plugin-vue";
import parserVue from "vue-eslint-parser";
import importPlugin from "eslint-plugin-import";
export default [
{
name: "app/files-to-lint",
files: ["**/*.{js,mjs,jsx,vue}"],
},
{
name: "app/files-to-ignore",
ignores: ["**/dist/**", "**/node_modules/**", "**/help-center/**"],
},
...pluginVue.configs["flat/recommended"],
{
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
parser: parserVue,
ecmaVersion: "latest",
sourceType: "module",
},
plugins: {
import: importPlugin,
},
rules: {
// 确保导入的模块实际存在(核心规则,防止构建失败)
"import/no-unresolved": "error",
// 确保导入的命名导出实际存在
"import/named": "error",
// 确保默认导出存在
"import/default": "error",
// 确保命名空间导出存在
"import/namespace": "error",
},
},
];
```
```
### Java 后端配置
```xml
<!-- pom.xml 关键插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.2.0</version>
</plugin>
```
### 数据库迁移配置
```yaml
# application.yml Flyway配置
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
```
javascript
// .eslintrc.js 关键配置
module.exports = {
plugins: ['import'],
rules: {
// 确保导入的模块实际存在
'import/no-unresolved': 'error',
// 确保导入的成员实际存在
'import/named': 'error',
// 禁止未使用的导入
'import/no-unused-modules': 'warn'
}
};
```
### Husky 配置
```bash
# .husky/pre-commit
#!/bin/sh
npm run lint-staged
# .husky/pre-push
#!/bin/sh
npm run test:unit && npm run build:prod
```
### lint-staged 配置
```json
// package.json
{
"lint-staged": {
"*.{js,vue}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["stylelint --fix", "prettier --write"]
}
}
```
```json
// package.json
{
"lint-staged": {
"*.{js,vue}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["stylelint --fix", "prettier --write"]
}
}
```
## 🚫 失败处理机制
### 自动处理
- **构建失败**:自动阻止 PR 合并
- **测试失败**:标记 PR 为失败状态
- **安全漏洞**:立即通知安全团队
### 人工处理
- **紧急修复**:可申请临时绕过(需架构师批准)
- **误报处理**:提交豁免申请并说明原因
- **规则调整**:通过 RFC 流程申请规则变更
## 📊 监控与度量
### 关键指标
- 门禁通过率 ≥ 95%
- 平均修复时间 ≤ 2小时
- 误报率 ≤ 5%
### 报告机制
- 每日门禁失败统计
- 周度质量趋势报告
- 月度规则优化建议
## 🔄 持续改进
### 规则演进
- 每月评审门禁规则有效性
- 根据项目需求调整检查强度
- 引入新的质量检查工具
### 团队培训
- 新成员入职培训包含门禁规范
- 定期分享最佳实践案例
- 建立常见问题解决方案库
---
**文档版本**v1.0
**最后更新**2026年4月24日
**负责人**:陈琳(文档专家)
**技术方案**:诸葛亮(架构师)
**适用范围**HIS 系统所有项目

144
MD/specs/COMMIT_TEMPLATE.md Executable file
View File

@@ -0,0 +1,144 @@
# 代码提交变更说明模板
> **文档类型**: 技术规范
> **适用范围**: 代码提交
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 📝 PR/Commit 模板
### 标题格式
```
<类型>(<模块>): <简短描述>
示例:
feat(patient): 添加患者基本信息编辑功能
fix(doctor): 修复医生排班显示异常问题
docs(api): 更新预约挂号接口文档
refactor(nurse): 重构护士站护理记录组件
```
### 正文模板
```markdown
## 🔍 变更背景
- **问题描述**:详细说明要解决的问题或实现的需求
- **影响范围**:列出受影响的模块、页面、功能
- **相关链接**禅道任务ID、需求文档链接等
## 🛠️ 变更内容
- **主要修改**:核心代码变更点
- **技术方案**:采用的技术方案和设计思路
- **兼容性**是否涉及API或数据结构变更
## 🗄️ 数据库变更
- **表结构变更**:列出新增/修改的表和字段
- **数据迁移**:是否需要数据迁移脚本
- **回滚方案**:数据库变更的回滚策略
## ✅ 验证情况
- **测试覆盖**:单元测试、集成测试覆盖情况
- **手动验证**:手动测试的场景和结果
- **构建验证**:本地构建截图(必填)
## 📋 检查清单
- [ ] 代码已通过 ESLint 检查
- [ ] 本地构建成功(附截图)
- [ ] 核心功能已测试验证
- [ ] 文档已同步更新
- [ ] Code Review 已完成
## 👥 相关人员
- **开发者**@开发者姓名
- **测试者**@测试者姓名
- **审核人**@架构师姓名
```
## 🏷️ 提交类型说明
| 类型 | 说明 | 示例 |
|------|------|------|
| feat | 新功能 | `feat: 添加用户登录功能` |
| fix | Bug修复 | `fix: 修复表单验证错误` |
| docs | 文档更新 | `docs: 更新API文档` |
| style | 代码格式调整 | `style: 格式化代码` |
| refactor | 代码重构 | `refactor: 重构组件结构` |
| test | 测试相关 | `test: 添加单元测试` |
| chore | 构建/依赖等 | `chore: 升级依赖版本` |
| perf | 性能优化 | `perf: 优化列表加载速度` |
## 📁 模块命名规范
| 模块 | 说明 |
|------|------|
| patient | 患者管理相关 |
| doctor | 医生工作站相关 |
| nurse | 护士站相关 |
| admin | 后台管理相关 |
| common | 公共组件/工具 |
| api | API接口相关 |
| auth | 认证授权相关 |
| payment | 支付相关 |
## 🖼️ 构建验证截图要求
### 必须包含的信息
1. **终端窗口**:显示 `npm run build:prod` 命令执行过程
2. **成功标识**:明确显示构建成功的提示信息
3. **时间戳**:截图包含当前时间,证明是最新构建
4. **分支信息**:显示当前工作分支名称
### 截图示例
```
$ git checkout feature/patient-edit
$ npm run build:prod
> his-system@1.0.0 build
> vue-cli-service build
⠇ Building for production...
DONE Build complete. The dist directory is ready to be deployed.
INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html
✨ Done in 45.23s.
```
## ⚠️ 禁止行为
### 严重违规(直接拒绝合并)
- 无构建验证截图
- 代码存在 ESLint 错误
- 未填写变更说明
- 修改无关代码文件
### 轻微违规(要求修正后重新提交)
- 描述过于简单
- 测试覆盖不完整
- 文档更新滞后
- 格式不符合规范
## 💡 最佳实践
### 高质量提交特征
- **原子性**:每次提交只解决一个问题
- **可追溯**关联具体的需求或Bug ID
- **可验证**:提供完整的验证证据
- **可理解**:描述清晰,他人能快速理解
### 团队协作建议
- 提交前先在本地完整测试
- 复杂变更提前与团队沟通
- 及时更新相关文档
- 主动帮助新人熟悉规范
---
**文档版本**v1.0
**最后更新**2026年4月24日
**负责人**:陈琳(文档专家)
**适用范围**HIS 系统所有开发人员

View File

@@ -0,0 +1,178 @@
# 会诊管理模块 — 三甲要求深度分析
> **文档类型**: 模块能力分析
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **三甲依据**: 《三级医院评审标准(2022版)》会诊管理制度
---
## 一、三甲对会诊管理的要求
### 1.1 评审标准条款
- **核心制度**: 会诊制度是十八项医疗核心制度之一
- **急会诊**: 急会诊10分钟内到位
- **科间会诊**: 48小时内完成
- **全院会诊**: 由医务部组织
- **疑难病例**: 多学科会诊(MDT)
- **病历要求**: 会诊记录必须写入病历
### 1.2 会诊类型与时限要求
| 会诊类型 | 时限要求 | 主持人 | 三甲依据 |
|---------|---------|--------|---------|
| 科间会诊 | 48小时内完成 | 主治医师以上 | 会诊制度 |
| 急会诊 | 10分钟内到位 | 二线值班医师 | 会诊制度 |
| 院内大会诊 | 24小时内安排 | 科主任/医务部 | 会诊制度 |
| 多学科会诊(MDT) | 72小时内安排 | 科主任/医务部 | 疑难病例管理 |
| 远程会诊 | 按约定时间 | 相关专科 | 互联网诊疗 |
| 院外会诊 | 按约定时间 | 被邀医院指定 | 外出会诊管理 |
---
## 二、现有模块能力分析
### 2.1 后端能力19个API
| API | 功能 | 三甲要求 | 状态 |
|-----|------|---------|------|
| GET /list | 获取会诊列表 | 基础查询 | ✅ |
| POST /query | 多条件查询 | 高级查询 | ✅ |
| POST /queryPage | 分页查询 | 分页支持 | ✅ |
| POST /save | 保存会诊申请 | 创建功能 | ✅ |
| POST /submit | 提交会诊申请 | 流程流转 | ✅ |
| POST /cancel | 作废会诊申请 | 流程控制 | ✅ |
| POST /complete | 完成会诊 | 流程完结 | ✅ |
| GET /department-tree | 科室树 | 科室选择 | ✅ |
| GET /my-invitations | 我的邀请 | 被邀查看 | ✅ |
| GET /activities | 会诊项目 | 费用关联 | ✅ |
| GET /confirmation/pending | 待确认列表 | 被邀确认 | ✅ |
| POST /confirmation/confirm | 确认会诊 | 流程流转 | ✅ |
| POST /confirmation/cancelConfirm | 取消确认 | 流程回退 | ✅ |
| POST /confirmation/sign | 签名会诊 | 电子签名 | ✅ |
| GET /confirmation/detail | 确认详情 | 详情查看 | ✅ |
| GET /confirmation/opinions | 会诊意见 | 意见记录 | ✅ |
| GET /detail/{id} | 申请详情 | 详情查看 | ✅ |
| POST /charge-items | 关联费用 | 费用管理 | ✅ |
| POST /confirm-charge-items | 确认收费 | 费用确认 | ✅ |
### 2.2 状态流转
```
新开(0) → 已提交(10) → 已确认(20) → 已签名(30) → 已完成(40)
已取消(50)
```
| 状态 | 值 | 允许操作 | 说明 |
|------|-----|---------|------|
| 新开 | 0 | 编辑/删除/提交 | 草稿状态 |
| 已提交 | 10 | 作废 | 等待被邀确认 |
| 已确认 | 20 | 签名/取消确认 | 被邀医生已确认 |
| 已签名 | 30 | 完成 | 被邀医生已签名 |
| 已完成 | 40 | 查看 | 会诊结束 |
| 已取消 | 50 | 查看 | 作废状态 |
### 2.3 前端页面4个共~120KB
| 页面 | 大小 | 功能 |
|------|------|------|
| consultationapplication | 27KB | 会诊申请管理(搜索/表格/新增弹窗/提交/作废) |
| consultationconfirmation | 24KB | 会诊确认管理(待确认列表/确认/签名/意见) |
| consultationconfirmation(clinic) | 21KB | 门诊会诊确认(另一套实现) |
| consultation.vue(doctorstation) | 50KB | 医生站会诊组件(嵌入医生工作站) |
### 2.4 数据模型
| 字段 | 说明 | ✅/❌ |
|------|------|-------|
| consultationId | 会诊单号 | ✅ |
| patientId/Name | 患者信息 | ✅ |
| encounterId | 就诊ID | ✅ |
| department | 申请科室 | ✅ |
| requestingPhysician | 申请医生 | ✅ |
| invitedList | 被邀医生列表 | ✅ |
| consultationDate | 会诊日期 | ✅ |
| consultationPurpose | 会诊目的 | ✅ |
| provisionalDiagnosis | 初步诊断 | ✅ |
| consultationUrgency | 紧急程度(1普通/2紧急) | ✅ |
| consultationActivityName | 会诊类型(院内/远程等) | ✅ |
| consultationStatus | 会诊状态 | ✅ |
| consultationOpinion | 会诊意见 | ✅ |
| signingPhysician | 签名医生 | ✅ |
| signingTime | 签名时间 | ✅ |
| submitFlag | 提交标记 | ✅ |
---
## 三、能力差距分析
### 3.1 已满足的三甲要求
| # | 要求 | 实现情况 | 评价 |
|---|------|---------|------|
| 1 | 会诊申请流程 | save→submit→confirm→sign→complete | ✅ 完整 |
| 2 | 科间会诊 | 支持科室选择+被邀医生 | ✅ 完整 |
| 3 | 会诊意见记录 | consultationOpinion字段+意见列表 | ✅ 完整 |
| 4 | 电子签名 | signConsultation接口 | ✅ 完整 |
| 5 | 费用关联 | chargeItems+confirmChargeItems | ✅ 完整 |
| 6 | 分页查询 | queryPage接口 | ✅ 完整 |
| 7 | 会诊项目管理 | activities接口 | ✅ 完整 |
| 8 | 状态流转 | 6状态完整生命周期 | ✅ 完整 |
### 3.2 未满足/待完善的三甲要求
| # | 要求 | 当前状态 | 差距 | 优先级 |
|---|------|---------|------|--------|
| 1 | **急会诊时限控制** | 有紧急程度字段(1普通/2紧急)但无10分钟到位时限校验 | ❌ 缺失时限逻辑 | 🔴 高 |
| 2 | **科间会诊48h时限** | 无48小时完成时限校验和提醒 | ❌ 缺失时限逻辑 | 🔴 高 |
| 3 | **会诊类型细分** | 有consultationActivityName(院内/远程),但缺科间/全院/MDT分类 | ⚠️ 不够细 | 🟡 中 |
| 4 | **会诊时限监控面板** | 无超时预警/统计面板 | ❌ 缺失 | 🔴 高 |
| 5 | **会诊与病历集成** | 会诊记录未自动归档到病历 | ❌ 缺失 | 🟡 中 |
| 6 | **MDT多学科会诊** | 无MDT专项流程(多科室同时参与) | ❌ 缺失 | 🟡 中 |
| 7 | **会诊记录打印** | 无标准格式会诊记录单打印 | ❌ 缺失 | 🟡 中 |
| 8 | **会诊统计报表** | 无会诊完成率/及时率统计 | ❌ 缺失 | 🟡 中 |
| 9 | **会诊与医嘱联动** | 会诊完成后未自动触发后续医嘱建议 | ❌ 缺失 | 🟢 低 |
| 10 | **远程会诊** | 有远程会诊项目,但无视频/图文远程对接 | ⚠️ 框架有 | 🟢 低 |
---
## 四、总体评价
### 4.1 完成度评分
| 维度 | 满分 | 得分 | 说明 |
|------|------|------|------|
| 会诊流程 | 25 | 22 | save→submit→confirm→sign→complete完整 |
| 数据模型 | 20 | 18 | 字段齐全,缺时限相关字段 |
| 前端页面 | 20 | 18 | 4个页面共120KB功能丰富 |
| 业务规则 | 20 | 12 | 有状态校验,缺时限控制 |
| 集成能力 | 15 | 10 | 有费用集成,缺病历/医嘱集成 |
| **总分** | **100** | **80** | **基本可用,需补全时限控制** |
### 4.2 结论
**现有会诊管理模块已完成约80%**,核心流程(申请→确认→签名→完成)完整可用。主要差距在于:
1. **时限控制缺失**最关键急会诊10分钟到位、科间会诊48小时完成的时限校验和提醒完全没有
2. **监控面板缺失**:无法实时查看会诊超时情况
3. **病历集成缺失**:会诊记录未自动归档到病历
### 4.3 补全建议
**优先级1必须做**:增加时限控制逻辑
- 急会诊提交后10分钟内未确认→自动升级通知
- 科间会诊提交后48小时未完成→超时预警
- 在ConsultationAppServiceImpl中增加时限校验
**优先级2应该做**:增加会诊时限监控面板
- 前端增加超时统计卡片
- 实时显示待处理/已超时/已完成数量
**优先级3可以做**:会诊记录打印+病历归档
---
> **结论**: 会诊管理模块基本满足三甲要求,核心差距是**时限控制**。
> 建议在现有代码基础上增强时限校验逻辑,无需重建。

View File

@@ -0,0 +1,188 @@
# 消毒供应中心(CSSD)追溯管理 + 影像3D重建 深度设计文档
> **文档类型**: 技术设计
> **版本**: v1.0
> **编制日期**: 2026-06-07
> **依据标准**: WS 310.1-310.3《医院消毒供应中心》、DICOM 3D重建规范
---
## 一、消毒供应中心(CSSD)追溯管理
### 1.1 业务背景
根据《医院消毒供应中心 第1部分:管理规范》(WS 310.1-2016)和《医院消毒供应中心 第3部分:清洗消毒及灭菌效果监测标准》(WS 310.3-2016)三甲医院CSSD必须实现:
- **全流程追溯**: 从器械回收→分类→清洗→消毒→干燥→检查→包装→灭菌→储存→发放的全链路可追溯
- **条码管理**: 每个器械包有唯一追溯码,支持扫码追溯
- **灭菌监测**: 生物监测、化学监测、物理监测的记录和预警
- **有效期管理**: 灭菌后器械包的有效期自动计算和过期预警
- **质量统计**: 清洗合格率、灭菌合格率、器械使用次数统计
### 1.2 业务流程
```
手术室/科室 使用后器械
↓ (回收)
CSSD回收清点 → 扫码登记(器械包ID+数量+来源科室)
分类 → 按器械类型分拣(手术器械/管腔器械/精密器械/普通器械)
清洗 → 手工清洗/超声清洗/机器清洗 → 清洗效果监测(ATP/蛋白残留)
消毒 → 湿热消毒(≥90℃/5min) 或 化学消毒
干燥 → 热风干燥/自然干燥
检查保养 → 功能检查+润滑+包装材料选择
包装 → 器械放入包装袋/容器 → 封口 → 贴追溯标签(条码+灭菌日期+有效期)
灭菌 → 压力蒸汽灭菌(134℃/4min) 或 低温灭菌 → 化学指示卡变色确认
储存 → 无菌物品存放区 → 按效期管理(先进先出)
发放 → 扫码出库 → 送达手术室/科室 → 签收确认
```
### 1.3 数据模型
#### 核心实体
1. **CssdTray** (器械包) — 器械包基础信息
- id, tray_code(唯一编码), tray_name, tray_type(手术/管腔/精密/普通)
- department_source(来源科室), status(在用/清洗中/灭菌中/储存中/已发放)
- current_location(当前位置), total_uses(使用次数)
- sterilize_count(灭菌次数), last_sterilize_time
2. **CssdTraceRecord** (追溯记录) — 每次流转记录
- id, tray_id, step_type(回收/清洗/消毒/包装/灭菌/储存/发放)
- operator_id, operator_name, operation_time
- device_name(设备名称), device_code
- parameters(JSON: 温度/时间/压力等工艺参数)
- result(合格/不合格), remark
3. **CssdSterilizeBatch** (灭菌批次) — 每锅灭菌记录
- id, batch_code, sterilizer_name, sterilizer_code
- start_time, end_time, cycle_type(预真空/下排气/快速)
- temperature, pressure, exposure_time
- biological_result(生物监测: 合格/不合格/待检)
- chemical_result(化学监测: 合格/不合格)
- physical_result(物理监测: 合格/不合格)
- batch_status(进行中/已完成/已释放)
4. **CssdSterilizeItem** (灭菌包明细) — 批次内的器械包
- id, batch_id, tray_id
- chemical_indicator(化学指示卡颜色变化)
- bi_indicator(生物指示剂结果)
5. **CssdExpiryAlert** (过期预警) — 有效期管理
- id, tray_id, batch_id
- sterilize_time, expiry_time, alert_time
- status(正常/预警/过期)
### 1.4 业务规则
| 规则编号 | 规则名称 | 规则描述 |
|---------|---------|---------|
| R1 | 回收扫码 | 所有器械包回收时必须扫码登记 |
| R2 | 清洗监测 | 清洗后必须进行ATP或蛋白残留检测 |
| R3 | 包装标签 | 包装必须贴追溯标签(条码+日期+有效期) |
| R4 | 灭菌三要素 | 生物+化学+物理三项监测全部合格才能释放 |
| R5 | 有效期管理 | 压力蒸汽灭菌: 无菌包装180天, 无纺布14天, 棉布7天 |
| R6 | 过期拦截 | 过期器械包禁止发放,必须重新灭菌 |
| R7 | 使用次数 | 器械包达到最大使用次数(可配置)时提醒报废 |
### 1.5 接口设计
| API | 方法 | 说明 |
|-----|------|------|
| /cssd/tray/page | GET | 器械包列表 |
| /cssd/tray/add | POST | 新建器械包 |
| /cssd/trace/scan | POST | 扫码追溯(流转) |
| /cssd/trace/history/{trayId} | GET | 器械包追溯历史 |
| /cssd/sterilize/batch/page | GET | 灭菌批次列表 |
| /cssd/sterilize/batch/add | POST | 新建灭菌批次 |
| /cssd/sterilize/batch/complete/{id} | PUT | 完成灭菌(录入监测结果) |
| /cssd/sterilize/batch/release/{id} | PUT | 释放批次(三项监测合格) |
| /cssd/expiry/alerts | GET | 过期预警列表 |
| /cssd/stats/overview | GET | 统计概览(清洗率/灭菌率/过期数) |
---
## 二、影像3D重建
### 2.1 业务背景
影像3D重建是影像诊断的高级功能主要应用于:
- **骨科**: 骨折三维重建,辅助手术规划
- **心血管**: 冠脉CTA三维重建评估狭窄程度
- **胸腹部**: 肿瘤三维定位,评估与周围组织关系
- **口腔**: 颌面骨三维重建,正畸/种植规划
### 2.2 业务流程
```
CT/MRI扫描 → DICOM图像导入
图像预处理 → 去噪/增强/分割
三维重建 → Volume Rendering(容积渲染) / MPR(多平面重建) / MIP(最大密度投影)
后处理 → 测量(距离/角度/体积) / 标注 / 裁剪
生成报告 → 3D截图 + 测量数据 + 诊断结论
审核发布 → 主治医师审核 → 发布到PACS/病历系统
```
### 2.3 数据模型
#### 核心实体
1. **ReconstructionTask** (重建任务) — 3D重建任务
- id, patient_id, patient_name, encounter_id
- apply_id(检查申请ID), study_uid(DICOM StudyUID)
- modality(CT/MRI), body_part, scan_range
- task_status(PENDING/PROCESSING/COMPLETED/FAILED)
- reconstruction_type(VR/MPR/MIP/VR+MPR)
- result_path(重建结果存储路径)
- slice_thickness, pixel_spacing
- request_doctor, complete_time
2. **ReconstructionResult** (重建结果) — 3D重建输出
- id, task_id, result_type(VR/MPR/MIP)
- image_path(截图路径), volume_data_path(体数据路径)
- measurements(JSON: 距离/角度/体积等测量数据)
- annotations(JSON: 标注信息)
- report_text(报告文本)
3. **ReconstructionReport** (重建报告) — 3D重建报告
- id, task_id, patient_id, encounter_id
- findings(所见), impression(印象), conclusion(结论)
- report_doctor, report_time
- verify_doctor, verify_time
- status(DRAFT/REPORTED/VERIFIED)
### 2.4 业务规则
| 规则编号 | 规则名称 | 规则描述 |
|---------|---------|---------|
| R1 | 任务触发 | 由影像科医生从PACS工作台发起3D重建任务 |
| R2 | 图像要求 | 至少需要50层连续断层图像才能进行3D重建 |
| R3 | 重建类型 | 支持VR(容积渲染)/MPR(多平面)/MIP(最大密度投影) |
| R4 | 测量功能 | 支持距离/角度/面积/体积测量 |
| R5 | 报告审核 | 3D重建报告必须由主治以上医师审核 |
| R6 | 图像存储 | 重建结果存储在PACS归档系统保留期≥1年 |
### 2.5 接口设计
| API | 方法 | 说明 |
|-----|------|------|
| /reconstruction/task/page | GET | 重建任务列表 |
| /reconstruction/task/add | POST | 新建重建任务 |
| /reconstruction/task/complete/{id} | PUT | 完成重建 |
| /reconstruction/result/list/{taskId} | GET | 重建结果列表 |
| /reconstruction/report/add | POST | 新建报告 |
| /reconstruction/report/verify/{id} | PUT | 审核报告 |
| /reconstruction/stats | GET | 统计(任务数/完成率/类型分布) |

112
MD/specs/FRONTEND_CHECKLIST.md Executable file
View File

@@ -0,0 +1,112 @@
# 前端发布前检查清单
> **文档类型**: 技术规范
> **适用范围**: 前端开发
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 📋 基础检查项
### 代码质量
- [ ] 代码已通过 ESLint 检查,无警告和错误
- [ ] 代码已通过 Prettier 格式化
- [ ] 无 console.log() 等调试代码残留
- [ ] 变量命名符合规范,语义清晰
- [ ] 函数职责单一,复杂度适中
### 构建验证
- [ ] 本地执行 `npm run build:prod` 成功完成
- [ ] 构建产物无报错,体积合理
- [ ] 静态资源路径正确无404错误
- [ ] 环境变量配置正确(开发/测试/生产)
### 功能验证
- [ ] 核心功能流程完整测试通过
- [ ] 边界条件和异常场景已覆盖
- [ ] 表单验证逻辑正确
- [ ] API 接口调用正常,错误处理完善
- [ ] 路由跳转逻辑正确
## 🔧 技术检查项
### 模块导入检查
- [ ] 所有 import 语句引用的模块实际存在
- [ ] 无未使用的 import 导入
- [ ] 路径别名(@/)配置正确
- [ ] 第三方库版本兼容性确认
### 性能优化
- [ ] 组件按需加载(懒加载)已配置
- [ ] 大数据列表已实现虚拟滚动或分页
- [ ] 图片资源已压缩,格式合适
- [ ] 无内存泄漏风险(事件监听器、定时器等)
### 安全检查
- [ ] 用户输入已做 XSS 防护
- [ ] 敏感信息不在前端硬编码
- [ ] API 请求已做 CSRF 防护
- [ ] 权限控制逻辑正确
## 🌐 兼容性检查
### 浏览器兼容
- [ ] 主流浏览器Chrome、Firefox、Safari、Edge显示正常
- [ ] 移动端适配良好(如适用)
- [ ] 分辨率适配1366x768、1920x1080等
### 设备兼容
- [ ] 触摸设备操作体验良好
- [ ] 键盘导航支持完整
- [ ] 屏幕阅读器兼容性(无障碍)
## 📱 发布准备
### 文档更新
- [ ] 相关 API 文档已同步更新
- [ ] 用户操作手册已更新(如适用)
- [ ] 变更日志已记录
### 回滚预案
- [ ] 回滚方案已准备
- [ ] 数据兼容性已确认
- [ ] 紧急联系人已明确
## 🔧 后端检查项
### 编译验证
- [ ] Maven编译成功`mvn clean package -DskipTests`
- [ ] 无编译错误,仅有可接受的警告
- [ ] 依赖版本兼容性确认
### 数据库脚本
- [ ] DDL/DML脚本语法正确
- [ ] 回滚脚本已准备
- [ ] 数据迁移脚本已测试
## 🔄 前后端协同
### 接口兼容性
- [ ] API接口契约变更已双方确认
- [ ] 前端调用后端接口正常
- [ ] 错误码处理逻辑一致
## ✅ 最终确认
### 发布前最后检查
- [ ] 本地构建截图已附在 PR 中
- [ ] 测试环境部署验证通过
- [ ] Code Review 已完成并获得批准
- [ ] 相关 Bug 已关闭或延期说明
---
**文档版本**v1.0
**最后更新**2026年4月24日
**负责人**:陈琳(文档专家)
**适用范围**HIS 系统所有前端项目

View File

@@ -0,0 +1,554 @@
# HealthLink-HIS 前端开发规范
> **文档类型**: 技术规范
> **适用范围**: 前端 Vue3 开发
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 一、技术栈
| 组件 | 版本 | 说明 |
|------|------|------|
| Vue | 3.x | 前端框架 |
| Vite | 5.x | 构建工具 |
| Element Plus | 2.x | UI组件库 |
| Pinia | 2.x | 状态管理 |
| Vue Router | 4.x | 路由管理 |
| Axios | 1.x | HTTP客户端 |
| RuoYi-Vue3 | 3.9.2+ | 基础框架 |
---
## 二、项目结构
```
healthlink-his-ui/
├── src/
│ ├── api/ # API接口定义
│ │ ├── module_name/ # 按模块分组
│ │ │ ├── index.js # 接口入口
│ │ │ └── *.js # 各接口文件
│ │ └── system/ # 系统管理接口
│ ├── views/ # 页面视图
│ │ └── module_name/ # 按模块分组
│ │ └── index.vue # 页面组件
│ ├── components/ # 公共组件
│ ├── store/ # Pinia状态管理
│ │ ├── modules/ # 模块store
│ │ └── store.js # store入口
│ ├── router/ # 路由配置
│ ├── utils/ # 工具函数
│ ├── directive/ # 自定义指令
│ ├── plugins/ # 插件
│ ├── layout/ # 布局组件
│ └── assets/ # 静态资源
├── vite.config.js # Vite配置
├── package.json # 依赖配置
└── .env.dev # 开发环境变量
```
---
## 三、命名规范
### 3.1 文件命名
| 类型 | 命名规则 | 示例 |
|------|---------|------|
| 页面组件 | `index.vue` | `views/registration/index.vue` |
| 弹窗组件 | `XxxDialog.vue` | `PatientDialog.vue` |
| 子组件 | `XxxDetail.vue` | `RegistrationDetail.vue` |
| API文件 | `index.js``xxx.js` | `api/registration/index.js` |
| Store模块 | `xxx.js` | `store/modules/user.js` |
| 工具函数 | `xxx.js` | `utils/validate.js` |
### 3.2 组件命名
```vue
<!-- 正确 - PascalCase -->
<template>
<PatientDialog ref="dialogRef" @success="getList" />
</template>
<!-- 错误 -->
<template>
<patient-dialog ref="dialogRef" />
</template>
```
### 3.3 变量命名
| 类型 | 命名规则 | 示例 |
|------|---------|------|
| 响应式变量 | `camelCase` | `const patientList = ref([])` |
| 常量 | `UPPER_SNAKE_CASE` | `const MAX_RETRY = 3` |
| 事件处理函数 | `handle` 前缀 | `const handleClick = () => {}` |
| 获取数据函数 | `getList` / `getData` | `const getList = async () => {}` |
| 表单引用 | `xxxForm` / `ruleForm` | `const ruleForm = ref(null)` |
| 表格引用 | `xxxTable` / `tableRef` | `const tableRef = ref(null)` |
---
## 四、API 接口规范
### 4.1 API文件结构
```javascript
// api/registration/index.js
import request from '@/utils/request'
// 查询挂号列表
export function listRegistration(query) {
return request({
url: '/healthlink-his/api/v1/registration/list',
method: 'get',
params: query
})
}
// 查询挂号详情
export function getRegistration(id) {
return request({
url: '/healthlink-his/api/v1/registration/' + id,
method: 'get'
})
}
// 新增挂号
export function addRegistration(data) {
return request({
url: '/healthlink-his/api/v1/registration',
method: 'post',
data: data
})
}
// 修改挂号
export function updateRegistration(data) {
return request({
url: '/healthlink-his/api/v1/registration',
method: 'put',
data: data
})
}
// 删除挂号
export function delRegistration(ids) {
return request({
url: '/healthlink-his/api/v1/registration/' + ids,
method: 'delete'
})
}
```
### 4.2 API 路径规范
- 统一前缀:`/healthlink-his/api/v1/`
- 使用 kebab-case`/patient-allergy` 而非 `/patientAllergy`
- 列表接口:`/list`
- 详情接口:`/{id}`
- 新增:`POST /`
- 修改:`PUT /`
- 删除:`DELETE /{id}`
- 批量删除:`DELETE /{ids}`(逗号分隔)
---
## 五、页面组件规范
### 5.1 标准页面模板
```vue
<template>
<div class="app-container">
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
<el-form-item label="患者姓名" prop="patientName">
<el-input v-model="queryParams.patientName" placeholder="请输入患者姓名" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['registration:add']">新增</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 -->
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="患者姓名" prop="patientName" />
<el-table-column label="操作" width="180" align="center">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['registration:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['registration:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 新增/修改弹窗 -->
<XxxDialog ref="dialogRef" @success="getList" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { listXxx, delXxx } from '@/api/xxx'
import XxxDialog from './XxxDialog.vue'
const { proxy } = getCurrentInstance()
const dataList = ref([])
const loading = ref(true)
const showSearch = ref(true)
const total = ref(0)
const ids = ref([])
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
patientName: undefined
})
const dialogRef = ref(null)
/** 查询列表 */
const getList = async () => {
loading.value = true
const res = await listXxx(queryParams)
dataList.value = res.rows
total.value = res.total
loading.value = false
}
/** 搜索 */
const handleQuery = () => {
queryParams.pageNum = 1
getList()
}
/** 重置 */
const resetQuery = () => {
proxy.resetForm('queryForm')
handleQuery()
}
/** 多选 */
const handleSelectionChange = (selection) => {
ids.value = selection.map(item => item.id)
}
/** 新增 */
const handleAdd = () => {
dialogRef.value.open()
}
/** 修改 */
const handleUpdate = (row) => {
dialogRef.value.open(row.id)
}
/** 删除 */
const handleDelete = async (row) => {
await proxy.$modal.confirm('确认删除该记录?')
await delXxx(row.id)
proxy.$modal.msgSuccess('删除成功')
getList()
}
onMounted(() => {
getList()
})
</script>
```
### 5.2 弹窗组件模板
```vue
<template>
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="患者姓名" prop="patientName">
<el-input v-model="form.patientName" placeholder="请输入患者姓名" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="cancel"> </el-button>
<el-button type="primary" @click="submitForm"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { getXxx, addXxx, updateXxx } from '@/api/xxx'
const { proxy } = getCurrentInstance()
const title = ref('')
const open = ref(false)
const formRef = ref(null)
const form = reactive({ id: undefined, patientName: '' })
const rules = {
patientName: [{ required: true, message: '患者姓名不能为空', trigger: 'blur' }]
}
/** 打开弹窗 */
const openDialog = async (id) => {
reset()
if (id) {
const res = await getXxx(id)
Object.assign(form, res.data)
title.value = '修改'
} else {
title.value = '新增'
}
open.value = true
}
/** 提交 */
const submitForm = async () => {
await proxy.$refs.formRef.validate()
if (form.id) {
await updateXxx(form)
proxy.$modal.msgSuccess('修改成功')
} else {
await addXxx(form)
proxy.$modal.msgSuccess('新增成功')
}
open.value = false
emit('success')
}
/** 取消 */
const cancel = () => {
open.value = false
reset()
}
const reset = () => {
form.id = undefined
form.patientName = ''
}
const emit = defineEmits(['success'])
defineExpose({ open: openDialog })
</script>
```
---
## 六、状态管理规范 (Pinia)
```javascript
// store/modules/user.js
import { defineStore } from 'pinia'
import { login, logout, getInfo } from '@/api/login'
const useUserStore = defineStore('user', {
state: () => ({
token: getToken(),
name: '',
roles: [],
permissions: []
}),
actions: {
async loginAction(userInfo) {
const res = await login(userInfo)
setToken(res.token)
this.token = res.token
},
async getInfoAction() {
const res = await getInfo()
this.name = res.user.nickName
this.roles = res.roles
this.permissions = res.permissions
},
logoutAction() {
this.token = ''
this.name = ''
this.roles = []
removeToken()
}
}
})
export default useUserStore
```
---
## 七、路由配置规范
```javascript
// router/index.js
const routes = [
{
path: '/registration',
component: Layout,
children: [
{
path: '',
name: 'Registration',
component: () => import('@/views/registration/index.vue'),
meta: { title: '挂号管理', icon: 'ticket' }
}
]
}
]
```
### 路由命名规则
- 路径使用 kebab-case`/patient-allergy`
- name 使用 PascalCase`PatientAllergy`
- meta.title 使用中文:`患者过敏史`
---
## 八、样式规范
### 8.1 使用 scoped
```vue
<style scoped>
.app-container {
padding: 20px;
}
</style>
```
### 8.2 使用 Element Plus 变量
```css
:deep(.el-button--primary) {
--el-button-bg-color: #1890ff;
}
```
### 8.3 禁止事项
- ❌ 使用内联样式(除动态绑定外)
- ❌ 使用 `!important`
- ❌ 全局样式污染其他组件
---
## 九、安全规范
### 9.1 XSS 防护
- 用户输入使用 `v-text` 而非 `v-html`
- 必须使用 `v-html` 时需做转义处理
### 9.2 敏感信息
- 不在前端硬编码密码、密钥
- API请求通过 `request.js` 统一拦截添加Token
- Token 存储在 `localStorage`,设置过期时间
### 9.3 权限控制
- 使用 `v-hasPermi` 指令控制按钮权限
- 使用路由 `meta.roles` 控制页面权限
- 接口请求在 `request.js` 中统一处理 401/403
---
## 十、性能优化
### 10.1 路由懒加载
```javascript
component: () => import('@/views/registration/index.vue')
```
### 10.2 组件按需导入
```javascript
import { ElButton, ElTable } from 'element-plus'
```
### 10.3 大列表优化
- 超过100行使用虚拟滚动
- 列表接口必须支持分页
- 图片使用懒加载 `v-lazy`
### 10.4 内存泄漏防护
- `onMounted` 中注册的事件在 `onUnmounted` 中移除
- 定时器在组件销毁时清除
- 避免在 `watch` 中创建新对象
---
## 十一、测试规范
### 11.1 单元测试 (Vitest)
```javascript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import PatientDialog from './PatientDialog.vue'
describe('PatientDialog', () => {
it('renders correctly', () => {
const wrapper = mount(PatientDialog)
expect(wrapper.find('.el-dialog').exists()).toBe(true)
})
})
```
### 11.2 E2E测试 (Playwright)
```javascript
import { test, expect } from '@playwright/test'
test('registration flow', async ({ page }) => {
await page.goto('/login')
await page.fill('#username', 'admin')
await page.fill('#password', 'admin123')
await page.click('.login-button')
await expect(page).toHaveURL('/')
await page.goto('/registration')
await expect(page.locator('.el-table')).toBeVisible()
})
```
---
## 十二、Git提交规范
同后端规范(`MD/specs/IRON_RULES.md`),额外要求:
- 提交前执行 `npm run lint` 确保无报错
- 提交前执行 `npm run build:dev` 确保构建成功
---
> **文档版本**: v1.0
> **最后更新**: 2026-06-06
---
## 七、UI设计铁律法则
> 所有前端页面设计和开发必须遵守以下法则,详见 `MD/specs/UI_DESIGN_IRON_RULES.md`
### 核心设计法则速查
| 法则 | 核心思想 | HIS应用 |
|------|---------|---------|
| 希克定律 | 选项越少决策越快 | 菜单≤7项表单≤12字段 |
| 费茨定律 | 目标大且近操作快 | 按钮≥44px危险操作远离安全操作 |
| 米勒定律 | 记忆负荷≤7±2 | 信息分组Tab≤6个 |
| 雅各布定律 | 遵循用户已有习惯 | 若依标准布局模式 |
| 格式塔原则 | 视觉分组要清晰 | 间距系统、颜色体系 |
| 多赫蒂阈值 | 响应<400ms | loading态骨架屏分页 |
| 尼尔森十大原则 | 全面可用性 | 操作反馈防错容错 |
| 泰斯勒定律 | 复杂性守恒 | 智能默认值常用模板 |
| 峰终定律 | 关键时刻做好 | 成功动画错误优雅处理 |
| ·雷斯托夫 | 不同的更容易记住 | 危急值红色脉冲徽标通知 |
### 设计文档必备
每个新页面/模块的设计文档必须包含
1. 页面UI布局描述组件位置栅格比例
2. 交互效果清单每个操作效果反馈
3. 前后端调用流程操作API处理链渲染
4. 状态流转图
5. 异常/边界处理方案

View File

@@ -0,0 +1,305 @@
# Harness Engineering 完整方法论
> **文档类型**: 技术规范
> **适用范围**: AI Agent 协作开发
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 一、WalkingLabs 5 子系统模型
```
┌─────────────────────────────────────────────┐
│ 指令Instruction— RULES.md / AGENTS.md │
│ 工具Tools— shell / 文件 / 测试 │
│ 环境Environment— 依赖 / 服务 / 版本 │
│ 状态State— PROGRESS.md / 功能清单 │
│ 反馈Feedback— test / lint / build │
└─────────────────────────────────────────────┘
```
### 1.1 指令子系统
| 文件 | 用途 |
|------|------|
| `RULES.md` | 项目铁律、约束、标准工作流 |
| `AGENTS.md` | 子目录铁律引用 |
| `.harness/PROGRESS.md` | 会话进度 + 已验证状态 |
| `.harness/feature_list.json` | 功能状态唯一事实来源 |
| `.harness/init.sh` | 统一启动入口 |
| `.harness/clean-state-checklist.md` | 结束时的清洁检查 |
### 1.2 工具子系统
| 层级 | 工具 | 用途 |
|------|------|------|
| L0 开发 | `mvn compile/test` / `npm run build` | 编译、测试 |
| L1 Agent | `agentforge executor --agent <name>` | Agent 主循环 |
| L2 Pipeline | `agentforge pipeline` | 流水线批量修 Bug |
| L3 集成 | Zentao REST API | 禅道操作 |
| L4 辅助 | `rg` / `git blame` | 代码搜索、历史追溯 |
### 1.3 环境子系统
| 组件 | 配置 |
|------|------|
| Redis | `redis://127.0.0.1:16379` |
| PostgreSQL | `192.168.110.252:15432` |
| Git | `http://192.168.110.253:3000/wangyizhe/his.git` |
### 1.4 状态子系统
| 机制 | 用途 | 持久化 |
|------|------|--------|
| `TraceStore` (SQLite) | Agent 活动追踪 | `/var/lib/agentforge/traces.db` |
| `fix_trajectory` | 修复轨迹 | Redis Hash |
| `dead_letter` | 失败任务持久化 | Redis List |
### 1.5 反馈子系统
| 层级 | 速度 | 命令 | 失败处理 |
|------|------|------|---------|
| L1 编译检查 | <10秒 | `mvn compile` | 立即阻断 |
| L1 单元测试 | <5分钟 | `mvn test` | 失败回退重试 |
| L2 代码质量 | <2分钟 | ESLint / 编译警告 | 警告可忽略错误阻断 |
| L3 质量门禁 | <30秒 | `run_quality_gates()` | 编译验证通过才提交 |
| L4 人工审查 | 5-10分钟 | diff review | 驳回/指导/批准 |
---
## 二、约束系统
### 2.1 四类约束
| 类型 | 内容 | 示例 |
|------|------|------|
| 架构约束 | 接口合约包结构命名规范 | 包结构 `com.healthlink.his.web.{module}` |
| 代码质量 | 圈复杂度风格类型提示 | 每函数50行 |
| 安全约束 | 敏感信息权限输入验证 | 患者信息脱敏 |
| 业务规则 | 领域逻辑数据一致性 | 全链路6环验证 |
### 2.2 约束 DSL
```yaml
constraint:
type: "must" | "must_not" | "should" | "may"
scope: "file" | "class" | "method" | "project"
rule: "具体规则"
verification: "如何验证"
```
### 2.3 约束优先级
```
安全(1) > 架构(2) > 业务(3) > 质量(4) > 性能(5)
```
---
## 三、反馈系统
### 3.1 闭环测试
```
测试失败
→ 分析失败原因(编译/逻辑/边界/依赖)
→ 提取可行动反馈(文件:行号:错误类型:修复方向)
→ Agent 修复
→ 重测
→ 持续失败3次 → 上报人类
```
### 3.2 反馈格式
```
文件路径:行号 错误类型 错误描述 | 修复建议
示例:
src/main/java/com/.../PatientService.java:42 NullPointerException patient name | 添加空值检查
```
### 3.3 失败原因分析
| 类型 | 占比 | 捕获门禁 |
|------|------|---------|
| 架构错误 | 35% | L1 编译 |
| 业务逻辑 | 25% | L3 单元测试 |
| 创造性偏差 | 20% | L3 + L5 |
| Debug残留 | 15% | L2 静态分析 |
| 其他 | 5% | L5 |
### 3.4 测试覆盖率目标
```yaml
unit_test_coverage: 90% # 行覆盖率
mutation_score: 80% # 变异测试通过率
branch_coverage: 85% # 分支覆盖率
```
---
## 四、持久执行
### 4.1 检查点策略
**触发时机**
- 每完成1个关键步骤
- 编译通过/失败后
- 每次代码修改后
**检查点内容**
```yaml
checkpoint:
step_id: "string"
status: "pending | in_progress | completed | failed"
inputs: {}
outputs: {}
error_message: ""
timestamp: "ISO8601"
```
### 4.2 恢复流程
```
失败 → 定位最新检查点 → 分析失败原因 → git restore → 从失败点修复 → 继续执行
```
### 4.3 幂等性模式
| 模式 | 实现 |
|------|------|
| 唯一标识 | 每个操作生成唯一ID已执行则跳过 |
| 状态检查 | 执行前检查目标是否已达成 |
| 补偿操作 | 不可逆操作提供 `git restore` 回滚 |
---
## 五、Agent 协作详解
### 5.1 管线路由
```
fix_done (关羽/赵云)
诸葛亮 (分析路由)
│── 无DB变更 ──→ 张飞 (Playwright测试)
│── 有DB变更 ─→ 荀彧 (DB审查) → 张飞 (测试)
└── 失败 → 回退给修复者重修最多10次
张飞(测试) → 华佗(验收) → 陈琳(归档)
```
### 5.2 去重机制
| 机制 | TTL | 用途 |
|------|-----|------|
| `pipeline_sent:{bug_id}` | 24h | 防重复触发管线 |
| `pipeline_retry:{bug_id}` | | 重试计数器 |
| `codex_lock:{agent}` | 1h | Agent 互斥锁 |
| `fix_active:{agent}:{bug_id}` | 30min | 防重复 fix_start |
### 5.3 禅道操作规则
| 阶段 | 智能体 | 禅道操作 |
|------|--------|---------|
| 分析路由 | 诸葛亮 | 添加备注分析结果 |
| DB审查 | 荀彧 | 添加备注审查结果 |
| 测试 | 张飞 | 添加测试报告 + resolve |
| 验收 | 华佗 | 添加备注 + resolve + assign |
| 归档 | 陈琳 | 添加备注全流程记录 |
---
## 六、审查与审计
### 6.1 三层审查
| 层级 | 内容 | 信任度 |
|------|------|--------|
| L1 自审 | Agent 对照约束逐条检查 | 强制 |
| L2 配对审查 | Agent 变更摘要 + 人类终审 | 按信任度比例 |
| L3 合规审查 | 审计追踪记录所有AI操作 | 强制 |
### 6.2 信任度比例
| 信任等级 | 自审 | 配对审查 | 合规审查 |
|---------|------|---------|---------|
| L1 怀疑 | 强制 | 逐行 | 强制 |
| L2 试探 | 强制 | 抽样30% | 强制 |
| L3 信任 | 强制 | 抽样10% | 按需 |
### 6.3 审计记录格式
```yaml
audit_record:
agent_id: "codex-v4"
task_id: "bug-597"
timestamp: "2026-05-28T14:30:00Z"
actions:
- type: "file_modify"
path: "AdviceManageAppMapper.xml"
diff: "+7 lines, -2 lines"
approvals:
- reviewer: "human"
decision: "approved"
```
---
## 七、BDT 方法论Bug Driven Testing
### 7.1 流程
```
获取Bug → 设计用例 → 基线测试(应失败) → 修复 → 回归测试(应通过) → 扩展测试 → 提交
```
### 7.2 测试用例7种检查模式
| # | 模式 | 适用场景 | Playwright写法 |
|---|------|---------|---------------|
| 1 | 页面加载 | 所有Bug | `expect(page).not.toHaveURL(/.*login.*/)` |
| 2 | 元素可见 | 显示/缺失类 | `expect(locator).toBeVisible()` |
| 3 | 元素可交互 | 按钮/弹窗类 | `await locator.click()` |
| 4 | 数据正确 | 列表/回显类 | `expect(locator).toHaveText()` |
| 5 | 无报错 | 所有Bug | `page.on('pageerror')` |
| 6 | 流程完整 | 交互流程类 | 多步骤操作链 |
| 7 | 状态变更 | 退回/审核类 | 操作前vs操作后状态对比 |
### 7.3 测试用例质量标准
- `@bug{N}` 标签可单独运行
- `@regression` 标签回归套件
- 操作路径来自禅道复现步骤
- 断言覆盖期望结果
- 检查无JS错误
- 有截图记录
- 独立运行不依赖其他测试
---
## 八、L4/L5 分析与优化
### 8.1 L4 量化分析
- TraceStore (SQLite): `/var/lib/agentforge/traces.db`
- 指标Agent成功率平均修复耗时失败模式分布Pipeline吞吐量
### 8.2 L5 AI 自主优化
| 机制 | 触发条件 | 动作 |
|------|---------|------|
| 约束增强 | 成功率<50%(≥3次 | 自动补充专项约束 |
| 智能路由 | 按bug类型匹配历史最优Agent | `best_agent_for(bug_type)` |
| 重试策略 | 失败后换提示词/换Agent | 最多10次 |
| 路由调整 | 某Agent成功率最低 | 减少分配 |
- 评分成功率(60%) + 速度(20%) + 类型匹配(20%)
---
> **文档版本**: v1.0
> **最后更新**: 2026-06-06

View File

@@ -0,0 +1,161 @@
# 知情同意管理模块设计文档
> **文档类型**: 深度业务设计
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **三甲依据**: 《医疗纠纷预防和处理条例》《侵权责任法》— 患者知情同意权
---
## 一、业务背景
知情同意是医疗行为的法律前提。依据《医疗纠纷预防和处理条例》2018版
- 手术/麻醉/输血/特殊检查/特殊治疗必须取得患者或家属书面知情同意
- 知情同意书必须由患者或其授权代理人签署
- 知情同意书是医疗纠纷中最关键的法律证据
- 三甲评审现场必查项
---
## 二、知情同意类型
| 类型 | 适用场景 | 签署人要求 | 三甲依据 |
|------|---------|-----------|---------|
| 手术知情同意 | 所有手术 | 患者或授权代理人 | 手术管理制度 |
| 麻醉知情同意 | 所有麻醉操作 | 患者或授权代理人 | 麻醉管理制度 |
| 输血知情同意 | 输血治疗 | 患者或授权代理人 | 输血管理规范 |
| 特殊检查知情同意 | 有创检查/造影等 | 患者或授权代理人 | 检查管理规范 |
| 特殊治疗知情同意 | 化疗/放疗/介入等 | 患者或授权代理人 | 治疗管理规范 |
| 病危通知书 | 病危/病重 | 患者家属或代理人 | 危重患者管理 |
| 自费项目知情同意 | 自费药品/耗材 | 患者或授权代理人 | 医保管理规范 |
---
## 三、完整业务流程
### 3.1 知情同意全流程
```
医生发起知情同意
选择同意类型 + 关联医嘱/手术
系统自动填充模板(患者信息+诊断+拟定方案)
医生编辑知情同意内容
├── 疾病诊断
├── 拟实施的手术/操作名称
├── 手术/操作目的
├── 手术/操作方式
├── 预期效果
├── 可能出现的风险和并发症
├── 替代方案及其利弊
├── 不接受治疗的后果
└── 其他需要说明的事项
医生电子签名
患者/家属阅读+理解确认
患者/家属电子签名(手写板/密码)
生成知情同意书PDF
归档到病历
```
### 3.2 异常流程
| 场景 | 处理方式 |
|------|---------|
| 患者拒绝签署 | 记录拒绝原因+见证人签名,生成"拒绝知情同意"记录 |
| 患者无签署能力 | 要求法定代理人签署+见证人签名 |
| 紧急情况无法签署 | 记录紧急情况说明+院长/授权人批准 |
| 签署后修改 | 生成新版本,保留原版本,记录修改原因 |
| 超时未签署 | 系统提醒→再次通知→超过时限则禁止执行 |
---
## 四、数据模型
### 4.1 知情同意书表 `sys_informed_consent`
| 字段 | 类型 | 说明 | 必填 |
|------|------|------|------|
| id | BIGSERIAL | 主键 | ✅ |
| encounter_id | BIGINT | 就诊ID | ✅ |
| patient_id | BIGINT | 患者ID | ✅ |
| patient_name | VARCHAR(50) | 患者姓名 | ✅ |
| consent_type | INT | 类型(1手术 2麻醉 3输血 4特殊检查 5特殊治疗 6病危 7自费) | ✅ |
| related_surgery_id | BIGINT | 关联手术ID(手术知情时) | ❌ |
| related_advice_id | BIGINT | 关联医嘱ID | ❌ |
| diagnosis | TEXT | 疾病诊断 | ✅ |
| procedure_name | VARCHAR(200) | 拟实施手术/操作名称 | ✅ |
| procedure_purpose | TEXT | 手术/操作目的 | ✅ |
| procedure_method | TEXT | 手术/操作方式 | ✅ |
| expected_outcome | TEXT | 预期效果 | ✅ |
| risks_and_complications | TEXT | 可能出现的风险和并发症 | ✅ |
| alternative_plans | TEXT | 替代方案及其利弊 | ✅ |
| consequences_of_refusal | TEXT | 不接受治疗的后果 | ✅ |
| other_notes | TEXT | 其他需要说明的事项 | ❌ |
| doctor_user_id | BIGINT | 签署医生ID | ✅ |
| doctor_name | VARCHAR(50) | 签署医生姓名 | ✅ |
| doctor_sign_time | TIMESTAMP | 医生签名时间 | ✅ |
| doctor_sign_image | TEXT | 医生签名图片(base64) | ✅ |
| patient_sign_status | INT | 患者签名状态(0未签 1已签 2拒绝) | ✅ |
| patient_sign_time | TIMESTAMP | 患者签名时间 | ❌ |
| patient_sign_image | TEXT | 患者签名图片(base64) | ❌ |
| guardian_name | VARCHAR(50) | 代理人姓名(患者无签署能力时) | ❌ |
| guardian_relation | VARCHAR(20) | 代理人与患者关系 | ❌ |
| witness_name | VARCHAR(50) | 见证人姓名 | ❌ |
| reject_reason | TEXT | 拒绝原因(患者拒绝时) | ❌ |
| status | INT | 状态(0草稿 1待患者签名 2已完成 3已归档 4已作废) | ✅ |
| version | INT | 版本号(修改后版本递增) | ✅ |
---
## 五、业务规则
| 规则编号 | 规则名称 | 规则描述 |
|---------|---------|---------|
| IC-001 | 手术强制签署 | 手术前必须完成手术知情同意书签署 |
| IC-002 | 麻醉强制签署 | 麻醉前必须完成麻醉知情同意书签署 |
| IC-003 | 输血强制签署 | 输血前必须完成输血知情同意书签署 |
| IC-004 | 紧急豁免 | 紧急情况可事后补签,需院长批准+详细记录 |
| IC-005 | 版本管理 | 修改后生成新版本,保留原版本可追溯 |
| IC-006 | 签署时限 | 知情同意签署后24小时内未执行需重新确认 |
| IC-007 | 模板管理 | 支持系统模板+科室模板+个人模板 |
| IC-008 | 归档要求 | 手术/操作完成后自动归档到病历 |
---
## 六、与手术/医嘱的集成
```
手术申请(Surgery) ──1:1──→ 手术知情同意书
麻醉记录(Anesthesia) ──1:1──→ 麻醉知情同意书
医嘱(Advice) ──1:N──→ 输血/特殊检查知情同意书
知情同意书 ──归档──→ 病案管理(MedicalRecord)
```
---
## 七、测试用例
| 用例编号 | 场景 | 预期结果 |
|---------|------|---------|
| TC-IC001 | 正常签署流程 | 医生签署→患者签署→完成→归档 |
| TC-IC002 | 手术前未签署 | 手术安排时拦截,提示"请先完成知情同意" |
| TC-IC003 | 患者拒绝签署 | 记录拒绝原因+见证人,生成拒绝记录 |
| TC-IC004 | 紧急情况 | 记录紧急说明+院长批准,事后补签 |
| TC-IC005 | 修改后版本 | 生成新版本,原版本保留可查看 |
| TC-IC006 | 签署超时 | 超过24小时未执行系统提醒重新确认 |

551
MD/specs/IRON_RULES.md Normal file
View File

@@ -0,0 +1,551 @@
# HealthLink-HIS 执行铁律
> **文档类型**: 技术规范
> **适用范围**: 全项目开发流程
> **版本**: v2.1
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06 (铁律18统一)
---
## 一、铁律总览
| 编号 | 铁律名称 | 优先级 | 适用范围 |
|------|---------|--------|---------|
| #1 | 修改完必须测试 | P0 | 全量代码 |
| #2 | Flyway 数据库迁移 | P0 | 数据库变更 |
| #3 | 先分解再行动 | P1 | 非平凡任务 |
| #4 | 验证后信 | P1 | 编译/构建 |
| #5 | 文档统一管理 | P1 | 文档产出 |
| #6 | 测试通过后才提交 | P0 | 代码提交 |
| #7 | 前后端API路径对齐 | P0 | 接口开发 |
| #8 | 铁律和规范文档放MD目录 | P1 | 规范文档 |
| #9 | 开发前必须审核原有代码 | P0 | 全量开发 |
| #10 | 设计文档必须包含UI设计和调用流程 | P0 | 设计文档/前端开发 |
| #11 | 模块设计必须分析业务逻辑不能只做CRUD | P0 | 全量模块设计 |
| #12 | 模块优化必须分析现有业务流并说明促进作用 | P0 | 全量模块优化 |
| #13 | 开发必须深度分析+深度设计,禁止浅层糊弄 | P0 | 全量开发 |
| #14 | 设计文档确认后自主开发 | P0 | 全量开发 |
| #15 | 模块设计必须分析业务逻辑 | P0 | 全量模块设计 |
| #16 | 模块优化必须分析业务流并说明促进作用 | P0 | 全量模块优化 |
| #17 | 设计文档必须包含UI设计和调用流程 | P0 | 设计文档/前端开发 |
| #18 | 禁止破坏原有功能 | P0 | 全项目(绝对) |
---
## 二、铁律详细说明
### 铁律 #1: 修改完必须测试
**任何代码修改后,必须完成以下测试才能提交:**
#### 白盒测试
- `mvn clean compile` 编译通过无ERROR
- 单元测试全部通过(如有)
- 代码无新增编译警告(或有书面说明可忽略)
#### 黑盒测试
- 启动应用,验证无启动报错
- 测试关键接口(登录、核心业务接口)
- 验证请求响应结构正确(`{code, msg, data}`
- 验证业务逻辑正确性非仅HTTP状态码
#### 冒烟测试
- 应用正常启动(端口监听)
- 健康检查接口返回正常
- 基础 CRUD 操作正常
- 登录→获取菜单→核心业务流程通畅
#### 前端测试
- `npm run build:dev` 构建成功
- ESLint 无错误
- 页面无控制台报错
- 核心业务页面功能正常
---
### 铁律 #2: Flyway 数据库迁移
**但凡遇到有新建表和字段的,必须通过 Flyway 框架去实现。**
#### 操作规范
1.`healthlink-his-domain/src/main/resources/db/migration/` 下创建迁移脚本
2. 命名格式:`V{版本号}__{描述}.sql`(双下划线分隔)
3. 示例:`V2.0.1__add_patient_allergy_table.sql`
4. 迁移脚本必须包含完整的 DDLCREATE TABLE / ALTER TABLE
5. 必须提供回滚方案(文档记录,非自动回滚)
#### 禁止事项
- ❌ 直接在数据库执行 SQL 不走 Flyway
- ❌ 修改已执行的迁移脚本
- ❌ 迁移脚本中使用 `DROP TABLE`(除非明确需要)
- ❌ 跳过版本号
---
### 铁律 #3: 先分解再行动
**任何非平凡任务先出 plan 再执行。**
#### 触发条件
- 修改超过 3 个文件的任务
- 涉及多个模块的变更
- 数据库结构变更
- 新功能开发
#### 执行步骤
1. 分析现有代码和架构
2. 制定分步计划(使用 `update_plan`
3. 确认测试方案
4. 逐步执行并验证
---
### 铁律 #4: 验证后信
**每次修改后必须验证编译通过,不信记忆。**
#### 验证命令
```bash
# 后端编译
export JAVA_HOME=/opt/jdk-25
mvn clean compile -DskipTests
# 完整构建
mvn install -DskipTests
# 前端构建
cd healthlink-his-ui && npm run build:dev
```
---
### 铁律 #5: 文档统一管理
**所有文档必须存储在 `MD/` 目录中,遵循文档规范。**
#### 目录结构
```
MD/
├── DOCUMENTATION_STANDARD.md # 文档管理规范
├── architecture/ # 架构设计
├── development/ # 开发计划与记录
├── standards/ # 国家/行业标准
├── specs/ # 技术规范与流程
├── bugs/ # Bug分析与修复记录
├── guides/ # 使用指南
└── upgrade/ # 升级记录
```
#### 命名规范
- 文件名使用 **大写英文+下划线**(如 `GRADE3A_DETAILED_DESIGN.md`
- 不使用中文作文件名
- 不使用空格分隔单词
- 版本号标注在文件名末尾(如 `_V2`
#### 格式要求
- 文档头部必须包含元数据块(文档类型、版本、日期)
- 代码块必须标注语言类型
- 表格使用标准Markdown格式
#### 详细规范
参见 `MD/DOCUMENTATION_STANDARD.md`
---
### 铁律 #6: 测试通过后才提交
**代码修改必须通过完整测试后才能提交到远程仓库。**
#### 提交前检查
1. `mvn clean compile` 编译通过
2. 接口测试全部通过88/88
3. 前端构建成功
4. 无新增编译警告
5. 代码变更范围已确认(`git status`
#### 提交规范
- 使用标准 Commit Message 格式
- 参见 `MD/specs/COMMIT_TEMPLATE.md`
- 不提交未完成的功能
- 不提交调试代码和临时文件
---
### 铁律 #7: 前后端API路径对齐
**前后端API路径必须保持一致。**
#### 规范要求
1. 后端接口路径统一前缀:`/healthlink-his/`
2. 前端 `request.js` 中配置的 `baseURL` 必须与后端匹配
3. 接口变更必须同步更新前后端代码
4. 新增接口必须在 Swagger 文档中注册
5. 接口路径命名使用小写字母和连字符kebab-case
---
### 铁律 #11: 设计文档确认后自主开发(铁律)
**设计文档一旦确认,后续开发必须按文档自主执行。**
#### 核心要求
- **禁止反复询问**"是否继续""下一步做什么""是否开始"——直接按计划推进
- 每完成一个 Sprint自动提交推送然后立即开始下一个 Sprint
- 设计文档是"**已签合同**",不是"参考意见"
- 只在遇到**无法解决的阻塞**时才暂停询问
#### 触发条件
- 设计文档已确认(如 `MD/architecture/GRADE3A_GAP_ANALYSIS_AND_DESIGN.md`
- Sprint 计划已制定
- 代码编译通过
#### 禁止事项
- ❌ 完成一个模块后问"继续吗?"
- ❌ 完成一个 Sprint 后问"下一步?"
- ❌ 每次工具调用前问"开始了吗?"
### 铁律 #8: 铁律和规范文档放MD目录
**所有铁律和规范文档统一存放在 `MD/specs/` 目录中。**
#### 已有规范文档
| 文档 | 路径 | 说明 |
|------|------|------|
| 执行铁律 | `MD/specs/IRON_RULES.md` | 本文档 |
| 后端开发规范 | `MD/specs/BACKEND_DEVELOPMENT_STANDARD.md` | 后端编码规范 |
| 前端开发规范 | `MD/specs/FRONTEND_DEVELOPMENT_STANDARD.md` | 前端编码规范 |
| 后端检查清单 | `MD/specs/BACKEND_CHECKLIST.md` | 发布前检查 |
| 前端检查清单 | `MD/specs/FRONTEND_CHECKLIST.md` | 发布前检查 |
| CI/CD门禁 | `MD/specs/CICD_GATEKEEPER.md` | 构建门禁 |
| 提交模板 | `MD/specs/COMMIT_TEMPLATE.md` | Commit规范 |
| 发布清单 | `MD/specs/RELEASE_CHECKLIST.md` | 发布流程 |
| E2E测试计划 | `MD/specs/PLAYWRIGHT_TESTING_PLAN.md` | Playwright测试 |
#### AGENTS.md 同步
- 后端 `healthlink-his-server/AGENTS.md` 必须引用本文档
- 新增铁律必须同步更新本文档和 AGENTS.md
---
## 三、违规处理
| 级别 | 描述 | 处理方式 |
|------|------|---------|
| P0 违规 | 跳过测试直接提交 | 必须回滚并重新测试 |
| P0 违规 | 数据库变更不走Flyway | 回滚数据库变更重新用Flyway执行 |
| P1 违规 | 未分解就行动 | 补充分析和计划文档 |
| P1 违规 | 文档不规范 | 补充元数据和格式 |
---
## 四、快速参考
### 后端开发速查
```bash
# 编译
export JAVA_HOME=/opt/jdk-25 && mvn clean compile -DskipTests
# 完整构建
mvn install -DskipTests
# 运行测试
mvn test -pl healthlink-his-application -Dtest="ClassName" -Dsurefire.failIfNoSpecifiedTests=false
# 启动应用
java -jar healthlink-his-application/target/*.jar --spring.profiles.active=dev
```
### 前端开发速查
```bash
# 开发模式
npm run dev
# 构建
npm run build:dev
# 测试
npm run test:run
# Lint
npm run lint
```
---
> **文档版本**: v2.0
> **最后更新**: 2026-06-06 (铁律18统一)
---
---
### 铁律 #9: 开发前必须审核原有代码
**任何新功能开发前,必须先搜索项目中是否已有相关代码。**
#### 搜索清单
| 搜索目标 | 搜索路径 | 命令 |
|---------|---------|------|
| 后端Controller | `healthlink-his-server/**/controller/` | `rg -l "关键词" ...` |
| AppService | `healthlink-his-server/**/appservice/` | 同上 |
| Service/ServiceImpl | `healthlink-his-server/**/service/` | 同上 |
| Mapper | `healthlink-his-server/**/mapper/` | 同上 |
| Entity/Domain | `healthlink-his-server/**/domain/` | 同上 |
| 前端页面 | `healthlink-his-ui/src/views/` | 同上 |
| 前端API | `healthlink-his-ui/src/api/` | 同上 |
| 数据库表 | Flyway迁移脚本 | `rg "CREATE TABLE" ...` |
#### 判定规则
| 情况 | 处理方式 |
|------|---------|
| 后端+前端都已有 | 审查现有实现,找出缺陷/遗漏,在原基础上优化 |
| 只有后端,前端缺失 | 只补前端页面调用现有API |
| 只有前端,后端缺失 | 只补后端接口前端API对齐 |
| 前端壳子存在但功能不完整 | 分析壳子现有逻辑,补充完善 |
| 后端接口存在但业务逻辑不完整 | 在原Service基础上扩展不新建 |
| 完全没有 | 从零开发,但先检查是否有可复用的组件/工具类 |
#### 禁止行为
- ❌ 不看代码就新建Controller/Service
- ❌ 已有功能重复实现
- ❌ 废弃原有代码另写一套
- ❌ 创建与现有模块功能重叠的新模块
---
---
---
---
### 铁律 #13: 开发必须深度分析+深度设计,禁止浅层糊弄
**如果一个模块不能在真实医院环境中使用,就不算完成。**
#### 禁止行为(红线)
| ❌ 禁止 | 说明 |
|---------|------|
| 写空壳页面就宣称"功能完成" | 页面有内容但没有实际业务逻辑 |
| 只做CRUD就宣称"模块开发完毕" | 缺少业务规则/状态流转/异常处理 |
| 设计文档只有标题没有内容 | 设计文档是"施工图纸",必须有实质内容 |
| 接口只返回200不验证业务逻辑 | 测试必须验证业务正确性不只是HTTP状态码 |
| 前端只有表格没有交互 | 缺少搜索/筛选/分页/操作反馈/空状态 |
| 后端没有参数校验 | 缺少必填校验/格式校验/业务规则校验 |
#### 每个模块必须达到的标准
| 维度 | 必须具备 | 自检方法 |
|------|---------|---------|
| **前端** | 搜索/筛选/分页/新增编辑弹窗/操作反馈/空状态/加载态 | 能否正常操作每个功能 |
| **后端** | 参数校验/业务规则校验/异常处理/日志记录 | 能否处理正常+异常场景 |
| **数据** | 完整字段/关联关系/索引/Flyway迁移 | 数据库能否支撑业务 |
| **业务** | 正常流程/异常流程/边界场景/状态机 | 能否覆盖真实业务场景 |
| **设计** | 业务背景/流程图/规则清单/时序图/测试用例 | 设计文档是否可执行 |
| **测试** | 接口测试/业务逻辑测试/异常测试 | 能否在真实环境使用 |
#### 质量自检清单
开发完成后必须回答以下问题:
```
□ 这个模块放到医院里,医生/护士/收费员能直接用吗?
□ 搜索条件是否覆盖了真实使用场景?
□ 表单校验是否覆盖了所有必填项和格式要求?
□ 操作反馈是否清晰(成功/失败/加载中/空数据)?
□ 后端是否有完整的参数校验和业务规则校验?
□ 异常场景(网络断开/数据不存在/权限不足)是否处理?
□ 状态流转是否完整(每个状态都能正确转换)?
□ 设计文档是否足够详细,其他人能据此开发?
□ 测试用例是否覆盖了正常流程和异常流程?
□ 接口返回的数据结构是否前后端对齐?
```
#### 深度设计文档标准
| 文档部分 | 最低要求 | 优秀标准 |
|---------|---------|---------|
| 业务背景 | 说明做什么 | 说明为什么做+参考什么标准 |
| 业务流程 | 正常流程文字描述 | 正常+异常+边界+流程图 |
| 状态流转 | 状态列表 | 状态机图+转换条件+权限 |
| 业务规则 | 规则名称 | 规则编号+描述+触发时机+处理方式 |
| 数据模型 | 表名+字段 | ER图+字段说明+索引+关联 |
| 接口设计 | API路径 | 请求/响应示例+错误码+版本 |
| 前端设计 | 页面列表 | UI线框+交互时序+组件选型 |
| 测试用例 | 功能清单 | 正常/异常/边界/性能测试用例 |
---
### 铁律 #12: 模块优化必须分析现有业务流并说明促进作用
**任何模块新增/优化前,必须先分析现有业务流程全貌。**
#### 必须回答的5个问题
| # | 问题 | 说明 |
|---|------|------|
| 1 | 该模块在整体业务流中处于什么位置? | 上游/下游/并行 |
| 2 | 该模块与哪些现有模块有数据流转关系? | 列出所有关联模块 |
| 3 | 优化对上下游模块有什么促进作用? | 减少重复、提升一致性、加快流程 |
| 4 | 变更是否影响现有业务流程? | 兼容性评估 |
| 5 | 业务规则是否与现有模块冲突? | 规则一致性检查 |
#### 业务逻辑分析文档模板
```
# 模块名 — 业务逻辑分析
## 1. 整体业务流程定位
[该模块在HIS系统中的位置上下游关系图]
## 2. 关联模块分析
| 关联模块 | 数据流向 | 交互方式 | 影响程度 |
|---------|---------|---------|---------|
## 3. 优化促进作用
| 维度 | 优化前 | 优化后 | 提升效果 |
|------|--------|--------|---------|
## 4. 兼容性评估
- 对现有模块的影响
- 数据迁移需求
- 接口变更影响
## 5. 规则一致性检查
- 新增规则是否与现有规则冲突
- 状态流转是否与现有状态机兼容
```
---
### 铁律 #11: 模块设计必须分析业务逻辑不能只做CRUD
**任何新模块/功能开发前,必须先进行业务逻辑分析和梳理。**
#### 禁止行为
- ❌ 拿到需求就直接写CRUD不思考业务流程
- ❌ 不查阅标准规范就开发医疗业务模块
- ❌ 没有设计文档就直接编码
- ❌ 把"能增删改查"当成"功能完成"
#### 必须完成的设计步骤
| # | 步骤 | 产出物 | 说明 |
|---|------|--------|------|
| 1 | 查阅标准规范 | 参考文档清单 | 国家卫健委标准、医保局规范、HL7/FHIR、三甲评审标准 |
| 2 | 梳理业务流程 | 流程图/文字描述 | 正常流程 + 异常流程 + 边界场景 |
| 3 | 设计状态流转 | 状态机图 | 每个实体的生命周期、状态转换条件 |
| 4 | 定义业务规则 | 规则清单 | 如:药品相互作用规则、医保审核规则、危急值判定规则 |
| 5 | 设计交互时序 | 时序图 | 用户操作 → 前端事件 → API → 后端处理 → 持久化 → 响应 |
| 6 | 编写设计文档 | MD文件 | 保存到 `MD/specs/``MD/architecture/` |
#### 医疗HIS业务逻辑参考标准
| 标准/规范 | 适用模块 | 获取途径 |
|----------|---------|---------|
| 三级医院评审标准(2022版) | 全量 | 卫健委官网 |
| 电子病历应用水平分级评价 | 电子病历/质控 | 卫健委官网 |
| 互联互通标准化成熟度测评 | ESB/集成平台 | 卫健委官网 |
| 医保基金使用监督管理条例 | 医保审核/结算 | 医保局官网 |
| HL7 FHIR R4 | 数据交换/ESB | hl7.org |
| 处方管理办法 | 合理用药/处方 | 卫健委官网 |
| 抗菌药物临床应用管理办法 | 抗菌药物管理 | 卫健委官网 |
| 医院感染管理办法 | 院感管理 | 卫健委官网 |
| 病案管理与质量控制标准 | 病案管理 | 卫健委官网 |
#### 设计文档模板
```
# 模块名 设计文档
## 1. 业务背景
- 依据什么标准/规范
- 解决什么业务问题
## 2. 业务流程
### 2.1 正常流程
[流程描述/流程图]
### 2.2 异常流程
[异常场景及处理方式]
### 2.3 边界场景
[特殊情况处理]
## 3. 状态流转
| 状态 | 值 | 触发条件 | 下一状态 |
|------|-----|---------|---------|
## 4. 业务规则
| 规则编号 | 规则名称 | 规则描述 | 触发时机 |
|---------|---------|---------|---------|
## 5. 数据模型
[实体关系图/表结构设计]
## 6. 接口设计
[API列表+参数+返回值]
## 7. 前端页面设计
[UI布局+交互+调用流程]
## 8. 测试用例
[关键业务场景测试]
```
---
### 铁律 #10: 设计文档必须包含UI设计和调用流程
**所有新模块/页面的设计文档必须包含以下要素,缺一不可:**
#### 必备要素
| # | 要素 | 说明 |
|---|------|------|
| 1 | 页面UI布局 | 每个区域放什么组件、尺寸比例、栅格布局(文字描述或线框图) |
| 2 | 交互效果清单 | 每个按钮/操作触发什么效果(弹窗、抽屉、跳转、动画) |
| 3 | 前后端调用流程 | 每个用户操作 → 对应API → 参数 → 返回数据 → 前端渲染 |
| 4 | 系统调用关系 | Controller → AppService → Service → Mapper 完整链路 |
| 5 | 方法函数调用关系 | 关键方法签名、参数、返回值、异常处理 |
| 6 | 状态流转图 | 数据状态变化 → UI如何响应 |
| 7 | 异常/边界处理 | 空数据、加载中、错误状态的UI表现 |
#### 前后端调用流程模板
```
用户操作: [具体按钮/操作]
→ 前端: [HTTP方法] [API路径] {参数}
→ 后端: Controller.method() → AppService.method() → Service.method() → Mapper.method()
→ 返回: {code, msg, data}
→ 前端: [渲染逻辑]
```
#### 详细规范
参见 `MD/specs/UI_DESIGN_IRON_RULES.md`
### 铁律18: 禁止破坏原有功能(绝对铁律)
**原则**: 完善增加功能和流程时,绝对不能破坏或者让原有功能不能用。
**执行要求**:
1. **修改已有实体前必须对比**: 用 `git show HEAD~N:./file.java` 对比原始文件,保留所有原有字段和方法
2. **新增字段只能追加**: 在实体类末尾追加新字段,不能删除或重命名已有字段
3. **新增方法只能追加**: 在Service接口末尾追加新方法不能修改已有方法签名
4. **SQL迁移只能ADD**: Flyway迁移脚本只允许 `ALTER TABLE ADD COLUMN`,不允许 `DROP COLUMN``RENAME COLUMN`
5. **Controller新端点**: 新增 `@PostMapping` / `@GetMapping`,不能修改已有端点的路径或参数
6. **前端新页面**: 新增页面目录,不能修改已有页面的组件结构
7. **编译必须通过**: 每次修改后必须 `mvn clean compile -DskipTests` 验证
8. **回归验证**: 修改后检查所有引用该类/方法的文件是否仍能编译
**违规判定**: 如果因为本次修改导致原有代码编译失败或运行报错视为违反铁律18必须立即回滚修复。
**铁律编号**: 18
**优先级**: P0绝对
**适用范围**: 全项目

View File

@@ -0,0 +1,91 @@
# 医嘱管理模块设计文档
> **文档类型**: 业务设计
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **依据标准**: 《三级医院评审标准(2022版)》医嘱管理制度
---
## 一、业务背景
医嘱管理是住院诊疗的核心环节。依据《病历书写基本规范》和《处方管理办法》,医嘱必须经过开具→审核→执行→完成的完整闭环。
---
## 二、状态流转
### 2.1 医嘱状态机
```
新开(0) → 已签发(1) → 执行中(2) → 已完成(3)
已停止(4) → 已取消停嘱(恢复)(2)
已签退(5)
```
| 状态 | 值 | 触发条件 | 允许操作 |
|------|-----|---------|---------|
| 新开 | 0 | 医生新开医嘱 | 签发/删除 |
| 已签发 | 1 | 医生签发 | 护士执行/签退 |
| 执行中 | 2 | 护士开始执行 | 停止/完成 |
| 已完成 | 3 | 执行完毕 | 查看 |
| 已停止 | 4 | 医生停止医嘱 | 恢复(取消停嘱) |
| 已签退 | 5 | 护士签退 | 查看 |
---
## 三、业务规则
| 规则编号 | 规则名称 | 规则描述 | 触发时机 |
|---------|---------|---------|---------|
| OR-001 | 长期医嘱停止时限 | 长期医嘱停止必须在执行时间之前2小时 | 停止医嘱时 |
| OR-002 | 用药医嘱审核 | 用药医嘱必须经过合理用药系统审核 | 签发用药医嘱时 |
| OR-003 | 医嘱查对 | 执行医嘱前必须双人查对 | 护士执行时 |
| OR-004 | 紧急医嘱标识 | 紧急医嘱需要特殊标识和优先执行 | 开具医嘱时 |
| OR-005 | 医嘱修改限制 | 已签发的医嘱不能修改,只能停止后新开 | 修改医嘱时 |
| OR-006 | 皮试医嘱联动 | 需要皮试的药物必须关联皮试医嘱 | 开具需皮试药物时 |
---
## 四、前后端交互时序
### 4.1 签发医嘱
```
用户操作: 医生点击"签发医嘱"
→ 前端: 收集选中医嘱列表
→ API: POST /reg-doctorstation/advice-manage/sign-reg-advice
→ 后端: AdviceManageController.signRegAdvice()
→ 校验医嘱状态必须为"新开"(OR-005)
→ 用药医嘱调用合理用药系统审核(OR-002)
→ 设置签发时间+签发人
→ 更新状态=已签发(1)
→ 返回: {code:200, msg:"签发成功"}
→ 前端: 刷新医嘱列表
```
### 4.2 停止医嘱
```
用户操作: 医生点击"停止医嘱"
→ 前端: 弹出确认框+填写停嘱原因
→ API: POST /reg-doctorstation/advice-manage/stop-reg-advice
→ 后端: 校验医嘱状态必须为"执行中"
→ 长期医嘱校验停止时限(OR-001)
→ 设置停嘱时间+停嘱原因
→ 更新状态=已停止(4)
→ 返回: {code:200, msg:"停嘱成功"}
```
---
## 五、测试用例
| 用例编号 | 场景 | 预期结果 |
|---------|------|---------|
| TC-O001 | 正常签发流程 | 新开→签发→执行→完成 |
| TC-O002 | 签发后修改 | 返回"已签发医嘱不能修改" |
| TC-O003 | 停止后恢复 | 已停止→恢复→执行中 |
| TC-O004 | 用药审核拦截 | 有相互作用的药物签发时被拦截 |
| TC-O005 | 紧急医嘱优先 | 紧急医嘱在列表中高亮显示 |

View File

@@ -0,0 +1,223 @@
# HIS项目 Playwright E2E 自动化测试方案 v1.0
> **文档类型**: 技术规范
> **适用范围**: E2E测试
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 一、方案概述
### 1.1 选型理由
- **Playwright** 是微软开源的端到端测试框架,完美适配 Vue 3 + Vite 技术栈
- 自动等待机制适合HIS系统复杂交互场景异步加载、动态渲染
- 支持多浏览器Chromium/Firefox/WebKitCI/CD集成成熟
- 已有 `@playwright/test ^1.58.2` 依赖 installed
### 1.2 目标
1. 核心业务流程自动化覆盖率达到 80%+
2. 已修复Bug 100% 回归测试覆盖
3. 每次代码推送自动触发测试,失败阻断发布
## 二、项目结构
```
healthlink-his-ui/
├── tests/
│ ├── e2e/
│ │ ├── fixtures/ # 测试夹具
│ │ │ └── auth.ts # 登录认证fixture
│ │ ├── pages/ # 页面对象模型POM
│ │ │ ├── LoginPage.ts
│ │ │ ├── DoctorStationPage.ts
│ │ │ └── SurgeryBillingPage.ts
│ │ ├── specs/ # 测试用例
│ │ │ ├── login.spec.ts
│ │ │ ├── doctor-station.spec.ts
│ │ │ ├── surgery-billing.spec.ts
│ │ │ └── bug-regression.spec.ts # Bug回归测试
│ │ └── utils/
│ │ └── test-data.ts # 测试数据
│ └── playwright.config.ts # Playwright配置
├── .env.test # 测试环境变量
└── package.json # 已有playwright依赖
```
## 三、环境配置
### 3.1 环境变量(.env.test
```bash
# 测试环境配置
VITE_APP_BASE_API=http://192.168.110.253:8080
TEST_USERNAME=test_admin
TEST_PASSWORD=test123456
TEST_BASE_URL=http://localhost:80
```
### 3.2 Playwright配置playwright.config.ts
```typescript
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e/specs',
timeout: 60 * 1000,
expect: { timeout: 10000 },
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: 1,
reporter: [['html', { outputFolder: 'playwright-report' }], ['list']],
use: {
baseURL: process.env.TEST_BASE_URL || 'http://localhost:80',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
],
});
```
## 四、核心测试用例
### 4.1 登录测试login.spec.ts
```typescript
import { test, expect } from '@playwright/test';
test('用户登录成功', async ({ page }) => {
await page.goto('/');
await page.fill('input[placeholder="请输入用户名"]', process.env.TEST_USERNAME || 'admin');
await page.fill('input[placeholder="请输入密码"]', process.env.TEST_PASSWORD || '123456');
await page.click('button:has-text("登录")');
await expect(page).toHaveURL(/.*dashboard.*/);
await expect(page.locator('.user-avatar')).toBeVisible();
});
test('登录失败-错误密码', async ({ page }) => {
await page.goto('/');
await page.fill('input[placeholder="请输入用户名"]', 'admin');
await page.fill('input[placeholder="请输入密码"]', 'wrongpassword');
await page.click('button:has-text("登录")');
await expect(page.locator('.el-message--error')).toBeVisible();
});
```
### 4.2 门诊医生站测试doctor-station.spec.ts
```typescript
import { test, expect } from '@playwright/test';
test.describe('门诊医生站', () => {
test.beforeEach(async ({ page }) => {
// 登录
await page.goto('/');
await page.fill('input[placeholder="请输入用户名"]', process.env.TEST_USERNAME || 'admin');
await page.fill('input[placeholder="请输入密码"]', process.env.TEST_PASSWORD || '123456');
await page.click('button:has-text("登录")');
await page.waitForURL(/.*dashboard.*/);
});
test('#427 检查项目分类手风琴展开', async ({ page }) => {
await page.goto('/doctorstation');
// 点击第一个分类
await page.click('.category-item >> nth=0');
await expect(page.locator('.category-content >> nth=0')).toBeVisible();
// 点击第二个分类,第一个应收起
await page.click('.category-item >> nth=1');
await expect(page.locator('.category-content >> nth=0')).not.toBeVisible();
await expect(page.locator('.category-content >> nth=1')).toBeVisible();
});
});
```
### 4.3 手术计费回归测试bug-regression.spec.ts
```typescript
import { test, expect } from '@playwright/test';
test.describe('Bug回归测试', () => {
test('#437 手术计费防重复提交', async ({ page }) => {
// 登录并导航到手术计费
await page.goto('/');
await page.fill('input[placeholder="请输入用户名"]', process.env.TEST_USERNAME || 'admin');
await page.fill('input[placeholder="请输入密码"]', process.env.TEST_PASSWORD || '123456');
await page.click('button:has-text("登录")');
await page.waitForURL(/.*dashboard.*/);
await page.goto('/surgery-billing');
// 快速连续点击新增按钮(测试防重复锁)
const addBtn = page.locator('button:has-text("新增")');
await addBtn.click();
await addBtn.click(); // 第二次应被阻止
await addBtn.click(); // 第三次应被阻止
// 验证只弹出一个表单
await expect(page.locator('.el-dialog')).toHaveCount(1);
});
});
```
## 五、执行命令
```bash
# 安装浏览器
npx playwright install chromium
# 运行所有测试
npm run test:e2e
# 运行单个测试文件
npx playwright test login.spec.ts
# 生成HTML报告
npx playwright show-report
# UI模式调试用
npx playwright test --ui
```
## 六、CI/CD集成
### 6.1 package.json脚本
```json
{
"scripts": {
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"test:e2e:report": "playwright show-report"
}
}
```
### 6.2 Spug流水线集成
```yaml
# Spug 构建后阶段添加
- name: E2E Testing
script: |
cd healthlink-his-ui
npx playwright install --with-deps chromium
npm run test:e2e -- --reporter=html
# 测试失败则阻断发布
if [ $? -ne 0 ]; then
echo "E2E测试失败阻断发布"
exit 1
fi
```
## 七、实施计划
| 阶段 | 时间 | 内容 | 负责人 |
|------|------|------|--------|
| Phase 1 | 第1周 | 登录+核心页面冒烟测试 | 张飞+赵云 |
| Phase 2 | 第2-3周 | 门诊医生站+手术计费全流程 | 张飞 |
| Phase 3 | 第4周 | Bug回归测试全覆盖 | 张飞 |
| Phase 4 | 第5周 | CI/CD流水线集成 | 赵云+运维 |
## 八、注意事项
1. **测试数据隔离**:使用独立的测试数据库,不污染生产数据
2. **环境变量**:敏感信息通过 `.env.test` 管理不提交到git
3. **截图留痕**:失败时自动截图,便于排查
4. **测试优先**:新功能开发时同步编写测试用例

View File

@@ -0,0 +1,290 @@
# 术前讨论记录模块设计文档
> **文档类型**: 深度业务设计
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **三甲依据**: 《三级医院评审标准(2022版)》手术分级管理制度 — 三级/四级手术必须有术前讨论记录
> **评审条款**: 现场检查必查项,缺失则一票否决
---
## 一、业务背景
### 1.1 为什么要术前讨论?
术前讨论是手术安全管理的核心制度。依据《医疗质量安全核心制度要点》2018版
- **三级手术**:必须有术前讨论,由副主任医师及以上主持
- **四级手术**:必须有科内讨论+全科讨论,由科主任主持
- 术前讨论记录是病历的必要组成部分,评审专家现场必查
### 1.2 当前系统差距
当前系统已有手术管理模块(申请→审批→安排→执行),但缺少**术前讨论记录**这一关键环节。评审时如果手术病历中没有术前讨论记录,将被判定为不合格。
### 1.3 参考标准
- 《医疗质量安全核心制度要点》2018版第5条术前讨论制度
- 《病历书写基本规范》2010版手术记录要求
- 《三级医院评审标准2022版手术质量安全核心指标
- 《手术分级管理办法》:手术分级与讨论要求对应关系
---
## 二、完整业务流程
### 2.1 术前讨论全流程
```
医生提交手术申请
系统判断手术级别
├── 一级/二级手术 → 无需术前讨论(可选)
└── 三级/四级手术 → 强制要求术前讨论
创建术前讨论记录
邀请讨论参与者至少2人
讨论内容录入
├── 患者基本信息(自动带入)
├── 术前诊断(关联诊断模块)
├── 手术名称和指征
├── 手术方案(主方案+备选方案)
├── 麻醉方式
├── 术中可能风险及对策
├── 术后注意事项
└── 讨论结论(同意手术/需进一步检查/暂不手术)
参与者签名(电子签名)
主持人审核确认
绑定到手术申请
手术申请可继续流转(审批→安排→执行)
```
### 2.2 异常流程
| 场景 | 处理方式 |
|------|---------|
| 讨论结论为"暂不手术" | 手术申请状态变为"讨论后暂停",需修改后重新讨论 |
| 讨论结论为"需进一步检查" | 手术申请状态变为"待补充检查",检查完成后重新讨论 |
| 参与者不足(三级手术<2人 | 拦截提交提示"三级手术术前讨论至少需要2名医师参与" |
| 四级手术主持人非科主任 | 拦截提交提示"四级手术必须由科主任主持讨论" |
| 术前讨论记录缺失时尝试安排手术 | 系统拦截提示"请先完成术前讨论" |
---
## 三、状态流转
### 3.1 术前讨论记录状态
```
草稿(0) → 待签名(1) → 待审核(2) → 已完成(3) → 已归档(4)
已驳回(5) → 草稿(0)
```
| 状态 | | 触发条件 | 允许操作 |
|------|-----|---------|---------|
| 草稿 | 0 | 创建讨论记录 | 编辑/删除/提交签名 |
| 待签名 | 1 | 提交参与者签名 | 参与者签名 |
| 待审核 | 2 | 所有参与者已签名 | 主持人审核 |
| 已完成 | 3 | 主持人审核通过 | 绑定手术/查看 |
| 已归档 | 4 | 手术完成自动归档 | 查看 |
| 已驳回 | 5 | 主持人驳回 | 编辑后重新提交 |
---
## 四、业务规则
| 规则编号 | 规则名称 | 规则描述 | 触发时机 | 处理方式 |
|---------|---------|---------|---------|---------|
| PD-001 | 三级手术讨论 | 三级手术必须有术前讨论记录 | 手术审批时 | 缺失则拦截 |
| PD-002 | 四级手术讨论 | 四级手术必须有科内讨论记录 | 手术审批时 | 缺失则拦截 |
| PD-003 | 主持人资质 | 三级手术副主任医师以上主持 | 创建讨论时 | 自动校验 |
| PD-004 | 四级手术主持人 | 四级手术必须由科主任主持 | 创建讨论时 | 自动校验 |
| PD-005 | 参与者人数 | 三级手术2人四级手术3人 | 提交时 | 不足则拦截 |
| PD-006 | 讨论时效 | 术前讨论必须在手术前24小时内完成 | 创建讨论时 | 超时则提醒 |
| PD-007 | 电子签名 | 所有参与者必须电子签名 | 审核前 | 未签则拦截 |
| PD-008 | 绑定手术 | 讨论完成后自动绑定到对应手术申请 | 审核通过时 | 自动关联 |
| PD-009 | 术前诊断一致性 | 讨论中的术前诊断必须与手术申请一致 | 提交审核时 | 不一致则警告 |
| PD-010 | 手术方案完整性 | 必须包含主方案+至少一个备选方案 | 提交时 | 缺失则拦截 |
---
## 五、数据模型
### 5.1 术前讨论记录表 `sys_preop_discussion`
| 字段 | 类型 | 说明 | 必填 |
|------|------|------|------|
| id | BIGSERIAL | 主键 | |
| encounter_id | BIGINT | 就诊ID | |
| surgery_id | BIGINT | 关联手术申请ID | |
| patient_id | BIGINT | 患者ID | |
| patient_name | VARCHAR(50) | 患者姓名 | |
| discussion_type | INT | 讨论类型(1科内讨论 2全科讨论 3全院讨论) | |
| surgery_level | INT | 手术级别(1/2/3/4) | |
| preop_diagnosis | TEXT | 术前诊断 | |
| surgery_name | VARCHAR(200) | 手术名称 | |
| surgery_indication | TEXT | 手术指征 | |
| main_plan | TEXT | 主手术方案 | |
| backup_plan | TEXT | 备选手术方案 | |
| anesthesia_type | VARCHAR(50) | 麻醉方式 | |
| risks_and_countermeasures | TEXT | 术中可能风险及对策 | |
| postop_notes | TEXT | 术后注意事项 | |
| discussion_conclusion | INT | 讨论结论(1同意手术 2需进一步检查 3暂不手术) | |
| discussion_result | TEXT | 讨论详细结果 | |
| host_user_id | BIGINT | 主持人用户ID | |
| host_user_name | VARCHAR(50) | 主持人姓名 | |
| status | INT | 状态(0草稿 1待签名 2待审核 3已完成 4已归档 5已驳回) | |
| discussion_time | TIMESTAMP | 讨论时间 | |
| discussion_location | VARCHAR(200) | 讨论地点 | |
### 5.2 术前讨论参与者表 `sys_preop_discussion_participant`
| 字段 | 类型 | 说明 | 必填 |
|------|------|------|------|
| id | BIGSERIAL | 主键 | |
| discussion_id | BIGINT | 关联讨论记录ID | |
| user_id | BIGINT | 参与者用户ID | |
| user_name | VARCHAR(50) | 参与者姓名 | |
| role | VARCHAR(20) | 角色(主持人/参与者/记录人) | |
| title | VARCHAR(50) | 职称(主任医师/副主任医师/主治医师) | |
| sign_status | INT | 签名状态(0未签 1已签) | |
| sign_time | TIMESTAMP | 签名时间 | |
| sign_image | TEXT | 签名图片(base64) | |
| opinion | TEXT | 个人意见 | |
---
## 六、接口设计
### 6.1 API列表
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /preop-discussion/add | 创建讨论记录 |
| PUT | /preop-discussion/update | 修改讨论记录 |
| GET | /preop-discussion/detail | 查看讨论详情 |
| GET | /preop-discussion/list | 查询讨论列表 |
| DELETE | /preop-discussion/delete | 删除讨论记录(仅草稿) |
| PUT | /preop-discussion/submit | 提交讨论(草稿待签名) |
| PUT | /preop-discussion/sign | 参与者签名 |
| PUT | /preop-discussion/review | 主持人审核(通过/驳回) |
| GET | /preop-discussion/check-required | 检查手术是否需要术前讨论 |
| GET | /preop-discussion/statistics | 讨论统计 |
### 6.2 核心接口时序
#### 创建术前讨论
```
前端: 弹出讨论表单 → 自动带入患者/手术信息
API: POST /preop-discussion/add
后端:
1. 校验手术级别(PD-001/PD-002)
2. 校验主持人资质(PD-003/PD-004)
3. 校验讨论时效(PD-006)
4. 保存讨论记录+参与者
5. 设置状态=草稿(0)
返回: {code:200, data:{discussionId}}
```
#### 主持人审核
```
前端: 主持人查看讨论内容 → 点击"审核通过"
API: PUT /preop-discussion/review
后端:
1. 校验当前用户是否为主持人
2. 校验所有参与者已签名(PD-007)
3. 校验参与者人数(PD-005)
4. 校验手术方案完整性(PD-010)
5. 更新状态=已完成(3)
6. 自动绑定到手术申请(PD-008)
返回: {code:200, msg:"审核通过"}
```
---
## 七、前端页面设计
### 7.1 页面布局
```
┌─────────────────────────────────────────────┐
│ 术前讨论管理 [新建讨论] │
├─────────────────────────────────────────────┤
│ 搜索区: [患者] [手术级别] [状态] [日期] [搜索] │
├─────────────────────────────────────────────┤
│ 表格: 序号|患者|手术名称|级别|主持人|状态|操作 │
│ 1 张三 阑尾切除 三级 李主任 已完成 │
├─────────────────────────────────────────────┤
│ 分页: < 1 2 3 > │
└─────────────────────────────────────────────┘
```
### 7.2 新建讨论弹窗(左右布局)
```
┌──────────────────────────┬────────────────────┐
│ 患者信息(自动带入) │ 讨论内容 │
│ 姓名: 张三 │ 术前诊断: [____] │
│ 住院号: 2026060001 │ 手术指征: [____] │
│ 科室: 普外科 │ 主方案: [____] │
│ 床号: 12床 │ 备选方案: [____] │
│ │ 麻醉方式: [____] │
│ 手术信息(自动带入) │ 风险及对策: [____] │
│ 手术名称: 阑尾切除术 │ 术后注意: [____] │
│ 手术级别: 三级 │ 讨论结论: [单选] │
│ 申请医生: 王医生 │ │
│ │ 讨论参与者: │
│ 讨论信息 │ □ 李主任(主持) │
│ 讨论时间: [____] │ □ 赵副主任 │
│ 讨论地点: [____] │ □ 孙主治 │
│ 讨论类型: [科内讨论] │ │
└──────────────────────────┴────────────────────┘
```
---
## 八、与手术管理模块的集成
### 8.1 数据关联
```
手术申请(Surgery) ──1:N──→ 术前讨论记录(PreopDiscussion)
术前讨论记录 ──1:N──→ 参与者(Participant)
```
### 8.2 流程集成
- **手术申请提交时**检查三级/四级手术是否有术前讨论
- **手术审批时**强制校验术前讨论完成状态
- **手术安排时**显示术前讨论结论
- **手术完成时**自动归档术前讨论记录
### 8.3 手术管理页面改造
在手术管理页面的"操作"列增加"术前讨论"按钮
- 三级/四级手术显示"查看讨论""新建讨论"
- 一级/二级手术显示"可选讨论"
---
## 九、测试用例
| 用例编号 | 场景 | 操作步骤 | 预期结果 |
|---------|------|---------|---------|
| TC-PD001 | 正常创建讨论 | 填写完整信息保存 | 状态=草稿,可编辑 |
| TC-PD002 | 三级手术强制讨论 | 三级手术不创建讨论直接审批 | 拦截提示"请先完成术前讨论" |
| TC-PD003 | 参与者不足 | 三级手术只邀请1人 | 拦截提示"至少需要2名医师" |
| TC-PD004 | 四级手术非科主任主持 | 主治医师主持四级手术讨论 | 拦截提示"必须由科主任主持" |
| TC-PD005 | 签名流程 | 所有参与者签名主持人审核 | 状态变为已完成 |
| TC-PD006 | 驳回后修改 | 主持人驳回修改重新提交 | 状态从驳回回到草稿 |
| TC-PD007 | 绑定手术 | 讨论完成关联手术申请 | 手术申请可继续流转 |
| TC-PD008 | 讨论时效校验 | 手术前48小时创建讨论 | 警告"请在手术前24小时内完成讨论" |

View File

@@ -0,0 +1,210 @@
# 病程记录模块设计文档
> **文档类型**: 深度业务设计
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **三甲依据**: 《病历书写基本规范》《电子病历应用管理规范》
---
## 一、业务背景
病程记录是住院病历的核心组成部分记录患者住院期间的诊疗过程。依据《病历书写基本规范》2010版
### 1.1 病程记录类型及时限要求
| 记录类型 | 书写时限 | 书写人要求 | 三甲依据 |
|---------|---------|-----------|---------|
| 首次病程记录 | 入院8小时内 | 住院医师及以上 | 病历书写规范 |
| 日常病程记录 | 病危每天至少1次 | 主治医师及以上 | 病历书写规范 |
| | 病重至少2天1次 | 住院医师及以上 | |
| | 一般至少3天1次 | 住院医师及以上 | |
| 上级医师查房记录 | 72小时内 | 主治/副主任/主任医师 | 三级查房制度 |
| 疑难病例讨论记录 | 确诊后及时 | 科主任主持 | 疑难病例讨论制度 |
| 阶段小结 | 住院超过30天 | 主管医师 | 病历书写规范 |
| 抢救记录 | 抢救后6小时内 | 参与抢救医师 | 危重患者抢救制度 |
| 转科记录 | 转科前 | 转出科医师 | 转科制度 |
| 接收记录 | 转科后 | 接收科医师 | 转科制度 |
| 出院记录 | 出院当天 | 主管医师 | 出院管理制度 |
| 死亡记录 | 死亡后24小时内 | 主管医师 | 死亡病例讨论制度 |
| 死亡病例讨论 | 死亡后7日内 | 科主任主持 | 死亡病例讨论制度 |
### 1.2 当前系统差距
当前系统有电子病历基础模块(模板+录入+签名),但缺少:
- 病程记录的**时限监控和预警**
- 病程记录的**自动提醒**
- 病程记录**完整性检查**
- 病程记录**质控统计**
---
## 二、完整业务流程
### 2.1 病程记录生命周期
```
入院
├──→ 首次病程记录(8小时内) ──→ 主治医师审核
├──→ 日常病程记录(按频率) ──→ 上级医师查阅
│ ├── 病危每天1次
│ ├── 病重2天1次
│ └── 一般3天1次
├──→ 上级医师查房记录(72小时内) ──→ 签名
├──→ [可选] 疑难病例讨论记录
├──→ [可选] 阶段小结(超过30天)
├──→ [可选] 抢救记录(6小时内)
├──→ [可选] 转科记录
├──→ 出院记录/死亡记录
└──→ 病历归档
```
### 2.2 时限监控流程
```
系统定时任务(每小时扫描)
检查每位住院患者的病程记录
├── 首次病程记录超时(>8小时)
│ → 红色预警 → 通知主管医师+科室主任
├── 日常病程记录超时
│ → 黄色预警 → 通知主管医师
├── 上级查房记录超时(>72小时)
│ → 橙色预警 → 通知上级医师+科室主任
└── 阶段小结超时(>30天)
→ 红色预警 → 通知主管医师+医务部
```
---
## 三、数据模型
### 3.1 病程记录表 `sys_progress_note`
| 字段 | 类型 | 说明 | 必填 |
|------|------|------|------|
| id | BIGSERIAL | 主键 | ✅ |
| encounter_id | BIGINT | 就诊ID | ✅ |
| patient_id | BIGINT | 患者ID | ✅ |
| patient_name | VARCHAR(50) | 患者姓名 | ✅ |
| note_type | INT | 记录类型(1首次 2日常 3上级查房 4疑难讨论 5阶段小结 6抢救 7转科 8接收 9出院 10死亡) | ✅ |
| note_content | TEXT | 记录内容(结构化) | ✅ |
| author_user_id | BIGINT | 书写人ID | ✅ |
| author_name | VARCHAR(50) | 书写人姓名 | ✅ |
| author_title | VARCHAR(50) | 书写人职称 | ✅ |
| review_user_id | BIGINT | 审核人ID(上级查房等) | ❌ |
| review_user_name | VARCHAR(50) | 审核人姓名 | ❌ |
| sign_status | INT | 签名状态(0未签 1已签) | ✅ |
| sign_time | TIMESTAMP | 签名时间 | ❌ |
| deadline | TIMESTAMP | 时限要求(系统自动计算) | ✅ |
| is_overdue | BOOLEAN | 是否超时 | ✅ |
| overdue_hours | INT | 超时小时数 | ❌ |
| template_id | BIGINT | 使用的模板ID | ❌ |
| version | INT | 版本号 | ✅ |
### 3.2 病程记录提醒表 `sys_progress_note_reminder`
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BIGSERIAL | 主键 |
| encounter_id | BIGINT | 就诊ID |
| patient_name | VARCHAR(50) | 患者姓名 |
| note_type | INT | 需要书写的记录类型 |
| deadline | TIMESTAMP | 截止时间 |
| status | INT | 状态(0待书写 1已书写 2已超时 3已提醒) |
| remind_user_id | BIGINT | 提醒对象 |
| remind_user_name | VARCHAR(50) | 提醒对象姓名 |
| created_time | TIMESTAMP | 创建时间 |
---
## 四、业务规则
| 规则编号 | 规则名称 | 规则描述 | 时限 |
|---------|---------|---------|------|
| PN-001 | 首次病程记录 | 入院后必须在8小时内完成 | 8小时 |
| PN-002 | 日常病程(病危) | 病危患者每天至少记录1次 | 24小时 |
| PN-003 | 日常病程(病重) | 病重患者至少2天记录1次 | 48小时 |
| PN-004 | 日常病程(一般) | 一般患者至少3天记录1次 | 72小时 |
| PN-005 | 上级查房记录 | 入院72小时内必须有上级医师查房记录 | 72小时 |
| PN-006 | 阶段小结 | 住院超过30天必须有阶段小结 | 30天 |
| PN-007 | 抢救记录 | 抢救后6小时内必须完成 | 6小时 |
| PN-008 | 出院记录 | 出院当天必须完成 | 当天 |
| PN-009 | 死亡记录 | 死亡后24小时内完成 | 24小时 |
| PN-010 | 死亡讨论 | 死亡后7日内完成讨论 | 7天 |
| PN-011 | 时限预警 | 超过时限前2小时自动提醒 | -2小时 |
| PN-012 | 超时上报 | 超过时限未完成自动上报科室主任 | 超时后 |
---
## 五、与现有模块的集成
### 5.1 与电子病历模块集成
- 病程记录使用电子病历的模板引擎
- 病程记录使用电子病历的签名机制
- 病程记录归档到电子病历系统
### 5.2 与护理评估集成
- 病危/病重标记由护理评估模块更新
- 标记变化自动调整病程记录频率
### 5.3 与病案管理集成
- 出院时自动检查病程记录完整性
- 缺失记录的病案不允许归档
---
## 六、前端页面设计
### 6.1 病程记录列表页
```
┌─────────────────────────────────────────────────┐
│ 病程记录管理 [新建记录] [时限监控面板] │
├─────────────────────────────────────────────────┤
│ 时限监控面板(顶部): │
│ 🔴 超时未完成: 3条 ⚠️ 即将超时: 5条 ✅ 正常: 42条│
├─────────────────────────────────────────────────┤
│ 搜索: [患者] [记录类型] [书写人] [日期] [搜索] │
├─────────────────────────────────────────────────┤
│ 表格: 患者|类型|内容摘要|书写人|时限|状态|操作 │
├─────────────────────────────────────────────────┤
│ 分页 │
└─────────────────────────────────────────────────┘
```
### 6.2 时限监控面板
```
┌──────────────────────────────────────────────────┐
│ 当前住院患者病程记录监控 │
├────────┬──────┬──────┬──────┬──────┬──────────────┤
│ 患者 │ 病情 │ 已记录│ 待记录│ 超时 │ 操作 │
├────────┼──────┼──────┼──────┼──────┼──────────────┤
│ 张三 │ 病危 │ 5/5 │ 0 │ 0 │ [查看] │
│ 李四 │ 一般 │ 2/3 │ 1 │ 0 │ [催促书写] │
│ 王五 │ 病重 │ 1/2 │ 1 │ 1 │ [上报超时] │
└────────┴──────┴──────┴──────┴──────┴──────────────┘
```
---
## 七、测试用例
| 用例编号 | 场景 | 预期结果 |
|---------|------|---------|
| TC-PN001 | 首次病程记录8小时提醒 | 入院6小时后黄色预警8小时后红色预警 |
| TC-PN002 | 日常病程记录频率 | 病危患者24小时未记录系统自动提醒 |
| TC-PN003 | 上级查房记录 | 入院72小时内无上级查房记录上报科室主任 |
| TC-PN004 | 阶段小结 | 住院30天无阶段小结红色预警+上报医务部 |
| TC-PN005 | 出院病程完整性 | 出院时检查所有病程记录是否完整 |
| TC-PN006 | 超时统计 | 科室/全院病程记录超时率统计 |

View File

@@ -0,0 +1,608 @@
# 影像3D重建 — 深度技术设计文档
> **文档类型**: 深度技术设计
> **版本**: v1.0
> **编制日期**: 2026-06-07
> **技术栈**: Cornerstone.js(DICOM解析) + VTK.js(3D渲染) + Spring Boot(后端处理)
---
## 一、技术选型分析
### 1.1 前端3D渲染方案对比
| 方案 | 优点 | 缺点 | 推荐度 |
|------|------|------|--------|
| **Cornerstone.js + VTK.js** | 专为医学影像设计DICOM原生支持WebGL GPU加速 | 学习曲线较陡 | ⭐⭐⭐⭐⭐ |
| **Three.js** | 通用3D引擎社区大 | 无DICOM支持需自行解析 | ⭐⭐⭐ |
| **OHIF Viewer** | 完整PACS查看器 | 太重,集成复杂 | ⭐⭐⭐ |
| **MITK** | 功能全面的医学影像工具包 | C++为主Web支持弱 | ⭐⭐ |
**推荐方案**: Cornerstone.js + VTK.js
- **Cornerstone.js**: DICOM图像解析、2D查看、MPR重建
- **VTK.js**: 容积渲染(VR)、等值面提取、3D测量
### 1.2 技术架构
```
┌─────────────────────────────────────────────────────────┐
│ 前端 (Vue 3 + Vite) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │Cornerstone│ │ VTK.js │ │测量工具栏│ │报告编辑器│ │
│ │ DICOM解析 │ │ 3D渲染 │ │距离/角度 │ │所见/印象 │ │
│ │ 2D/MPR │ │VR/MIP │ │体积/面积 │ │结论 │ │
│ └─────┬────┘ └─────┬────┘ └────┬─────┘ └────┬────┘ │
│ └─────────────┴────────────┴──────────────┘ │
│ ↓ HTTP/REST API │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 后端 (Spring Boot 4.0.6) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │DICOM解析 │ │任务调度 │ │结果存储 │ │PACS对接 │ │
│ │dcm4che │ │异步处理 │ │MinIO/NFS │ │WADO-RS │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 存储层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │PostgreSQL │ │文件存储 │ │PACS系统 │ │
│ │ 元数据 │ │MinIO/NFS │ │DICOM节点 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
```
---
## 二、后端深度设计
### 2.1 DICOM解析服务
#### 2.1.1 dcm4che集成
```java
// DICOM文件解析流程
public class DicomParserService {
// 解析DICOM文件元数据
public DicomMetadata parseDicomFile(InputStream dicomStream) {
// 1. 使用dcm4che读取DICOM文件
Dataset ds = DicomInputStream.read(dicomStream);
// 2. 提取关键元数据
DicomMetadata metadata = new DicomMetadata();
metadata.setPatientName(ds.getString(Tag.PatientName)); // 患者姓名
metadata.setPatientId(ds.getString(Tag.PatientID)); // 患者ID
metadata.setStudyInstanceUID(ds.getString(Tag.StudyInstanceUID)); // 检查UID
metadata.setSeriesInstanceUID(ds.getString(Tag.SeriesInstanceUID)); // 序列UID
metadata.setSopInstanceUID(ds.getString(Tag.SOPInstanceUID)); // 实例UID
metadata.setModality(ds.getString(Tag.Modality)); // CT/MRI/US
metadata.setStudyDate(ds.getString(Tag.StudyDate)); // 检查日期
metadata.setBodyPartExamined(ds.getString(Tag.BodyPartExamined)); // 检查部位
metadata.setImageOrientationPatient(ds.getStrings(Tag.ImageOrientationPatient)); // 图像方向
metadata.setImagePositionPatient(ds.getStrings(Tag.ImagePositionPatient)); // 图像位置
metadata.setPixelSpacing(ds.getStrings(Tag.PixelSpacing)); // 像素间距
metadata.setSliceThickness(ds.getString(Tag.SliceThickness)); // 层厚
metadata.setRows(ds.getInt(Tag.Rows)); // 行数
metadata.setColumns(ds.getInt(Tag.Columns)); // 列数
metadata.setBitsAllocated(ds.getInt(Tag.BitsAllocated)); // 位深
metadata.setWindowCenter(ds.getString(Tag.WindowCenter)); // 窗位
metadata.setWindowWidth(ds.getString(Tag.WindowWidth)); // 窗宽
// 3. 提取像素数据
byte[] pixelData = ds.getBytes(Tag.PixelData);
metadata.setPixelData(pixelData);
return metadata;
}
// 批量解析同一Series的所有DICOM文件
public List<DicomMetadata> parseSeries(List<InputStream> dicomFiles) {
List<DicomMetadata> series = new ArrayList<>();
for (InputStream file : dicomFiles) {
series.add(parseDicomFile(file));
}
// 按ImagePositionPatient排序(确保层序正确)
series.sort(Comparator.comparing(m ->
Double.parseDouble(m.getImagePositionPatient()[2])));
return series;
}
}
```
#### 2.1.2 3D重建处理服务
```java
// 3D重建处理服务
@Service
public class ReconstructionProcessingService {
@Async("reconstructionExecutor")
public void processReconstruction(Long taskId) {
// 1. 获取任务信息
ReconstructionTask task = taskMapper.selectById(taskId);
task.setTaskStatus("PROCESSING");
taskMapper.updateById(task);
try {
// 2. 加载DICOM序列数据
List<DicomMetadata> series = loadDicomSeries(task.getApplyId());
// 3. 预处理: 去噪 + 窗宽窗位调整
float[][][] volumeData = preprocessVolume(series);
// 4. 根据重建类型执行
switch (task.getReconstructionType()) {
case "VR": // 容积渲染
processVolumeRendering(task, volumeData);
break;
case "MPR": // 多平面重建
processMPR(task, volumeData);
break;
case "MIP": // 最大密度投影
processMIP(task, volumeData);
break;
case "VR+MPR": // 混合重建
processVolumeRendering(task, volumeData);
processMPR(task, volumeData);
break;
}
// 5. 生成结果截图
saveResultImages(task);
// 6. 更新任务状态
task.setTaskStatus("COMPLETED");
task.setCompleteTime(new Date());
task.setResultPath("/reconstruction/" + taskId + "/");
taskMapper.updateById(task);
} catch (Exception e) {
task.setTaskStatus("FAILED");
taskMapper.updateById(task);
log.error("3D重建任务失败: {}", taskId, e);
}
}
// 容积渲染(Volume Rendering)
private void processVolumeRendering(ReconstructionTask task, float[][][] volume) {
// 1. 建立体数据(Volume Data)
int dimX = volume.length;
int dimY = volume[0].length;
int dimZ = volume[0][0].length;
// 2. 传递函数(Transfer Function)设置
// CT值 → 颜色+透明度
// 骨骼: 高CT值(>300), 不透明, 白色
// 软组织: 中CT值(30-300), 半透明, 粉色
// 空气: 低CT值(<-500), 全透明
TransferFunction tf = new TransferFunction();
tf.addMapping(-1000, 0.0f, 0.0f, 0.0f, 0.0f); // 空气: 全透明
tf.addMapping(-500, 0.0f, 0.0f, 0.0f, 0.0f); // 肺: 全透明
tf.addMapping(30, 0.8f, 0.2f, 0.2f, 0.4f); // 软组织: 半透明粉红
tf.addMapping(300, 0.9f, 0.9f, 0.8f, 0.9f); // 骨骼: 不透明白
tf.addMapping(3000, 1.0f, 1.0f, 1.0f, 1.0f); // 金属: 全不透明
// 3. 光线投射(Ray Casting)算法
// 从每个像素发射光线,沿光线采样,累积颜色和透明度
// C(积累) = Σ(Ci * αi * Π(1-αj))
// 4. 保存渲染结果为PNG
saveVolumeRenderingResult(task, tf);
}
// 多平面重建(Multi-Planar Reconstruction)
private void processMPR(ReconstructionTask task, float[][][] volume) {
// 1. 矢状面(Sagittal)重建: 沿X轴切割
float[][] sagittalPlane = extractSagittalPlane(volume, volume.length / 2);
// 2. 冠状面(Coronal)重建: 沿Y轴切割
float[][] coronalPlane = extractCoronalPlane(volume, volume[0].length / 2);
// 3. 轴位(Axial)重建: 沿Z轴切割(原始方向)
float[][] axialPlane = extractAxialPlane(volume, volume[0][0].length / 2);
// 4. 交互式切割: 支持任意角度平面
// 通过旋转矩阵变换采样坐标
saveMPRResult(task, sagittalPlane, coronalPlane, axialPlane);
}
// 最大密度投影(Maximum Intensity Projection)
private void processMIP(ReconstructionTask task, float[][][] volume) {
int dimX = volume.length;
int dimY = volume[0].length;
int dimZ = volume[0][0].length;
float[][] mipImage = new float[dimX][dimY];
for (int x = 0; x < dimX; x++) {
for (int y = 0; y < dimY; y++) {
float maxVal = Float.MIN_VALUE;
for (int z = 0; z < dimZ; z++) {
maxVal = Math.max(maxVal, volume[x][y][z]);
}
mipImage[x][y] = maxVal;
}
}
saveMIPResult(task, mipImage);
}
}
```
### 2.2 DICOM存储方案
```
存储架构:
├── PostgreSQL → 元数据(患者/检查/序列/任务/报告)
├── MinIO/NFS → DICOM原始文件 + 重建结果(截图/体数据)
└── PACS系统 → 通过WADO-RS/DICOMweb获取DICOM图像
获取DICOM数据流程:
1. 任务创建时 → 从PACS获取StudyUID对应的DICOM文件
2. 使用WADO-RS协议: GET /dicomweb/studies/{studyUid}/series/{seriesUid}
3. 下载到本地临时目录 → 解析 → 处理 → 清理临时文件
4. 重建结果保存到MinIO → 元数据保存到PostgreSQL
```
### 2.3 接口设计(完整版)
| API | 方法 | 说明 | 参数 |
|-----|------|------|------|
| /reconstruction/task/page | GET | 任务列表(分页+筛选) | patientName,modality,status,pageNo,pageSize |
| /reconstruction/task/add | POST | 新建任务(从PACS拉取) | patientId,studyUid,modality,bodyPart,reconstructionType |
| /reconstruction/task/{id} | GET | 任务详情 | - |
| /reconstruction/task/cancel/{id} | PUT | 取消任务 | - |
| /reconstruction/result/list/{taskId} | GET | 重建结果列表 | - |
| /reconstruction/result/{id}/image | GET | 获取结果截图 | width,height,window |
| /reconstruction/result/{id}/volume | GET | 获取体数据(JSON格式) | resolution |
| /reconstruction/report/add | POST | 新建报告 | taskId,findings,impression,conclusion |
| /reconstruction/report/{id} | GET | 报告详情 | - |
| /reconstruction/report/verify/{id} | PUT | 审核报告 | verifyDoctor |
| /reconstruction/stats | GET | 统计概览 | startDate,endDate |
---
## 三、前端深度设计
### 3.1 技术栈
```json
{
"cornerstone-core": "^2.6.1", // DICOM图像解析与2D显示
"cornerstone-wado-image-loader": "^4.13.2", // WADO加载器
"cornerstone-tools": "^7.1.0", // 交互工具(测量/标注)
"vtk.js": "^29.0.0", // 3D渲染引擎(WebGL)
"dicom-parser": "^1.8.21" // DICOM文件解析
}
```
### 3.2 组件架构
```
src/views/reconstruction/
├── index.vue # 主页面(任务列表+工作台)
├── api.js # API接口
├── components/
│ ├── DicomViewer.vue # 2D DICOM查看器(Cornerstone)
│ ├── MprViewer.vue # MPR多平面重建查看器
│ ├── VrViewer.vue # VR容积渲染查看器(VTK.js)
│ ├── MipViewer.vue # MIP最大密度投影查看器
│ ├── MeasurementToolbar.vue # 测量工具栏
│ ├── ReconstructionTaskList.vue # 任务列表
│ ├── ReconstructionReport.vue # 报告编辑器
│ └── ReconstructionStats.vue # 统计面板
```
### 3.3 核心组件实现
#### DicomViewer.vue (2D DICOM查看器)
```vue
<template>
<div class="dicom-viewer">
<div ref="viewerContainer" class="viewer-container" />
<div class="toolbar">
<el-button-group>
<el-button @click="setTool('windowing')">窗宽窗位</el-button>
<el-button @click="setTool('pan')">平移</el-button>
<el-button @click="setTool('zoom')">缩放</el-button>
<el-button @click="setTool('length')">距离测量</el-button>
<el-button @click="setTool('angle')">角度测量</el-button>
<el-button @click="setTool('area')">面积测量</el-button>
<el-button @click="setTool('ellipse')">椭圆面积</el-button>
<el-button @click="setTool('probe')">CT值探针</el-button>
</el-button-group>
</div>
<div class="info-overlay">
<div>Patient: {{ patientInfo.name }}</div>
<div>Window: {{ windowCenter }}/{{ windowWidth }}</div>
<div>Zoom: {{ zoomLevel }}</div>
</div>
</div>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
import * as cornerstone from 'cornerstone-core'
import * as cornerstoneTools from 'cornerstone-tools'
import * as cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
import dicomParser from 'dicom-parser'
// 初始化Cornerstone
cornerstoneWADOImageLoader.external.dicomParser = dicomParser
cornerstoneWADOImageLoader.external.cornerstone = cornerstone
const viewerContainer = ref(null)
let enabledElement = null
onMounted(() => {
// 启用Cornerstone
enabledElement = cornerstone.getEnabledElement(viewerContainer.value)
cornerstone.enable(viewerContainer.value)
// 加载DICOM图像
loadDicomImage()
})
const loadDicomImage = async () => {
const imageId = `wado:${wadoRoot}?requestType=WADO&studyUID=${studyUid}&seriesUID=${seriesUid}&objectUID=${sopUid}`
const image = await cornerstone.loadAndCacheImage(imageId)
cornerstone.displayImage(enabledElement, image)
// 启用工具
cornerstoneTools.mouseInput.enable(enabledElement)
cornerstoneTools.mouseWheelInput.enable(enabledElement)
cornerstoneTools.wwwc.activate(enabledElement, 1) // 左键: 窗宽窗位
cornerstoneTools.pan.activate(enabledElement, 2) // 右键: 平移
cornerstoneTools.zoom.activate(enabledElement, 4) // 中键: 缩放
cornerstoneTools.length.enable(enabledElement) // 距离测量
cornerstoneTools.angle.enable(enabledElement) // 角度测量
cornerstoneTools.ellipseRoi.enable(enabledElement) // 椭圆面积
cornerstoneTools.probe.enable(enabledElement) // CT值探针
}
const setTool = (toolName) => {
// 切换工具并高亮按钮
}
</script>
```
#### VrViewer.vue (VR容积渲染)
```vue
<template>
<div class="vr-viewer">
<div ref="vtkContainer" class="vtk-container" />
<div class="transfer-function-panel">
<div class="preset-buttons">
<el-button @click="applyPreset('bone')">骨骼</el-button>
<el-button @click="applyPreset('softTissue')">软组织</el-button>
<el-button @click="applyPreset('lung')">肺部</el-button>
<el-button @click="applyPreset('angio')">血管</el-button>
<el-button @click="applyPreset('skin')">皮肤</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, onUnmounted } from 'vue'
import vtkProxyManager from 'vtk.js/Sources/Proxy/ProxyManager'
let proxyManager = null
onMounted(() => {
initVtk()
})
const initVtk = () => {
// 创建VTK ProxyManager
proxyManager = vtkProxyManager.newInstance({ container: vtkContainer.value })
// 加载体数据
const source = proxyManager.createProxy('Sources', 'TrivialProducer')
source.setInputData(volumeData)
// 创建VR表示
const representation = proxyManager.createProxy('Representations', 'Volume')
representation.setInput(source)
// 设置传递函数
const actor = representation.getActor()
const property = actor.getProperty()
// 设置预设
applyPreset('bone')
}
const applyPreset = (preset) => {
const presets = {
bone: [
{ value: -1000, opacity: 0, color: [0, 0, 0] },
{ value: -300, opacity: 0, color: [0, 0, 0] },
{ value: 200, opacity: 0.2, color: [0.8, 0.4, 0.3] },
{ value: 500, opacity: 0.8, color: [1, 1, 1] },
{ value: 3000, opacity: 1, color: [1, 1, 1] }
],
softTissue: [
{ value: -1000, opacity: 0, color: [0, 0, 0] },
{ value: -500, opacity: 0, color: [0, 0, 0] },
{ value: 30, opacity: 0.3, color: [0.8, 0.3, 0.3] },
{ value: 100, opacity: 0.5, color: [0.9, 0.5, 0.5] },
{ value: 300, opacity: 0.8, color: [1, 0.8, 0.7] },
{ value: 3000, opacity: 1, color: [1, 1, 1] }
],
lung: [
{ value: -1000, opacity: 0.3, color: [0.2, 0.2, 0.3] },
{ value: -700, opacity: 0.1, color: [0.4, 0.4, 0.5] },
{ value: -300, opacity: 0.3, color: [0.6, 0.6, 0.7] },
{ value: 0, opacity: 0.8, color: [0.8, 0.8, 0.8] },
{ value: 3000, opacity: 1, color: [1, 1, 1] }
],
angio: [
{ value: -1000, opacity: 0, color: [0, 0, 0] },
{ value: 100, opacity: 0, color: [0, 0, 0] },
{ value: 200, opacity: 0.5, color: [1, 0, 0] },
{ value: 500, opacity: 0.9, color: [1, 0.2, 0.2] },
{ value: 3000, opacity: 1, color: [1, 0.5, 0.5] }
],
skin: [
{ value: -1000, opacity: 0, color: [0, 0, 0] },
{ value: -300, opacity: 0, color: [0, 0, 0] },
{ value: -100, opacity: 0.2, color: [0.9, 0.7, 0.6] },
{ value: 50, opacity: 0.5, color: [0.95, 0.8, 0.7] },
{ value: 200, opacity: 0.8, color: [1, 0.9, 0.85] },
{ value: 3000, opacity: 1, color: [1, 1, 1] }
]
}
// 应用传递函数到VTK actor
const preset = presets[preset] || presets.bone
applyTransferFunction(preset)
}
</script>
```
#### MeasurementToolbar.vue (测量工具)
```vue
<template>
<div class="measurement-toolbar">
<el-button-group>
<el-tooltip content="距离测量(Ctrl+D)">
<el-button :type="activeTool==='length'?'primary':''" @click="activateTool('length')">
<el-icon><Ruler /></el-icon> 距离
</el-button>
</el-tooltip>
<el-tooltip content="角度测量(Ctrl+A)">
<el-button :type="activeTool==='angle'?'primary':''" @click="activateTool('angle')">
<el-icon><ScaleToOriginal /></el-icon> 角度
</el-button>
</el-tooltip>
<el-tooltip content="面积测量(Ctrl+M)">
<el-button :type="activeTool==='area'?'primary':''" @click="activateTool('area')">
<el-icon><Grid /></el-icon> 面积
</el-button>
</el-tooltip>
<el-tooltip content="CT值探针(Ctrl+P)">
<el-button :type="activeTool==='probe'?'primary':''" @click="activateTool('probe')">
<el-icon><Position /></el-icon> CT值
</el-button>
</el-tooltip>
</el-button-group>
<!-- 测量结果列表 -->
<div class="measurement-results" v-if="measurements.length">
<el-table :data="measurements" size="small" border>
<el-table-column prop="type" label="类型" width="80"/>
<el-table-column prop="value" label="测量值" width="120"/>
<el-table-column prop="unit" label="单位" width="60"/>
<el-table-column label="操作" width="60">
<template #default="{row}">
<el-button type="danger" link size="small" @click="removeMeasurement(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import * as cornerstoneTools from 'cornerstone-tools'
const activeTool = ref('')
const measurements = ref([])
const activateTool = (toolName) => {
activeTool.value = toolName
// 禁用所有工具
cornerstoneTools.length.deactivate(enabledElement, 1)
cornerstoneTools.angle.deactivate(enabledElement, 1)
cornerstoneTools.ellipseRoi.deactivate(enabledElement, 1)
cornerstoneTools.probe.deactivate(enabledElement, 1)
// 激活选中工具
switch(toolName) {
case 'length':
cornerstoneTools.length.activate(enabledElement, 1)
break
case 'angle':
cornerstoneTools.angle.activate(enabledElement, 1)
break
case 'area':
cornerstoneTools.ellipseRoi.activate(enabledElement, 1)
break
case 'probe':
cornerstoneTools.probe.activate(enabledElement, 1)
break
}
}
</script>
```
---
## 四、数据库设计(补充)
### 4.1 补充字段
```sql
-- 在reconstruction_task表补充字段
ALTER TABLE reconstruction_task ADD COLUMN slice_count INT; -- 层数
ALTER TABLE reconstruction_task ADD COLUMN pixel_spacing_x DECIMAL(6,3); -- X像素间距
ALTER TABLE reconstruction_task ADD COLUMN pixel_spacing_y DECIMAL(6,3); -- Y像素间距
ALTER TABLE reconstruction_task ADD COLUMN table_position VARCHAR(50); -- 床位位置
ALTER TABLE reconstruction_task ADD COLUMN kvp INT; -- 管电压
ALTER TABLE reconstruction_task ADD COLUMN mas DECIMAL(8,2); -- 管电流时间积
-- 在reconstruction_result表补充字段
ALTER TABLE reconstruction_result ADD COLUMN rendering_time_ms INT; -- 渲染耗时
ALTER TABLE reconstruction_result ADD COLUMN file_size_bytes BIGINT; -- 文件大小
ALTER TABLE reconstruction_result ADD COLUMN thumbnail_path VARCHAR(500); -- 缩略图
```
---
## 五、部署架构
```
前端构建: npm run build → dist/ → Nginx
后端部署: Spring Boot JAR → Docker / 直接运行
存储: MinIO(对象存储) / NFS(文件系统)
PACS对接: WADO-RS / DICOM C-STORE
GPU加速: 前端WebGL(VTK.js自带) / 后端可选CUDA加速(处理大型数据集)
```
---
## 六、性能优化策略
### 6.1 前端优化
- **LOD(Level of Detail)**: 根据缩放级别加载不同分辨率
- **瓦片加载**: 大图像分块加载,减少内存占用
- **Web Worker**: DICOM解析和预处理在Worker线程执行
- **缓存策略**: Cornerstone缓存最近查看的图像
### 6.2 后端优化
- **异步处理**: 3D重建任务异步执行不阻塞请求
- **批量解析**: 一次IO读取整个Series的DICOM文件
- **结果缓存**: 重建结果缓存到Redis/文件系统
- **并行处理**: 多个重建任务并行执行
### 6.3 存储优化
- **压缩存储**: 体数据使用LZ4压缩
- **增量保存**: 只保存变化部分
- **分层存储**: 热数据SSD冷数据HDD
---
## 七、安全设计
1. **访问控制**: 只有影像科医生可以发起重建任务
2. **数据脱敏**: 患者敏感信息在非工作场景脱敏显示
3. **操作审计**: 所有重建操作记录审计日志
4. **数据加密**: DICOM文件传输使用HTTPS/TLS
5. **权限分级**: 普通医生查看,主治以上审核报告

584
MD/specs/RELEASE_CHECKLIST.md Executable file
View File

@@ -0,0 +1,584 @@
# HIS项目发布检查清单 v1.0
> **文档类型**: 技术规范
> **适用范围**: 发布流程
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
> **文档说明**本清单整合了提交规范、前端检查、后端检查、CI/CD门禁四个部分作为HIS项目发布的标准化检查依据。每次发布前必须逐项确认。
## 目录
- [1. 提交规范commit-template](#1-提交规范commit-template)
- [2. 前端检查frontend-checklist](#2-前端检查frontend-checklist)
- [3. 后端检查backend-checklist](#3-后端检查backend-checklist)
- [4. CI/CD门禁cicd-gatekeeper](#4-cicd门禁cicd-gatekeeper)
- [5. 发布确认与回滚预案](#5-发布确认与回滚预案)
---
## 1. 提交规范commit-template
### 📝 PR/Commit 模板
#### 标题格式
```
<类型>(<模块>): <简短描述>
示例:
feat(patient): 添加患者基本信息编辑功能
fix(doctor): 修复医生排班显示异常问题
docs(api): 更新预约挂号接口文档
refactor(nurse): 重构护士站护理记录组件
```
#### 正文模板
```markdown
## 🔍 变更背景
- **问题描述**:详细说明要解决的问题或实现的需求
- **影响范围**:列出受影响的模块、页面、功能
- **相关链接**禅道任务ID、需求文档链接等
## 🛠️ 变更内容
- **主要修改**:核心代码变更点
- **技术方案**:采用的技术方案和设计思路
- **兼容性**是否涉及API或数据结构变更
## 🗄️ 数据库变更
- **表结构变更**:列出新增/修改的表和字段
- **数据迁移**:是否需要数据迁移脚本
- **回滚方案**:数据库变更的回滚策略
## ✅ 验证情况
- **测试覆盖**:单元测试、集成测试覆盖情况
- **手动验证**:手动测试的场景和结果
- **构建验证**:本地构建截图(必填)
## 📋 检查清单
- [ ] 代码已通过 ESLint 检查
- [ ] 本地构建成功(附截图)
- [ ] 核心功能已测试验证
- [ ] 文档已同步更新
- [ ] Code Review 已完成
## 👥 相关人员
- **开发者**@开发者姓名
- **测试者**@测试者姓名
- **审核人**@架构师姓名
```
### 🏷️ 提交类型说明
| 类型 | 说明 | 示例 |
|------|------|------|
| feat | 新功能 | `feat: 添加用户登录功能` |
| fix | Bug修复 | `fix: 修复表单验证错误` |
| docs | 文档更新 | `docs: 更新API文档` |
| style | 代码格式调整 | `style: 格式化代码` |
| refactor | 代码重构 | `refactor: 重构组件结构` |
| test | 测试相关 | `test: 添加单元测试` |
| chore | 构建/依赖等 | `chore: 升级依赖版本` |
| perf | 性能优化 | `perf: 优化列表加载速度` |
### 📁 模块命名规范
| 模块 | 说明 |
|------|------|
| patient | 患者管理相关 |
| doctor | 医生工作站相关 |
| nurse | 护士站相关 |
| admin | 后台管理相关 |
| common | 公共组件/工具 |
| api | API接口相关 |
| auth | 认证授权相关 |
| payment | 支付相关 |
### 🖼️ 构建验证截图要求
#### 必须包含的信息
1. **终端窗口**:显示 `npm run build:prod` 命令执行过程
2. **成功标识**:明确显示构建成功的提示信息
3. **时间戳**:截图包含当前时间,证明是最新构建
4. **分支信息**:显示当前工作分支名称
### ⚠️ 禁止行为
#### 严重违规(直接拒绝合并)
- 无构建验证截图
- 代码存在 ESLint 错误
- 未填写变更说明
- 修改无关代码文件
---
## 2. 前端检查frontend-checklist
### 📋 基础检查项
#### 代码质量
- [ ] 代码已通过 ESLint 检查,无警告和错误
- [ ] 代码已通过 Prettier 格式化
- [ ] 无 console.log() 等调试代码残留
- [ ] 变量命名符合规范,语义清晰
- [ ] 函数职责单一,复杂度适中
#### 构建验证
- [ ] 本地执行 `npm run build:prod` 成功完成
- [ ] 构建产物无报错,体积合理
- [ ] 静态资源路径正确无404错误
- [ ] 环境变量配置正确(开发/测试/生产)
#### 功能验证
- [ ] 核心功能流程完整测试通过
- [ ] 边界条件和异常场景已覆盖
- [ ] 表单验证逻辑正确
- [ ] API 接口调用正常,错误处理完善
- [ ] 路由跳转逻辑正确
### 🔧 技术检查项
#### 模块导入检查
- [ ] 所有 import 语句引用的模块实际存在
- [ ] 无未使用的 import 导入
- [ ] 路径别名(@/)配置正确
- [ ] 第三方库版本兼容性确认
#### 性能优化
- [ ] 组件按需加载(懒加载)已配置
- [ ] 大数据列表已实现虚拟滚动或分页
- [ ] 图片资源已压缩,格式合适
- [ ] 无内存泄漏风险(事件监听器、定时器等)
#### 安全检查
- [ ] 用户输入已做 XSS 防护
- [ ] 敏感信息不在前端硬编码
- [ ] API 请求已做 CSRF 防护
- [ ] 权限控制逻辑正确
### 🌐 兼容性检查
#### 浏览器兼容
- [ ] 主流浏览器Chrome、Firefox、Safari、Edge显示正常
- [ ] 移动端适配良好(如适用)
- [ ] 分辨率适配1366x768、1920x1080等
#### 设备兼容
- [ ] 触摸设备操作体验良好
- [ ] 键盘导航支持完整
- [ ] 屏幕阅读器兼容性(无障碍)
### 📱 发布准备
#### 文档更新
- [ ] 相关 API 文档已同步更新
- [ ] 用户操作手册已更新(如适用)
- [ ] 变更日志已记录
#### 回滚预案
- [ ] 回滚方案已准备
- [ ] 数据兼容性已确认
- [ ] 紧急联系人已明确
### ✅ 最终确认
#### 发布前最后检查
- [ ] 本地构建截图已附在 PR 中
- [ ] 测试环境部署验证通过
- [ ] Code Review 已完成并获得批准
- [ ] 相关 Bug 已关闭或延期说明
---
## 3. 后端检查backend-checklist
### 📋 基础检查项
#### Maven编译验证
- [ ] 本地执行 `mvn compile` 编译通过无ERROR
- [ ] 执行 `mvn package -DskipTests` 打包成功
- [ ] 依赖版本无冲突(`mvn dependency:tree` 检查)
- [ ] 无编译警告(或已有书面说明可忽略)
#### 构建产物验证
- [ ] JAR/WAR包生成完整大小合理
- [ ] `application.yml` 等配置文件已打包进产物
- [ ] 第三方依赖jar包完整lib目录无缺失
### 🔧 Spring Boot 配置检查
#### 多环境配置
- [ ] `application-dev.yml`(开发)配置正确
- [ ] `application-test.yml`(测试)配置正确
- [ ] `application-prod.yml`(生产)配置正确
- [ ] 启动参数 `--spring.profiles.active` 指定正确环境
- [ ] 生产环境未启用devtools热部署
#### Actuator安全
- [ ] 生产环境 `/actuator` 端点已禁用或限制访问
- [ ] `/actuator/env``/actuator/heapdump` 等敏感端点已关闭
- [ ] 健康检查端点 `/actuator/health` 返回信息已脱敏
#### 启动校验
- [ ] 数据库连接池配置合理HikariCP最大/最小连接数)
- [ ] Redis/消息中间件连接配置正确
- [ ] 启动日志无ERROR级别异常
### 🗄️ MyBatis Plus 规范检查
#### 实体-表映射
- [ ] 所有实体类标注 `@TableName`,表名与实际一致
- [ ] 主键字段标注 `@TableId(type = IdType.AUTO)` 或对应策略
- [ ] 非表字段标注 `@TableField(exist = false)`
- [ ] 字段命名符合下划线转驼峰规则
#### SQL安全
- [ ] 所有查询使用参数化查询(`QueryWrapper` / `LambdaQueryWrapper`
- [ ] 禁止字符串拼接SQL`"WHERE name = '" + name + "'"`
- [ ] 批量操作使用MyBatis Plus `saveBatch` / `updateBatchById`
- [ ] 复杂SQL使用XML映射避免注解内嵌长SQL
#### 事务管理
- [ ] 涉及多表写操作的方法标注 `@Transactional`
- [ ] 事务边界合理不包含外部HTTP调用
- [ ] 异常回滚配置正确(`rollbackFor = Exception.class`
- [ ] 事务方法未被同一类内方法直接调用(自调用失效问题)
#### 分页插件
- [ ] `PaginationInnerInterceptor` 已正确配置
- [ ] 分页查询使用 `Page<T>` 对象非手动limit/offset
### 🔌 RESTful API 设计检查
#### 统一返回格式
- [ ] 所有接口返回 `{code, msg, data}` 统一结构
- [ ] 成功返回 `code=200`,业务错误使用自定义错误码
- [ ] 异常通过 `@ControllerAdvice` + `@ExceptionHandler` 统一处理
#### HTTP状态码
- [ ] 资源创建返回 `201 Created`
- [ ] 资源删除返回 `204 No Content`
- [ ] 参数校验失败返回 `400 Bad Request`
- [ ] 未认证返回 `401 Unauthorized`
- [ ] 无权限返回 `403 Forbidden`
- [ ] 资源不存在返回 `404 Not Found`
#### 参数校验
- [ ] 请求参数使用 `@Valid` / `@Validated` 注解校验
- [ ] 必填字段标注 `@NotBlank` / `@NotNull`
- [ ] 数值范围标注 `@Min` / `@Max`
- [ ] 格式校验使用 `@Pattern`(如手机号、身份证号)
- [ ] 校验失败返回明确错误信息非500堆栈
#### API版本管理
- [ ] 接口路径包含版本号(`/api/v1/``/api/v2/`
- [ ] 废弃接口标注 `@Deprecated`,并在文档中说明
- [ ] 不兼容变更必须升级版本号
### 🔒 安全与合规检查
#### 数据脱敏
- [ ] 患者身份证号在日志中脱敏(`***` 掩码)
- [ ] 患者手机号在日志中脱敏前3后4中间`****`
- [ ] 敏感字段序列化时使用 `@JsonSerialize` 自定义脱敏器
- [ ] 接口返回中非必需字段不暴露如密码、salt
#### 权限控制
- [ ] 所有涉及患者数据的接口标注 `@PreAuthorize`
- [ ] 数据级权限校验(医生只能访问本科室患者)
- [ ] 越权访问返回 `403`,非 `404``500`
- [ ] 敏感操作(删除、修改诊断)需二次确认或额外权限
#### 审计日志
- [ ] 处方修改记录操作人、时间、变更内容
- [ ] 病历删除操作记录完整审计链
- [ ] 审计日志独立存储,不可被业务用户删除
- [ ] 关键业务操作记录IP地址和操作终端
### ⚡ 性能检查
#### 数据库查询
- [ ] 无N+1查询问题使用 `JOIN` 或批量查询)
- [ ] 大表查询必须有分页限制
- [ ] 慢查询已优化(执行时间 < 500ms
- [ ] 索引已覆盖高频查询条件
#### 接口性能
- [ ] 核心接口响应时间 < 1秒
- [ ] 列表接口支持分页无全量返回
- [ ] 大文件下载使用流式传输非全量加载到内存
### 📝 文档与发布准备
#### 文档更新
- [ ] API接口文档已同步更新路径参数返回值
- [ ] 数据库变更脚本已提供DDL/DML
- [ ] 配置变更说明已记录新增/修改的配置项
- [ ] 影响范围说明已明确哪些模块哪些接口受影响
#### 回滚预案
- [ ] 数据库变更可回滚提供反向SQL脚本
- [ ] 配置变更可快速回退
- [ ] 紧急回滚流程已明确怎么做多长时间
- [ ] 回滚后数据一致性已验证
### ✅ 最终确认
#### 发布前最后检查
- [ ] `mvn compile` 构建成功附终端截图
- [ ] 关键单元测试通过
- [ ] 测试环境部署验证通过
- [ ] Code Review 已完成并获得批准
- [ ] 相关Bug已关闭或延期说明
---
## 4. CI/CD门禁cicd-gatekeeper
### 🎯 规范目标
建立自动化质量门禁确保每次代码提交都经过严格验证防止低质量代码进入主干分支提升系统稳定性和开发效率
### 🔒 门禁层级
#### 1. 提交前门禁Pre-commit
**触发时机**`git commit` 执行前
**验证内容**
- ESLint 代码规范检查
- Prettier 代码格式化
- 简单的单元测试快速执行
**工具配置**
- Husky + lint-staged
- 配置文件`.husky/pre-commit`
#### 2. 推送前门禁Pre-push
**触发时机**`git push` 执行前
**验证内容**
- 完整的单元测试套件
- 构建验证`npm run build:prod`
- 集成测试核心流程
**工具配置**
- Husky pre-push hook
- 配置文件`.husky/pre-push`
#### 3. CI流水线门禁CI Pipeline
**触发时机**代码推送到远程仓库后
**验证内容**
- 完整的测试套件单元+集成+端到端
- 代码覆盖率检查分阶段目标Q130%Q250%Q380%
- 安全扫描SAST
- 构建产物验证
- 部署到测试环境
**工具配置**
- Spug CI/CD 流水线
- Gitea Webhook 触发
#### 4. 发布前门禁Release Gate
**触发时机**准备发布到生产环境前
**验证内容**
- 生产环境冒烟测试
- 性能基准测试
- 安全合规检查
- 回滚预案验证
### ⚙️ 具体配置要求
#### ESLint 配置
```javascript
// eslint.config.js 关键配置
import globals from "globals";
import pluginVue from "eslint-plugin-vue";
import parserVue from "vue-eslint-parser";
import importPlugin from "eslint-plugin-import";
export default [
{
name: "app/files-to-lint",
files: ["**/*.{js,mjs,jsx,vue}"],
},
{
name: "app/files-to-ignore",
ignores: ["**/dist/**", "**/node_modules/**", "**/help-center/**"],
},
...pluginVue.configs["flat/recommended"],
{
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
parser: parserVue,
ecmaVersion: "latest",
sourceType: "module",
},
plugins: {
import: importPlugin,
},
rules: {
// 确保导入的模块实际存在(核心规则,防止构建失败)
"import/no-unresolved": "error",
// 确保导入的命名导出实际存在
"import/named": "error",
// 确保默认导出存在
"import/default": "error",
// 确保命名空间导出存在
"import/namespace": "error",
},
},
];
```
#### Java 后端配置
```xml
<!-- pom.xml 关键插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.2.0</version>
</plugin>
```
#### 数据库迁移配置
```yaml
# application.yml Flyway配置
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
```
#### Husky 配置
```bash
# .husky/pre-commit
#!/bin/sh
npm run lint-staged
# .husky/pre-push
#!/bin/sh
npm run test:unit && npm run build:prod
```
#### lint-staged 配置
```json
// package.json
{
"lint-staged": {
"*.{js,vue}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["stylelint --fix", "prettier --write"]
}
}
```
### 🚫 失败处理机制
#### 自动处理
- **构建失败**自动阻止 PR 合并
- **测试失败**标记 PR 为失败状态
- **安全漏洞**立即通知安全团队
#### 人工处理
- **紧急修复**可申请临时绕过需架构师批准
- **误报处理**提交豁免申请并说明原因
- **规则调整**通过 RFC 流程申请规则变更
### 📊 监控与度量
#### 关键指标
- 门禁通过率 95%
- 平均修复时间 2小时
- 误报率 5%
#### 报告机制
- 每日门禁失败统计
- 周度质量趋势报告
- 月度规则优化建议
### 🔄 持续改进
#### 规则演进
- 每月评审门禁规则有效性
- 根据项目需求调整检查强度
- 引入新的质量检查工具
#### 团队培训
- 新成员入职培训包含门禁规范
- 定期分享最佳实践案例
- 建立常见问题解决方案库
---
## 5. 发布确认与回滚预案
### 📋 发布前最终确认清单
#### 前端确认
- [ ] 本地构建成功`npm run build:prod`
- [ ] 核心功能流程测试通过
- [ ] 模块导入检查通过无import错误
- [ ] 兼容性测试完成
#### 后端确认
- [ ] Maven编译成功`mvn compile`
- [ ] 单元测试通过
- [ ] 数据库脚本验证通过
- [ ] API接口测试通过
#### 协同确认
- [ ] 前后端接口契约一致
- [ ] 联调测试通过
- [ ] Code Review 已完成
- [ ] 测试环境部署验证通过
### 🚨 回滚预案
#### 触发条件
- [ ] 生产环境出现严重Bug
- [ ] 性能严重下降
- [ ] 数据一致性问题
- [ ] 安全漏洞暴露
#### 回滚步骤
1. **立即停止**暂停新流量进入
2. **版本回退**部署上一个稳定版本
3. **数据回滚**执行数据库回滚脚本如有
4. **验证恢复**确认系统功能正常
5. **问题分析**记录根本原因和改进措施
#### 责任分工
- **技术负责人**执行回滚操作
- **测试负责人**验证回滚后功能
- **项目经理**协调沟通和进度同步
- **运维团队**监控系统状态
### 📞 紧急联系人
| 角色 | 姓名 | 联系方式 | 职责 |
|------|------|----------|------|
| 技术负责人 | 诸葛亮 | @诸葛亮 | 架构决策和技术指导 |
| 前端负责人 | 赵云 | @赵云 | 前端问题处理 |
| 后端负责人 | 关羽 | @关羽 | 后端问题处理 |
| 测试负责人 | 张飞 | @张飞 | 质量验证和问题复现 |
| 项目经理 | 刘备 | @刘备 | 项目协调和进度管理 |
| 文档负责人 | 陈琳 | @陈琳 | 文档维护和知识沉淀 |
---
**文档版本**v1.0
**最后更新**2026年4月25日
**负责人**陈琳文档专家
**适用范围**HIS 系统所有开发人员

View File

@@ -0,0 +1,139 @@
# 手术管理模块设计文档
> **文档类型**: 业务设计
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **依据标准**: 《三级医院评审标准(2022版)》手术质量安全核心制度
---
## 一、业务背景
手术管理是三甲医院评审的核心检查项。依据《医疗质量安全核心制度》中的"手术分级管理制度"和"术前讨论制度",手术必须经过完整的术前评估→审批→执行→术后跟踪流程。
### 参考标准
- 三级医院评审标准(2022版) — 手术质量安全核心指标
- 电子病历应用水平分级评价 — 4级要求手术信息全院共享
- 《手术分级管理办法》— 手术分级授权管理
- 《病案管理与质量控制标准》— 手术记录规范
---
## 二、状态流转
### 2.1 手术状态机
```
待申请(0) → 待审批(1) → 已审批(2) → 待手术(3) → 手术中(4) → 已完成(5)
↓ ↓
已驳回(6) 已取消(7)
```
| 状态 | 值 | 触发条件 | 允许操作 |
|------|-----|---------|---------|
| 待申请 | 0 | 医生提交手术申请 | 编辑/删除/提交审批 |
| 待审批 | 1 | 提交审批 | 审批/驳回 |
| 已审批 | 2 | 科主任审批通过 | 安排手术室/取消 |
| 待手术 | 3 | 安排手术室和时间 | 开始手术/取消 |
| 手术中 | 4 | 主刀医生确认开始 | 记录术中事件/完成 |
| 已完成 | 5 | 主刀医生确认完成 | 查看/打印记录 |
| 已驳回 | 6 | 科主任驳回 | 编辑后重新提交 |
| 已取消 | 7 | 任意阶段取消 | 查看 |
### 2.2 手术分级
| 级别 | 名称 | 审批权限 | 示例 |
|------|------|---------|------|
| 一级 | 一级手术 | 住院医师可独立完成 | 阑尾切除术 |
| 二级 | 二级手术 | 主治医师以上 | 胃大部切除术 |
| 三级 | 三级手术 | 副主任医师以上 | 心脏搭桥术 |
| 四级 | 四级手术 | 科主任审批+医务部备案 | 器官移植术 |
---
## 三、业务规则
| 规则编号 | 规则名称 | 规则描述 | 触发时机 |
|---------|---------|---------|---------|
| SR-001 | 手术分级权限校验 | 医生只能申请其权限范围内的手术级别 | 提交申请时 |
| SR-002 | 术前讨论记录 | 三级/四级手术必须有术前讨论记录 | 提交审批时 |
| SR-003 | 术前评估 | 必须完成麻醉评估和手术风险评估 | 安排手术时 |
| SR-004 | 手术室冲突检查 | 同一手术室同一时间不能安排两台手术 | 安排手术室时 |
| SR-005 | 术前禁食提醒 | 手术前8小时禁止进食4小时禁止饮水 | 手术前1天 |
| SR-006 | 术后随访 | 手术后24h/48h/72h必须有随访记录 | 完成手术后 |
| SR-007 | 手术安全核查 | 术前/术中/术后三次安全核查(WS/T 313) | 手术各阶段 |
---
## 四、前后端交互时序
### 4.1 提交手术申请
```
用户操作: 医生点击"提交手术申请"
→ 前端: 校验表单(必填项+业务规则前端预检)
→ API: POST /clinical-manage/surgery/surgery
→ 后端: SurgeryController.addSurgery()
→ SurgeryAppService.addSurgery()
→ 校验手术分级权限(SR-001)
→ 校验三级/四级手术术前讨论(SR-002)
→ 设置状态=待申请(0)
→ 保存到数据库
→ 返回: {code:200, msg:"申请已提交"}
→ 前端: ElMessage.success → 刷新列表
```
### 4.2 安排手术室
```
用户操作: 护士长点击"安排手术"
→ 前端: 弹出安排弹窗(选择手术室/时间/麻醉医生)
→ API: PUT /clinical-manage/surgery/surgery (携带手术室+时间信息)
→ 后端: 校验手术室冲突(SR-004)
→ 校验术前评估完成(SR-003)
→ 更新状态=待手术(3)
→ 返回: {code:200, msg:"安排成功"}
```
### 4.3 开始/完成手术
```
用户操作: 主刀医生点击"开始手术"
→ API: PUT /clinical-manage/surgery/surgery-status?id=&statusEnum=4
→ 后端: 更新状态=手术中(4), 记录开始时间
用户操作: 主刀医生点击"完成手术"
→ API: PUT /clinical-manage/surgery/surgery-status?id=&statusEnum=5
→ 后端: 更新状态=已完成(5), 记录结束时间
→ 触发术后随访提醒(SR-006)
```
---
## 五、数据模型扩展
现有 `SurgeryDto` 需增加以下字段:
| 字段 | 类型 | 说明 |
|------|------|------|
| surgeryLevel | String | 手术级别(1/2/3/4) |
| surgeryRoom | String | 手术室 |
| anesthesiaType | String | 麻醉方式(全麻/局麻/脊麻/硬膜外) |
| preopDiagnosis | String | 术前诊断 |
| postopDiagnosis | String | 术后诊断 |
| startTime | DateTime | 实际开始时间 |
| endTime | DateTime | 实际结束时间 |
| complications | String | 并发症记录 |
| bloodLoss | Integer | 术中出血量(ml) |
| specimenSent | Boolean | 是否送检标本 |
---
## 六、测试用例
| 用例编号 | 场景 | 操作步骤 | 预期结果 |
|---------|------|---------|---------|
| TC-S001 | 正常申请流程 | 医生提交→科主任审批→护士安排→手术完成 | 状态正确流转 |
| TC-S002 | 越级申请拒绝 | 住院医师申请四级手术 | 返回权限不足错误 |
| TC-S003 | 手术室冲突 | 同一时间安排两台手术到同一手术室 | 返回冲突提示 |
| TC-S004 | 驳回后重新提交 | 科主任驳回→医生修改→重新提交 | 状态从驳回回到待审批 |
| TC-S005 | 取消手术 | 已审批的手术点击取消 | 状态变为已取消 |
| TC-S006 | 缺少术前讨论 | 三级手术无术前讨论记录直接提交 | 拦截并提示 |

View File

@@ -0,0 +1,404 @@
# HealthLink-HIS UI 设计铁律
> **文档类型**: 设计规范
> **适用范围**: 全项目前端UI设计与交互
> **版本**: v1.0
> **编制日期**: 2026-06-06
> **最后更新**: 2026-06-06
---
## 一、总则
> **设计文档必须写清楚前端页面UI布局、交互效果、前后端调用流程。**
> 没有明确UI设计的模块禁止直接编码。
### 设计文档必备要素
每个新模块/页面的设计文档必须包含:
| # | 要素 | 说明 |
|---|------|------|
| 1 | **页面线框图/布局描述** | 每个区域放什么组件、尺寸比例、栅格布局 |
| 2 | **交互效果清单** | 每个按钮/操作触发什么效果(弹窗、抽屉、跳转、动画) |
| 3 | **前后端调用流程** | 每个用户操作 → 对应API → 参数 → 返回数据 → 前端渲染 |
| 4 | **状态流转图** | 数据状态变化 → UI如何响应 |
| 5 | **异常/边界处理** | 空数据、加载中、错误状态的UI表现 |
| 6 | **响应式断点** | 不同屏幕尺寸下的布局适配方案 |
---
## 二、十大UI设计铁律法则
> 以下法则源自认知心理学、人机交互学、HCI经典理论。
> 医疗HIS系统因涉及生命安全**全部铁律等级提升为P0**。
### 法则1: 希克定律 (Hick's Law) — 选择越少越好
> **决策时间 = a + b × log₂(选项数量)**
| 维度 | 规则 | HIS场景 |
|------|------|---------|
| 菜单层级 | 一级菜单 ≤ 7项二级菜单 ≤ 9项 | 医生工作站左侧导航 |
| 表单字段 | 单页表单 ≤ 12个字段超出用分步表单 | 患者登记、医嘱录入 |
| 按钮组 | 主要操作按钮 ≤ 3个/区域 | 处方页面:保存/提交/打印 |
| 弹窗选项 | 弹窗内选项 ≤ 5个 | 确认对话框不超过3个按钮 |
**违反案例**: 某页面一次展示20个筛选条件 → 医生找不到关键字段
**正确做法**: 默认显示5个常用条件"更多筛选"展开高级选项
### 法则2: 费茨定律 (Fitts's Law) — 目标要大要近
> **移动时间 = a + b × log₂(距离/尺寸 + 1)**
| 维度 | 规则 | HIS场景 |
|------|------|---------|
| 可点击区域 | 最小 44×44px移动端 48×48px | 移动护理PDA场景 |
| 主要操作 | 放在用户视线自然落点(右下/顶部) | 保存按钮固定在表单右下 |
| 危险操作 | 与安全操作保持物理距离 ≥ 100px | 删除按钮远离保存按钮 |
| 快捷入口 | 高频操作提供快捷键/快捷入口 | F2=保存, F3=打印 |
**违反案例**: "确认发药"和"取消发药"按钮紧挨着 → 误点
**正确做法**: 确认按钮绿色大按钮,取消按钮灰色小按钮,间距 ≥ 80px
### 法则3: 米勒定律 (Miller's Law) — 记忆负荷 ≤ 7±2
> **短时记忆容量7 ± 2 个信息块**
| 维度 | 规则 | HIS场景 |
|------|------|---------|
| 信息分组 | 每组 ≤ 7个条目 | 检验报告分组显示 |
| 导航层级 | 总层级 ≤ 4层 | 菜单→子菜单→功能→详情 |
| 表格列数 | 默认显示 ≤ 8列其余可配置 | 处方列表核心列8个 |
| 标签页 | Tab标签 ≤ 6个超出用下拉 | 患者详情Tab |
**违反案例**: 患者信息页一次展示30个字段 → 医生记不住哪个要改
**正确做法**: 按"基本信息/病史/过敏/诊断"分组,每组 ≤ 7个字段
### 法则4: 雅各布定律 (Jakob's Law) — 用户要的是熟悉感
> **用户把时间花在别的系统上,期望你的系统有一样的操作方式**
| 维度 | 规则 | HIS场景 |
|------|------|---------|
| 布局模式 | 遵循医疗软件行业惯例 | 左导航+顶部栏+内容区 |
| 表格操作 | 行末操作按钮(编辑/删除/查看) | 与主流HIS系统一致 |
| 搜索模式 | 顶部搜索栏+筛选条件+表格 | 通用管理后台模式 |
| CRUD流程 | 列表→新增弹窗→编辑弹窗→详情抽屉 | 标准若依模式 |
**违反案例**: 新模块把"新增"放在表格底部 → 用户习惯在顶部找
**正确做法**: "新增"按钮统一在表格上方左侧
### 法则5: 格式塔原则 (Gestalt Principles) — 分组要明确
| 子原则 | 规则 | HIS场景 |
|--------|------|---------|
| **接近性** | 相关元素间距 < 不相关元素间距 | 表单label与input间距8px字段组间距24px |
| **相似性** | 同类操作用相同颜色/形状 | 所有"保存"用蓝色所有"删除"用红色 |
| **连续性** | 视觉引导线引导阅读流 | 表单从上到下从左到右 |
| **封闭性** | 卡片/分组用边框或背景色区分 | 患者信息分区用卡片包裹 |
| **图底关系** | 内容层 > 背景层,弹窗要有遮罩 | Dialog背景半透明遮罩 |
**违反案例**: 表单字段间距不一致 → 视觉混乱
**正确做法**: 统一间距系统8/12/16/24/32px
### 法则6: 多赫蒂阈值 (Doherty Threshold) — 响应要快
> **系统响应 < 400ms 时用户生产力提升4倍**
| 维度 | 规则 | HIS场景 |
|------|------|---------|
| 接口响应 | 核心接口 ≤ 200ms普通 ≤ 500ms | 挂号、查询必须 ≤ 200ms |
| 加载反馈 | 等待 > 200ms 显示loading | el-table加载用v-loading |
| 操作反馈 | 点击后 ≤ 100ms 有视觉响应 | 按钮点击立即变灰防重复提交 |
| 列表分页 | 默认20条/页,禁止一次加载全部 | 处方列表分页 |
| 骨架屏 | 首屏加载用Skeleton占位 | 患者列表页骨架屏 |
**违反案例**: 查询接口3秒无响应 → 用户反复点击
**正确做法**: 200ms内显示loading超时5s提示"查询超时"
### 法则7: 尼尔森十大可用性原则 (Nielsen's 10 Heuristics)
| # | 原则 | HIS应用规则 |
|---|------|------------|
| 1 | **系统状态可见** | 每个操作后显示结果:保存成功✓、提交成功✓、审批中⏳ |
| 2 | **贴近真实世界** | 使用医疗术语挂号、处方、医嘱不用技术术语CRUD、API |
| 3 | **用户控制与自由** | 每个操作可撤销:提交可撤回、删除有确认、编辑可取消 |
| 4 | **一致性和标准** | 全系统统一:按钮颜色、弹窗样式、表格样式、表单校验 |
| 5 | **防错优先** | 危险操作二次确认;必填字段标红*;格式校验实时提示 |
| 6 | **识别而非记忆** | 下拉选择 > 手动输入;最近使用列表;搜索联想 |
| 7 | **灵活高效** | 快捷键;批量操作;常用模板;收藏功能 |
| 8 | **简洁美观** | 去掉无关信息;留白适度;视觉层次清晰 |
| 9 | **容错帮助** | 错误信息说人话:"身份证号格式错误"而非"Invalid input" |
| 10 | **帮助文档** | 复杂功能提供操作引导Help Tooltip |
**违反案例**: 删除后无提示 → 用户不确定是否成功
**正确做法**: 删除后 `ElMessage.success('删除成功')` 并刷新列表
### 法则8: 泰斯勒定律 (Tesler's Law) — 复杂性守恒
> **每个系统都有不可消除的复杂性,必须 somewhere 被处理**
| 维度 | 规则 | HIS场景 |
|------|------|---------|
| 简单前端复杂后端 | 用户操作尽量简单,复杂逻辑放后端 | 医保结算:用户点"结算",后端算所有费用 |
| 智能默认值 | 80%场景用默认值,减少用户输入 | 科室默认当前科室,药品默认常用规格 |
| 渐进式披露 | 先展示核心信息,高级选项折叠 | 医嘱默认常用,"更多选项"展开完整 |
| 自动化 | 能自动填充的不手动输入 | 选择患者自动填充病历号、性别、年龄 |
**违反案例**: 开医嘱要手动输入药品剂量、频次、途径 → 复杂
**正确做法**: 提供"常用医嘱模板",一键套用,仅需微调
### 法则9: 峰终定律 (Peak-End Rule) — 关键时刻要做好
> **用户记住的是体验的峰值和结束时刻**
| 维度 | 规则 | HIS场景 |
|------|------|---------|
| 操作峰值 | 关键操作给正向反馈 | 挂号成功→大✓动画+患者信息卡 |
| 结束体验 | 流程结束给明确结果 | 收费完成→打印凭条+成功提示 |
| 错误峰值 | 错误也要优雅处理 | 校验失败→精确定位错误字段+红色高亮 |
| 批量操作 | 批量完成后给统计 | "成功导入58条失败2条" |
**违反案例**: 批量导入完成后无提示 → 用户不知道是否成功
**正确做法**: 弹出结果面板:"✓ 成功58条 / ✗ 失败2条点击查看"
### 法则10: 冯·雷斯托夫效应 (Von Restorff Effect) — 隔离记忆
> **在相似事物中,与众不同的那个更容易被记住**
| 维度 | 规则 | HIS场景 |
|------|------|---------|
| 紧急标记 | 危急值用红色醒目样式 | 危急值报告→红色闪烁标签 |
| 当前选中 | 选中项明显高亮 | 菜单选中项蓝色背景+左侧条 |
| 重要操作 | 主要按钮用强调色 | "提交处方"蓝色实心,"取消"灰色描边 |
| 通知徽标 | 未读消息用Badge | 右上角铃铛红点+数字 |
**违反案例**: 危急值和普通信息用同一颜色 → 医生忽略
**正确做法**: 危急值红色脉冲动画 + 声音提醒
---
## 三、HIS医疗系统专项UI规范
### 3.1 色彩体系
| 用途 | 颜色 | HEX | 说明 |
|------|------|-----|------|
| 主色 | 医疗蓝 | #1890ff | 品牌色、主要按钮 |
| 成功 | 安全绿 | #52c41a | 操作成功、正常状态 |
| 警告 | 警示橙 | #faad14 | 注意、待处理 |
| 危险 | 危急红 | #ff4d4f | 危急值、删除、错误 |
| 信息 | 信息灰 | #909399 | 辅助信息、次要文本 |
| 背景 | 浅灰 | #f5f7fa | 页面背景 |
| 卡片 | 白色 | #ffffff | 卡片/弹窗背景 |
**状态色标准**:
```
待诊 → #909399(灰) 已诊 → #1890ff(蓝)
已收费 → #52c41a(绿) 已发药 → #722ed1(紫)
危急 → #ff4d4f(红脉冲) 已完成 → #b7eb8f(浅绿)
```
### 3.2 间距系统 (8px基准)
| Token | 值 | 用途 |
|-------|-----|------|
| xs | 4px | 图标与文字间距 |
| sm | 8px | 表单项内间距、紧凑行距 |
| md | 12px | 表单项之间间距 |
| lg | 16px | 卡片内边距、区块间距 |
| xl | 24px | 区域分隔 |
| xxl | 32px | 页面级边距 |
### 3.3 字体规范
| 场景 | 字号 | 字重 | 说明 |
|------|------|------|------|
| 页面标题 | 20px | 600 | h1 |
| 区块标题 | 16px | 600 | h2 |
| 正文 | 14px | 400 | 默认 |
| 辅助文字 | 12px | 400 | 说明、提示 |
| 数据突出 | 24px | 700 | 统计数字、金额 |
| 危急值 | 16px | 700 | 红色加粗 |
### 3.4 表格设计规范
| 规则 | 说明 |
|------|------|
| 列数 | 默认 ≤ 8列超出用横向滚动或配置列 |
| 行高 | 48px紧凑40px宽松56px |
| 操作列 | 固定右侧,宽度 ≥ 160px |
| 排序 | 默认按时间倒序,支持点击列头排序 |
| 分页 | 20条/页可切换10/20/50/100 |
| 空状态 | 无数据时显示空状态插画+文字"暂无数据" |
| 加载 | v-loading指令骨架屏或旋转图标 |
| 斑马纹 | 奇偶行交替背景色 #fafafa |
### 3.5 表单设计规范
| 规则 | 说明 |
|------|------|
| 布局 | 简单表单用inline复杂用labelWidth=120px |
| 必填标记 | 红色 * 号在label前 |
| 校验时机 | blur时校验非实时提交时全量校验 |
| 错误提示 | 字段下方红色文字,与字段左对齐 |
| 按钮位置 | 表单底部右侧,主按钮在右 |
| 禁用态 | 禁用字段灰底+灰字+禁止光标 |
| 加载态 | 提交按钮loading态防重复提交 |
### 3.6 弹窗/抽屉规范
| 类型 | 适用场景 | 规则 |
|------|---------|------|
| Dialog | 简单表单≤6字段 | 宽度400-600px标题+内容+底部按钮 |
| Drawer | 复杂表单/详情查看 | 宽度60%,右侧滑入,含关闭按钮 |
| Modal | 确认操作 | 标题+内容+确认/取消,危险操作红色确认 |
| Fullscreen | 大表单/复杂编辑 | 全屏,顶栏标题+关闭,底部操作栏 |
### 3.7 交互反馈规范
| 操作 | 反馈方式 | 示例 |
|------|---------|------|
| 保存成功 | ElMessage.success | "保存成功" |
| 保存失败 | ElMessage.error | "保存失败XXX原因" |
| 删除确认 | ElMessageBox.confirm | "确定要删除该记录吗?" |
| 表单校验 | 字段下方红色文字 | "请输入患者姓名" |
| 加载中 | v-loading | 旋转图标覆盖表格 |
| 空数据 | 空状态组件 | 插画+"暂无挂号记录" |
| 网络错误 | ElMessage.error | "网络异常,请重试" |
| 无权限 | ElMessage.warning | "您没有该操作权限" |
### 3.8 医疗HIS特殊交互
| 场景 | 交互要求 |
|------|---------|
| **危急值** | 红色脉冲动画 + 弹窗强制确认 + 声音提醒 + 操作记录 |
| **医嘱审核** | 双人审核弹窗,审核人签章,不可撤销提示 |
| **处方开具** | 药品搜索联想 + 剂量自动计算 + 相互作用预警弹窗 |
| **费用结算** | 费用明细折叠/展开 + 医保/自费分类 + 打印预览 |
| **患者搜索** | 模糊搜索+拼音首字母+身份证号+病历号 多维度 |
| **电子签名** | 手写板签名+密码验证 双重认证 |
| **打印功能** | 套打对齐微调 + 批量打印 + 预览 |
| **权限控制** | 按钮级权限 v-hasPermi + 数据权限过滤 |
---
## 四、设计文档模板
> 每个新模块必须按此模板编写设计文档
```markdown
# 模块名 设计文档
## 1. 页面列表
| 页面 | 路由 | 类型 | 说明 |
|------|------|------|------|
| 列表页 | /module/list | 管理页 | ... |
| 新增弹窗 | - | Dialog | ... |
## 2. 页面布局设计
### 2.1 列表页
```
┌─────────────────────────────────┐
│ 搜索区 [关键词] [筛选] [搜索] │
├─────────────────────────────────┤
│ 操作区 [+新增] [导出] [批量删除] │
├─────────────────────────────────┤
│ 数据表格 (el-table) │
│ 列1 | 列2 | 列3 | ... | 操作 │
├─────────────────────────────────┤
│ 分页 [1] [2] [3] ... │
└─────────────────────────────────┘
```
## 3. 交互效果清单
| 操作 | 触发方式 | 效果 | 反馈 |
|------|---------|------|------|
| 点击"新增" | 按钮click | 打开Dialog | - |
| 点击"保存" | 按钮click | 提交API→关闭Dialog→刷新列表 | success消息 |
| 点击"删除" | 按钮click | 二次确认弹窗→调用API→刷新 | success消息 |
| 表单校验 | blur/submit | 字段下方提示 | error文字 |
## 4. 前后端调用流程
### 4.1 查询列表
```
用户操作: 页面加载/点击搜索
→ 前端: GET /api/v1/module/list?pageNum=1&pageSize=20&keyword=xxx
→ 后端: Controller.list() → AppService.query() → Service.page()
→ 返回: {code:200, data:{rows:[...], total:100}}
→ 前端: el-table渲染 rowspagination渲染 total
```
### 4.2 新增记录
```
用户操作: 点击"新增"→填写表单→点击"保存"
→ 前端: POST /api/v1/module {field1, field2, ...}
→ 后端: Controller.add() → AppService.create() → Service.save()
→ 返回: {code:200, msg:"操作成功"}
→ 前端: ElMessage.success → 关闭Dialog → getList()
```
## 5. 状态流转
| 状态 | 值 | 下一状态 | 触发条件 |
|------|-----|---------|---------|
| 草稿 | 0 | 已提交 | 用户点击提交 |
| 已提交 | 1 | 已审核 | 审核人点击审核 |
## 6. 异常处理
| 场景 | UI表现 |
|------|--------|
| 网络断开 | ElMessage.error("网络异常") |
| 数据为空 | 空状态插画+"暂无数据" |
| 权限不足 | 按钮隐藏/v-if控制 |
| 加载中 | v-loading覆盖 |
```
---
## 五、违反检查清单
> 代码审查时对照此清单逐项检查
```
□ 页面布局是否遵循左导航+顶部栏+内容区?
□ 每页功能按钮是否 ≤ 3个主要操作
□ 表单字段是否 ≤ 12个超出是否分步/折叠?
□ 可点击区域是否 ≥ 44px
□ 危险操作是否与安全操作保持距离?
□ 加载等待是否显示loading
□ 操作成功/失败是否有明确反馈?
□ 删除操作是否有二次确认?
□ 表格是否分页是否默认20条
□ 空数据是否有空状态提示?
□ 色彩是否符合色彩体系?
□ 间距是否使用8px基准系统
□ 字体是否符合字体规范?
□ 弹窗类型选择是否合理?
□ 表单校验是否blur触发
□ 医疗特殊交互(危急值/医嘱等)是否按规范实现?
□ 设计文档是否包含UI布局+交互清单+调用流程?
```
---
## 六、参考文献
| 来源 | 内容 |
|------|------|
| Hick (1952) | Hick's Law — 选择反应时间 |
| Fitts (1954) | Fitts's Law — 运动时间与目标尺寸 |
| Miller (1956) | Miller's Law — 7±2信息块 |
| Jakob Nielsen | 10 Usability Heuristics |
| Gestalt Psychology | 接近性/相似性/连续性/封闭性/图底 |
| Doherty & Thadhani (1982) | 400ms响应阈值 |
| Larry Tesler | 复杂性守恒定律 |
| Kahneman | 峰终定律 |
| Hedwig von Restorff | 隔离效应 |
| ISO 9241-210 | 以人为中心的交互系统设计 |
| GB/T 33758-2017 | 人机交互系统人机界面设计原则 |
| WS/T 500-2017 | 电子病历共享文档规范 |
---
> ⚠️ 本文件是UI设计铁律的唯一信源。所有前端模块设计文档必须遵守本规范。