feat:数据质量筛选规则需求整理
This commit is contained in:
@@ -0,0 +1,809 @@
|
||||
# 异常数据分析
|
||||
|
||||
> **文档目的**:根据业务表结构,预先梳理各模块可能产生脏数据的数据库表及对应的脏数据类型,供后续脏数据检测开发使用。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
- [一、脏数据类型汇总](#一脏数据类型汇总)
|
||||
- [二、健康评估](#二健康评估)
|
||||
- [2.1 涉及数据库表](#21-涉及数据库表)
|
||||
- [2.2 系统脏数据检测规则](#22-系统脏数据检测规则)
|
||||
- [2.3 检测频率建议](#23-检测频率建议)
|
||||
- [三、健康咨询](#三健康咨询)
|
||||
- [3.1 涉及数据库表](#31-涉及数据库表)
|
||||
- [3.2 系统脏数据检测规则](#32-系统脏数据检测规则)
|
||||
- [3.3 现有后端实现评估](#33-现有后端实现评估)
|
||||
- [3.4 检测频率建议](#34-检测频率建议)
|
||||
- [四、应急就医](#四应急就医)
|
||||
- [4.1 涉及数据库表](#41-涉及数据库表)
|
||||
- [4.2 系统脏数据检测规则](#42-系统脏数据检测规则)
|
||||
- [4.3 检测频率建议](#43-检测频率建议)
|
||||
- [五、营养管理](#五营养管理)
|
||||
- [5.1 涉及数据库表](#51-涉及数据库表)
|
||||
- [5.2 系统脏数据检测规则](#52-系统脏数据检测规则)
|
||||
- [5.3 现有后端实现评估](#53-现有后端实现评估)
|
||||
- [5.4 检测频率建议](#54-检测频率建议)
|
||||
- [六、健康监测](#六健康监测)
|
||||
- [6.1 涉及数据库表](#61-涉及数据库表)
|
||||
- [6.2 系统脏数据检测规则](#62-系统脏数据检测规则)
|
||||
- [6.3 检测频率建议](#63-检测频率建议)
|
||||
|
||||
---
|
||||
|
||||
## 一、脏数据类型汇总
|
||||
|
||||
| 脏数据类型 | 健康评估 | 健康咨询 | 应急就医 | 营养管理 | 健康监测 |
|
||||
|------------|:--:|:--:|:--:|:--:|:--:|
|
||||
| 数据缺失 | ✅ | ✅ | — | ✅ | ✅ |
|
||||
| 格式错误 | ✅ | ✅ | — | ✅ | ✅ |
|
||||
| 逻辑矛盾 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| 重复数据 | ✅ | — | — | ✅ | ✅ |
|
||||
| 范围越界 | ✅ | ✅ | — | ✅ | ✅ |
|
||||
| 关联缺失 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| 状态异常 | ✅ | ✅ | ✅ | — | — |
|
||||
| 非法数据 | — | — | ✅ | — | — |
|
||||
| 异常坐标 | — | — | ✅ | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 二、健康评估
|
||||
|
||||
> **后端服务**:`platform-assessment`(端口 24803)| **原型参考**:评估模块原型使用摹刀独立设计
|
||||
>
|
||||
> **开发状态**:⚠️ 后端已有 `AssDataAbnormalController` 占位(返回硬编码 mock 数据)。
|
||||
|
||||
健康评估模块对员工进行多维度健康评估,包括风险评估、心理评估、规律起居评估、人群分类等。
|
||||
|
||||
### 2.1 涉及数据库表
|
||||
|
||||
评估模块共 21 张业务表,按子域分类如下。
|
||||
|
||||
#### 风险评估(7+2 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `ass_risk_evaluation` | 风险评估主表(问卷+自动双模式) | 高 — `eval_source`(评估来源:1=问卷/2=自动)、`status`(任务状态:1=成功/2=处理中/3=失败)、`is_exception`(是否异常:0=否/1=是)、`user_id`(用户ID) |
|
||||
| `ass_risk_result` | 风险评估结果(疾病等级、BMI、生活习惯标记) | 高 — `bmi`(BMI值)、`sbp`(收缩压)/`dbp`(舒张压)、`fasting_bg`(空腹血糖)、`diabetes_level`(糖尿病等级)、`bmi_mark`(BMI标记格式) |
|
||||
| `ass_risk_evaluation_statistics` | 风险评估统计(按用户/年份汇总) | 中 — `statics_num`(统计评估次数)、`exception_num`(异常评估次数) |
|
||||
| `ass_risk_factor` | 风险因素明细 | 中 — `current_value`(当前检测值)、`reference_range`(参考范围)、`is_abnormal`(是否异常) |
|
||||
| `ass_risk_questionnaire_info` | 问卷基础信息(病史、生活方式) | 高 — `height`(身高cm)/`weight`(体重kg)/`waist_line`(腰围cm)、`smoking_status`(吸烟状态:1-3) |
|
||||
| `ass_risk_diet_sports_prescription` | 饮食运动处方 | 中 — `f_elements`(食物元素格式)、`aerobic_*`(有氧运动)、`strength_*`(力量训练)、`flexibility_*`(柔韧训练) |
|
||||
| `ass_risk_hms_log` | 第三方HMS接口调用日志 | 低 — XML 格式完整性 |
|
||||
| `ass_risk_request_cache` | MD5请求去重缓存 | 低 — 缓存过期/碰撞 |
|
||||
| `ass_risk_food_element` | 食物营养元素字典 | 低 — 字典数据完整性 |
|
||||
|
||||
#### 心理评估(3 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `ass_psychology` | 心理评估主表(综合/压力/焦虑/抑郁) | 高 — `type`(评估类型:1=综合/2=压力/3=焦虑/4=抑郁)、`grade`(评估得分)、`phy_grade_level`(健康等级)、`is_exception`(是否异常)、`status`(任务状态) |
|
||||
| `ass_psychology_statistics` | 心理评估统计 | 中 — 统计值与实际记录数一致性 |
|
||||
| `ass_influence_factor` | 心理影响因素评估 | 中 — 因子数据完整性 |
|
||||
|
||||
#### 规律起居(2 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `ass_daily_routine_online` | 在线穿戴数据评估(睡眠/运动/心率/血氧/压力) | 高 — `sleep_hour`(睡眠时长分钟)、`sport_minute`(运动时长分钟)、`resting_heart_rate`(静息心率bpm)、`oxygen_saturation`(血氧饱和度%)、`week_start_date`(周开始日期)/`week_end_date`(周结束日期) |
|
||||
| `ass_daily_routine_paper` | 问卷规律起居(体力活动/睡眠/上网) | 中 — `sport_value`(运动值)、`sleep_value`(睡眠值)、`time_of_net_value`(上网时长)、`questions_id`(关联问卷ID) |
|
||||
|
||||
#### 人群分类(4 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `ass_group_user` | 人群分类主表(A/B/C/D/E五类) | 高 — `user_group`(人群分类枚举:A/B/C/D/E)、`audit_status`(审核状态:0-2)、`is_archived`(是否归档)、`latest_assessment_date`(最近评估日期) |
|
||||
| `ass_group_user_detail` | 人群分类明细(疾病/体检项) | 中 — `detail_type`(明细类型:A/B/C/D)、`item_code`(项目编码)、`risk_level_flag`(风险等级标记) |
|
||||
| `ass_group_user_change_his` | 分类变更历史 | 低 — 变更记录完整性 |
|
||||
| `ass_group_user_audit_his` | 分类审核历史 | 低 — 审核记录完整性 |
|
||||
|
||||
#### 共享/基础(3 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `ass_questions` | 问卷答案(JSON) | 中 — `questions_json`(问卷JSON)、`status`(状态:卡处理中) |
|
||||
| `ass_algorithm_model` | 算法模型文档 | 低 |
|
||||
| `ass_trigger_config` | 评估触发器配置 | 低 |
|
||||
|
||||
### 2.2 系统脏数据检测规则
|
||||
|
||||
> 参照营养模块 `nut_ano_dirty` 模式。mock 数据中定义了四种异常类型:缺失值、超范围值、重复数据、格式错误。
|
||||
|
||||
#### 风险评估
|
||||
|
||||
**评估主表(`ass_risk_evaluation`)**
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及字段 | 说明 |
|
||||
|----------|----------|----------|------|
|
||||
| 数据缺失 | `user_id` 为 NULL | `user_id`(用户ID) | 评估记录无归属人 |
|
||||
| 范围越界 | `eval_source` 不在 1-2 范围内 | `eval_source`(评估来源) | 评估来源异常(1=问卷/2=自动) |
|
||||
| 状态异常 | `status` = 2(处理中)或 3(失败)超过 24 小时 | `status`(任务状态) | 评估任务卡住未完成 |
|
||||
| 逻辑矛盾 | `is_exception` = 1 但 `ass_risk_result` 中所有疾病等级均为正常 | `is_exception`(是否异常) ↔ `ass_risk_result.*_level`(疾病等级) | 异常标记与结果数据不一致 |
|
||||
|
||||
**评估结果(`ass_risk_result`)**
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及字段 | 说明 |
|
||||
|----------|----------|----------|------|
|
||||
| 范围越界 | BMI 值 < 10 或 > 80 | `bmi`(BMI值) | 超出人体可能范围 |
|
||||
| 范围越界 | 收缩压 < 50 或 > 300 mmHg | `sbp`(收缩压) | 血压值异常 |
|
||||
| 范围越界 | 舒张压 < 30 或 > 200 mmHg | `dbp`(舒张压) | 血压值异常 |
|
||||
| 逻辑矛盾 | `sbp` < `dbp` | `sbp`(收缩压)、`dbp`(舒张压) | 收缩压低于舒张压 |
|
||||
| 范围越界 | `fasting_bg`(空腹血糖)< 0 或 > 50 mmol/L | `fasting_bg`(空腹血糖) | 血糖值异常 |
|
||||
| 范围越界 | `health_age` / `potential_health_age` 计算为负数或 > 150 | `health_age`(健康年龄)、`potential_health_age`(潜在健康年龄) | 健康年龄异常 |
|
||||
| 格式错误 | `bmi_mark` / `smoke_mark` / `sleep_mark` 等不符合 `state,score,fullmark` 格式 | `*_mark` 字段(生活习惯标记) | 生活习惯标记格式异常 |
|
||||
| 范围越界 | 疾病等级(`diabetes_level`、`hypertension_level` 等)不在预期枚举范围内 | `*_level` 字段(疾病等级) | 等级编码越界 |
|
||||
| 逻辑矛盾 | `cholesterol`、`triglycerin`、`hdlc`、`ldlc` 均为 0 或 NULL 但疾病等级非空 | 血脂四项 + `*_level`(疾病等级) | 血脂数据缺失但给出了疾病评级 |
|
||||
|
||||
**问卷信息(`ass_risk_questionnaire_info`)**
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及字段 | 说明 |
|
||||
|----------|----------|----------|------|
|
||||
| 范围越界 | 身高 < 50cm 或 > 250cm | `height`(身高cm) | 录入异常 |
|
||||
| 范围越界 | 体重 < 20kg 或 > 300kg | `weight`(体重kg) | 录入异常 |
|
||||
| 范围越界 | 腰围 < 30cm 或 > 200cm | `waist_line`(腰围cm) | 录入异常 |
|
||||
| 范围越界 | `smoking_status` 不在 1-3 | `smoking_status`(吸烟状态) | 吸烟状态枚举越界 |
|
||||
| 范围越界 | 个人病史字段(`personal_diabetes` 等)不为 0 或 1 | `personal_*` 字段(个人病史) | 病史枚举越界 |
|
||||
| 数据缺失 | `height`、`weight`、`waist_line` 均为 NULL | `height`(身高)、`weight`(体重)、`waist_line`(腰围) | 基础体测数据完全缺失 |
|
||||
| 格式错误 | 问卷 JSON 原始数据格式异常 | `questions_json`(问卷JSON,通过 `ass_questions`) | JSON 解析失败 |
|
||||
|
||||
**评估统计(`ass_risk_evaluation_statistics`)**
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及字段 | 说明 |
|
||||
|----------|----------|----------|------|
|
||||
| 逻辑矛盾 | `statics_num` 与 `ass_risk_evaluation` 中实际评估次数不一致 | `statics_num`(统计评估次数) | 统计数据过期 |
|
||||
| 逻辑矛盾 | `is_bmi_abnormal` 等疾病异常标记与 `last_evaluation_id` 对应结果数据不一致 | `is_*_abnormal` 字段(疾病异常标记) | 统计标记与源数据脱节 |
|
||||
| 逻辑矛盾 | `exception_num` 与实际 `is_exception=1` 的记录数不一致 | `exception_num`(异常计数) | 异常计数错误 |
|
||||
|
||||
#### 心理评估
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 范围越界 | `type` 不在 1-4(综合/压力/焦虑/抑郁) | `ass_psychology` | `type`(评估类型) |
|
||||
| 范围越界 | `grade` 超出该量表合理分值范围 | `ass_psychology` | `grade`(评估得分) |
|
||||
| 数据缺失 | `grade` 或 `phy_grade_level` 为 NULL | `ass_psychology` | `grade`(评估得分)、`phy_grade_level`(健康等级) |
|
||||
| 格式错误 | `phy_grade_level` 编码不在数据字典范围内 | `ass_psychology` | `phy_grade_level`(健康等级编码) |
|
||||
| 状态异常 | `status` = 2(分析中)超过 24 小时 | `ass_psychology` | `status`(任务状态) |
|
||||
| 逻辑矛盾 | `is_exception` = 1 但 `grade` 在正常范围内 | `ass_psychology` | `is_exception`(是否异常) ↔ `grade`(评估得分) |
|
||||
| 关联缺失 | `questions_id` 在 `ass_questions` 中不存在 | `ass_psychology` | `questions_id`(关联问卷ID) |
|
||||
| 逻辑矛盾 | `ass_psychology_statistics` 统计值与实际评估记录数不一致 | `ass_psychology_statistics` | — |
|
||||
|
||||
#### 规律起居
|
||||
|
||||
**在线穿戴评估(`ass_daily_routine_online`)**
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及字段 | 说明 |
|
||||
|----------|----------|----------|------|
|
||||
| 范围越界 | `sleep_hour` < 0 或 > 1440 分钟 | `sleep_hour`(睡眠时长分钟) | 睡眠时长不合理 |
|
||||
| 范围越界 | `sport_minute` < 0 或 > 1440 分钟 | `sport_minute`(运动时长分钟) | 运动时长不合理 |
|
||||
| 范围越界 | `resting_heart_rate` < 30 或 > 220 bpm | `resting_heart_rate`(静息心率bpm) | 静息心率异常 |
|
||||
| 范围越界 | `oxygen_saturation` < 60% 或 > 100% | `oxygen_saturation`(血氧饱和度%) | 血氧值异常 |
|
||||
| 范围越界 | `pressure_value` 超出传感器量程 | `pressure_value`(压力值) | 压力值异常 |
|
||||
| 逻辑矛盾 | `week_end_date` < `week_start_date` | `week_end_date`(周结束日期)、`week_start_date`(周开始日期) | 周起止日期倒置 |
|
||||
| 逻辑矛盾 | `sleep_hour` + `sport_minute` > 1440 | `sleep_hour`(睡眠时长)、`sport_minute`(运动时长) | 睡眠+运动超过24小时 |
|
||||
| 状态异常 | `status` = 2(分析中)超过 24 小时 | `status`(任务状态) | 任务卡住 |
|
||||
| 数据缺失 | `is_exception` 为 NULL | `is_exception`(是否异常) | 异常标记缺失 |
|
||||
|
||||
**问卷评估(`ass_daily_routine_paper`)**
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及字段 | 说明 |
|
||||
|----------|----------|----------|------|
|
||||
| 范围越界 | `sport_value` / `sleep_value` / `time_of_net_value` 为负值 | `sport_value`(运动值)、`sleep_value`(睡眠值)、`time_of_net_value`(上网时长) | 负数无意义 |
|
||||
| 范围越界 | `time_of_net_value` > 24 小时 | `time_of_net_value`(上网时长) | 上网时长不合理 |
|
||||
| 范围越界 | `sport_level` / `sleep_type` / `time_of_net_level` 不在枚举范围 | `sport_level`(运动等级)、`sleep_type`(睡眠类型)、`time_of_net_level`(上网等级) | 等级编码越界 |
|
||||
| 关联缺失 | `questions_id` 在 `ass_questions` 中不存在 | `questions_id`(关联问卷ID) | 孤立问卷关联 |
|
||||
| 数据缺失 | `is_exception` 为 NULL | `is_exception`(是否异常) | 异常标记缺失 |
|
||||
|
||||
#### 人群分类
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 范围越界 | `user_group` 不在 A/B/C/D/E 范围内 | `ass_group_user` | `user_group`(人群分类) |
|
||||
| 范围越界 | `group_change_type` 不在 1-3 | `ass_group_user` | `group_change_type`(变更类型) |
|
||||
| 范围越界 | `audit_status` 不在 0-2 | `ass_group_user` | `audit_status`(审核状态) |
|
||||
| 逻辑矛盾 | `is_archived` = 1 且 `archived_time` 为 NULL | `ass_group_user` | `is_archived`(是否归档)、`archived_time`(归档时间) |
|
||||
| 范围越界 | `date_year` 为未来年份或早于 2020 | `ass_group_user` | `date_year`(归属年份) |
|
||||
| 范围越界 | `latest_assessment_date` 为未来日期 | `ass_group_user` | `latest_assessment_date`(最近评估日期) |
|
||||
| 关联缺失 | `group_user_id` 在 `ass_group_user` 中不存在 | `ass_group_user_detail` | `group_user_id`(人群分类ID) |
|
||||
| 范围越界 | `detail_type` 不在 A/B/C/D | `ass_group_user_detail` | `detail_type`(明细类型) |
|
||||
| 范围越界 | `data_type` 不在 1-2 | `ass_group_user_detail` | `data_type`(数据类型) |
|
||||
| 重复数据 | 同一用户同一年度存在多条活跃分类记录 | `ass_group_user` | `user_id`(用户ID) + `date_year`(归属年份) |
|
||||
|
||||
#### 问卷与处方
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 格式错误 | `questions_json` 格式非法(JSON 解析失败) | `ass_questions` | `questions_json`(问卷JSON) |
|
||||
| 状态异常 | `status` = 2(分析中)超过 24 小时 | `ass_questions` | `status`(任务状态) |
|
||||
| 格式错误 | `f_elements` 不符合 `meal_foodCode_amount;...` 格式 | `ass_risk_diet_sports_prescription` | `f_elements`(食物元素格式) |
|
||||
| 范围越界 | `energy_level` 为负值或 > 10000 kcal | `ass_risk_diet_sports_prescription` | `energy_level`(能量等级) |
|
||||
| 数据缺失 | 评估正常但处方中所有运动字段为 NULL | `ass_risk_diet_sports_prescription` | `aerobic_*`(有氧运动)、`strength_*`(力量训练)、`flexibility_*`(柔韧训练) |
|
||||
|
||||
### 2.3 检测频率建议
|
||||
|
||||
| 检测类型 | 建议频率 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 评估任务卡住检测 | 每小时 | `status=2` 超过 24 小时的记录 |
|
||||
| 数值范围越界检测 | 每日凌晨(评估任务完成后) | 全量扫描 BMI/血压/心率等 |
|
||||
| 统计一致性校验 | 每日凌晨 | `statics_num` vs 实际记录数 |
|
||||
| 格式校验(JSON/mark) | 数据入库时实时 | 问卷JSON、`f_elements`、`*_mark` |
|
||||
|
||||
---
|
||||
|
||||
## 三、健康咨询
|
||||
|
||||
> **后端服务**:`platform-consult`(端口 24806)| **原型参考**:无独立原型页面
|
||||
>
|
||||
> **开发状态**:✅ 已实现 `con_exception_dirty` 表 + 3 种异常类型定时检测,管理端分页查询/忽略/导出功能完整。
|
||||
|
||||
健康咨询模块管理员工在线图文/视频咨询全流程,涵盖咨询会话、专家管理、病历档案、IM 消息、评价结算等。
|
||||
|
||||
### 3.1 涉及数据库表
|
||||
|
||||
#### 咨询核心(4 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `con_consult` | 咨询会话主表(图文/视频统一) | 高 — `consult_no`(咨询单号)、`content_status`(预约/咨询状态:1-8)、`session_status`(会话状态:1=进行中/2=已结束)、`start_time`(开始时间)/`end_time`(结束时间)、`duration_minutes`(咨询时长秒)、`score`(用户评分1-5)、`cost`(咨询费用) |
|
||||
| `con_evaluate` | 咨询评价表 | 高 — `score`(评分1-5)、`consult_id`(关联咨询ID)、`expert_id`(被评价专家ID) |
|
||||
| `con_medical_record` | 病历档案表 | 中 — `medical_describe`(病情描述)、`duration_type`(持续时间:1-4)、`images`(检查资料图片URL) |
|
||||
| `con_family_member` | 家庭成员/咨询人表 | 中 — `member_name`(成员姓名)、`birthday`(出生日期)、`height`(身高cm)、`weight`(体重kg)、`relation`(家庭关系) |
|
||||
|
||||
#### 专家与排班(2 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `con_expert` | 专家信息表 | 高 — `expert_no`(专家编号)、`expert_type`(专家类型:1=收费/2=免费/3=其他)、`overall_merit`(综合评分)、`response_rate`(24h回复率)、`hospital_id`(所属医院ID)、`dept_id`(所属科室ID)、`reg_date`(入职日期)/`off_date`(离职日期) |
|
||||
| `con_expert_schedule_rule` | 专家排班规则表(按周设置) | 中 — `week_day`(周几:1-7)、`period`(时段:1-4)、`start_time`(出诊开始时间)/`end_time`(出诊结束时间)、`capacity`(接诊人数上限) |
|
||||
|
||||
#### IM 消息(2 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `con_im_message` | IM消息记录表 | 中 — `msg_key`(腾讯IM消息唯一标识)、`msg_type`(消息类型:1=单聊/2=群聊/3=应急群聊/4=音视频)、`msg_content`(消息内容)、`send_time`(发送时间)、`consult_id`(关联咨询ID) |
|
||||
| `con_im_chat` | IM聊天会话表(通讯录单聊) | 中 — `session_id`(会话ID)、`pair_id`(会话对唯一标识)、`from_user_id`(发起者)、`to_user_id`(接受者) |
|
||||
|
||||
#### 结算(4 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `con_settle_main` | 结算主表 | 中 — `settle_status`(结算状态:0=待结算/1=结算中/2=已结算/3=异常)、`com_fee_per_month`(每月通讯费)、`error_msg`(异常信息) |
|
||||
| `con_settle_result` | 结算结果 | 中 — 金额一致性 |
|
||||
| `con_settle_result_item` | 结算结果明细 | 中 — 明细与汇总一致性 |
|
||||
| `con_settle_cost_config` | 费用配置 | 低 — 配置值合理性 |
|
||||
|
||||
#### 基础数据(4 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `con_hospital` | 医院关联配置 | 中 — `ref_id`(关联外部医院ID) |
|
||||
| `con_hospital_dept` | 医院-科室关联表 | 低 — `hospital_id`(医院ID)、`dept_id`(科室ID) |
|
||||
| `con_department` | 科室表 | 中 — `dept_name`(科室名称)、`parent_id`(上级科室ID) |
|
||||
| `con_disease` | 疾病信息表 | 低 — `disease_name`(疾病名称)、`dept_id`(所属科室ID) |
|
||||
|
||||
#### 其他(4 张表)
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `con_notice` | 咨询须知表 | 低 |
|
||||
| `con_phrase` | 常用语表 | 低 |
|
||||
| `con_settle_period_config` | 结算周期配置 | 低 |
|
||||
|
||||
### 3.2 系统脏数据检测规则
|
||||
|
||||
> 后端已实现 `con_exception_dirty` 表,目前定义了 3 种异常类型:咨询时长异常(`exception_type=1`)、长时间未回复(`exception_type=2`)、评价分数极低(`exception_type=3`)。
|
||||
>
|
||||
> ⚠️ **已知问题**:`ConConsultTimeoutJob` 每小时自动关闭超时 7 天的会话,因此"咨询时长异常"检测的阈值必须设置在 7 天以内,否则异常记录永远无法生成。
|
||||
>
|
||||
> ⚠️ **已知缺陷**:`ConExceptionDirtyMapper.xml` 第 29 行 `work_no` 被硬编码为 `NULL`,前端展示员工工号列为空。
|
||||
>
|
||||
> ⚠️ **已知缺陷**:`ConExceptionDirtyMapper.xml` 中 `h."name" AS hospital_name` 引用了 `con_hospital` 表中可能不存在的 `name` 列(`con_hospital` 实体仅有 `ref_id` 无 `name`),需确认运行时是否会报错或从外部服务取数。
|
||||
|
||||
#### 咨询会话(已有)
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 状态异常 | 咨询时长异常:会话进行中但 `duration_minutes` 超过合理阈值(如 > 60 分钟) | `con_consult` | `duration_minutes`(咨询时长)、`content_status`(预约/咨询状态) | `exception_type=1`,需在超时 Job(7天)前触发 |
|
||||
| 状态异常 | 长时间未回复:专家超过 N 小时未回复用户消息 | `con_consult` | `last_reply_time`(最后回复时间)、`content_status`(预约/咨询状态) | `exception_type=2` |
|
||||
| 范围越界 | 评价分数极低:`score` < 2 分 | `con_evaluate` / `con_consult` | `score`(评分) | `exception_type=3` |
|
||||
|
||||
#### 咨询会话(建议新增)
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 逻辑矛盾 | `start_time` > `end_time` | `con_consult` | `start_time`(开始时间)、`end_time`(结束时间) | 咨询结束时间早于开始时间 |
|
||||
| 逻辑矛盾 | `session_status` = 进行中(1) 但 `end_time` 不为空 | `con_consult` | `session_status`(会话状态)、`end_time`(结束时间) | 状态与时间矛盾 |
|
||||
| 逻辑矛盾 | `content_status` = 已完成(3) 但 `end_time` 为空 | `con_consult` | `content_status`(预约/咨询状态)、`end_time`(结束时间) | 已完成但无结束时间 |
|
||||
| 逻辑矛盾 | `content_status` = 已拒绝(8) 但 `reject_reason` 为空 | `con_consult` | `content_status`(预约/咨询状态)、`reject_reason`(拒绝原因) | 拒绝但无理由 |
|
||||
| 范围越界 | `duration_minutes` < 0 | `con_consult` | `duration_minutes`(咨询时长) | 咨询时长为负数 |
|
||||
| 范围越界 | `consult_type` 不在 1-2 | `con_consult` | `consult_type`(咨询类型:1=图文/2=视频) | 咨询类型枚举越界 |
|
||||
| 范围越界 | `content_status` 不在 1-8 | `con_consult` | `content_status`(预约/咨询状态) | 内容状态枚举越界 |
|
||||
| 范围越界 | `cost` < 0 | `con_consult` | `cost`(咨询费用) | 咨询费用为负数 |
|
||||
| 关联缺失 | `expert_id` 在 `con_expert` 中不存在 | `con_consult` | `expert_id`(专家ID) | 关联专家已删除 |
|
||||
| 关联缺失 | `member_id` 不为空但在 `con_family_member` 中不存在 | `con_consult` | `member_id`(咨询人ID) | 关联咨询人已删除 |
|
||||
| 数据缺失 | `consult_no` 为空 | `con_consult` | `consult_no`(咨询单号) | 咨询单号缺失 |
|
||||
|
||||
#### 专家信息
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 范围越界 | `overall_merit` < 0 或 > 5 | `con_expert` | `overall_merit`(综合评分) | 综合评分越界 |
|
||||
| 范围越界 | `response_rate` < 0 或 > 100 | `con_expert` | `response_rate`(24h回复率%) | 回复率越界 |
|
||||
| 范围越界 | `expert_type` 不在 1-3 | `con_expert` | `expert_type`(专家类型) | 专家类型枚举越界 |
|
||||
| 数据缺失 | `expert_no` 为空 | `con_expert` | `expert_no`(专家编号) | 专家编号缺失 |
|
||||
| 逻辑矛盾 | `off_date` < `reg_date`(均已填写时) | `con_expert` | `off_date`(离职日期)、`reg_date`(入职日期) | 离职日期早于入职日期 |
|
||||
| 关联缺失 | `hospital_id` 在 `con_hospital` 中不存在 | `con_expert` | `hospital_id`(所属医院ID) | 关联医院不存在 |
|
||||
| 关联缺失 | `dept_id` 在 `con_department` 中不存在 | `con_expert` | `dept_id`(所属科室ID) | 关联科室不存在 |
|
||||
|
||||
#### 咨询评价
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 范围越界 | `score` < 0 或 > 5 | `con_evaluate` | `score`(评分) | 评分越界 |
|
||||
| 关联缺失 | `consult_id` 在 `con_consult` 中不存在 | `con_evaluate` | `consult_id`(关联咨询ID) | 评价关联的咨询不存在 |
|
||||
| 关联缺失 | `expert_id` 在 `con_expert` 中不存在 | `con_evaluate` | `expert_id`(被评价专家ID) | 评价关联的专家不存在 |
|
||||
|
||||
#### 家庭成员
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 范围越界 | `height` < 50 或 > 250 (cm) | `con_family_member` | `height`(身高cm) | 身高越界 |
|
||||
| 范围越界 | `weight` < 20 或 > 300 (kg) | `con_family_member` | `weight`(体重kg) | 体重越界 |
|
||||
| 范围越界 | `sex` 不在 1-2 | `con_family_member` | `sex`(性别:1=男/2=女) | 性别枚举越界 |
|
||||
| 范围越界 | `birthday` 为未来日期 | `con_family_member` | `birthday`(出生日期) | 生日为未来日期 |
|
||||
|
||||
#### 病历档案
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 数据缺失 | `medical_describe` 为空 | `con_medical_record` | `medical_describe`(病情描述) | 病情描述缺失 |
|
||||
| 范围越界 | `duration_type` 不在 1-4 | `con_medical_record` | `duration_type`(持续时间:1=几天内/2=1-2周/3=1-3月/4=3月以上) | 持续时间枚举越界 |
|
||||
|
||||
#### IM 消息
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 数据缺失 | `msg_content` 为空且非撤回消息 | `con_im_message` | `msg_content`(消息内容) | 消息内容缺失 |
|
||||
| 范围越界 | `msg_type` 不在 1-4 | `con_im_message` | `msg_type`(消息类型) | 消息类型枚举越界 |
|
||||
| 关联缺失 | `consult_id` 不为空但在 `con_consult` 中不存在 | `con_im_message` | `consult_id`(关联咨询ID) | 消息关联的咨询不存在 |
|
||||
|
||||
#### 排班规则
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 范围越界 | `week_day` 不在 1-7 | `con_expert_schedule_rule` | `week_day`(星期:1=周一~7=周日) | 星期枚举越界 |
|
||||
| 范围越界 | `period` 不在 1-4 | `con_expert_schedule_rule` | `period`(时段:1-4) | 时段枚举越界 |
|
||||
| 范围越界 | `capacity` < 0 | `con_expert_schedule_rule` | `capacity`(接诊人数上限) | 接诊人数为负 |
|
||||
| 逻辑矛盾 | `end_time` < `start_time` | `con_expert_schedule_rule` | `start_time`(出诊开始时间)、`end_time`(出诊结束时间) | 排班结束时间早于开始时间 |
|
||||
|
||||
### 3.3 现有后端实现评估
|
||||
|
||||
#### 已实现
|
||||
|
||||
| 组件 | 状态 | 说明 |
|
||||
|------|:--:|------|
|
||||
| `con_exception_dirty` 表 | ✅ 已上线 | 5个字段:consult_id、consult_no、exception_type、exception_value、alarm_time |
|
||||
| `ConExceptionDirtyController` | ✅ 已上线 | `/page` 分页查询 + `/ignore` 批量忽略 + `/export` 导出 |
|
||||
| `ConExceptionDirtyService` | ✅ 已上线 | 分页 JOIN 咨询/专家/医院 + Feign 批量查用户名 |
|
||||
| `ExceptionTypeEnum` | ✅ 已上线 | 3 种异常类型:时长异常/长时间未回复/低分评价 |
|
||||
| `ConConsultTimeoutJob` | ✅ 已上线 | 每小时扫描,7 天超时自动关闭会话 |
|
||||
|
||||
#### 待完善
|
||||
|
||||
| 项目 | 优先级 | 说明 |
|
||||
|------|:--:|------|
|
||||
| 异常数据自动检测定时任务 | 高 | 需实现定时扫描生成 `con_exception_dirty` 记录 |
|
||||
| `work_no` 字段补充 | 高 | 当前 Mapper XML 硬编码为 NULL,需 JOIN `con_user_snapshot` 获取 |
|
||||
| 咨询时长异常阈值与超时 Job 的协调 | 高 | 时长异常应在超时 Job 触发前检测(如 > 60 分钟即告警,而非等 7 天) |
|
||||
| 专家/家庭成员/病历/排班等数据校验 | 中 | 当前仅覆盖咨询会话维度的 3 种异常 |
|
||||
| IM 消息数据完整性校验 | 低 | 消息内容、关联关系 |
|
||||
|
||||
### 3.4 检测频率建议
|
||||
|
||||
| 检测类型 | 建议频率 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 咨询时长异常检测 | 每 30 分钟 | 需在超时 Job(7天)前触发,建议 > 60 分钟即告警 |
|
||||
| 长时间未回复检测 | 每小时 | 检查 `last_reply_time` 超过阈值 |
|
||||
| 低分评价检测 | 评价生成时实时 | 评价提交后即时判断 |
|
||||
| 枚举/范围/逻辑矛盾校验 | 每日凌晨 | 全量扫描各表枚举字段和数值范围 |
|
||||
|
||||
---
|
||||
|
||||
## 四、应急就医
|
||||
|
||||
> **后端服务**:`platform-emergency`(端口 24808)| **原型参考**:`web-admin/emergency-dispatch/admin/exception-dirty.html`
|
||||
>
|
||||
> **开发状态**:⚠️ 后端已有 `EmDirtyDataController` 占位(返回空数据),`EmExceptionDictConstant` 定义常量;尚未实现具体检测和存储。
|
||||
|
||||
应急就医管理员工应急工单、云坐席通话、AED 设备部署与管理、救护车调度等。脏数据类型与其他模块差异较大,主要关注 **AED 设备**数据质量和**通话记录**完整性。
|
||||
|
||||
### 4.1 涉及数据库表
|
||||
|
||||
#### 核心应急表
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `em_emergency_center` | 应急中心 | 中 — `longitude`(经度)/`latitude`(纬度)、`center_phone`(中心电话)、`status`(状态) |
|
||||
| `em_user_profile` | 应急人员档案 | 中 — `cert_number`(证书编号)、`license_number`(执照编号)、`station_status`(驻场状态) |
|
||||
| `em_call_record` | 通话记录(七陌云客服) | 高 — `incoming_phone`(来电号码)、`match_status`(匹配状态:1=唯一匹配/2=多重匹配)、`employee_id`(匹配员工ID)、`duration`(通话时长) |
|
||||
| `em_emergency_order` | 应急工单 | 高 — `order_no`(工单编号)、`status`(工单状态)、`location_desc`(位置描述)、`location_lat`(纬度)/`location_lng`(经度)、`closed_at`(关闭时间) |
|
||||
| `em_work_order_dispatch` | 工单调度日志 | 中 — 调度链路完整性 |
|
||||
|
||||
#### AED 设备管理
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `em_aed_device` | AED 设备主表 | 高 — `battery_level`(电池电量百分比)、`battery_status`(电池状态枚举) |
|
||||
| `em_aed_deploy_point` | AED 部署点位 | 高 — `longitude`(经度)、`latitude`(纬度) |
|
||||
| `em_aed_maintenance` | AED 维护记录 | 中 — 维护日期、到期提醒 |
|
||||
| `em_aed_latest` | AED 最新状态 | 高 — `battery_power`(厂商原始电池数据String)、实时状态聚合 |
|
||||
| `em_aed_warn_info` | AED 告警信息 | 中 — 告警记录 |
|
||||
| `em_aed_usage` | AED 使用记录 | 中 — 使用时间、使用人 |
|
||||
|
||||
#### 其他应急表
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `em_ambulance` | 救护车 | 中 — `plate_no`(车牌号)、`driver`(驾驶员)、`status`(状态) |
|
||||
| `em_schedule_record` | 值班排班记录 | 中 — 排班时间冲突 |
|
||||
| `em_emergency_contact` | 紧急联系人 | 中 — 联系方式有效性 |
|
||||
| `em_emergency_center_call_record` | 应急中心通话记录 | 中 — `call_id`(通话ID)、`employee_id`(员工ID)、`begin_time`(开始时间)、`end_time`(结束时间)、`record_file`(录音文件) |
|
||||
| `em_emergency_center_call_join` | 应急中心通话参与人 | 中 — 参与人关联完整性、`employee_id`(员工ID) |
|
||||
| `em_hospital` | 应急合作医院 | 低 |
|
||||
| `em_first_aid_kit` | 急救箱 | 中 — 过期检查 |
|
||||
| `em_drill_record` | 演练记录 | 低 |
|
||||
|
||||
### 4.2 系统脏数据检测规则
|
||||
|
||||
> 应急模块使用独特的异常类型分类:非法数据 / 异常坐标 / 状态异常。
|
||||
>
|
||||
> **注意**:后端 `EmExceptionDictConstant` 当前定义了 `MISSING_FIELD` / `INVALID_FORMAT` / `ORPHAN_RECORD`,与原型中的 `非法数据` / `异常坐标` / `状态异常` 分类不一致,需后续对齐。
|
||||
|
||||
#### 通话记录
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 非法数据 | 电话号码格式不合法(非国内手机号/非座机号) | `em_call_record` | `incoming_phone`(来电号码) | 云客服传入的号码非法 |
|
||||
| 状态异常 | `match_status` 为"多重匹配"(=2),存在多个员工对应同一号码 | `em_call_record` | `match_status`(匹配状态)、`employee_id`(匹配员工ID) | 一个号码匹配到多名员工,需人工确认 |
|
||||
| 关联缺失 | 通话记录关联的 `order_id` 在 `em_emergency_order` 中不存在 | `em_call_record` | `order_id`(关联工单ID) | 孤立的工单关联 |
|
||||
| 逻辑矛盾 | 通话结束时间早于开始时间 | `em_call_record` | `begin_time`(开始时间)、`end_time`(结束时间) | 时间戳异常 |
|
||||
| 逻辑矛盾 | 通话状态为"已接听"但时长为 0 | `em_call_record` | `answer_status`(接听状态) + `duration`(通话时长) | 状态与数据矛盾 |
|
||||
|
||||
#### AED 设备管理
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 | 说明 |
|
||||
|----------|----------|--------|----------|------|
|
||||
| 非法数据 | 电池电量百分比超出 0-100% 范围(如 = 260%) | `em_aed_device` | `battery_level`(电池电量百分比) | 硬件上传了不可能的电量值 |
|
||||
| 非法数据 | 设备上报的原始电池电压/电量(String 类型,厂商原始值) | `em_aed_latest` | `battery_power`(厂商原始电池数据) | 厂商原始电池数据,非 0-100% 百分比 |
|
||||
| 非法数据 | 电池状态值不在预定义枚举范围内 | `em_aed_device` | `battery_status`(电池状态) | 状态码异常,如"未知" |
|
||||
| 异常坐标 | GPS 坐标不在国内范围(经度 73-135°E,纬度 18-54°N) | `em_aed_deploy_point` | `longitude`(经度)、`latitude`(纬度) | 如坐标指向海外(悉尼) |
|
||||
| 异常坐标 | GPS 坐标为 (0,0) 或 NULL(未获取到定位) | `em_aed_deploy_point` | `longitude`(经度)、`latitude`(纬度) | AED 部署点位无有效坐标 |
|
||||
| 关联缺失 | AED 部署点位关联的应急中心不存在 | `em_aed_deploy_point` ↔ `em_emergency_center` | 中心关联字段 | |
|
||||
| 逻辑矛盾 | AED 最近一次维护日期晚于当前日期 | `em_aed_maintenance` | 维护日期 | 未来日期,数据录入错误 |
|
||||
| 数据缺失 | AED 设备缺少维护记录 | `em_aed_device` ↔ `em_aed_maintenance` | | 设备部署后从未维护 |
|
||||
|
||||
> **注意**:AED 设备离线检测(基于心跳时间差)当前暂不可用,因为 `em_aed_latest` 表缺少 `update_time` 字段。需后续新增该字段。
|
||||
|
||||
### 4.3 检测频率建议
|
||||
|
||||
| 检测类型 | 建议频率 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 系统脏数据 — AED 电池/坐标 | 每日凌晨 | AED 设备数据量小 |
|
||||
| 系统脏数据 — 通话记录非法数据 | 每日凌晨 | 通话记录增量扫描 |
|
||||
| AED 设备离线检测 | 每小时 | `em_aed_latest` 心跳超时判断 |
|
||||
|
||||
---
|
||||
|
||||
## 五、营养管理
|
||||
|
||||
> **后端服务**:`platform-nutrition`(端口 24810)| **原型参考**:`web-admin/nutrition/ano-dirty.html`
|
||||
>
|
||||
> **开发状态**:✅ 已实现脏数据存储表 `nut_ano_dirty`,服务已上线。
|
||||
|
||||
营养管理是系统最大的模块(约 130 张表),涵盖菜品/食谱管理、订餐/取餐、农场种植养殖、原材料采购库存、中央厨房生产、营养算法与 AI 推荐等全链路。
|
||||
|
||||
### 5.1 涉及数据库表
|
||||
|
||||
#### 用户与档案
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `nut_user` | 营养用户(用餐者) | 高 — `phone`(手机号)、`bmi`(BMI值)、`health_tags`(健康标签) |
|
||||
| `nut_user_profile` | 用户健康档案 | 高 — `height`(身高)、`weight`(体重)、`target_weight`(目标体重)、`allergies`(过敏原)、`dietary_restrictions`(饮食限制) |
|
||||
| `nut_user_account` | 用户账户/充值 | 中 — 账户余额字段 |
|
||||
| `nut_user_face` | 面部识别数据 | 中 — 面部嵌入向量有效性 |
|
||||
| `nut_member` | 会员记录 | 中 — 会员有效期 |
|
||||
|
||||
#### 食品与食谱
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `nut_food` | 菜品主表 | 高 — `price`(价格)、`nutrition_info`(营养信息)、`status`(状态) |
|
||||
| `nut_food_class` | 菜品分类 | 中 — `parent_id`(上级分类ID) 自引用完整性 |
|
||||
| `nut_food_composition` | 食物成分 | 高 — `value_per_100g`(每100g营养值) |
|
||||
| `nut_food_nutri` | 食物营养数据 | 高 — 详细营养分解 |
|
||||
| `nut_food_spec` | 食物规格/份量 | 中 — `weight`(份量重量) |
|
||||
| `nut_food_check` | 食品检测记录 | 中 — `result`(检测结果)、`passed`(是否通过) |
|
||||
| `nut_recipe` | 食谱 | 中 — `total_calories`(总热量)、`nutrition_summary`(营养汇总JSON) |
|
||||
| `nut_recipe_food` | 食谱-菜品关联 | 中 — `portion`(份数) |
|
||||
| `nut_cookbook` | 菜谱 | 低 — `steps`(步骤) |
|
||||
|
||||
#### 膳食与订餐
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `nut_order` | 订单主表 | 高 — `total_amount`(订单总金额)、`status`(订单状态)、`order_type`(订单类型) |
|
||||
| `nut_order_item` | 订单明细 | 高 — `quantity`(数量)、`price`(单价)、`subtotal`(小计) |
|
||||
| `nut_canteen` | 餐厅/食堂 | 中 — `capacity`(容量)、`status`(状态) |
|
||||
| `nut_canteen_pickup_record` | 取餐记录 | 中 — `portion`(份量)、`calories`(热量) |
|
||||
| `nut_pickup_order` | 取餐订单 | 中 — `nutrition_info`(营养汇总) |
|
||||
| `nut_consume_record` | 消费记录 | 中 — 金额一致性 |
|
||||
| `nut_pay_error` | 支付错误日志 | 低 — 支付异常记录 |
|
||||
|
||||
#### 原材料与供应
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `nut_mater_base` | 原材料主表 | 高 — `price`(价格)、`unit`(单位) |
|
||||
| `nut_raw_inbound` | 原材料入库 | 高 — `quantity`(数量)、`weight`(重量) |
|
||||
| `nut_sup_inventory` | 供应库存 | 高 — `quantity`(库存数量) |
|
||||
| `nut_sup_inventory_flow` | 库存流水 | 中 — `qty`(操作量)、`current_qty_after`(操作后在库量) |
|
||||
| `nut_sup_hygiene_test` | 卫生检测 | 中 — 检测结果 |
|
||||
| `nut_sup_warehouse` | 仓库 | 低 — `location`(位置)、`manager`(管理员) |
|
||||
|
||||
> **注**:`nut_sup_inventory_flow` 的 SQL DDL 文件缺失(`db/nutrition/` 目录下未找到对应建表脚本),需补充。
|
||||
|
||||
#### 生产与中央厨房
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `nut_prod_combo_task` | 组合生产任务 | 中 — `plan_date`(计划日期)、`status`(任务状态) |
|
||||
| `nut_prod_qc_sample` | 质检样品 | 高 — `status`(状态:0=留样中/1=已处置/2=已检验) |
|
||||
| `nut_prod_qc_violation` | 质检违规 | 中 — 违规记录完整性 |
|
||||
| `nut_prod_serve_record` | 供餐记录 | 中 — 实际供餐与实际订单一致性 |
|
||||
| `nut_prod_stat_cost` | 生产成本统计 | 中 — 金额合理性 |
|
||||
|
||||
#### 农场
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `nut_farm_plot` | 地块 | 中 — `area`(面积)、`soil_type`(土壤类型) |
|
||||
| `nut_farm_crop_batch` | 作物批次 | 中 — `plant_date`(种植日期)、`expected_harvest`(预计采收日期) |
|
||||
| `nut_farm_harvest` | 采收记录 | 中 — `quantity`(采收数量) |
|
||||
| `nut_farm_livestock_batch` | 牲畜批次 | 中 — `count`(数量) |
|
||||
| `nut_farm_supplier_rating` | 供应商评级 | 低 — 评分范围 |
|
||||
|
||||
#### 算法与 AI
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `nut_algo_personal` | 个性化算法结果 | 高 — 营养计算结果 |
|
||||
| `nut_algo_mass` | 批量算法结果 | 高 — 批量计算结果 |
|
||||
| `nut_algo_standard` | 算法标准 | 中 — 标准值合理性 |
|
||||
| `nut_model_llm` | LLM 模型配置 | 中 — 配置有效性 |
|
||||
| `nut_model_small_version` | 模型版本 | 低 — 版本管理 |
|
||||
|
||||
#### 设备与终端
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `nut_terminal` | 终端设备 | 中 — 设备状态 |
|
||||
| `nut_terminal_fault` | 终端故障记录 | 低 |
|
||||
| `nut_meter_device` | 计量设备(秤) | 中 — 计量精度 |
|
||||
| `nut_meter_reading` | 计量读数 | 高 — 读数合理性 |
|
||||
|
||||
### 5.2 系统脏数据检测规则
|
||||
|
||||
> 后端已实现 `nut_ano_dirty` 表,以下按原型业务模块分类列出需要检测的规则。
|
||||
|
||||
#### 用户档案
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 逻辑矛盾 | 年龄为负数 | `nut_user_profile` | `birthday`(生日) → 计算年龄 |
|
||||
| 范围越界 | BMI 值超出合理范围 | `nut_user` / `nut_user_profile` | `bmi`(BMI值) |
|
||||
| 数据缺失 | 手机号为空 | `nut_user` | `phone`(手机号) |
|
||||
| 重复数据 | 同一 `user_id` 存在多条档案记录 | `nut_user_profile` | `user_id`(用户ID) |
|
||||
| 逻辑矛盾 | 健康目标与饮食限制冲突(如目标为增重但设置了减脂限制) | `nut_user_profile` | `health_goal`(健康目标) ↔ `dietary_restrictions`(饮食限制) |
|
||||
|
||||
#### 食谱管理
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 数据缺失 | 热量值字段为空 | `nut_recipe` / `nut_food_nutri` | `total_calories`(总热量) |
|
||||
| 关联缺失 | 食谱引用的食材ID在食材库中不存在 | `nut_recipe_food` | `food_id`(食材ID) → `nut_food.id` |
|
||||
| 格式错误 | 食谱营养汇总JSON格式非法 | `nut_recipe` | `nutrition_summary`(营养汇总JSON) |
|
||||
|
||||
#### 订餐管理
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 格式错误 | 订餐日期格式非法 | `nut_order` | 订单日期字段 |
|
||||
| 范围越界 | 单次订餐份数超出系统上限 | `nut_order_item` | `quantity`(数量) |
|
||||
| 逻辑矛盾 | 订单金额与明细小计之和不一致 | `nut_order.total_amount` vs `SUM(nut_order_item.subtotal)` | |
|
||||
|
||||
#### 营养分析
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 重复数据 | 同一用户同日存在多条重复营养分析记录 | `nut_algo_personal` | `user_id`(用户ID) + 日期 |
|
||||
| 范围越界 | 营养素计算结果超出合理范围 | `nut_algo_personal` / `nut_algo_mass` | 营养结果字段 |
|
||||
|
||||
#### 食材库存
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 范围越界 | 库存数量为负值 | `nut_sup_inventory` | `quantity`(库存数量) |
|
||||
| 逻辑矛盾 | 库存流水余额与当前库存不一致 | `nut_sup_inventory_flow` ↔ `nut_sup_inventory` | `current_qty_after`(操作后在库量) vs `quantity`(库存数量) |
|
||||
| 关联缺失 | 库存记录的原材料在 `nut_mater_base` 中不存在 | `nut_sup_inventory` | `mater_id`(原材料ID) |
|
||||
|
||||
#### 健康生产
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 格式错误 | 生产批次号含非法字符 | `nut_prod_combo_task` | `task_no`(任务编号) |
|
||||
| 逻辑矛盾 | 生产任务完成但无供餐记录 | `nut_prod_combo_task` ↔ `nut_prod_serve_record` | |
|
||||
| 数据缺失 | 质检样品无检测结果 | `nut_prod_qc_sample` | `status`(状态:0=留样中/1=已处置/2=已检验) |
|
||||
|
||||
#### 卫生供应
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 数据缺失 | 供应商资质证书编号为空 | `nut_farm_supplier_external` | 证书字段 |
|
||||
| 格式错误 | 卫生检测报告编号格式非法 | `nut_sup_hygiene_test` | 检测编号字段 |
|
||||
| 关联缺失 | 供应记录关联的供应商已删除 | `nut_raw_inbound` | `supplier_id`(供应商ID) |
|
||||
|
||||
### 5.3 现有后端实现评估
|
||||
|
||||
#### 已实现
|
||||
|
||||
| 组件 | 状态 | 说明 |
|
||||
|------|:--:|------|
|
||||
| `nut_ano_dirty` 表 | ✅ 已上线 | 5个索引,支持分页/筛选/导出 |
|
||||
| `NutAnoDirtyService` | ✅ 已上线 | 完整 CRUD + 异步导出 |
|
||||
| `NutAnoDirtyController` | ✅ 已上线 | 与原型一致的查询接口 |
|
||||
|
||||
#### 待完善
|
||||
|
||||
| 项目 | 优先级 | 说明 |
|
||||
|------|:--:|------|
|
||||
| 系统脏数据自动检测定时任务 | 高 | 需实现每日全量扫描 Job |
|
||||
| 订餐管理、食材库存、健康生产、卫生供应的脏数据规则 | 高 | 原型有定义但后端可能未覆盖全 |
|
||||
| 农场子域的脏数据检测 | 中 | 原型未明确涉及,但表结构已存在 |
|
||||
| 设备/终端数据脏数据检测 | 低 | 秤读数、终端故障等 |
|
||||
|
||||
### 5.4 检测频率建议
|
||||
|
||||
| 检测类型 | 建议频率 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 系统脏数据全面扫描 | 每日凌晨 2:00 | 全量扫描所有7个业务模块 |
|
||||
| 库存数量负值检查 | 每日凌晨 + 每次出入库后 | 实时性要求较高 |
|
||||
| 订单金额一致性 | 每日凌晨 | 财务敏感性数据 |
|
||||
|
||||
---
|
||||
|
||||
## 六、健康监测
|
||||
|
||||
> **后端服务**:`platform-monitor`(端口 24805)| **原型参考**:`web-admin/health-monitor/exception-dirty.html`
|
||||
>
|
||||
> **开发状态**:❌ 未实现独立的脏数据检测表,已有 `mon_alert_record`(穿戴告警)和 `mon_env_warn_info`(环境告警)。
|
||||
|
||||
健康监测是系统第二大模块,涵盖可穿戴设备数据采集、环境监测、健康调查问卷等。
|
||||
|
||||
### 6.1 涉及数据库表
|
||||
|
||||
#### 设备与告警
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `mon_device` | 可穿戴设备主表 | 高 — `device_code`(设备编码)、`bind_status`(绑定状态)、`bind_user_id`(绑定用户ID)、`online_status`(在线状态)、`last_data_time`(最后数据上报时间) |
|
||||
| `mon_device_config` | 设备监测配置 | 高 — `threshold_min`(阈值下限)、`threshold_max`(阈值上限)、`upload_frequency`(上报频率) |
|
||||
| `mon_bind_record` | 设备绑定/解绑记录 | 中 — `bind_date`(绑定日期)、`unbind_date`(解绑日期) |
|
||||
| `mon_alert_record` | 告警记录 | 中 — `alert_value`(告警值)、`threshold_range`(阈值范围)、GPS 坐标 |
|
||||
| `mon_notification` | 通知消息 | 低 — `send_time`(发送时间)、`notice_status`(通知状态) |
|
||||
|
||||
#### 每日聚合统计(9张表)
|
||||
|
||||
| 表名 | 关键字段 | 脏数据风险 |
|
||||
|------|----------|:--:|
|
||||
| `mon_daily_stats_summary` | `wear_flag`(佩戴标记)、`last_upload_time`(最后上报时间) | 中 |
|
||||
| `mon_daily_stats_heart_rate` | `hr_max`(最大心率)/`hr_min`(最小心率)/`hr_avg`(平均心率)/`hr_latest`(最新心率)、`silence_hr_*`(静息心率) | 高 |
|
||||
| `mon_daily_stats_spo2` | `spo2_max`(最大血氧)/`spo2_min`(最小血氧)/`spo2_avg`(平均血氧)/`spo2_latest`(最新血氧) | 高 |
|
||||
| `mon_daily_stats_stress` | `stress_max`(最大压力)/`stress_min`(最小压力)/`stress_avg`(平均压力)/`stress_latest`(最新压力) | 中 |
|
||||
| `mon_daily_stats_temperature` | `temp_max`(最高体温)/`temp_min`(最低体温)/`temp_avg`(平均体温)/`temp_latest`(最新体温)、`skin_temp_*`(皮肤温度) | 高 |
|
||||
| `mon_daily_stats_blood_pressure` | `systolic_max`(最高收缩压)/`systolic_min`(最低收缩压)、`diastolic_max`(最高舒张压)/`diastolic_min`(最低舒张压) | 高 |
|
||||
| `mon_daily_stats_sleep` | `total_min`(总睡眠时长分钟)、`deep_min`(深睡时长)、`score`(睡眠评分) | 中 |
|
||||
| `mon_daily_stats_exercise` | `steps`(步数)、`exercise_calorie`(运动消耗卡路里)、`steps_distance`(步行距离)、`exercise_distance`(运动距离) | 中 |
|
||||
| `mon_daily_stats_ecg` | `ecg_count`(心电测量次数)、`latest_value`(最新值) | 低 |
|
||||
|
||||
#### 原始监测数据(12张表)
|
||||
|
||||
| 表名 | 关键字段 | 脏数据风险 |
|
||||
|------|----------|:--:|
|
||||
| `mon_data_heart_rate` | `data_value`(心率值bpm)、`silence_value`(静息心率值) | 高 |
|
||||
| `mon_data_spo2` | `data_value`(血氧值%) | 高 |
|
||||
| `mon_data_stress` | `data_value`(压力值)、`start_time`(测量开始时间)、`end_time`(测量结束时间) | 中 |
|
||||
| `mon_data_temperature` | `data_value`(体温值℃)、`skin_value`(皮肤温度) | 高 |
|
||||
| `mon_data_sleep` | `fall_asleep_time`(入睡时间)、`wake_up_time`(醒来时间)、`sleep_score`(睡眠评分) | 中 |
|
||||
| `mon_data_sleep_stage` | `stage_type`(睡眠阶段类型)、`start_time`(开始时间)、`end_time`(结束时间)、`duration`(持续时间) | 中 |
|
||||
| `mon_data_ecg` | `avg_heart_rate`(平均心率)、`arrhy_type`(心律失常类型)、`data_points_url`(数据点文件URL) | 中 |
|
||||
| `mon_data_exercise` | `calorie`(消耗卡路里)、`distance`(运动距离)、`duration`(运动时长) | 中 |
|
||||
| `mon_data_exercise_trace` | `longitude`(经度)、`latitude`(纬度)、`altitude`(海拔) | 中 |
|
||||
| `mon_data_steps` | `step_count`(步数)、`calorie`(消耗卡路里)、`distance`(距离) | 中 |
|
||||
| `mon_data_blood_pressure` | `systolic_value`(收缩压)、`diastolic_value`(舒张压) | 高 |
|
||||
| `mon_data_gps` | `longitude`(经度)、`latitude`(纬度)、`address`(地址) | 中 |
|
||||
|
||||
#### 环境监测(16张表)
|
||||
|
||||
| 类别 | 数据表 | 日数据表 | 月数据表 | 使用记录表 |
|
||||
|------|--------|----------|----------|-----------|
|
||||
| 室内 | `mon_env_data_indoor` | `mon_env_day_data_indoor` | `mon_env_month_data_indoor` | `mon_env_use_record_indoor` |
|
||||
| 室外 | `mon_env_data_outdoor` | `mon_env_day_data_outdoor` | `mon_env_month_data_outdoor` | `mon_env_use_record_outdoor` |
|
||||
| 花粉 | `mon_env_data_pollen` | `mon_env_day_data_pollen` | `mon_env_month_data_pollen` | `mon_env_use_record_pollen` |
|
||||
| 水质 | `mon_env_data_water` | `mon_env_day_data_water` | `mon_env_month_data_water` | `mon_env_use_record_water` |
|
||||
|
||||
附加表:`mon_env_category_indoor/outdoor/pollen/water`(指标类别定义)、`mon_env_meter_info`(环境仪表元数据)、`mon_env_warn_info`(环境告警记录)、`mon_env_warn_sync_record`(告警同步记录)
|
||||
|
||||
#### 调查问卷
|
||||
|
||||
| 表名 | 说明 | 脏数据风险 |
|
||||
|------|------|:--:|
|
||||
| `mon_survey` | 调查主表 | 低 |
|
||||
| `mon_survey_activity` | 调查活动 | 低 |
|
||||
| `mon_survey_answer_record` | 回答记录 | 中 |
|
||||
| `mon_survey_answer_detail` | 回答详情 | 中 |
|
||||
|
||||
### 6.2 系统脏数据检测规则
|
||||
|
||||
> 按原型业务模块分类:健康排查、穿戴监测、体重监测、环境监测
|
||||
|
||||
#### 健康排查(问卷)
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 数据缺失 | 积分字段异常(`mon_survey_answer_record` 无 score 字段,积分在别处计算) | `mon_survey_answer_record` + 积分相关表 | — |
|
||||
| 逻辑矛盾 | 问卷回答时间早于活动发布时间 | `mon_survey_answer_record` ↔ `mon_survey_activity` | 时间字段 |
|
||||
| 重复数据 | 同一用户同一问卷出现多条回答记录 | `mon_survey_answer_record` | `user_id`(用户ID) + `survey_id`(问卷ID) |
|
||||
|
||||
#### 穿戴监测
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 格式错误 | 设备绑定日期格式非法 | `mon_bind_record` | `bind_date`(绑定日期) |
|
||||
| 重复数据 | 同一设备同一时间段出现重复数据记录 | `mon_data_heart_rate` / `mon_data_spo2` / ... | `device_id`(设备ID) + `data_time`(数据时间) |
|
||||
| 范围越界 | 心率值超出人体可能范围(如 <20 或 >300 bpm) | `mon_data_heart_rate` | `data_value`(心率值bpm) |
|
||||
| 范围越界 | 血氧值超出合理范围(如 <50% 或 >100%) | `mon_data_spo2` | `data_value`(血氧值%) |
|
||||
| 范围越界 | 体温值超出人体可能范围(如 <30℃ 或 >45℃) | `mon_data_temperature` | `data_value`(体温值℃) |
|
||||
| 逻辑矛盾 | 静息心率高于活动心率 | `mon_daily_stats_heart_rate` | `silence_hr_avg`(静息心率均值) > `hr_avg`(心率均值) |
|
||||
| 逻辑矛盾 | 设备在线但超过 N 天无数据上报 | `mon_device` | `online_status`(在线状态) + `last_data_time`(最后上报时间) |
|
||||
| 范围越界 | GPS 坐标超出国内范围 | `mon_data_gps` | `longitude`(经度)、`latitude`(纬度) |
|
||||
| 格式错误 | 穿戴设备原始数据 `data_points_url` 指向的 URL 不可访问 | `mon_data_ecg` | `data_points_url`(数据点文件URL) |
|
||||
|
||||
#### 体重监测
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 逻辑矛盾 | 日统计中的最大心率 < 最小心率 | `mon_daily_stats_heart_rate` | `hr_max`(最大心率) < `hr_min`(最小心率) |
|
||||
| 逻辑矛盾 | 日统计中的收缩压 < 舒张压 | `mon_daily_stats_blood_pressure` | `systolic_*`(收缩压) < `diastolic_*`(舒张压) |
|
||||
| 逻辑矛盾 | 睡眠时长 > 24小时 | `mon_daily_stats_sleep` | `total_min`(总睡眠时长) > 1440 |
|
||||
|
||||
#### 环境监测
|
||||
|
||||
| 异常类型 | 检测规则 | 涉及表 | 涉及字段 |
|
||||
|----------|----------|--------|----------|
|
||||
| 逻辑矛盾 | 室内温度高于室外温度超过10℃(且空调未在制热) | `mon_env_data_indoor` + `mon_env_data_outdoor` | 温度字段 |
|
||||
| 范围越界 | 环境温度超出设备量程 | 各环境数据表 | 温度字段 |
|
||||
| 范围越界 | PM2.5 值为负数 | `mon_env_data_indoor` / `mon_env_data_outdoor` | PM2.5 字段 |
|
||||
| 范围越界 | ph 值超出 0-14 范围 | `mon_env_data_water` | `ph`(酸碱度) |
|
||||
| 数据缺失 | 环境监测设备超过 N 天未上报数据 | 各环境数据表 | `read_time`(读取时间) |
|
||||
| 关联缺失 | 环境数据关联的仪表在 `mon_env_meter_info` 中不存在 | 各环境数据表 | `meter_code`(仪表编码) |
|
||||
|
||||
### 6.3 检测频率建议
|
||||
|
||||
| 检测类型 | 建议频率 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 系统脏数据全面扫描 | 每日凌晨 3:00 | 穿戴/环境数据量大,错峰执行 |
|
||||
| 原始数据范围越界检查 | 数据入库时实时 | 在数据接收层做第一道校验 |
|
||||
| 聚合统计一致性检查 | 每日凌晨(聚合任务完成后) | 校验日统计 = 原始数据汇总 |
|
||||
| 设备在线但无数据告警 | 每小时 | `mon_device.online_status` + `last_data_time` |
|
||||
| GPS 坐标越界检查 | 每日凌晨 | 全量扫描 `mon_data_gps` |
|
||||
@@ -0,0 +1,966 @@
|
||||
# 异常事件数据质量控制规则说明书
|
||||
|
||||
> **文档版本**:v1.0
|
||||
> **编写日期**:2026-07-28
|
||||
> **适用范围**:系统管理、健康咨询、应急就医、健康体检、营养管理、健康监测(共 6 个业务板块)
|
||||
> **执行主体**:数据中台(于数据同步环节内嵌执行质量校验)
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
- [一、文档概述](#一文档概述)
|
||||
- [二、系统脏数据类型定义](#二系统脏数据类型定义)
|
||||
- [三、脏数据与结果异常的边界](#三脏数据与结果异常的边界)
|
||||
- [四、数据中台质量校验流程](#四数据中台质量校验流程)
|
||||
- [五、各模块检测规则](#五各模块检测规则)
|
||||
- [5.1 系统管理](#51-系统管理)
|
||||
- [5.2 健康咨询](#52-健康咨询)
|
||||
- [5.3 应急就医](#53-应急就医)
|
||||
- [5.4 健康体检](#54-健康体检)
|
||||
- [5.5 营养管理](#55-营养管理)
|
||||
- [5.6 健康监测](#56-健康监测)
|
||||
- [六、附录](#六附录)
|
||||
|
||||
---
|
||||
|
||||
## 一、文档概述
|
||||
|
||||
### 1.1 编写目的
|
||||
|
||||
本文档定义平台各业务板块"系统脏数据"的统一质量校验规则,作为数据中台实现自动化数据质量检测(DQC, Data Quality Check)的依据。核心目标:
|
||||
|
||||
1. **统一标准**:收敛各板块原型和研发文档中分散、不一致的脏数据类型定义,建立全平台统一的异常分类体系
|
||||
2. **明确边界**:厘清"系统脏数据"与"结果异常"的判定标准,确保两类异常各归其位
|
||||
3. **指导落地**:为数据中台在 CDC / 增量同步链路中嵌入质量校验提供规则输入
|
||||
|
||||
### 1.2 适用范围
|
||||
|
||||
| 板块 | 管理端模块 | 当前状态 |
|
||||
|------|-----------|---------|
|
||||
| 健康咨询 | `web-admin/health-consult/` | 原型已定稿,后端已部分实现 |
|
||||
| 应急就医 | `web-admin/emergency-dispatch/` | 原型已定稿,后端有占位 |
|
||||
| 健康体检 | `web-admin/health-checkup/` | 原型已定稿 |
|
||||
| 营养管理 | `web-admin/nutrition/` | 原型已定稿,后端已部分实现 |
|
||||
| 健康监测 | `web-admin/health-monitor/` | 原型已定稿 |
|
||||
| 系统管理 | `platform-java/platform-system/` | 后端已实现 |
|
||||
|
||||
### 1.3 术语定义
|
||||
|
||||
| 术语 | 定义 |
|
||||
|------|------|
|
||||
| **系统脏数据** | 写入数据库后,因其字段值违反数据完整性约束(非空、格式、取值范围、外键关联、唯一性、逻辑一致性)而不可信或不可用的数据记录 |
|
||||
| **结果异常** | 数据本身在存储层面合法、完整,但所反映的业务结果偏离正常范围(如超时未关闭、评分异常偏低、指标超出医学参考范围等),属于业务流程或健康结果的异常,**不属于系统脏数据范畴** |
|
||||
| **数据中台 DQC** | Data Quality Check,在数据同步管道(CDC 或定时增量)中内嵌执行的数据质量校验环节 |
|
||||
| **CDC** | Change Data Capture,基于数据库变更日志的实时增量数据捕获机制 |
|
||||
|
||||
---
|
||||
|
||||
## 二、系统脏数据类型定义
|
||||
|
||||
全平台统一使用以下 6 种脏数据类型。各板块的具体检测规则均以此分类为准。
|
||||
|
||||
### 2.1 类型一览
|
||||
|
||||
| 编码 | 类型名称 | 判定标准 | 严重级别 |
|
||||
|------|----------|----------|:--:|
|
||||
| D01 | **数据缺失** | 业务规则要求非空的字段,其值为 NULL 或空字符串 | 高 |
|
||||
| D02 | **格式违规** | 字段值不符合预定义的格式规范(正则、JSON Schema、日期格式等) | 高 |
|
||||
| D03 | **取值越界** | 字段值超出物理极限或逻辑合理范围(含连续数值越界和离散枚举越界) | 高 |
|
||||
| D04 | **逻辑冲突** | 同一记录内多个字段之间,或存在业务关联的多条记录之间,字段值存在不可调和的逻辑矛盾 | 高 |
|
||||
| D05 | **关联断裂** | 外键字段值非空,但其引用的目标记录在关联表中不存在(孤儿记录) | 中 |
|
||||
| D06 | **数据重复** | 违反业务唯一性约束,存在多条本应唯一的记录 | 中 |
|
||||
|
||||
### 2.2 各类型详细定义
|
||||
|
||||
#### D01 — 数据缺失
|
||||
|
||||
**定义**:业务语义上必须具备值的字段,在数据库层面为 NULL 或等效空值。
|
||||
|
||||
**判定逻辑**:
|
||||
- 单字段规则:`field IS NULL OR field = ''`
|
||||
- 组合规则:同一记录内多个关联字段全部为空(如身高、体重、腰围三者均为空)
|
||||
|
||||
**典型示例**:
|
||||
- 用户档案中姓名为空
|
||||
- 订单主表中订单编号为空
|
||||
- 体检报告中检查结果值为空
|
||||
- 设备编码为空
|
||||
|
||||
**注意事项**:
|
||||
- 允许为空的字段(如选填的备注、非必填的附件URL)不在检测范围
|
||||
- 需结合业务规则确认哪些字段为"必填",不能仅凭数据库 DDL 的 `NOT NULL` 约束判断(有些字段在 DDL 层面允许 NULL,但业务上必须具备值)
|
||||
|
||||
---
|
||||
|
||||
#### D02 — 格式违规
|
||||
|
||||
**定义**:字段值已填充,但其字符串形式不符合约定的格式规范。
|
||||
|
||||
**判定逻辑**:
|
||||
- 正则匹配失败(手机号、身份证号、邮箱等)
|
||||
- JSON/XML 解析失败(如 `questions_json`、`nutrition_summary` 等)
|
||||
- 日期/时间字符串无法按预期格式解析
|
||||
- URL 格式不合法
|
||||
|
||||
**典型示例**:
|
||||
- 手机号字段值为 `"abc123"` 或长度不为 11 位
|
||||
- 常规体检指标数据出现汉字,空腹血糖值 `"无记录"`
|
||||
- 问卷 JSON 字段 `parse()` 抛出异常
|
||||
- 日期字段值为 `"2026-13-40"`(无效日期)
|
||||
- 生活习惯标记字段不符合 `state,score,fullmark` 格式
|
||||
|
||||
**注意事项**:
|
||||
- 格式校验的正则表达式需与业务端输入校验规则保持一致
|
||||
- 对于允许自由文本的字段(如备注、描述),不执行格式校验
|
||||
|
||||
---
|
||||
|
||||
#### D03 — 取值越界
|
||||
|
||||
**定义**:字段值已填充且格式合法,但数值大小或枚举编码超出了物理/逻辑合理范围。
|
||||
|
||||
**判定逻辑**:
|
||||
- 连续数值越界:`value < min OR value > max`(min/max 基于人体生理极限或业务规则)
|
||||
- 离散枚举越界:`value NOT IN (enum_set)`(enum_set 为字段的合法枚举值集合)
|
||||
|
||||
**典型示例**:
|
||||
- BMI 值为 85.3 或 -5(合理范围 10~80)
|
||||
- 收缩压为 350 mmHg(合理范围 50~300)
|
||||
- 库存数量为 -100(不应为负)
|
||||
- 性别字段值为 3(枚举仅 1=男 / 2=女)
|
||||
- 人群分类字段值为 `"X"`(枚举仅 A/B/C/D/E)
|
||||
- 经纬度超出中国版图范围,北纬4°-53°33′,东经135°5′-73°40′
|
||||
|
||||
#### 统一取值越界参考标准
|
||||
|
||||
以下为跨模块通用的数值边界定义。各模块检测规则中的对应阈值统一以此表为准,避免同一业务含义的字段在不同模块中出现不一致的校验边界。
|
||||
|
||||
**人体测量类**
|
||||
|
||||
| 字段 | 单位 | 下限 | 上限 | 说明 |
|
||||
|------|------|:--:|:--:|------|
|
||||
| 身高 | cm | 50 | 250 | 低于50cm不具备成年人体征,高于250cm超出人类身高纪录 |
|
||||
| 体重 | kg | 20 | 300 | 低于20kg不具备成年人体征,300kg为临床极端值上限 |
|
||||
| BMI | — | 10 | 80 | 10以下为生命维持极限,80以上为世界纪录的约3倍 |
|
||||
| 体脂率 | % | 2 | 60 | 2%为男性必需脂肪下限,60%超出临床病态肥胖上限 |
|
||||
| 腰围 | cm | 30 | 200 | 30cm为新生儿水平,200cm超出临床极端值 |
|
||||
| 年龄 | 岁 | 0 | 150 | 0岁为出生当年,150岁超出人类寿命极限 |
|
||||
|
||||
**生命体征类**
|
||||
|
||||
| 字段 | 单位 | 下限 | 上限 | 说明 |
|
||||
|------|------|:--:|:--:|------|
|
||||
| 收缩压 | mmHg | 50 | 300 | 50mmHg为濒危休克值,300mmHg超出血压计量程 |
|
||||
| 舒张压 | mmHg | 30 | 200 | 30mmHg为濒危休克值,200mmHg超出临床极端值 |
|
||||
| 心率 | bpm | 20 | 300 | 20bpm为深度休眠/濒危值,300bpm超出心室颤动极限 |
|
||||
| 血氧饱和度 | % | 50 | 100 | 50%以下为致命性低氧,100%为理论饱和上限 |
|
||||
| 体温 | ℃ | 30 | 45 | 30℃为致命性低温,45℃超出人体存活上限 |
|
||||
| 空腹血糖 | mmol/L | 0 | 50 | 0为理论下界,50mmol/L超出临床极端高值 |
|
||||
|
||||
**时间度量类**
|
||||
|
||||
| 字段 | 单位 | 下限 | 上限 | 说明 |
|
||||
|------|------|:--:|:--:|------|
|
||||
| 睡眠时长 | 分钟 | 0 | 1440 | 0为未睡眠,1440为一天总分钟数 |
|
||||
|
||||
**地理坐标类**
|
||||
|
||||
| 字段 | 单位 | 下限 | 上限 | 说明 |
|
||||
|------|------|:--:|:--:|------|
|
||||
| 经度(中国境内) | 度 | 73 | 136 | 东经73°40′(新疆阿克赛钦)~ 东经135°5′(黑龙江抚远),取整 |
|
||||
| 纬度(中国境内) | 度 | 4 | 54 | 北纬4°(南沙群岛曾母暗沙)~ 北纬53°33′(黑龙江漠河),取整 |
|
||||
|
||||
**评分与占比类**
|
||||
|
||||
| 字段 | 单位 | 下限 | 上限 | 说明 |
|
||||
|------|------|:--:|:--:|------|
|
||||
| 评分(5分制) | 分 | 0 | 5 | 适用于专家评分、咨询评分等五级评分体系 |
|
||||
| 百分比 | % | 0 | 100 | 适用于回复率、电量百分比、完成率等百分比字段 |
|
||||
| pH 值 | — | 0 | 14 | 水溶液酸碱度理论范围 |
|
||||
|
||||
**与格式违规的区别**:
|
||||
- 格式违规关注"值的形态"(如"abc"不是数字)
|
||||
- 取值越界关注"值的量级"(如 999 是合法数字但超出了合理上限)
|
||||
|
||||
---
|
||||
|
||||
#### D04 — 逻辑冲突
|
||||
|
||||
**定义**:单条记录内多个字段之间存在不可调和的值矛盾,或多条关联记录之间的汇总/引用关系不成立。
|
||||
|
||||
**判定逻辑**:
|
||||
- 同一行内两字段比较(如 `end_time < start_time`、`sbp < dbp`)
|
||||
- 一对多汇总不一致(如 `total_amount != SUM(subtotal)`)
|
||||
- 状态与时间戳矛盾(如状态=已完成但 end_time 为空)
|
||||
- 标记与明细不一致(如 is_exception=1 但所有子项指标均正常)
|
||||
|
||||
**典型示例**:
|
||||
- 咨询结束时间早于开始时间
|
||||
- 订单总金额不等于明细小计之和
|
||||
- 会话状态为"进行中"但结束时间已填充
|
||||
- 收缩压(110)低于舒张压(85)
|
||||
- 睡眠时长 + 运动时长 > 1440 分钟(超过一天)
|
||||
|
||||
**注意事项**:
|
||||
- 逻辑冲突规则需要深入理解业务语义,建议由产品经理与研发联合确认
|
||||
- 统计类字段(如 `statics_num`)与源表记录数的一致性校验属于此类,但因实时性要求低,可在每日全量对账时执行
|
||||
|
||||
---
|
||||
|
||||
#### D05 — 关联断裂
|
||||
|
||||
**定义**:记录中的外键字段指向了一个在关联表中已不存在的 ID。
|
||||
|
||||
**判定逻辑**:
|
||||
- `foreign_key IS NOT NULL AND foreign_key NOT IN (SELECT id FROM referenced_table)`
|
||||
|
||||
**典型示例**:
|
||||
- 咨询记录中的 `expert_id` 在专家表中不存在(专家已删除)
|
||||
- 订单中的 `user_id` 在用户表中不存在
|
||||
- 评价记录中的 `consult_id` 在咨询表中不存在
|
||||
- AED 设备部署点位关联的应急中心 ID 无效
|
||||
|
||||
**注意事项**:
|
||||
- 仅在外键值非空时检测(允许 NULL 的外键不触发此规则,因为 NULL 表示"未关联"而非"关联无效")
|
||||
- 软删除场景需确认关联表的过滤条件(如 `del_falg IS NULL`)
|
||||
|
||||
---
|
||||
|
||||
#### D06 — 数据重复
|
||||
|
||||
**定义**:同一业务实体在违反唯一性约束的情况下出现了多条记录。
|
||||
|
||||
**判定逻辑**:
|
||||
- 按业务唯一键分组计数:`COUNT(*) > 1 GROUP BY business_unique_key`
|
||||
|
||||
**典型示例**:
|
||||
- 同一用户同一年度存在多条活跃人群分类记录
|
||||
- 同一员工同一活动重复报名
|
||||
- 同一设备同一时间点存在多条监测数据记录
|
||||
- 同一用户同一天存在多条营养分析结果记录
|
||||
|
||||
**注意事项**:
|
||||
- 业务唯一键 ≠ 数据库唯一索引。需根据业务语义定义去重维度
|
||||
- 区分"合理的多条记录"(如一个用户多次咨询)与"异常的多条记录"(如一个用户同一时刻两条档案)
|
||||
|
||||
---
|
||||
|
||||
## 三、脏数据与结果异常的边界
|
||||
|
||||
### 3.1 判定原则
|
||||
|
||||
> **核心原则**:系统脏数据关注"数据本身是否合法",结果异常关注"业务结果是否正常"。前者是数据质量的范畴,后者是业务监控的范畴。
|
||||
|
||||
### 3.2 边界对照表
|
||||
|
||||
| 场景 | 数据是否合法 | 分类 | 理由 |
|
||||
|------|:--:|------|------|
|
||||
| 血压值为 -50 mmHg | 否 | **脏数据 (D03)** | 数值超出物理极限 |
|
||||
| JSON 字段解析失败 | 否 | **脏数据 (D02)** | 格式不符合规范 |
|
||||
| 员工编号为空 | 否 | **脏数据 (D01)** | 必填字段缺失 |
|
||||
| 订单关联的用户已删除 | 否 | **脏数据 (D05)** | 外键关联失效 |
|
||||
| 同一用户同日两条档案 | 否 | **脏数据 (D06)** | 违反唯一性约束 |
|
||||
| 收缩压 110 < 舒张压 85 | 否 | **脏数据 (D04)** | 字段间逻辑矛盾 |
|
||||
| 血压值 185/110 mmHg | **是** | 结果异常 | 值在物理范围内,但超出医学正常参考范围 |
|
||||
| 工单创建后 7 天未关闭 | **是** | 结果异常 | 状态值和时长均合法,属业务流程超时 |
|
||||
| 专家评分 1.5 分(满分 5) | **是** | 结果异常 | 评分值在合法范围内,属服务质量问题 |
|
||||
| 咨询会话超过 60 分钟 | **是** | 结果异常 | 时长值合法,属服务效率问题 |
|
||||
| 设备超过 3 天未上报数据 | **是** | 结果异常 | 数据本身无异常,属设备离线告警 |
|
||||
| ICU 患者血糖 22 mmol/L | **是** | 结果异常 | 值本身合法,属危急值预警 |
|
||||
|
||||
### 3.3 典型易混淆场景澄清
|
||||
|
||||
**场景一:咨询时长异常**
|
||||
|
||||
研发文档中健康咨询模块的 `exception_type=1`(咨询时长异常 > 60 分钟)被归类为系统脏数据,实为**结果异常**。`duration_minutes` 字段的值 61、120 等在格式和范围内均合法,只是反映了"这个咨询用时很长"这一业务事实——这是服务质量监控指标,不是数据质量问题。
|
||||
|
||||
**场景二:任务状态卡住**
|
||||
|
||||
研发文档中多处出现 `status = 处理中 超过 24 小时` 的规则。若状态字段值本身合法(确实为"处理中"),则属于结果异常(任务卡住);但若状态值与时间戳存在矛盾(如状态=已完成但 end_time 为空),则为脏数据(D04 逻辑冲突)。
|
||||
|
||||
**场景三:评价分数极低**
|
||||
|
||||
评分字段值 1 在 1~5 范围内合法,属于结果异常(服务评价差)。只有当 score 值超出 1~5 范围时,才属于脏数据(D03 取值越界)。
|
||||
|
||||
---
|
||||
|
||||
## 四、数据中台质量校验流程
|
||||
|
||||
### 4.1 整体架构
|
||||
|
||||
系统脏数据的检测由数据中台统一执行,不依赖各业务服务自行实现定时任务。质量校验嵌入在数据中台从业务数据库同步数据的管道中,实现"同步即校验"。
|
||||
|
||||
```
|
||||
┌──────────────┐ CDC/增量同步 ┌────────────────────┐
|
||||
│ 业务数据库 │ ──────────────────> │ 数据中台 │
|
||||
│ (postgreSQL) │ │ │
|
||||
│ │ │ ┌──────────────┐ │
|
||||
│ health_ │ │ │ DQC 规则引擎 │ │
|
||||
│ consult │ │ │ (同步即校验) │ │
|
||||
│ emergency │ │ └──────┬───────┘ │
|
||||
│ exam │ │ │ │
|
||||
│ nutrition │ │ ┌────▼───────┐ │
|
||||
│ monitor │ │ │ 脏数据存储库 │ │
|
||||
│ weight │ │ │ (汇总查询) │ │
|
||||
│ ... │ │ └────────────┘ │
|
||||
└──────────────┘ └────────────────────┘
|
||||
```
|
||||
|
||||
### 4.2 校验触发时机
|
||||
|
||||
| 同步模式 | 触发时机 | 适用场景 |
|
||||
|----------|----------|----------|
|
||||
| **CDC 实时同步** | 每捕获一条 INSERT/UPDATE 变更事件,即对该记录执行 DQC 规则校验 | 数据缺失、格式违规、取值越界、逻辑冲突(单行)、枚举非法 |
|
||||
| **增量批次同步** | 每个批次(如每 5 分钟一批)同步完成后,对批次内记录执行跨表校验 | 关联断裂 |
|
||||
| **每日全量对账** | 每日凌晨,对全量/增量数据进行汇总级校验 | 逻辑冲突(汇总不一致)、数据重复 |
|
||||
|
||||
### 4.3 校验管线
|
||||
|
||||
```
|
||||
数据变更事件 (CDC Event)
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ 1. 字段映射 │ 将业务表字段映射为标准 DQC 字段模型
|
||||
└────────┬────────┘
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ 2. 规则匹配 │ 根据「表名.字段名」匹配对应 DQC 规则集
|
||||
└────────┬────────┘
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ 3. 规则执行 │ 逐条执行规则 → 输出 (通过 / 不通过 + 异常详情)
|
||||
└────────┬────────┘
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ 4. 结果路由 │ 通过 → 数据入仓
|
||||
│ │ 不通过 → 写入脏数据表 + 同步告警(可选)
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### 4.4 脏数据记录模型
|
||||
|
||||
校验发现脏数据后,统一写入以下结构的异常记录:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|--------------------|------|------------------------------------------------------------------------|
|
||||
| `id` | bigint | 主键 |
|
||||
| `module` | varchar | 业务板块(health_consult / emergency / exam / nutrition / monitor / weight) |
|
||||
| `dirty_type` | varchar | 脏数据类型编码(D01 ~ D06) |
|
||||
| `table_name` | varchar | 来源表名 |
|
||||
| `table_desc` | varchar | 业务表描述(设备主表、咨询记录表、应急工单表等) |
|
||||
| `field_name` | varchar | 异常字段名(多字段时用逗号分隔) |
|
||||
| `record_id` | varchar | 异常记录的主键/业务编号 |
|
||||
| `abnormal_value` | text | 异常值 |
|
||||
| `rule_description` | text | 触发的规则描述 |
|
||||
| `detected_at` | datetime | 检测时间 |
|
||||
| `data_created_at` | datetime | 异常数据的业务产生时间(来自源表时间戳字段) |
|
||||
| `status` | varchar | 处理状态(待处理 / 已忽略 / 已修复) |
|
||||
|
||||
### 4.5 告警与处置
|
||||
|
||||
- **系统脏数据查询**:在各业务版块下的异常事件-系统脏数据中提供脏查询功能
|
||||
- **实时告警(暂不实现)**:D01~D03 类型(数据缺失、格式违规、取值越界)发现后即时推送告警,通知对应板块的数据负责人
|
||||
- **定时报告(暂不实现)**:D04~D06 类型(逻辑冲突、关联断裂、数据重复)汇总至每日数据质量日报,统一呈现
|
||||
- **处置闭环((暂不实现))**:业务端通过"异常事件 → 系统脏数据"页面查看、筛选、导出,确认后可标记为"已忽略"或修复源数据后自动复检清除
|
||||
|
||||
---
|
||||
|
||||
## 五、各模块检测规则
|
||||
|
||||
> 以下规则按「业务域 → 表 → 规则明细」三层结构组织,每个模块统一格式。
|
||||
|
||||
### 5.1 系统管理
|
||||
|
||||
#### 涉及数据表
|
||||
|
||||
系统管理是平台的基础支撑模块,管理用户、角色、组织架构、字典、配置等核心公共数据。以下仅列出直接影响业务数据完整性的核心校验表。
|
||||
|
||||
| 业务子域 | 核心表 | 关键校验字段 |
|
||||
|----------|--------|-------------|
|
||||
| 用户与角色 | `sys_user`, `sys_user_extend`, `sys_role`, `sys_user_role` | username, workNo, phone, idCard, sex, status, accountStatus, personType, birthday, height, weight, bmi, roleName, roleCode |
|
||||
| 组织机构 | `sys_depart` | departName, orgCode, orgCategory, orgType, status, lng, lat, parentId |
|
||||
| 字典与配置 | `sys_dict`, `sys_dict_item`, `sys_config` | name, code, itemName, itemValue, configKey, configName |
|
||||
|
||||
#### 检测规则
|
||||
|
||||
**sys_user(用户信息)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| S01-D01 | 登录账号缺失 | `username` | `IS NULL OR = ''` |
|
||||
| S01-D01 | 工号缺失 | `workNo` | `IS NULL OR = ''` |
|
||||
| S01-D02 | 手机号格式不合法 | `phone` | 不匹配 11 位手机号正则(如 `"888"` 或非数字字符) |
|
||||
| S01-D02 | 身份证号格式不合法 | `idCard` | 长度不为 18 位,或含非法字符,或校验位不通过 |
|
||||
| S01-D03 | 性别枚举越界 | `sex` | `NOT IN (0, 1, 2)`(0=未知, 1=男, 2=女) |
|
||||
| S01-D03 | 员工状态枚举越界 | `status` | `NOT IN (1, 2, 3)`(1=在岗, 2=封存, 3=注销) |
|
||||
| S01-D03 | 账号状态枚举越界 | `accountStatus` | `NOT IN (0, 1)`(0=锁定, 1=激活) |
|
||||
| S01-D03 | 用户类型枚举越界 | `personType` | `NOT IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)` |
|
||||
| S01-D03 | 生日为未来日期 | `birthday` | `birthday > CURRENT_DATE` |
|
||||
| S01-D06 | 工号重复 | `workNo` | 存在多条记录使用同一工号(排除已逻辑删除记录) |
|
||||
|
||||
**sys_role(角色)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| S02-D01 | 角色名称缺失 | `roleName` | `IS NULL OR = ''` |
|
||||
| S02-D01 | 角色编码缺失 | `roleCode` | `IS NULL OR = ''` |
|
||||
| S02-D03 | 角色类型枚举越界 | `roleType` | `NOT IN (0, 1)`(0=自定义, 1=系统内置) |
|
||||
| S02-D06 | 角色编码重复 | `roleCode` | 存在多条记录使用同一角色编码 |
|
||||
|
||||
**sys_user_role(用户角色关联)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| S03-D05 | 关联用户不存在 | `userId` | 引用的用户不存在 |
|
||||
| S03-D05 | 关联角色不存在 | `roleId` | 引用的角色不存在 |
|
||||
| S03-D06 | 用户角色重复分配 | `userId`, `roleId` | 同一用户被重复分配同一角色 |
|
||||
|
||||
**sys_depart(组织机构)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| S04-D01 | 机构名称缺失 | `departName` | `IS NULL OR = ''` |
|
||||
| S04-D01 | 机构编码缺失 | `orgCode` | `IS NULL OR = ''` |
|
||||
| S04-D03 | 机构类别枚举越界 | `orgCategory` | `NOT IN ('1', '2', '3')`(1=公司, 2=组织机构, 3=岗位) |
|
||||
| S04-D03 | 机构类型枚举越界 | `orgType` | `NOT IN ('1', '2')`(1=一级部门, 2=子部门) |
|
||||
| S04-D03 | 状态枚举越界 | `status` | `NOT IN ('0', '1')`(0=不启用, 1=启用) |
|
||||
| S04-D03 | 经纬度超出国内范围 | `lng`, `lat` | `lng < 73 OR lng > 136 OR lat < 4 OR lat > 54`(含 (0,0) 未初始化场景) |
|
||||
| S04-D04 | 父机构指向自身 | `id`, `parentId` | `id = parentId` |
|
||||
| S04-D05 | 关联父机构不存在 | `parentId` | 引用的父机构不存在 |
|
||||
| S04-D06 | 机构编码重复 | `orgCode` | 存在多条记录使用同一机构编码 |
|
||||
|
||||
**sys_dict(字典主表)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| S05-D01 | 字典名称缺失 | `name` | `IS NULL OR = ''` |
|
||||
| S05-D01 | 字典编码缺失 | `code` | `IS NULL OR = ''` |
|
||||
| S05-D06 | 字典编码重复 | `code` | 存在多条记录使用同一字典编码 |
|
||||
|
||||
**sys_dict_item(字典项)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| S06-D01 | 字典项名称缺失 | `itemName` | `IS NULL OR = ''` |
|
||||
| S06-D01 | 字典项值缺失 | `itemValue` | `IS NULL OR = ''` |
|
||||
| S06-D03 | 字典项状态枚举越界 | `status` | `NOT IN (0, 1)`(0=不启用, 1=启用) |
|
||||
| S06-D05 | 关联字典不存在 | `dictId` | 引用的字典不存在 |
|
||||
| S06-D06 | 同一字典下字典项值重复 | `dictId`, `itemValue` | 同一字典下存在重复的字典项值 |
|
||||
|
||||
**sys_config(参数配置)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| S07-D01 | 配置名称缺失 | `configName` | `IS NULL OR = ''` |
|
||||
| S07-D01 | 配置键缺失 | `configKey` | `IS NULL OR = ''` |
|
||||
| S07-D06 | 配置键重复 | `configKey` | 存在多条记录使用同一配置键 |
|
||||
|
||||
**sys_user_extend(用户扩展信息)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| S08-D03 | 身高越界 | `height` | `< 50 OR > 250` (cm) |
|
||||
| S08-D03 | 体重越界 | `weight` | `< 20 OR > 300` (kg) |
|
||||
| S08-D03 | BMI 越界 | `bmi` | `< 10 OR > 80` |
|
||||
| S08-D05 | 关联用户不存在 | `userId` | 引用的用户不存在 |
|
||||
|
||||
---
|
||||
|
||||
### 5.2 健康咨询
|
||||
|
||||
#### 涉及数据表
|
||||
|
||||
| 表名 | 说明 | 核心校验字段 |
|
||||
|------|------|-------------|
|
||||
| `con_consult` | 咨询会话主表 | consult_no, consult_type, content_status, session_status, start_time, end_time, duration_minutes, cost, expert_id, member_id |
|
||||
| `con_expert` | 专家信息表 | expert_no, expert_type, overall_merit, response_rate, reg_date, off_date, hospital_id, dept_id |
|
||||
| `con_evaluate` | 咨询评价表 | score, consult_id, expert_id |
|
||||
| `con_family_member` | 家庭成员表 | member_name, birthday, height, weight, sex |
|
||||
| `con_medical_record` | 病历档案表 | medical_describe, duration_type |
|
||||
| `con_im_message` | IM 消息记录表 | msg_content, msg_type, consult_id |
|
||||
| `con_expert_schedule_rule` | 专家排班规则表 | week_day, period, start_time, end_time, capacity |
|
||||
| `con_settle_main` | 结算主表 | settle_status, com_fee_per_month |
|
||||
|
||||
#### 检测规则
|
||||
|
||||
**con_consult(咨询会话)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| C01-D01 | 咨询单号缺失 | `consult_no` | `IS NULL OR = ''` |
|
||||
| C01-D03 | 咨询类型枚举越界 | `consult_type` | `NOT IN (1, 2)` |
|
||||
| C01-D03 | 内容状态枚举越界 | `content_status` | `NOT IN (1,2,3,4,5,6,7,8)` |
|
||||
| C01-D03 | 咨询费用为负数 | `cost` | `< 0` |
|
||||
| C01-D04 | 结束时间早于开始时间 | `start_time`, `end_time` | 结束时间早于开始时间 |
|
||||
| C01-D04 | 会话进行中但已有结束时间 | `session_status`, `end_time` | 会话状态为进行中但已有结束时间 |
|
||||
| C01-D04 | 内容已完成但无结束时间 | `content_status`, `end_time` | 内容已完成但无结束时间 |
|
||||
| C01-D04 | 已拒绝但无拒绝原因 | `content_status`, `reject_reason` | 已拒绝但未填写拒绝原因 |
|
||||
| C01-D05 | 关联专家不存在 | `expert_id` | 引用的专家不存在 |
|
||||
| C01-D05 | 关联咨询人不存在 | `member_id` | 引用的家庭成员不存在 |
|
||||
|
||||
**con_expert(专家信息)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| C02-D01 | 专家编号缺失 | `expert_no` | `IS NULL OR = ''` |
|
||||
| C02-D03 | 专家类型枚举越界 | `expert_type` | `NOT IN (1, 2, 3)` |
|
||||
| C02-D03 | 综合评分越界 | `overall_merit` | `< 0 OR > 5` |
|
||||
| C02-D03 | 回复率越界 | `response_rate` | `< 0 OR > 100` |
|
||||
| C02-D04 | 离职日期早于入职日期 | `reg_date`, `off_date` | 离职日期早于入职日期 |
|
||||
| C02-D05 | 关联医院不存在 | `hospital_id` | 引用的医院不存在 |
|
||||
| C02-D05 | 关联科室不存在 | `dept_id` | 引用的科室不存在 |
|
||||
|
||||
**con_evaluate(咨询评价)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| C03-D03 | 评分越界 | `score` | `< 0 OR > 5` |
|
||||
| C03-D05 | 关联咨询不存在 | `consult_id` | 引用的咨询记录不存在 |
|
||||
| C03-D05 | 关联专家不存在 | `expert_id` | 引用的专家不存在 |
|
||||
|
||||
**con_family_member(家庭成员)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| C04-D03 | 身高越界 | `height` | `< 50 OR > 250` |
|
||||
| C04-D03 | 体重越界 | `weight` | `< 20 OR > 300` |
|
||||
| C04-D03 | 性别枚举越界 | `sex` | `NOT IN (1, 2)` |
|
||||
| C04-D03 | 生日为未来日期 | `birthday` | `birthday > CURRENT_DATE` |
|
||||
|
||||
**con_medical_record(病历档案)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| C05-D01 | 病情描述缺失 | `medical_describe` | `IS NULL OR = ''` |
|
||||
| C05-D03 | 持续时间类型枚举越界 | `duration_type` | `NOT IN (1, 2, 3, 4)` |
|
||||
|
||||
**con_im_message(IM 消息)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| C06-D01 | 消息内容缺失(非撤回消息) | `msg_content` | 消息内容为空且消息类型非撤回 |
|
||||
| C06-D03 | 消息类型枚举越界 | `msg_type` | `NOT IN (1, 2, 3, 4)` |
|
||||
| C06-D05 | 关联咨询不存在 | `consult_id` | 引用的咨询记录不存在 |
|
||||
|
||||
**con_expert_schedule_rule(排班规则)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| C07-D03 | 星期枚举越界 | `week_day` | `NOT IN (1,2,3,4,5,6,7)` |
|
||||
| C07-D03 | 时段枚举越界 | `period` | `NOT IN (1, 2, 3, 4)` |
|
||||
| C07-D03 | 接诊人数为负数 | `capacity` | `< 0` |
|
||||
| C07-D04 | 排班结束时间早于开始时间 | `start_time`, `end_time` | `end_time < start_time` |
|
||||
|
||||
---
|
||||
|
||||
### 5.3 应急就医
|
||||
|
||||
#### 涉及数据表
|
||||
|
||||
| 表名 | 说明 | 核心校验字段 |
|
||||
|------|------|-------------|
|
||||
| `em_emergency_order` | 应急工单 | order_no, status, location_lat, location_lng, closed_at |
|
||||
| `em_call_record` | 通话记录 | incoming_phone, match_status, order_id, begin_time, end_time, answer_status, duration |
|
||||
| `em_aed_device` | AED 设备 | battery_level, battery_status |
|
||||
| `em_aed_deploy_point` | AED 部署点位 | longitude, latitude |
|
||||
| `em_aed_latest` | AED 最新状态 | battery_power |
|
||||
| `em_aed_maintenance` | AED 维护记录 | maintenance_date |
|
||||
| `em_user_profile` | 应急人员档案 | cert_number, license_number, station_status |
|
||||
| `em_ambulance` | 救护车 | plate_no, status |
|
||||
| `em_emergency_center` | 应急中心 | longitude, latitude, center_phone, status |
|
||||
| `em_emergency_center_call_record` | 应急中心通话 | call_id, employee_id, begin_time, end_time |
|
||||
| `em_emergency_center_call_join` | 通话参与人 | employee_id, call_record_id |
|
||||
|
||||
#### 检测规则
|
||||
|
||||
**em_call_record(通话记录)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| E01-D02 | 来电号码格式不合法 | `incoming_phone` | 不匹配手机号/座机号正则 |
|
||||
| E01-D03 | 通话时长负数 | `duration` | `< 0` |
|
||||
| E01-D04 | 结束时间早于开始时间 | `begin_time`, `end_time` | 结束时间早于开始时间 |
|
||||
| E01-D04 | 已接听但通话时长为 0 | `answer_status`, `duration` | 已接听但通话时长为零 |
|
||||
| E01-D05 | 关联工单不存在 | `order_id` | 引用的应急工单不存在 |
|
||||
|
||||
**em_aed_device / em_aed_latest(AED 设备)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| E02-D03 | 电池电量百分比越界 | `battery_level` | 电池电量百分比不在 0~100 范围内 |
|
||||
| E02-D03 | 电池状态枚举越界 | `battery_status` | 不在预定义电池状态枚举集合内 |
|
||||
|
||||
**em_aed_deploy_point(AED 部署点位)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| E03-D03 | GPS 坐标超出国内范围 | `longitude`, `latitude` | `longitude < 73 OR longitude > 136 OR latitude < 4 OR latitude > 54` |
|
||||
| E03-D01 | GPS 坐标为 (0, 0) 或 NULL | `longitude`, `latitude` | GPS 坐标为空值或为 (0, 0) |
|
||||
| E03-D05 | 关联应急中心不存在 | 中心关联字段 | 引用的应急中心不存在 |
|
||||
|
||||
**em_aed_maintenance(AED 维护记录)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| E04-D03 | 维护日期为未来日期 | `maintenance_date` | `maintenance_date > CURRENT_DATE` |
|
||||
| E04-D01 | 设备缺少维护记录 | — | 设备已部署超过阈值天数且无维护记录 |
|
||||
|
||||
**em_emergency_order(应急工单)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| E05-D01 | 工单编号缺失 | `order_no` | `IS NULL OR = ''` |
|
||||
| E05-D03 | GPS 坐标超出国内范围 | `location_lat`, `location_lng` | 同 E03-D03 |
|
||||
| E05-D04 | 已关闭但无关闭时间 | `status`, `closed_at` | 已关闭但无关闭时间 |
|
||||
|
||||
**em_user_profile(应急人员档案)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| E06-D01 | 证书编号缺失 | `cert_number` | `IS NULL OR = ''` |
|
||||
| E06-D03 | 驻场状态枚举越界 | `station_status` | 不在预定义状态枚举集合内 |
|
||||
|
||||
**em_ambulance(救护车)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| E07-D01 | 车牌号缺失 | `plate_no` | `IS NULL OR = ''` |
|
||||
| E07-D03 | 车辆状态枚举越界 | `status` | 不在预定义状态枚举集合内 |
|
||||
|
||||
**em_emergency_center_call_record(应急中心通话)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| E08-D04 | 结束时间早于开始时间 | `begin_time`, `end_time` | 结束时间早于开始时间 |
|
||||
| E08-D01 | 通话ID缺失 | `call_id` | `IS NULL OR = ''` |
|
||||
|
||||
---
|
||||
|
||||
### 5.4 健康体检
|
||||
|
||||
#### 涉及数据表
|
||||
|
||||
| 表名 | 说明 | 核心校验字段 |
|
||||
|------|------|-------------|
|
||||
| `exam_appointment` | 体检预约 | phone, employee_id, appointment_date, hospital_id, status |
|
||||
| `employee_archive` | 员工档案 | id_card, name, gender, birth_date |
|
||||
| `exam_report` | 体检报告 | report_status, employee_id, exam_date, hospital_id |
|
||||
| `exam_item_result` | 体检项目结果 | result_value, item_code, reference_range, is_abnormal, exam_report_id |
|
||||
| `exam_standard_item` | 体检基本项目 | item_code, item_name, is_key_indicator, has_reference |
|
||||
| `exam_hospital_item` | 医院体检项目 | hospital_id, item_code, linked_standard_item_id |
|
||||
| `exam_hospital` | 医院信息 | hospital_name, address, enable_occupational |
|
||||
| `exam_report_template` | 报告模板 | template_name, version, status |
|
||||
| `exam_plan` | 体检计划 | plan_name, year, date_range, hospital_id, status |
|
||||
| `exam_quota` | 体检名额 | plan_id, unit_id, total_quota, used_quota |
|
||||
|
||||
#### 检测规则
|
||||
|
||||
**exam_appointment(体检预约)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H01-D02 | 手机号格式不合法 | `phone` | 不匹配 11 位手机号正则(如 `"888"` 或非数字字符) |
|
||||
| H01-D01 | 预约员工ID缺失 | `employee_id` | `IS NULL OR = ''` |
|
||||
| H01-D03 | 预约日期为过去年份(录入错误) | `appointment_date` | 年份早于 2020 或晚于当前年份+2 |
|
||||
| H01-D05 | 关联医院不存在 | `hospital_id` | 引用的医院不存在 |
|
||||
|
||||
**employee_archive(员工档案)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H02-D02 | 身份证号格式不合法 | `id_card` | 长度不为 18 位,或含非法字符,或校验位不通过 |
|
||||
| H02-D01 | 姓名缺失 | `name` | `IS NULL OR = ''` |
|
||||
| H02-D03 | 性别枚举越界 | `gender` | `NOT IN (1, 2)` 或 `NOT IN ('男', '女')` |
|
||||
| H02-D03 | 出生日期为未来日期 | `birth_date` | `birth_date > CURRENT_DATE` |
|
||||
|
||||
**exam_report(体检报告)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H03-D03 | 报告状态枚举越界 | `report_status` | 不在预定义报告状态枚举集合内 |
|
||||
| H03-D05 | 关联员工不存在 | `employee_id` | 引用的员工档案不存在 |
|
||||
| H03-D04 | 报告状态为"已生成"但无结果明细 | `report_status` ↔ `exam_item_result` | 报告状态为已生成但无关联的检查结果明细 |
|
||||
|
||||
**exam_item_result(体检项目结果)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H04-D01 | 检查结果值为空 | `result_value` | `IS NULL OR = ''` |
|
||||
| H04-D03 | 结果值为负数(仅适用于不应为负的指标) | `result_value` | `result_value < 0` 且项目类型非偏移量类指标 |
|
||||
| H04-D05 | 关联体检项目不存在 | `item_code` | 引用的标准体检项目不存在 |
|
||||
| H04-D05 | 关联报告不存在 | `exam_report_id` | 引用的体检报告不存在 |
|
||||
| H04-D04 | 异常标记与结果值矛盾 | `is_abnormal`, `result_value`, `reference_range` | 标记为异常但结果值在参考范围内,或标记为正常但结果值明显超出参考范围 |
|
||||
|
||||
**exam_standard_item(体检基本项目)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H05-D01 | 项目编码缺失 | `item_code` | `IS NULL OR = ''` |
|
||||
| H05-D01 | 项目名称缺失 | `item_name` | `IS NULL OR = ''` |
|
||||
| H05-D06 | 项目编码重复 | `item_code` | 存在多条记录使用同一项目编码 |
|
||||
|
||||
**exam_hospital_item(医院体检项目)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H06-D05 | 关联标准项目不存在 | `linked_standard_item_id` | 引用的标准体检项目不存在 |
|
||||
| H06-D05 | 关联医院不存在 | `hospital_id` | 引用的医院不存在 |
|
||||
|
||||
**exam_report_template(报告模板)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H07-D01 | 模板名称缺失 | `template_name` | `IS NULL OR = ''` |
|
||||
| H07-D03 | 模板状态枚举越界 | `status` | `NOT IN (0, 1)`(0=无效, 1=有效) |
|
||||
|
||||
**exam_plan(体检计划)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H08-D04 | 计划结束日期早于开始日期 | `date_range` (start, end) | `end_date < start_date` |
|
||||
| H08-D05 | 关联医院不存在 | `hospital_id` | 引用的医院不存在 |
|
||||
|
||||
**exam_quota(体检名额)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| H09-D03 | 名额总数为负数 | `total_quota` | `< 0` |
|
||||
| H09-D03 | 已用名额大于总数 | `used_quota` | `used_quota > total_quota` |
|
||||
| H09-D05 | 关联计划不存在 | `plan_id` | 引用的体检计划不存在 |
|
||||
|
||||
---
|
||||
|
||||
### 5.5 营养管理
|
||||
|
||||
#### 涉及数据表
|
||||
|
||||
营养管理是系统中表数量最多的模块。以下按业务子域列出核心校验表。
|
||||
|
||||
| 业务子域 | 核心表 | 关键校验字段 |
|
||||
|----------|--------|-------------|
|
||||
| 用户档案 | `nut_user`, `nut_user_profile` | phone, bmi, height, weight, birthday, health_goal, dietary_restrictions |
|
||||
| 食品管理 | `nut_food`, `nut_food_composition`, `nut_food_nutri`, `nut_food_spec` | price, nutrition_info, value_per_100g, weight |
|
||||
| 食谱管理 | `nut_recipe`, `nut_recipe_food` | total_calories, nutrition_summary, food_id, portion |
|
||||
| 订餐管理 | `nut_order`, `nut_order_item` | total_amount, status, order_type, quantity, price, subtotal |
|
||||
| 原材料 | `nut_mater_base`, `nut_raw_inbound` | price, unit, quantity, weight, supplier_id |
|
||||
| 库存 | `nut_sup_inventory`, `nut_sup_inventory_flow` | quantity, qty, current_qty_after |
|
||||
| 生产 | `nut_prod_combo_task`, `nut_prod_qc_sample`, `nut_prod_serve_record` | task_no, plan_date, status, qc_status |
|
||||
| 算法 | `nut_algo_personal`, `nut_algo_mass` | user_id, 营养结果字段 |
|
||||
| 农场 | `nut_farm_plot`, `nut_farm_crop_batch`, `nut_farm_harvest`, `nut_farm_livestock_batch` | area, plant_date, expected_harvest, quantity, count |
|
||||
| 设备 | `nut_meter_reading` | 读数合理性 |
|
||||
|
||||
#### 检测规则
|
||||
|
||||
**nut_user / nut_user_profile(用户档案)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| N01-D01 | 手机号为空 | `phone` | `IS NULL OR = ''` |
|
||||
| N01-D03 | BMI 值越界 | `bmi` | `< 10 OR > 80` |
|
||||
| N01-D03 | 身高越界 | `height` | `< 50 OR > 250` |
|
||||
| N01-D03 | 体重越界 | `weight` | `< 20 OR > 300` |
|
||||
| N01-D04 | 计算年龄为负数 | `birthday` | 生日晚于当前日期 |
|
||||
| N01-D06 | 同一 user_id 存在多条档案记录 | `user_id` | 同一用户存在多条档案记录 |
|
||||
|
||||
**nut_food / nut_food_composition / nut_food_nutri / nut_food_spec(食品管理)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| N02-D03 | 价格为负数 | `price` | `< 0` |
|
||||
| N02-D03 | 每 100g 营养值为负数 | `value_per_100g` | `< 0` |
|
||||
| N02-D01 | 营养信息JSON为空 | `nutrition_info` | `IS NULL OR = '' OR = '{}'` |
|
||||
| N02-D02 | 营养信息JSON解析失败 | `nutrition_info` | JSON 格式不合法,无法解析 |
|
||||
| N02-D03 | 份量重量为负数或零 | `weight` | `<= 0` |
|
||||
|
||||
**nut_recipe / nut_recipe_food(食谱管理)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| N03-D01 | 总热量为空 | `total_calories` | `IS NULL` |
|
||||
| N03-D02 | 营养汇总JSON格式非法 | `nutrition_summary` | JSON 格式不合法,无法解析 |
|
||||
| N03-D05 | 食谱引用的食材ID不存在 | `food_id` | 引用的食品不存在 |
|
||||
|
||||
**nut_order / nut_order_item(订餐管理)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| N04-D03 | 订单金额为负数 | `total_amount` | `< 0` |
|
||||
| N04-D03 | 单次订餐份数超出上限 | `quantity` | `quantity > 系统设定的最大份数` |
|
||||
| N04-D03 | 单价为负数 | `price` | `< 0` |
|
||||
| N04-D04 | 订单金额与明细小计之和不一致 | `total_amount` ↔ `SUM(subtotal)` | 订单金额与明细小计之和不相等 |
|
||||
|
||||
**nut_mater_base / nut_raw_inbound / nut_sup_inventory / nut_sup_inventory_flow(原材料与库存)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| N05-D03 | 入库数量为负数或零 | `quantity` | `<= 0` |
|
||||
| N05-D03 | 入库重量为负数 | `weight` | `< 0` |
|
||||
| N05-D03 | 库存数量为负数 | `quantity` | `< 0` |
|
||||
| N05-D04 | 库存流水余额与当前库存不一致 | `current_qty_after` ↔ `quantity` | 库存流水余额与当前库存数量不相等 |
|
||||
| N05-D05 | 原材料ID在原料库中不存在 | `mater_id` | 引用的原材料不存在 |
|
||||
| N05-D05 | 供应商ID不存在 | `supplier_id` | 引用的供应商不存在 |
|
||||
|
||||
**nut_prod_combo_task / nut_prod_qc_sample / nut_prod_serve_record(健康生产)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| N06-D02 | 生产批次号含非法字符 | `task_no` | 不匹配批次号正则 |
|
||||
| N06-D04 | 生产任务完成但无供餐记录 | `status` ↔ `nut_prod_serve_record` | 生产任务已完成但无关联供餐记录 |
|
||||
| N06-D01 | 质检样品状态为"留样中"超过阈值天数 | `qc_status`, `sample_date` | 留样中状态持续超过阈值天数 |
|
||||
| N06-D03 | 计划日期为未来年份 | `plan_date` | 年份超出合理范围 |
|
||||
|
||||
**nut_algo_personal / nut_algo_mass(算法与AI)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| N07-D06 | 同一用户同日存在多条分析记录 | `user_id` + 日期 | 同一用户同日存在多条分析记录 |
|
||||
| N07-D03 | 营养素计算结果超出合理范围 | 营养结果字段 | 各营养素值 < 0 或超过人体每日上限的 N 倍 |
|
||||
|
||||
**nut_farm_plot / nut_farm_crop_batch / nut_farm_harvest / nut_farm_livestock_batch(农场)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| N08-D03 | 地块面积为负数 | `area` | `< 0` |
|
||||
| N08-D04 | 预计采收日期早于种植日期 | `plant_date`, `expected_harvest` | `expected_harvest < plant_date` |
|
||||
| N08-D03 | 采收数量为负数 | `quantity` | `< 0` |
|
||||
| N08-D03 | 牲畜数量为负数 | `count` | `< 0` |
|
||||
|
||||
---
|
||||
|
||||
### 5.6 健康监测
|
||||
|
||||
#### 涉及数据表
|
||||
|
||||
| 表名 | 说明 | 核心校验字段 |
|
||||
|------|------|-------------|
|
||||
| `mon_device` | 可穿戴设备主表 | device_code, bind_status, bind_user_id, online_status, last_data_time |
|
||||
| `mon_device_config` | 设备监测配置 | threshold_min, threshold_max, upload_frequency |
|
||||
| `mon_bind_record` | 设备绑定/解绑记录 | bind_date, unbind_date |
|
||||
| `mon_daily_stats_heart_rate` | 心率日统计 | hr_max, hr_min, hr_avg, silence_hr_avg |
|
||||
| `mon_daily_stats_spo2` | 血氧日统计 | spo2_max, spo2_min, spo2_avg |
|
||||
| `mon_daily_stats_temperature` | 体温日统计 | temp_max, temp_min, temp_avg |
|
||||
| `mon_daily_stats_blood_pressure` | 血压日统计 | systolic_max, systolic_min, diastolic_max, diastolic_min |
|
||||
| `mon_daily_stats_sleep` | 睡眠日统计 | total_min, deep_min, score |
|
||||
| `mon_data_heart_rate` | 心率原始数据 | data_value |
|
||||
| `mon_data_spo2` | 血氧原始数据 | data_value |
|
||||
| `mon_data_temperature` | 体温原始数据 | data_value |
|
||||
| `mon_data_blood_pressure` | 血压原始数据 | systolic_value, diastolic_value |
|
||||
| `mon_data_gps` | GPS 原始数据 | longitude, latitude |
|
||||
| `mon_data_ecg` | 心电原始数据 | avg_heart_rate, data_points_url |
|
||||
| `mon_survey_answer_record` | 问卷回答记录 | user_id, survey_id, answer_time |
|
||||
| 环境监测各表 | 室内/室外/花粉/水质 | 温度、PM2.5、pH、read_time、meter_code |
|
||||
|
||||
#### 检测规则
|
||||
|
||||
**mon_device(设备主表)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| M01-D01 | 设备编码缺失 | `device_code` | `IS NULL OR = ''` |
|
||||
| M01-D03 | 绑定状态枚举越界 | `bind_status` | 不在预定义枚举集合内 |
|
||||
| M01-D03 | 在线状态枚举越界 | `online_status` | 不在预定义枚举集合内 |
|
||||
| M01-D04 | 设备在线但最后上报时间为未来 | `online_status`, `last_data_time` | 设备在线但最后数据上报时间为未来时间 |
|
||||
|
||||
**mon_device_config(设备配置)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| M02-D03 | 阈值下限大于阈值上限 | `threshold_min`, `threshold_max` | `threshold_min > threshold_max` |
|
||||
| M02-D03 | 上报频率为负数或零 | `upload_frequency` | `<= 0` |
|
||||
|
||||
**mon_bind_record(绑定记录)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| M03-D04 | 解绑日期早于绑定日期 | `bind_date`, `unbind_date` | 解绑日期早于绑定日期 |
|
||||
| M03-D02 | 绑定日期格式非法 | `bind_date` | 无法解析为有效日期 |
|
||||
|
||||
**mon_data_heart_rate / mon_data_spo2 / mon_data_temperature / mon_data_blood_pressure / mon_data_ecg(穿戴原始数据)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| M04-D03 | 心率值越界 | `data_value` | `< 20 OR > 300` (bpm) |
|
||||
| M04-D03 | 血氧值越界 | `data_value` | `< 50 OR > 100` (%) |
|
||||
| M04-D03 | 体温值越界 | `data_value` | `< 30 OR > 45` (℃) |
|
||||
| M04-D03 | 收缩压越界 | `systolic_value` | `< 50 OR > 300` (mmHg) |
|
||||
| M04-D03 | 舒张压越界 | `diastolic_value` | `< 30 OR > 200` (mmHg) |
|
||||
| M04-D04 | 收缩压低于舒张压 | `systolic_value`, `diastolic_value` | `systolic_value < diastolic_value` |
|
||||
| M04-D06 | 同一设备同一时间点重复数据 | `device_id` + `data_time` | 同一设备同一时间点存在多条数据 |
|
||||
| M04-D02 | 心电数据文件URL不可达 | `data_points_url` | URL格式非法或指向不存在资源 |
|
||||
|
||||
**mon_data_gps(GPS 数据)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| M05-D03 | GPS 坐标超出国内范围 | `longitude`, `latitude` | `longitude < 73 OR longitude > 136 OR latitude < 4 OR latitude > 54` |
|
||||
|
||||
**mon_daily_stats_heart_rate / mon_daily_stats_spo2 / mon_daily_stats_temperature / mon_daily_stats_blood_pressure / mon_daily_stats_sleep(日统计聚合数据)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| M06-D04 | 最大心率低于最小心率 | `hr_max`, `hr_min` | `hr_max < hr_min` |
|
||||
| M06-D04 | 最大收缩压低于最小收缩压 | `systolic_max`, `systolic_min` | `systolic_max < systolic_min` |
|
||||
| M06-D04 | 最大舒张压低于最小舒张压 | `diastolic_max`, `diastolic_min` | `diastolic_max < diastolic_min` |
|
||||
| M06-D04 | 静息心率高于平均心率 | `silence_hr_avg`, `hr_avg` | `silence_hr_avg > hr_avg` |
|
||||
| M06-D03 | 睡眠总时长越界 | `total_min` | `< 0 OR > 1440` |
|
||||
| M06-D04 | 深睡时长大于总时长 | `deep_min`, `total_min` | `deep_min > total_min` |
|
||||
|
||||
**mon_survey_answer_record / mon_survey_activity(调查问卷)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| M07-D04 | 回答时间早于活动发布时间 | `answer_time` ↔ `mon_survey_activity.publish_time` | `answer_time < publish_time` |
|
||||
| M07-D06 | 同一用户同一问卷多条回答 | `user_id`, `survey_id` | 同一用户对同一问卷存在多条回答 |
|
||||
|
||||
**mon_env_data_indoor / mon_env_data_outdoor / mon_env_data_pollen / mon_env_data_water(环境监测)**
|
||||
|
||||
| 编码 | 规则描述 | 涉及字段 | 判定逻辑 |
|
||||
|------|----------|----------|----------|
|
||||
| M08-D03 | PM2.5 值为负数 | PM2.5字段 | `< 0` |
|
||||
| M08-D03 | pH 值越界 | `ph` | `< 0 OR > 14` |
|
||||
| M08-D03 | 环境温度超出设备量程 | 温度字段 | 超出传感器标定量程范围 |
|
||||
| M08-D05 | 环境数据关联仪表不存在 | `meter_code` | 引用的环境监测仪表不存在 |
|
||||
|
||||
---
|
||||
|
||||
## 六、附录
|
||||
|
||||
### 6.1 脏数据类型编码速查
|
||||
|
||||
| 编码 | 名称 | 一句话描述 |
|
||||
|------|------|--------------|
|
||||
| D01 | 数据缺失 | 该有的值没有 |
|
||||
| D02 | 格式违规 | 数据值的形态不对 |
|
||||
| D03 | 取值越界 | 值的量级不对 |
|
||||
| D04 | 逻辑冲突 | 多个值互相矛盾 |
|
||||
| D05 | 关联断裂 | 外键指向了不存在的记录 |
|
||||
| D06 | 数据重复 | 本应唯一的记录出现了多条 |
|
||||
|
||||
### 6.2 规则编号说明
|
||||
|
||||
规则编号格式:`{模块前缀}{序号}-{脏数据类型编码}`
|
||||
|
||||
| 模块 | 前缀 |
|
||||
|------|------|
|
||||
| 健康咨询 | C (Consult) |
|
||||
| 应急就医 | E (Emergency) |
|
||||
| 健康体检 | H (Health Checkup) |
|
||||
| 营养管理 | N (Nutrition) |
|
||||
| 健康监测 | M (Monitor) |
|
||||
| 系统管理 | S (System) |
|
||||
|
||||
示例:`C01-D03` = 健康咨询模块第 1 组规则,脏数据类型为 D03(取值越界)。
|
||||
|
||||
### 6.3 各模块规则数量统计
|
||||
|
||||
| 模块 | D01 | D02 | D03 | D04 | D05 | D06 | 合计 |
|
||||
|------|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
|
||||
| 系统管理 | 12 | 2 | 14 | 1 | 5 | 7 | **41** |
|
||||
| 健康咨询 | 3 | 0 | 12 | 5 | 8 | 0 | **28** |
|
||||
| 应急就医 | 5 | 2 | 10 | 4 | 3 | 0 | **24** |
|
||||
| 健康体检 | 6 | 2 | 9 | 5 | 9 | 2 | **33** |
|
||||
| 营养管理 | 4 | 3 | 14 | 5 | 4 | 2 | **32** |
|
||||
| 健康监测 | 1 | 2 | 14 | 9 | 1 | 3 | **30** |
|
||||
| **合计** | **31** | **11** | **73** | **29** | **30** | **14** | **188** |
|
||||
Reference in New Issue
Block a user