-- ===================================================================================== -- 1.0.527 · S8 Stage-1「订单评审」ActualHours 数据链(Action Event → MDP → KPI) -- -- ── 背景 ──────────────────────────────────────────────────────────────────────────── -- S8 Stage-1 的「订单评审实际耗时」此前无任何真实数据来源: -- · mdp_std_so 只投影评审【状态】(progress/flow_state/review_status),零评审【时间】列; -- · crm_seorderentry.update_time 被 6 类无关业务共享覆盖(评审/确认/重排/工单调整/订单编辑), -- 判定为 LEVEL C,不可作 KPI Authority; -- · 系统无 progress 状态迁移历史表。 -- 唯一 LEVEL A 事件时间是 aidop_action_run_log,但它完全未进入数据中台 -- (mdp_entity 注册 0 / mdp_stg_* 引用 0 / ETL 代码引用 0)。 -- -- ── 本批建立的链路 ────────────────────────────────────────────────────────────────── -- aidop_action_run_log → mdp_stg_action_run → mdp_std_action_event → dwd_order_review_kpi → S8 -- 与中台既有唯一的「源侧事件流水」先例 mdp_stg_inv_trans → mdp_std_inv_trans 同构。 -- -- ── 关键约束 ──────────────────────────────────────────────────────────────────────── -- ① tenant_id 是唯一隔离边界,三张表的唯一键首列均为 tenant_id。 -- ② 源行【不是内容级 append-only】:FinishAsync/UpdateProgressAsync/FailStaleRunningAsync -- 会原地 UPDATE 既有行(RUNNING → SUCCESS/FAILED)。因此同步必须幂等 upsert, -- 且必须有 RUNNING 回捞补偿(源表无 update_time 列,create_time ≡ start_time 且不随更新推进)。 -- ③ 源 id 是雪花(YitIdHelper)不是自增 —— 全局唯一但非严格单调,只作 tiebreaker / 唯一键。 -- ④ STD 是审计事实层:SUCCESS / FAILED / RUNNING 全部保留,KPI 层再过滤。 -- -- ── 本批不做 ──────────────────────────────────────────────────────────────────────── -- TargetHours / S0 PI 匹配 / order_type 映射 / factory 推导 / 红黄绿 / Stage 2~5 / 子节点。 -- 不改 mdp_std_so,不改任何源业务表。 -- ===================================================================================== -- --------------------------------------------------------------------------- -- ① L1 贴源层:mdp_stg_action_run -- 一行 = 源 aidop_action_run_log 某 action_run_id 的【最新快照】 -- 列集必须满足 MdpStagingWriter 的 canonical 契约(见 MdpStagingWriter.cs:15-19) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS `mdp_stg_action_run` ( `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '代理主键', `tenant_id` BIGINT NOT NULL COMMENT '租户ID(唯一隔离边界,uk 首列)', `source_system` VARCHAR(50) NOT NULL COMMENT '源系统编码,固定 AIDOPDEV_MYSQL', `source_table` VARCHAR(100) NOT NULL COMMENT '源表名,固定 aidop_action_run_log', `source_row_id` VARCHAR(100) NOT NULL COMMENT '源行主键 = aidop_action_run_log.id', `source_biz_key` VARCHAR(200) NOT NULL COMMENT '业务键 = 源 id(biz_key_expr=id)', `raw_data` JSON NOT NULL COMMENT '源行原文 JSON', `sync_batch_id` VARCHAR(100) NOT NULL COMMENT '同步批次号', `sync_time` DATETIME NOT NULL COMMENT '本次同步时刻', `process_status` VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/DONE', `process_message` VARCHAR(500) NULL COMMENT '处理信息', `create_time` DATETIME NULL COMMENT '首次落库时刻', `update_time` DATETIME NULL COMMENT '最近一次 upsert 时刻', PRIMARY KEY (`id`), UNIQUE KEY `uk_stg_action_run` (`tenant_id`, `source_table`, `source_biz_key`), KEY `idx_stg_action_run_rowid` (`tenant_id`, `source_row_id`), KEY `idx_stg_action_run_batch` (`tenant_id`, `sync_batch_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MDP贴源-业务动作运行日志'; -- --------------------------------------------------------------------------- -- ② L2 标准事件层:mdp_std_action_event -- Grain = tenant_id + action_run_id -- 审计事实层:FAILED / RUNNING / SUCCESS 全保留,不因 KPI 只需 SUCCESS 而丢弃 -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS `mdp_std_action_event` ( `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '代理主键', `tenant_id` BIGINT NOT NULL COMMENT '租户ID(唯一隔离边界,uk 首列)', `action_run_id` BIGINT NOT NULL COMMENT '动作运行ID = 源 aidop_action_run_log.id(雪花)', `action_code` VARCHAR(80) NOT NULL COMMENT '动作编码,如 S1_ORDER_REVIEW', `biz_type` VARCHAR(80) NOT NULL COMMENT '业务类型,如 crm_seorder', `biz_id` BIGINT NULL COMMENT '业务主键(订单头 crm_seorder.Id)', `biz_no` VARCHAR(128) NULL COMMENT '业务单号(仅展示/交叉校验,不作归因权威)', `action_status` VARCHAR(20) NOT NULL COMMENT 'RUNNING / SUCCESS / FAILED', `action_start_time` DATETIME NOT NULL COMMENT '动作开始执行时刻', `action_end_time` DATETIME NULL COMMENT '动作完成时刻(RUNNING 时为 NULL)', `message` VARCHAR(1000) NULL COMMENT '动作消息', `detail_json` JSON NULL COMMENT '动作明细快照', `source_system` VARCHAR(50) NOT NULL COMMENT '源系统编码', `source_table` VARCHAR(100) NOT NULL COMMENT '源表名', `source_biz_key` VARCHAR(200) NOT NULL COMMENT '贴源业务键', `sync_batch_id` VARCHAR(100) NULL COMMENT '最近一次物化批次号', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '首次物化时刻', `update_time` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '最近一次物化时刻', PRIMARY KEY (`id`), UNIQUE KEY `uk_std_action_event` (`tenant_id`, `action_run_id`), KEY `idx_std_action_event_biz` (`tenant_id`, `biz_type`, `biz_id`, `action_code`, `action_status`), KEY `idx_std_action_event_start` (`tenant_id`, `action_code`, `action_start_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MDP标准层-业务动作事件(审计事实,全状态保留)'; -- --------------------------------------------------------------------------- -- ③ L3 KPI 事实层:dwd_order_review_kpi -- Grain = tenant_id + sales_order_id(一张销售订单一条当前有效 KPI) -- 本批不含 target_hours / kpi_status / factory_ref_id / order_type -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS `dwd_order_review_kpi` ( `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '代理主键', `tenant_id` BIGINT NOT NULL COMMENT '租户ID(唯一隔离边界,uk 首列)', `sales_order_id` BIGINT NOT NULL COMMENT '销售订单头ID = crm_seorder.Id(归因权威)', `sales_order_no` VARCHAR(128) NULL COMMENT '销售订单号(展示用,来自 biz_no)', `review_action_run_id` BIGINT NULL COMMENT '被采纳的评审事件ID', `confirm_action_run_id` BIGINT NULL COMMENT '被采纳的交期确认事件ID', `review_start_time` DATETIME NULL COMMENT '评审开始时刻 = FIRST SUCCESS 的 action_start_time', `review_end_time` DATETIME NULL COMMENT '评审结束时刻 = 首个晚于开始的确认 SUCCESS 的 action_end_time', `actual_hours` DECIMAL(12,2) NULL COMMENT '实际耗时(自然 elapsed 小时,2 位小数)', `calculation_status` VARCHAR(32) NOT NULL COMMENT 'OK/NO_START/IN_PROGRESS/INVALID/INVALID_TIME_SEQUENCE', `review_success_count` INT NOT NULL DEFAULT 0 COMMENT '评审 SUCCESS 次数(可观测性,不参与计算)', `confirm_success_count` INT NOT NULL DEFAULT 0 COMMENT '确认 SUCCESS 次数(可观测性,不参与计算)', `review_failed_count` INT NOT NULL DEFAULT 0 COMMENT '评审 FAILED 次数(可观测性,不参与计算)', `confirm_failed_count` INT NOT NULL DEFAULT 0 COMMENT '确认 FAILED 次数(可观测性,不参与计算)', `calc_batch_id` VARCHAR(100) NULL COMMENT '最近一次重算批次号', `calc_time` DATETIME NULL COMMENT '最近一次重算时刻', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '首次落库时刻', `update_time` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '最近一次更新时刻', PRIMARY KEY (`id`), UNIQUE KEY `uk_dwd_order_review_kpi` (`tenant_id`, `sales_order_id`), KEY `idx_dwd_order_review_kpi_status` (`tenant_id`, `calculation_status`), KEY `idx_dwd_order_review_kpi_no` (`tenant_id`, `sales_order_no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DWD-订单评审KPI(本批仅 ActualHours,无 TargetHours)'; -- --------------------------------------------------------------------------- -- ④ MDP 实体注册:S1_ACTION_RUN_LOG -- source_id = 1 (AIDOPDEV_MYSQL,本库);sync_mode=INCR;主游标 start_time + id tiebreaker -- 幂等:按 entity_code 判存在 -- 注意:incr_column 仅为主游标;RUNNING 终态回捞由 ActionEventMdpSyncService 补偿, -- 原因是源表无 update_time、create_time ≡ start_time 且不随 UPDATE 推进。 -- --------------------------------------------------------------------------- INSERT INTO `mdp_entity` (`tenant_id`, `source_id`, `entity_code`, `entity_name`, `entity_type`, `source_table_name`, `target_table_name`, `sync_mode`, `incr_column`, `batch_size`, `biz_key_expr`, `status`, `remark`, `create_time`, `update_time`) SELECT 0, 1, 'S1_ACTION_RUN_LOG', 'S1业务动作运行日志', 'TABLE', 'aidop_action_run_log', 'mdp_stg_action_run', 'INCR', 'start_time', 2000, 'id', 1, 'S8 Stage-1 订单评审 ActualHours 的唯一时间 Authority;RUNNING 终态由补偿查询回捞', NOW(), NOW() WHERE NOT EXISTS ( SELECT 1 FROM (SELECT `entity_code` FROM `mdp_entity`) t WHERE t.`entity_code` = 'S1_ACTION_RUN_LOG' ); -- --------------------------------------------------------------------------- -- ⑤ 菜单:S8 异常监控 → 订单评审耗时 -- 注意:Admin.NET 框架表 EnableUnderLine=false → 表名/列名 PascalCase(SysMenu,非 sys_menu)。 -- 与 SysMenuSeedData.cs 的 s8MonitoringDirId + 7 = 1329008000027 同号(既有库不跑 Seed,故此处补)。 -- 幂等:按 Id 判存在。 -- --------------------------------------------------------------------------- INSERT INTO `SysMenu` (`Id`, `Pid`, `Type`, `Name`, `Path`, `Component`, `Title`, `Icon`, `IsIframe`, `OutLink`, `IsHide`, `IsKeepAlive`, `IsAffix`, `OrderNo`, `Status`, `Remark`, `CreateTime`) SELECT 1329008000027, 1329008000020, 2, 'aidopS8OrderReviewActualHours', '/aidop/s8/monitoring/order-review-hours', '/aidop/s8/monitoring/OrderReviewActualHoursPage', '订单评审耗时', 'ele-Timer', 0, 0, 0, 1, 0, 16, 1, 'S8 Stage-1 订单评审实际耗时(数据中台 dwd_order_review_kpi,无 seed 回落)', NOW() WHERE NOT EXISTS ( SELECT 1 FROM (SELECT `Id` FROM `SysMenu`) t WHERE t.`Id` = 1329008000027 );