评估漏测检查 — 数据取值规则
一12项必查评估类型
▼系统定义了 12种必查评估类型(代码常量 REQUIRED_TYPES),每位在住老人每年均需完成全部12项。任何一项缺失即记为"漏评"。
| 序号 | 评估类型名称 | 说明 |
|---|---|---|
| 1 | 能力评估 | 综合能力评定(ADL/IADL) |
| 2 | 压疮风险评估 | Braden压疮风险筛查 |
| 3 | 食品药品误食风险评估 | 吞咽功能/误食风险筛查 |
| 4 | 坠床风险评估 | Morse坠床风险量表 |
| 5 | 噎食风险评估 | 进食噎食风险评估 |
| 6 | 烫伤风险评估 | 热水/热食烫伤风险筛查 |
| 7 | 他伤自伤风险评估 | 精神行为异常风险评估 |
| 8 | 走失风险评估 | 认知障碍走失风险筛查 |
| 9 | 跌倒风险评估 | Morse跌倒风险评估 |
| 10 | 文娱活动风险评估 | 参与文娱活动的安全风险 |
| 11 | 误吸 | 吞咽功能障碍误吸评估 |
| 12 | 营养 | 营养状态筛查(MNA等) |
⚠️ 注意:
assessment_records 表中可能存在非必查类型的记录(如"管路滑脱"、"约束"、"精神"、"疼痛"、"抑郁"、"血栓"、"睡眠"等)。这些类型不计入12项必查统计中。
# analyze_assessment.py 第31-36行
REQUIRED_TYPES = [
"能力评估", "压疮风险评估", "食品药品误食风险评估",
"坠床风险评估", "噎食风险评估", "烫伤风险评估",
"他伤自伤风险评估", "走失风险评估", "跌倒风险评估",
"文娱活动风险评估", "误吸", "营养",
]
二核心分析逻辑
▼2.1 分析总流程(3步)
┌─────────────────────────────────────────────┐
│ Step 1: 从 resident_info 读取入住协议主数据 │
│ → 获取所有老人名单 + 状态信息 │
└──────────────────┬──────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ Step 2: 从 assessment_records 匹配评估记录 │
│ → 只保留协议内人员的记录 │
│ → 按人按类型汇总 year_types 集合 │
│ → 协议内但无记录的 → 补充为空集合 │
└──────────────────┬──────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ Step 3: 对每人计算完成情况 │
│ → 判断在住/离院 │
│ → 在住者:看最新评估是否当年 │
│ → 计算 completed / missing │
│ → 写入 assessment_analysis 表 │
└─────────────────────────────────────────────┘
2.2 在住老人的完成判定(最关键逻辑)
# analyze_assessment.py 第183-193行 — 核心判定伪代码
if is_discharged:
completed = set() # ← 离院:强制清空
else:
latest_date = 该人的最新评估日期
latest_year = latest_date 的前4位
if latest_year == 当前分析年份:
completed = year_types # ✓ 最新评估是当年的 → 认可
else:
completed = set() # ✗ 最新评估不是当年 → 清空!
missing = [t for t in REQUIRED_TYPES if t not in completed]
关键理解:系统不是简单统计"今年做了哪些评估",而是先判断最新一次评估是否在今年。只有最新评估在当年,才认可该人今年的已完成评估;否则全部清零视为"未评估"。这是为了防止用旧年份数据冒充当年数据。
| 场景 | completed 结果 | missing_count | status_summary |
|---|---|---|---|
| 最新评估日期 = 2026-05-20 year_types 含 ["能力评估","跌倒"] |
["能力评估","跌倒"] | 10 | 漏评10项 |
| 最新评估日期 = 2025-12-01 即使有2026年的记录(不可能) |
[] (空) | 12 | 漏评12项 |
| 无任何评估记录 | [] (空) | 12 | 漏评12项 |
2.3 同一人同类型的多次评估
- 同一人在同一年内对同一评估类型可能有多条记录
- 使用 Set 集合 去重——只要该类型至少有一条当年记录,就计入已完成
- 取最新一条记录的
assessor、score、assessment_date作为展示信息(后续覆盖先前的)
三数据源与人员范围
▼3.1 涉及的数据表
| 表名 | 角色 | 关键字段 |
|---|---|---|
resident_info | 主数据(权威源) | id_number, caregiver_name, institution, area, bed_number, admission_date, status, leave_date, care_level, age |
assessment_records | 原始评估记录 | id_number, caregiver_name, assessment_type, assessment_date, assessor, score |
assessment_analysis | 分析结果缓存表 | analysis_year, id_number, completed_types, missing_count, is_discharged, type_details ... |
3.2 人员范围规则
- 只分析 resident_info 表中存在的老人(以身份证号为唯一匹配条件)
assessment_records中身份证号不在resident_info中的记录 → 直接跳过(视为脏数据)resident_info中有但assessment_records完全没有的人 → 补充进来,标记为12项全缺
即:resident_info 是唯一权威的人员清单。不在协议里的人,无论评估记录有多少条,都不参与分析。
四离院处理规则
▼4.1 判断标准
# analyze_assessment.py 第132行
_is_discharged = info["status"] == "离院"
当 resident_info.status == "离院" 时,判定该老人已离院。
4.2 离院的特殊处理
| 属性 | 值 |
|---|---|
| completed(完成列表) | 强制为 空集 [] —— 无论实际有多少评估记录 |
| missing_count | 始终为 12 |
| is_complete | 始终为 false |
| is_discharged | 始终为 true |
| status_summary | "离院"(不显示漏评数量) |
| 参与"在住"统计? | 不参与—— 排除在 active/complete/missed 统计之外 |
| 排序位置 | 排在最前面(is_discharged ASC 优先) |
重要:离院老人即使有2026年的完整12项评估记录,系统也会将其 completed 强制置空。这是业务规则要求——离院后不再考核评估完成度。
示例:离院老人数据
| 字段 | 值 |
|---|---|
| caregiver_name | 姚世瑞 |
| institution | 富贵山颐养中心 |
| status (resident_info) | 离院 |
| discharge_date | 2025-11-30 |
| completed_types | [] (强制清空) |
| completed_count | 0 |
| missing_count | 12 |
| status_summary | 离院 |
五"当年未评估"特殊场景
▼5.1 什么是"当年未评估"?
指老人在住、且历史上有过评估记录,但最近一次评估的年份 ≠ 当前分析年份。
# 核心逻辑(第188-193行)
latest_year = latest_date[:4] # 如 "2025"
if latest_year == str(year): # year=2026
completed = year_types # 认可
else:
completed = set() # 全部清空!
not_this_year_count += 1 # 计入"当年未评估"统计
5.2 具体场景举例
| 场景描述 | latest_date | latest_year | 分析年份 | 结果 |
|---|---|---|---|---|
| 今年正常评估了几项 | 2026-05-20 | 2026 | 2026 | ✓ 正常计算 |
| 去年评估过,今年还没做 | 2025-11-15 | 2025 | 2026 | ✗ completed=[], missing=12 |
| 从未做过任何评估 | (空) | (空) | 2026 | ✗ completed=[], missing=12 |
这个设计确保了:不会因为去年的旧记录而让某人看起来"已经完成了今年的评估"。每年必须重新做评估才能被计数。
六同步与分析流程
▼6.1 "同步"按钮(两步合一)
点击页面上的「同步」按钮,会依次执行两个步骤:
用户点击 [同步]
│
▼
┌─────────────────────┐
│ Step 1: 同步评估数据 │ python3 sync_assessment.py --full
│ (从轻流API拉取最新 │ 超时: 20分钟
│ assessment_records) │
└──────────┬──────────┘
│ 成功?
▼
┌─────────────────────┐
│ Step 2: 分析漏评 │ python3 analyze_assessment.py
│ (重算 analysis表) │ 超时: 10分钟
└──────────┬──────────┘
│
▼
完成! 返回前端结果
6.2 "重新分析"按钮(仅第2步)
点击「重新分析」按钮,只执行 Step 2(跳过数据同步),直接基于当前数据库内容重新运行分析脚本。
| 同步按钮 | 重新分析按钮 | |
|---|---|---|
| 步骤1: 拉取数据 | ✓ 执行 | ✗ 跳过 |
| 步骤2: 重算分析 | ✓ 执行 | ✓ 执行 |
| 适用场景 | 需要最新轻流数据时 | 手动改了DB想刷新结果时 |
| 预计耗时 | 2~3 分钟 | 30秒 ~ 1分钟 |
6.3 异步任务机制
- 同步和分析都在后台线程中异步执行,不阻塞HTTP响应
- 前端通过轮询
/api/assessment/task/status获取进度 - 如果已有任务正在运行,再次点击会被拒绝并提示"任务正在进行中"
- 状态写入
.assessment_task文件持久化
| step | message | 说明 |
|---|---|---|
| sync | 正在同步评估数据... | Step 1 进行中 |
| analyze | 正在分析漏评... | Step 2 进行中 |
| done | 同步+分析完成 | 全部完成 |
| error | 同步失败 / 分析失败 | 出错 |
七输出数据结构
▼7.1 API返回结构 (/api/assessment/result)
{
"success": true,
"data": {
"year": "2026",
"total": 113, // 协议内总人数
"page": 1,
"page_size": 50,
"total_pages": 3,
"stats": {
"active": 113, // 在住人数
"complete": 0, // 12项全部完成
"missed": 113, // 有漏评的在住人数
"not_this_year": 55 // 最新评估非本年度
},
"filters": {
"institutions": [...], // 可选机构
"areas": [...], // 可选区域
"care_levels": [...] // 护理等级选项
},
"people": [ // 每人的详情数组
{
"caregiver_name": "范素英",
"id_number": "320106...",
"institution": "梅苑颐养中心",
"area": "康养楼3区5层",
"bed_number": "康505-1床",
"check_in_date": "2020-03-15",
"care_level": "3",
"age": "85",
"completed_types": [], // 已完成的类型列表
"completed_count": 0,
"expected_count": 12,
"missing_types": [...], // 缺失的类型列表
"missing_count": 12,
"is_complete": false,
"is_discharged": false,
"discharge_date": "",
"status_summary": "漏评12项",
"type_details": {}, // 各类型详情(评分/评估师)
"assessors": []
},
...
]
}
}
7.2 数据库写入方式
使用 INSERT ... ON DUPLICATE KEY UPDATE,以 (analysis_year, id_number) 为唯一键。每次分析都会完全覆写该人当年的记录。
这意味着:如果有人在数据库中手动修改了
assessment_analysis 表的内容(比如把 missing_count 从12改成11),下次点击"重新分析"或"同步"后会被还原回程序计算的结果。该表只是缓存,不可当作手工编辑的数据源。
八真实数据示例
▼8.1 示例A:完全未评估(最常见)
在住老人 · 12项全缺
| 字段 | 值 |
|---|---|
| caregiver_name | 范素英 |
| 机构 | 梅苑颐养中心 |
| 区域/床位 | 康养楼3区5层 / 康505-1床 |
| 护理等级 | - |
| 年龄 | - |
| completed_types | [] |
| completed_count | 0 |
| missing_types | [全部12项] |
| missing_count | 12 |
| is_discharged | false(在住) |
| status_summary | 漏评12项 |
原因推测:该老人最新评估日期可能为空或不在2026年,导致 completed 被清空。
8.2 示例B:部分完成(完成1项)
在住老人 · 完成1项
| 字段 | 值 |
|---|---|
| caregiver_name | 周震华 |
| 机构 | 富贵山颐养中心 |
| 区域/床位 | 住宅楼1层 / 101-3床 |
| completed_types | ["能力评估"] |
| completed_count | 1 |
| missing_types | [其余11项] |
| missing_count | 11 |
| status_summary | 漏评11项 |
8.3 示例C:离院老人
离院老人 · 不参与考核
| 字段 | 值 |
|---|---|
| caregiver_name | 姚世瑞 |
| 机构 | 富贵山颐养中心 |
| 区域/床位 | 主楼1层 / 101-1床 |
| status (来源) | 离院 |
| discharge_date | 2025-11-30 |
| completed_types | [] (强制清空) |
| completed_count | 0 |
| missing_count | 12 |
| status_summary | 离院 |
8.4 示例D:评估记录类型分布(全局统计)
以下为 assessment_records 表中各类型的记录数量(含非必查类型):
| 评估类型 | 记录数 | 是否必查? |
|---|---|---|
| 能力评估 | 4095 | ✓ 必查 |
| 坠床风险评估 | 3993 | ✓ 必查 |
| 跌倒风险评估 | 3966 | ✓ 必查 |
| 营养 | 3961 | ✓ 必查 |
| 误吸 | 3959 | ✓ 必查 |
| 食品药品误食风险评估 | 3956 | ✓ 必查 |
| 噎食风险评估 | 3948 | ✓ 必查 |
| 压疮风险评估 | 3943 | ✓ 必查 |
| 文娱活动风险评估 | 3940 | ✓ 必查 |
| 走失风险评估 | 3940 | ✓ 必查 |
| 他伤自伤风险评估 | 3940 | ✓ 必查 |
| 烫伤风险评估 | 3939 | ✓ 必查 |
| 管路滑脱 | 648 | — 非必查 |
| 约束 | 555 | — 非必查 |
| 精神 | 427 | — 非必查 |
| 疼痛 | 87 | — 非必查 |
| 抑郁 | 58 | — 非必查 |
| 血栓 | 17 | — 非必查 |
| 睡眠 | 4 | — 非必查 |
九已知边界与注意事项
▼9.1 手动修改 DB 会被覆盖
assessment_analysis 是计算结果缓存表,每次"同步"或"重新分析"都会用 INSERT ON DUPLICATE KEY UPDATE 完全覆盖。手动修改此表的 completed_types / missing_count 等字段会在下次分析后被还原。
9.2 非必查类型的存在
assessment_records 中存在约 1690 条非必查类型的记录(管路滑脱、约束、精神、疼痛、抑郁、血栓、睡眠),这些记录被分析脚本静默忽略——不影响12项必查统计,也不出现在漏评列表中。
9.3 身份证号为唯一匹配键
- 所有关联都通过
id_number(身份证号)进行 - 如果
resident_info和assessment_records中的身份证号格式不一致(如大小写、空格),会导致匹配失败,该人的评估记录被跳过
9.4 expected_count 固定为12
当前版本中 expected_count 硬编码为 12。未来如果某些护理等级的老人只需要做部分评估(如特级护理只需做6项),则需要在此处增加按护理等级的条件分支。
9.5 care_level 字段的来源
care_level 和 age 字段不存在于 assessment_analysis 表中。它们来自 resident_info 表的实时 JOIN 查询,在 API 返回时动态附加到每条人员记录上。
9.6 排序规则
# analyze_assessment.py 第227-231行
results.sort(key=lambda x: (
0 if x["is_discharged"] else 1, # 离院排前面
-x["missing_count"], # 缺最多的排前面
x.get("bed_number", "zzz") # 床位号升序
))