# 异常事件数据质量控制规则说明书 > **文档版本**:v1.1 > **编写日期**:2026-07-29 > **适用范围**:系统管理、健康咨询、应急就医、健康评估、营养管理、健康监测(共 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-assessment/` | 原型待开发,后端已部分实现 | | 营养管理 | `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 健康评估 #### 涉及数据表 健康评估模块对员工进行多维度健康评估,涵盖风险评估、心理评估、规律起居评估及人群分类。以下按业务子域列出核心校验表。 | 业务子域 | 核心表 | 关键校验字段 | |----------|--------|-------------| | 风险评估 | `ass_risk_evaluation`, `ass_risk_result`, `ass_risk_questionnaire_info`, `ass_risk_evaluation_statistics`, `ass_risk_diet_sports_prescription` | user_id, eval_source, status, is_exception, bmi, sbp, dbp, fasting_bg, health_age, bmi_mark, smoke_mark, height, weight, waist_line, smoking_status, personal_*, questions_json, statics_num, exception_num, energy_level, f_elements, aerobic_*, strength_*, flexibility_* | | 心理评估 | `ass_psychology`, `ass_psychology_statistics` | type, grade, phy_grade_level, status, is_exception, questions_id | | 规律起居 | `ass_daily_routine_online`, `ass_daily_routine_paper` | sleep_hour, sport_minute, resting_heart_rate, oxygen_saturation, pressure_value, week_start_date, week_end_date, sport_value, sleep_value, time_of_net_value, sport_level, sleep_type, time_of_net_level, is_exception | | 人群分类 | `ass_group_user`, `ass_group_user_detail` | user_group, group_change_type, audit_status, is_archived, archived_time, date_year, latest_assessment_date, detail_type, data_type | | 问卷 | `ass_questions` | questions_json | #### 检测规则 **ass_risk_evaluation(风险评估主表)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A01-D01 | 用户ID缺失 | `user_id` | `IS NULL` | | A01-D03 | 评估来源枚举越界 | `eval_source` | `NOT IN (1, 2)`(1=问卷, 2=自动) | | A01-D04 | 异常标记与评估结果矛盾 | `is_exception` ↔ `ass_risk_result.*_level` | `is_exception = 1` 但关联结果中所有疾病等级均为正常 | **ass_risk_result(风险评估结果)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A02-D03 | BMI 值越界 | `bmi` | `< 10 OR > 80` | | A02-D03 | 收缩压越界 | `sbp` | `< 50 OR > 300` (mmHg) | | A02-D03 | 舒张压越界 | `dbp` | `< 30 OR > 200` (mmHg) | | A02-D03 | 空腹血糖越界 | `fasting_bg` | `< 0 OR > 50` (mmol/L) | | A02-D03 | 健康年龄越界 | `health_age`, `potential_health_age` | `< 0 OR > 150` | | A02-D03 | 疾病等级枚举越界 | `diabetes_level`, `hypertension_level` 等 | 不在预定义枚举集合内 | | A02-D02 | 生活习惯标记格式非法 | `bmi_mark`, `smoke_mark`, `sleep_mark` 等 | 不符合 `state,score,fullmark` 格式 | | A02-D04 | 收缩压低于舒张压 | `sbp`, `dbp` | `sbp < dbp` | | A02-D04 | 血脂数据缺失但疾病等级非空 | `cholesterol`, `triglycerin`, `hdlc`, `ldlc` + `*_level` | 血脂四项均为 0 或 NULL 但存在非空疾病等级 | **ass_risk_questionnaire_info(问卷信息)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A03-D01 | 基础体测数据完全缺失 | `height`, `weight`, `waist_line` | 三者均为 NULL | | A03-D03 | 身高越界 | `height` | `< 50 OR > 250` (cm) | | A03-D03 | 体重越界 | `weight` | `< 20 OR > 300` (kg) | | A03-D03 | 腰围越界 | `waist_line` | `< 30 OR > 200` (cm) | | A03-D03 | 吸烟状态枚举越界 | `smoking_status` | `NOT IN (1, 2, 3)` | | A03-D03 | 个人病史枚举越界 | `personal_diabetes`, `personal_hypertension` 等 `personal_*` 字段 | `NOT IN (0, 1)` | | A03-D02 | 问卷 JSON 格式非法 | `questions_json`(通过 `ass_questions`) | JSON 解析失败 | **ass_risk_evaluation_statistics(评估统计)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A04-D04 | 统计次数与实际评估次数不一致 | `statics_num` ↔ `ass_risk_evaluation` | `statics_num` 不等于该用户实际评估记录数 | | A04-D04 | 疾病异常标记与源数据脱节 | `is_bmi_abnormal`, `is_sbp_abnormal` 等 ↔ `last_evaluation_id` 对应结果 | 统计标记与引用的评估结果数据不一致 | | A04-D04 | 异常计数错误 | `exception_num` | `exception_num` 不等于实际 `is_exception = 1` 的记录数 | **ass_psychology / ass_psychology_statistics(心理评估)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A05-D01 | 评估得分或健康等级缺失 | `grade`, `phy_grade_level` | 任一为 NULL | | A05-D03 | 评估类型枚举越界 | `type` | `NOT IN (1, 2, 3, 4)`(1=综合, 2=压力, 3=焦虑, 4=抑郁) | | A05-D03 | 评估得分超出合理范围 | `grade` | 超出该评估量表的标准分值范围 | | A05-D03 | 健康等级编码越界 | `phy_grade_level` | 不在数据字典预定义编码范围内 | | A05-D04 | 异常标记与得分矛盾 | `is_exception`, `grade` | `is_exception = 1` 但 `grade` 在正常范围内 | | A05-D04 | 统计值与实际评估记录数不一致 | `ass_psychology_statistics` 统计字段 | 统计值不等于 `ass_psychology` 中实际记录数 | | A05-D05 | 关联问卷不存在 | `questions_id` | 引用的问卷在 `ass_questions` 中不存在 | **ass_daily_routine_online(在线穿戴起居评估)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A06-D01 | 异常标记缺失 | `is_exception` | `IS NULL` | | A06-D03 | 睡眠时长越界 | `sleep_hour` | `< 0 OR > 1440`(分钟) | | A06-D03 | 运动时长越界 | `sport_minute` | `< 0 OR > 1440`(分钟) | | A06-D03 | 静息心率越界 | `resting_heart_rate` | `< 20 OR > 300` (bpm) | | A06-D03 | 血氧饱和度越界 | `oxygen_saturation` | `< 50 OR > 100` (%) | | A06-D03 | 压力值超出量程 | `pressure_value` | 超出传感器标定量程范围 | | A06-D04 | 周结束日期早于开始日期 | `week_start_date`, `week_end_date` | `week_end_date < week_start_date` | | A06-D04 | 睡眠+运动超过 24 小时 | `sleep_hour`, `sport_minute` | `sleep_hour + sport_minute > 1440` | **ass_daily_routine_paper(问卷起居评估)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A07-D01 | 异常标记缺失 | `is_exception` | `IS NULL` | | A07-D03 | 运动/睡眠/上网时长为负数 | `sport_value`, `sleep_value`, `time_of_net_value` | 任一 < 0 | | A07-D03 | 上网时长超出合理范围 | `time_of_net_value` | `> 24`(小时) | | A07-D03 | 运动/睡眠/上网等级枚举越界 | `sport_level`, `sleep_type`, `time_of_net_level` | 不在预定义枚举集合内 | | A07-D05 | 关联问卷不存在 | `questions_id` | 引用的问卷在 `ass_questions` 中不存在 | **ass_group_user / ass_group_user_detail(人群分类)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A08-D03 | 人群分类枚举越界 | `user_group` | `NOT IN ('A', 'B', 'C', 'D', 'E')` | | A08-D03 | 变更类型枚举越界 | `group_change_type` | `NOT IN (1, 2, 3)` | | A08-D03 | 审核状态枚举越界 | `audit_status` | `NOT IN (0, 1, 2)` | | A08-D03 | 归属年份越界 | `date_year` | 早于 2020 或为未来年份 | | A08-D03 | 最近评估日期为未来日期 | `latest_assessment_date` | `latest_assessment_date > CURRENT_DATE` | | A08-D03 | 明细类型枚举越界 | `detail_type` | `NOT IN ('A', 'B', 'C', 'D')` | | A08-D03 | 数据类型枚举越界 | `data_type` | `NOT IN (1, 2)` | | A08-D04 | 已归档但无归档时间 | `is_archived`, `archived_time` | `is_archived = 1` 且 `archived_time IS NULL` | | A08-D05 | 关联人群分类主表记录不存在 | `group_user_id` | 引用的 `ass_group_user` 记录不存在 | | A08-D06 | 同一用户同一年度多条活跃分类记录 | `user_id`, `date_year` | `COUNT(*) > 1 GROUP BY user_id, date_year`(排除已归档记录) | **ass_questions(问卷答案)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A09-D02 | 问卷 JSON 格式非法 | `questions_json` | JSON 解析失败 | **ass_risk_diet_sports_prescription(饮食运动处方)** | 编码 | 规则描述 | 涉及字段 | 判定逻辑 | |------|----------|----------|----------| | A10-D01 | 评估正常但运动处方字段全为空 | `aerobic_*`, `strength_*`, `flexibility_*` | 关联评估为正常但所有运动字段均为 NULL | | A10-D02 | 食物元素格式非法 | `f_elements` | 不符合 `meal_foodCode_amount;...` 格式 | | A10-D03 | 能量等级越界 | `energy_level` | `< 0 OR > 10000` (kcal) | --- ### 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) | | 健康评估 | A (Assessment) | | 营养管理 | 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 | 4 | 31 | 11 | 3 | 1 | **56** | | 营养管理 | 4 | 3 | 14 | 5 | 4 | 2 | **32** | | 健康监测 | 1 | 2 | 14 | 9 | 1 | 3 | **30** | | **合计** | **31** | **13** | **95** | **35** | **24** | **13** | **211** |