815 lines
24 KiB
Markdown
815 lines
24 KiB
Markdown
# Warm-Flow 工作流开发规范
|
||
|
||
## 🎯 概述
|
||
|
||
本规范基于 **warm-flow** 工作流框架,适用于所有工作流相关的开发任务。warm-flow 是 dromara 社区开源的轻量级工作流引擎,与 Spring Boot 和若依框架无缝集成。
|
||
|
||
---
|
||
|
||
## 🔧 技术栈与配置
|
||
|
||
### 核心依赖
|
||
|
||
```xml
|
||
<!-- warm-flow核心依赖 -->
|
||
<dependency>
|
||
<groupId>org.dromara.warm</groupId>
|
||
<artifactId>warm-flow-mybatis-plus-sb3-starter</artifactId>
|
||
</dependency>
|
||
<dependency>
|
||
<groupId>org.dromara.warm</groupId>
|
||
<artifactId>warm-flow-plugin-ui-sb-web</artifactId>
|
||
</dependency>
|
||
```
|
||
|
||
### 配置开关
|
||
|
||
```yaml
|
||
# application.yml
|
||
warm-flow:
|
||
enabled: true # 设置为 true 时,启用工作流功能
|
||
```
|
||
|
||
### 条件开启注解
|
||
|
||
```java
|
||
// 所有工作流相关类必须添加此注解
|
||
@ConditionalOnEnable
|
||
@Service / @Controller / @Component
|
||
public class WorkflowRelatedClass {
|
||
// 实现逻辑
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🏗️ 后端开发规范
|
||
|
||
### 1. 实体类规范
|
||
|
||
#### 1.1 BO 类规范
|
||
|
||
```java
|
||
@Data
|
||
@EqualsAndHashCode(callSuper = true)
|
||
public class TestLeaveBo extends BaseEntity {
|
||
private Long id;
|
||
private String leaveType;
|
||
private String startDate;
|
||
private String endDate;
|
||
private Integer leaveDays;
|
||
private String remark;
|
||
private String status; // 工作流状态字段(必需)
|
||
}
|
||
```
|
||
|
||
#### 1.2 VO 类规范(🔴 强制性)
|
||
|
||
```java
|
||
@Data
|
||
@ExcelIgnoreUnannotated
|
||
public class TestLeaveVo {
|
||
// 业务字段
|
||
private Long id;
|
||
private String leaveType;
|
||
private String startDate;
|
||
private String endDate;
|
||
private Integer leaveDays;
|
||
private String remark;
|
||
private String status;
|
||
|
||
// 🔴 基础字段(必须包含,避免MyBatis映射错误)
|
||
private Long createBy;
|
||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||
private Date createTime;
|
||
private Long updateBy;
|
||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||
private Date updateTime;
|
||
}
|
||
```
|
||
|
||
**⚠️ 重要提醒**: 所有工作流业务 VO 类必须包含四个基础字段,否则会出现 `Could not set property 'createBy'` 错误。
|
||
|
||
### 2. Controller 规范
|
||
|
||
```java
|
||
@ConditionalOnEnable // 🔴 必须添加
|
||
@Validated
|
||
@RequiredArgsConstructor
|
||
@RestController
|
||
@RequestMapping("/workflow/业务模块")
|
||
public class WorkflowController extends BaseController {
|
||
|
||
private final IWorkflowService workflowService;
|
||
|
||
// 🔴 所有接口必须添加权限注解
|
||
@SaCheckPermission("workflow:业务模块:list")
|
||
@GetMapping("/list")
|
||
public TableDataInfo<WorkflowVo> list(WorkflowBo bo, PageQuery pageQuery) {
|
||
return workflowService.queryPageList(bo, pageQuery);
|
||
}
|
||
|
||
@SaCheckPermission("workflow:业务模块:add")
|
||
@PostMapping()
|
||
public R<WorkflowVo> add(@Validated(AddGroup.class) @RequestBody WorkflowBo bo) {
|
||
return R.ok(workflowService.insertByBo(bo));
|
||
}
|
||
|
||
@SaCheckPermission("workflow:业务模块:edit")
|
||
@PutMapping()
|
||
public R<WorkflowVo> edit(@Validated(EditGroup.class) @RequestBody WorkflowBo bo) {
|
||
return R.ok(workflowService.updateByBo(bo));
|
||
}
|
||
|
||
@SaCheckPermission("workflow:业务模块:remove")
|
||
@DeleteMapping("/{ids}")
|
||
public R<Void> remove(@PathVariable Long[] ids) {
|
||
return toAjax(workflowService.deleteWithValidByIds(List.of(ids)));
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. Service 规范
|
||
|
||
```java
|
||
@ConditionalOnEnable // 🔴 必须添加
|
||
@Service
|
||
@RequiredArgsConstructor
|
||
public class WorkflowServiceImpl implements IWorkflowService {
|
||
|
||
private final WorkflowMapper baseMapper;
|
||
|
||
@Override
|
||
@Transactional(rollbackFor = Exception.class) // 🔴 重要操作需要事务
|
||
public WorkflowVo insertByBo(WorkflowBo bo) {
|
||
Workflow entity = BeanUtil.toBean(bo, Workflow.class);
|
||
// 🔴 新建时必须设置状态为草稿
|
||
entity.setStatus("draft");
|
||
validEntityBeforeSave(entity);
|
||
boolean flag = baseMapper.insert(entity) > 0;
|
||
if (flag) {
|
||
bo.setId(entity.getId());
|
||
return BeanUtil.toBean(entity, WorkflowVo.class);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// 其他CRUD方法...
|
||
}
|
||
```
|
||
|
||
### 4. 数据库规范
|
||
|
||
#### 4.1 业务表必需字段
|
||
|
||
```sql
|
||
-- 所有工作流业务表必须包含以下字段
|
||
CREATE TABLE workflow_business (
|
||
id BIGINT(20) NOT NULL PRIMARY KEY COMMENT '主键ID',
|
||
|
||
-- 业务字段
|
||
-- ...
|
||
|
||
-- 🔴 工作流状态字段(必需)
|
||
status VARCHAR(20) DEFAULT 'draft' COMMENT '流程状态',
|
||
|
||
-- 🔴 标准基础字段(必需)
|
||
tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户编号',
|
||
create_dept BIGINT(20) DEFAULT NULL COMMENT '创建部门',
|
||
create_by BIGINT(20) DEFAULT NULL COMMENT '创建者',
|
||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
update_by BIGINT(20) DEFAULT NULL COMMENT '更新者',
|
||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
deleted TINYINT(1) DEFAULT 0 COMMENT '删除标志'
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工作流业务表';
|
||
```
|
||
|
||
#### 4.2 工作流状态值规范
|
||
|
||
| 状态值 | 状态名称 | 说明 | 可用操作 |
|
||
| --------- | -------- | ------------ | -------------------- |
|
||
| draft | 草稿 | 新建但未提交 | 编辑、删除、提交 |
|
||
| waiting | 待审批 | 流程进行中 | 查看、撤销 |
|
||
| complete | 已完成 | 流程正常结束 | 查看 |
|
||
| cancel | 已取消 | 申请人撤销 | 编辑、删除、重新提交 |
|
||
| back | 已退回 | 审批人退回 | 编辑、删除、重新提交 |
|
||
| invalid | 已作废 | 管理员作废 | 查看 |
|
||
| terminate | 已终止 | 流程异常终止 | 查看 |
|
||
|
||
---
|
||
|
||
## 🎨 前端开发规范
|
||
|
||
### 1. 页面结构规范
|
||
|
||
#### 1.1 列表页面结构
|
||
|
||
```vue
|
||
<template>
|
||
<div class="p-2">
|
||
<!-- 搜索表单 -->
|
||
<transition
|
||
:enter-active-class="proxy?.animate.searchAnimate.enter"
|
||
:leave-active-class="proxy?.animate.searchAnimate.leave"
|
||
>
|
||
<div v-show="showSearch" class="search">
|
||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||
<!-- 搜索字段 -->
|
||
<el-form-item>
|
||
<el-button type="primary" icon="Search" @click="handleQuery">
|
||
搜索
|
||
</el-button>
|
||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
</transition>
|
||
|
||
<!-- 数据表格 -->
|
||
<el-card shadow="never">
|
||
<template #header>
|
||
<el-row :gutter="10" class="mb8">
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
v-hasPermi="['workflow:业务:add']"
|
||
type="primary"
|
||
plain
|
||
icon="Plus"
|
||
@click="handleAdd"
|
||
>
|
||
新增
|
||
</el-button>
|
||
</el-col>
|
||
</el-row>
|
||
</template>
|
||
|
||
<el-table v-loading="loading" border :data="dataList">
|
||
<el-table-column type="selection" width="55" align="center" />
|
||
|
||
<!-- 业务字段 -->
|
||
|
||
<!-- 🔴 工作流状态列(必需) -->
|
||
<el-table-column label="流程状态" align="center">
|
||
<template #default="scope">
|
||
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<!-- 🔴 操作列(根据状态显示不同按钮) -->
|
||
<el-table-column label="操作" align="center">
|
||
<template #default="scope">
|
||
<el-row :gutter="10" class="mb8">
|
||
<el-col
|
||
:span="1.5"
|
||
v-if="['draft', 'cancel', 'back'].includes(scope.row.status)"
|
||
>
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
icon="Edit"
|
||
@click="handleUpdate(scope.row)"
|
||
>
|
||
修改
|
||
</el-button>
|
||
</el-col>
|
||
<el-col
|
||
:span="1.5"
|
||
v-if="['draft', 'cancel', 'back'].includes(scope.row.status)"
|
||
>
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
icon="Delete"
|
||
@click="handleDelete(scope.row)"
|
||
>
|
||
删除
|
||
</el-button>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="10" class="mb8">
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
icon="View"
|
||
@click="handleView(scope.row)"
|
||
>
|
||
查看
|
||
</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5" v-if="scope.row.status === 'waiting'">
|
||
<el-button
|
||
size="small"
|
||
type="primary"
|
||
icon="Notification"
|
||
@click="handleCancel(scope.row.id)"
|
||
>
|
||
撤销
|
||
</el-button>
|
||
</el-col>
|
||
</el-row>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-card>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { list业务, del业务 } from '@/api/workflow/业务模块';
|
||
import { cancelProcessApply } from '@/api/workflow/instance';
|
||
|
||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||
|
||
// 组件逻辑...
|
||
</script>
|
||
```
|
||
|
||
#### 1.2 编辑页面结构(🔴 标准模板)
|
||
|
||
```vue
|
||
<template>
|
||
<div class="p-2">
|
||
<!-- 🔴 1. 审批按钮组件(必需) -->
|
||
<el-card shadow="never">
|
||
<approvalButton
|
||
@submitForm="submitForm"
|
||
@approvalVerifyOpen="approvalVerifyOpen"
|
||
@handleApprovalRecord="handleApprovalRecord"
|
||
:buttonLoading="buttonLoading"
|
||
:id="form.id"
|
||
:status="form.status"
|
||
:pageType="routeParams.type"
|
||
/>
|
||
</el-card>
|
||
|
||
<!-- 2. 业务表单 -->
|
||
<el-card shadow="never" style="height: 78vh; overflow-y: auto">
|
||
<el-form
|
||
ref="formRef"
|
||
v-loading="loading"
|
||
:disabled="routeParams.type === 'view'"
|
||
:model="form"
|
||
:rules="rules"
|
||
label-width="80px"
|
||
>
|
||
<!-- 业务字段 -->
|
||
</el-form>
|
||
</el-card>
|
||
|
||
<!-- 🔴 3. 工作流组件(必需) -->
|
||
<submitVerify
|
||
ref="submitVerifyRef"
|
||
:task-variables="taskVariables"
|
||
@submit-callback="submitCallback"
|
||
/>
|
||
<approvalRecord ref="approvalRecordRef" />
|
||
|
||
<!-- 4. 流程选择对话框 -->
|
||
<el-dialog v-model="dialogVisible.visible" title="流程定义" width="500">
|
||
<el-select v-model="flowCode" placeholder="Select">
|
||
<el-option
|
||
v-for="item in flowCodeOptions"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value"
|
||
/>
|
||
</el-select>
|
||
<template #footer>
|
||
<el-button @click="handleClose">取消</el-button>
|
||
<el-button type="primary" @click="submitFlow()">确认</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
// 🔴 必需的组件引入
|
||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||
|
||
// 🔴 必需的API引入
|
||
import { add业务, get业务, update业务 } from '@/api/workflow/业务模块';
|
||
import { startWorkFlow } from '@/api/workflow/task';
|
||
|
||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||
|
||
// 🔴 必需的ref引用
|
||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||
|
||
// 🔴 必需的变量定义
|
||
const buttonLoading = ref(false);
|
||
const loading = ref(true);
|
||
const routeParams = ref<Record<string, any>>({});
|
||
const taskVariables = ref<Record<string, any>>({});
|
||
|
||
// 🔴 流程定义选项(根据实际业务配置)
|
||
const flowCodeOptions = [{ value: 'workflow_code', label: '工作流名称' }];
|
||
|
||
// 🔴 必需的事件处理函数
|
||
const submitForm = async (status: string) => {
|
||
try {
|
||
// 1. 表单验证
|
||
await formRef.value?.validate();
|
||
|
||
// 2. 保存业务数据
|
||
buttonLoading.value = true;
|
||
let res;
|
||
if (form.value.id) {
|
||
res = await update业务(form.value);
|
||
} else {
|
||
res = await add业务(form.value);
|
||
}
|
||
form.value = res.data;
|
||
|
||
// 3. 处理不同状态
|
||
if (status === 'draft') {
|
||
proxy?.$modal.msgSuccess('暂存成功');
|
||
proxy.$tab.closePage(proxy.$route);
|
||
proxy.$router.go(-1);
|
||
return;
|
||
}
|
||
|
||
// 4. 启动工作流
|
||
if (!flowCode.value) {
|
||
dialogVisible.visible = true;
|
||
return;
|
||
}
|
||
|
||
await handleStartWorkFlow(res.data);
|
||
} catch (error) {
|
||
console.error('提交失败:', error);
|
||
} finally {
|
||
buttonLoading.value = false;
|
||
}
|
||
};
|
||
|
||
const handleStartWorkFlow = async (data) => {
|
||
const submitFormData = {
|
||
flowCode: flowCode.value,
|
||
businessId: data.id,
|
||
variables: taskVariables.value,
|
||
};
|
||
|
||
const resp = await startWorkFlow(submitFormData);
|
||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||
};
|
||
|
||
const approvalVerifyOpen = () => {
|
||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||
};
|
||
|
||
const handleApprovalRecord = () => {
|
||
approvalRecordRef.value.init(form.value.id);
|
||
};
|
||
|
||
const submitCallback = async () => {
|
||
await proxy.$tab.closePage(proxy.$route);
|
||
proxy.$router.go(-1);
|
||
};
|
||
|
||
// 🔴 页面初始化
|
||
onMounted(() => {
|
||
nextTick(async () => {
|
||
routeParams.value = proxy.$route.query;
|
||
// 初始化逻辑
|
||
if (['update', 'view', 'approval'].includes(routeParams.value.type)) {
|
||
getInfo();
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
```
|
||
|
||
### 2. API 接口规范
|
||
|
||
#### 2.1 类型定义
|
||
|
||
```typescript
|
||
// api/workflow/业务模块/types.ts
|
||
export interface WorkflowForm extends BaseEntity {
|
||
id?: string | number;
|
||
// 业务字段
|
||
status?: string; // 🔴 工作流状态字段
|
||
}
|
||
|
||
export interface WorkflowVO extends BaseEntity {
|
||
id?: string | number;
|
||
// 业务字段
|
||
status?: string; // 🔴 工作流状态字段
|
||
}
|
||
|
||
export interface WorkflowQuery extends PageQuery {
|
||
// 查询字段
|
||
status?: string;
|
||
}
|
||
```
|
||
|
||
#### 2.2 接口定义
|
||
|
||
```typescript
|
||
// api/workflow/业务模块/index.ts
|
||
import request from '@/utils/request';
|
||
import { WorkflowQuery, WorkflowForm, WorkflowVO } from './types';
|
||
|
||
export const list业务 = (query: WorkflowQuery): AxiosPromise<WorkflowVO[]> => {
|
||
return request({
|
||
url: '/workflow/业务模块/list',
|
||
method: 'get',
|
||
params: query,
|
||
});
|
||
};
|
||
|
||
export const get业务 = (id: string | number): AxiosPromise<WorkflowVO> => {
|
||
return request({
|
||
url: `/workflow/业务模块/${id}`,
|
||
method: 'get',
|
||
});
|
||
};
|
||
|
||
export const add业务 = (data: WorkflowForm): AxiosPromise<WorkflowVO> => {
|
||
return request({
|
||
url: '/workflow/业务模块',
|
||
method: 'post',
|
||
data: data,
|
||
});
|
||
};
|
||
|
||
export const update业务 = (data: WorkflowForm): AxiosPromise<WorkflowVO> => {
|
||
return request({
|
||
url: '/workflow/业务模块',
|
||
method: 'put',
|
||
data: data,
|
||
});
|
||
};
|
||
|
||
export const del业务 = (id: string | number | Array<string | number>): AxiosPromise<void> => {
|
||
return request({
|
||
url: `/workflow/业务模块/${id}`,
|
||
method: 'delete',
|
||
});
|
||
};
|
||
```
|
||
|
||
### 3. 路由配置规范
|
||
|
||
```typescript
|
||
// router配置
|
||
{
|
||
path: '/workflow/业务模块',
|
||
component: Layout,
|
||
redirect: '/workflow/业务模块/index',
|
||
name: 'Workflow业务模块',
|
||
meta: {
|
||
title: '业务模块管理',
|
||
icon: 'workflow'
|
||
},
|
||
children: [
|
||
{
|
||
path: 'index',
|
||
component: () => import('@/views/workflow/业务模块/index.vue'),
|
||
name: 'Workflow业务模块List',
|
||
meta: { title: '业务模块列表', activeMenu: '/workflow/业务模块/index' }
|
||
},
|
||
{
|
||
path: 'edit',
|
||
component: () => import('@/views/workflow/业务模块/edit.vue'),
|
||
name: 'Workflow业务模块Edit',
|
||
hidden: true,
|
||
meta: { title: '业务模块编辑', activeMenu: '/workflow/业务模块/index' }
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 工作流核心功能
|
||
|
||
### 1. 流程启动
|
||
|
||
```typescript
|
||
// 启动工作流标准代码
|
||
const handleStartWorkFlow = async (businessData: any) => {
|
||
const submitFormData = {
|
||
flowCode: 'your_flow_code', // 🔴 流程定义编码
|
||
businessId: businessData.id, // 🔴 业务数据ID
|
||
variables: {
|
||
// 🔴 流程变量
|
||
// 条件判断变量
|
||
amount: businessData.amount,
|
||
// 会签用户列表
|
||
userList: ['1', '3', '4'],
|
||
// 其他业务变量
|
||
...otherVariables,
|
||
},
|
||
};
|
||
|
||
try {
|
||
const resp = await startWorkFlow(submitFormData);
|
||
// 打开提交确认对话框
|
||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||
} catch (error) {
|
||
console.error('启动工作流失败:', error);
|
||
}
|
||
};
|
||
```
|
||
|
||
### 2. 任务办理
|
||
|
||
```typescript
|
||
// 在 submitVerify 组件中自动处理
|
||
// 支持的操作:
|
||
// - 提交审批
|
||
// - 委托 (delegateTask)
|
||
// - 转办 (transferTask)
|
||
// - 加签 (addSignature)
|
||
// - 减签 (reductionSignature)
|
||
// - 终止 (terminationTask)
|
||
// - 退回 (backProcess)
|
||
```
|
||
|
||
**🔴 退回残留任务清理(强制性,2026-10-15)**:
|
||
|
||
- `backProcess` 在 `skip(REJECT)` 后必须清理同实例下非目标节点残留 `flow_task`/`flow_user`(`cleanResidualTasksAfterBack`)
|
||
- 草稿/撤销/退回重新提交时,`startWorkFlow` 需自愈多任务脏数据并按实例状态解析正确 taskId(`healResidualTasksOnRestart`)
|
||
- 背景:退回后若残留原审批节点 + draft 申请人任务,移动端再提交会报「启动工作流失败」
|
||
|
||
### 3. 流程撤销
|
||
|
||
```typescript
|
||
// 申请人撤销流程
|
||
const handleCancelProcessApply = async (businessId: string) => {
|
||
await proxy?.$modal.confirm('是否确认撤销当前单据?');
|
||
|
||
const data = {
|
||
businessId: businessId,
|
||
message: '申请人撤销流程!',
|
||
};
|
||
|
||
await cancelProcessApply(data);
|
||
proxy?.$modal.msgSuccess('撤销成功');
|
||
getList(); // 刷新列表
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 常用工作流模式
|
||
|
||
### 1. 普通线性流程
|
||
|
||
```typescript
|
||
// 流程编码:simple_approval
|
||
// 特点:线性审批,一步一步进行
|
||
const taskVariables = {
|
||
// 基本业务数据即可
|
||
businessData: formData,
|
||
};
|
||
```
|
||
|
||
### 2. 排他网关流程
|
||
|
||
```typescript
|
||
// 流程编码:exclusive_gateway
|
||
// 特点:根据条件选择不同审批分支
|
||
const taskVariables = {
|
||
amount: formData.amount, // 金额条件
|
||
urgentLevel: formData.urgent, // 紧急程度
|
||
applicantLevel: currentUser.level, // 申请人级别
|
||
};
|
||
```
|
||
|
||
### 3. 并行网关流程
|
||
|
||
```typescript
|
||
// 流程编码:parallel_gateway
|
||
// 特点:多个分支并行执行
|
||
const taskVariables = {
|
||
parallelBranches: ['finance', 'hr', 'legal'], // 并行分支
|
||
businessData: formData,
|
||
};
|
||
```
|
||
|
||
### 4. 会签流程
|
||
|
||
```typescript
|
||
// 流程编码:countersign
|
||
// 特点:多人会签,所有人都需要审批
|
||
const taskVariables = {
|
||
userList: ['1', '3', '4', '5'], // 会签用户列表
|
||
signType: 'all', // all-全部同意 any-任一同意
|
||
businessData: formData,
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 权限配置规范
|
||
|
||
### 1. 菜单权限配置
|
||
|
||
在系统管理 → 菜单管理中配置:
|
||
|
||
```
|
||
父菜单:工作流管理
|
||
├── 业务模块管理
|
||
├── 菜单权限:workflow:业务模块:list
|
||
├── 按钮权限:
|
||
├── 新增:workflow:业务模块:add
|
||
├── 修改:workflow:业务模块:edit
|
||
├── 删除:workflow:业务模块:remove
|
||
├── 查询:workflow:业务模块:query
|
||
└── 导出:workflow:业务模块:export
|
||
```
|
||
|
||
### 2. 工作流权限配置
|
||
|
||
```
|
||
工作流通用权限:
|
||
├── 任务管理:workflow:task:list
|
||
├── 实例管理:workflow:instance:list
|
||
├── 定义管理:workflow:definition:list
|
||
└── 审批权限:workflow:approval:handle
|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ 常见问题与解决方案
|
||
|
||
### 1. MyBatis 映射错误
|
||
|
||
**问题**: `Could not set property 'createBy'`
|
||
|
||
**解决**: 确保 VO 类包含完整的基础字段:
|
||
|
||
```java
|
||
// 🔴 必须包含的四个基础字段
|
||
private Long createBy;
|
||
private Date createTime;
|
||
private Long updateBy;
|
||
private Date updateTime;
|
||
```
|
||
|
||
### 2. 工作流功能不显示
|
||
|
||
**问题**: 工作流相关功能无法使用
|
||
|
||
**检查清单**:
|
||
|
||
- [ ] 配置文件:`warm-flow.enabled=true`
|
||
- [ ] 类注解:`@ConditionalOnEnable`
|
||
- [ ] 权限注解:`@SaCheckPermission`
|
||
- [ ] 组件引入路径正确
|
||
|
||
### 3. 流程启动失败
|
||
|
||
**常见原因**:
|
||
|
||
- 流程定义未发布
|
||
- flowCode 不存在
|
||
- 业务数据状态非 'draft'
|
||
- 权限不足
|
||
|
||
### 4. 日期格式问题
|
||
|
||
**解决**: 统一使用标准格式
|
||
|
||
```vue
|
||
<el-date-picker
|
||
v-model="dateRange"
|
||
type="daterange"
|
||
value-format="YYYY-MM-DD HH:mm:ss"
|
||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
|
||
/>
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 代码生成模板
|
||
|
||
### 快速生成工作流业务模块
|
||
|
||
1. **数据库表**: 按照规范创建业务表
|
||
2. **后端代码**: 使用代码生成器,添加工作流注解
|
||
3. **前端代码**: 复制标准模板,修改业务字段
|
||
4. **权限配置**: 在菜单管理中配置权限
|
||
5. **流程定义**: 在流程设计器中创建流程
|
||
|
||
---
|
||
|
||
## 📚 参考文档
|
||
|
||
- [Warm-Flow 工作流框架开发指南](../开发文档/warm-flow工作流框架开发指南.md)
|
||
- [API 开发最佳实践总结](../开发文档/API开发最佳实践总结.md)
|
||
- [请假工作流示例](../开发文档/API/请假工作流API.md)
|
||
|
||
---
|
||
|
||
**规范版本**: v1.0
|
||
**最后更新**: 2025-01-09
|
||
**适用范围**: 所有基于 warm-flow 的工作流开发任务
|