提交
This commit is contained in:
1 parent
f269a994f4
commit
93cd506a90
71 files changed
+8297
-2207
No files matched your search
@@ -0,0 +1,21 @@
|
||||
-- 细胞存储采集协议 ⇄ 科研捐赠 转移关联(一对一)
|
||||
CREATE TABLE IF NOT EXISTS `biz_protocol_donation_convert` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID',
|
||||
`convert_type` varchar(32) NOT NULL COMMENT 'storage_to_research/research_to_storage',
|
||||
`protocol_id` varchar(64) NOT NULL COMMENT '采集协议单ID',
|
||||
`research_donation_id` varchar(64) NOT NULL COMMENT '科研捐赠单ID',
|
||||
`biz_no` varchar(64) NOT NULL COMMENT '转移完成时共用编号快照',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT 0 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` tinyint(4) NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_pdc_protocol` (`protocol_id`, `del_flag`),
|
||||
KEY `idx_pdc_donation` (`research_donation_id`, `del_flag`),
|
||||
KEY `idx_pdc_biz_no` (`tenant_no`, `biz_no`, `del_flag`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='细胞存储协议与科研捐赠转移关联';
|
||||
@@ -0,0 +1,8 @@
|
||||
-- 细胞存储管理二级菜单:重命名 + 排序(已执行 zkxw.sql 的环境可单独运行)
|
||||
-- 顺序:采集协议单录入、采集协议单管理、缴费信息、缴费确认(财务)、退费确认(财务)
|
||||
|
||||
UPDATE `sys_menu` SET `menu_name` = '采集协议单录入', `order_num` = 1 WHERE `id` = '50000000000000000000000000000002';
|
||||
UPDATE `sys_menu` SET `menu_name` = '采集协议单管理', `order_num` = 2 WHERE `id` = '50000000000000000000000000000003';
|
||||
UPDATE `sys_menu` SET `order_num` = 3 WHERE `id` = '904b5173519411f1944300163e3bdd96';
|
||||
UPDATE `sys_menu` SET `order_num` = 4 WHERE `id` = '50000000000000000000000000000004';
|
||||
UPDATE `sys_menu` SET `order_num` = 5 WHERE `id` = '50000000000000000000000000000005';
|
||||
+13
-10
@@ -11,6 +11,7 @@ CREATE TABLE IF NOT EXISTS `biz_consumable` (
|
||||
`consumable_name` varchar(100) NOT NULL COMMENT '耗材名称',
|
||||
`spec_model` varchar(200) DEFAULT NULL COMMENT '规格型号',
|
||||
`standard_usage` varchar(100) DEFAULT NULL COMMENT '标准用量',
|
||||
`unit` varchar(64) DEFAULT NULL COMMENT '单位',
|
||||
`description` varchar(500) DEFAULT NULL COMMENT '描述',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号',
|
||||
@@ -144,6 +145,7 @@ CREATE TABLE IF NOT EXISTS `biz_consumable_pack_item` (
|
||||
`consumable_name` varchar(100) DEFAULT NULL COMMENT '耗材名称',
|
||||
`spec_model` varchar(200) DEFAULT NULL COMMENT '耗材规格型号',
|
||||
`standard_usage` varchar(100) DEFAULT NULL COMMENT '标准用量',
|
||||
`unit` varchar(64) DEFAULT NULL COMMENT '单位',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号',
|
||||
@@ -219,6 +221,7 @@ CREATE TABLE IF NOT EXISTS `biz_process_consumable` (
|
||||
`consumable_name` varchar(100) DEFAULT NULL COMMENT '耗材名称',
|
||||
`spec_model` varchar(200) DEFAULT NULL COMMENT '耗材规格型号',
|
||||
`standard_usage` varchar(100) DEFAULT NULL COMMENT '标准用量',
|
||||
`unit` varchar(64) DEFAULT NULL COMMENT '单位',
|
||||
`is_required` char(1) DEFAULT '1' COMMENT '是否必需(1-必须 0-可选)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
@@ -269,13 +272,13 @@ INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `co
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
('90000000000000000000000000000002', '耗材管理', '90000000000000000000000000000001', 'C', 'consumable', '/production/consumable/index', 'production:consumable:list', 1, '1', '1', 'zkxw', 1, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
|
||||
-- 耗材包管理
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
('90000000000000000000000000000007', '耗材包管理', '90000000000000000000000000000001', 'C', 'consumable-pack', '/production/consumable-pack/index', 'production:consumable-pack:list', 1, '1', '1', 'zkxw', 2, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
|
||||
-- 试剂管理
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
('90000000000000000000000000000003', '试剂管理', '90000000000000000000000000000001', 'C', 'reagent', '/production/reagent/index', 'production:reagent:list', 1, '1', '1', 'zkxw', 2, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
|
||||
-- SOP文档
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
('90000000000000000000000000000004', 'SOP文档', '90000000000000000000000000000001', 'C', 'sop', '/production/sop/index', 'production:sop:list', 1, '1', '1', 'zkxw', 3, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
('90000000000000000000000000000003', '试剂管理', '90000000000000000000000000000001', 'C', 'reagent', '/production/reagent/index', 'production:reagent:list', 1, '1', '1', 'zkxw', 3, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
|
||||
-- 工艺工序分类
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
@@ -285,10 +288,10 @@ INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `co
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
('90000000000000000000000000000006', '工艺产出物类型', '90000000000000000000000000000001', 'C', 'output-type', '/production/output-type/index', 'production:output-type:list', 1, '1', '1', 'zkxw', 5, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
|
||||
-- 耗材包管理
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
('90000000000000000000000000000007', '耗材包管理', '90000000000000000000000000000001', 'C', 'consumable-pack', '/production/consumable-pack/index', 'production:consumable-pack:list', 1, '1', '1', 'zkxw', 6, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
|
||||
-- 工艺库管理
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
('90000000000000000000000000000008', '工艺库管理', '90000000000000000000000000000001', 'C', 'process', '/production/process/index', 'production:process:list', 1, '1', '1', 'zkxw', 7, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
('90000000000000000000000000000008', '工艺库管理', '90000000000000000000000000000001', 'C', 'process', '/production/process/index', 'production:process:list', 1, '1', '1', 'zkxw', 6, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
|
||||
-- SOP文档
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES
|
||||
('90000000000000000000000000000004', 'SOP文档', '90000000000000000000000000000001', 'C', 'sop', '/production/sop/index', 'production:sop:list', 1, '1', '1', 'zkxw', 7, NULL, NULL, '', '2026-05-18 00:00:00', NULL, '2026-05-18 00:00:00', 0);
|
||||
@@ -0,0 +1,9 @@
|
||||
-- 生产耗材相关表增加「单位」字段(与试剂 unit 一致,数据来自物品单位管理)
|
||||
ALTER TABLE `biz_consumable`
|
||||
ADD COLUMN `unit` varchar(64) DEFAULT NULL COMMENT '单位' AFTER `standard_usage`;
|
||||
|
||||
ALTER TABLE `biz_consumable_pack_item`
|
||||
ADD COLUMN `unit` varchar(64) DEFAULT NULL COMMENT '单位' AFTER `standard_usage`;
|
||||
|
||||
ALTER TABLE `biz_process_consumable`
|
||||
ADD COLUMN `unit` varchar(64) DEFAULT NULL COMMENT '单位' AFTER `standard_usage`;
|
||||
@@ -0,0 +1,10 @@
|
||||
-- 生产管理二级菜单排序调整(已执行 production.sql 的环境可单独运行)
|
||||
-- 顺序:耗材管理、耗材包管理、试剂管理、工艺工序分类、工艺产出物类型、工艺库管理、SOP文档
|
||||
|
||||
UPDATE `sys_menu` SET `order_num` = 1 WHERE `id` = '90000000000000000000000000000002';
|
||||
UPDATE `sys_menu` SET `order_num` = 2 WHERE `id` = '90000000000000000000000000000007';
|
||||
UPDATE `sys_menu` SET `order_num` = 3 WHERE `id` = '90000000000000000000000000000003';
|
||||
UPDATE `sys_menu` SET `order_num` = 4 WHERE `id` = '90000000000000000000000000000005';
|
||||
UPDATE `sys_menu` SET `order_num` = 5 WHERE `id` = '90000000000000000000000000000006';
|
||||
UPDATE `sys_menu` SET `order_num` = 6 WHERE `id` = '90000000000000000000000000000008';
|
||||
UPDATE `sys_menu` SET `order_num` = 7 WHERE `id` = '90000000000000000000000000000004';
|
||||
@@ -0,0 +1,23 @@
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 工艺数据采集项 biz_process_data_collection
|
||||
-- 用途:在工艺库中配置该工艺需要采集的数据信息(名称、单位)
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `biz_process_data_collection` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID',
|
||||
`process_id` varchar(64) NOT NULL COMMENT '工艺id',
|
||||
`collection_name` varchar(200) NOT NULL COMMENT '采集项名称',
|
||||
`unit` varchar(64) DEFAULT NULL COMMENT '单位',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
|
||||
`order_num` int(11) 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 DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人id',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_pdc_process` (`process_id`, `del_flag`),
|
||||
KEY `idx_pdc_tenant` (`tenant_no`, `del_flag`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工艺数据采集项';
|
||||
@@ -0,0 +1,6 @@
|
||||
-- 科研捐赠管理二级菜单名称调整(已执行 research_donation_tables.sql 的环境可单独运行)
|
||||
-- 捐赠协议单 → 捐赠协议单录入
|
||||
-- 捐赠协议审核 → 捐赠协议单管理
|
||||
|
||||
UPDATE `sys_menu` SET `menu_name` = '捐赠协议单录入', `update_time` = NOW() WHERE `id` = '60000000000000000000000000000002' AND `del_flag` = 0;
|
||||
UPDATE `sys_menu` SET `menu_name` = '捐赠协议单管理', `update_time` = NOW() WHERE `id` = '60000000000000000000000000000003' AND `del_flag` = 0;
|
||||
@@ -171,6 +171,6 @@ CREATE TABLE IF NOT EXISTS `biz_research_donation_sample_transport` (
|
||||
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('60000000000000000000000000000001', '科研捐赠管理', '2', 'M', '/research-donation', '/index/index', NULL, 1, '1', '1', 'zkxw', 5, NULL, NULL, '', NOW(), NULL, NOW(), 0);
|
||||
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('60000000000000000000000000000002', '捐赠协议单', '60000000000000000000000000000001', 'C', 'list', '/research-donation/list/index', 'biz:researchDonation:list', 1, '1', '1', 'zkxw', 1, NULL, NULL, '', NOW(), NULL, NOW(), 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('60000000000000000000000000000002', '捐赠协议单录入', '60000000000000000000000000000001', 'C', 'list', '/research-donation/list/index', 'biz:researchDonation:list', 1, '1', '1', 'zkxw', 1, NULL, NULL, '', NOW(), NULL, NOW(), 0);
|
||||
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('60000000000000000000000000000003', '捐赠协议审核', '60000000000000000000000000000001', 'C', 'audit', '/research-donation/audit/index', 'biz:researchDonationAudit:list', 1, '1', '1', 'zkxw', 2, NULL, NULL, '', NOW(), NULL, NOW(), 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('60000000000000000000000000000003', '捐赠协议单管理', '60000000000000000000000000000001', 'C', 'audit', '/research-donation/audit/index', 'biz:researchDonationAudit:list', 1, '1', '1', 'zkxw', 2, NULL, NULL, '', NOW(), NULL, NOW(), 0);
|
||||
@@ -0,0 +1,155 @@
|
||||
-- ============================================================
|
||||
-- 生产管理模块基础测试数据
|
||||
-- 涵盖:耗材 → 试剂 → 工序分类 → 产出类型 → 耗材包(含明细)
|
||||
-- 租户编号:zkxw
|
||||
-- 执行前若需重复导入,可先执行文末「清理脚本」
|
||||
-- ============================================================
|
||||
|
||||
-- ----------------------------
|
||||
-- 1. 生产耗材(8 条)
|
||||
-- ----------------------------
|
||||
INSERT INTO `biz_consumable`
|
||||
(`id`, `consumable_code`, `consumable_name`, `spec_model`, `standard_usage`, `unit`, `description`,
|
||||
`tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`)
|
||||
VALUES
|
||||
('prod_cons_001', 'HC001', 'T25 细胞培养瓶', '25cm²', '1', '个', '贴壁细胞常规培养',
|
||||
'zkxw', 1, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cons_002', 'HC002', '15mL 离心管', '无菌', '2', '支', '细胞传代离心分装',
|
||||
'zkxw', 2, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cons_003', 'HC003', '10mL 移液管', '无菌独立包装', '1', '支', '培养基与试剂移液',
|
||||
'zkxw', 3, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cons_004', 'HC004', '0.22μm 针头滤器', '33mm', '1', '个', '培养基除菌过滤',
|
||||
'zkxw', 4, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cons_005', 'HC005', '细胞刮刀', '18cm', '1', '把', '贴壁细胞消化前刮取',
|
||||
'zkxw', 5, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cons_006', 'HC006', '冻存管', '2mL 外旋盖', '6', '支', '细胞冻存分装',
|
||||
'zkxw', 6, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cons_007', 'HC007', '细胞计数板', '血球计数板', '1', '块', '台盼蓝计数用',
|
||||
'zkxw', 7, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cons_008', 'HC008', '一次性无菌手套', 'M 码', '1', '双', '操作防护',
|
||||
'zkxw', 8, NULL, NULL, '', NOW(), NULL, NOW(), 0);
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 2. 试剂(6 条)
|
||||
-- ----------------------------
|
||||
INSERT INTO `biz_reagent`
|
||||
(`id`, `reagent_code`, `reagent_name`, `spec`, `standard_usage`, `unit`, `description`,
|
||||
`tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`)
|
||||
VALUES
|
||||
('prod_reag_001', 'SJ001', 'DMEM 高糖培养基', '500mL', '10', 'mL', '基础培养基',
|
||||
'zkxw', 1, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_reag_002', 'SJ002', '胎牛血清 FBS', '500mL', '1', 'mL', '培养基添加剂',
|
||||
'zkxw', 2, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_reag_003', 'SJ003', '0.25% 胰酶-EDTA', '100mL', '2', 'mL', '细胞消化',
|
||||
'zkxw', 3, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_reag_004', 'SJ004', 'PBS 缓冲液', '500mL', '5', 'mL', '细胞洗涤',
|
||||
'zkxw', 4, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_reag_005', 'SJ005', '台盼蓝染液', '10mL', '0.1', 'mL', '死活细胞染色计数',
|
||||
'zkxw', 5, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_reag_006', 'SJ006', 'DMSO 细胞冻存液', '100mL', '0.5', 'mL', '冻存保护剂',
|
||||
'zkxw', 6, NULL, NULL, '', NOW(), NULL, NOW(), 0);
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 3. 工艺工序分类(5 条)
|
||||
-- ----------------------------
|
||||
INSERT INTO `biz_process_category`
|
||||
(`id`, `category_code`, `category_name`,
|
||||
`tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`)
|
||||
VALUES
|
||||
('prod_pcat_001', 'GXFL001', '细胞复苏', 'zkxw', 1, '从液氮取出至接种前', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_pcat_002', 'GXFL002', '细胞传代', 'zkxw', 2, '贴壁细胞常规扩增', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_pcat_003', 'GXFL003', '细胞冻存', 'zkxw', 3, '液氮冻存入库', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_pcat_004', 'GXFL004', '收获与制剂', 'zkxw', 4, '上清收获或细胞收集', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_pcat_005', 'GXFL005', '质检取样', 'zkxw', 5, '留样与送检取样', NULL, '', NOW(), NULL, NOW(), 0);
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 4. 工艺产出物类型(5 条)
|
||||
-- ----------------------------
|
||||
INSERT INTO `biz_output_type`
|
||||
(`id`, `type_code`, `type_name`,
|
||||
`tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`)
|
||||
VALUES
|
||||
('prod_otype_001', 'CCLX001', '活细胞', 'zkxw', 1, '传代或扩增后的细胞悬液', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_otype_002', 'CCLX002', '冻存细胞', 'zkxw', 2, '液氮冻存管', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_otype_003', 'CCLX003', '上清液', 'zkxw', 3, '培养上清产物', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_otype_004', 'CCLX004', '留样', 'zkxw', 4, '质检留样管', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_otype_005', 'CCLX005', '废料', 'zkxw', 5, '废弃培养物', NULL, '', NOW(), NULL, NOW(), 0);
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 5. 耗材包(4 条:2 标准 + 2 自定义)
|
||||
-- ----------------------------
|
||||
INSERT INTO `biz_consumable_pack`
|
||||
(`id`, `pack_code`, `pack_name`, `usage_scene`, `pack_type`, `status`,
|
||||
`tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`)
|
||||
VALUES
|
||||
('prod_pack_001', 'HCB001', '细胞传代标准包', '贴壁细胞 T25 传代', 'bzhcb', '1',
|
||||
'zkxw', 1, '含培养瓶、离心管、移液管等', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_pack_002', 'HCB002', '细胞冻存标准包', '液氮冻存分装', 'bzhcb', '1',
|
||||
'zkxw', 2, NULL, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_pack_003', 'HCB003', '复苏接种自定义包', '复苏后首次接种', 'zdyhcb', '1',
|
||||
'zkxw', 3, '按项目定制', NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_pack_004', 'HCB004', '质检取样包(停用示例)', '留样分装', 'zdyhcb', '0',
|
||||
'zkxw', 4, '测试停用状态', NULL, '', NOW(), NULL, NOW(), 0);
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 6. 耗材包明细(关联上述耗材包与耗材编码)
|
||||
-- ----------------------------
|
||||
INSERT INTO `biz_consumable_pack_item`
|
||||
(`id`, `pack_id`, `consumable_code`, `consumable_name`, `spec_model`, `standard_usage`, `unit`, `remark`,
|
||||
`tenant_no`, `order_num`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`)
|
||||
VALUES
|
||||
-- 细胞传代标准包 HCB001
|
||||
('prod_cpi_001', 'prod_pack_001', 'HC001', 'T25 细胞培养瓶', '25cm²', '1', '个', NULL,
|
||||
'zkxw', 1, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_002', 'prod_pack_001', 'HC002', '15mL 离心管', '无菌', '2', '支', NULL,
|
||||
'zkxw', 2, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_003', 'prod_pack_001', 'HC003', '10mL 移液管', '无菌独立包装', '1', '支', NULL,
|
||||
'zkxw', 3, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_004', 'prod_pack_001', 'HC005', '细胞刮刀', '18cm', '1', '把', NULL,
|
||||
'zkxw', 4, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_005', 'prod_pack_001', 'HC008', '一次性无菌手套', 'M 码', '1', '双', NULL,
|
||||
'zkxw', 5, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
|
||||
-- 细胞冻存标准包 HCB002
|
||||
('prod_cpi_006', 'prod_pack_002', 'HC002', '15mL 离心管', '无菌', '2', '支', NULL,
|
||||
'zkxw', 1, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_007', 'prod_pack_002', 'HC006', '冻存管', '2mL 外旋盖', '6', '支', NULL,
|
||||
'zkxw', 2, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_008', 'prod_pack_002', 'HC008', '一次性无菌手套', 'M 码', '1', '双', NULL,
|
||||
'zkxw', 3, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
|
||||
-- 复苏接种自定义包 HCB003
|
||||
('prod_cpi_009', 'prod_pack_003', 'HC001', 'T25 细胞培养瓶', '25cm²', '2', '个', '双瓶接种',
|
||||
'zkxw', 1, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_010', 'prod_pack_003', 'HC004', '0.22μm 针头滤器', '33mm', '1', '个', NULL,
|
||||
'zkxw', 2, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_011', 'prod_pack_003', 'HC007', '细胞计数板', '血球计数板', '1', '块', NULL,
|
||||
'zkxw', 3, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
|
||||
-- 质检取样包 HCB004(停用包,明细仍保留供查看)
|
||||
('prod_cpi_012', 'prod_pack_004', 'HC002', '15mL 离心管', '无菌', '3', '支', NULL,
|
||||
'zkxw', 1, NULL, '', NOW(), NULL, NOW(), 0),
|
||||
('prod_cpi_013', 'prod_pack_004', 'HC006', '冻存管', '2mL 外旋盖', '2', '支', '留样管',
|
||||
'zkxw', 2, NULL, '', NOW(), NULL, NOW(), 0);
|
||||
|
||||
|
||||
-- ============================================================
|
||||
-- 清理脚本(重复导入前可选执行,按 id 前缀删除)
|
||||
-- ============================================================
|
||||
-- DELETE FROM `biz_consumable_pack_item` WHERE `id` LIKE 'prod_cpi_%';
|
||||
-- DELETE FROM `biz_consumable_pack` WHERE `id` LIKE 'prod_pack_%';
|
||||
-- DELETE FROM `biz_output_type` WHERE `id` LIKE 'prod_otype_%';
|
||||
-- DELETE FROM `biz_process_category` WHERE `id` LIKE 'prod_pcat_%';
|
||||
-- DELETE FROM `biz_reagent` WHERE `id` LIKE 'prod_reag_%';
|
||||
-- DELETE FROM `biz_consumable` WHERE `id` LIKE 'prod_cons_%';
|
||||
+5
-5
@@ -4872,10 +4872,10 @@ INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `co
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('30000000000000000000000000000001', '工作流管理', '2', 'M', '/workflow', '/index/index', NULL, 1, '1', '1', 'zkxw', 5, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-14 00:00:00', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('4760DB762DA842DABA41C0687D6F418F', '2', 'A68CEECA9A7543B29DF9FCF6BE0801A2', 'M', '12', NULL, NULL, 1, '1', '1', 'zkxw', 0, '12', 'd3000000000000000000000000000001', '', '2026-05-14 15:27:55', 'd3000000000000000000000000000001', '2026-05-14 15:27:59', 1);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000001', '细胞存储管理', '2', 'M', '/cell-storage', '/index/index', NULL, 1, '1', '1', 'zkxw', 4, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-14 00:00:00', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000002', '采集协议单', '50000000000000000000000000000001', 'C', 'protocol', '/cell-storage/protocol/index', 'biz:cellStorageProtocol:list', 1, '1', '1', 'zkxw', 1, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-14 00:00:00', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000003', '采集协议单审核', '50000000000000000000000000000001', 'C', 'protocol-audit', '/cell-storage/protocol-audit/index', 'biz:cellStorageProtocolAudit:list', 1, '1', '1', 'zkxw', 2, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-14 00:00:00', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000004', '缴费确认(财务)', '50000000000000000000000000000001', 'C', 'payment-confirm', '/cell-storage/payment-confirm/index', 'biz:cellStoragePaymentConfirm:list', 1, '1', '1', 'zkxw', 3, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-17 11:23:39', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000005', '退费确认(财务)', '50000000000000000000000000000001', 'C', 'refund-confirm', '/cell-storage/refund-confirm/index', 'biz:cellStorageRefundConfirm:list', 1, '1', '1', 'zkxw', 4, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-17 11:23:39', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000002', '采集协议单录入', '50000000000000000000000000000001', 'C', 'protocol', '/cell-storage/protocol/index', 'biz:cellStorageProtocol:list', 1, '1', '1', 'zkxw', 1, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-14 00:00:00', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000003', '采集协议单管理', '50000000000000000000000000000001', 'C', 'protocol-audit', '/cell-storage/protocol-audit/index', 'biz:cellStorageProtocolAudit:list', 1, '1', '1', 'zkxw', 2, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-14 00:00:00', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000004', '缴费确认(财务)', '50000000000000000000000000000001', 'C', 'payment-confirm', '/cell-storage/payment-confirm/index', 'biz:cellStoragePaymentConfirm:list', 1, '1', '1', 'zkxw', 4, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-17 11:23:39', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000005', '退费确认(财务)', '50000000000000000000000000000001', 'C', 'refund-confirm', '/cell-storage/refund-confirm/index', 'biz:cellStorageRefundConfirm:list', 1, '1', '1', 'zkxw', 5, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-17 11:23:39', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('50000000000000000000000000000006', '分期缴费预警', '50000000000000000000000000000001', 'C', 'installment-warning', '/cell-storage/installment-warning/index', 'biz:cellStorageInstallmentWarning:list', 1, '1', '1', 'zkxw', 5, NULL, NULL, '', '2026-05-14 00:00:00', NULL, '2026-05-17 12:07:03', 1);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('70000000000000000000000000000001', '质量检测', '2', 'M', '/quality-inspection', '/index/index', NULL, 1, '1', '1', 'zkxw', 4, NULL, NULL, '', '2026-05-17 16:22:32', NULL, '2026-05-17 16:22:32', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('70000000000000000000000000000002', '样本接收', '70000000000000000000000000000001', 'C', 'sample-reception', '/quality-inspection/sample-reception/index', 'biz:sampleReception:list', 1, '1', '1', 'zkxw', 1, NULL, NULL, '', '2026-05-17 16:22:32', NULL, '2026-05-17 16:22:32', 0);
|
||||
@@ -4884,7 +4884,7 @@ INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `co
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('70000000000000000000000000000006', '实验室自检项目', '70000000000000000000000000000001', 'C', 'lab-test-item', '/quality-inspection/lab-test-item/index', 'biz:qcLabTestItem:list', 1, '1', '1', 'zkxw', 5, NULL, NULL, '', '2026-05-17 19:37:18', NULL, '2026-05-17 19:37:18', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('70000000000000000000000000000007', '质检工单', '70000000000000000000000000000001', 'C', 'qc-work-order', '/quality-inspection/qc-work-order/index', 'biz:qcWorkOrder:list', 1, '1', '1', 'zkxw', 6, NULL, NULL, '', '2026-05-17 19:37:18', NULL, '2026-05-17 19:37:18', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('70000000000000000000000000000008', '质检任务', '70000000000000000000000000000001', 'C', 'qc-task', '/quality-inspection/qc-task/index', 'biz:qcTask:list', 1, '1', '1', 'zkxw', 7, NULL, NULL, '', '2026-05-17 19:37:18', NULL, '2026-05-17 19:37:18', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('904b5173519411f1944300163e3bdd96', '缴费信息', '50000000000000000000000000000001', 'C', 'payment-info', '/cell-storage/payment-info/index', 'cellStorage:paymentInfo:list', 1, '1', '1', 'zkxw', 2, NULL, NULL, '', '2026-05-17 10:03:14', NULL, '2026-05-17 10:03:14', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('904b5173519411f1944300163e3bdd96', '缴费信息', '50000000000000000000000000000001', 'C', 'payment-info', '/cell-storage/payment-info/index', 'cellStorage:paymentInfo:list', 1, '1', '1', 'zkxw', 3, NULL, NULL, '', '2026-05-17 10:03:14', NULL, '2026-05-17 10:03:14', 0);
|
||||
INSERT INTO `sys_menu` (`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`, `is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`) VALUES ('A68CEECA9A7543B29DF9FCF6BE0801A2', '1', '2', 'M', '1', NULL, NULL, 1, '1', '1', 'zkxw', 0, '1', 'd3000000000000000000000000000001', '', '2026-05-14 15:27:46', 'd3000000000000000000000000000001', '2026-05-14 15:28:01', 1);
|
||||
COMMIT;
|
||||
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
# 工艺路线管理模块设计规格
|
||||
|
||||
## 概述
|
||||
|
||||
实现需求文档 2.3.8 节「工艺路线配置」。在生产管理菜单下的「工艺库管理」之后新增「工艺路线管理」菜单。
|
||||
|
||||
核心功能:维护工艺路线基础信息(路线编码、名称、产品类型、版本号),支持同编码多版本管理(轻量版:is_current 标记当前版本),并通过拖拽式三栏弹窗配置路线中的工艺步骤和子表数据。
|
||||
|
||||
## 设计决策
|
||||
|
||||
| 决策项 | 选择 | 理由 |
|
||||
|--------|------|------|
|
||||
| 版本号 | 同编码多版本 + is_current 标记当前版本 | 轻量版:同 route_code 可有多条记录,仅一个可标记为当前版本。无发布/草稿状态机 |
|
||||
| 子表范围 | 完整复刻4张子表(试剂/耗材/产出物/数据采集) | 从工艺库拖入时克隆默认数据,用户可覆盖编辑 |
|
||||
| 排列模式 | 线性排列(A→B→C→D) | 卡片从上到下,无需分支逻辑 |
|
||||
| 可编辑范围 | 全部字段可编辑(基础信息+4张子表) | 右侧面板展示完整工艺信息供修改 |
|
||||
| 保存方式 | 实时保存,拖入即创建后端记录 | 每步操作即时持久化,弹窗关闭无需额外保存 |
|
||||
| UI方案 | 方案A:单弹窗 + vue-draggable-plus | 项目中已有3处成熟用法,跨栏拖拽通过HTML5 Drag API组合实现 |
|
||||
| 步骤删除 | 支持删除,软删除步骤+级联软删除子表 | 中栏卡片上有删除按钮,确认后删除 |
|
||||
|
||||
## 依赖
|
||||
|
||||
| 依赖模块 | 用途 | 状态 |
|
||||
|----------|------|------|
|
||||
| 细胞产品类型管理(biz_cell_product_type) | 产品类型下拉 | 已实现 |
|
||||
| 工艺工序分类(biz_process_category) | 工艺分组展示 | 已实现 |
|
||||
| 工艺库(biz_process + 4张子表) | 拖入时的数据源和克隆来源 | 已实现 |
|
||||
| SOP文档(biz_sop_document) | 步骤关联SOP | 已实现 |
|
||||
| vue-draggable-plus@0.6.0 | 卡片排序拖拽 | 已安装 |
|
||||
| sortablejs@1.15.7 | vue-draggable-plus 底层引擎 | 已安装 |
|
||||
|
||||
## SQL 表(6 张新建)
|
||||
|
||||
所有表遵循项目公共字段规范:`id` VARCHAR(64) UUID → 业务字段 → `tenant_no` → `order_num` → `remark` → `create_by` → `create_dept_id` → `create_time` → `update_by` → `update_time` → `del_flag`。
|
||||
|
||||
### 1. biz_process_route — 工艺路线主表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | VARCHAR(64) PK | UUID |
|
||||
| route_code | VARCHAR(64) NOT NULL | 路线编码 |
|
||||
| route_name | VARCHAR(100) NOT NULL | 路线名称 |
|
||||
| product_type_id | VARCHAR(64) DEFAULT NULL | 细胞产品类型ID(引用 biz_cell_product_type) |
|
||||
| version | VARCHAR(50) DEFAULT NULL | 版本号(用户手填文本,如 V1.0、V2.0) |
|
||||
| is_current | CHAR(1) DEFAULT '0' | 是否当前版本(0-否 1-是)。同 route_code 下仅一条记录 is_current=1 |
|
||||
| + 公共字段 | | |
|
||||
|
||||
索引:`idx_route_tenant(tenant_no, del_flag)`
|
||||
|
||||
### 2. biz_process_route_step — 路线工序步骤
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | VARCHAR(64) PK | UUID |
|
||||
| route_id | VARCHAR(64) NOT NULL | 所属路线ID |
|
||||
| process_id | VARCHAR(64) DEFAULT NULL | 来源工艺库工艺ID(工艺被删时可null) |
|
||||
| step_order | INT DEFAULT NULL | 步骤顺序(拖拽排序时自动计算) |
|
||||
| process_code | VARCHAR(64) DEFAULT NULL | 工序代码(从工艺库克隆,可编辑) |
|
||||
| category_id | VARCHAR(64) DEFAULT NULL | 工序分类ID(可编辑) |
|
||||
| process_name | VARCHAR(100) DEFAULT NULL | 工序名称(可编辑) |
|
||||
| description | VARCHAR(500) DEFAULT NULL | 描述(可编辑) |
|
||||
| equipment_name | VARCHAR(200) DEFAULT NULL | 预计使用设备(可编辑) |
|
||||
| estimated_duration | VARCHAR(100) DEFAULT NULL | 预估耗时(可编辑) |
|
||||
| sop_ids | VARCHAR(1000) DEFAULT NULL | 关联SOP文档ID(可编辑,逗号分隔) |
|
||||
| + 公共字段 | | |
|
||||
|
||||
索引:`idx_prs_route(route_id, del_flag)`、`idx_prs_tenant(tenant_no, del_flag)`
|
||||
|
||||
### 3. biz_process_route_step_reagent — 步骤试剂
|
||||
|
||||
字段完全镜像 `biz_process_reagent`,但外键改为 `step_id`(关联 biz_process_route_step.id):
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | VARCHAR(64) PK | UUID |
|
||||
| step_id | VARCHAR(64) NOT NULL | 所属步骤ID |
|
||||
| reagent_code | VARCHAR(64) DEFAULT NULL | 试剂编码 |
|
||||
| reagent_name | VARCHAR(100) DEFAULT NULL | 试剂名称 |
|
||||
| spec | VARCHAR(200) DEFAULT NULL | 规格 |
|
||||
| standard_usage | VARCHAR(100) DEFAULT NULL | 标准用量 |
|
||||
| unit | VARCHAR(64) DEFAULT NULL | 单位 |
|
||||
| is_key_material | CHAR(1) DEFAULT '0' | 是否关键物料(0-否 1-是) |
|
||||
| + 公共字段 | | |
|
||||
|
||||
索引:`idx_prsr_step(step_id, del_flag)`
|
||||
|
||||
### 4. biz_process_route_step_consumable — 步骤耗材
|
||||
|
||||
字段完全镜像 `biz_process_consumable`,外键改为 `step_id`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | VARCHAR(64) PK | UUID |
|
||||
| step_id | VARCHAR(64) NOT NULL | 所属步骤ID |
|
||||
| consumable_code | VARCHAR(64) DEFAULT NULL | 耗材编码 |
|
||||
| consumable_name | VARCHAR(100) DEFAULT NULL | 耗材名称 |
|
||||
| spec_model | VARCHAR(200) DEFAULT NULL | 规格型号 |
|
||||
| standard_usage | VARCHAR(100) DEFAULT NULL | 标准用量 |
|
||||
| unit | VARCHAR(64) DEFAULT NULL | 单位 |
|
||||
| is_required | CHAR(1) DEFAULT '1' | 是否必需(1-必须 0-可选) |
|
||||
| remark | VARCHAR(512) DEFAULT NULL | 备注 |
|
||||
| + 公共字段(不含 remark) | | |
|
||||
|
||||
索引:`idx_prsc_step(step_id, del_flag)`
|
||||
|
||||
### 5. biz_process_route_step_output — 步骤产出物
|
||||
|
||||
字段完全镜像 `biz_process_output`,外键改为 `step_id`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | VARCHAR(64) PK | UUID |
|
||||
| step_id | VARCHAR(64) NOT NULL | 所属步骤ID |
|
||||
| output_type_id | VARCHAR(64) DEFAULT NULL | 产出类型ID |
|
||||
| output_name | VARCHAR(200) DEFAULT NULL | 产出物名称 |
|
||||
| output_barcode | VARCHAR(200) DEFAULT NULL | 产出物条码 |
|
||||
| + 公共字段 | | |
|
||||
|
||||
索引:`idx_prso_step(step_id, del_flag)`
|
||||
|
||||
### 6. biz_process_route_step_data_collection — 步骤数据采集
|
||||
|
||||
字段完全镜像 `biz_process_data_collection`,外键改为 `step_id`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | VARCHAR(64) PK | UUID |
|
||||
| step_id | VARCHAR(64) NOT NULL | 所属步骤ID |
|
||||
| collection_name | VARCHAR(100) DEFAULT NULL | 采集信息名称 |
|
||||
| unit | VARCHAR(64) DEFAULT NULL | 单位 |
|
||||
| + 公共字段 | | |
|
||||
|
||||
索引:`idx_prsdc_step(step_id, del_flag)`
|
||||
|
||||
### 菜单数据
|
||||
|
||||
在「工艺库管理」(order_num=6)之后、「SOP文档」(order_num=7)之前插入,SOP 文档 order_num 改为 8:
|
||||
|
||||
```sql
|
||||
INSERT INTO sys_menu (id, menu_name, parent_id, menu_type, path, component, perms, is_frame, visible, status, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag)
|
||||
VALUES ('90000000000000000000000000000010', '工艺路线管理', '90000000000000000000000000000001', 'C', 'process-route', '/production/process-route/index', 'production:process-route:list', 1, '1', '1', 'zkxw', 7, NULL, NULL, '', '2026-05-19 00:00:00', NULL, '2026-05-19 00:00:00', 0);
|
||||
|
||||
-- SOP文档 order_num 从 7 改为 8
|
||||
UPDATE sys_menu SET order_num = 8 WHERE id = '90000000000000000000000000000004';
|
||||
```
|
||||
|
||||
## 后端 API
|
||||
|
||||
路由前缀:`/api/admin/production/route/`
|
||||
|
||||
### 路线主表 CRUD
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/list` | 路线分页列表。支持筛选:route_name(模糊)、route_code(精确)、product_type_id。排序:order_num ASC, create_time DESC。带 tenant_no 隔离。 |
|
||||
| POST | `/create` | 创建路线主表。必填:route_code, route_name。自动填充 tenant_no。默认 is_current=0。 |
|
||||
| PUT | `/update` | 更新路线主表信息(编码、名称、产品类型、版本号、备注)。 |
|
||||
| PUT | `/set-current` | 设置指定路线为当前版本。逻辑:先将同 route_code + tenant_no 下所有记录 is_current 置 0,再将目标记录 is_current 置 1。 |
|
||||
| DELETE | `/delete/{id}` | 软删除路线(del_flag=1)+ 级联软删除所有步骤及步骤子表。 |
|
||||
| GET | `/detail/{id}` | 获取路线详情:主表 + 步骤列表(按 step_order ASC)+ 每个步骤的4张子表数据。 |
|
||||
|
||||
### 步骤操作(实时保存)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/step/add` | 从工艺库拖入创建步骤。入参:route_id, process_id, step_order。后端读取 biz_process 基础信息克隆到 step 表,读取4张子表数据批量克隆到 route_step_* 子表。返回完整 step 对象(含子表)。 |
|
||||
| PUT | `/step/update` | 更新步骤基础信息(右侧面板字段修改时触发)。 |
|
||||
| PUT | `/step/reorder` | 批量重排步骤顺序。入参:route_id, step_ids[](新顺序数组)。遍历更新 step_order。 |
|
||||
| DELETE | `/step/delete/{id}` | 软删除步骤(del_flag=1)+ 级联软删除该步骤的4张子表数据。 |
|
||||
| PUT | `/step/reagent/update` | 更新步骤试剂子表。入参:step_id, items[](完整替换)。 |
|
||||
| PUT | `/step/consumable/update` | 更新步骤耗材子表。入参:step_id, items[](完整替换)。 |
|
||||
| PUT | `/step/output/update` | 更新步骤产出子表。入参:step_id, items[](完整替换)。 |
|
||||
| PUT | `/step/data-collection/update` | 更新步骤数据采集子表。入参:step_id, items[](完整替换)。 |
|
||||
|
||||
### 关键后端逻辑
|
||||
|
||||
**拖入克隆(step/add)**:
|
||||
1. 校验 route_id 存在且属于当前租户
|
||||
2. 从 `biz_process` 读取工艺基础信息
|
||||
3. 插入 `biz_process_route_step`(克隆字段:process_code, category_id, process_name, description, equipment_name, estimated_duration, sop_ids)
|
||||
4. 从 `biz_process_reagent` 等4张子表批量读取并插入对应 `biz_process_route_step_*`
|
||||
5. 返回完整 step 对象
|
||||
|
||||
**级联软删除**:
|
||||
- 删除路线 → 遍历所有步骤设 del_flag=1 → 遍历每步子表设 del_flag=1
|
||||
- 删除步骤 → 遍历该步骤子表设 del_flag=1
|
||||
|
||||
**子表更新(完整替换策略)**:
|
||||
- 接收 items[] 后,将现有记录 del_flag=1,然后批量插入新记录
|
||||
- 避免逐条 diff,简化逻辑
|
||||
|
||||
## 前端设计
|
||||
|
||||
### 文件清单
|
||||
|
||||
| 文件 | 操作 | 说明 |
|
||||
|------|------|------|
|
||||
| `web-admin/src/views/production/process-route/index.vue` | 新建 | 路线列表页 + 路线图配置弹窗 |
|
||||
| `web-admin/src/api/production.ts` | 追加 | route 相关 API 函数 |
|
||||
| `web-admin/src/router/modules/sqxp.ts` | 追加 | process-route 路由条目 |
|
||||
|
||||
### 列表页
|
||||
|
||||
遵循标准列表模板(参考 `src/views/system/unit/index.vue`):
|
||||
|
||||
- **搜索栏**:路线名称(模糊)、路线编码(精确)、产品类型(下拉,数据来自细胞产品类型管理列表 API)
|
||||
- **工具栏**:新增按钮(单一 primary)
|
||||
- **表格列**:路线名称、路线编码、产品类型名称、版本号、当前版本(is_current=1 时显示绿色 `el-tag` 标签)、备注、创建时间
|
||||
- **操作列**(fixed="right", min-width ≥ 260px):路线图配置、编辑、设为当前版本(仅 is_current=0 时显示)、删除
|
||||
- **新增/编辑弹窗**:标准表单(label-position="top"),字段:路线编码、路线名称、产品类型(下拉)、版本号(文本)、备注
|
||||
|
||||
### 路线图配置弹窗
|
||||
|
||||
**弹窗属性**:`width="90vw"`,`destroy-on-close`,标题显示路线名称和版本号
|
||||
|
||||
**三栏布局**(flex):
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 路线图配置 - {路线名称} v{版本号} [关闭] │
|
||||
├────────────┬──────────────────────┬──────────────────────────┤
|
||||
│ 工艺库 │ 工艺流程布局 │ 工艺详情 │
|
||||
│ (240px) │ (flex:1) │ (360px) │
|
||||
│ │ │ │
|
||||
│ [分类折叠] │ ┌────────────┐ │ 工序名称: [___] │
|
||||
│ > 细胞培养 │ │ 步骤1: xxx │ ←拖 │ 工序分类: [下拉] │
|
||||
│ [卡片] │ └────────────┘ │ 描述: [___] │
|
||||
│ [卡片] │ ┌────────────┐ │ 设备: [___] │
|
||||
│ > 病毒转染 │ │ 步骤2: xxx │ │ 预估耗时: [___] │
|
||||
│ [卡片] │ └────────────┘ │ SOP: [选择] │
|
||||
│ > ... │ │ ────────────── │
|
||||
│ │ [+ 拖入工艺卡片] │ [试剂][耗材][产出][采集] │
|
||||
│ │ │ (子表tab切换编辑) │
|
||||
└────────────┴──────────────────────┴──────────────────────────┘
|
||||
```
|
||||
|
||||
**左栏 — 工艺库面板(240px 固定宽度)**:
|
||||
- 使用 `el-collapse` 按工序分类(biz_process_category)分组展示
|
||||
- 每组内展示工艺小卡片:工序名称 + 编码
|
||||
- 卡片使用 HTML5 `draggable="true"` + `@dragstart` 传递 `process_id`
|
||||
- 无分类的工艺归入"未分类"组
|
||||
- 仅展示当前租户未删除的工艺
|
||||
|
||||
**中栏 — 流程布局区(flex:1 自适应)**:
|
||||
- 使用 `vue-draggable-plus`(VueDraggable 组件)包裹步骤卡片列表
|
||||
- 每张步骤卡片显示:步骤序号(圆角标签)+ 工艺名称 + 操作按钮(删除图标)
|
||||
- 支持内部排序拖拽(handle 拖拽手柄,使用 `<el-icon><Rank /></el-icon>`)
|
||||
- 空白区域通过 `@dragover.prevent` + `@drop` 接收从左栏拖入的工艺卡片
|
||||
- 拖入时调用 `POST /step/add`,即时创建后端记录
|
||||
- 排序变化时调用 `PUT /step/reorder`
|
||||
- 点击卡片 → 选中态(高亮边框)→ 触发右栏加载详情
|
||||
- 卡片上的删除按钮 → 确认弹窗 → `DELETE /step/delete/{id}` → 从列表移除
|
||||
|
||||
**右栏 — 工艺详情编辑面板(360px 固定宽度)**:
|
||||
- **顶部**:工艺基础信息表单
|
||||
- 工序名称(el-input)
|
||||
- 工序分类(el-select,下拉数据来自工艺工序分类)
|
||||
- 描述(el-input textarea)
|
||||
- 设备名称(el-input)
|
||||
- 预估耗时(el-input)
|
||||
- SOP文档(el-select multiple,数据来自 SOP 文档列表)
|
||||
- 字段修改时 `@change` 触发 `PUT /step/update` 实时保存
|
||||
- **底部**:4 个 el-tab-pane 切换子表编辑
|
||||
- **试剂 tab**:表格列(试剂编码、名称、规格、标准用量、单位、是否关键物料),底部"添加"按钮新增行,每行有删除按钮。修改后实时保存 `PUT /step/reagent/update`
|
||||
- **耗材 tab**:表格列(耗材编码、名称、规格型号、标准用量、单位、是否必需、备注),同上交互
|
||||
- **产出 tab**:表格列(产出类型[下拉选择产出物类型]、名称、条码),同上交互
|
||||
- **数据采集 tab**:表格列(采集名称、单位),同上交互
|
||||
- 未选中任何步骤时显示空状态提示:"请从左侧工艺库拖入工艺,或点击已添加的步骤查看详情"
|
||||
|
||||
### 数据流
|
||||
|
||||
```
|
||||
拖入流程:
|
||||
左栏卡片 dragstart(process_id)
|
||||
→ 中栏 drop 事件
|
||||
→ POST /step/add {route_id, process_id, step_order: list.length + 1}
|
||||
→ 后端克隆工艺+子表 → 返回完整 step
|
||||
→ 前端追加到步骤列表
|
||||
|
||||
排序流程:
|
||||
中栏内 vue-draggable-plus 拖拽排序
|
||||
→ @end 回调
|
||||
→ PUT /step/reorder {route_id, step_ids: [...]}
|
||||
|
||||
编辑流程:
|
||||
右栏字段 @change
|
||||
→ PUT /step/update {step_id, ...fields}
|
||||
|
||||
右栏子表增删改
|
||||
→ PUT /step/{sub-table}/update {step_id, items: [...]}
|
||||
|
||||
删除步骤:
|
||||
卡片删除按钮 → ElMessageBox.confirm
|
||||
→ DELETE /step/delete/{step_id}
|
||||
→ 前端从列表移除
|
||||
|
||||
点击步骤:
|
||||
中栏卡片 click
|
||||
→ 设置 selectedStepId
|
||||
→ 右栏加载该步骤详情(从列表数据中取,无需额外 API)
|
||||
```
|
||||
|
||||
## 实现文件清单
|
||||
|
||||
| 层 | 文件 | 操作 |
|
||||
|----|------|------|
|
||||
| SQL | `docs/sql/production_process_route.sql` | 新建:6张表DDL + 菜单INSERT + SOP order_num UPDATE |
|
||||
| Model | `backend/app/models/models.py` | 追加 6 个 SQLAlchemy Model 类 |
|
||||
| Model | `backend/app/models/__init__.py` | 追加 6 个 export |
|
||||
| CRUD | `backend/app/crud/process_route.py` | 新建:路线CRUD + 步骤CRUD + 子表CRUD + 克隆逻辑 |
|
||||
| API | `backend/app/api/production.py` | 追加 route 子路由(挂载到 production router 下) |
|
||||
| Schema | `backend/app/schemas/process_route.py` | 新建:Pydantic v2 schemas |
|
||||
| 前端 API | `web-admin/src/api/production.ts` | 追加 route 相关函数(~15个 API 函数) |
|
||||
| 前端页面 | `web-admin/src/views/production/process-route/index.vue` | 新建:列表页 + 三栏拖拽配置弹窗 |
|
||||
| 路由 | `web-admin/src/router/modules/sqxp.ts` | 追加 process-route 路由条目 |
|
||||
|
||||
## 风险与注意事项
|
||||
|
||||
1. **跨容器拖拽**:左栏(HTML5 Drag)→ 中栏(vue-draggable-plus)的跨容器拖入是核心难点。需在 drop 事件中正确获取 process_id 并调用 API。参考项目中 FlowDesigner.vue 的 HTML5 drag 实现。
|
||||
2. **大弹窗性能**:90vw 弹窗内三栏 + 多个子表可能数据量大。步骤列表应限制每页展示(暂无分页需求,路线步骤通常 < 50)。
|
||||
3. **工艺库删除影响**:步骤的 process_id 引用工艺库,但工艺被删除后步骤保留(process_id 可 null)。右栏编辑时不依赖 process_id 回查,所有数据已克隆到步骤中。
|
||||
4. **子表更新策略**:使用完整替换(del旧 + insert新),避免复杂 diff。注意 UUID 生成和 tenant_no 继承。
|
||||
@@ -0,0 +1,339 @@
|
||||
# 细胞存储 ⇄ 科研捐赠 转移改造方案
|
||||
|
||||
> 日期:2026-05-19
|
||||
> 状态:已实施(2026-05-19)
|
||||
> 关联模块:采集协议单管理、捐赠协议单管理
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与问题
|
||||
|
||||
### 1.1 业务场景
|
||||
|
||||
- **协议转科研**:细胞存储采集协议(`sxz`)→ 新建科研捐赠单,源协议状态 `zky`。
|
||||
- **转细胞存储**:科研捐赠单(`sxz`)→ 新建采集协议单,源捐赠状态 `zckc`。
|
||||
|
||||
产品约定:
|
||||
|
||||
1. 转移时 **协议号与样本编码与源单一致**(同一业务在不同模块各一张单)。
|
||||
2. 转移后用户 **可能单独调整** 采集协议号或捐赠协议号(两边不必长期同号)。
|
||||
3. 二次编辑保存时不应误报「协议号已存在」「样本编码已被占用」。
|
||||
|
||||
### 1.2 现状问题
|
||||
|
||||
| 问题 | 原因 |
|
||||
|------|------|
|
||||
| 转移后协议号为 `KY…` / `XC…` 临时串 | `convert_from_storage` / `convert_to_storage` 临时生成编号 |
|
||||
| 二次保存报样本编码已占用 | 全局唯一校验未识别「转移配对单」 |
|
||||
| 同号需求与跨表唯一校验冲突 | `protocol_no` 与 `donation_no` 互斥,未对配对单豁免 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 改造目标
|
||||
|
||||
| # | 目标 |
|
||||
|---|------|
|
||||
| G1 | 转移瞬间:新单 `protocol_no` / `donation_no` = 源单展示号;样本 `sample_code` / `sample_code_id` 原样拷贝 |
|
||||
| G2 | 建立 **转移关联** 持久化记录(中间表),供保存/改号校验查询 |
|
||||
| G3 | 样本编码、协议号唯一性:对 **配对单据 ID** 豁免,不依赖编号字符串是否相同 |
|
||||
| G4 | 转移后允许用户 **独立修改** 本单协议号/捐赠号,**不自动同步** 对端 |
|
||||
| G5 | 非配对单据仍严格执行全局唯一,不影响手工新建/审核等流程 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 方案概述
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph transfer [转移事务]
|
||||
A[源单状态变更 zky/zckc]
|
||||
B[新建目标单 同号同码]
|
||||
C[写入关联表 biz_protocol_donation_convert]
|
||||
end
|
||||
subgraph save [编辑保存]
|
||||
D[根据当前单 ID 查配对 protocol_id / donation_id]
|
||||
E[协议号校验 排除配对单]
|
||||
F[样本编码校验 排除配对单样本行]
|
||||
end
|
||||
transfer --> save
|
||||
```
|
||||
|
||||
**核心原则**:配对关系由 **关联表 + 双方主键 ID** 锁定;`biz_no` 仅记录转移完成时的初始编号(审计),**不参与** 豁免判断。
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据库设计
|
||||
|
||||
### 4.1 新建表 `biz_protocol_donation_convert`
|
||||
|
||||
脚本路径:`docs/sql/biz_protocol_donation_convert.sql`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | VARCHAR(64) | 主键 UUID |
|
||||
| `convert_type` | VARCHAR(32) | `storage_to_research` / `research_to_storage` |
|
||||
| `protocol_id` | VARCHAR(64) | `biz_collection_protocol.id` |
|
||||
| `research_donation_id` | VARCHAR(64) | `biz_research_donation.id` |
|
||||
| `biz_no` | VARCHAR(64) | **转移完成时** 的共用编号快照(不随改号自动更新) |
|
||||
| `tenant_no` | VARCHAR(64) | 租户 |
|
||||
| 公共字段 | — | `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag` |
|
||||
|
||||
**索引与约束(建议)**
|
||||
|
||||
- `UNIQUE (protocol_id)`:同一采集协议仅允许一条有效转移关联(应用层保证 `del_flag=0` 唯一)。
|
||||
- `UNIQUE (research_donation_id)`:同一科研捐赠仅允许一条有效转移关联。
|
||||
- `KEY (tenant_no, biz_no, del_flag)`:按初始编号排查。
|
||||
|
||||
**不新建** 主表字段为一期必选项;科研侧已有 `source_type`、`source_protocol_id` 可继续用于列表筛选与展示。
|
||||
|
||||
### 4.2 与现有表关系
|
||||
|
||||
```
|
||||
biz_collection_protocol (1) ──< biz_protocol_donation_convert >── (1) biz_research_donation
|
||||
│ │
|
||||
├── biz_protocol_sample ├── biz_research_donation_sample
|
||||
```
|
||||
|
||||
一对一:一次转移产生一对主单 + 一条关联记录。
|
||||
|
||||
---
|
||||
|
||||
## 5. 转移业务规则
|
||||
|
||||
### 5.1 协议转科研(`convert_from_storage`)
|
||||
|
||||
**前置**
|
||||
|
||||
- 源协议存在、`tenant_no` 匹配、`del_flag=0`。
|
||||
- 源协议状态 = `sxz`(生效中)。
|
||||
- 该 `protocol_id` 尚未存在有效关联记录。
|
||||
|
||||
**事务内操作**
|
||||
|
||||
| 步骤 | 操作 |
|
||||
|------|------|
|
||||
| 1 | 新建 `biz_research_donation`:`donation_no = proto.protocol_no`,`donation_status=dsx`,`source_type=from_storage`,`source_protocol_id=protocol_id` |
|
||||
| 2 | 复制 party / collection / samples(+transport),样本编码与源一致 |
|
||||
| 3 | 源协议 `protocol_status=zky`,写 `to_research_time` / `to_research_desc` |
|
||||
| 4 | 插入关联表:`convert_type=storage_to_research`,`biz_no=proto.protocol_no` |
|
||||
|
||||
**删除**:`KY` + 时间戳 + UUID 临时号逻辑。
|
||||
|
||||
### 5.2 转细胞存储(`convert_to_storage`)
|
||||
|
||||
**前置**
|
||||
|
||||
- 源捐赠存在、`sxz`、无有效关联。
|
||||
|
||||
**事务内操作**
|
||||
|
||||
| 步骤 | 操作 |
|
||||
|------|------|
|
||||
| 1 | 新建 `biz_collection_protocol`:`protocol_no = donation.donation_no`,`protocol_status=dsx`;`protocol_no_id` 可按 `biz_no` 反查号池(可选) |
|
||||
| 2 | 复制子表,样本同码;价格字段置空 |
|
||||
| 3 | 源捐赠 `donation_status=zckc`,写 `to_storage_time` / `to_storage_desc` |
|
||||
| 4 | 插入关联表:`convert_type=research_to_storage`,`biz_no=donation.donation_no` |
|
||||
|
||||
**删除**:`XC` + 时间戳临时号逻辑。
|
||||
|
||||
### 5.3 转移后改号(用户可能调整)
|
||||
|
||||
| 规则 | 说明 |
|
||||
|------|------|
|
||||
| 允许改号 | 采集协议可改 `protocol_no`;科研捐赠可改 `donation_no`(需确认前端是否已暴露字段,后端须支持校验) |
|
||||
| 不同步对端 | 改 A 单号 **不自动修改** B 单号(方案 A) |
|
||||
| 关联表 `biz_no` | **保留转移快照**,不随改号更新 |
|
||||
| 可选 UI 提示 | 改号成功后提示「配对单据当前编号为 xxx」(二期) |
|
||||
|
||||
---
|
||||
|
||||
## 6. 校验规则改造
|
||||
|
||||
### 6.1 公共能力(新建)
|
||||
|
||||
位置建议:`backend/app/crud/protocol_donation_convert.py`(或合入 `research_donation.py`)
|
||||
|
||||
| 函数 | 说明 |
|
||||
|------|------|
|
||||
| `create_convert_link(db, ...)` | 转移事务内写入关联 |
|
||||
| `get_convert_partner(db, tenant_no, *, protocol_id=None, donation_id=None)` | 返回 `{ protocol_id, research_donation_id, biz_no, convert_type }` 或 `None` |
|
||||
| `get_partner_sample_codes(db, tenant_no, protocol_id, donation_id)` | 配对单上所有 `del_flag=0` 的 `sample_code` 集合 |
|
||||
|
||||
### 6.2 样本编码唯一性
|
||||
|
||||
改造:`collection_protocol.validate_sample_codes_not_used`
|
||||
|
||||
```text
|
||||
占用集合 = 全租户 采集样本表 ∪ 科研捐赠样本表(del_flag=0)
|
||||
占用集合 -= 配对 protocol_id 下样本编码
|
||||
占用集合 -= 配对 research_donation_id 下样本编码
|
||||
若 待保存编码 ∩ 占用集合 非空 → 报错
|
||||
```
|
||||
|
||||
**调用点**
|
||||
|
||||
- `collection_protocol.save_samples`:传入当前 `collection_protocol_id`,查 partner 后排除。
|
||||
- `research_donation._create_samples`:传入当前 `research_donation_id`,查 partner 后排除。
|
||||
|
||||
> 本单 upsert 会先软删旧样本行,排除逻辑必须基于 **配对单 ID**,与双方编号是否一致无关。
|
||||
|
||||
### 6.3 协议号 / 捐赠号跨表唯一性
|
||||
|
||||
改造:`create_collection_protocol`、`update_collection_protocol`、`create_donation`、`update_donation`(若支持改 `donation_no`)。
|
||||
|
||||
**判断「编号是否冲突」时:**
|
||||
|
||||
```text
|
||||
冲突对象 = 其他采集协议.protocol_no(排除当前 protocol_id)
|
||||
∪ 其他科研捐赠.donation_no(排除当前 donation_id)
|
||||
|
||||
若存在 convert 配对:
|
||||
- 更新采集协议时:再排除 配对 research_donation_id 对应行的 donation_no
|
||||
- 更新科研捐赠时:再排除 配对 protocol_id 对应行的 protocol_no
|
||||
|
||||
仅当 新编号 落在「冲突对象」中时报错
|
||||
```
|
||||
|
||||
**说明**:配对单占用 **整行单据** 豁免,不要求新号与对端当前号相同。例如协议改为 A001、捐赠仍为 A002,只要无第三方占用,均应通过。
|
||||
|
||||
### 6.4 非转移场景
|
||||
|
||||
- 手工新建、无关联记录:保持现有严格唯一。
|
||||
- 批量转移失败策略:维持现有「逐条调用、部分成功」行为。
|
||||
|
||||
---
|
||||
|
||||
## 7. 后端改动清单
|
||||
|
||||
| 序号 | 文件 | 改动要点 |
|
||||
|------|------|----------|
|
||||
| 1 | `docs/sql/biz_protocol_donation_convert.sql` | 建表 |
|
||||
| 2 | `backend/app/models/research_donation.py` | `BizProtocolDonationConvert` |
|
||||
| 3 | `backend/app/models/__init__.py` | 导出 Model |
|
||||
| 4 | `backend/app/crud/protocol_donation_convert.py` | 关联 CRUD + 查询(新建) |
|
||||
| 5 | `backend/app/crud/research_donation.py` | `convert_*` 同号同码 + 写关联;`_create_samples` 传排除参数;`update_donation` 支持 `donation_no` 改号校验 |
|
||||
| 6 | `backend/app/crud/collection_protocol.py` | `validate_sample_codes_not_used`、`save_samples`、create/update 协议号校验 |
|
||||
| 7 | `backend/app/api/research_donation.py` | 无路由变更(可选详情返回 `convertPartner`) |
|
||||
|
||||
**API**:不新增对外接口;现有:
|
||||
|
||||
- `POST /web/admin/research-donations/convert-from-storage`
|
||||
- `POST /web/admin/research-donations/{id}/convert-to-storage`
|
||||
|
||||
---
|
||||
|
||||
## 8. 前端改动清单
|
||||
|
||||
### 8.1 一期(随然后端联调)
|
||||
|
||||
| 项 | 改动 |
|
||||
|----|------|
|
||||
| 转移确认文案 | 说明「将创建新单,**初始**协议号与样本编码与源单一致」 |
|
||||
| 编辑表单 | 转移生成的新单:**协议号/捐赠号保持可编辑**(勿做只读) |
|
||||
| 保存逻辑 | 无改动,依赖后端豁免 |
|
||||
|
||||
### 8.2 二期(体验增强)
|
||||
|
||||
| 项 | 改动 |
|
||||
|----|------|
|
||||
| 查看弹窗 | 展示「转移关联」:对端单据类型、编号、跳转 |
|
||||
| 改号提示 | 保存后若与对端编号不一致,轻提示对端当前号 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 历史数据
|
||||
|
||||
| 类型 | 处理 |
|
||||
|------|------|
|
||||
| 已用 `KY…`/`XC…` 生成的转移单 | 脚本按 `source_protocol_id`、`to_research_desc`、`remark` 尝试配对并补关联表;编号是否改为源单同号需 **业务确认后** 再批量更新 |
|
||||
| 无法配对 | 保持现状,仅新转移走新逻辑 |
|
||||
|
||||
脚本建议:`backend/scripts/backfill_protocol_donation_convert.py`(可选)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 实施步骤
|
||||
|
||||
| 阶段 | 内容 | 产出 |
|
||||
|------|------|------|
|
||||
| P1 | SQL + Model + 关联 CRUD | 表可建、可查询配对 |
|
||||
| P2 | 改造 `convert_from_storage` / `convert_to_storage` | 转移同号同码 + 写关联 |
|
||||
| P3 | 样本编码校验 + `save_samples` / `_create_samples` | 二次编辑样本保存通过 |
|
||||
| P4 | 协议号/捐赠号 create & update 豁免 | 改号不误报、可独立改号 |
|
||||
| P5 | 联调 + 回归 + 确认文案 | 测试清单通过 |
|
||||
| P6 | 历史数据脚本(可选) | 补关联记录 |
|
||||
|
||||
---
|
||||
|
||||
## 11. 测试用例
|
||||
|
||||
### 11.1 转移
|
||||
|
||||
| # | 步骤 | 预期 |
|
||||
|---|------|------|
|
||||
| T1 | `sxz` 协议转科研 | 捐赠号=协议号;样本码一致;关联表 1 条;源单 `zky` |
|
||||
| T2 | `sxz` 捐赠转存储 | 协议号=捐赠号;样本码一致;关联表 1 条;源单 `zckc` |
|
||||
| T3 | 非 `sxz` 转移 | 400 业务错误 |
|
||||
| T4 | 已转移协议再次转科研 | 失败 |
|
||||
|
||||
### 11.2 二次保存(样本)
|
||||
|
||||
| # | 步骤 | 预期 |
|
||||
|---|------|------|
|
||||
| T5 | 转移后不改编码,直接保存 | 成功 |
|
||||
| T6 | 修改非编码字段后保存 | 成功 |
|
||||
|
||||
### 11.3 改号
|
||||
|
||||
| # | 步骤 | 预期 |
|
||||
|---|------|------|
|
||||
| T7 | 只改采集协议号 | 成功;捐赠号可不变 |
|
||||
| T8 | 只改捐赠号 | 成功 |
|
||||
| T9 | 改为第三方已占用号 | 失败 |
|
||||
| T10 | 改为配对单当前持有的号 | 成功(豁免) |
|
||||
|
||||
### 11.4 回归
|
||||
|
||||
| # | 步骤 | 预期 |
|
||||
|---|------|------|
|
||||
| T11 | 无关联手工新建协议+样本 | 重复编码仍失败 |
|
||||
| T12 | 审核、状态变更、删除 | 行为不变 |
|
||||
|
||||
---
|
||||
|
||||
## 12. 风险与待定项
|
||||
|
||||
| 项 | 说明 | 建议 |
|
||||
|----|------|------|
|
||||
| 号池下发状态 | 转移同号后 `biz_collection_protocol_no` 是否标记已下发 | 二期与基础数据模块对齐 |
|
||||
| `protocol_no_id` | 转存储时是否回填号池 ID | 可选:按 `biz_no` 查池 |
|
||||
| 链式转移 | 同一业务多次互转 | 当前按 **一对一** 设计;若需支持需单独立项 |
|
||||
| 软删一方 | 另一方编辑是否仍豁免 | 建议:**仍豁免**(关联保留,占用仅计 `del_flag=0`) |
|
||||
|
||||
---
|
||||
|
||||
## 13. 已确认产品决策
|
||||
|
||||
| 决策 | 结论 |
|
||||
|------|------|
|
||||
| 转移初始编号 | 与源单相同 |
|
||||
| 转移初始样本编码 | 与源单相同 |
|
||||
| 转移后改号 | 允许,两边可不一致 |
|
||||
| 改号是否同步对端 | **否** |
|
||||
| 关联表 `biz_no` | 转移快照,不随改号更新 |
|
||||
| 豁免依据 | 关联表 **单据 ID**,非编号字符串 |
|
||||
|
||||
---
|
||||
|
||||
## 14. 参考代码位置(改造前)
|
||||
|
||||
| 逻辑 | 文件 |
|
||||
|------|------|
|
||||
| 转移(临时号) | `backend/app/crud/research_donation.py` → `convert_from_storage` / `convert_to_storage` |
|
||||
| 样本编码校验 | `backend/app/crud/collection_protocol.py` → `validate_sample_codes_not_used` |
|
||||
| 协议号互斥 | `create_collection_protocol` / `update_collection_protocol` / `create_donation` |
|
||||
| 前端转移调用 | `web-admin/src/api/research-donation.ts` |
|
||||
|
||||
---
|
||||
|
||||
*文档结束*
|
||||
Reference in new issue
Block a user