feat: 二期审批引擎扩展与会签/明细/回填/附件分类共享层(#46)

- ApprovalDocumentType SPI + 注册表:新增单据不再改引擎
- ApprovalApproverResolver:会签组、orgLeaderByCode/orgDeputyByCode、租户岗位解析器
- 会签:任务带 group_key/group_name/group_seq,一人多组一次通过,只取消同组待办
- 回填:节点 writableFields、BACKFILL 动作、approval_field_change 留痕
- 附件:新增 VOUCHER 分类并按单据类型校验必传
- 详情:document.fields/lines/lineColumns/groupProgress + permissions.writableFields
- 列表/导出:title/search_text 落库、flowCode 筛选、明细行数/合计金额/会签进度列、明细导出
- sql/05-approval_phase2.sql(可重复执行)
This commit is contained in:
weicw
2026-10-31 06:13:45 +08:00
parent 5018463005
commit d5001c981c
59 changed files with 3230 additions and 661 deletions
+19
View File
@@ -75,3 +75,22 @@ WHERE m.tenant_id = 10150
AND NOT EXISTS (
SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = 586 AND rm.menu_id = m.menu_id AND rm.tenant_id = 10150
);
SET @instanceMenu = (SELECT menu_id FROM sys_menu WHERE tenant_id = 10150 AND path = '/approval/instance' AND menu_type = 0 AND deleted = 0 ORDER BY menu_id LIMIT 1);
-- 价格表查看(ADR 0008):受众全体员工,独立权限点,配 /approval/price 只读页
SET @parent = (SELECT menu_id FROM sys_menu WHERE tenant_id = 10150 AND path = '/approval' AND menu_type = 0 AND deleted = 0 ORDER BY menu_id LIMIT 1);
INSERT INTO sys_menu (parent_id, title, path, component, sort_number, authority, icon, menu_type, tenant_id, deleted)
SELECT @parent, '设施价格表', '/approval/price', '/approval/price', 3, 'approval:price:view', '', 0, 10150, 0
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM sys_menu WHERE tenant_id = 10150 AND path = '/approval/price' AND menu_type = 0 AND deleted = 0
);
INSERT INTO sys_menu (parent_id, title, path, component, sort_number, authority, icon, menu_type, tenant_id, deleted)
SELECT @instanceMenu, '价格表查看', '', '', 6, 'approval:price:view', '', 1, 10150, 0
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM sys_menu WHERE tenant_id = 10150 AND authority = 'approval:price:view' AND menu_type = 1 AND deleted = 0
);
+39
View File
@@ -57,3 +57,42 @@ WHERE r.tenant_id = @tenant_id AND r.deleted = 0 AND r.role_code = 'approval_arc
SELECT 1 FROM sys_role_menu rm
WHERE rm.role_id = r.role_id AND rm.menu_id = m.menu_id AND rm.tenant_id = @tenant_id
);
-- 4. 相关部门(体验券领用申请单固定角色,ADR 0013;待客户确认)
INSERT INTO sys_role (role_name, role_code, comments, sort_number, tenant_id, deleted)
SELECT '相关部门', 'approval_related_dept', '审批种子:体验券领用申请单「相关部门」节点,多人或签(ADR 0013)', 926, @tenant_id, 0
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM sys_role WHERE tenant_id = @tenant_id AND deleted = 0 AND role_code = 'approval_related_dept'
);
INSERT INTO sys_role_menu (role_id, menu_id, tenant_id)
SELECT r.role_id, m.menu_id, @tenant_id
FROM sys_role r
JOIN sys_menu m
ON m.tenant_id = @tenant_id AND m.deleted = 0
AND (m.path IN ('/approval', '/approval/todo', '/approval/instance')
OR m.authority IN ('approval:instance:list', 'approval:instance:submit', 'approval:instance:approve'))
WHERE r.tenant_id = @tenant_id AND r.deleted = 0 AND r.role_code = 'approval_related_dept'
AND NOT EXISTS (
SELECT 1 FROM sys_role_menu rm
WHERE rm.role_id = r.role_id AND rm.menu_id = m.menu_id AND rm.tenant_id = @tenant_id
);
-- 5. 价格表查看:全体员工可查当前生效与历史版本(ADR 0008)
INSERT INTO sys_role_menu (role_id, menu_id, tenant_id)
SELECT r.role_id, m.menu_id, @tenant_id
FROM sys_role r
JOIN sys_menu m
ON m.tenant_id = @tenant_id AND m.deleted = 0
AND (m.path = '/approval/price' OR m.authority = 'approval:price:view')
WHERE r.tenant_id = @tenant_id AND r.deleted = 0
AND (r.role_code = 'approval_staff'
OR LEFT(r.role_code, 12) = 'dept_leader_'
OR LEFT(r.role_code, 12) = 'dept_deputy_'
OR r.role_code IN ('approval_archivist', 'approval_cashier', 'approval_typist',
'approval_issuer', 'approval_general_manager', 'approval_related_dept'))
AND NOT EXISTS (
SELECT 1 FROM sys_role_menu rm
WHERE rm.role_id = r.role_id AND rm.menu_id = m.menu_id AND rm.tenant_id = @tenant_id
);
+107
View File
@@ -0,0 +1,107 @@
-- 二期审批引擎扩展(可重复执行)
-- 目标库:db_gxtyzx(master)
-- 执行顺序:01-approval.sql -> 02-approval_menu.sql -> 03-approval_orgs_roles.sql
-- -> 04-approval_role_grants.sql -> 05-approval_phase2.sql
--
-- 覆盖 ADR 0003(会签)、0004(明细行)、0006(回填)、0007(流程类型筛选)。
-- MySQL 8 不支持 ADD COLUMN IF NOT EXISTS,因此用 information_schema 判断后动态执行。
-- 老数据回填:一期实例没有 title/search_text(幂等,只补空值)
UPDATE approval_instance i
JOIN approval_completion_form f ON f.instance_id = i.id
SET i.title = f.name,
i.search_text = CONCAT_WS(' ', f.name, f.implement_org, f.service_content)
WHERE i.title IS NULL;
UPDATE approval_instance i
JOIN approval_coordination_form c ON c.instance_id = i.id
SET i.title = c.title,
i.search_text = CONCAT_WS(' ', c.title, c.content, c.remark)
WHERE i.title IS NULL;
DROP PROCEDURE IF EXISTS approval_phase2_add_column;
DROP PROCEDURE IF EXISTS approval_phase2_add_index;
DELIMITER $$
CREATE PROCEDURE approval_phase2_add_column(IN p_table VARCHAR(64), IN p_column VARCHAR(64),
IN p_definition TEXT)
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = p_table AND column_name = p_column
) THEN
SET @ddl = CONCAT('ALTER TABLE ', p_table, ' ADD COLUMN ', p_definition);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END$$
CREATE PROCEDURE approval_phase2_add_index(IN p_table VARCHAR(64), IN p_index VARCHAR(64),
IN p_definition TEXT)
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = p_table AND index_name = p_index
) THEN
SET @ddl = CONCAT('ALTER TABLE ', p_table, ' ADD ', p_definition);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END$$
DELIMITER ;
-- 会签任务分组:非会签节点三列为空(ADR 0003)
CALL approval_phase2_add_column('approval_task', 'group_key',
'group_key VARCHAR(40) DEFAULT NULL COMMENT ''会签组标识'' AFTER opinion');
CALL approval_phase2_add_column('approval_task', 'group_name',
'group_name VARCHAR(100) DEFAULT NULL COMMENT ''会签组显示名'' AFTER group_key');
CALL approval_phase2_add_column('approval_task', 'group_seq',
'group_seq INT DEFAULT NULL COMMENT ''会签组展示顺序'' AFTER group_name');
-- 列表标题与检索文本:由单据实现计算落库,列表/检索不再按 doc_type 分支(ADR 0007)
CALL approval_phase2_add_column('approval_instance', 'title',
'title VARCHAR(200) DEFAULT NULL COMMENT ''列表显示标题'' AFTER biz_id');
CALL approval_phase2_add_column('approval_instance', 'search_text',
'search_text VARCHAR(500) DEFAULT NULL COMMENT ''关键词检索文本'' AFTER title');
-- 回填唯一性检索用:同类单据按 flow_code 过滤
CALL approval_phase2_add_index('approval_instance', 'idx_flow',
'KEY idx_flow (tenant_id, flow_code, status)');
-- 字段改值历史(ADR 0006)
CREATE TABLE IF NOT EXISTS approval_field_change (
id BIGINT NOT NULL AUTO_INCREMENT,
tenant_id INT NOT NULL DEFAULT 10150,
instance_id BIGINT NOT NULL,
task_id BIGINT DEFAULT NULL,
node_key VARCHAR(40) DEFAULT NULL,
field_key VARCHAR(40) NOT NULL,
field_label VARCHAR(100) DEFAULT NULL,
old_value VARCHAR(500) DEFAULT NULL,
new_value VARCHAR(500) DEFAULT NULL,
operator_id INT NOT NULL,
operator_name VARCHAR(100) DEFAULT NULL,
round INT NOT NULL,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_instance (instance_id, create_time),
KEY idx_field (tenant_id, field_key, new_value)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审批字段改值历史';
-- 老数据回填:一期实例没有 title/search_text(幂等,只补空值)
UPDATE approval_instance i
JOIN approval_completion_form f ON f.instance_id = i.id
SET i.title = f.name,
i.search_text = CONCAT_WS(' ', f.name, f.implement_org, f.service_content)
WHERE i.title IS NULL;
UPDATE approval_instance i
JOIN approval_coordination_form c ON c.instance_id = i.id
SET i.title = c.title,
i.search_text = CONCAT_WS(' ', c.title, c.content, c.remark)
WHERE i.title IS NULL;
DROP PROCEDURE IF EXISTS approval_phase2_add_column;
DROP PROCEDURE IF EXISTS approval_phase2_add_index;