体格数据功能设计文档.md 5.8 KB

体格数据功能设计文档

概述: 本文档描述系统中体格(Physical)数据的上报、查询与删除能力,以及相关权限、审计与存储设计。对应代码位置:src/main/java/.../controller/PhysicalDataController.javaservice/PhysicalDataService、数据库表 t_physical_data

目标: 允许患者上报身高/体重等体格测量值,系统可计算并返回 BMI;允许绑定方(医生/家属)在存在绑定关系时查询患者体格数据;保证访问受限并记录审计日志以便追溯。

接口清单:

  • 添加体格数据

    • 路径: POST /physical/add
    • 描述: 患者上报一条体格测量记录(身高、体重)。
    • 请求体: AddPhysicalDataRequest (application/json)
    • height: BigDecimal,身高(cm),必填,范围 [100, 250]
    • weight: BigDecimal,体重(kg),必填,范围 [20, 300]
    • measureTime: LocalDateTime,测量时间,必填
    • 服务端行为:
    • 计算 BMI = weight(kg) / (height(m))^2 并持久化(或在返回时计算)
    • 将记录 user_id 设为当前 token 对应用户
    • 响应: 标准 R 成功/失败返回。
    • 校验: 注解校验(@NotNull, @DecimalMin, @DecimalMax),并在 service 层校验合理时间窗口。
  • 分页查询体格数据(本人)

    • 路径: POST /physical/list
    • 描述: 当前用户根据时间范围和分页参数查询自己的体格记录。
    • 请求体: BaseQueryRequest (application/json)
    • pageNum: 页码,默认 1
    • pageSize: 每页大小,默认 10
    • startTime, endTime: 可选时间范围
    • 响应: PhysicalDataPageResponse,包含分页 metadata 与 PhysicalDataResponse 列表(含 bmi 字段)。
  • 绑定方分页查询患者体格数据

    • 路径: POST /physical/list-by-bound-user
    • 描述: 医生或家属查询目标患者体格记录(需有绑定关系)。
    • 参数: patientUserId (Long, 必填),bindingType (String, 可选),请求体 BaseQueryRequest
    • 权限检查流程:
    • 获取当前发起查询的用户 boundUserId(从 token / SecurityUtils)
    • 调用 UserBindingService.checkUserBinding 验证绑定关系
    • 若不存在绑定关系,返回 DATA_ACCESS_DENIED
    • 若存在且 bindingType 为空,则从检查结果中使用绑定类型
    • 审计: 记录访问日志(logger.info),包含访问方、患者、时间范围与数据类型(type=physical)。
    • 响应: 同 list,返回 PhysicalDataPageResponse
  • 删除体格数据

    • 路径: POST /physical/delete
    • 描述: 根据记录 ID 删除体格数据(通常仅允许记录创建者或有权限的管理方删除,具体权限在 service 层实现)。
    • 请求体: DeletePhysicalDataRequest,包含 id (Long,必填)
    • 响应: 标准 R 成功/失败返回。

数据模型 (VO / PO)

  • 请求/响应 VO:

    • AddPhysicalDataRequest:
    • height : BigDecimal (cm)
    • weight : BigDecimal (kg)
    • measureTime : LocalDateTime
    • PhysicalDataResponse:
    • id : String
    • height : BigDecimal
    • weight : BigDecimal
    • bmi : BigDecimal
    • measureTime : LocalDateTime
    • createTime : LocalDateTime
  • 持久化表: t_physical_data(建议字段)

    • 建议字段: id, user_id, height_cm, weight_kg, bmi, measure_time, create_time, update_time, deleted_flag

校验规则

  • height 非空且 100-250 cm。
  • weight 非空且 20-300 kg。
  • measureTime 非空且不晚于服务器当前时间(service 层可增强校验)。

权限与访问控制

  • 上报数据: 需要登录,记录写入当前用户(user_id 从 token 中获取)。
  • 个人查询: 仅返回当前登录用户的数据。
  • 绑定方查询: 必须存在绑定关系(通过 UserBindingService.checkUserBinding),否则返回 DATA_ACCESS_DENIED
  • 删除操作: service 层应校验调用者是否为记录所有者或拥有管理权限。

审计与日志

  • list-by-bound-user 接口中记录访问日志:记录访问方 ID、患者 ID、数据类型(physical)、查询时间范围。
  • 在新增/删除等关键操作处建议记录操作日志用于审计。

错误码

  • 参考 ErrorCode 枚举:
    • PARAMETER_ERROR (1001):请求参数缺失或校验失败
    • SYSTEM_ERROR (1000):服务器内部错误
    • UNAUTHORIZED (1002):未授权(token 无效)
    • DATA_ACCESS_DENIED (4001):绑定方访问时无权限
    • DATA_NOT_FOUND (4000):删除/查询的记录不存在

服务与 Mapper 关系

  • Controller -> PhysicalDataService(负责业务校验、权限判断、持久化调用、分页查询实现)
  • Service -> Mapper (PhysicalDataMapper) 与 t_physical_data 表交互

兼容性与注意事项

  • BMI 计算注意单位转换:height 从 cm 转为 m 后计算,即 bmi = weight / (height/100)^2。
  • 时间字段使用 LocalDateTime,前端需按约定时区/格式发送(建议 ISO-8601)。
  • 分页返回使用 MyBatis-Plus Page,Controller 将其转换为页面友好格式 PhysicalDataPageResponse

示例

  • 添加请求示例:

    {
    "height": 170.5,
    "weight": 65.2,
    "measureTime": "2025-11-20T09:00:00"
    }
    
  • 查询(分页)请求示例:

    {
    "pageNum": 1,
    "pageSize": 20,
    "startTime": "2025-11-01T00:00:00",
    "endTime": "2025-11-21T23:59:59"
    }
    
  • 响应示例 (分页 records 片段):

    {
    "records": [
    {
      "id": "phy-001",
      "height": 170.5,
      "weight": 65.2,
      "bmi": 22.43,
      "measureTime": "2025-11-20T09:00:00",
      "createTime": "2025-11-20T09:05:00"
    }
    ],
    "total": 1,
    "size": 20,
    "current": 1
    }
    

后续建议

  • 在 Service 层补充更严格的校验与权限逻辑(删除权限、measureTime 范围限制等),并在必要处记录操作审计日志。