sync: local modifications to workflow_approval
- Updated all model JSON files: approval_instance, approval_step, approval_task, approval_workflow - Updated init.py, mysql.ddl.sql, mobile_base.ui - Added __init__.py - Added API files: instance CRUD, step CRUD, task approve/reject/list, workflow CRUD - Added UI files: base.ui, approval_instance.ui, approval_task.ui, approval_workflow.ui
This commit is contained in:
parent
91270d6ced
commit
5472211972
@ -1,137 +1,27 @@
|
||||
{
|
||||
"summary": [
|
||||
{
|
||||
"name": "approval_instance",
|
||||
"title": "审批实例",
|
||||
"primary": "id",
|
||||
"catelog": "entity"
|
||||
}
|
||||
],
|
||||
"table_name": "approval_instance",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"title": "ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "主键UUID"
|
||||
},
|
||||
{
|
||||
"name": "workflow_id",
|
||||
"title": "工作流ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "关联的工作流定义"
|
||||
},
|
||||
{
|
||||
"name": "module_type",
|
||||
"title": "模块类型",
|
||||
"type": "str",
|
||||
"length": 50,
|
||||
"nullable": "no",
|
||||
"comments": "customer/opportunity/contract/financial"
|
||||
},
|
||||
{
|
||||
"name": "module_record_id",
|
||||
"title": "模块记录ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "关联的具体业务记录ID"
|
||||
},
|
||||
{
|
||||
"name": "current_step_id",
|
||||
"title": "当前步骤ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "yes",
|
||||
"comments": "当前待审批的步骤"
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"title": "状态",
|
||||
"type": "str",
|
||||
"length": 20,
|
||||
"nullable": "no",
|
||||
"comments": "pending/approved/rejected/cancelled"
|
||||
},
|
||||
{
|
||||
"name": "initiator_id",
|
||||
"title": "发起人ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "审批发起人用户ID"
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"title": "标题",
|
||||
"type": "str",
|
||||
"length": 200,
|
||||
"nullable": "no",
|
||||
"comments": "审批标题"
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"title": "描述",
|
||||
"type": "str",
|
||||
"length": 1000,
|
||||
"nullable": "yes",
|
||||
"comments": "审批详细描述"
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"title": "组织ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "多租户组织隔离"
|
||||
},
|
||||
{
|
||||
"name": "created_at",
|
||||
"title": "创建时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "no",
|
||||
"comments": "创建时间"
|
||||
},
|
||||
{
|
||||
"name": "completed_at",
|
||||
"title": "完成时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "yes",
|
||||
"comments": "完成时间"
|
||||
}
|
||||
{"name": "id", "type": "varchar(32)", "not_null": true, "comment": "主键ID"},
|
||||
{"name": "workflow_id", "type": "varchar(32)", "not_null": true, "comment": "工作流ID"},
|
||||
{"name": "business_type", "type": "varchar(50)", "not_null": true, "comment": "业务类型: contract/customer/opportunity"},
|
||||
{"name": "business_id", "type": "varchar(64)", "not_null": true, "comment": "业务记录ID"},
|
||||
{"name": "current_step", "type": "int", "comment": "当前步骤号"},
|
||||
{"name": "status", "type": "varchar(20)", "comment": "状态: pending/approved/rejected/cancelled"},
|
||||
{"name": "initiator_id", "type": "varchar(32)", "comment": "发起人ID"},
|
||||
{"name": "org_id", "type": "varchar(32)", "comment": "组织ID"},
|
||||
{"name": "initiated_at", "type": "timestamp", "comment": "发起时间"},
|
||||
{"name": "completed_at", "type": "timestamp", "comment": "完成时间"}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_instance_workflow",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["workflow_id"]
|
||||
},
|
||||
{
|
||||
"name": "idx_instance_module",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["module_type", "module_record_id"]
|
||||
},
|
||||
{
|
||||
"name": "idx_instance_status",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["status"]
|
||||
},
|
||||
{
|
||||
"name": "idx_instance_org",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["org_id"]
|
||||
}
|
||||
{"name": "idx_instance_workflow", "fields": ["workflow_id"], "type": "normal"},
|
||||
{"name": "idx_instance_business", "fields": ["business_type", "business_id"], "type": "normal", "comment": "复合索引:按业务类型和记录查询"},
|
||||
{"name": "idx_instance_status", "fields": ["status"], "type": "normal"},
|
||||
{"name": "idx_instance_initiator", "fields": ["initiator_id"], "type": "normal"}
|
||||
],
|
||||
"codes": [
|
||||
{
|
||||
"field": "status",
|
||||
"table": "appcodes",
|
||||
"valuefield": "k",
|
||||
"textfield": "v",
|
||||
"cond": "codetype='APPROVAL_STATUS'"
|
||||
}
|
||||
{"key": "pending", "name": "审批中"},
|
||||
{"key": "approved", "name": "已通过"},
|
||||
{"key": "rejected", "name": "已驳回"},
|
||||
{"key": "cancelled", "name": "已取消"}
|
||||
]
|
||||
}
|
||||
@ -1,118 +1,21 @@
|
||||
{
|
||||
"summary": [
|
||||
{
|
||||
"name": "approval_step",
|
||||
"title": "审批步骤",
|
||||
"primary": "id",
|
||||
"catelog": "entity"
|
||||
}
|
||||
],
|
||||
"table_name": "approval_step",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"title": "ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "主键UUID"
|
||||
},
|
||||
{
|
||||
"name": "workflow_id",
|
||||
"title": "工作流ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "关联的工作流"
|
||||
},
|
||||
{
|
||||
"name": "step_name",
|
||||
"title": "步骤名称",
|
||||
"type": "str",
|
||||
"length": 100,
|
||||
"nullable": "no",
|
||||
"comments": "审批步骤名称"
|
||||
},
|
||||
{
|
||||
"name": "step_order",
|
||||
"title": "步骤顺序",
|
||||
"type": "long",
|
||||
"nullable": "no",
|
||||
"comments": "步骤执行顺序"
|
||||
},
|
||||
{
|
||||
"name": "approver_type",
|
||||
"title": "审批人类型",
|
||||
"type": "str",
|
||||
"length": 20,
|
||||
"nullable": "no",
|
||||
"comments": "role/user/department/dynamic"
|
||||
},
|
||||
{
|
||||
"name": "approver_value",
|
||||
"title": "审批人值",
|
||||
"type": "str",
|
||||
"length": 100,
|
||||
"nullable": "yes",
|
||||
"comments": "角色ID/用户ID/部门ID/动态表达式"
|
||||
},
|
||||
{
|
||||
"name": "approval_type",
|
||||
"title": "审批类型",
|
||||
"type": "str",
|
||||
"length": 20,
|
||||
"nullable": "no",
|
||||
"comments": "single/multiple/sequential/parallel"
|
||||
},
|
||||
{
|
||||
"name": "timeout_hours",
|
||||
"title": "超时小时数",
|
||||
"type": "long",
|
||||
"nullable": "yes",
|
||||
"comments": "审批超时时间(小时)"
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"title": "描述",
|
||||
"type": "str",
|
||||
"length": 500,
|
||||
"nullable": "yes",
|
||||
"comments": "步骤描述"
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"title": "组织ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "多租户组织隔离"
|
||||
}
|
||||
{"name": "id", "type": "varchar(32)", "not_null": true, "comment": "主键ID"},
|
||||
{"name": "workflow_id", "type": "varchar(32)", "not_null": true, "comment": "所属工作流ID"},
|
||||
{"name": "step_name", "type": "varchar(100)", "not_null": true, "comment": "步骤名称"},
|
||||
{"name": "step_number", "type": "int", "not_null": true, "comment": "步骤顺序号"},
|
||||
{"name": "approver_role", "type": "varchar(20)", "comment": "审批角色: role/user"},
|
||||
{"name": "approver_id", "type": "varchar(32)", "comment": "审批人ID"},
|
||||
{"name": "description", "type": "varchar(500)", "comment": "步骤描述"},
|
||||
{"name": "timeout_hours", "type": "int", "comment": "超时小时数"}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_step_workflow",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["workflow_id"]
|
||||
},
|
||||
{
|
||||
"name": "idx_step_order",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["workflow_id", "step_order"]
|
||||
}
|
||||
{"name": "idx_step_workflow", "fields": ["workflow_id"], "type": "normal"},
|
||||
{"name": "idx_step_order", "fields": ["workflow_id", "step_number"], "type": "normal", "comment": "复合索引:按工作流和顺序查询"}
|
||||
],
|
||||
"codes": [
|
||||
{
|
||||
"field": "approver_type",
|
||||
"table": "appcodes",
|
||||
"valuefield": "k",
|
||||
"textfield": "v",
|
||||
"cond": "codetype='APPROVER_TYPE'"
|
||||
},
|
||||
{
|
||||
"field": "approval_type",
|
||||
"table": "appcodes",
|
||||
"valuefield": "k",
|
||||
"textfield": "v",
|
||||
"cond": "codetype='APPROVAL_TYPE'"
|
||||
}
|
||||
{"key": "role", "name": "角色审批"},
|
||||
{"key": "user", "name": "指定人审批"}
|
||||
]
|
||||
}
|
||||
@ -1,115 +1,24 @@
|
||||
{
|
||||
"summary": [
|
||||
{
|
||||
"name": "approval_task",
|
||||
"title": "审批任务",
|
||||
"primary": "id",
|
||||
"catelog": "entity"
|
||||
}
|
||||
],
|
||||
"table_name": "approval_task",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"title": "ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "主键UUID"
|
||||
},
|
||||
{
|
||||
"name": "instance_id",
|
||||
"title": "实例ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "关联的审批实例"
|
||||
},
|
||||
{
|
||||
"name": "step_id",
|
||||
"title": "步骤ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "关联的审批步骤"
|
||||
},
|
||||
{
|
||||
"name": "approver_id",
|
||||
"title": "审批人ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "具体审批人用户ID"
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"title": "状态",
|
||||
"type": "str",
|
||||
"length": 20,
|
||||
"nullable": "no",
|
||||
"comments": "pending/approved/rejected"
|
||||
},
|
||||
{
|
||||
"name": "decision",
|
||||
"title": "决策",
|
||||
"type": "str",
|
||||
"length": 1000,
|
||||
"nullable": "yes",
|
||||
"comments": "审批意见"
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"title": "组织ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "多租户组织隔离"
|
||||
},
|
||||
{
|
||||
"name": "assigned_at",
|
||||
"title": "分配时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "no",
|
||||
"comments": "任务分配时间"
|
||||
},
|
||||
{
|
||||
"name": "completed_at",
|
||||
"title": "完成时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "yes",
|
||||
"comments": "任务完成时间"
|
||||
},
|
||||
{
|
||||
"name": "due_at",
|
||||
"title": "截止时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "yes",
|
||||
"comments": "任务截止时间"
|
||||
}
|
||||
{"name": "id", "type": "varchar(32)", "not_null": true, "comment": "主键ID"},
|
||||
{"name": "instance_id", "type": "varchar(32)", "not_null": true, "comment": "所属实例ID"},
|
||||
{"name": "step_id", "type": "varchar(32)", "not_null": true, "comment": "审批步骤ID"},
|
||||
{"name": "assignee_id", "type": "varchar(32)", "comment": "审批人ID"},
|
||||
{"name": "status", "type": "varchar(20)", "comment": "状态: pending/approved/rejected"},
|
||||
{"name": "comment", "type": "varchar(1000)", "comment": "审批意见"},
|
||||
{"name": "org_id", "type": "varchar(32)", "comment": "组织ID"},
|
||||
{"name": "assigned_at", "type": "timestamp", "comment": "分配时间"},
|
||||
{"name": "completed_at", "type": "timestamp", "comment": "完成时间"}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_task_instance",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["instance_id"]
|
||||
},
|
||||
{
|
||||
"name": "idx_task_approver",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["approver_id"]
|
||||
},
|
||||
{
|
||||
"name": "idx_task_status",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["status"]
|
||||
}
|
||||
{"name": "idx_task_instance", "fields": ["instance_id"], "type": "normal"},
|
||||
{"name": "idx_task_assignee", "fields": ["assignee_id"], "type": "normal"},
|
||||
{"name": "idx_task_status", "fields": ["status"], "type": "normal"}
|
||||
],
|
||||
"codes": [
|
||||
{
|
||||
"field": "status",
|
||||
"table": "appcodes",
|
||||
"valuefield": "k",
|
||||
"textfield": "v",
|
||||
"cond": "codetype='TASK_STATUS'"
|
||||
}
|
||||
{"key": "pending", "name": "待审批"},
|
||||
{"key": "approved", "name": "已通过"},
|
||||
{"key": "rejected", "name": "已驳回"}
|
||||
]
|
||||
}
|
||||
@ -1,100 +1,24 @@
|
||||
{
|
||||
"summary": [
|
||||
{
|
||||
"name": "approval_workflow",
|
||||
"title": "审批工作流",
|
||||
"primary": "id",
|
||||
"catelog": "entity"
|
||||
}
|
||||
],
|
||||
"table_name": "approval_workflow",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"title": "ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "主键UUID"
|
||||
},
|
||||
{
|
||||
"name": "workflow_name",
|
||||
"title": "工作流名称",
|
||||
"type": "str",
|
||||
"length": 100,
|
||||
"nullable": "no",
|
||||
"comments": "审批工作流名称"
|
||||
},
|
||||
{
|
||||
"name": "module_type",
|
||||
"title": "模块类型",
|
||||
"type": "str",
|
||||
"length": 50,
|
||||
"nullable": "no",
|
||||
"comments": "关联的模块类型(customer/opportunity/contract/financial)"
|
||||
},
|
||||
{
|
||||
"name": "trigger_condition",
|
||||
"title": "触发条件",
|
||||
"type": "str",
|
||||
"length": 500,
|
||||
"nullable": "yes",
|
||||
"comments": "JSON格式的触发条件表达式"
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"title": "描述",
|
||||
"type": "str",
|
||||
"length": 500,
|
||||
"nullable": "yes",
|
||||
"comments": "工作流描述"
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"title": "组织ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"comments": "多租户组织隔离"
|
||||
},
|
||||
{
|
||||
"name": "created_at",
|
||||
"title": "创建时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "no",
|
||||
"comments": "创建时间"
|
||||
},
|
||||
{
|
||||
"name": "updated_at",
|
||||
"title": "更新时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "no",
|
||||
"comments": "更新时间"
|
||||
},
|
||||
{
|
||||
"name": "is_active",
|
||||
"title": "是否激活",
|
||||
"type": "str",
|
||||
"length": 1,
|
||||
"nullable": "no",
|
||||
"comments": "Y/N"
|
||||
}
|
||||
{"name": "id", "type": "varchar(32)", "not_null": true, "comment": "主键ID"},
|
||||
{"name": "name", "type": "varchar(100)", "not_null": true, "comment": "工作流名称"},
|
||||
{"name": "module", "type": "varchar(50)", "not_null": true, "comment": "所属模块"},
|
||||
{"name": "trigger_event", "type": "varchar(100)", "comment": "触发事件"},
|
||||
{"name": "description", "type": "text", "comment": "描述"},
|
||||
{"name": "org_id", "type": "varchar(32)", "comment": "组织ID"},
|
||||
{"name": "status", "type": "varchar(20)", "default": "Y", "comment": "状态 Y-启用 N-禁用"},
|
||||
{"name": "created_at", "type": "timestamp", "comment": "创建时间"},
|
||||
{"name": "updated_at", "type": "timestamp", "comment": "更新时间"}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_workflow_org",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["org_id"]
|
||||
},
|
||||
{
|
||||
"name": "idx_workflow_module",
|
||||
"idxtype": "index",
|
||||
"idxfields": ["module_type"]
|
||||
},
|
||||
{
|
||||
"name": "uk_workflow_name_org",
|
||||
"idxtype": "unique",
|
||||
"idxfields": ["workflow_name", "org_id"]
|
||||
}
|
||||
{"name": "idx_workflow_module", "fields": ["module"], "type": "normal"},
|
||||
{"name": "idx_workflow_org", "fields": ["org_id"], "type": "normal"},
|
||||
{"name": "idx_workflow_status", "fields": ["status"], "type": "normal"}
|
||||
],
|
||||
"codes": []
|
||||
"codes": [
|
||||
{"key": "contract_approval", "name": "合同审批"},
|
||||
{"key": "customer_approval", "name": "客户审批"},
|
||||
{"key": "opportunity_approval", "name": "商机审批"}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
-- Table from approval_instance.json
|
||||
CREATE TABLE IF NOT EXISTS `approval_instance` (
|
||||
`id` VARCHAR(32) NOT NULL COMMENT '主键UUID',
|
||||
`workflow_id` VARCHAR(32) NOT NULL COMMENT '关联的工作流定义',
|
||||
`module_type` VARCHAR(50) NOT NULL COMMENT 'customer/opportunity/contract/financial',
|
||||
`module_record_id` VARCHAR(32) NOT NULL COMMENT '关联的具体业务记录ID',
|
||||
`current_step_id` VARCHAR(32) COMMENT '当前待审批的步骤',
|
||||
`status` VARCHAR(20) NOT NULL COMMENT 'pending/approved/rejected/cancelled',
|
||||
`initiator_id` VARCHAR(32) NOT NULL COMMENT '审批发起人用户ID',
|
||||
`title` VARCHAR(200) NOT NULL COMMENT '审批标题',
|
||||
`description` VARCHAR(1000) COMMENT '审批详细描述',
|
||||
`org_id` VARCHAR(32) NOT NULL COMMENT '多租户组织隔离',
|
||||
`created_at` TIMESTAMP NOT NULL COMMENT '创建时间',
|
||||
`completed_at` TIMESTAMP COMMENT '完成时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='审批实例';
|
||||
|
||||
CREATE INDEX `idx_instance_workflow` ON `approval_instance` (`workflow_id`);
|
||||
CREATE INDEX `idx_instance_module` ON `approval_instance` (`module_type`, `module_record_id`);
|
||||
CREATE INDEX `idx_instance_status` ON `approval_instance` (`status`);
|
||||
CREATE INDEX `idx_instance_org` ON `approval_instance` (`org_id`);
|
||||
|
||||
-- Table from approval_step.json
|
||||
CREATE TABLE IF NOT EXISTS `approval_step` (
|
||||
`id` VARCHAR(32) NOT NULL COMMENT '主键UUID',
|
||||
`workflow_id` VARCHAR(32) NOT NULL COMMENT '关联的工作流',
|
||||
`step_name` VARCHAR(100) NOT NULL COMMENT '审批步骤名称',
|
||||
`step_order` INT NOT NULL COMMENT '步骤执行顺序',
|
||||
`approver_type` VARCHAR(20) NOT NULL COMMENT 'role/user/department/dynamic',
|
||||
`approver_value` VARCHAR(100) COMMENT '角色ID/用户ID/部门ID/动态表达式',
|
||||
`approval_type` VARCHAR(20) NOT NULL COMMENT 'single/multiple/sequential/parallel',
|
||||
`timeout_hours` INT COMMENT '审批超时时间(小时)',
|
||||
`description` VARCHAR(500) COMMENT '步骤描述',
|
||||
`org_id` VARCHAR(32) NOT NULL COMMENT '多租户组织隔离',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='审批步骤';
|
||||
|
||||
CREATE INDEX `idx_step_workflow` ON `approval_step` (`workflow_id`);
|
||||
CREATE INDEX `idx_step_order` ON `approval_step` (`workflow_id`, `step_order`);
|
||||
|
||||
-- Table from approval_task.json
|
||||
CREATE TABLE IF NOT EXISTS `approval_task` (
|
||||
`id` VARCHAR(32) NOT NULL COMMENT '主键UUID',
|
||||
`instance_id` VARCHAR(32) NOT NULL COMMENT '关联的审批实例',
|
||||
`step_id` VARCHAR(32) NOT NULL COMMENT '关联的审批步骤',
|
||||
`approver_id` VARCHAR(32) NOT NULL COMMENT '具体审批人用户ID',
|
||||
`status` VARCHAR(20) NOT NULL COMMENT 'pending/approved/rejected',
|
||||
`decision` VARCHAR(1000) COMMENT '审批意见',
|
||||
`org_id` VARCHAR(32) NOT NULL COMMENT '多租户组织隔离',
|
||||
`assigned_at` TIMESTAMP NOT NULL COMMENT '任务分配时间',
|
||||
`completed_at` TIMESTAMP COMMENT '任务完成时间',
|
||||
`due_at` TIMESTAMP COMMENT '任务截止时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='审批任务';
|
||||
|
||||
CREATE INDEX `idx_task_instance` ON `approval_task` (`instance_id`);
|
||||
CREATE INDEX `idx_task_approver` ON `approval_task` (`approver_id`);
|
||||
CREATE INDEX `idx_task_status` ON `approval_task` (`status`);
|
||||
|
||||
-- Table from approval_workflow.json
|
||||
CREATE TABLE IF NOT EXISTS `approval_workflow` (
|
||||
`id` VARCHAR(32) NOT NULL COMMENT '主键UUID',
|
||||
`workflow_name` VARCHAR(100) NOT NULL COMMENT '审批工作流名称',
|
||||
`module_type` VARCHAR(50) NOT NULL COMMENT '关联的模块类型(customer/opportunity/contract/financial)',
|
||||
`trigger_condition` VARCHAR(500) COMMENT 'JSON格式的触发条件表达式',
|
||||
`description` VARCHAR(500) COMMENT '工作流描述',
|
||||
`org_id` VARCHAR(32) NOT NULL COMMENT '多租户组织隔离',
|
||||
`created_at` TIMESTAMP NOT NULL COMMENT '创建时间',
|
||||
`updated_at` TIMESTAMP NOT NULL COMMENT '更新时间',
|
||||
`is_active` VARCHAR(1) NOT NULL COMMENT 'Y/N',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='审批工作流';
|
||||
|
||||
CREATE INDEX `idx_workflow_org` ON `approval_workflow` (`org_id`);
|
||||
CREATE INDEX `idx_workflow_module` ON `approval_workflow` (`module_type`);
|
||||
CREATE UNIQUE INDEX `uk_workflow_name_org` ON `approval_workflow` (`workflow_name`, `org_id`);
|
||||
1
workflow_approval/__init__.py
Normal file
1
workflow_approval/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# Workflow Approval Module
|
||||
@ -1,6 +1,14 @@
|
||||
from ahserver.serverenv import ServerEnv
|
||||
from appPublic.worker import awaitify
|
||||
from .core import WorkflowCore
|
||||
from sqlor.dbpools import DBPools
|
||||
|
||||
|
||||
def get_workflow_dbname():
|
||||
"""获取workflow_approval模块使用的数据库名"""
|
||||
env = ServerEnv()
|
||||
return env.get_module_dbname('workflow_approval')
|
||||
|
||||
|
||||
def load_workflow_approval():
|
||||
"""加载跨模块审批流程模块"""
|
||||
@ -8,8 +16,10 @@ def load_workflow_approval():
|
||||
|
||||
# 创建核心实例的工厂函数
|
||||
async def create_workflow_core(org_id):
|
||||
from sqlor.dbp import getDBP
|
||||
db = await getDBP(org_id)
|
||||
return WorkflowCore(db)
|
||||
db = DBPools()
|
||||
dbname = env.get_module_dbname('workflow_approval')
|
||||
sor = await db.sqlorContext(dbname)
|
||||
return WorkflowCore(sor)
|
||||
|
||||
env.create_workflow_core = create_workflow_core
|
||||
env.create_workflow_core = create_workflow_core
|
||||
env.get_workflow_dbname = get_workflow_dbname
|
||||
60
wwwroot/api/instance_create.dspy
Normal file
60
wwwroot/api/instance_create.dspy
Normal file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Create approval instance"""
|
||||
import json, time, uuid
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
workflow_id = params_kw.get('workflow_id', '')
|
||||
module_type = params_kw.get('module_type', '')
|
||||
module_record_id = params_kw.get('module_record_id', '')
|
||||
title = params_kw.get('title', '')
|
||||
description = params_kw.get('description', '')
|
||||
|
||||
if not workflow_id or not module_type or not module_record_id or not title:
|
||||
result['options'] = {'title': 'Error', 'message': '工作流ID、模块类型、记录ID和标题不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
new_id = str(uuid.uuid4()).replace('-', '')[:32]
|
||||
now = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
org_id = '0'
|
||||
initiator_id = '0'
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
workflows = await sor.sqlExe("SELECT id FROM approval_workflow WHERE id=${id}$ AND status='Y'", {'id': workflow_id})
|
||||
if not workflows:
|
||||
result['options'] = {'title': 'Error', 'message': '工作流不存在或未激活', 'type': 'error'}
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
|
||||
first_step = await sor.sqlExe("SELECT id, step_number FROM approval_step WHERE workflow_id=${workflow_id}$ ORDER BY step_number ASC LIMIT 1", {'workflow_id': workflow_id})
|
||||
|
||||
current_step_num = first_step[0]['step_number'] if first_step else 0
|
||||
first_step_id = first_step[0]['id'] if first_step else ''
|
||||
|
||||
await sor.sqlExe("""
|
||||
INSERT INTO approval_instance (id, workflow_id, business_type, business_id, current_step, status, initiator_id, org_id, initiated_at)
|
||||
VALUES (${id}$, ${workflow_id}$, ${business_type}$, ${business_id}$, ${current_step}$, 'pending', ${initiator_id}$, ${org_id}$, ${initiated_at}$)
|
||||
""", {
|
||||
'id': new_id, 'workflow_id': workflow_id, 'business_type': module_type,
|
||||
'business_id': module_record_id, 'current_step': current_step_num,
|
||||
'initiator_id': initiator_id, 'org_id': org_id, 'initiated_at': now
|
||||
})
|
||||
|
||||
if first_step_id:
|
||||
task_id = str(uuid.uuid4()).replace('-', '')[:32]
|
||||
async with DBPools().sqlorContext(dbname) as sor2:
|
||||
await sor2.sqlExe("""
|
||||
INSERT INTO approval_task (id, instance_id, step_id, assignee_id, status, org_id, assigned_at)
|
||||
VALUES (${id}$, ${instance_id}$, ${step_id}$, ${assignee_id}$, 'pending', ${org_id}$, ${assigned_at}$)
|
||||
""", {
|
||||
'id': task_id, 'instance_id': new_id, 'step_id': first_step_id,
|
||||
'assignee_id': initiator_id,
|
||||
'org_id': org_id, 'assigned_at': now
|
||||
})
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '审批实例创建成功', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'创建失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
35
wwwroot/api/instance_list.dspy
Normal file
35
wwwroot/api/instance_list.dspy
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""List approval instances"""
|
||||
import json
|
||||
|
||||
result = {'success': False, 'rows': [], 'total': 0}
|
||||
|
||||
try:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
ns = {
|
||||
'page': int(params_kw.get('page', 1)),
|
||||
'rows': int(params_kw.get('rows', 20)),
|
||||
'sort': 'id'
|
||||
}
|
||||
sql = """
|
||||
SELECT ai.id, ai.workflow_id, aw.name as workflow_name, ai.business_type as module_type, ai.business_id as module_record_id,
|
||||
ai.current_step as current_step_id, ai.status, ai.initiator_id, ai.org_id,
|
||||
ai.initiated_at as created_at, ai.completed_at
|
||||
FROM approval_instance ai
|
||||
LEFT JOIN approval_workflow aw ON ai.workflow_id = aw.id
|
||||
"""
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
data = await sor.sqlExe(sql, ns)
|
||||
if isinstance(data, dict):
|
||||
result['total'] = data.get('total', 0)
|
||||
result['rows'] = [dict(r) for r in data.get('rows', [])]
|
||||
else:
|
||||
result['rows'] = [dict(r) for r in (data or [])]
|
||||
result['total'] = len(result['rows'])
|
||||
result['success'] = True
|
||||
except Exception as e:
|
||||
result['error'] = str(e)
|
||||
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
40
wwwroot/api/step_create.dspy
Normal file
40
wwwroot/api/step_create.dspy
Normal file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Create approval step"""
|
||||
import json, uuid
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
workflow_id = params_kw.get('workflow_id', '')
|
||||
step_name = params_kw.get('step_name', '')
|
||||
step_order = params_kw.get('step_order', '1')
|
||||
approver_type = params_kw.get('approver_type', '')
|
||||
approver_value = params_kw.get('approver_value', '')
|
||||
description = params_kw.get('description', '')
|
||||
timeout_hours = params_kw.get('timeout_hours', '')
|
||||
|
||||
if not workflow_id or not step_name:
|
||||
result['options'] = {'title': 'Error', 'message': '工作流ID和步骤名称不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
new_id = str(uuid.uuid4()).replace('-', '')[:32]
|
||||
org_id = '0'
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
await sor.sqlExe("""
|
||||
INSERT INTO approval_step (id, workflow_id, step_name, step_number, approver_role, approver_id, description, timeout_hours)
|
||||
VALUES (${id}$, ${workflow_id}$, ${step_name}$, ${step_number}$, ${approver_role}$, ${approver_id}$, ${description}$, ${timeout_hours}$)
|
||||
""", {
|
||||
'id': new_id, 'workflow_id': workflow_id, 'step_name': step_name,
|
||||
'step_number': int(step_order), 'approver_role': approver_type,
|
||||
'approver_id': approver_value,
|
||||
'description': description,
|
||||
'timeout_hours': int(timeout_hours) if timeout_hours else None
|
||||
})
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '步骤创建成功', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'创建失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
24
wwwroot/api/step_delete.dspy
Normal file
24
wwwroot/api/step_delete.dspy
Normal file
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Delete approval step"""
|
||||
import json
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
record_id = params_kw.get('id', '')
|
||||
if not record_id:
|
||||
result['options'] = {'title': 'Error', 'message': '记录ID不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
existing = await sor.sqlExe("SELECT id FROM approval_step WHERE id=${id}$", {'id': record_id})
|
||||
if not existing:
|
||||
result['options'] = {'title': 'Error', 'message': '步骤不存在', 'type': 'error'}
|
||||
else:
|
||||
await sor.sqlExe("DELETE FROM approval_step WHERE id=${id}$", {'id': record_id})
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '步骤删除成功', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'删除失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
33
wwwroot/api/step_list.dspy
Normal file
33
wwwroot/api/step_list.dspy
Normal file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""List approval steps"""
|
||||
import json
|
||||
|
||||
result = {'success': False, 'rows': [], 'total': 0}
|
||||
|
||||
try:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
workflow_id = params_kw.get('workflow_id', '')
|
||||
|
||||
sql = "SELECT id, workflow_id, step_name, step_number as step_order, approver_role as approver_type, approver_id as approver_value, description, timeout_hours FROM approval_step"
|
||||
ns = {
|
||||
'page': int(params_kw.get('page', 1)),
|
||||
'rows': int(params_kw.get('rows', 50)),
|
||||
'sort': 'id'
|
||||
}
|
||||
if workflow_id:
|
||||
ns['where'] = f"workflow_id='{workflow_id}'"
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
data = await sor.sqlExe(sql, ns)
|
||||
if isinstance(data, dict):
|
||||
result['total'] = data.get('total', 0)
|
||||
result['rows'] = [dict(r) for r in data.get('rows', [])]
|
||||
else:
|
||||
result['rows'] = [dict(r) for r in (data or [])]
|
||||
result['total'] = len(result['rows'])
|
||||
result['success'] = True
|
||||
except Exception as e:
|
||||
result['error'] = str(e)
|
||||
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
44
wwwroot/api/step_update.dspy
Normal file
44
wwwroot/api/step_update.dspy
Normal file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Update approval step"""
|
||||
import json
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
record_id = params_kw.get('id', '')
|
||||
workflow_id = params_kw.get('workflow_id', '')
|
||||
step_name = params_kw.get('step_name', '')
|
||||
step_order = params_kw.get('step_order', '1')
|
||||
approver_type = params_kw.get('approver_type', '')
|
||||
approver_value = params_kw.get('approver_value', '')
|
||||
description = params_kw.get('description', '')
|
||||
timeout_hours = params_kw.get('timeout_hours', '')
|
||||
|
||||
if not record_id:
|
||||
result['options'] = {'title': 'Error', 'message': '记录ID不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
existing = await sor.sqlExe("SELECT id FROM approval_step WHERE id=${id}$", {'id': record_id})
|
||||
if not existing:
|
||||
result['options'] = {'title': 'Error', 'message': '步骤不存在', 'type': 'error'}
|
||||
else:
|
||||
await sor.sqlExe("""
|
||||
UPDATE approval_step SET workflow_id=${workflow_id}$, step_name=${step_name}$,
|
||||
step_number=${step_number}$, approver_role=${approver_role}$, approver_id=${approver_id}$,
|
||||
description=${description}$, timeout_hours=${timeout_hours}$
|
||||
WHERE id=${id}$
|
||||
""", {
|
||||
'id': record_id, 'workflow_id': workflow_id, 'step_name': step_name,
|
||||
'step_number': int(step_order), 'approver_role': approver_type,
|
||||
'approver_id': approver_value,
|
||||
'description': description,
|
||||
'timeout_hours': int(timeout_hours) if timeout_hours else None
|
||||
})
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '步骤更新成功', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'更新失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
76
wwwroot/api/task_approve.dspy
Normal file
76
wwwroot/api/task_approve.dspy
Normal file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Approve an approval task"""
|
||||
import json, time, uuid
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
task_id = params_kw.get('id', '')
|
||||
decision = params_kw.get('decision', '')
|
||||
|
||||
if not task_id:
|
||||
result['options'] = {'title': 'Error', 'message': '任务ID不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
now = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
org_id = '0'
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
tasks = await sor.sqlExe("SELECT * FROM approval_task WHERE id=${id}$ AND status='pending'", {'id': task_id})
|
||||
if not tasks:
|
||||
result['options'] = {'title': 'Error', 'message': '任务不存在或已处理', 'type': 'error'}
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
|
||||
task = tasks[0]
|
||||
instance_id = task['instance_id']
|
||||
step_id = task['step_id']
|
||||
|
||||
await sor.sqlExe("""
|
||||
UPDATE approval_task SET status='approved', comment=${comment}$, completed_at=${completed_at}$
|
||||
WHERE id=${id}$
|
||||
""", {'id': task_id, 'comment': decision, 'completed_at': now})
|
||||
|
||||
pending = await sor.sqlExe("SELECT id FROM approval_task WHERE instance_id=${instance_id}$ AND step_id=${step_id}$ AND status='pending'", {'instance_id': instance_id, 'step_id': step_id})
|
||||
|
||||
if not pending:
|
||||
current_step_order = await sor.sqlExe("""
|
||||
SELECT step_number FROM approval_step WHERE id=${step_id}$
|
||||
""", {'step_id': step_id})
|
||||
|
||||
if current_step_order:
|
||||
order = current_step_order[0]['step_number']
|
||||
next_step = await sor.sqlExe("""
|
||||
SELECT id, approver_id FROM approval_step WHERE workflow_id=(SELECT workflow_id FROM approval_step WHERE id=${step_id}$)
|
||||
AND step_number > ${order}$ ORDER BY step_number ASC LIMIT 1
|
||||
""", {'step_id': step_id, 'order': order})
|
||||
|
||||
if next_step:
|
||||
ns = next_step[0]
|
||||
new_task_id = str(uuid.uuid4()).replace('-', '')[:32]
|
||||
await sor.sqlExe("""
|
||||
UPDATE approval_instance SET current_step=${step_id}$ WHERE id=${instance_id}$
|
||||
""", {'step_id': ns['id'], 'instance_id': instance_id})
|
||||
|
||||
await sor.sqlExe("""
|
||||
INSERT INTO approval_task (id, instance_id, step_id, assignee_id, status, org_id, assigned_at)
|
||||
VALUES (${id}$, ${instance_id}$, ${step_id}$, ${assignee_id}$, 'pending', ${org_id}$, ${assigned_at}$)
|
||||
""", {
|
||||
'id': new_task_id, 'instance_id': instance_id, 'step_id': ns['id'],
|
||||
'assignee_id': ns.get('approver_id', '0'),
|
||||
'org_id': org_id, 'assigned_at': now
|
||||
})
|
||||
else:
|
||||
await sor.sqlExe("""
|
||||
UPDATE approval_instance SET status='approved', completed_at=${completed_at}$ WHERE id=${instance_id}$
|
||||
""", {'completed_at': now, 'instance_id': instance_id})
|
||||
else:
|
||||
await sor.sqlExe("""
|
||||
UPDATE approval_instance SET status='approved', completed_at=${completed_at}$ WHERE id=${instance_id}$
|
||||
""", {'completed_at': now, 'instance_id': instance_id})
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '审批通过', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'审批失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
37
wwwroot/api/task_list.dspy
Normal file
37
wwwroot/api/task_list.dspy
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""List approval tasks"""
|
||||
import json
|
||||
|
||||
result = {'success': False, 'rows': [], 'total': 0}
|
||||
|
||||
try:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
ns = {
|
||||
'page': int(params_kw.get('page', 1)),
|
||||
'rows': int(params_kw.get('rows', 20)),
|
||||
'sort': 'assigned_at desc'
|
||||
}
|
||||
sql = """
|
||||
SELECT at.id, at.instance_id, at.step_id, at.assignee_id as approver_id, at.status, at.comment as decision,
|
||||
at.org_id, at.assigned_at, at.completed_at,
|
||||
ai.business_type as module_type, ai.business_id as module_record_id,
|
||||
ast.step_name, ast.approver_role as approver_type
|
||||
FROM approval_task at
|
||||
LEFT JOIN approval_instance ai ON at.instance_id = ai.id
|
||||
LEFT JOIN approval_step ast ON at.step_id = ast.id
|
||||
"""
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
data = await sor.sqlExe(sql, ns)
|
||||
if isinstance(data, dict):
|
||||
result['total'] = data.get('total', 0)
|
||||
result['rows'] = [dict(r) for r in data.get('rows', [])]
|
||||
else:
|
||||
result['rows'] = [dict(r) for r in (data or [])]
|
||||
result['total'] = len(result['rows'])
|
||||
result['success'] = True
|
||||
except Exception as e:
|
||||
result['error'] = str(e)
|
||||
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
40
wwwroot/api/task_reject.dspy
Normal file
40
wwwroot/api/task_reject.dspy
Normal file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Reject an approval task"""
|
||||
import json, time
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
task_id = params_kw.get('id', '')
|
||||
decision = params_kw.get('decision', '')
|
||||
|
||||
if not task_id:
|
||||
result['options'] = {'title': 'Error', 'message': '任务ID不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
now = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
tasks = await sor.sqlExe("SELECT * FROM approval_task WHERE id=${id}$ AND status='pending'", {'id': task_id})
|
||||
if not tasks:
|
||||
result['options'] = {'title': 'Error', 'message': '任务不存在或已处理', 'type': 'error'}
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
|
||||
task = tasks[0]
|
||||
instance_id = task['instance_id']
|
||||
|
||||
await sor.sqlExe("""
|
||||
UPDATE approval_task SET status='rejected', comment=${comment}$, completed_at=${completed_at}$
|
||||
WHERE id=${id}$
|
||||
""", {'id': task_id, 'comment': decision, 'completed_at': now})
|
||||
|
||||
await sor.sqlExe("""
|
||||
UPDATE approval_instance SET status='rejected', completed_at=${completed_at}$ WHERE id=${instance_id}$
|
||||
""", {'completed_at': now, 'instance_id': instance_id})
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '已拒绝', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'拒绝失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
37
wwwroot/api/workflow_create.dspy
Normal file
37
wwwroot/api/workflow_create.dspy
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Create approval workflow"""
|
||||
import json, time, uuid
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
workflow_name = params_kw.get('workflow_name', '')
|
||||
module_type = params_kw.get('module_type', '')
|
||||
trigger_condition = params_kw.get('trigger_condition', '')
|
||||
description = params_kw.get('description', '')
|
||||
is_active = params_kw.get('is_active', 'Y')
|
||||
|
||||
if not workflow_name or not module_type:
|
||||
result['options'] = {'title': 'Error', 'message': '工作流名称和模块类型不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
new_id = str(uuid.uuid4()).replace('-', '')[:32]
|
||||
now = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
org_id = '0'
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
await sor.sqlExe("""
|
||||
INSERT INTO approval_workflow (id, name, module, trigger_event, description, org_id, status, created_at, updated_at)
|
||||
VALUES (${id}$, ${name}$, ${module}$, ${trigger_event}$, ${description}$, ${org_id}$, ${status}$, ${created_at}$, ${updated_at}$)
|
||||
""", {
|
||||
'id': new_id, 'name': workflow_name, 'module': module_type,
|
||||
'trigger_event': trigger_condition, 'description': description,
|
||||
'org_id': org_id, 'status': is_active, 'created_at': now, 'updated_at': now
|
||||
})
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '工作流创建成功', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'创建失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
25
wwwroot/api/workflow_delete.dspy
Normal file
25
wwwroot/api/workflow_delete.dspy
Normal file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Delete approval workflow"""
|
||||
import json
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
record_id = params_kw.get('id', '')
|
||||
if not record_id:
|
||||
result['options'] = {'title': 'Error', 'message': '记录ID不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
existing = await sor.sqlExe("SELECT id FROM approval_workflow WHERE id=${id}$", {'id': record_id})
|
||||
if not existing:
|
||||
result['options'] = {'title': 'Error', 'message': '工作流不存在', 'type': 'error'}
|
||||
else:
|
||||
await sor.sqlExe("DELETE FROM approval_step WHERE workflow_id=${id}$", {'id': record_id})
|
||||
await sor.sqlExe("DELETE FROM approval_workflow WHERE id=${id}$", {'id': record_id})
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '工作流删除成功', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'删除失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
29
wwwroot/api/workflow_list.dspy
Normal file
29
wwwroot/api/workflow_list.dspy
Normal file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""List approval workflows"""
|
||||
import json
|
||||
|
||||
result = {'success': False, 'rows': [], 'total': 0}
|
||||
|
||||
try:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
ns = {
|
||||
'page': int(params_kw.get('page', 1)),
|
||||
'rows': int(params_kw.get('rows', 20)),
|
||||
'sort': 'id'
|
||||
}
|
||||
sql = "SELECT id, name as workflow_name, module as module_type, trigger_event as trigger_condition, description, org_id, status as is_active, created_at, updated_at FROM approval_workflow"
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
data = await sor.sqlExe(sql, ns)
|
||||
if isinstance(data, dict):
|
||||
result['total'] = data.get('total', 0)
|
||||
result['rows'] = [dict(r) for r in data.get('rows', [])]
|
||||
else:
|
||||
result['rows'] = [dict(r) for r in (data or [])]
|
||||
result['total'] = len(result['rows'])
|
||||
result['success'] = True
|
||||
except Exception as e:
|
||||
result['error'] = str(e)
|
||||
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
40
wwwroot/api/workflow_update.dspy
Normal file
40
wwwroot/api/workflow_update.dspy
Normal file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Update approval workflow"""
|
||||
import json, time
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid request', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
record_id = params_kw.get('id', '')
|
||||
workflow_name = params_kw.get('workflow_name', '')
|
||||
module_type = params_kw.get('module_type', '')
|
||||
trigger_condition = params_kw.get('trigger_condition', '')
|
||||
description = params_kw.get('description', '')
|
||||
is_active = params_kw.get('is_active', 'Y')
|
||||
|
||||
if not record_id:
|
||||
result['options'] = {'title': 'Error', 'message': '记录ID不能为空', 'type': 'error'}
|
||||
else:
|
||||
dbname = get_module_dbname('workflow_approval')
|
||||
now = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
existing = await sor.sqlExe("SELECT id FROM approval_workflow WHERE id=${id}$", {'id': record_id})
|
||||
if not existing:
|
||||
result['options'] = {'title': 'Error', 'message': '工作流不存在', 'type': 'error'}
|
||||
else:
|
||||
await sor.sqlExe("""
|
||||
UPDATE approval_workflow SET name=${name}$, module=${module}$,
|
||||
trigger_event=${trigger_event}$, description=${description}$, status=${status}$,
|
||||
updated_at=${updated_at}$ WHERE id=${id}$
|
||||
""", {
|
||||
'id': record_id, 'name': workflow_name, 'module': module_type,
|
||||
'trigger_event': trigger_condition, 'description': description,
|
||||
'status': is_active, 'updated_at': now
|
||||
})
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '工作流更新成功', 'type': 'success'}}
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': f'更新失败: {str(e)}', 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
79
wwwroot/approval_instance.ui
Normal file
79
wwwroot/approval_instance.ui
Normal file
@ -0,0 +1,79 @@
|
||||
{
|
||||
"widgettype": "Page",
|
||||
"options": {
|
||||
"title": "审批实例管理",
|
||||
"style": {"height": "100vh", "padding": "0"}
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"style": {"padding": "16px", "height": "100%"}},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"style": {"marginBottom": "16px"}},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "审批实例管理", "style": {"fontSize": "20px", "fontWeight": "bold"}}
|
||||
},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
"options": {
|
||||
"label": "发起审批",
|
||||
"style": {"backgroundColor": "#007bff", "color": "#fff", "border": "none", "padding": "8px 16px", "borderRadius": "4px", "marginLeft": "auto"},
|
||||
"onclick": "openDialog('newInstanceDialog')"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "DataViewer",
|
||||
"options": {
|
||||
"title": "审批实例",
|
||||
"data_url": "/main/workflow_approval/api/instance_list.dspy",
|
||||
"page_rows": 20,
|
||||
"row_options": {
|
||||
"fields": [
|
||||
{"name": "title", "label": "审批标题", "uitype": "text"},
|
||||
{"name": "workflow_name", "label": "工作流", "uitype": "text"},
|
||||
{"name": "module_type", "label": "模块类型", "uitype": "text"},
|
||||
{"name": "status", "label": "状态", "uitype": "text"},
|
||||
{"name": "created_at", "label": "发起时间", "uitype": "text"},
|
||||
{"name": "completed_at", "label": "完成时间", "uitype": "text"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Dialog",
|
||||
"id": "newInstanceDialog",
|
||||
"options": {
|
||||
"title": "发起审批",
|
||||
"width": 500,
|
||||
"content": {
|
||||
"widgettype": "Form",
|
||||
"id": "newInstanceForm",
|
||||
"fields": [
|
||||
{"name": "workflow_id", "label": "选择工作流", "uitype": "code", "data_url": "/main/workflow_approval/api/workflow_list.dspy", "required": true},
|
||||
{"name": "module_type", "label": "模块类型", "uitype": "code", "data": [
|
||||
{"value": "customer", "text": "客户管理"},
|
||||
{"value": "opportunity", "text": "商机管理"},
|
||||
{"value": "contract", "text": "合同管理"},
|
||||
{"value": "financial", "text": "财务管理"}
|
||||
], "required": true},
|
||||
{"name": "module_record_id", "label": "业务记录ID", "uitype": "text", "required": true},
|
||||
{"name": "title", "label": "审批标题", "uitype": "text", "required": true},
|
||||
{"name": "description", "label": "审批描述", "uitype": "textarea"}
|
||||
],
|
||||
"actions": [
|
||||
{"widgettype": "Button", "options": {"label": "取消", "onclick": "closeDialog('newInstanceDialog')"}},
|
||||
{"widgettype": "Button", "options": {"label": "提交", "style": {"backgroundColor": "#007bff", "color": "#fff"}, "onclick": "submitForm('newInstanceForm', '/main/workflow_approval/api/instance_create.dspy', 'newInstanceDialog', null)"}}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
107
wwwroot/approval_task.ui
Normal file
107
wwwroot/approval_task.ui
Normal file
@ -0,0 +1,107 @@
|
||||
{
|
||||
"widgettype": "Page",
|
||||
"options": {
|
||||
"title": "待办任务",
|
||||
"style": {"height": "100vh", "padding": "0"}
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"style": {"padding": "16px", "height": "100%"}},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "待办审批任务", "style": {"fontSize": "20px", "fontWeight": "bold", "marginBottom": "16px"}}
|
||||
},
|
||||
{
|
||||
"widgettype": "DataViewer",
|
||||
"options": {
|
||||
"title": "任务列表",
|
||||
"data_url": "/main/workflow_approval/api/task_list.dspy",
|
||||
"page_rows": 20,
|
||||
"row_options": {
|
||||
"fields": [
|
||||
{"name": "instance_title", "label": "审批事项", "uitype": "text"},
|
||||
{"name": "step_name", "label": "审批步骤", "uitype": "text"},
|
||||
{"name": "module_type", "label": "模块", "uitype": "text"},
|
||||
{"name": "status", "label": "状态", "uitype": "text"},
|
||||
{"name": "assigned_at", "label": "分配时间", "uitype": "text"},
|
||||
{"name": "due_at", "label": "截止时间", "uitype": "text"}
|
||||
]
|
||||
},
|
||||
"row_actions": [
|
||||
{
|
||||
"label": "审批",
|
||||
"onclick": "openDialog('approveDialog'); setDialogField('approveDialog', 'task_id', '${id}'); setDialogField('approveDialog', 'task_title', '${instance_title}')",
|
||||
"condition": "status == 'pending'"
|
||||
},
|
||||
{
|
||||
"label": "查看详情",
|
||||
"onclick": "openDialog('taskDetailDialog'); setDialogField('taskDetailDialog', 'task_id', '${id}'); setDialogField('taskDetailDialog', 'task_title', '${instance_title}'); setDialogField('taskDetailDialog', 'step_name', '${step_name}'); setDialogField('taskDetailDialog', 'assigned_at', '${assigned_at}'); setDialogField('taskDetailDialog', 'due_at', '${due_at}'); setDialogField('taskDetailDialog', 'approval_type', '${approval_type}')"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Dialog",
|
||||
"id": "approveDialog",
|
||||
"options": {
|
||||
"title": "审批处理",
|
||||
"width": 500,
|
||||
"content": {
|
||||
"widgettype": "Form",
|
||||
"id": "approveForm",
|
||||
"fields": [
|
||||
{"name": "task_id", "label": "任务ID", "uitype": "hidden"},
|
||||
{"name": "task_title", "label": "审批事项", "uitype": "text", "readonly": true},
|
||||
{"name": "decision", "label": "审批意见", "uitype": "textarea"}
|
||||
],
|
||||
"actions": [
|
||||
{"widgettype": "Button", "options": {"label": "取消", "onclick": "closeDialog('approveDialog')"}},
|
||||
{"widgettype": "Button", "options": {"label": "拒绝", "style": {"backgroundColor": "#dc3545", "color": "#fff"}, "onclick": "submitForm('approveForm', '/main/workflow_approval/api/task_reject.dspy', 'approveDialog', null)"}},
|
||||
{"widgettype": "Button", "options": {"label": "批准", "style": {"backgroundColor": "#28a745", "color": "#fff"}, "onclick": "submitForm('approveForm', '/main/workflow_approval/api/task_approve.dspy', 'approveDialog', null)"}}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Dialog",
|
||||
"id": "taskDetailDialog",
|
||||
"options": {
|
||||
"title": "任务详情",
|
||||
"width": 500,
|
||||
"content": {
|
||||
"widgettype": "VBox",
|
||||
"options": {"gap": 8},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Text", "id": "detail_title", "options": {"text": ""}},
|
||||
{"widgettype": "Divider", "options": {}},
|
||||
{"widgettype": "HBox", "options": {"gap": 8}, "subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "步骤: ", "style": {"fontWeight": "bold"}}},
|
||||
{"widgettype": "Text", "id": "detail_step", "options": {"text": ""}}
|
||||
]},
|
||||
{"widgettype": "HBox", "options": {"gap": 8}, "subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "审批类型: ", "style": {"fontWeight": "bold"}}},
|
||||
{"widgettype": "Text", "id": "detail_type", "options": {"text": ""}}
|
||||
]},
|
||||
{"widgettype": "HBox", "options": {"gap": 8}, "subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "分配时间: ", "style": {"fontWeight": "bold"}}},
|
||||
{"widgettype": "Text", "id": "detail_assigned", "options": {"text": ""}}
|
||||
]},
|
||||
{"widgettype": "HBox", "options": {"gap": 8}, "subwidgets": [
|
||||
{"widgettype": "Text", "options": {"text": "截止时间: ", "style": {"fontWeight": "bold"}}},
|
||||
{"widgettype": "Text", "id": "detail_due", "options": {"text": ""}}
|
||||
]},
|
||||
{"widgettype": "Divider", "options": {}},
|
||||
{"widgettype": "HBox", "options": {"gap": 8}, "subwidgets": [
|
||||
{"widgettype": "Button", "options": {"label": "关闭", "onclick": "closeDialog('taskDetailDialog')"}},
|
||||
{"widgettype": "Button", "options": {"label": "去审批", "style": {"backgroundColor": "#007bff", "color": "#fff"}, "onclick": "closeDialog('taskDetailDialog'); openDialog('approveDialog'); setDialogField('approveDialog', 'task_id', getDialogField('taskDetailDialog', 'task_id')); setDialogField('approveDialog', 'task_title', getDialogField('taskDetailDialog', 'task_title'))"}}
|
||||
]}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
wwwroot/approval_workflow.ui
Normal file
115
wwwroot/approval_workflow.ui
Normal file
@ -0,0 +1,115 @@
|
||||
{
|
||||
"widgettype": "Page",
|
||||
"options": {
|
||||
"title": "审批工作流管理",
|
||||
"style": {"height": "100vh", "padding": "0"}
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"style": {"padding": "16px", "height": "100%"}},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"style": {"marginBottom": "16px"}},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "审批工作流管理", "style": {"fontSize": "20px", "fontWeight": "bold"}}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "DataViewer",
|
||||
"options": {
|
||||
"title": "工作流列表",
|
||||
"data_url": "/main/workflow_approval/api/workflow_list.dspy",
|
||||
"page_rows": 20,
|
||||
"editable": {
|
||||
"new_data_url": "/main/workflow_approval/api/workflow_create.dspy",
|
||||
"update_data_url": "/main/workflow_approval/api/workflow_update.dspy",
|
||||
"delete_data_url": "/main/workflow_approval/api/workflow_delete.dspy",
|
||||
"form_cheight": 10,
|
||||
"fields": [
|
||||
{"name": "workflow_name", "label": "工作流名称", "uitype": "text", "required": true},
|
||||
{"name": "module_type", "label": "模块类型", "uitype": "code", "data": [
|
||||
{"value": "customer", "text": "客户管理"},
|
||||
{"value": "opportunity", "text": "商机管理"},
|
||||
{"value": "contract", "text": "合同管理"},
|
||||
{"value": "financial", "text": "财务管理"}
|
||||
], "required": true},
|
||||
{"name": "trigger_condition", "label": "触发条件", "uitype": "textarea"},
|
||||
{"name": "description", "label": "描述", "uitype": "textarea"},
|
||||
{"name": "is_active", "label": "是否激活", "uitype": "code", "data": [
|
||||
{"value": "Y", "text": "是"},
|
||||
{"value": "N", "text": "否"}
|
||||
], "value": "Y"}
|
||||
]
|
||||
},
|
||||
"row_options": {
|
||||
"fields": [
|
||||
{"name": "workflow_name", "label": "工作流名称", "uitype": "text"},
|
||||
{"name": "module_type", "label": "模块类型", "uitype": "text"},
|
||||
{"name": "description", "label": "描述", "uitype": "text"},
|
||||
{"name": "is_active", "label": "状态", "uitype": "text"},
|
||||
{"name": "created_at", "label": "创建时间", "uitype": "text"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Divider",
|
||||
"options": {"style": {"margin": "20px 0"}}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "审批步骤配置", "style": {"fontSize": "16px", "fontWeight": "bold", "marginBottom": "12px"}}
|
||||
},
|
||||
{
|
||||
"widgettype": "DataViewer",
|
||||
"options": {
|
||||
"title": "审批步骤",
|
||||
"data_url": "/main/workflow_approval/api/step_list.dspy",
|
||||
"page_rows": 20,
|
||||
"editable": {
|
||||
"new_data_url": "/main/workflow_approval/api/step_create.dspy",
|
||||
"update_data_url": "/main/workflow_approval/api/step_update.dspy",
|
||||
"delete_data_url": "/main/workflow_approval/api/step_delete.dspy",
|
||||
"form_cheight": 10,
|
||||
"fields": [
|
||||
{"name": "workflow_id", "label": "所属工作流", "uitype": "code", "data_url": "/main/workflow_approval/api/workflow_list.dspy", "required": true},
|
||||
{"name": "step_name", "label": "步骤名称", "uitype": "text", "required": true},
|
||||
{"name": "step_order", "label": "步骤顺序", "uitype": "number", "required": true},
|
||||
{"name": "approver_type", "label": "审批人类型", "uitype": "code", "data": [
|
||||
{"value": "role", "text": "角色"},
|
||||
{"value": "user", "text": "用户"},
|
||||
{"value": "department", "text": "部门"},
|
||||
{"value": "dynamic", "text": "动态"}
|
||||
], "required": true},
|
||||
{"name": "approver_value", "label": "审批人值", "uitype": "text"},
|
||||
{"name": "approval_type", "label": "审批类型", "uitype": "code", "data": [
|
||||
{"value": "single", "text": "单人审批"},
|
||||
{"value": "multiple", "text": "多人审批"},
|
||||
{"value": "sequential", "text": "顺序审批"},
|
||||
{"value": "parallel", "text": "并行审批"}
|
||||
], "required": true},
|
||||
{"name": "timeout_hours", "label": "超时时间(小时)", "uitype": "number"},
|
||||
{"name": "description", "label": "描述", "uitype": "textarea"}
|
||||
]
|
||||
},
|
||||
"row_options": {
|
||||
"fields": [
|
||||
{"name": "workflow_id", "label": "工作流ID", "uitype": "text"},
|
||||
{"name": "step_name", "label": "步骤名称", "uitype": "text"},
|
||||
{"name": "step_order", "label": "顺序", "uitype": "text"},
|
||||
{"name": "approver_type", "label": "审批人类型", "uitype": "text"},
|
||||
{"name": "approval_type", "label": "审批类型", "uitype": "text"},
|
||||
{"name": "timeout_hours", "label": "超时(小时)", "uitype": "text"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
70
wwwroot/base.ui
Normal file
70
wwwroot/base.ui
Normal file
@ -0,0 +1,70 @@
|
||||
{
|
||||
"widgettype": "Page",
|
||||
"options": {
|
||||
"title": "审批管理",
|
||||
"style": {"height": "100vh", "overflow": "hidden"}
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "HBox",
|
||||
"options": {"style": {"height": "100vh"}},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Drawer",
|
||||
"options": {"width": 220, "variant": "permanent", "style": {"backgroundColor": "#1a1a2e"}},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"gap": 4, "style": {"padding": "8px"}},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "审批管理",
|
||||
"style": {"color": "#fff", "fontSize": "18px", "fontWeight": "bold", "padding": "12px 8px"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Divider",
|
||||
"options": {"style": {"backgroundColor": "#333", "margin": "8px 0"}}
|
||||
},
|
||||
{
|
||||
"widgettype": "ListTile",
|
||||
"options": {
|
||||
"leading": "account_tree",
|
||||
"title": "工作流配置",
|
||||
"style": {"color": "#ccc"},
|
||||
"onclick": "navigate('main/workflow_approval/approval_workflow.ui')"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "ListTile",
|
||||
"options": {
|
||||
"leading": "assignment",
|
||||
"title": "审批实例",
|
||||
"style": {"color": "#ccc"},
|
||||
"onclick": "navigate('main/workflow_approval/approval_instance.ui')"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "ListTile",
|
||||
"options": {
|
||||
"leading": "assignment_turned_in",
|
||||
"title": "待办任务",
|
||||
"style": {"color": "#ccc"},
|
||||
"onclick": "navigate('main/workflow_approval/approval_task.ui')"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "Frame",
|
||||
"id": "workflow_frame",
|
||||
"options": {"flex": 1, "src": "main/workflow_approval/approval_workflow.ui"}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -40,7 +40,7 @@
|
||||
{
|
||||
"widgettype": "TabPanel",
|
||||
"options": {
|
||||
"tabs": [
|
||||
"items": [
|
||||
{
|
||||
"title": "待我审批",
|
||||
"content": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user