-- 采集协议单 / 科研捐赠:状态变更历史表(追加写,同类型不覆盖) -- 对齐 docs/superpowers/plans/2026-10-17-protocol-status-change-history.md CREATE TABLE IF NOT EXISTS biz_protocol_status_change ( id VARCHAR(64) NOT NULL COMMENT '主键ID', collection_protocol_id VARCHAR(64) NOT NULL COMMENT '采集协议单ID', change_type VARCHAR(32) NOT NULL COMMENT '变更类型 activate/expire/void/to_research', from_status VARCHAR(16) DEFAULT NULL COMMENT '变更前状态码', to_status VARCHAR(16) NOT NULL COMMENT '变更后状态码', change_time DATETIME NOT NULL COMMENT '业务变更时间', change_desc VARCHAR(512) DEFAULT NULL COMMENT '变更描述', void_type VARCHAR(32) DEFAULT NULL COMMENT '作废类型(字典 xyzflx)', operator_user_id VARCHAR(64) DEFAULT NULL COMMENT '操作人用户ID', tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号', order_num INT DEFAULT NULL COMMENT '排序号', remark VARCHAR(512) DEFAULT NULL COMMENT '备注', create_by VARCHAR(64) DEFAULT NULL COMMENT '创建人id', create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID', create_time DATETIME NOT NULL COMMENT '创建时间', update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人id', update_time DATETIME NOT NULL COMMENT '更新时间', del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记', PRIMARY KEY (id), KEY idx_bpsc_protocol_time (tenant_no, collection_protocol_id, del_flag, change_time) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采集协议单状态变更记录'; CREATE TABLE IF NOT EXISTS biz_donation_status_change ( id VARCHAR(64) NOT NULL COMMENT '主键ID', research_donation_id VARCHAR(64) NOT NULL COMMENT '科研捐赠单ID', change_type VARCHAR(32) NOT NULL COMMENT '变更类型 activate/expire/void/to_storage', from_status VARCHAR(16) DEFAULT NULL COMMENT '变更前状态码', to_status VARCHAR(16) NOT NULL COMMENT '变更后状态码', change_time DATETIME NOT NULL COMMENT '业务变更时间', change_desc VARCHAR(512) DEFAULT NULL COMMENT '变更描述', void_type VARCHAR(32) DEFAULT NULL COMMENT '作废类型(字典 xyzflx)', operator_user_id VARCHAR(64) DEFAULT NULL COMMENT '操作人用户ID', tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号', order_num INT DEFAULT NULL COMMENT '排序号', remark VARCHAR(512) DEFAULT NULL COMMENT '备注', create_by VARCHAR(64) DEFAULT NULL COMMENT '创建人id', create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID', create_time DATETIME NOT NULL COMMENT '创建时间', update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人id', update_time DATETIME NOT NULL COMMENT '更新时间', del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记', PRIMARY KEY (id), KEY idx_bdsc_donation_time (tenant_no, research_donation_id, del_flag, change_time) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='科研捐赠状态变更记录'; -- 回填:主表已有快照各插 1 条(幂等:同协议同 change_type 尚无历史时) INSERT INTO biz_protocol_status_change ( id, collection_protocol_id, change_type, from_status, to_status, change_time, change_desc, void_type, operator_user_id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag ) SELECT UPPER(MD5(CONCAT(p.id, '|activate'))), p.id, 'activate', NULL, 'sxz', p.effective_time, p.effective_desc, NULL, p.update_by, p.tenant_no, 0, NULL, p.update_by, '', IFNULL(p.effective_time, NOW()), p.update_by, IFNULL(p.effective_time, NOW()), 0 FROM biz_collection_protocol p WHERE p.del_flag = 0 AND p.effective_time IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM biz_protocol_status_change c WHERE c.collection_protocol_id = p.id AND c.change_type = 'activate' AND c.del_flag = 0 ); INSERT INTO biz_protocol_status_change ( id, collection_protocol_id, change_type, from_status, to_status, change_time, change_desc, void_type, operator_user_id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag ) SELECT UPPER(MD5(CONCAT(p.id, '|expire'))), p.id, 'expire', NULL, 'ygq', p.expire_time, p.expire_desc, NULL, p.update_by, p.tenant_no, 0, NULL, p.update_by, '', IFNULL(p.expire_time, NOW()), p.update_by, IFNULL(p.expire_time, NOW()), 0 FROM biz_collection_protocol p WHERE p.del_flag = 0 AND p.expire_time IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM biz_protocol_status_change c WHERE c.collection_protocol_id = p.id AND c.change_type = 'expire' AND c.del_flag = 0 ); INSERT INTO biz_protocol_status_change ( id, collection_protocol_id, change_type, from_status, to_status, change_time, change_desc, void_type, operator_user_id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag ) SELECT UPPER(MD5(CONCAT(p.id, '|void'))), p.id, 'void', NULL, 'yzf', p.void_time, p.void_desc, p.void_type, p.update_by, p.tenant_no, 0, NULL, p.update_by, '', IFNULL(p.void_time, NOW()), p.update_by, IFNULL(p.void_time, NOW()), 0 FROM biz_collection_protocol p WHERE p.del_flag = 0 AND p.void_time IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM biz_protocol_status_change c WHERE c.collection_protocol_id = p.id AND c.change_type = 'void' AND c.del_flag = 0 ); INSERT INTO biz_protocol_status_change ( id, collection_protocol_id, change_type, from_status, to_status, change_time, change_desc, void_type, operator_user_id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag ) SELECT UPPER(MD5(CONCAT(p.id, '|to_research'))), p.id, 'to_research', NULL, 'zky', p.to_research_time, p.to_research_desc, NULL, p.update_by, p.tenant_no, 0, NULL, p.update_by, '', IFNULL(p.to_research_time, NOW()), p.update_by, IFNULL(p.to_research_time, NOW()), 0 FROM biz_collection_protocol p WHERE p.del_flag = 0 AND p.to_research_time IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM biz_protocol_status_change c WHERE c.collection_protocol_id = p.id AND c.change_type = 'to_research' AND c.del_flag = 0 ); INSERT INTO biz_donation_status_change ( id, research_donation_id, change_type, from_status, to_status, change_time, change_desc, void_type, operator_user_id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag ) SELECT UPPER(MD5(CONCAT(d.id, '|activate'))), d.id, 'activate', NULL, 'sxz', d.effective_time, d.effective_desc, NULL, d.update_by, d.tenant_no, 0, NULL, d.update_by, '', IFNULL(d.effective_time, NOW()), d.update_by, IFNULL(d.effective_time, NOW()), 0 FROM biz_research_donation d WHERE d.del_flag = 0 AND d.effective_time IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM biz_donation_status_change c WHERE c.research_donation_id = d.id AND c.change_type = 'activate' AND c.del_flag = 0 ); INSERT INTO biz_donation_status_change ( id, research_donation_id, change_type, from_status, to_status, change_time, change_desc, void_type, operator_user_id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag ) SELECT UPPER(MD5(CONCAT(d.id, '|expire'))), d.id, 'expire', NULL, 'ygq', d.expire_time, d.expire_desc, NULL, d.update_by, d.tenant_no, 0, NULL, d.update_by, '', IFNULL(d.expire_time, NOW()), d.update_by, IFNULL(d.expire_time, NOW()), 0 FROM biz_research_donation d WHERE d.del_flag = 0 AND d.expire_time IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM biz_donation_status_change c WHERE c.research_donation_id = d.id AND c.change_type = 'expire' AND c.del_flag = 0 ); INSERT INTO biz_donation_status_change ( id, research_donation_id, change_type, from_status, to_status, change_time, change_desc, void_type, operator_user_id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag ) SELECT UPPER(MD5(CONCAT(d.id, '|void'))), d.id, 'void', NULL, 'yzf', d.void_time, d.void_desc, d.void_type, d.update_by, d.tenant_no, 0, NULL, d.update_by, '', IFNULL(d.void_time, NOW()), d.update_by, IFNULL(d.void_time, NOW()), 0 FROM biz_research_donation d WHERE d.del_flag = 0 AND d.void_time IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM biz_donation_status_change c WHERE c.research_donation_id = d.id AND c.change_type = 'void' AND c.del_flag = 0 ); INSERT INTO biz_donation_status_change ( id, research_donation_id, change_type, from_status, to_status, change_time, change_desc, void_type, operator_user_id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag ) SELECT UPPER(MD5(CONCAT(d.id, '|to_storage'))), d.id, 'to_storage', NULL, 'zckc', d.to_storage_time, d.to_storage_desc, NULL, d.update_by, d.tenant_no, 0, NULL, d.update_by, '', IFNULL(d.to_storage_time, NOW()), d.update_by, IFNULL(d.to_storage_time, NOW()), 0 FROM biz_research_donation d WHERE d.del_flag = 0 AND d.to_storage_time IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM biz_donation_status_change c WHERE c.research_donation_id = d.id AND c.change_type = 'to_storage' AND c.del_flag = 0 );