作者:974294341-bit | 技术栈:Spring Boot 3 / Vue3 / MySQL·H2 | 标准:MZ/T 039-2013
-
为什么写这篇
起因很朴素:动手做这个项目前,在 B 站刷到两个"老年人能力评估系统"的视频,一个是微信小程序版、一个是机构 Web 版。看演示挺像回事,但点进去只有解说,没有源码、没有题库、没有打分逻辑。
作为一个想真正搞懂"它到底怎么算出来'失能等级'"的人,光看演示没用。于是我做了三件事: -
逆向这两个系统的设计与架构(设计级,非反编译);
-
扒标准——找到民政部《老年人能力评估》MZ/T 039-2013,把"22 题怎么评、等级怎么定"搞透;
-
自己落地一套能跑的系统:电脑端管理后台 + 后端评估引擎(手机端原生 App 下轮做)。
这篇博客就是这条链路的完整记录,重点放在评估算法怎么工程化和踩过的坑,而不是堆界面截图。 -
逆向对象:两个系统的真实面貌
两个 B 站链接都是搜索聚合落地页,拿不到源码,所以做的是设计级逆向——基于公开描述 + 国标框架还原架构。结论如下:
系统 A(教学演示向)
系统 B(机构专业向)
形态
微信小程序(C 端)+ Web 后台
Web 系统(机构/医养场景)
角色
老人 / 自评师 / 管理员(3 类)
评估员 / 管理员
技术栈
Spring + Vue3 + Bootstrap + 小程序
同类 Web(框架未明示)
评估类型
单一(国标能力评估)
多量表(能力/认知/营养…)
特色
自评 + 评估师建议 + 统计看板
AI 处方 + 详细/简易双报告
定位
轻量/教学演示
专业评估/干预闭环
关键启发来自系统 B:它"支持多种评估类型"的本质,是把量表配置化——一套表结构能吃下所有量表,加新量表 = 插几条数据,不碰代码。这一点我直接吸收进了自己的设计。 -
标准深挖:评估到底怎么算
拿到 MZ/T 039-2013 标准后,核心模型非常清晰,是一个四层结构:
22 个二级指标(逐项 0~4 评分)
↓ 求和
4 个一级指标
↓ 按得分区间划级
一级指标等级(0 能力完好 ~ 3 重度受损)
↓ 组合判定(ADL 权重最高)
综合能力等级(0 能力完好 ~ 3 重度失能)
2.1 4 个一级指标 + 22 个二级指标
一级指标
满分
二级指标(数量)
日常生活活动(ADL)
40
进食、洗澡、修饰、穿衣、大便控制、小便控制、如厕、床椅转移、平地行走、上下楼梯(10)
精神状态
8
认知功能、攻击行为、抑郁症状(3)
感知觉与沟通
10
意识水平、视力、听力、沟通交流(4)
社会参与
20
生活能力、工作能力、时间/空间定向、人物定向、社会交往能力(5)
多数项目 04 分(4=完好,0=完全丧失);部分损伤类项目(攻击行为、抑郁、视力、听力、意识)只用 02 档。
2.2 综合等级判定(2013 版核心)
不是简单取平均分,日常生活活动(ADL)权重最高。判定规则:
- 0 级 能力完好:4 个维度全为 0 级
- 1 级 轻度失能:出现 1 级且无更高
- 2 级 中度失能:出现 2 级(或 ADL=1 且其他有 ≥1 项为 2 级)
- 3 级 重度失能:任一维度=3 级(或 ADL=2 且其他 ≥2 项为 2/3 级;或 ADL=3)
2.3 一个易踩的版本坑
MZ/T 039-2013(2013 版)和 GB/T 42195-2022(2022 版)不是一回事:
- 2013 版 = 22 题、能力分 4 级(0~3)
- 2022 版 = 26 题、能力分 5 级(新增"完全失能"4 级)
拿源码后第一件事,就是确认它吃的是哪一版,决定题库是 22 还是 26、等级是 4 还是 5 档。我这里先按 2013 版实现。
-
关键决策:不要小程序,要原生 App
用户(也是我自己做项目时的硬性要求)明确:电脑端 + 手机端 App,不要微信小程序。
手机端技术选型当时对比了三种:
方案
优点
缺点
结论
Flutter
一套代码出 Android+iOS 真机,最像"正经 App"
多学一门 Dart
最省事但非首选
Android Kotlin 原生
与 Java 后端生态近、项目演示有说服力
只有 Android,无 iOS
选定(下轮做)
React Native
前端 React 复用
与现成 Vue 后台不共用
排除
最终落地节奏:后端 Spring Boot + 电脑端 Vue 管理后台先跑通,手机端 Android(Kotlin + Retrofit + Compose)复用同一套 REST API,不改后端。 -
工程落地(核心)
项目路径:elder-assessment-engine/,约 1266 行代码,结构如下:
elder-assessment-engine/
├── pom.xml # Spring Boot 3 / Java 17
├── sql/elder_assessment_mzt039_2013.sql # 生产建表 + 22 题选项 JSON
├── src/main/java/com/example/elder/
│ ├── assessment/AssessmentEngine.java # ★ 评估算法核心
│ ├── entity/ # Elder, Scale, ScaleItem, ScaleResult, ScaleAnswer...
│ ├── repo/ # Spring Data JPA
│ ├── service/ # 评估业务
│ ├── controller/ # /api/scale, /api/elders, /api/assessments
│ ├── config/ # CORS + 启动种子数据
│ └── dto/
└── frontend/ # Vue3 + Vite + Element Plus
└── src/views/ # ElderList(建档) / Assessment(22题表单) / Report(双报告)
4.1 评估引擎(最重要的一块)
把"四层模型"直接写成纯 Java 方法,不依赖框架,方便独立测试。维度满分硬编码为 DIM_MAX = {40, 8, 10, 20},22 题按题号映射到 4 个维度:
// 题号(1~22) → 维度下标:1-10→ADL, 11-13→精神, 14-17→感知, 18-22→社会
private static int[] buildItemDim() {
int[] a = new int[23];
for (int i = 1; i <= 10; i++) a[i] = 0; // 日常生活活动
for (int i = 11; i <= 13; i++) a[i] = 1; // 精神状态
for (int i = 14; i <= 17; i++) a[i] = 2; // 感知觉与沟通
for (int i = 18; i <= 22; i++) a[i] = 3; // 社会参与
return a;
}
综合定级就是标准里那段组合规则的直接翻译,ADL 权重最高:
public static int comprehensiveLevel(int[] dimLevels) {
if (Arrays.stream(dimLevels).allMatch(l -> l == 0)) return 0; // 全 0 → 完好
int adl = dimLevels[0];
if (adl == 3) return 3; // ADL 重度 → 综合重度
if (Arrays.stream(dimLevels).anyMatch(l -> l == 3)) return 3; // 任一维度重度
int othersGE2 = 0;
for (int i = 1; i < 4; i++) if (dimLevels[i] >= 2) othersGE2++;
if (adl == 2 && othersGE2 >= 2) return 3; // ADL 中度 + 其他≥2项中度
if (Arrays.stream(dimLevels).anyMatch(l -> l == 2)) return 2; // 任一中度
if (adl == 1 && othersGE2 >= 1) return 2;
if (Arrays.stream(dimLevels).anyMatch(l -> l == 1)) return 1; // 任一轻度
return 0;
}
主入口 assess(answers, thresholds):题号→分值 + 各维度等级阈值 → 返回四个维度原始分、维度等级、综合等级与名称。
4.2 后端 Spring Boot
- 表设计沿用"多量表配置化"思路:scale / scale_dimension / scale_item / scale_result / scale_answer / scale_dimension_level。当前只挂了 MZ/T 039-2013 一张量表,但结构能无缝扩展认知、营养等量表。
- REST API(前端直接消费):
- GET /api/scale —— 拉取评估表单(维度+题目+选项)
- GET/POST/PUT /api/elders —— 老人建档管理
- POST /api/assessments —— 提交 22 题答案,返回定级结果
- GET /api/assessments/{id}/report —— 详细/简易双报告
- dev 用 H2 内存库 + 启动自动种子(4 维度 / 22 题 / 等级阈值 / 演示老人),开箱即跑;application-prod.yml 切 MySQL。
4.3 电脑端 Vue3 管理后台
三个页面串起完整业务流:
老人管理(建档) → 去评估(22 题表单, 按维度分组渲染) → 提交 → 查看报告(详细/简易)
技术:Vue3 + Vite + Element Plus,vite build 通过(1666 模块,exit 0),所有 SFC 编译正常。
- 踩坑与校准(干货)
5.1 定级阈值不能拍脑袋 ⚠️
维度原始分 → 维度等级,需要阈值(如 ADL ≥36 为 0 级)。我代码里留了 thresholds 注入点,但默认值只是"按满分百分比"的近似(90% / 75% / 50%)。
上线前必须做:用你标准附录《一级指标等级划分》的精确分值覆盖 scale_dimension_level 表,否则定级结果可能与官方不一致。这是整个系统最容易"看起来对、实际错"的地方。
5.2 本机环境的两个真实坑
- PATH 里的 java/javac 是坏的(指向一个不完整的 JDK),编译要显式用可用的 JDK 17,且务必带 -encoding UTF-8,否则中文注释直接 GBK 报错。
- Maven 全量构建在本环境受限(中央仓库被代理拦截),所以后端我做了"引擎独立编译 + 前端完整构建"两级验证,没有硬跑 mvn package。代码是标准 Spring Boot 写法,你本机 mvn spring-boot:run 即可。
5.3 "AI 处方"是医疗敏感词
系统 B 的卖点"AI 处方",在医养语境下本质是干预/照护方案,不是开药。若要做:
- 干预项来自人工维护的目录(可审计),LLM 只做自然语言润色,不自主诊断;
- 输出需人工审核留痕(auditor_id),无资质场景不做诊断。否则合规风险很大。
-
验证结果
验证项
结果
评估引擎独立编译(JDK 17, UTF-8)
✅ 通过
前端 npm install + vite build(1666 模块)
✅ 通过
后端全量 mvn 打包
⚠️ 本环境受限,未跑;标准写法,本机可启 -
本地运行
后端(默认 H2 内存库,:8080)
cd elder-assessment-engine
mvn spring-boot:run
电脑端(:5173,已配 /api 代理到 8080)
cd elder-assessment-engine/frontend
npm install && npm run dev
体验路径:老人管理 → 新建 → 去评估 → 答 22 题 → 提交 → 看详细/简易报告。
-
后续规划
-
手机端 Android 原生 App(Kotlin + Retrofit + Compose):复用现有 /api/*,无需改后端,下一轮做。
-
扩展多量表 + AI 处方引擎:接系统 B 的设计——规则引擎出干预项、LLM 做文案润色、人工审核留痕。
-
升级 GB/T 42195-2022:若目标系统实为 2022 版,扩题库到 26 题、等级到 5 档。
-
小结
这次从"看两个视频"到"自己写出能跑的评估引擎",最大的体会是:项目里的"智能评估"剥掉包装,核心就是"一套标准 + 一张题库表 + 一段定级函数"。把国标吃透、把算法写成可单测的纯函数,比堆界面有价值得多。
逆向的价值不在"抄",在于逼自己把别人的演示翻译成可验证的工程实现——然后你会发现,很多"高大上"的系统,骨架也就这么大。
源码已落地于 elder-assessment-engine/,欢迎按需取用、校准阈值后用于学习或二次开发。
浙公网安备 33010602011771号