183 lines
13 KiB
Markdown
183 lines
13 KiB
Markdown
# 健康业务模块与身份模型
|
||
|
||
更新日期:2026-10-05。实施仓库:`elder-yudao-pro`,分支:`axr`。
|
||
|
||
## 1. 本次业务决定
|
||
|
||
以下规则来自用户本次确认,后续开发应沿用:
|
||
|
||
- 老人、志愿者、家属使用 **手机号+密码** 登录,短信验证后续接入。
|
||
- **每个账号只有一种业务身份**,不能同时是老人、志愿者和家属。后台管理员属于另一套账号体系。
|
||
- 志愿者需要管理员审核,通过且启用后才能参与志愿服务。
|
||
- 第一版由管理员创建账号与身份档案,后续再开放本人注册。
|
||
- 一位老人可关联多位家属,一位家属可关联多位老人。
|
||
- 家属关联需老人本人确认;管理员也可以核实后确认,必须填写核实理由。
|
||
- 家属只在关联已确认且双方身份有效时,才能读取关联老人的健康信息。
|
||
- 暂不删除已有源码、模块和目录;身份使用停用,关联使用解除,保留历史。
|
||
|
||
管理员核实方式、注册时的手机号验证流程,后续实现对应入口时再细化。目前没有公共密码注册接口。
|
||
|
||
## 2. 账号与身份的边界
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
System[system_users 后台管理员] --> Admin[管理端权限和审核]
|
||
Member[member_user 手机号账号] --> Identity[health_identity 单一业务身份]
|
||
Identity --> Elder[老人 health_elderly_profile]
|
||
Identity --> Volunteer[志愿者 health_volunteer_profile]
|
||
Identity --> Family[家属身份]
|
||
Family --> Relation[health_family_relation 待确认或已确认]
|
||
Relation --> Elder
|
||
```
|
||
|
||
`system` 的角色、菜单权限与 `health` 的业务身份用途不同。前台选择“老人”或“志愿者”不能获得该身份;后端按登录的 `memberId` 查询可信身份。
|
||
|
||
框架区分 `/admin-api` 的后台 Token 与 `/app-api` 的会员 Token。健康 APP Controller 额外使用 `@PreAuthorize("isAuthenticated()")`,因为本版本芋道的 APP 路径默认允许匿名进入。
|
||
|
||
| 名称 | 含义 | 使用位置 |
|
||
| --- | --- | --- |
|
||
| `adminUserId` | `system_users.id` | 审核管理员、管理端权限 |
|
||
| `memberId` | `member_user.id` | 手机号登录账号 |
|
||
| `identityId` | `health_identity.id` | 老人、志愿者或家属的业务身份 |
|
||
| `elderlyProfileId` | `health_elderly_profile.id` | 老人健康档案,后续评估与预约的主体 |
|
||
| `volunteerProfileId` | `health_volunteer_profile.id` | 志愿者服务资料,后续派单关联 |
|
||
| `relationId` | `health_family_relation.id` | 单条家属与老人关联 |
|
||
|
||
不同表的 ID 可以恰好相同,不能靠数值相同推导关联。创建账号、身份和对应档案在一个数据库事务内完成;账号密码使用芋道 BCrypt,响应不包含密码。
|
||
|
||
## 3. 模块与表
|
||
|
||
根 Maven 和 `yudao-server` 已启用 `member`、`health`。健康业务只有一个模块,按芋道惯例分为 `api/biz`,不引入新的微服务或通用工作流。
|
||
|
||
```
|
||
yudao-module-health/
|
||
yudao-module-health-api/ 模块间接口、DTO、身份枚举、错误码
|
||
yudao-module-health-biz/ Controller、Service、DO、Mapper、测试
|
||
yudao-ui-admin-vue3/src/
|
||
api/health/ 健康管理请求封装
|
||
views/health/identity/ 身份、基础档案与志愿者审核
|
||
views/health/family-relation/ 家属关联确认与解除
|
||
mysql_script/health/ 独立增量 SQL
|
||
```
|
||
|
||
所有健康表继承 `TenantBaseDO`,含租户、创建/更新和逻辑删除字段;使用框架租户拦截器,关联查询与建档校验均在当前租户内完成。
|
||
|
||
| 表 | 当前字段与约束 |
|
||
| --- | --- |
|
||
| `member_user` | 手机号、BCrypt 密码、账号状态;新建表添加 `(tenant_id,mobile)` 唯一索引 |
|
||
| `health_identity` | 账号、单一身份、姓名、性别、生日、联系方式、地址、启用状态、审核结果;`(tenant_id,member_id)` 唯一 |
|
||
| `health_elderly_profile` | 紧急联系人、健康摘要、病史、用药、特殊需求;每个老人身份一份基础档案 |
|
||
| `health_volunteer_profile` | 技能、服务区域、可服务时间说明、服务经验;每个志愿者身份一份服务档案 |
|
||
| `health_family_relation` | 家属身份、老人档案、亲属关系、确认/解除状态、处理账号类型与编号、时间、理由;同一配对唯一 |
|
||
|
||
当前不采集身份证号。生日存储为 `date`,年龄后续按生日计算。性别沿用芋道:`1=男、2=女、3=未知`;旧系统 `0=男、1=女` 必须显式转换。
|
||
|
||
手机号用于登录;`contactPhone` 是档案联系方式,不会因编辑档案而更改登录手机号。已有会员账号通过 `memberId` 显式绑定,建档不会重置其密码。身份类型和绑定账号创建后不可变更,避免后续服务记录主体发生变化。
|
||
|
||
账号停用和身份停用均会使业务身份校验失败。模板会员模块仍保留积分、等级等源码与空表,本次管理页面只展示健康相关功能。
|
||
|
||
## 4. 审核与关联状态
|
||
|
||
业务身份:`10=老人、20=志愿者、30=家属`。
|
||
|
||
启用状态:`0=启用、1=停用`。审核状态:`0=待审核、1=通过、2=驳回`。两者独立,启用一个待审志愿者不能使其获得服务权限。
|
||
|
||
- 管理员创建老人和家属身份时直接通过;创建志愿者时进入待审。
|
||
- 只有待审志愿者能审核;驳回必须填写理由。
|
||
- 驳回后可修改资料并重新提审;重复审核由条件更新拦截。
|
||
- 编辑档案不会修改启用或审核状态。
|
||
|
||
家属关联:`0=待确认、1=已确认、2=已拒绝、3=已解除`。
|
||
|
||
- 新增关联仅创建申请,不能自动获得读取权限。
|
||
- 本人端申请的家属身份取自登录账号,忽略请求中伪造的 `familyIdentityId`。
|
||
- 老人只能处理自己的关联;管理员核实确认或拒绝时必须填写理由。
|
||
- 老人、家属可解除本人的待确认/已确认关联;管理员也可解除,均需填写理由。
|
||
- 管理员可将已拒绝/已解除关联重新申请,此时必须重新确认才恢复授权。
|
||
- 处理字段保留最近一次审核/解除痕迹,尚不是完整的每次变更事件流水。
|
||
- 当前确认代表该家属可读取关联老人的基础健康档案;第一阶段不提供家属代预约。
|
||
|
||
## 5. 接口与权限
|
||
|
||
管理端前缀 `/admin-api`:
|
||
|
||
| 路径 | 功能 | 权限 |
|
||
| --- | --- | --- |
|
||
| `POST /health/identity/create` | 创建账号与身份档案,或绑定已有会员账号 | `health:identity:create` |
|
||
| `PUT /health/identity/update` | 编辑基本资料及对应档案 | `health:identity:update` |
|
||
| `GET /health/identity/get`、`/page` | 详情与分页筛选 | `health:identity:query` |
|
||
| `PUT /health/identity/audit`、`/resubmit` | 志愿者审核与重新提审 | `health:identity:audit` |
|
||
| `PUT /health/identity/update-status` | 身份启用与停用 | `health:identity:update-status` |
|
||
| `GET /health/family-relation/page` | 查看关联列表 | `health:family-relation:query` |
|
||
| `POST /health/family-relation/create` | 提交关联申请 | `health:family-relation:create` |
|
||
| `PUT /health/family-relation/review`、`/reopen` | 核实处理与重新申请 | `health:family-relation:review` |
|
||
| `PUT /health/family-relation/revoke` | 解除关联 | `health:family-relation:revoke` |
|
||
|
||
新增关联页面按姓名搜索老人和家属,同时需要 `health:identity:query`。普通后台角色应通过系统角色管理授予所需菜单与按钮权限;超级管理员默认拥有全部菜单。
|
||
|
||
会员端前缀 `/app-api`:
|
||
|
||
| 路径 | 当前行为 |
|
||
| --- | --- |
|
||
| `POST /member/auth/login` | 复用芋道的手机号与密码登录、Token 颁发 |
|
||
| `GET /health/identity/me` | 读取当前会员的单一身份与对应档案;可查看本人志愿者待审结果 |
|
||
| `GET /health/identity/family-relations` | 本人相关关联列表 |
|
||
| `POST /health/identity/family-relation/request` | 家属提交关联申请 |
|
||
| `PUT /health/identity/family-relation/review` | 老人本人确认或拒绝 |
|
||
| `PUT /health/identity/family-relation/revoke` | 老人或家属解除本人关联 |
|
||
| `GET /health/identity/family-elderly-profile` | 已确认家属按老人档案编号读取健康档案 |
|
||
|
||
本次提供 APP 后端接口,没有改造旧移动端。请求需正确的 Token 和 `tenant-id`;家属和老人账号类型同为 MEMBER,具体业务权限仍须健康服务校验。
|
||
|
||
其他模块调用 `HealthIdentityApi`:
|
||
|
||
- `getIdentityByMemberId` 仅查询身份,不表示身份有效。
|
||
- `requireActiveIdentity(memberId, identityType)` 检查账号存在/启用、业务身份类型、启用状态与审核结果。后续预约与接单使用此方法。
|
||
- `requireConfirmedFamilyRelation(familyMemberId, elderlyProfileId)` 检查双方有效及已确认关联。后续家属访问评估、运动与告警记录使用此方法。
|
||
- 本次没有提供志愿者读取任意老人健康档案的入口;后续必须结合已分配工单校验访问范围。
|
||
|
||
## 6. 数据库与 IDEA 运行
|
||
|
||
按顺序执行:
|
||
|
||
1. `V000__member_schema.sql`:从模板提取的 11 张会员表的纯 DDL,去掉 DROP、示例账号、演示数据及自增起点。
|
||
2. `V001__health_identity.sql`:新增 4 张健康业务表与唯一索引。
|
||
3. `V002__health_menu.sql`:新增“健康服务 → 身份与档案、家属关联”及按钮权限。
|
||
|
||
均使用存在性判断,不清空数据。`CREATE TABLE IF NOT EXISTS` 不会升级已有旧表结构;若已有 member_user 缺少约定唯一索引,初始化脚本会停止并提示核实,不能直接覆盖已有表。
|
||
|
||
在项目根目录执行:
|
||
|
||
```powershell
|
||
powershell -ExecutionPolicy Bypass -File .\deploy\local\initialize-health.ps1
|
||
```
|
||
|
||
脚本读取已有的私有 `secrets.psd1`,仅允许操作 `elder_yudao_*` 本地独立数据库。不会导入旧老年系统数据,不会初始化摄像头、短信或外部呼叫服务。
|
||
|
||
IDEA 点击 Maven 的 Reload All Maven Projects,再重新运行已有的后端和前端启动配置。前端 `.env` 已增加 `health`;模板会员商城页面未加入产品菜单。
|
||
|
||
管理端重新登录后进入“健康服务”,可以新建老人、志愿者和家属档案,审批志愿者、申请和核实家属关联。
|
||
|
||
## 7. 旧系统迁移注意事项与下一步
|
||
|
||
旧数据库 `sys_user.user_id` 是登录编号,`elderly_info.elderly_id` 是档案编号;一些旧家属代码把 `elderly_id` 当作登录编号。不能直接沿用旧字段名解释。正式导入时需要 legacy ID 映射,明确旧登录 ID → 新 memberId、旧档案 ID → 新 elderlyProfileId、旧采集记录 ID → 新 assessmentId。
|
||
|
||
旧健康采集和评估允许多次记录。当前 `health_elderly_profile` 是基础档案,不能把所有历史评估覆盖到这一行。下一阶段应建立独立评估记录、保存时间及原始指标,再逐项迁移已核实的评分逻辑。
|
||
|
||
后续既定顺序:健康采集与评估 → 轻量运动/场地/设备 → 自由预约与活动报名 → 志愿者匹配/派单/按月拒单理由 → 提醒;LLM/智能体和固定场地摄像头另行接入。摄像头跌倒检测、最近 72 小时视频保存、自动呼叫 120 都尚未实现,老人无回应的判定仍待讨论。
|
||
|
||
新增能力继续放在 health 的独立包与表中,预约使用老人档案编号,派单使用志愿者身份/服务档案编号,健康历史数据单独保存。不要将手机号、密码或管理员角色塞进健康评估表。
|
||
|
||
参考:[迁移上下文](芋道框架迁移上下文.md)、[扩展需求草案](老年健康系统扩展需求与设计草案.md)、[项目目录说明](项目目录说明.md)。扩展草案是历史需求记录,具体已实现内容以本文和代码为准。
|
||
|
||
## 8. 验证记录
|
||
|
||
- Maven 后端打包通过,`HealthIdentityServiceTest` 的 9 项测试全部通过:加密账号/档案创建、事务回滚、单身份约束、重复手机号不重置密码、志愿者审核与停用、家属确认与解除、伪造身份拦截及多对多、租户隔离、匿名 APP 调用拦截。
|
||
- Vue 管理端 desktop 生产构建通过,新增文件 ESLint 检查通过。
|
||
- 前端原始全量 `vue-tsc` 因既有类型声明路径配置报 TS2688;使用临时检查配置补充核实后,新增 health 页面/API 没有类型错误,但模板其他页面/组件仍有既有错误,不能宣称全仓库类型检查通过。
|
||
- 本地 `elder_yudao_local` 增量初始化完成,共 76 张表(原 61+member 11+health 4);脚本重复执行验证通过,健康账号与关联表保持空数据。
|
||
- 临时后端在 `48081`、Redis DB 14 验证后已关闭;已有 `48080` 后端和 `5173` 前端进程未重启。新代码需要由用户在 IDEA 重新运行。
|
||
- 实际 HTTP 验证通过:管理员登录、身份与关联分页、新增两个健康菜单、匿名 APP 拒绝(业务码 403)、后台 Token 调用 APP 拒绝(403)、错误手机号拒绝(400)、匿名后台接口拒绝(401)。未创建演示会员账号。
|
||
|
||
未迁移旧数据,未改造移动端页面,未实现历次健康评估、预约派单或设备/智能体接入;这些仍是后续阶段。
|