From e4b62d6406d5535dcfdf3dbf6c661d38e87d9376 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Fri, 13 Nov 2026 11:12:07 +0800 Subject: [PATCH] =?UTF-8?q?chore(sql):=20=E5=A2=9E=E5=8A=A0=20UC=20?= =?UTF-8?q?=E5=85=A5=E5=BA=93=E7=BC=96=E7=A0=81=E7=94=9F=E4=BA=A7=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E4=B8=80=E6=AC=A1=E6=80=A7=E5=9B=9E=E8=A1=A5=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与种子 SQL 分开,按空任务入库工单补派五步任务;并在种子/Python 回补说明中交叉引用。 Co-authored-by: Cursor --- .../backfill_uc_msc_production_tasks.py | 3 + .../2026-11-13-uc-msc-builtin-task-set.sql | 8 +- ...-11-13-uc-msc-production-task-backfill.sql | 409 ++++++++++++++++++ 3 files changed, 417 insertions(+), 3 deletions(-) create mode 100644 docs/sql/migrations/2026-11-13-uc-msc-production-task-backfill.sql diff --git a/backend/scripts/backfill_uc_msc_production_tasks.py b/backend/scripts/backfill_uc_msc_production_tasks.py index 4d64b51c..c59c5305 100644 --- a/backend/scripts/backfill_uc_msc_production_tasks.py +++ b/backend/scripts/backfill_uc_msc_production_tasks.py @@ -7,6 +7,9 @@ python -m scripts.backfill_uc_msc_production_tasks python -m scripts.backfill_uc_msc_production_tasks --apply python -m scripts.backfill_uc_msc_production_tasks --tenant zkxw --apply + +等价一次性 SQL(与种子脚本分开): + docs/sql/migrations/2026-11-13-uc-msc-production-task-backfill.sql """ from __future__ import annotations diff --git a/docs/sql/migrations/2026-11-13-uc-msc-builtin-task-set.sql b/docs/sql/migrations/2026-11-13-uc-msc-builtin-task-set.sql index 83322fe7..3d210435 100644 --- a/docs/sql/migrations/2026-11-13-uc-msc-builtin-task-set.sql +++ b/docs/sql/migrations/2026-11-13-uc-msc-builtin-task-set.sql @@ -1,9 +1,11 @@ -- UC 入库编码自动派发:脐带MSC原代培养(内置模版)5 步 -- 步骤:原代培养 → 半换液 → 二次贴壁 → 重铺 → 冻存(不含传代) -- 内容从既有「干细胞培养(内置模版)」/ MSC培养-BUILTIN 按 process_code 拷贝 --- 幂等:已存在同名内置集合则跳过主数据创建-- 生产历史空任务工单请用: --- cd backend && python -m scripts.backfill_uc_msc_production_tasks --dry-run --- cd backend && python -m scripts.backfill_uc_msc_production_tasks --apply +-- 幂等:已存在同名内置集合则跳过主数据创建-- 生产历史空任务工单回补(二选一,勿重复对同一工单各跑一遍): +-- SQL:docs/sql/migrations/2026-11-13-uc-msc-production-task-backfill.sql +-- 或 Python: +-- cd backend && python -m scripts.backfill_uc_msc_production_tasks +-- cd backend && python -m scripts.backfill_uc_msc_production_tasks --apply SET NAMES utf8mb4; diff --git a/docs/sql/migrations/2026-11-13-uc-msc-production-task-backfill.sql b/docs/sql/migrations/2026-11-13-uc-msc-production-task-backfill.sql new file mode 100644 index 00000000..95211781 --- /dev/null +++ b/docs/sql/migrations/2026-11-13-uc-msc-production-task-backfill.sql @@ -0,0 +1,409 @@ +-- 【一次性回补】UC 开头实验室入库编码 → 补派「脐带MSC原代培养」5 步生产任务 +-- 与种子脚本分开:先执行 2026-11-13-uc-msc-builtin-task-set.sql(或确保模版已存在),再执行本文件。 +-- 等价于 backend/scripts/backfill_uc_msc_production_tasks.py --apply 的候选范围。 +-- +-- 候选条件(须全部满足): +-- 1) 样本接收 accept_conclusion=js、del_flag=0 +-- 2) lab_storage_code 以 UC/uc 开头(非空) +-- 3) 关联入库生产工单 work_order_type=inbound、状态 dpz/jxz、del_flag=0 +-- 4) 该工单当前无任何有效生产任务(已有任务如 UC2026010 跳过) +-- +-- 动作: +-- - 每工单插入 1 条 biz_production_task(状态 dpz,任务名 {入库编码}样本处理) +-- - 从 UC 内置路线复制 5 个步骤到 biz_production_task_step(及试剂/耗材/产出/采集子表) +-- - 工单状态 dpz → jxz(已是 jxz/ywc 的不改 ywc;本脚本候选不含 ywc) +-- +-- 幂等:已有有效任务的工单不会进入候选;重复执行影响行数应为 0。 +-- 前置:biz_process_route.route_code='MSC原代-UC-BUILTIN'(或固定 id UCMSCROUTE…)及 5 步须已存在。 +-- MySQL 5.7 / utf8mb4。未在生产库执行;执行前请先跑下方「预览」SELECT。 + +SET NAMES utf8mb4; + +-- --------------------------------------------------------------------------- +-- 0. 解析 UC 内置工艺路线 +-- --------------------------------------------------------------------------- +SET @uc_route_id := ( + SELECT r.id + FROM biz_process_route r + WHERE r.del_flag = 0 + AND ( + r.id = 'UCMSCROUTEA5CC11F194118AC54085447A' + OR r.route_code = 'MSC原代-UC-BUILTIN' + OR (r.route_name = '脐带MSC原代培养(内置模版)' AND r.is_builtin = '1') + ) + ORDER BY + CASE + WHEN r.id = 'UCMSCROUTEA5CC11F194118AC54085447A' THEN 0 + WHEN r.route_code = 'MSC原代-UC-BUILTIN' THEN 1 + ELSE 2 + END + LIMIT 1 +); + +SET @uc_step_count := ( + SELECT COUNT(*) + FROM biz_process_route_step s + WHERE s.route_id = @uc_route_id + AND s.del_flag = 0 +); + +-- 预览:模版是否就绪(应 route 非空且 step_count=5) +SELECT @uc_route_id AS uc_route_id, @uc_step_count AS uc_step_count; + +-- 若模版未就绪则主动失败(避免插入无步骤任务) +SET @uc_ready := IF(@uc_route_id IS NOT NULL AND @uc_step_count = 5, 1, 0); +-- 下面用 @uc_ready 约束所有写操作;为 0 时 INSERT 选不出行 + +-- --------------------------------------------------------------------------- +-- 1. 候选工单临时表 +-- --------------------------------------------------------------------------- +DROP TEMPORARY TABLE IF EXISTS tmp_uc_wo_backfill; +CREATE TEMPORARY TABLE tmp_uc_wo_backfill ( + seq INT NOT NULL AUTO_INCREMENT, + work_order_id VARCHAR(64) NOT NULL, + reception_id VARCHAR(64) NOT NULL, + lab_storage_code VARCHAR(32) NOT NULL, + tenant_no VARCHAR(64) NOT NULL, + sample_code VARCHAR(32) NULL, + task_id VARCHAR(64) NULL, + task_no VARCHAR(32) NULL, + route_id VARCHAR(64) NULL, + PRIMARY KEY (seq), + UNIQUE KEY uk_wo (work_order_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT INTO tmp_uc_wo_backfill ( + work_order_id, reception_id, lab_storage_code, tenant_no, sample_code, route_id +) +SELECT + wo.id, + rec.id, + TRIM(rec.lab_storage_code), + wo.tenant_no, + wo.sample_code, + @uc_route_id +FROM biz_production_work_order wo +INNER JOIN biz_sample_reception rec + ON rec.id = wo.reception_id + AND rec.tenant_no = wo.tenant_no + AND rec.del_flag = 0 +WHERE @uc_ready = 1 + AND wo.del_flag = 0 + AND wo.work_order_type = 'inbound' + AND wo.work_order_status IN ('dpz', 'jxz') + AND rec.accept_conclusion = 'js' + AND rec.lab_storage_code IS NOT NULL + AND TRIM(rec.lab_storage_code) <> '' + AND ( + rec.lab_storage_code LIKE 'UC%' + OR rec.lab_storage_code LIKE 'uc%' + ) + AND NOT EXISTS ( + SELECT 1 + FROM biz_production_task t + WHERE t.work_order_id = wo.id + AND t.tenant_no = wo.tenant_no + AND t.del_flag = 0 + ) +ORDER BY rec.reception_time ASC, wo.create_time ASC; + +-- 预览候选(执行写库前请核对) +SELECT + seq, + work_order_id, + lab_storage_code, + sample_code, + tenant_no, + reception_id +FROM tmp_uc_wo_backfill +ORDER BY seq; + +SELECT COUNT(*) AS candidate_count FROM tmp_uc_wo_backfill; + +-- 分配 task_id / task_no(RW + yyyymmdd + 4 位序号,接当日已有最大序号) +SET @task_day := DATE_FORMAT(NOW(), '%Y%m%d'); +SET @task_no_base := ( + SELECT IFNULL(MAX(CAST(SUBSTRING(t.task_no, 11) AS UNSIGNED)), 0) + FROM biz_production_task t + WHERE t.task_no LIKE CONCAT('RW', @task_day, '%') +); + +UPDATE tmp_uc_wo_backfill +SET + task_id = UPPER(REPLACE(UUID(), '-', '')), + task_no = CONCAT('RW', @task_day, LPAD(@task_no_base + seq, 4, '0')); + +-- --------------------------------------------------------------------------- +-- 2. 插入生产任务 +-- --------------------------------------------------------------------------- +INSERT INTO biz_production_task ( + id, task_no, work_order_id, order_source, task_type, task_name, description, + route_id, task_status, current_assignee_user_id, started_time, completed_time, + conclusion, remark, attachments, equipment_ids, equipment_name, + tenant_no, order_num, create_by, create_dept_id, create_time, update_by, update_time, del_flag +) +SELECT + c.task_id, + c.task_no, + c.work_order_id, + 'inbound', + 'cell_storage', + CONCAT(c.lab_storage_code, '样本处理'), + '脐带MSC原代培养(内置模版)', + c.route_id, + 'dpz', + NULL, + NULL, + NULL, + NULL, + '一次性SQL回补:UC入库编码自动派发', + NULL, + r.equipment_ids, + r.equipment_name, + c.tenant_no, + 0, + NULL, + '', + NOW(), + NULL, + NOW(), + 0 +FROM tmp_uc_wo_backfill c +INNER JOIN biz_process_route r + ON r.id = c.route_id + AND r.del_flag = 0 +WHERE @uc_ready = 1 + AND c.task_id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 FROM biz_production_task t + WHERE t.work_order_id = c.work_order_id + AND t.tenant_no = c.tenant_no + AND t.del_flag = 0 + ); + +-- --------------------------------------------------------------------------- +-- 3. 步骤映射:路线步骤 → 新任务步骤 ID +-- --------------------------------------------------------------------------- +DROP TEMPORARY TABLE IF EXISTS tmp_uc_step_map; +CREATE TEMPORARY TABLE tmp_uc_step_map ( + task_id VARCHAR(64) NOT NULL, + work_order_id VARCHAR(64) NOT NULL, + tenant_no VARCHAR(64) NOT NULL, + route_step_id VARCHAR(64) NOT NULL, + task_step_id VARCHAR(64) NOT NULL, + step_order INT NOT NULL, + PRIMARY KEY (task_id, route_step_id), + KEY ix_route_step (route_step_id), + KEY ix_task_step (task_step_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT INTO tmp_uc_step_map ( + task_id, work_order_id, tenant_no, route_step_id, task_step_id, step_order +) +SELECT + c.task_id, + c.work_order_id, + c.tenant_no, + rs.id, + UPPER(REPLACE(UUID(), '-', '')), + rs.step_order +FROM tmp_uc_wo_backfill c +INNER JOIN biz_process_route_step rs + ON rs.route_id = c.route_id + AND rs.del_flag = 0 +WHERE @uc_ready = 1 + AND EXISTS ( + SELECT 1 FROM biz_production_task t + WHERE t.id = c.task_id AND t.del_flag = 0 + ); + +-- --------------------------------------------------------------------------- +-- 4. 插入任务步骤 +-- --------------------------------------------------------------------------- +INSERT INTO biz_production_task_step ( + id, task_id, step_order, process_code, category_id, process_name, description, + equipment_ids, equipment_name, estimated_duration, actual_duration, + sop_ids, sop_content, step_status, planned_start_time, started_time, + completed_time, completed_by, tenant_no, order_num, remark, + create_by, create_dept_id, create_time, update_by, update_time, del_flag +) +SELECT + m.task_step_id, + m.task_id, + rs.step_order, + rs.process_code, + rs.category_id, + rs.process_name, + rs.description, + rs.equipment_ids, + rs.equipment_name, + rs.estimated_duration, + NULL, + rs.sop_ids, + rs.sop_content, + 'dzx', + NULL, + NULL, + NULL, + NULL, + m.tenant_no, + IFNULL(rs.order_num, rs.step_order), + NULL, + NULL, + '', + NOW(), + NULL, + NOW(), + 0 +FROM tmp_uc_step_map m +INNER JOIN biz_process_route_step rs + ON rs.id = m.route_step_id + AND rs.del_flag = 0 +WHERE NOT EXISTS ( + SELECT 1 FROM biz_production_task_step x + WHERE x.id = m.task_step_id +); + +-- --------------------------------------------------------------------------- +-- 5. 复制路线步骤子表 → 任务步骤子表 +-- --------------------------------------------------------------------------- +INSERT INTO biz_production_task_step_reagent ( + id, step_id, reagent_code, reagent_name, spec, standard_usage, unit, + is_key_material, tenant_no, order_num, remark, + create_by, create_dept_id, create_time, update_by, update_time, del_flag +) +SELECT + UPPER(REPLACE(UUID(), '-', '')), + m.task_step_id, + src.reagent_code, + src.reagent_name, + src.spec, + src.standard_usage, + src.unit, + src.is_key_material, + m.tenant_no, + src.order_num, + src.remark, + NULL, + '', + NOW(), + NULL, + NOW(), + 0 +FROM tmp_uc_step_map m +INNER JOIN biz_process_route_step_reagent src + ON src.step_id = m.route_step_id + AND src.del_flag = 0; + +INSERT INTO biz_production_task_step_consumable ( + id, step_id, consumable_code, consumable_name, spec_model, standard_usage, + unit, is_required, remark, tenant_no, order_num, + create_by, create_dept_id, create_time, update_by, update_time, del_flag +) +SELECT + UPPER(REPLACE(UUID(), '-', '')), + m.task_step_id, + src.consumable_code, + src.consumable_name, + src.spec_model, + src.standard_usage, + src.unit, + src.is_required, + src.remark, + m.tenant_no, + src.order_num, + NULL, + '', + NOW(), + NULL, + NOW(), + 0 +FROM tmp_uc_step_map m +INNER JOIN biz_process_route_step_consumable src + ON src.step_id = m.route_step_id + AND src.del_flag = 0; + +INSERT INTO biz_production_task_step_output ( + id, step_id, output_type_id, output_name, output_barcode, + tenant_no, order_num, remark, + create_by, create_dept_id, create_time, update_by, update_time, del_flag +) +SELECT + UPPER(REPLACE(UUID(), '-', '')), + m.task_step_id, + src.output_type_id, + src.output_name, + src.output_barcode, + m.tenant_no, + src.order_num, + src.remark, + NULL, + '', + NOW(), + NULL, + NOW(), + 0 +FROM tmp_uc_step_map m +INNER JOIN biz_process_route_step_output src + ON src.step_id = m.route_step_id + AND src.del_flag = 0; + +INSERT INTO biz_production_task_step_data_collection ( + id, step_id, collection_name, unit, tenant_no, order_num, remark, + create_by, create_dept_id, create_time, update_by, update_time, del_flag +) +SELECT + UPPER(REPLACE(UUID(), '-', '')), + m.task_step_id, + src.collection_name, + src.unit, + m.tenant_no, + src.order_num, + src.remark, + NULL, + '', + NOW(), + NULL, + NOW(), + 0 +FROM tmp_uc_step_map m +INNER JOIN biz_process_route_step_data_collection src + ON src.step_id = m.route_step_id + AND src.del_flag = 0; + +-- --------------------------------------------------------------------------- +-- 6. 回写工单状态:有任务则 jxz(不改 ywc) +-- --------------------------------------------------------------------------- +UPDATE biz_production_work_order wo +INNER JOIN tmp_uc_wo_backfill c ON c.work_order_id = wo.id +SET + wo.work_order_status = 'jxz', + wo.update_time = NOW() +WHERE wo.del_flag = 0 + AND wo.work_order_status = 'dpz' + AND EXISTS ( + SELECT 1 FROM biz_production_task t + WHERE t.work_order_id = wo.id + AND t.tenant_no = wo.tenant_no + AND t.del_flag = 0 + ); + +-- --------------------------------------------------------------------------- +-- 7. 结果核对 +-- --------------------------------------------------------------------------- +SELECT + c.lab_storage_code, + c.work_order_id, + wo.work_order_no, + wo.work_order_status, + t.id AS task_id, + t.task_no, + t.task_name, + (SELECT COUNT(*) FROM biz_production_task_step s WHERE s.task_id = t.id AND s.del_flag = 0) AS step_count +FROM tmp_uc_wo_backfill c +LEFT JOIN biz_production_work_order wo ON wo.id = c.work_order_id +LEFT JOIN biz_production_task t ON t.id = c.task_id AND t.del_flag = 0 +ORDER BY c.seq; + +DROP TEMPORARY TABLE IF EXISTS tmp_uc_step_map; +DROP TEMPORARY TABLE IF EXISTS tmp_uc_wo_backfill;