Sfoglia il codice sorgente

docs(follow-up): 更新复诊管理功能设计文档

- 补充数据库设计规范引用及主键生成策略说明
- 明确公共字段与索引建议,新增建表示例
- 更新RESTful API路由与参数处理方式
- 补充安全规范引用及功能相关安全实现要点
- 强调长整型ID传输策略与数据迁移建议
mcbaiyun 1 mese fa
parent
commit
c961fa4a90
1 ha cambiato i file con 77 aggiunte e 14 eliminazioni
  1. 77 14
      docs/New/复诊管理功能设计文档.md

+ 77 - 14
docs/New/复诊管理功能设计文档.md

@@ -8,13 +8,13 @@
 
 ### 2.1 复诊记录表 (t_follow_up)
 
-根据项目数据库表设计规范,创建复诊记录表:
+根据项目数据库表设计规范(参见 `docs/OLD/DevRule/07-数据库规范.md`),创建复诊记录表:
 
 | 字段名 | 类型 | 描述 |
 |--------|------|------|
-| id | BIGINT | 主键ID |
-| patient_user_id | BIGINT | 患者用户ID |
-| doctor_user_id | BIGINT | 医生用户ID |
+| id | BIGINT | 主键ID,使用雪花算法(MyBatis-Plus `ASSIGN_ID`) |
+| patient_user_id | BIGINT | 患者用户ID,外键(可选) |
+| doctor_user_id | BIGINT | 医生用户ID,外键(可选) |
 | appointment_time | DATETIME | 预约时间 |
 | actual_time | DATETIME | 实际就诊时间 |
 | status | VARCHAR(20) | 复诊状态 (PENDING-待确认, CONFIRMED-已确认, CANCELLED-已取消, COMPLETED-已完成) |
@@ -27,6 +27,39 @@
 | version | INT | 版本号(乐观锁) |
 | remark | VARCHAR(255) | 备注 |
 
+遵循的数据库规范要点:
+- 使用 `BIGINT` 主键并通过雪花算法生成(MyBatis-Plus `ASSIGN_ID`)。
+- 公共字段(`version`、`create_user`、`create_time`、`update_user`、`update_time`)由 `BaseEntity` 与 `CustomMetaObjectHandler` 自动填充。
+- 建议添加索引:`patient_user_id`、`doctor_user_id`、`appointment_time`、`create_time`。如有按状态频繁查询,可加 `status` 的组合索引。
+- 根据需要添加外键约束(注意性能影响)或在应用层校验关联数据完整性。
+- 数据迁移建议使用 Flyway/Liquibase(脚本命名遵循 `V{version}__{description}.sql`)。
+
+示例建表(参考):
+```
+CREATE TABLE t_follow_up (
+    id BIGINT PRIMARY KEY,
+    patient_user_id BIGINT NOT NULL,
+    doctor_user_id BIGINT NOT NULL,
+    appointment_time DATETIME NOT NULL,
+    actual_time DATETIME,
+    status VARCHAR(20) NOT NULL,
+    reason TEXT,
+    notes TEXT,
+    create_user BIGINT,
+    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
+    update_user BIGINT,
+    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    version INT DEFAULT 0,
+    remark VARCHAR(255)
+);
+CREATE INDEX idx_followup_patient ON t_follow_up(patient_user_id);
+CREATE INDEX idx_followup_doctor ON t_follow_up(doctor_user_id);
+CREATE INDEX idx_followup_appointment ON t_follow_up(appointment_time);
+CREATE INDEX idx_followup_create ON t_follow_up(create_time);
+```
+
+备注:对外响应的 `id` 建议以字符串形式返回以避免前端 JS 精度丢失(参见 `docs/OLD/DevRule/03-API设计规范.md` 的长整型 ID 传输策略)。
+
 ## 3. 实体类设计
 
 ### 3.1 PO实体类 (FollowUp.java)
@@ -550,9 +583,11 @@ public class FollowUpController {
             content = @Content(mediaType = "application/json",
                 schema = @Schema(implementation = Void.class)))
     })
-    @PostMapping(path = "/update", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
-    public R<?> update(@RequestBody UpdateFollowUpRequest req) {
+    @PutMapping(path = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+    public R<?> update(@PathVariable Long id, @RequestBody UpdateFollowUpRequest req) {
         try {
+            // 将路径ID赋值到请求对象,保证一致性
+            req.setId(id);
             followUpService.updateFollowUp(req);
             return R.success(200, "复诊记录更新成功");
         } catch (Exception e) {
@@ -597,7 +632,7 @@ public class FollowUpController {
                 schema = @Schema(implementation = Void.class)))
     })
     @PostMapping(path = "/list-by-patient", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
-    public R<?> listByPatient(Long patientUserId, @RequestBody BaseQueryRequest req) {
+    public R<?> listByPatient(@RequestParam("patientUserId") Long patientUserId, @RequestBody BaseQueryRequest req) {
         try {
             Page<FollowUpResponse> page = followUpService.listFollowUpsByPatient(patientUserId, req);
             work.baiyun.chronicdiseaseapp.model.vo.FollowUpPageResponse vo = new work.baiyun.chronicdiseaseapp.model.vo.FollowUpPageResponse();
@@ -622,10 +657,10 @@ public class FollowUpController {
             content = @Content(mediaType = "application/json",
                 schema = @Schema(implementation = Void.class)))
     })
-    @PostMapping(path = "/delete", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
-    public R<?> delete(@RequestBody work.baiyun.chronicdiseaseapp.model.vo.DeleteFollowUpRequest req) {
+    @DeleteMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+    public R<?> delete(@PathVariable Long id) {
         try {
-            followUpService.deleteFollowUp(req.getId());
+            followUpService.deleteFollowUp(id);
             return R.success(200, "复诊记录删除成功");
         } catch (Exception e) {
             logger.error("delete follow up record failed", e);
@@ -724,7 +759,35 @@ CANCELLED(已取消)
 
 ## 12. 安全考虑
 
-1. 数据访问权限控制
-2. 参数验证和输入检查
-3. 防止SQL注入
-4. 日志记录和审计追踪
+本项目安全实现应遵循 `docs/OLD/DevRule/08-安全规范.md` 中的已有约定,以下为与复诊管理功能相关的要点(需在实现时落地):
+
+1. **认证与授权**:
+    - 使用 Token(优先 `Authorization: Bearer <token>`,兼容 `X-Token` / `token`)并通过 `AuthInterceptor` 校验,将 `currentUserId`/`currentUserRole` 注入请求上下文。
+    - 仅允许符合角色与绑定关系的用户访问资源(患者仅访问本人,医生访问分配给自己的或其患者,系统管理员可查看所有记录)。
+
+2. **输入校验**:
+    - 使用 Bean Validation 注解(`@NotNull`、`@Future` 等)对请求参数进行校验。
+    - 对时间类型(`appointmentTime`)增加业务校验:不可为过去时间、合法时间窗口、与已有预约冲突的检测。
+
+3. **异常与统一错误响应**:
+    - 使用全局异常处理器(`@RestControllerAdvice`/`CustomExceptionHandler`)统一映射 `CustomException`、校验异常、未知异常到 `R.fail(code, message)`,并返回合适的 HTTP 状态码(如 400/403/404/500)。
+    - 业务异常(如 `FOLLOW_UP_NOT_FOUND` / `FOLLOW_UP_ACCESS_DENIED`)应使用明确错误码并在 `ErrorCode` 中定义。
+
+4. **日志与敏感信息**:
+    - 在日志中避免记录完整 Token 或敏感字段;若需记录,脱敏或仅记录前 8 位。
+    - 记录关键审计事件:创建、更新、取消、完成、删除等操作的用户 ID 与时间戳。
+
+5. **SQL 注入与 ORM 使用**:
+    - 使用 MyBatis-Plus 提供的预编译与条件构造器,禁止使用字符串拼接构建 SQL。
+
+6. **会话安全与 Token 管理**:
+    - Token 存储与过期策略遵循全局规范(存 `t_user_token`,有效期 72 小时,低于阈值自动延长)。
+
+7. **部署/传输**:
+    - 建议生产环境使用 HTTPS,证书放置在 `classpath:cert/` 并在启动时加载。
+
+8. **最小权限原则**:
+    - 服务端对每个接口、数据读取与修改操作都进行基于角色的授权校验,不信任前端传入的角色或用户 ID。
+
+9. **审计与监控**:
+    - 对认证失败、权限拒绝、异常错误等关键安全事件进行集中日志与告警(便于安全分析)。