# 元数据审核流 API 使用说明(疑似冗余 / 元数据变动) 本文档面向前端开发人员,用于开发“元数据疑似冗余/变动”审核工作台页面。 ## 基本信息 - **蓝图前缀**:后端注册为 `app.register_blueprint(meta_bp, url_prefix='/api/meta')`,因此以下接口完整路径均以 `/api/meta` 开头。 - **返回格式**:统一为 ```json { "code": 200, "message": "操作成功", "data": {} } ``` 失败时: ```json { "code": 500, "message": "错误原因", "data": null } ``` ## 业务概念 ### 记录类型 `record_type` - `redundancy`:疑似冗余(解析出的新元数据与现有元数据“存在候选但不完全一致”)。 - `change`:疑似变动(某业务领域当前已关联的元数据,与新解析结果不一致;或新解析中缺失了旧关联字段)。 ### 状态 `status` - `pending`:待处理 - `resolved`:已处理 - `ignored`:已忽略 ### 处理动作 `action` `POST /api/meta/review/resolve` 的 `action` 取值: - `alias`:将“新解析元数据”指定为某个候选元数据的别名(建立业务领域到候选元数据的关联,并在关系上记录别名信息)。 - `create_new`:将“新解析元数据”确认为全新元数据(要求传入区分后的中文名)。 - `accept_change`:接受变动,将新快照写回目标元数据,并写入版本历史。 - `reject_change`:拒绝变动,仅标记记录已处理。 - `ignore`:忽略该记录,仅标记 ignored。 ## 数据结构说明 ### MetadataReviewRecord(审核记录) 字段说明(前端通常只关心以下字段): - `id`:审核记录ID(PG) - `record_type`:`redundancy` / `change` - `business_domain_id`:触发该记录的业务领域 Neo4j ID(用于回到业务领域详情页) - `new_meta`:新解析元数据快照(示例:`{name_zh,name_en,data_type,tag_ids}`) - `candidates`:候选列表(redundancy 场景使用;每项包含 `candidate_meta_id`、候选快照、差异字段) - `old_meta`:旧快照(change 场景使用;包含 `meta_id` 与旧快照/差异字段) - `status`:`pending/resolved/ignored` - `resolution_action` / `resolution_payload`:处理动作与处理参数 - `impact_graph`:仅在 detail 接口里返回(change 场景,若能定位到 `meta_id`) ### impact_graph(影响关系图谱) `GET /api/meta/review/detail` 在变动记录场景可能返回: ```json { "nodes": [{ "id": 1, "name_zh": "...", "name_en": "...", "...": "..." }], "relationships": [{ "id": 10, "source": 1, "target": 2, "type": "REL" }] } ``` 该结构与现有元数据影响图谱返回一致,可直接复用前端图谱组件。 ## 接口 1:审核记录列表 ### URL - `POST /api/meta/review/list` ### 请求体(JSON) | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | current | int | 否 | 页码,默认 1 | | size | int | 否 | 每页数量,默认 10 | | record_type | string | 否 | `redundancy` 或 `change` | | status | string | 否 | `pending` / `resolved` / `ignored` | | business_domain_id | int | 否 | 业务领域 Neo4j ID | | keyword | string | 否 | 关键字,匹配 `new_meta.name_zh` 或 `new_meta.name_en`(contains) | 示例: ```json { "current": 1, "size": 10, "status": "pending", "record_type": "redundancy", "keyword": "科室" } ``` ### 响应 data ```json { "records": [ { "...": "MetadataReviewRecord.to_dict()" } ], "total": 100, "size": 10, "current": 1 } ``` ### 前端建议 - 页面可默认筛选 `status=pending`。 - 列表展示建议字段:`id / record_type / new_meta.name_zh / new_meta.name_en / business_domain_id / created_at / status`。 ## 接口 2:审核记录详情(含变动影响图谱) ### URL - `GET /api/meta/review/detail?id={id}` ### 响应 data 返回审核记录完整字段(`to_dict()`)并追加 `impact_graph`: - `record_type=change` 且能定位 `old_meta.meta_id` 时,返回 `impact_graph`;否则为 `null`。 示例: ```json { "code": 200, "message": "操作成功", "data": { "id": 12, "record_type": "change", "business_domain_id": 345, "new_meta": { "name_zh": "HIS科室名称", "name_en": "HISKSMC", "data_type": "varchar(50)", "tag_ids": [1, 2] }, "old_meta": { "meta_id": 789, "snapshot": { "id": 789, "name_zh": "HIS科室名称", "name_en": "HISKSMC", "data_type": "varchar(20)", "tag_ids": [1, 2] }, "diff_fields": ["data_type"] }, "impact_graph": { "nodes": [], "relationships": [] }, "status": "pending", "created_at": "2025-12-15T12:00:00.000000", "updated_at": "2025-12-15T12:00:00.000000" } } ``` ### 前端建议 - 详情页按 `record_type` 切换布局: - `redundancy`:展示 `candidates` 列表,给出“设为别名 / 作为新元数据”操作 - `change`:展示 `old_meta` vs `new_meta` 差异字段,并展示 `impact_graph` 风险评估 ## 接口 3:处理审核记录 ### URL - `POST /api/meta/review/resolve` ### 请求体(JSON) | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | id | int | 是 | 审核记录ID | | action | string | 是 | `alias/create_new/accept_change/reject_change/ignore` | | payload | object | 否 | 动作参数(见下) | | resolved_by | string | 否 | 处理人标识(建议前端传登录用户名/工号) | | notes | string | 否 | 处理备注 | 注意:后端会拒绝重复处理(当 `status != pending` 时返回失败)。 ### action=alias(设为某候选元数据别名) 用途:处理 `record_type=redundancy` 的记录。 payload: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | candidate_meta_id | int | 是 | 选定的候选元数据 Neo4j ID | 示例: ```json { "id": 1001, "action": "alias", "payload": { "candidate_meta_id": 789 }, "resolved_by": "alice", "notes": "确认与既有字段一致,设为别名" } ``` 后端行为: - 为 `business_domain_id` 建立 `(:BusinessDomain)-[:INCLUDES]->(:DataMeta)` 到 `candidate_meta_id` - 在关系上写入 `alias_name_zh/alias_name_en`(取自该记录的 `new_meta`) - 将审核记录标记为 `resolved` ### action=create_new(确认作为新元数据) 用途:处理 `record_type=redundancy` 的记录。 payload: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | new_name_zh | string | 是 | 新元数据中文名(要求与现有区分) | 示例: ```json { "id": 1002, "action": "create_new", "payload": { "new_name_zh": "HIS科室名称(新)" }, "resolved_by": "alice" } ``` 后端行为: - 在 Neo4j 创建新的 `DataMeta` 节点并关联业务领域 - 将审核记录标记为 `resolved` ### action=accept_change(接受变动) 用途:处理 `record_type=change` 的记录。 payload(可选): | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | meta_id | int | 否 | 目标元数据 Neo4j ID;不传时使用 `old_meta.meta_id` | 示例: ```json { "id": 2001, "action": "accept_change", "payload": { "meta_id": 789 }, "resolved_by": "bob", "notes": "来源字段长度已调整,接受变动" } ``` 后端行为: - 将 `new_meta` 写回目标 `DataMeta`(更新 name_zh/name_en/data_type,并尝试按 tag_ids 同步标签) - 在 PG 写入一条 `metadata_version_history`(before/after 快照) - 将审核记录标记为 `resolved` ### action=reject_change(拒绝变动) 用途:处理 `record_type=change` 的记录,不更新 Neo4j。 示例: ```json { "id": 2002, "action": "reject_change", "resolved_by": "bob", "notes": "变动不合规,先不更新" } ``` ### action=ignore(忽略) 用途:任何类型记录都可忽略。 示例: ```json { "id": 3001, "action": "ignore", "resolved_by": "bob" } ``` ## 前端页面交互建议(落地) 建议实现 2 个页面: 1. **审核列表页** - 筛选项:`status`(默认 pending)、`record_type`、`keyword`、`business_domain_id` - 行操作:进入详情页 2. **审核详情页** - `redundancy`:展示候选列表 `candidates[]`,提供: - “设为别名”按钮(调用 resolve alias,传 candidate_meta_id) - “确认新元数据”按钮(弹窗输入 new_name_zh,调用 resolve create_new) - `change`:展示 old/new 对比(diff_fields),展示 `impact_graph` 图谱,提供: - “接受变动”(resolve accept_change) - “拒绝变动”(resolve reject_change) - “忽略”(resolve ignore) ## 注意事项 - 列表接口的 `keyword` 是对 `new_meta.name_zh/name_en` 做 contains 匹配(JSONB 文本提取),适合“快速检索”;如需更复杂搜索建议前端做组合筛选。 - `resolve` 接口只允许处理 `status=pending` 的记录;已处理记录会返回失败。 - `accept_change` 会更新 Neo4j 的 `DataMeta` 属性并写版本历史(PG);如果 `new_meta.tag_ids` 为空,则不会调整标签关系。