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_countstatus_summary
最新评估日期 = 2026-05-20
year_types 含 ["能力评估","跌倒"]
["能力评估","跌倒"] 10 漏评10项
最新评估日期 = 2025-12-01
即使有2026年的记录(不可能)
[] (空) 12 漏评12项
无任何评估记录 [] (空) 12 漏评12项

2.3 同一人同类型的多次评估

  • 同一人在同一年内对同一评估类型可能有多条记录
  • 使用 Set 集合 去重——只要该类型至少有一条当年记录,就计入已完成
  • 取最新一条记录的 assessorscoreassessment_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_date2025-11-30
completed_types[] (强制清空)
completed_count0
missing_count12
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_datelatest_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 文件持久化
stepmessage说明
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_count0
missing_types[全部12项]
missing_count12
is_dischargedfalse(在住)
status_summary漏评12项

原因推测:该老人最新评估日期可能为空或不在2026年,导致 completed 被清空。

8.2 示例B:部分完成(完成1项)

在住老人 · 完成1项
字段
caregiver_name周震华
机构富贵山颐养中心
区域/床位住宅楼1层 / 101-3床
completed_types["能力评估"]
completed_count1
missing_types[其余11项]
missing_count11
status_summary漏评11项

8.3 示例C:离院老人

离院老人 · 不参与考核
字段
caregiver_name姚世瑞
机构富贵山颐养中心
区域/床位主楼1层 / 101-1床
status (来源)离院
discharge_date2025-11-30
completed_types[] (强制清空)
completed_count0
missing_count12
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_infoassessment_records 中的身份证号格式不一致(如大小写、空格),会导致匹配失败,该人的评估记录被跳过

9.4 expected_count 固定为12

当前版本中 expected_count 硬编码为 12。未来如果某些护理等级的老人只需要做部分评估(如特级护理只需做6项),则需要在此处增加按护理等级的条件分支。

9.5 care_level 字段的来源

care_levelage 字段不存在于 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")              # 床位号升序
))