Use this as the starting point for a code-first business workflow migration. Replace all xxx_* placeholders and fixed seed IDs before committing.
-- Business approval workflow: xxx_order.
CREATE TABLE IF NOT EXISTS `xxx_order` (
`id` bigint NOT NULL COMMENT '主键ID',
`tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
`order_no` varchar(64) NOT NULL COMMENT '单据编号',
`title` varchar(128) NOT NULL COMMENT '单据标题',
`amount_cent` bigint NOT NULL DEFAULT 0 COMMENT '金额,单位分',
`status` varchar(32) NOT NULL DEFAULT 'DRAFT' COMMENT '业务状态',
`applicant_id` bigint DEFAULT NULL COMMENT '申请人ID',
`applicant_name` varchar(64) DEFAULT NULL COMMENT '申请人名称',
`applicant_dept_id` bigint DEFAULT NULL COMMENT '申请部门ID',
`applicant_dept_name` varchar(128) DEFAULT NULL COMMENT '申请部门名称',
`business_key` varchar(128) DEFAULT NULL COMMENT '流程业务Key',
`process_instance_id` varchar(128) DEFAULT NULL COMMENT '流程实例ID',
`approver_id` bigint DEFAULT NULL COMMENT '审批人ID',
`approver_remark` varchar(500) DEFAULT NULL COMMENT '审批意见',
`reject_reason` varchar(500) DEFAULT NULL COMMENT '驳回/取消原因',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`create_by` bigint DEFAULT NULL COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`update_by` bigint DEFAULT NULL COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_xxx_order_no` (`tenant_id`, `order_no`),
UNIQUE KEY `uk_xxx_order_business_key` (`tenant_id`, `business_key`),
KEY `idx_xxx_order_status` (`tenant_id`, `status`, `update_time`),
KEY `idx_xxx_order_process` (`tenant_id`, `process_instance_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='xxx审批业务表';
INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
FROM (
SELECT 1 tenant_id, 'xxx审批状态' dict_name, 'xxx_order_status' dict_type, 1 dict_status, 'xxx审批业务状态' remark
) seed
WHERE NOT EXISTS (
SELECT 1 FROM sys_dict_type t
WHERE t.tenant_id = seed.tenant_id AND t.dict_type = seed.dict_type
);
INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class,
is_default, dict_status, remark, create_time, update_time)
SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL,
seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
FROM (
SELECT 1 tenant_id, 1 dict_sort, '草稿' dict_label, 'DRAFT' dict_value, 'xxx_order_status' dict_type, 'default' list_class, 'Y' is_default, '草稿' remark
UNION ALL SELECT 1, 2, '审批中', 'IN_PROCESS', 'xxx_order_status', 'info', 'N', '审批中'
UNION ALL SELECT 1, 3, '待修改', 'NEED_MODIFY', 'xxx_order_status', 'warning', 'N', '被驳回后等待申请人修改'
UNION ALL SELECT 1, 4, '已通过', 'APPROVED', 'xxx_order_status', 'success', 'N', '审批通过'
UNION ALL SELECT 1, 5, '已拒绝', 'REJECTED', 'xxx_order_status', 'error', 'N', '流程拒绝结束'
UNION ALL SELECT 1, 6, '已取消', 'CANCELED', 'xxx_order_status', 'default', 'N', '流程取消'
) seed
WHERE NOT EXISTS (
SELECT 1 FROM sys_dict_data d
WHERE d.tenant_id = seed.tenant_id
AND d.dict_type = seed.dict_type
AND d.dict_value = seed.dict_value
);
SET @app_center_root_id := (
SELECT id FROM sys_resource
WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 1
AND parent_id = 0 AND resource_name = '应用中心'
ORDER BY id LIMIT 1
);
SET @business_parent_id := COALESCE(@app_center_root_id, 0);
INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
update_by, update_time, create_dept, client_code)
SELECT 1, 'xxx审批', @business_parent_id, 2, 10, '/business/xxx-order', 'business/xxx-order', 0,
0, NULL, '_self', 0, 1, 1, 'business:xxxOrder:list', 'ionicons5:DocumentTextOutline',
NULL, NULL, 0, 0, NULL, 'xxx审批业务页面', 1, NOW(), 1, NOW(), 1, 'pc'
WHERE NOT EXISTS (
SELECT 1 FROM sys_resource
WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/business/xxx-order'
);
SET @xxx_menu_id := (
SELECT id FROM sys_resource
WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/business/xxx-order'
ORDER BY id LIMIT 1
);
INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
update_by, update_time, create_dept, client_code)
SELECT seed.tenant_id, seed.resource_name, @xxx_menu_id, 3, seed.sort, NULL, NULL, 0,
0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
FROM (
SELECT 1 tenant_id, 'xxx查询' resource_name, 1 sort, 'business:xxxOrder:query' perms, 'xxx查询按钮权限' remark
UNION ALL SELECT 1, 'xxx新增', 2, 'business:xxxOrder:add', 'xxx新增按钮权限'
UNION ALL SELECT 1, 'xxx修改', 3, 'business:xxxOrder:edit', 'xxx修改按钮权限'
UNION ALL SELECT 1, 'xxx删除', 4, 'business:xxxOrder:remove', 'xxx删除按钮权限'
UNION ALL SELECT 1, 'xxx提交审批', 5, 'business:xxxOrder:submit', 'xxx提交审批按钮权限'
UNION ALL SELECT 1, 'xxx初始化流程', 6, 'business:xxxOrder:initFlow', 'xxx流程初始化按钮权限'
) seed
WHERE @xxx_menu_id IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM sys_resource r
WHERE r.tenant_id = seed.tenant_id
AND r.client_code = 'pc'
AND r.resource_type = 3
AND r.perms = seed.perms
);
SET @admin_role_id := (
SELECT id FROM sys_role
WHERE tenant_id = 1 AND role_key = 'admin'
ORDER BY id LIMIT 1
);
INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
SELECT 1, @admin_role_id, target.id, NOW()
FROM sys_resource target
WHERE @admin_role_id IS NOT NULL
AND target.tenant_id = 1
AND target.client_code = 'pc'
AND (
target.path = '/business/xxx-order'
OR target.perms LIKE 'business:xxxOrder:%'
)
AND NOT EXISTS (
SELECT 1 FROM sys_role_resource exists_rr
WHERE exists_rr.tenant_id = 1
AND exists_rr.role_id = @admin_role_id
AND exists_rr.resource_id = target.id
);
INSERT INTO ai_business_suite (id, tenant_id, parent_id, suite_code, suite_name, icon, description, status,
sort_order, options, create_by, create_time, create_dept, update_by, update_time)
SELECT 1910000000000010001, 1, NULL, 'XXX_SUITE', 'xxx业务', 'ionicons5:BriefcaseOutline',
'xxx审批业务域', 1, 40,
'{"codeApp":true,"scenario":"xxx_order_flow"}',
1, NOW(), 1, 1, NOW()
WHERE NOT EXISTS (
SELECT 1 FROM ai_business_suite
WHERE tenant_id = 1 AND suite_code = 'XXX_SUITE'
);
INSERT INTO ai_business_object (id, tenant_id, suite_code, object_code, object_name, object_type, model_id,
model_code, display_field, icon, description, status, sort_order, options,
design_status, config_key, last_publish_time, last_publish_version,
designer_options, create_by, create_time, create_dept, update_by, update_time)
SELECT 1910000000000010002, 1, 'XXX_SUITE', 'xxx_order', 'xxx申请', 'TRANSACTION', NULL,
NULL, 'title', 'ionicons5:DocumentTextOutline',
'代码实现的xxx审批业务,流程设计器维护节点表单和字段权限', 1, 10,
'{"codeApp":true,"businessType":"xxx_order","flowModelKey":"xxx_order_approval"}',
'PUBLISHED', NULL, NOW(), 1,
'{"codeApp":true,"documentManaged":false,"defaultPanel":"flow-app"}',
1, NOW(), 1, 1, NOW()
WHERE NOT EXISTS (
SELECT 1 FROM ai_business_object
WHERE tenant_id = 1 AND suite_code = 'XXX_SUITE' AND object_code = 'xxx_order'
);
SET @xxx_object_id := (
SELECT id FROM ai_business_object
WHERE tenant_id = 1 AND suite_code = 'XXX_SUITE' AND object_code = 'xxx_order'
LIMIT 1
);
INSERT INTO ai_business_app (id, tenant_id, app_code, app_name, app_type, suite_code, object_code, entry_mode,
entry_url, config_key, icon, description, status, sort_order, options, create_by,
create_time, create_dept, update_by, update_time)
SELECT 1910000000000010003, 1, 'XXX_ORDER_APPROVAL', 'xxx审批', 'BUSINESS',
'XXX_SUITE', 'xxx_order', 'ROUTE',
'/business/xxx-order', NULL, 'ionicons5:ClipboardOutline',
'打开xxx审批业务页面', 1, 10,
'{"codeApp":true,"flowConfigUrl":"/app-center/object/xxx_order/designer?panel=flow-app&codeApp=1&name=xxx申请"}',
1, NOW(), 1, 1, NOW()
WHERE @xxx_object_id IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM ai_business_app
WHERE tenant_id = 1 AND app_code = 'XXX_ORDER_APPROVAL'
);
INSERT INTO ai_business_binding (id, tenant_id, target_type, target_id, target_code, binding_type, binding_key,
binding_name, binding_config, description, status, sort_order, create_by,
create_time, create_dept, update_by, update_time)
SELECT 1910000000000010004, 1, 'OBJECT', @xxx_object_id, 'xxx_order', 'FLOW', 'xxx_order_approval',
'xxx审批流程',
'{
"flowModelKey":"xxx_order_approval",
"flowModelName":"xxx审批流程",
"titleTemplate":"xxx审批-{orderNo}",
"startMode":"MANUAL",
"businessBinding":{
"mode":"ADAPTER",
"primaryKeyField":"id",
"tenantField":"tenant_id",
"titleField":"title",
"statusField":"status",
"ownerField":"applicantId"
},
"variableMapping":[
{"formField":"businessKey","flowVariable":"businessKey","label":"业务Key"},
{"formField":"orderNo","flowVariable":"orderNo","label":"单据编号"},
{"formField":"title","flowVariable":"title","label":"单据标题"},
{"formField":"amountCent","flowVariable":"amountCent","label":"金额分"},
{"formField":"approverId","flowVariable":"approverId","label":"审批人"}
],
"nodeForms":[],
"conditionFlows":[],
"options":{"codeApp":true,"businessKeyPattern":"xxx_order:{recordId}"}
}',
'xxx代码业务默认流程绑定。节点表单与字段权限以BPMN节点配置为准,nodeForms仅作兼容兜底。',
1, 1, 1, NOW(), 1, 1, NOW()
WHERE @xxx_object_id IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM ai_business_binding
WHERE tenant_id = 1
AND target_type = 'OBJECT'
AND target_code = 'xxx_order'
AND binding_type = 'FLOW'
AND binding_key = 'xxx_order_approval'
);
V<next_version>__<lower_snake_description>.sql.forge_schema_history.tenant_id = 1 for built-in business/config data.${...} in SQL string literals because Flyway may parse placeholders. Use {field} or CONCAT('$', '{field}') when a literal ${field} is unavoidable.