Files
hzdyjs/docs/开发文档/Warm-Flow工作流开发最佳实践总结.md
T
zlwu 45b5d58ae4 feat: 完整的Warm-Flow工作流框架文档体系建设
- 新增工作流框架开发指南文档 (warm-flow工作流框架开发指南.md)
  包含技术架构、核心组件、开发流程、请假工作流示例等完整内容

- 新增工作流开发规范 (.cursor/cursorrules-workflow.md)
  整合到cursorrules体系,包含强制性VO类规范、状态管理、前后端开发模板

- 新增工作流开发最佳实践总结 (Warm-Flow工作流开发最佳实践总结.md)
  基于请假工作流实践的快速开始模板、开发效率统计、常见问题解决方案

- 更新主配置文件 (.cursorrules)
  添加工作流规范引用,确保Cursor AI在工作流开发时自动应用规范

- 新增变更记录 (code-adjust-record-2025-01-09-wuzilong.md)
  详细记录本次工作流文档建设的所有变更内容

关键成果:
- 建立了7种标准工作流状态管理体系
- 总结了6种常用工作流模式 (线性、排他网关、并行网关、会签等)
- 提供了完整的前后端开发模板和最佳实践
- 解决了VO类基础字段规范等关键技术问题
- 形成了3.5天标准开发周期的高效开发流程
2025-07-06 17:54:37 +08:00

17 KiB
Raw Blame History

Warm-Flow 工作流开发最佳实践总结

📋 概述

本文档基于请假工作流的成功实践,总结了使用 Warm-Flow 工作流框架进行开发的最佳实践、常用模板和经验教训。


🚀 快速开始模板

1. 工作流业务模块标准结构

工作流业务模块/
├── 后端代码
│   ├── controller/     # 业务控制器(包含@ConditionalOnEnable)
│   ├── service/       # 业务服务层
│   ├── domain/        # 实体类(Bo、Vo、Entity)
│   └── mapper/        # 数据访问层
├── 前端代码
│   ├── api/           # API接口定义
│   ├── types/         # TypeScript类型定义
│   ├── views/         # 页面组件(列表页、编辑页)
│   └── components/    # 工作流通用组件
├── 数据库脚本
│   ├── 表结构.sql     # 业务表创建
│   ├── 字典数据.sql   # 状态字典配置
│   └── 权限配置.sql   # 菜单权限数据
└── 流程定义
    └── 流程图.json    # Warm-Flow流程定义文件

2. 标准开发流程(6 个阶段)

阶段 1: 需求分析和设计

1. 业务需求文档 → docs/业务模块/[模块名]/需求分析/
2. 数据库设计文档 → docs/设计文档/database/
3. API接口设计 → docs/开发文档/API/

阶段 2: 数据库初始化

-- 标准业务表结构
CREATE TABLE wf_business_table (
    id                  BIGINT(20)      NOT NULL    PRIMARY KEY,
    -- 业务字段
    business_field1     VARCHAR(100),
    business_field2     VARCHAR(200),

    -- 🔴 工作流状态字段(必需)
    status              VARCHAR(20)     DEFAULT 'draft',

    -- 🔴 标准基础字段(必需)
    tenant_id           VARCHAR(20)     DEFAULT '000000',
    create_dept         BIGINT(20)      DEFAULT NULL,
    create_by           BIGINT(20)      DEFAULT NULL,
    create_time         DATETIME        DEFAULT CURRENT_TIMESTAMP,
    update_by           BIGINT(20)      DEFAULT NULL,
    update_time         DATETIME        DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted             TINYINT(1)      DEFAULT 0
);

阶段 3: 后端开发模板

// 1. 实体类模板
@Data
@ExcelIgnoreUnannotated
public class BusinessVo {
    // 业务字段
    private Long id;
    private String businessField;
    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;
}

// 2. Controller模板
@ConditionalOnEnable  // 🔴 必须添加
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/business")
public class BusinessController extends BaseController {

    private final IBusinessService businessService;

    @SaCheckPermission("workflow:business:list")
    @GetMapping("/list")
    public TableDataInfo<BusinessVo> list(BusinessBo bo, PageQuery pageQuery) {
        return businessService.queryPageList(bo, pageQuery);
    }

    // 其他CRUD接口...
}

// 3. Service模板
@ConditionalOnEnable  // 🔴 必须添加
@Service
@RequiredArgsConstructor
public class BusinessServiceImpl implements IBusinessService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BusinessVo insertByBo(BusinessBo bo) {
        Business entity = BeanUtil.toBean(bo, Business.class);
        entity.setStatus("draft");  // 🔴 设置初始状态
        validEntityBeforeSave(entity);
        boolean flag = baseMapper.insert(entity) > 0;
        if (flag) {
            return BeanUtil.toBean(entity, BusinessVo.class);
        }
        return null;
    }
}

阶段 4: 前端开发模板

<!-- 列表页面模板 -->
<template>
    <div class="p-2">
        <!-- 搜索表单 -->
        <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>

        <!-- 数据表格 -->
        <el-card shadow="never">
            <el-table v-loading="loading" border :data="dataList">
                <!-- 业务字段 -->

                <!-- 🔴 工作流状态列(必需) -->
                <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-button
                            v-if="['draft', 'cancel', 'back'].includes(scope.row.status)"
                            type="primary"
                            size="small"
                            @click="handleUpdate(scope.row)"
                        >
                            修改
                        </el-button>
                        <el-button type="primary" size="small" @click="handleView(scope.row)">
                            查看
                        </el-button>
                        <el-button
                            v-if="scope.row.status === 'waiting'"
                            size="small"
                            type="primary"
                            @click="handleCancel(scope.row.id)"
                        >
                            撤销
                        </el-button>
                    </template>
                </el-table-column>
            </el-table>
        </el-card>
    </div>
</template>
<!-- 编辑页面模板 -->
<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">
            <el-form ref="formRef" :model="form" :rules="rules">
                <!-- 业务字段 -->
            </el-form>
        </el-card>

        <!-- 🔴 3. 工作流组件(必需) -->
        <submitVerify
            ref="submitVerifyRef"
            :task-variables="taskVariables"
            @submit-callback="submitCallback"
        />
        <approvalRecord ref="approvalRecordRef" />
    </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';

// 核心事件处理
const submitForm = async (status: string) => {
    // 1. 表单验证
    await formRef.value?.validate();

    // 2. 保存业务数据
    const res = form.value.id ? await updateBusiness(form.value) : await addBusiness(form.value);

    // 3. 启动工作流
    if (status === 'submit') {
        await handleStartWorkFlow(res.data);
    }
};

const handleStartWorkFlow = async (data: any) => {
    const submitFormData = {
        flowCode: 'your_flow_code',
        businessId: data.id,
        variables: taskVariables.value,
    };

    const resp = await startWorkFlow(submitFormData);
    submitVerifyRef.value.openDialog(resp.data.taskId);
};
</script>

阶段 5: API 接口文档

// API类型定义模板
export interface BusinessForm extends BaseEntity {
    id?: string | number;
    businessField?: string;
    status?: string; // 🔴 工作流状态字段
}

export interface BusinessVO extends BaseEntity {
    id?: string | number;
    businessField?: string;
    status?: string; // 🔴 工作流状态字段
}

// API接口定义模板
export const listBusiness = (query: BusinessQuery): AxiosPromise<BusinessVO[]> => {
    return request({
        url: '/workflow/business/list',
        method: 'get',
        params: query,
    });
};

export const addBusiness = (data: BusinessForm): AxiosPromise<BusinessVO> => {
    return request({
        url: '/workflow/business',
        method: 'post',
        data: data,
    });
};

阶段 6: 权限和流程配置

菜单权限配置:
├── 父菜单:工作流管理
    ├── 业务模块管理
        ├── 菜单权限:workflow:business:list
        ├── 按钮权限:
            ├── 新增:workflow:business:add
            ├── 修改:workflow:business:edit
            ├── 删除:workflow:business:remove
            └── 查询:workflow:business:query

流程定义配置:
├── 流程编码:business_approval
├── 流程名称:业务审批流程
├── 流程变量:businessData、approvalLevel等
└── 审批节点:申请 → 审批 → 完成

🔍 核心要点总结

1. 🔴 强制性规范

VO 类基础字段(避免 MyBatis 映射错误)

// 所有工作流业务VO类必须包含的四个基础字段
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;

条件开启注解

// 所有工作流相关类必须添加
@ConditionalOnEnable

权限注解

// 所有接口必须添加权限检查
@SaCheckPermission("workflow:module:action")

2. 工作流状态管理

标准状态流转

draft(草稿) → waiting(待审批) → complete(已完成)
     ↓              ↓
cancel(已取消)   back(已退回)

状态检查工具

// 前端状态检查
const canEdit = computed(() => {
    return ['draft', 'cancel', 'back'].includes(form.value.status);
});

const canCancel = computed(() => {
    return form.value.status === 'waiting';
});

3. 常用工作流模式

普通线性流程

const taskVariables = {
    businessData: formData,
};

排他网关流程(条件分支)

const taskVariables = {
    amount: formData.amount, // 金额条件
    urgentLevel: formData.urgent, // 紧急程度
    applicantLevel: currentUser.level, // 申请人级别
};

会签流程

const taskVariables = {
    userList: ['1', '3', '4', '5'], // 会签用户列表
    signType: 'all', // all-全部同意 any-任一同意
    businessData: formData,
};

📊 开发效率统计

基于请假工作流的实际数据

开发周期

  • 总开发时间: 约 3.5 天
  • 后端开发: 1.5 天(包含完整 CRUD + 工作流集成)
  • 前端开发: 1 天(包含列表页 + 编辑页 + 工作流组件)
  • 文档编写: 0.5 天(API 文档 + 用户手册)
  • 测试验证: 0.5 天(功能测试 + 流程测试)

交付物清单

  • 后端代码: 18 个文件(Controller、Service、Mapper、实体类等)
  • 前端代码: 6 个文件(页面组件、API 接口、类型定义)
  • 数据库脚本: 3 个 SQL 文件(表结构、字典数据、权限配置)
  • 文档: 1 个完整 API 文档(400+行)
  • 测试脚本: 1 个 Python 自动化测试脚本(450+行)

代码质量指标

  • 接口数量: 16 个标准 API 接口
  • 测试覆盖: 100%接口功能测试
  • 文档同步: 代码完成即时更新文档
  • 错误处理: 完整的异常处理和用户提示

🛠️ 工具和辅助资源

1. 代码生成器优化

# 使用若依代码生成器生成基础CRUD代码
# 然后手动添加工作流相关注解和逻辑

# 必须手动添加的内容:
# 1. @ConditionalOnEnable 注解
# 2. VO类基础字段
# 3. 工作流组件引入
# 4. 状态检查逻辑

2. 测试脚本模板

# 工作流业务模块测试脚本模板
import requests
import json
from datetime import datetime

class WorkflowBusinessTest:
    def __init__(self):
        self.base_url = "http://localhost:8080"
        self.token = None

    def login(self):
        """AES+RSA双重加密登录"""
        # 登录逻辑(参考 cursorrules-api-test.md)

    def test_workflow_crud(self):
        """测试工作流业务CRUD操作"""
        # 1. 新增(状态为draft)
        # 2. 修改
        # 3. 查询列表
        # 4. 启动工作流
        # 5. 审批处理
        # 6. 撤销流程
        # 7. 删除

    def test_workflow_states(self):
        """测试工作流状态流转"""
        # 测试各种状态下的可用操作

3. 前端组件库

// 工作流通用组件工具函数
export const workflowUtils = {
    // 状态检查
    canEdit: (status: string) => ['draft', 'cancel', 'back'].includes(status),
    canCancel: (status: string) => status === 'waiting',
    canApprove: (status: string) => status === 'waiting',

    // 状态标签
    getStatusTag: (status: string) => {
        const statusMap = {
            draft: { type: 'info', label: '草稿' },
            waiting: { type: 'warning', label: '待审批' },
            complete: { type: 'success', label: '已完成' },
            cancel: { type: 'danger', label: '已取消' },
            back: { type: 'danger', label: '已退回' },
        };
        return statusMap[status] || { type: 'info', label: '未知' };
    },
};

❌ 常见错误和解决方案

1. MyBatis 映射错误

错误: Could not set property 'createBy'

原因: VO 类缺少基础字段,但 SQL 查询包含这些字段

解决:

// 确保所有VO类包含四个基础字段
private Long createBy;
private Date createTime;
private Long updateBy;
private Date updateTime;

2. 工作流组件不显示

错误: 审批按钮等组件不显示

检查清单:

  • 配置文件:warm-flow.enabled=true
  • 类注解:@ConditionalOnEnable
  • 权限注解:@SaCheckPermission
  • 组件引入路径正确

3. 流程启动失败

常见原因:

  • 流程定义未发布
  • flowCode 不存在
  • 业务数据状态非 'draft'
  • 权限不足

解决:

// 检查流程启动前置条件
if (form.value.status !== 'draft') {
    proxy?.$modal.msgError('只能提交草稿状态的数据');
    return;
}

if (!flowCode.value) {
    proxy?.$modal.msgError('请选择流程定义');
    return;
}

4. 日期格式问题

错误: 前端日期格式与后端不匹配

解决:

<!-- 统一使用标准格式 -->
<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. 前端优化

// 1. 组件懒加载
const SubmitVerify = defineAsyncComponent(() => import('@/components/Process/submitVerify.vue'));

// 2. 接口缓存
const { data: taskInfo } = useCachedRequest(() => getTask(taskId.value), {
    cacheKey: `task_${taskId.value}`,
    ttl: 5 * 60 * 1000, // 5分钟缓存
});

// 3. 状态计算优化
const statusActions = computed(() => {
    const status = form.value.status;
    return {
        canEdit: ['draft', 'cancel', 'back'].includes(status),
        canCancel: status === 'waiting',
        canApprove: status === 'waiting',
    };
});

2. 后端优化

// 1. 查询优化
@Select("SELECT * FROM business WHERE status = #{status} LIMIT #{limit}")
List<Business> selectByStatus(@Param("status") String status, @Param("limit") int limit);

// 2. 缓存使用
@Cacheable(value = "workflow", key = "#businessId")
public BusinessVo queryById(Long businessId) {
    // 查询逻辑
}

// 3. 批量操作
@Transactional(rollbackFor = Exception.class)
public boolean batchUpdateStatus(List<Long> ids, String status) {
    // 批量更新逻辑
}

📈 后续优化方向

1. 工作流扩展功能

  • 自定义表单设计器
  • 流程图可视化编辑
  • 流程数据统计分析
  • 移动端审批支持

2. 开发工具优化

  • 工作流代码生成器
  • 自动化测试框架
  • 性能监控工具
  • 文档自动生成

3. 最佳实践积累

  • 更多业务场景模板
  • 复杂流程设计模式
  • 异常处理策略
  • 用户体验优化

文档维护: 基于请假工作流实践总结
最后更新: 2025-01-09
版本: v1.0