兰宝车间质量管理系统-前端
!172 合并 warmflow 功能分支
* update 优化 流程定义页面 点击复制之后跳转到未发布列表
* update 优化 流程定义页面 增加加载loading层
* fix: v-model处理有延迟 需要手动处理
* update 调整流程定义查询
* Merge remote-tracking branch 'origin/dev' into warm-flw-future
* update 调整可驳回的节点
* update: 调整文案
* update: 激活/挂起改为switch操作
* update 优化 代码删除无用输出
* update 统一抄送人使用昵称展示
* update 调整分类接口
* update 统一业务id参数
* update 删除默认顶节点
* !168 优化流程分类
* update 恢复误删除代码
* update 优化流程分类
* update 修复 路由跳转未改全
* [update]
* fix 修复一些问题
* update 重构流程分类表
* update 流程定义增加表单路径与编辑功能 修复一些其他bug
* fix 修复 一些问题
* update 变量统一命名
* add 增加示例
* Merge branch 'warm-flw-future' of https://gitee.com/JavaLionLi/plus-ui…
* update 调整办理人
* Merge remote-tracking branch 'origin/dev' into warm-flw-future
* add 增加示例
* update 调整审批记录 添加流程导出
* remove 删除无用代码
* remove 删除无用代码
* [update]
* [fix]
* 流程干预删除委托
* 增加附件
* 附件修改
* 申请人查询修改
* 1.修改查询条件
* !167 fix 修复 import路径修改不全问题
* fix 修复 import路径修改不全问题
* !166 update 清除 ProcessPreview 引用
* update 清除 ProcessPreview 引用
* remove 删除 bpmn.js 设计器
* remove 删除 bpmn.js 设计器
* remove 删除 bpmn.js 设计器
* remove 删除 bpmn.js 设计器
* fix 修复 前端路径修改不全问题
* update 优化接口请求路径
* add 添加作废
* add 添加流程干预
* update 调整加签,减签
* update 调整加签,减签
* add 增加流程查看
* update 调整委托,转办
* update 调整流程变量显示
* update 调整办理人修改
* update 调整流程实例状态页面
* update 调整已办页面
* add 添加流程撤销
* update 调整任务,流程实例 ,流程定义页面
* Merge branch 'dev' into warm-flw-future
* update 调整流程定义页面
* add 添加流程变量查看
* update 调整设计器路由名称
* update 调整办理人
* update 调整设计器uri
* update 调整设计器请求uri 调整待办状态
* update 调整办理 驳回 终止等状态
* add 添加模型新增
* add 添加warm-ui设计器,删除无用代码
* Merge remote-tracking branch 'origin/dev' into warm-flw-future
* add 添加流程设计
* update 调整驳回
* update 调整视图类型错误
* Merge branch 'warm-flw-future' of https://gitee.com/JavaLionLi/plus-ui…
* 添加已办,未办
* Merge remote-tracking branch 'origin/dev' into warm-flw-future
* update 调整流程实例,待办查询
* add 添加代办人,调整提交按钮校验
* update 调整流程定义查询
* add添加流程定义激活 挂起
* add 添加流程文件部署 调整流程发布
* update 优化 时间搜索组件统一
* Merge remote-tracking branch 'origin/dev' into warm-flw-future
* fix 修复 用户管理编辑安全权限错误问题
* Merge remote-tracking branch 'origin/dev' into warm-flw-future
* update 优化 类型报错问题
* update 优化 切换租户后刷新首页
* update 优化 实现表格行选中切换
* update 优化 使用 vueuse 重构 websocket 实现
* update 优化 使用 vueuse 重构 websocket 实现
* fix 修复 登出后重新登录 sse推送报错问题
* reset 回滚 代码修改 采用其他方案
* fix 修复 登出后重新登录 sse推送报错问题
* update 优化 删除无用代码
* update element-plus 2.7.5 => 2.7.8
* reset 回滚 错误修复
* update 优化 代码生成器编辑页禁用缓存 防止同步后页面不更新问题
* fix 修复 代码生成同步点击取消报错问题
* 初始化添加warm-flow
已添加6个文件
已删除48个文件
已修改24个文件
10717 ■■■■ 文件已修改
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dept/index.ts 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/category/index.ts 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/category/types.ts 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/definition/index.ts 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/definition/types.ts 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/definitionConfig/index.ts 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/definitionConfig/types.ts 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/formManage/index.ts 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/formManage/types.ts 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/instance/index.ts 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/instance/types.ts 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/model/index.ts 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/model/types.ts 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/nodeConfig/types.ts 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/processDefinition/index.ts 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/processDefinition/types.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/processInstance/index.ts 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/processInstance/types.ts 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/task/index.ts 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/task/types.ts 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/workflowCommon/index.ts 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/workflow/workflowCommon/types.ts 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/variables.module.scss 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/defaultXML.ts 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/lang/zh.ts 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/moddle/flowable.ts 1250 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/module/ContextPad/CustomContextPadProvider.ts 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/module/Palette/CustomPaletteProvider.ts 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/module/Renderer/CustomRenderer.ts 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/module/Translate/index.ts 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/module/index.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/showConfig.ts 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/assets/style/index.scss 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/hooks/usePanel.ts 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/hooks/useParseElement.ts 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/index.vue 496 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/GatewayPanel.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/ParticipantPanel.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/ProcessPanel.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/SequenceFlowPanel.vue 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/StartEndPanel.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/SubProcessPanel.vue 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/TaskPanel.vue 491 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/index.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/property/DueDate.vue 252 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/property/ExecutionListener.vue 308 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/property/ListenerParam.vue 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/bpmn/panel/property/TaskListener.vue 310 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/BpmnDesign/index.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/BpmnView/index.vue 411 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Process/approvalRecord.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Process/multiInstanceUser.vue 378 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Process/processMeddle.vue 207 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Process/submitVerify.vue 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/UserSelect/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/enums/bpmn/IndexEnums.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/modeler.ts 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/types/bpmn/editor/global.d.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/types/bpmn/index.d.ts 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/types/bpmn/moddle.d.ts 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/types/bpmn/panel.d.ts 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/category/index.vue 194 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/formManage/index.vue 243 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/leave/index.vue 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/leave/leaveEdit.vue 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/model/index.vue 383 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/processDefinition/components/processPreview.vue 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/processDefinition/design.vue 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/processDefinition/index.vue 590 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/processInstance/index.vue 357 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/task/allTaskWaiting.vue 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/task/myDocument.vue 138 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/task/taskCopyList.vue 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/task/taskFinish.vue 97 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workflow/task/taskWaiting.vue 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -27,7 +27,6 @@
    "animate.css": "4.1.1",
    "await-to-js": "3.0.0",
    "axios": "1.7.8",
    "bpmn-js": "16.4.0",
    "crypto-js": "4.2.0",
    "diagram-js": "12.3.0",
    "didi": "9.0.2",
src/api/system/dept/index.ts
@@ -1,6 +1,6 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { DeptForm, DeptQuery, DeptVO } from './types';
import {DeptForm, DeptQuery, DeptTreeVO, DeptVO} from './types';
// æŸ¥è¯¢éƒ¨é—¨åˆ—表
export const listDept = (query?: DeptQuery) => {
@@ -8,6 +8,17 @@
    url: '/system/dept/list',
    method: 'get',
    params: query
  });
};
/**
 * é€šè¿‡deptIds查询部门
 * @param deptIds
 */
export const optionSelect = (deptIds: (number | string)[]): AxiosPromise<DeptVO[]> => {
  return request({
    url: '/system/dept/optionselect?deptIds=' + deptIds,
    method: 'get'
  });
};
@@ -28,7 +39,7 @@
};
// æŸ¥è¯¢éƒ¨é—¨ä¸‹æ‹‰æ ‘结构
export const treeselect = (): AxiosPromise<DeptVO[]> => {
export const treeselect = (): AxiosPromise<DeptTreeVO[]> => {
  return request({
    url: '/system/dept/treeselect',
    method: 'get'
src/api/workflow/category/index.ts
@@ -1,6 +1,6 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/workflow/category/types';
import { CategoryVO, CategoryForm, CategoryQuery, CategoryTreeVO } from '@/api/workflow/category/types';
/**
 * æŸ¥è¯¢æµç¨‹åˆ†ç±»åˆ—表
@@ -18,11 +18,11 @@
/**
 * æŸ¥è¯¢æµç¨‹åˆ†ç±»è¯¦ç»†
 * @param id
 * @param categoryId
 */
export const getCategory = (id: string | number): AxiosPromise<CategoryVO> => {
export const getCategory = (categoryId: string | number): AxiosPromise<CategoryVO> => {
  return request({
    url: '/workflow/category/' + id,
    url: '/workflow/category/' + categoryId,
    method: 'get'
  });
};
@@ -53,11 +53,24 @@
/**
 * åˆ é™¤æµç¨‹åˆ†ç±»
 * @param id
 * @param categoryId
 */
export const delCategory = (id: string | number | Array<string | number>) => {
export const delCategory = (categoryId: string | number | Array<string | number>) => {
  return request({
    url: '/workflow/category/' + id,
    url: '/workflow/category/' + categoryId,
    method: 'delete'
  });
};
/**
 * èŽ·å–æµç¨‹åˆ†ç±»æ ‘åˆ—è¡¨
 * @param query æµç¨‹å®žä¾‹id
 * @returns
 */
export const categoryTree = (query?: CategoryForm): AxiosPromise<CategoryTreeVO[]> => {
  return request({
    url: `/workflow/category/categoryTree`,
    method: 'get',
    params: query
  });
};
src/api/workflow/category/types.ts
@@ -1,18 +1,16 @@
export interface CategoryTreeVO {
  id: number | string;
  label: string;
  parentId: number | string;
  weight: number;
  children: CategoryTreeVO[];
}
export interface CategoryVO {
  /**
   * ä¸»é”®
   */
  id: string;
  /**
   * åˆ†ç±»åç§°
   * æµç¨‹åˆ†ç±»ID
   */
  categoryName: string;
  /**
   * åˆ†ç±»ç¼–码
   */
  categoryCode: string;
  categoryId: string | number;
  /**
   * çˆ¶çº§id
@@ -20,48 +18,55 @@
  parentId: string | number;
  /**
   * æŽ’序
   * æµç¨‹åˆ†ç±»åç§°
   */
  sortNum: number;
  categoryName: string;
  children?: CategoryVO[];
  /**
   * æ˜¾ç¤ºé¡ºåº
   */
  orderNum: number;
  /**
   * åˆ›å»ºæ—¶é—´
   */
  createTime: string;
  /**
   * å­å¯¹è±¡
   */
  children: CategoryVO[];
}
export interface CategoryForm extends BaseEntity {
  /**
   * ä¸»é”®
   */
  id?: string | number;
  /**
   * åˆ†ç±»åç§°
   * æµç¨‹åˆ†ç±»ID
   */
  categoryId?: string | number;
  /**
   * æµç¨‹åˆ†ç±»åç§°
   */
  categoryName?: string;
  /**
   * åˆ†ç±»ç¼–码
   */
  categoryCode?: string;
  /**
   * çˆ¶çº§id
   * çˆ¶æµç¨‹åˆ†ç±»id
   */
  parentId?: string | number;
  /**
   * æŽ’序
   * æ˜¾ç¤ºé¡ºåº
   */
  sortNum?: number;
  orderNum?: number;
}
export interface CategoryQuery extends PageQuery {
export interface CategoryQuery {
  /**
   * åˆ†ç±»åç§°
   * æµç¨‹åˆ†ç±»åç§°
   */
  categoryName?: string;
  /**
   * åˆ†ç±»ç¼–码
   */
  categoryCode?: string;
}
src/api/workflow/definition/index.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,170 @@
import request from '@/utils/request';
import { FlowDefinitionQuery, definitionXmlVO, FlowDefinitionForm, FlowDefinitionVo } from '@/api/workflow/definition/types';
import { AxiosPromise } from 'axios';
/**
 * èŽ·å–æµç¨‹å®šä¹‰åˆ—è¡¨
 * @param query æµç¨‹å®žä¾‹id
 * @returns
 */
export const listDefinition = (query: FlowDefinitionQuery): AxiosPromise<FlowDefinitionVo[]> => {
  return request({
    url: `/workflow/definition/list`,
    method: 'get',
    params: query
  });
};
/**
 * æŸ¥è¯¢æœªå‘布的流程定义列表
 * @param query æµç¨‹å®žä¾‹id
 * @returns
 */
export const unPublishList = (query: FlowDefinitionQuery): AxiosPromise<FlowDefinitionVo[]> => {
  return request({
    url: `/workflow/definition/unPublishList`,
    method: 'get',
    params: query
  });
};
/**
 * é€šè¿‡æµç¨‹å®šä¹‰id获取xml
 * @param definitionId æµç¨‹å®šä¹‰id
 * @returns
 */
export const definitionXml = (definitionId: string): AxiosPromise<definitionXmlVO> => {
  return request({
    url: `/workflow/definition/definitionXml/${definitionId}`,
    method: 'get'
  });
};
/**
 * åˆ é™¤æµç¨‹å®šä¹‰
 * @param id æµç¨‹å®šä¹‰id
 * @returns
 */
export const deleteDefinition = (id: string | string[]) => {
  return request({
    url: `/workflow/definition/${id}`,
    method: 'delete'
  });
};
/**
 * æŒ‚èµ·/激活
 * @param definitionId æµç¨‹å®šä¹‰id
 * @param activityStatus çŠ¶æ€
 * @returns
 */
export const active = (definitionId: string, activityStatus: boolean) => {
  return request({
    url: `/workflow/definition/active/${definitionId}`,
    method: 'put',
    params: {
      active: activityStatus
    }
  });
};
/**
 * é€šè¿‡zip或xml部署流程定义
 * @returns
 */
export function importDef(data: any) {
  return request({
    url: '/workflow/definition/importDef',
    method: 'post',
    data: data,
    headers: {
      repeatSubmit: false
    }
  });
}
/**
 * å‘布流程定义
 * @param id æµç¨‹å®šä¹‰id
 * @returns
 */
export const publish = (id: string) => {
  return request({
    url: `/workflow/definition/publish/${id}`,
    method: 'put'
  });
};
/**
 * å–消发布流程定义
 * @param id æµç¨‹å®šä¹‰id
 * @returns
 */
export const unPublish = (id: string) => {
  return request({
    url: `/workflow/definition/unPublish/${id}`,
    method: 'put'
  });
};
/**
 * èŽ·å–æµç¨‹å®šä¹‰xml字符串
 * @param id æµç¨‹å®šä¹‰id
 * @returns
 */
export const xmlString = (id: string) => {
  return request({
    url: `/workflow/definition/xmlString/${id}`,
    method: 'get'
  });
};
/**
 * æ–°å¢ž
 * @param data å‚æ•°
 * @returns
 */
export const add = (data: FlowDefinitionForm) => {
  return request({
    url: `/workflow/definition`,
    method: 'post',
    data: data
  });
};
/**
 * ä¿®æ”¹
 * @param data å‚æ•°
 * @returns
 */
export const edit = (data: FlowDefinitionForm) => {
  return request({
    url: `/workflow/definition`,
    method: 'put',
    data: data
  });
};
/**
 * æŸ¥è¯¢è¯¦æƒ…
 * @param id å‚æ•°
 * @returns
 */
export const getInfo = (id: number | string) => {
  return request({
    url: `/workflow/definition/${id}`,
    method: 'get'
  });
};
/**
 * å¤åˆ¶æµç¨‹å®šä¹‰
 * @param id æµç¨‹å®šä¹‰id
 * @returns
 */
export const copy = (id: string) => {
  return request({
    url: `/workflow/definition/copy/${id}`,
    method: 'post'
  });
};
src/api/workflow/definition/types.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
export interface FlowDefinitionQuery extends PageQuery {
  flowCode?: string;
  flowName?: string;
  category: string | number;
  isPublish?: number;
}
export interface FlowDefinitionVo {
  id: string;
  flowName: string;
  flowCode: string;
  formPath: string;
  version: string;
  isPublish: number;
  activityStatus: number;
  createTime: Date;
  updateTime: Date;
}
export interface FlowDefinitionForm {
  id: string;
  flowName: string;
  flowCode: string;
  category: string;
  formPath: string;
}
export interface definitionXmlVO {
  xml: string[];
  xmlStr: string;
}
src/api/workflow/definitionConfig/index.ts
ÎļþÒÑɾ³ý
src/api/workflow/definitionConfig/types.ts
ÎļþÒÑɾ³ý
src/api/workflow/formManage/index.ts
ÎļþÒÑɾ³ý
src/api/workflow/formManage/types.ts
ÎļþÒÑɾ³ý
src/api/workflow/instance/index.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,101 @@
import request from '@/utils/request';
import { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types';
import { AxiosPromise } from 'axios';
/**
 * æŸ¥è¯¢è¿è¡Œä¸­å®žä¾‹åˆ—表
 * @param query
 * @returns {*}
 */
export const pageByRunning = (query: FlowInstanceQuery): AxiosPromise<FlowInstanceVO[]> => {
  return request({
    url: '/workflow/instance/pageByRunning',
    method: 'get',
    params: query
  });
};
/**
 * æŸ¥è¯¢å·²å®Œæˆå®žä¾‹åˆ—表
 * @param query
 * @returns {*}
 */
export const pageByFinish = (query: FlowInstanceQuery): AxiosPromise<FlowInstanceVO[]> => {
  return request({
    url: '/workflow/instance/pageByFinish',
    method: 'get',
    params: query
  });
};
/**
 * é€šè¿‡ä¸šåŠ¡id获取历史流程图
 */
export const flowImage = (businessId: string | number) => {
  return request({
    url: `/workflow/instance/flowImage/${businessId}` + '?t' + Math.random(),
    method: 'get'
  });
};
/**
 * åˆ†é¡µæŸ¥è¯¢å½“前登录人单据
 * @param query
 * @returns {*}
 */
export const pageByCurrent = (query: FlowInstanceQuery): AxiosPromise<FlowInstanceVO[]> => {
  return request({
    url: '/workflow/instance/pageByCurrent',
    method: 'get',
    params: query
  });
};
/**
 * æ’¤é”€æµç¨‹
 * @param data å‚æ•°
 * @returns
 */
export const cancelProcessApply = (data: any) => {
  return request({
    url: `/workflow/instance/cancelProcessApply`,
    method: 'put',
    data: data
  });
};
/**
 * èŽ·å–æµç¨‹å˜é‡
 * @param instanceId å®žä¾‹id
 * @returns
 */
export const instanceVariable = (instanceId: string | number) => {
  return request({
    url: `/workflow/instance/instanceVariable/${instanceId}`,
    method: 'get'
  });
};
/**
 * åˆ é™¤
 * @param instanceIds æµç¨‹å®žä¾‹id
 * @returns
 */
export const deleteByInstanceIds = (instanceIds: Array<string | number> | string | number) => {
  return request({
    url: `/workflow/instance/deleteByInstanceIds/${instanceIds}`,
    method: 'delete'
  });
};
/**
 * ä½œåºŸæµç¨‹
 * @param data å‚æ•°
 * @returns
 */
export const invalid = (data: any) => {
  return request({
    url: `/workflow/instance/invalid`,
    method: 'post',
    data: data
  });
};
src/api/workflow/instance/types.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
import { FlowTaskVO } from '@/api/workflow/task/types';
export interface FlowInstanceQuery extends PageQuery {
  category?: string | number;
  nodeName?: string;
  flowCode?: string;
  flowName?: string;
  createByIds?: string[] | number[];
  businessId?: string;
}
export interface FlowInstanceVO extends BaseEntity {
  id: string | number;
  definitionId: string;
  flowName: string;
  flowCode: string;
  version: string;
  businessId: string;
  activityStatus: number;
  tenantId: string;
  createTime: string;
  createBy: string;
  flowStatus: string;
  flowStatusName: string;
  flowTaskList: FlowTaskVO[];
}
src/api/workflow/model/index.ts
ÎļþÒÑɾ³ý
src/api/workflow/model/types.ts
ÎļþÒÑɾ³ý
src/api/workflow/nodeConfig/types.ts
ÎļþÒÑɾ³ý
src/api/workflow/processDefinition/index.ts
ÎļþÒÑɾ³ý
src/api/workflow/processDefinition/types.ts
ÎļþÒÑɾ³ý
src/api/workflow/processInstance/index.ts
ÎļþÒÑɾ³ý
src/api/workflow/processInstance/types.ts
ÎļþÒÑɾ³ý
src/api/workflow/task/index.ts
@@ -1,15 +1,15 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { TaskQuery, TaskVO } from '@/api/workflow/task/types';
import { TaskQuery, FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
/**
 * æŸ¥è¯¢å¾…办列表
 * @param query
 * @returns {*}
 */
export const getPageByTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
export const pageByTaskWait = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
  return request({
    url: '/workflow/task/getPageByTaskWait',
    url: '/workflow/task/pageByTaskWait',
    method: 'get',
    params: query
  });
@@ -20,9 +20,9 @@
 * @param query
 * @returns {*}
 */
export const getPageByTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
export const pageByTaskFinish = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
  return request({
    url: '/workflow/task/getPageByTaskFinish',
    url: '/workflow/task/pageByTaskFinish',
    method: 'get',
    params: query
  });
@@ -33,9 +33,9 @@
 * @param query
 * @returns {*}
 */
export const getPageByTaskCopy = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
export const pageByTaskCopy = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
  return request({
    url: '/workflow/task/getPageByTaskCopy',
    url: '/workflow/task/pageByTaskCopy',
    method: 'get',
    params: query
  });
@@ -46,9 +46,9 @@
 * @param query
 * @returns {*}
 */
export const getPageByAllTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
export const pageByAllTaskWait = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
  return request({
    url: '/workflow/task/getPageByAllTaskWait',
    url: '/workflow/task/pageByAllTaskWait',
    method: 'get',
    params: query
  });
@@ -59,9 +59,9 @@
 * @param query
 * @returns {*}
 */
export const getPageByAllTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
export const pageByAllTaskFinish = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
  return request({
    url: '/workflow/task/getPageByAllTaskFinish',
    url: '/workflow/task/pageByAllTaskFinish',
    method: 'get',
    params: query
  });
@@ -94,30 +94,6 @@
};
/**
 * è®¤é¢†ä»»åŠ¡
 * @param taskId
 * @returns {*}
 */
export const claim = (taskId: string): any => {
  return request({
    url: '/workflow/task/claim/' + taskId,
    method: 'post'
  });
};
/**
 * å½’还任务
 * @param taskId
 * @returns {*}
 */
export const returnTask = (taskId: string): any => {
  return request({
    url: '/workflow/task/returnTask/' + taskId,
    method: 'post'
  });
};
/**
 * ä»»åŠ¡é©³å›ž
 * @param data
 * @returns {*}
@@ -135,61 +111,24 @@
 * @param taskId
 * @returns
 */
export const getTaskById = (taskId: string) => {
export const getTask = (taskId: string) => {
  return request({
    url: '/workflow/task/getTaskById/' + taskId,
    url: '/workflow/task/getTask/' + taskId,
    method: 'get'
  });
};
/**
 * åŠ ç­¾
 * @param data
 * @returns
 */
export const addMultiInstanceExecution = (data: any) => {
  return request({
    url: '/workflow/task/addMultiInstanceExecution',
    method: 'post',
    data: data
  });
};
/**
 * å‡ç­¾
 * @param data
 * @returns
 */
export const deleteMultiInstanceExecution = (data: any) => {
  return request({
    url: '/workflow/task/deleteMultiInstanceExecution',
    method: 'post',
    data: data
  });
};
/**
 * ä¿®æ”¹ä»»åŠ¡åŠžç†äºº
 * @param taskIds
 * @param taskIdList
 * @param userId
 * @returns
 */
export const updateAssignee = (taskIds: Array<string>, userId: string) => {
export const updateAssignee = (taskIdList: Array<string>, userId: string) => {
  return request({
    url: `/workflow/task/updateAssignee/${taskIds}/${userId}`,
    method: 'put'
  });
};
/**
 * è½¬åŠžä»»åŠ¡
 * @returns
 */
export const transferTask = (data: any) => {
  return request({
    url: `/workflow/task/transferTask`,
    method: 'post',
    data: data
    url: `/workflow/task/updateAssignee/${userId}`,
    method: 'put',
    data: taskIdList
  });
};
@@ -206,59 +145,36 @@
};
/**
 * æŸ¥è¯¢æµç¨‹å˜é‡
 * @returns
 */
export const getInstanceVariable = (taskId: string) => {
  return request({
    url: `/workflow/task/getInstanceVariable/${taskId}`,
    method: 'get'
  });
};
/**
 * èŽ·å–å¯é©³å›žå¾—ä»»åŠ¡èŠ‚ç‚¹
 * @returns
 */
export const getTaskNodeList = (processInstanceId: string) => {
export const getBackTaskNode = (definitionId: string, nodeCode: string) => {
  return request({
    url: `/workflow/task/getTaskNodeList/${processInstanceId}`,
    url: `/workflow/task/getBackTaskNode/${definitionId}/${nodeCode}`,
    method: 'get'
  });
};
/**
 * å§”托任务
 * ä»»åŠ¡æ“ä½œ æ“ä½œç±»åž‹ï¼Œå§”æ´¾ delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
 * @returns
 */
export const delegateTask = (data: any) => {
export const taskOperation = (data: TaskOperationBo, operation: string) => {
  return request({
    url: `/workflow/task/delegateTask`,
    url: `/workflow/task/taskOperation/${operation}`,
    method: 'post',
    data: data
  });
};
/**
 * æŸ¥è¯¢å·¥ä½œæµä»»åŠ¡ç”¨æˆ·é€‰æ‹©åŠ ç­¾äººå‘˜
 * @param taskId
 * @returns {*}
 * èŽ·å–å½“å‰ä»»åŠ¡åŠžç†äºº
 * @param taskId ä»»åŠ¡id
 * @returns
 */
export const getTaskUserIdsByAddMultiInstance = (taskId: string) => {
export const currentTaskAllUser = (taskId: string | number) => {
  return request({
    url: '/workflow/task/getTaskUserIdsByAddMultiInstance/' + taskId,
    method: 'get'
  });
};
/**
 * æŸ¥è¯¢å·¥ä½œæµé€‰æ‹©å‡ç­¾äººå‘˜
 * @param taskId
 * @returns {*}
 */
export const getListByDeleteMultiInstance = (taskId: string) => {
  return request({
    url: '/workflow/task/getListByDeleteMultiInstance/' + taskId,
    url: `/workflow/task/currentTaskAllUser/${taskId}`,
    method: 'get'
  });
};
src/api/workflow/task/types.ts
@@ -1,9 +1,8 @@
import { NodeConfigVO } from '@/api/workflow/nodeConfig/types';
import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types';
export interface TaskQuery extends PageQuery {
  name?: string;
  processDefinitionKey?: string;
  processDefinitionName?: string;
  nodeName?: string;
  flowCode?: string;
  flowName?: string;
  createByIds?: string[] | number[];
}
export interface ParticipantVo {
@@ -12,38 +11,38 @@
  candidateName: string[];
  claim: boolean;
}
export interface TaskVO extends BaseEntity {
  id: string;
  name: string;
  description?: string;
  priority: number;
  owner?: string;
  assignee?: string | number;
  assigneeName?: string;
  processInstanceId: string;
  executionId: string;
  taskDefinitionId?: any;
  processDefinitionId: string;
  endTime?: string;
  taskDefinitionKey: string;
  dueDate?: string;
  category?: any;
  parentTaskId?: any;
  tenantId: string;
  claimTime?: string;
  businessStatus?: string;
  businessStatusName?: string;
  processDefinitionName?: string;
  processDefinitionKey?: string;
  participantVo?: ParticipantVo;
  multiInstance?: boolean;
  businessKey?: string;
  wfNodeConfigVo?: NodeConfigVO;
  wfDefinitionConfigVo?: DefinitionConfigVO;
export interface FlowTaskVO {
  id: string | number;
  createTime?: Date;
  updateTime?: Date;
  tenantId?: string;
  definitionId?: string;
  instanceId: string;
  flowName: string;
  businessId: string;
  nodeCode: string;
  nodeName: string;
  flowCode: string;
  flowStatus: string;
  formCustom: string;
  formPath: string;
  nodeType: number;
  nodeRatio: string | number;
  version?: string;
}
export interface VariableVo {
  key: string;
  value: string;
}
export interface TaskOperationBo {
  //委派/转办人的用户ID(必填,准对委派/转办人操作)
  userId?: string;
  //加签/减签人的用户ID列表(必填,针对加签/减签操作)
  userIds?: string[];
  //任务ID(必填)
  taskId: string | number;
  //意见或备注信息(可选)
  message?: string;
}
src/api/workflow/workflowCommon/index.ts
@@ -2,28 +2,14 @@
export default {
  routerJump(routerJumpVo: RouterJumpVo, proxy) {
    if (routerJumpVo.wfNodeConfigVo && routerJumpVo.wfNodeConfigVo.formType === 'static' && routerJumpVo.wfNodeConfigVo.wfFormManageVo) {
      proxy.$tab.closePage(proxy.$route);
      proxy.$router.push({
        path: `${routerJumpVo.wfNodeConfigVo.wfFormManageVo.router}`,
        query: {
          id: routerJumpVo.businessKey,
          type: routerJumpVo.type,
          taskId: routerJumpVo.taskId
        }
      });
    } else if (routerJumpVo.wfNodeConfigVo && routerJumpVo.wfNodeConfigVo.formType === 'dynamic' && routerJumpVo.wfNodeConfigVo.wfFormManageVo) {
      proxy.$tab.closePage(proxy.$route);
      proxy.$router.push({
        path: `${routerJumpVo.wfNodeConfigVo.wfFormManageVo.router}`,
        query: {
          id: routerJumpVo.businessKey,
          type: routerJumpVo.type,
          taskId: routerJumpVo.taskId
        }
      });
    } else {
      proxy?.$modal.msgError('请到模型配置菜单!');
    }
    proxy.$tab.closePage(proxy.$route);
    proxy.$router.push({
      path: routerJumpVo.formPath,
      query: {
        id: routerJumpVo.businessId,
        type: routerJumpVo.type,
        taskId: routerJumpVo.taskId
      }
    });
  }
};
src/api/workflow/workflowCommon/types.ts
@@ -1,16 +1,13 @@
import { NodeConfigVO } from '@/api/workflow/nodeConfig/types';
import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types';
export interface RouterJumpVo {
  wfNodeConfigVo: NodeConfigVO;
  wfDefinitionConfigVo: DefinitionConfigVO;
  businessKey: string;
  taskId: string;
  businessId: string;
  taskId: string | number;
  type: string;
  formCustom: string;
  formPath: string;
}
export interface StartProcessBo {
  businessKey: string | number;
  tableName: string;
  businessId: string | number;
  flowCode: string;
  variables: any;
}
src/assets/styles/variables.module.scss
@@ -14,11 +14,6 @@
  --tableHeaderBg: #f8f8f9;
  --tableHeaderTextColor: #515a6e;
  // å·¥ä½œæµ
  --bpmn-panel-border: #eeeeee;
  --bpmn-panel-box-shadow: #cccccc;
  --bpmn-panel-bar-background-color: #f5f7fa;
  // ele
  --brder-color: #e8e8e8;
@@ -77,11 +72,6 @@
  --vxe-table-border-width: 1px;
  --vxe-table-border-color: #37373a;
  --vxe-toolbar-background-color: #37373a;
  // å·¥ä½œæµ
  --bpmn-panel-border: #37373a;
  --bpmn-panel-box-shadow: #37373a;
  --bpmn-panel-bar-background-color: #37373a;
  // ele
  --brder-color: #37373a;
src/bpmn/assets/defaultXML.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/lang/zh.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/moddle/flowable.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/module/ContextPad/CustomContextPadProvider.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/module/Palette/CustomPaletteProvider.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/module/Renderer/CustomRenderer.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/module/Translate/index.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/module/index.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/showConfig.ts
ÎļþÒÑɾ³ý
src/bpmn/assets/style/index.scss
ÎļþÒÑɾ³ý
src/bpmn/hooks/usePanel.ts
ÎļþÒÑɾ³ý
src/bpmn/hooks/useParseElement.ts
ÎļþÒÑɾ³ý
src/bpmn/index.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/GatewayPanel.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/ParticipantPanel.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/ProcessPanel.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/SequenceFlowPanel.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/StartEndPanel.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/SubProcessPanel.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/TaskPanel.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/index.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/property/DueDate.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/property/ExecutionListener.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/property/ListenerParam.vue
ÎļþÒÑɾ³ý
src/bpmn/panel/property/TaskListener.vue
ÎļþÒÑɾ³ý
src/components/BpmnDesign/index.vue
ÎļþÒÑɾ³ý
src/components/BpmnView/index.vue
ÎļþÒÑɾ³ý
src/components/Process/approvalRecord.vue
@@ -2,39 +2,49 @@
  <div class="container">
    <el-dialog v-model="visible" draggable title="审批记录" :width="props.width" :height="props.height" :close-on-click-modal="false">
      <el-tabs v-model="tabActiveName" class="demo-tabs">
        <el-tab-pane label="流程图" name="bpmn">
          <BpmnView ref="bpmnViewRef"></BpmnView>
        <el-tab-pane v-loading="loading" label="流程图" name="bpmn">
          <img :src="imgUrl" width="100%" style="margin: 0 auto" />
        </el-tab-pane>
        <el-tab-pane v-loading="loading" label="审批信息" name="info">
          <div>
            <el-table :data="historyList" style="width: 100%" border fit>
              <el-table-column type="index" label="序号" align="center" width="60"></el-table-column>
              <el-table-column prop="name" label="任务名称" sortable align="center"></el-table-column>
              <el-table-column prop="nickName" :show-overflow-tooltip="true" label="办理人" sortable align="center">
              <el-table-column prop="nodeName" label="任务名称" sortable align="center"></el-table-column>
              <el-table-column prop="approveName" :show-overflow-tooltip="true" label="办理人" sortable align="center">
                <template #default="scope">
                  <el-tag type="success">{{ scope.row.nickName || '无' }}</el-tag>
                  <template v-if="scope.row.approveName">
                    <el-tag v-for="(item, index) in scope.row.approveName.split(',')" :key="index" type="success">{{ item }}</el-tag>
                  </template>
                  <template v-else> <el-tag type="success">无</el-tag></template>
                </template>
              </el-table-column>
              <el-table-column label="状态" sortable align="center">
              <el-table-column prop="flowStatus" label="状态" width="80" sortable align="center">
                <template #default="scope">
                  <el-tag type="success">{{ scope.row.statusName }}</el-tag>
                  <dict-tag :options="wf_task_status" :value="scope.row.flowStatus"></dict-tag>
                </template>
              </el-table-column>
              <el-table-column prop="comment" label="审批意见" sortable align="center"></el-table-column>
              <el-table-column prop="startTime" label="开始时间" sortable align="center"></el-table-column>
              <el-table-column prop="endTime" label="结束时间" sortable align="center"></el-table-column>
              <el-table-column prop="runDuration" label="运行时长" sortable align="center"></el-table-column>
              <el-table-column prop="attachmentList" label="附件" sortable align="center">
              <el-table-column prop="message" label="审批意见" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
              <el-table-column prop="createTime" label="开始时间" width="160" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
              <el-table-column prop="updateTime" label="结束时间" width="160" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
              <el-table-column
                prop="runDuration"
                label="运行时常"
                width="140"
                :show-overflow-tooltip="true"
                sortable
                align="center"
              ></el-table-column>
              <el-table-column prop="attachmentList" width="120" label="附件" align="center">
                <template #default="scope">
                  <el-popover v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" placement="right" :width="310" trigger="click">
                    <template #reference>
                      <el-button style="margin-right: 16px">附件</el-button>
                      <el-button type="primary" style="margin-right: 16px">附件</el-button>
                    </template>
                    <el-table border :data="scope.row.attachmentList">
                      <el-table-column prop="name" width="202" :show-overflow-tooltip="true" label="附件名称"></el-table-column>
                      <el-table-column prop="originalName" width="202" :show-overflow-tooltip="true" label="附件名称"></el-table-column>
                      <el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="操作">
                        <template #default="tool">
                          <el-button type="text" @click="handleDownload(tool.row.contentId)">下载</el-button>
                          <el-button type="text" @click="handleDownload(tool.row.ossId)">下载</el-button>
                        </template>
                      </el-table-column>
                    </el-table>
@@ -49,36 +59,50 @@
  </div>
</template>
<script lang="ts" setup>
import BpmnView from '@/components/BpmnView/index.vue';
import processApi from '@/api/workflow/processInstance';
import { flowImage } from '@/api/workflow/instance';
import { propTypes } from '@/utils/propTypes';
import { listByIds } from '@/api/system/oss';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { wf_task_status } = toRefs<any>(proxy?.useDict('wf_task_status'));
const props = defineProps({
  width: propTypes.string.def('70%'),
  width: propTypes.string.def('80%'),
  height: propTypes.string.def('100%')
});
const loading = ref(false);
const visible = ref(false);
const historyList = ref<Array<any>>([]);
const tabActiveName = ref('bpmn');
const bpmnViewRef = ref<BpmnView>();
const imgUrl = ref('');
//初始化查询审批记录
const init = async (businessKey: string | number) => {
const init = async (businessId: string | number) => {
  visible.value = true;
  loading.value = true;
  tabActiveName.value = 'bpmn';
  historyList.value = [];
  processApi.getHistoryRecord(businessKey).then((resp) => {
    historyList.value = resp.data;
    loading.value = false;
  flowImage(businessId).then((resp) => {
    if (resp.data) {
      historyList.value = resp.data.list;
      imgUrl.value = 'data:image/gif;base64,' + resp.data.image;
      if (historyList.value.length > 0) {
        historyList.value.forEach((item) => {
          if (item.ext) {
            getIds(item.ext).then((res) => {
              item.attachmentList = res.data;
            });
          } else {
            item.attachmentList = [];
          }
        });
      }
      loading.value = false;
    }
  });
  await nextTick(() => {
    bpmnViewRef.value.init(businessKey);
  });
};
const getIds = async (ids: string | number) => {
  const res = await listByIds(ids);
  return res;
};
/** ä¸‹è½½æŒ‰é’®æ“ä½œ */
src/components/Process/multiInstanceUser.vue
ÎļþÒÑɾ³ý
src/components/Process/processMeddle.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,207 @@
<template>
  <el-dialog v-model="visible" draggable title="流程干预" :width="props.width" :height="props.height" :close-on-click-modal="false">
    <el-descriptions v-loading="loading" class="margin-top" :title="`${task.flowName}(${task.flowCode})`" :column="2" border>
      <el-descriptions-item label="任务名称">{{ task.nodeName }}</el-descriptions-item>
      <el-descriptions-item label="节点编码">{{ task.nodeCode }}</el-descriptions-item>
      <el-descriptions-item label="开始时间">{{ task.createTime }}</el-descriptions-item>
      <el-descriptions-item label="流程实例ID">{{ task.instanceId }}</el-descriptions-item>
      <el-descriptions-item label="版本号">{{ task.version }}.0</el-descriptions-item>
      <el-descriptions-item label="业务ID">{{ task.businessId }}</el-descriptions-item>
    </el-descriptions>
    <template #footer>
      <span class="dialog-footer">
        <el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> è½¬åŠž </el-button>
        <el-button
          v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
          :disabled="buttonDisabled"
          type="primary"
          @click="openMultiInstanceUser"
        >
          åŠ ç­¾
        </el-button>
        <el-button
          v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
          :disabled="buttonDisabled"
          type="primary"
          @click="handleTaskUser"
        >
          å‡ç­¾
        </el-button>
        <el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> ç»ˆæ­¢ </el-button>
      </span>
    </template>
    <!-- è½¬åŠž -->
    <UserSelect ref="transferTaskRef" :multiple="false" @confirm-call-back="handleTransferTask"></UserSelect>
    <!-- åŠ ç­¾ç»„ä»¶ -->
    <UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect>
    <el-dialog v-model="deleteSignatureVisible" draggable title="减签人员" width="700px" height="400px" append-to-body :close-on-click-modal="false"
      ><div>
        <el-table :data="deleteUserList" border>
          <el-table-column prop="nodeName" label="任务名称" />
          <el-table-column prop="nickName" label="办理人" />
          <el-table-column label="操作" align="center" width="160">
            <template #default="scope">
              <el-button type="danger" size="small" icon="Delete" @click="deleteMultiInstanceUser(scope.row)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-dialog>
  </el-dialog>
</template>
<script lang="ts" setup>
import { propTypes } from '@/utils/propTypes';
import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
import UserSelect from '@/components/UserSelect';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
import { getTask, taskOperation, currentTaskAllUser, terminationTask } from '@/api/workflow/task';
const props = defineProps({
  width: propTypes.string.def('50%'),
  height: propTypes.string.def('100%')
});
const emits = defineEmits(['submitCallback']);
const transferTaskRef = ref<InstanceType<typeof UserSelect>>();
const multiInstanceUserRef = ref<InstanceType<typeof UserSelect>>();
//遮罩层
const loading = ref(true);
//按钮
const buttonDisabled = ref(true);
const visible = ref(false);
//减签弹窗
const deleteSignatureVisible = ref(false);
//可减签的人员
const deleteUserList = ref<any>([]);
//任务
const task = ref<FlowTaskVO>({
  id: undefined,
  createTime: undefined,
  updateTime: undefined,
  tenantId: undefined,
  definitionId: undefined,
  instanceId: undefined,
  flowName: undefined,
  businessId: undefined,
  nodeCode: undefined,
  nodeName: undefined,
  flowCode: undefined,
  flowStatus: undefined,
  nodeType: undefined,
  nodeRatio: undefined,
  version: undefined
});
const open = (taskId: string) => {
  visible.value = true;
  getTask(taskId).then((response) => {
    loading.value = false;
    buttonDisabled.value = false;
    task.value = response.data;
  });
};
//打开转办
const openTransferTask = () => {
  transferTaskRef.value.open();
};
//转办
const handleTransferTask = async (data) => {
  if (data && data.length > 0) {
    const taskOperationBo = reactive<TaskOperationBo>({
      userId: data[0].userId,
      taskId: task.value.id,
      message: ''
    });
    await proxy?.$modal.confirm('是否确认提交?');
    loading.value = true;
    buttonDisabled.value = true;
    await taskOperation(taskOperationBo, 'transferTask').finally(() => {
      loading.value = false;
      buttonDisabled.value = false;
    });
    visible.value = false;
    emits('submitCallback');
    proxy?.$modal.msgSuccess('操作成功');
  } else {
    proxy?.$modal.msgWarning('请选择用户!');
  }
};
//加签
const openMultiInstanceUser = async () => {
  multiInstanceUserRef.value.open();
};
//加签
const addMultiInstanceUser = async (data) => {
  if (data && data.length > 0) {
    const taskOperationBo = reactive<TaskOperationBo>({
      userIds: data.map((e) => e.userId),
      taskId: task.value.id,
      message: ''
    });
    await proxy?.$modal.confirm('是否确认提交?');
    loading.value = true;
    buttonDisabled.value = true;
    await taskOperation(taskOperationBo, 'addSignature').finally(() => {
      loading.value = false;
      buttonDisabled.value = false;
    });
    visible.value = false;
    emits('submitCallback');
    proxy?.$modal.msgSuccess('操作成功');
  } else {
    proxy?.$modal.msgWarning('请选择用户!');
  }
};
//减签
const deleteMultiInstanceUser = async (row) => {
  await proxy?.$modal.confirm('是否确认提交?');
  loading.value = true;
  buttonDisabled.value = true;
  const taskOperationBo = reactive<TaskOperationBo>({
    userIds: [row.userId],
    taskId: task.value.id,
    message: ''
  });
  await taskOperation(taskOperationBo, 'reductionSignature').finally(() => {
    loading.value = false;
    buttonDisabled.value = false;
  });
  visible.value = false;
  emits('submitCallback');
  proxy?.$modal.msgSuccess('操作成功');
};
//获取办理人
const handleTaskUser = async () => {
  let data = await currentTaskAllUser(task.value.id);
  deleteUserList.value = data.data;
  if (deleteUserList.value && deleteUserList.value.length > 0) {
    deleteUserList.value.forEach((e) => {
      e.nodeName = task.value.nodeName;
    });
  }
  deleteSignatureVisible.value = true;
};
//终止任务
const handleTerminationTask = async () => {
  let params = {
    taskId: task.value.id,
    comment: ''
  };
  await proxy?.$modal.confirm('是否确认终止?');
  loading.value = true;
  buttonDisabled.value = true;
  await terminationTask(params).finally(() => {
    loading.value = false;
    buttonDisabled.value = false;
  });
  visible.value = false;
  emits('submitCallback');
  proxy?.$modal.msgSuccess('操作成功');
};
/**
 * å¯¹å¤–暴露子组件方法
 */
defineExpose({
  open
});
</script>
src/components/Process/submitVerify.vue
@@ -3,47 +3,47 @@
    <el-form v-loading="loading" :model="form" label-width="120px">
      <el-form-item label="消息提醒">
        <el-checkbox-group v-model="form.messageType">
          <el-checkbox label="1" name="type" disabled>站内信</el-checkbox>
          <el-checkbox label="2" name="type">邮件</el-checkbox>
          <el-checkbox label="3" name="type">短信</el-checkbox>
          <el-checkbox value="1" name="type" disabled>站内信</el-checkbox>
          <el-checkbox value="2" name="type">邮件</el-checkbox>
          <el-checkbox value="3" name="type">短信</el-checkbox>
        </el-checkbox-group>
      </el-form-item>
      <el-form-item v-if="task.businessStatus === 'waiting'" label="附件">
        <fileUpload v-model="form.fileId" :file-type="['doc', 'xls', 'ppt', 'txt', 'pdf', 'xlsx', 'docx', 'zip']" :file-size="'20'" />
      <el-form-item v-if="task.flowStatus === 'waiting'" label="附件">
        <fileUpload v-model="form.fileId" :file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'xlsx', 'xls', 'ppt', 'txt', 'pdf']" :file-size="20" />
      </el-form-item>
      <el-form-item label="抄送">
        <el-button type="primary" icon="Plus" circle @click="openUserSelectCopy" />
        <el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)">
          {{ user.userName }}
          {{ user.nickName }}
        </el-tag>
      </el-form-item>
      <el-form-item v-if="task.businessStatus === 'waiting'" label="审批意见">
      <el-form-item v-if="task.flowStatus === 'waiting'" label="审批意见">
        <el-input v-model="form.message" type="textarea" resize="none" />
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button :disabled="buttonDisabled" type="primary" @click="handleCompleteTask"> æäº¤ </el-button>
        <el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openDelegateTask"> å§”托 </el-button>
        <el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> è½¬åŠž </el-button>
        <el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openDelegateTask"> å§”托 </el-button>
        <el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> è½¬åŠž </el-button>
        <el-button
          v-if="task.businessStatus === 'waiting' && task.multiInstance"
          v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
          :disabled="buttonDisabled"
          type="primary"
          @click="addMultiInstanceUser"
          @click="openMultiInstanceUser"
        >
          åŠ ç­¾
        </el-button>
        <el-button
          v-if="task.businessStatus === 'waiting' && task.multiInstance"
          v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
          :disabled="buttonDisabled"
          type="primary"
          @click="deleteMultiInstanceUser"
          @click="handleTaskUser"
        >
          å‡ç­¾
        </el-button>
        <el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> ç»ˆæ­¢ </el-button>
        <el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleBackProcessOpen"> é€€å›ž </el-button>
        <el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> ç»ˆæ­¢ </el-button>
        <el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleBackProcessOpen"> é€€å›ž </el-button>
        <el-button :disabled="buttonDisabled" @click="cancel">取消</el-button>
      </span>
    </template>
@@ -54,14 +54,14 @@
    <!-- å§”托 -->
    <UserSelect ref="delegateTaskRef" :multiple="false" @confirm-call-back="handleDelegateTask"></UserSelect>
    <!-- åŠ ç­¾ç»„ä»¶ -->
    <multiInstanceUser ref="multiInstanceUserRef" :title="title" @submit-callback="closeDialog" />
    <UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect>
    <!-- é©³å›žå¼€å§‹ -->
    <el-dialog v-model="backVisible" draggable title="驳回" width="40%" :close-on-click-modal="false">
      <el-form v-if="task.businessStatus === 'waiting'" v-loading="backLoading" :model="backForm" label-width="120px">
      <el-form v-if="task.flowStatus === 'waiting'" v-loading="backLoading" :model="backForm" label-width="120px">
        <el-form-item label="驳回节点">
          <el-select v-model="backForm.targetActivityId" clearable placeholder="请选择" style="width: 300px">
            <el-option v-for="item in taskNodeList" :key="item.nodeId" :label="item.nodeName" :value="item.nodeId" />
          <el-select v-model="backForm.nodeCode" clearable placeholder="请选择" style="width: 300px">
            <el-option v-for="item in taskNodeList" :key="item.nodeCode" :label="item.nodeName" :value="item.nodeCode" />
          </el-select>
        </el-form-item>
        <el-form-item label="消息提醒">
@@ -83,6 +83,19 @@
      </template>
    </el-dialog>
    <!-- é©³å›žç»“束 -->
    <el-dialog v-model="deleteSignatureVisible" draggable title="减签人员" width="700px" height="400px" append-to-body :close-on-click-modal="false">
      <div>
        <el-table :data="deleteUserList" border>
          <el-table-column prop="nodeName" label="任务名称" />
          <el-table-column prop="nickName" label="办理人" />
          <el-table-column label="操作" align="center" width="160">
            <template #default="scope">
              <el-button type="danger" size="small" icon="Delete" @click="deleteMultiInstanceUser(scope.row)">删除 </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-dialog>
  </el-dialog>
</template>
@@ -90,18 +103,17 @@
import { ref } from 'vue';
import { ComponentInternalInstance } from 'vue';
import { ElForm } from 'element-plus';
import { completeTask, backProcess, getTaskById, transferTask, terminationTask, getTaskNodeList, delegateTask } from '@/api/workflow/task';
import { completeTask, backProcess, getTask, taskOperation, terminationTask, getBackTaskNode, currentTaskAllUser } from '@/api/workflow/task';
import UserSelect from '@/components/UserSelect';
import MultiInstanceUser from '@/components/Process/multiInstanceUser.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
import { UserVO } from '@/api/system/user/types';
import { TaskVO } from '@/api/workflow/task/types';
import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
const userSelectCopyRef = ref<InstanceType<typeof UserSelect>>();
const transferTaskRef = ref<InstanceType<typeof UserSelect>>();
const delegateTaskRef = ref<InstanceType<typeof UserSelect>>();
//加签组件
const multiInstanceUserRef = ref<InstanceType<typeof MultiInstanceUser>>();
const multiInstanceUserRef = ref<InstanceType<typeof UserSelect>>();
const props = defineProps({
  taskVariables: {
@@ -119,65 +131,53 @@
const selectCopyUserList = ref<UserVO[]>([]);
//抄送人id
const selectCopyUserIds = ref<string>(undefined);
// é©³å›žæ˜¯å¦æ˜¾ç¤º
//可减签的人员
const deleteUserList = ref<any>([]);
//驳回是否显示
const backVisible = ref(false);
const backLoading = ref(true);
const backButtonDisabled = ref(true);
// å¯é©³å›žå¾—任务节点
const taskNodeList = ref([]);
//任务
const task = ref<TaskVO>({
const task = ref<FlowTaskVO>({
  id: undefined,
  name: undefined,
  description: undefined,
  priority: undefined,
  owner: undefined,
  assignee: undefined,
  assigneeName: undefined,
  processInstanceId: undefined,
  executionId: undefined,
  taskDefinitionId: undefined,
  processDefinitionId: undefined,
  endTime: undefined,
  taskDefinitionKey: undefined,
  dueDate: undefined,
  category: undefined,
  parentTaskId: undefined,
  createTime: undefined,
  updateTime: undefined,
  tenantId: undefined,
  claimTime: undefined,
  businessStatus: undefined,
  businessStatusName: undefined,
  processDefinitionName: undefined,
  processDefinitionKey: undefined,
  participantVo: undefined,
  multiInstance: undefined,
  businessKey: undefined,
  wfNodeConfigVo: undefined
  definitionId: undefined,
  instanceId: undefined,
  flowName: undefined,
  businessId: undefined,
  nodeCode: undefined,
  nodeName: undefined,
  flowCode: undefined,
  flowStatus: undefined,
  formCustom: undefined,
  formPath: undefined,
  nodeType: undefined,
  nodeRatio: undefined
});
//加签 å‡ç­¾æ ‡é¢˜
const title = ref('');
const dialog = reactive<DialogOption>({
  visible: false,
  title: '提示'
});
//减签弹窗
const deleteSignatureVisible = ref(false);
const form = ref<Record<string, any>>({
  taskId: undefined,
  message: undefined,
  variables: {},
  messageType: ['1'],
  wfCopyList: []
  flowCopyList: []
});
const backForm = ref<Record<string, any>>({
  taskId: undefined,
  targetActivityId: undefined,
  nodeCode: undefined,
  message: undefined,
  variables: {},
  messageType: ['1']
});
const closeDialog = () => {
  dialog.visible = false;
};
//打开弹窗
const openDialog = (id?: string) => {
  selectCopyUserIds.value = undefined;
@@ -189,7 +189,7 @@
  loading.value = true;
  buttonDisabled.value = true;
  nextTick(() => {
    getTaskById(taskId.value).then((response) => {
    getTask(taskId.value).then((response) => {
      task.value = response.data;
      loading.value = false;
      buttonDisabled.value = false;
@@ -205,15 +205,15 @@
  form.value.taskId = taskId.value;
  form.value.taskVariables = props.taskVariables;
  if (selectCopyUserList.value && selectCopyUserList.value.length > 0) {
    let wfCopyList = [];
    let flowCopyList = [];
    selectCopyUserList.value.forEach((e) => {
      let copyUser = {
        userId: e.userId,
        userName: e.nickName
      };
      wfCopyList.push(copyUser);
      flowCopyList.push(copyUser);
    });
    form.value.wfCopyList = wfCopyList;
    form.value.flowCopyList = flowCopyList;
  }
  await proxy?.$modal.confirm('是否确认提交?');
  loading.value = true;
@@ -236,11 +236,11 @@
  backVisible.value = true;
  backLoading.value = true;
  backButtonDisabled.value = true;
  let data = await getTaskNodeList(task.value.processInstanceId);
  let data = await getBackTaskNode(task.value.definitionId, task.value.nodeCode);
  taskNodeList.value = data.data;
  backLoading.value = false;
  backButtonDisabled.value = false;
  backForm.value.targetActivityId = taskNodeList.value[0].nodeId;
  backForm.value.nodeCode = taskNodeList.value[0].nodeCode;
};
/** é©³å›žæµç¨‹ */
const handleBackProcess = async () => {
@@ -249,7 +249,10 @@
  loading.value = true;
  backLoading.value = true;
  backButtonDisabled.value = true;
  await backProcess(backForm.value).finally(() => (loading.value = false));
  await backProcess(backForm.value).finally(() => {
    loading.value = false;
    buttonDisabled.value = false;
  });
  dialog.visible = false;
  backLoading.value = false;
  backButtonDisabled.value = false;
@@ -282,18 +285,48 @@
  selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(',');
};
//加签
const addMultiInstanceUser = () => {
  if (multiInstanceUserRef.value) {
    title.value = '加签人员';
    multiInstanceUserRef.value.getAddMultiInstanceList(taskId.value, []);
const openMultiInstanceUser = async () => {
  multiInstanceUserRef.value.open();
};
//加签
const addMultiInstanceUser = async (data) => {
  if (data && data.length > 0) {
    const taskOperationBo = reactive<TaskOperationBo>({
      userIds: data.map((e) => e.userId),
      taskId: taskId.value,
      message: form.value.message
    });
    await proxy?.$modal.confirm('是否确认提交?');
    loading.value = true;
    buttonDisabled.value = true;
    await taskOperation(taskOperationBo, 'addSignature').finally(() => {
      loading.value = false;
      buttonDisabled.value = false;
    });
    dialog.visible = false;
    emits('submitCallback');
    proxy?.$modal.msgSuccess('操作成功');
  } else {
    proxy?.$modal.msgWarning('请选择用户!');
  }
};
//减签
const deleteMultiInstanceUser = () => {
  if (multiInstanceUserRef.value) {
    title.value = '减签人员';
    multiInstanceUserRef.value.getDeleteMultiInstanceList(taskId.value);
  }
const deleteMultiInstanceUser = async (row) => {
  await proxy?.$modal.confirm('是否确认提交?');
  loading.value = true;
  buttonDisabled.value = true;
  const taskOperationBo = reactive<TaskOperationBo>({
    userIds: [row.userId],
    taskId: taskId.value,
    message: form.value.message
  });
  await taskOperation(taskOperationBo, 'reductionSignature').finally(() => {
    loading.value = false;
    buttonDisabled.value = false;
  });
  dialog.visible = false;
  emits('submitCallback');
  proxy?.$modal.msgSuccess('操作成功');
};
//打开转办
const openTransferTask = () => {
@@ -302,15 +335,18 @@
//转办
const handleTransferTask = async (data) => {
  if (data && data.length > 0) {
    let params = {
      taskId: taskId.value,
    const taskOperationBo = reactive<TaskOperationBo>({
      userId: data[0].userId,
      comment: form.value.message
    };
      taskId: taskId.value,
      message: form.value.message
    });
    await proxy?.$modal.confirm('是否确认提交?');
    loading.value = true;
    buttonDisabled.value = true;
    await transferTask(params).finally(() => (loading.value = false));
    await taskOperation(taskOperationBo, 'transferTask').finally(() => {
      loading.value = false;
      buttonDisabled.value = false;
    });
    dialog.visible = false;
    emits('submitCallback');
    proxy?.$modal.msgSuccess('操作成功');
@@ -326,15 +362,18 @@
//委托
const handleDelegateTask = async (data) => {
  if (data && data.length > 0) {
    let params = {
      taskId: taskId.value,
    const taskOperationBo = reactive<TaskOperationBo>({
      userId: data[0].userId,
      nickName: data[0].nickName
    };
      taskId: taskId.value,
      message: form.value.message
    });
    await proxy?.$modal.confirm('是否确认提交?');
    loading.value = true;
    buttonDisabled.value = true;
    await delegateTask(params).finally(() => (loading.value = false));
    await taskOperation(taskOperationBo, 'delegateTask').finally(() => {
      loading.value = false;
      buttonDisabled.value = false;
    });
    dialog.visible = false;
    emits('submitCallback');
    proxy?.$modal.msgSuccess('操作成功');
@@ -343,7 +382,7 @@
  }
};
//终止任务
const handleTerminationTask = async (data) => {
const handleTerminationTask = async () => {
  let params = {
    taskId: taskId.value,
    comment: form.value.message
@@ -351,11 +390,24 @@
  await proxy?.$modal.confirm('是否确认终止?');
  loading.value = true;
  buttonDisabled.value = true;
  await terminationTask(params).finally(() => (loading.value = false));
  await terminationTask(params).finally(() => {
    loading.value = false;
    buttonDisabled.value = false;
  });
  dialog.visible = false;
  emits('submitCallback');
  proxy?.$modal.msgSuccess('操作成功');
};
const handleTaskUser = async () => {
  let data = await currentTaskAllUser(taskId.value);
  deleteUserList.value = data.data;
  if (deleteUserList.value && deleteUserList.value.length > 0) {
    deleteUserList.value.forEach((e) => {
      e.nodeName = task.value.nodeName;
    });
  }
  deleteSignatureVisible.value = true;
};
/**
 * å¯¹å¤–暴露子组件方法
src/components/UserSelect/index.vue
@@ -43,7 +43,7 @@
          <el-card shadow="hover">
            <template v-if="prop.multiple" #header>
              <el-tag v-for="user in selectUserList" :key="user.userId" closable style="margin: 2px" @close="handleCloseTag(user)">
                {{ user.userName }}
                {{ user.nickName }}
              </el-tag>
            </template>
@@ -100,14 +100,14 @@
<script setup lang="ts">
import api from '@/api/system/user';
import { UserQuery, UserVO } from '@/api/system/user/types';
import { DeptVO } from '@/api/system/dept/types';
import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
import { VxeTableInstance } from 'vxe-table';
import useDialog from '@/hooks/useDialog';
interface PropType {
  modelValue?: UserVO[] | UserVO | undefined;
  multiple?: boolean;
  data?: string | number | (string | number)[];
  data?: string | number | (string | number)[] | undefined;
}
const prop = withDefaults(defineProps<PropType>(), {
  multiple: true,
@@ -125,7 +125,7 @@
const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const deptName = ref('');
const deptOptions = ref<DeptVO[]>([]);
const deptOptions = ref<DeptTreeVO[]>([]);
const selectUserList = ref<UserVO[]>([]);
const deptTreeRef = ref<ElTreeInstance>();
src/enums/bpmn/IndexEnums.ts
ÎļþÒÑɾ³ý
src/router/index.ts
@@ -176,6 +176,20 @@
        meta: { title: '请假申请', activeMenu: '/workflow/leave', noCache: true }
      }
    ]
  },
  {
    path: '/workflow/design',
    component: Layout,
    hidden: true,
    permissions: ['workflow:leave:edit'],
    children: [
      {
        path: 'index',
        component: () => import('@/views/workflow/processDefinition/design.vue'),
        name: 'design',
        meta: { title: '流程设计', activeMenu: '/workflow/processDefinition', noCache: true }
      }
    ]
  }
];
src/store/modules/modeler.ts
ÎļþÒÑɾ³ý
src/types/bpmn/editor/global.d.ts
ÎļþÒÑɾ³ý
src/types/bpmn/index.d.ts
ÎļþÒÑɾ³ý
src/types/bpmn/moddle.d.ts
ÎļþÒÑɾ³ý
src/types/bpmn/panel.d.ts
ÎļþÒÑɾ³ý
src/views/workflow/category/index.vue
@@ -6,9 +6,6 @@
          <el-form-item label="分类名称" prop="categoryName">
            <el-input v-model="queryParams.categoryName" placeholder="请输入分类名称" clearable @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item label="分类编码" prop="categoryCode">
            <el-input v-model="queryParams.categoryCode" placeholder="请输入分类编码" clearable @keyup.enter="handleQuery" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -21,64 +18,66 @@
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button v-hasPermi="['workflow:category:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
            <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['workflow:category:add']">新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
          </el-col>
          <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>
      <el-table
        ref="categoryTableRef"
        v-loading="loading"
        :data="categoryList"
        row-key="id"
        row-key="categoryId"
        :default-expand-all="isExpandAll"
        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      >
        <el-table-column label="分类名称" prop="categoryName" />
        <el-table-column label="分类编码" align="center" prop="categoryCode" />
        <el-table-column label="排序" align="center" prop="sortNum" />
        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <el-table-column label="分类名称" prop="categoryName" width="260"/>
        <el-table-column label="显示顺序" align="center" prop="orderNum" width="200" />
        <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
        <el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-tooltip content="修改" placement="top">
              <el-button v-hasPermi="['workflow:category:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['workflow:category:edit']" />
            </el-tooltip>
            <el-tooltip content="新增" placement="top">
              <el-button v-hasPermi="['workflow:category:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
              <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['workflow:category:add']" />
            </el-tooltip>
            <el-tooltip content="删除" placement="top">
              <el-button v-hasPermi="['workflow:category:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['workflow:category:remove']" />
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹æµç¨‹åˆ†ç±»å¯¹è¯æ¡† -->
    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
      <el-form ref="categoryFormRef" v-loading="loading" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="父级分类" prop="parentId">
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
      <el-form ref="categoryFormRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="上级分类" prop="parentId">
          <el-tree-select
            v-model="form.parentId"
            :data="categoryOptions"
            :props="{ value: 'id', label: 'categoryName', children: 'children' }"
            value-key="id"
            placeholder="请选择父级id"
            :props="{ value: 'categoryId', label: 'categoryName', children: 'children' }"
            value-key="categoryId"
            placeholder="请选择上级分类"
            check-strictly
          />
        </el-form-item>
        <el-form-item label="分类名称" prop="categoryName">
          <el-input v-model="form.categoryName" placeholder="请输入分类名称" />
        </el-form-item>
        <el-form-item label="分类编码" prop="categoryCode">
          <el-input v-model="form.categoryCode" placeholder="请输入分类编码" />
        </el-form-item>
        <el-form-item label="排序" prop="sortNum">
          <el-input-number v-model="form.sortNum" placeholder="请输入排序" controls-position="right" :min="0" />
        </el-form-item>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="分类名称" prop="categoryName">
              <el-input v-model="form.categoryName" placeholder="请输入分类名称" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="排序" prop="orderNum">
              <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
    <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
@@ -89,16 +88,17 @@
</template>
<script setup name="Category" lang="ts">
import { listCategory, getCategory, delCategory, addCategory, updateCategory } from '@/api/workflow/category';
import { listCategory, getCategory, delCategory, addCategory, updateCategory } from "@/api/workflow/category";
import { CategoryVO, CategoryQuery, CategoryForm } from '@/api/workflow/category/types';
type CategoryOption = {
  id: number;
  categoryId: number;
  categoryName: string;
  children?: CategoryOption[];
};
}
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { proxy } = getCurrentInstance() as ComponentInternalInstance;;
const categoryList = ref<CategoryVO[]>([]);
const categoryOptions = ref<CategoryOption[]>([]);
@@ -109,34 +109,32 @@
const queryFormRef = ref<ElFormInstance>();
const categoryFormRef = ref<ElFormInstance>();
const categoryTableRef = ref<ElTableInstance>();
const categoryTableRef = ref<ElTableInstance>()
const dialog = reactive<DialogOption>({
  visible: false,
  title: ''
});
const initFormData: CategoryForm = {
  id: undefined,
  categoryName: undefined,
  categoryCode: undefined,
  categoryId: undefined,
  categoryName: "",
  parentId: undefined,
  sortNum: 0
};
  orderNum: 0,
}
const data = reactive<PageData<CategoryForm, CategoryQuery>>({
  form: { ...initFormData },
  form: {...initFormData},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    categoryName: undefined,
    categoryCode: undefined
  },
  rules: {
    id: [{ required: true, message: '主键不能为空', trigger: 'blur' }],
    categoryName: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }],
    categoryCode: [{ required: true, message: '分类编码不能为空', trigger: 'blur' }],
    parentId: [{ required: true, message: '父级id不能为空', trigger: 'blur' }]
    categoryId: [
      { required: true, message: "流程分类ID不能为空", trigger: "blur" }
    ],
    parentId: [{ required: true, message: "请选择上级分类", trigger: "change" }],
    categoryName: [{ required: true, message: "请输入分类名称", trigger: "blur" }]
  }
});
@@ -146,116 +144,112 @@
const getList = async () => {
  loading.value = true;
  const res = await listCategory(queryParams.value);
  const data = proxy?.handleTree<CategoryVO>(res.data, 'id', 'parentId');
  const data = proxy?.handleTree<CategoryVO>(res.data, "categoryId", "parentId");
  if (data) {
    categoryList.value = data;
    loading.value = false;
  }
};
}
/** æŸ¥è¯¢æµç¨‹åˆ†ç±»ä¸‹æ‹‰æ ‘结构 */
const getTreeselect = async () => {
  const res = await listCategory();
  categoryOptions.value = [];
  const data: CategoryOption = { id: 0, categoryName: '顶级节点', children: [] };
  data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId');
  categoryOptions.value.push(data);
  // å¤„理树形数据
  const data = proxy?.handleTree<CategoryOption>(res.data, "categoryId", "parentId");
  if (data) {
    categoryOptions.value = data; // å°†å¤„理后的树形数据赋值
  }
};
// å–消按钮
const cancel = () => {
  reset();
  dialog.visible = false;
};
}
// è¡¨å•重置
const reset = () => {
  form.value = { ...initFormData };
  form.value = {...initFormData}
  categoryFormRef.value?.resetFields();
};
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  getList();
};
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
  queryFormRef.value?.resetFields();
  handleQuery();
};
}
/** æ–°å¢žæŒ‰é’®æ“ä½œ */
const handleAdd = (row?: CategoryVO) => {
  reset();
  getTreeselect();
  if (row?.categoryId) {
    form.value.parentId = row.categoryId;
  } else {
    form.value.parentId = undefined;
  }
  dialog.visible = true;
  dialog.title = '添加流程分类';
  nextTick(() => {
    reset();
    getTreeselect();
    if (row != null && row.id) {
      form.value.parentId = row.id;
    } else {
      form.value.parentId = 0;
    }
  });
};
  dialog.title = "添加流程分类";
}
/** å±•å¼€/折叠操作 */
const handleToggleExpandAll = () => {
  isExpandAll.value = !isExpandAll.value;
  toggleExpandAll(categoryList.value, isExpandAll.value);
};
  toggleExpandAll(categoryList.value, isExpandAll.value)
}
/** å±•å¼€/折叠操作 */
const toggleExpandAll = (data: CategoryVO[], status: boolean) => {
  data.forEach((item) => {
    categoryTableRef.value?.toggleRowExpansion(item, status);
    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
  });
};
    categoryTableRef.value?.toggleRowExpansion(item, status)
    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
  })
}
/** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
const handleUpdate = (row: CategoryVO) => {
  loading.value = true;
const handleUpdate = async (row: CategoryVO) => {
  reset();
  await getTreeselect();
  if (row != null) {
    form.value.parentId = row.parentId;
  }
  const res = await getCategory(row.categoryId);
  Object.assign(form.value, res.data);
  dialog.visible = true;
  dialog.title = '修改流程分类';
  nextTick(async () => {
    reset();
    await getTreeselect();
    if (row != null) {
      form.value.parentId = row.id;
    }
    const res = await getCategory(row.id);
    loading.value = false;
    Object.assign(form.value, res.data);
  });
};
  dialog.title = "修改流程分类";
}
/** æäº¤æŒ‰é’® */
const submitForm = () => {
  categoryFormRef.value.validate(async (valid: boolean) => {
  categoryFormRef.value?.validate(async (valid: boolean) => {
    if (valid) {
      buttonLoading.value = true;
      if (form.value.id) {
        await updateCategory(form.value).finally(() => (buttonLoading.value = false));
      if (form.value.categoryId) {
        await updateCategory(form.value).finally(() => buttonLoading.value = false);
      } else {
        await addCategory(form.value).finally(() => (buttonLoading.value = false));
        await addCategory(form.value).finally(() => buttonLoading.value = false);
      }
      proxy?.$modal.msgSuccess('操作成功');
      proxy?.$modal.msgSuccess("操作成功");
      dialog.visible = false;
      await getList();
      getList();
    }
  });
};
}
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
const handleDelete = async (row: CategoryVO) => {
  await proxy?.$modal.confirm('是否确认删除流程分类编号为"' + row.id + '"的数据项?');
  await proxy?.$modal.confirm('是否确认删除"' + row.categoryName + '"的分类?');
  loading.value = true;
  await delCategory(row.id).finally(() => (loading.value = false));
  await delCategory(row.categoryId).finally(() => loading.value = false);
  await getList();
  proxy?.$modal.msgSuccess('删除成功');
};
  proxy?.$modal.msgSuccess("删除成功");
}
onMounted(() => {
  getList();
src/views/workflow/formManage/index.vue
ÎļþÒÑɾ³ý
src/views/workflow/leave/index.vue
@@ -31,7 +31,7 @@
        </el-row>
      </template>
      <el-table v-loading="loading" :data="leaveList" @selection-change="handleSelectionChange">
      <el-table v-loading="loading" border :data="leaveList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column v-if="false" label="主键" align="center" prop="id" />
        <el-table-column label="请假类型" align="center">
@@ -56,38 +56,28 @@
            <dict-tag :options="wf_business_status" :value="scope.row.status"></dict-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <el-table-column label="操作" align="center" width="162">
          <template #default="scope">
            <el-button
              v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'"
              v-hasPermi="['workflow:leave:edit']"
              size="small"
              link
              type="primary"
              icon="Edit"
              @click="handleUpdate(scope.row)"
              >修改</el-button
            >
            <el-button
              v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'"
              v-hasPermi="['workflow:leave:remove']"
              size="small"
              link
              type="primary"
              icon="Delete"
              @click="handleDelete(scope.row)"
              >删除</el-button
            >
            <el-button link type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button>
            <el-button
              v-if="scope.row.status === 'waiting'"
              link
              size="small"
              type="primary"
              icon="Notification"
              @click="handleCancelProcessApply(scope.row.id)"
              >撤销</el-button
            >
            <el-row :gutter="10" class="mb8">
              <el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
                <el-button v-hasPermi="['workflow:leave:edit']" size="small" type="primary" icon="Edit" @click="handleUpdate(scope.row)"
                  >修改</el-button
                >
              </el-col>
              <el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
                <el-button v-hasPermi="['workflow:leave:remove']" size="small" type="primary" 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="handleCancelProcessApply(scope.row.id)">撤销</el-button>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
      </el-table>
@@ -99,7 +89,7 @@
<script setup name="Leave" lang="ts">
import { delLeave, listLeave } from '@/api/workflow/leave';
import { cancelProcessApply } from '@/api/workflow/processInstance';
import { cancelProcessApply } from '@/api/workflow/instance';
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -232,7 +222,11 @@
const handleCancelProcessApply = async (id: string) => {
  await proxy?.$modal.confirm('是否确认撤销当前单据?');
  loading.value = true;
  await cancelProcessApply(id).finally(() => (loading.value = false));
  let data = {
    businessId: id,
    message: '申请人撤销流程!'
  };
  await cancelProcessApply(data).finally(() => (loading.value = false));
  await getList();
  proxy?.$modal.msgSuccess('撤销成功');
};
src/views/workflow/leave/leaveEdit.vue
@@ -44,6 +44,17 @@
    <submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
    <!-- å®¡æ‰¹è®°å½• -->
    <approvalRecord ref="approvalRecordRef" />
    <el-dialog v-model="dialogVisible.visible" :title="dialogVisible.title" :before-close="handleClose" width="500">
      <el-select v-model="flowCode" placeholder="Select" style="width: 240px">
        <el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
      </el-select>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="handleClose">取消</el-button>
          <el-button type="primary" @click="submitFlow()"> ç¡®è®¤ </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
@@ -80,6 +91,35 @@
    label: '婚假'
  }
];
const flowCodeOptions = [
  {
    value: 'leave1',
    label: '请假申请-普通'
  },
  {
    value: 'leave2',
    label: '请假申请-排他网关'
  },
  {
    value: 'leave3',
    label: '请假申请-并行网关'
  },
  {
    value: 'leave4',
    label: '请假申请-会签'
  },
  {
    value: 'leave5',
    label: '请假申请-并行会签网关'
  }
];
const flowCode = ref<string>('');
const dialogVisible = reactive<DialogOption>({
  visible: false,
  title: '流程定义'
});
//提交组件
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
//审批记录组件
@@ -88,8 +128,8 @@
const leaveFormRef = ref<ElFormInstance>();
const submitFormData = ref<StartProcessBo>({
  businessKey: '',
  tableName: '',
  businessId: '',
  flowCode: '',
  variables: {}
});
const taskVariables = ref<Record<string, any>>({});
@@ -119,6 +159,11 @@
  }
});
const handleClose = () => {
  dialogVisible.visible = false;
  flowCode.value = '';
  buttonLoading.value = false;
};
const { form, rules } = toRefs(data);
/** è¡¨å•重置 */
@@ -174,6 +219,15 @@
          proxy.$tab.closePage(proxy.$route);
          proxy.$router.go(-1);
        } else {
          if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
            flowCode.value = flowCodeOptions[0].value;
            dialogVisible.visible = true;
            return;
          }
          //说明启动过先随意穿个参数
          if (flowCode.value === '' || flowCode.value === null) {
            flowCode.value = 'xx';
          }
          await handleStartWorkFlow(res.data);
        }
      }
@@ -183,17 +237,19 @@
  }
};
const submitFlow = async () => {
  handleStartWorkFlow(form.value);
  dialogVisible.visible = false;
};
//提交申请
const handleStartWorkFlow = async (data: LeaveVO) => {
  try {
    submitFormData.value.tableName = 'test_leave';
    submitFormData.value.businessKey = data.id;
    submitFormData.value.flowCode = flowCode.value;
    submitFormData.value.businessId = data.id;
    //流程变量
    taskVariables.value = {
      entity: data,
      leaveDays: data.leaveDays,
      userList: ['1', '3'],
      userList2: ['1', '3']
      userList: ['1', '3', '4']
    };
    submitFormData.value.variables = taskVariables.value;
    const resp = await startWorkFlow(submitFormData.value);
src/views/workflow/model/index.vue
ÎļþÒÑɾ³ý
src/views/workflow/processDefinition/components/processPreview.vue
ÎļþÒÑɾ³ý
src/views/workflow/processDefinition/design.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
<template>
  <div ref="container" class="container">
    <iframe ref="iframe" :src="iframeUrl" frameborder="0" width="100%" height="100%"></iframe>
  </div>
</template>
<script setup name="WarmFlow">
const { proxy } = getCurrentInstance();
import { onMounted } from 'vue';
// definitionId为需要查询的流程定义id,
// disabled为是否可编辑, ä¾‹å¦‚:查看的时候不可编辑,不可保存
const iframeUrl = ref('');
const baseUrl = import.meta.env.VITE_APP_BASE_API;
import { getToken } from '@/utils/auth';
const iframeLoaded = () => {
  // iframe监听组件内设计器保存事件
  window.onmessage = (event) => {
    switch (event.data.method) {
      case 'close':
        close();
        break;
    }
  };
};
const open = async (definitionId, disabled) => {
  let url = baseUrl + `/warm-flow-ui/index.html?id=${definitionId}&disabled=${disabled}`;
  iframeUrl.value = url + '&Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID;
};
/** å…³é—­æŒ‰é’® */
function close() {
  const obj = { path: '/workflow/processDefinition' };
  proxy.$tab.closeOpenPage(obj);
}
onMounted(() => {
  iframeLoaded();
  open(proxy.$route.query.definitionId, proxy.$route.query.disabled);
});
/**
 * å¯¹å¤–暴露子组件方法
 */
defineExpose({
  open
});
</script>
<style scoped>
.container {
  width: 100%;
  height: calc(100vh - 84px);
}
</style>
src/views/workflow/processDefinition/index.vue
@@ -10,7 +10,7 @@
            class="mt-2"
            node-key="id"
            :data="categoryOptions"
            :props="{ label: 'categoryName', children: 'children' }"
            :props="{ label: 'label', children: 'children' }"
            :expand-on-click-node="false"
            :filter-node-method="filterNode"
            highlight-current
@@ -24,11 +24,11 @@
          <div v-show="showSearch" class="mb-[10px]">
            <el-card shadow="hover">
              <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
                <el-form-item label="流程定义名称" prop="name">
                  <el-input v-model="queryParams.name" placeholder="请输入流程定义名称" clearable @keyup.enter="handleQuery" />
                <el-form-item label="流程定义名称" prop="flowName">
                  <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" clearable @keyup.enter="handleQuery" />
                </el-form-item>
                <el-form-item label="流程定义KEY" prop="key">
                  <el-input v-model="queryParams.key" placeholder="请输入流程定义KEY" clearable @keyup.enter="handleQuery" />
                <el-form-item label="流程定义KEY" prop="flowCode">
                  <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义KEY" clearable @keyup.enter="handleQuery" />
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -42,93 +42,86 @@
          <template #header>
            <el-row :gutter="10" class="mb8">
              <el-col :span="1.5">
                <el-button type="primary" icon="Plus" @click="handleAdd()">添加</el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button type="success" icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button type="danger" icon="Delete" :disabled="multiple" @click="handleDelete()">删除</el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button type="primary" icon="UploadFilled" @click="uploadDialog.visible = true">部署流程文件</el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button type="warning" icon="Download" :disabled="single" @click="handleExportDef">导出</el-button>
              </el-col>
              <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
            </el-row>
          </template>
          <el-table v-loading="loading" border :data="processDefinitionList" @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="55" align="center" />
            <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
            <el-table-column align="center" prop="name" label="流程定义名称" :show-overflow-tooltip="true"></el-table-column>
            <el-table-column align="center" prop="key" label="标识KEY" width="80"></el-table-column>
            <el-table-column align="center" prop="version" label="版本号" width="80">
              <template #default="scope"> v{{ scope.row.version }}.0</template>
            </el-table-column>
            <el-table-column align="center" prop="resourceName" label="流程XML" width="100" :show-overflow-tooltip="true">
              <template #default="scope">
                <el-link type="primary" @click="clickPreview(scope.row.id, 'xml')">{{ scope.row.resourceName }}</el-link>
              </template>
            </el-table-column>
            <el-table-column align="center" prop="diagramResourceName" label="流程图片" width="100" :show-overflow-tooltip="true">
              <template #default="scope">
                <el-link type="primary" @click="clickPreview(scope.row.id, 'bpmn')">{{ scope.row.diagramResourceName }}</el-link>
              </template>
            </el-table-column>
            <el-table-column align="center" prop="suspensionState" label="状态" width="80">
              <template #default="scope">
                <el-tag v-if="scope.row.suspensionState == 1" type="success">激活</el-tag>
                <el-tag v-else type="danger">挂起</el-tag>
              </template>
            </el-table-column>
            <el-table-column align="center" prop="deploymentTime" label="部署时间" width="120" :show-overflow-tooltip="true"></el-table-column>
            <el-table-column align="center" label="表名/表单KEY" width="120" :show-overflow-tooltip="true">
              <template #default="scope">
                <span v-if="scope.row.wfDefinitionConfigVo">
                  {{ scope.row.wfDefinitionConfigVo.tableName }}
                </span>
              </template>
            </el-table-column>
            <el-table-column fixed="right" label="操作" align="center" width="220" class-name="small-padding fixed-width">
              <template #default="scope">
                <el-row :gutter="10" class="mb8">
                  <el-col :span="1.5">
                    <el-button
                      link
                      type="primary"
                      size="small"
                      :icon="scope.row.suspensionState === 1 ? 'Lock' : 'Unlock'"
                      @click="handleProcessDefState(scope.row)"
                    >
                      {{ scope.row.suspensionState === 1 ? '挂起流程' : '激活流程' }}
                    </el-button>
                  </el-col>
                  <el-col :span="1.5">
                    <el-button link type="primary" size="small" icon="Document" @click="getProcessDefinitionHitoryList(scope.row.id, scope.row.key)">
                      åŽ†å²ç‰ˆæœ¬
                    </el-button>
                  </el-col>
                  <el-col :span="1.5">
                    <el-button link 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 link type="primary" size="small" icon="Sort" @click="handleConvertToModel(scope.row)"> è½¬æ¢æ¨¡åž‹ </el-button>
                  </el-col>
                  <el-col :span="1.5">
                    <el-button link type="primary" size="small" icon="Tickets" @click="handleDefinitionConfigOpen(scope.row)">绑定业务</el-button>
                  </el-col>
                </el-row>
              </template>
            </el-table-column>
          </el-table>
          <pagination
            v-show="total > 0"
            v-model:page="queryParams.pageNum"
            v-model:limit="queryParams.pageSize"
            :total="total"
            @pagination="getList"
          />
          <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
            <el-tab-pane label="已发布" name="0"></el-tab-pane>
            <el-tab-pane label="未发布" name="1"></el-tab-pane>
            <el-table v-loading="loading" border :data="processDefinitionList" @selection-change="handleSelectionChange">
              <el-table-column type="selection" width="55" align="center" />
              <el-table-column align="center" prop="id" label="主键" v-if="false"></el-table-column>
              <el-table-column align="center" prop="flowName" label="流程定义名称" :show-overflow-tooltip="true"></el-table-column>
              <el-table-column align="center" prop="flowCode" label="标识KEY" :show-overflow-tooltip="true"></el-table-column>
              <el-table-column align="center" prop="version" label="版本号" width="80">
                <template #default="scope"> v{{ scope.row.version }}.0</template>
              </el-table-column>
              <el-table-column align="center" prop="activityStatus" label="激活状态" width="130">
                <template #default="scope">
                  <el-switch
                    v-model="scope.row.activityStatus"
                    :active-value="1"
                    :inactive-value="0"
                    @change="(status) => handleProcessDefState(scope.row, status)"
                  />
                </template>
              </el-table-column>
              <el-table-column align="center" prop="isPublish" label="发布状态" width="100">
                <template #default="scope">
                  <el-tag v-if="scope.row.isPublish == 0" type="danger">未发布</el-tag>
                  <el-tag v-else-if="scope.row.isPublish == 1" type="success">已发布</el-tag>
                  <el-tag v-else type="danger">失效</el-tag>
                </template>
              </el-table-column>
              <el-table-column fixed="right" label="操作" align="center" width="170" class-name="small-padding fixed-width">
                <template #default="scope">
                  <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                      <el-button link type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">删除流程</el-button>
                    </el-col>
                    <el-col :span="1.5">
                      <el-button link type="primary" size="small" icon="CopyDocument" @click="handleCopyDef(scope.row)">复制流程</el-button>
                    </el-col>
                  </el-row>
                  <el-row :gutter="10" class="mb8">
                    <el-col :span="1.5">
                      <el-button link type="primary" v-if="scope.row.isPublish === 0" icon="Pointer" size="small" @click="design(scope.row)"
                        >流程设计</el-button
                      >
                      <el-button link type="primary" v-else icon="View" size="small" @click="designView(scope.row)">查看流程</el-button>
                    </el-col>
                    <el-col v-if="scope.row.isPublish !== 1" :span="1.5">
                      <el-button link type="primary" size="small" icon="CircleCheck" @click="handlePublish(scope.row)">发布流程</el-button>
                    </el-col>
                  </el-row>
                </template>
              </el-table-column>
            </el-table>
            <pagination
              v-show="total > 0"
              v-model:page="queryParams.pageNum"
              v-model:limit="queryParams.pageSize"
              :total="total"
              @pagination="handleQuery"
            />
          </el-tabs>
        </el-card>
      </el-col>
    </el-row>
    <!-- é¢„览图片或xml -->
    <process-preview ref="previewRef" />
    <!-- éƒ¨ç½²æ–‡ä»¶ -->
    <el-dialog v-if="uploadDialog.visible" v-model="uploadDialog.visible" :title="uploadDialog.title" width="30%">
@@ -138,9 +131,9 @@
          <el-tree-select
            v-model="selectCategory"
            :data="categoryOptions"
            :props="{ value: 'categoryCode', label: 'categoryName', children: 'children' }"
            :props="{ value: 'id', label: 'label', children: 'children' }"
            filterable
            value-key="categoryCode"
            value-key="id"
            :render-after-expand="false"
            check-strictly
            style="width: 240px"
@@ -152,7 +145,7 @@
          multiple
          accept="application/zip,application/xml,.bpmn"
          :before-upload="handlerBeforeUpload"
          :http-request="handerDeployProcessFile"
          :http-request="handlerImportDefinition"
        >
          <el-icon class="UploadFilled"><upload-filled /></el-icon>
          <div class="el-upload__text"><em>点击上传,选择BPMN流程文件</em></div>
@@ -162,88 +155,35 @@
      </div>
    </el-dialog>
    <!-- åŽ†å²ç‰ˆæœ¬ -->
    <el-dialog v-if="processDefinitionDialog.visible" v-model="processDefinitionDialog.visible" :title="processDefinitionDialog.title" width="70%">
      <el-table v-loading="loading" :data="processDefinitionHistoryList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
        <el-table-column align="center" prop="name" label="流程定义名称" :show-overflow-tooltip="true" min-width="80"></el-table-column>
        <el-table-column align="center" prop="key" label="标识KEY"></el-table-column>
        <el-table-column align="center" prop="version" label="版本号" width="90">
          <template #default="scope"> v{{ scope.row.version }}.0</template>
        </el-table-column>
        <el-table-column align="center" prop="resourceName" label="流程XML" min-width="80" :show-overflow-tooltip="true">
          <template #default="scope">
            <el-link type="primary" @click="clickPreviewXML(scope.row.id)">{{ scope.row.resourceName }}</el-link>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="diagramResourceName" label="流程图片" min-width="80" :show-overflow-tooltip="true">
          <template #default="scope">
            <el-link type="primary" @click="clickPreviewImg(scope.row.id)">{{ scope.row.diagramResourceName }}</el-link>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="suspensionState" label="状态" min-width="70">
          <template #default="scope">
            <el-tag v-if="scope.row.suspensionState == 1" type="success">激活</el-tag>
            <el-tag v-else type="danger">挂起</el-tag>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="deploymentTime" label="部署时间" :show-overflow-tooltip="true"></el-table-column>
        <el-table-column fixed="right" label="操作" align="center" width="200" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-row :gutter="10" class="mb8">
              <el-col :span="1.5">
                <el-button
                  link
                  type="primary"
                  size="small"
                  :icon="scope.row.suspensionState === 1 ? 'Lock' : 'Unlock'"
                  @click="handleProcessDefState(scope.row)"
                >
                  {{ scope.row.suspensionState === 1 ? '挂起流程' : '激活流程' }}
                </el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button type="text" size="small" icon="Tickets" @click="handleDefinitionConfigOpen(scope.row)">绑定业务</el-button>
              </el-col>
            </el-row>
            <el-row :gutter="10" class="mb8">
              <el-col :span="1.5">
                <el-button link type="primary" icon="Sort" size="small" @click="handleConvertToModel(scope.row)"> è½¬æ¢æ¨¡åž‹ </el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button link type="primary" icon="Delete" size="small" @click="handleDelete(scope.row)">删除</el-button>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <!-- è¡¨å•配置 -->
    <el-dialog
      v-model="definitionConfigDialog.visible"
      :title="definitionConfigDialog.title"
      width="650px"
      append-to-body
      :close-on-click-modal="false"
    >
      <el-form :model="definitionConfigForm" label-width="auto">
        <el-form-item label="流程KEY">
          <el-input v-model="definitionConfigForm.processKey" disabled />
        </el-form-item>
        <el-form-item label="表名" prop="formId">
          <el-input v-model="definitionConfigForm.tableName" placeholder="示例:test_leave" />
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="definitionConfigForm.remark" type="textarea" resize="none" />
        </el-form-item>
      </el-form>
    <!-- æ–°å¢ž/编辑流程定义 -->
    <el-dialog v-model="modelDialog.visible" :title="modelDialog.title" width="650px" append-to-body :close-on-click-modal="false">
      <template #footer>
        <el-form ref="defFormRef" :model="form" :rules="rules" label-width="110px">
          <el-form-item label="流程类别" prop="category">
            <el-tree-select
              v-model="form.category"
              :data="categoryOptions"
              :props="{ value: 'id', label: 'label', children: 'children' }"
              filterable
              value-key="id"
              :render-after-expand="false"
              check-strictly
              style="width: 100%"
            />
          </el-form-item>
          <el-form-item label="流程编码" prop="flowCode">
            <el-input v-model="form.flowCode" placeholder="请输入流程编码" maxlength="40" show-word-limit />
          </el-form-item>
          <el-form-item label="流程名称" prop="flowName">
            <el-input v-model="form.flowName" placeholder="请输入流程名称" maxlength="100" show-word-limit />
          </el-form-item>
          <el-form-item label="表单路径" prop="flowName">
            <el-input v-model="form.formPath" placeholder="请输入表单路径" maxlength="100" show-word-limit />
          </el-form-item>
        </el-form>
        <div class="dialog-footer">
          <el-button @click="definitionConfigDialog.visible = false">取消</el-button>
          <el-button type="primary" @click="handlerSaveForm">保存</el-button>
          <el-button @click="modelDialog.visible = false">取消</el-button>
          <el-button type="primary" @click="handleSubmit">保存</el-button>
        </div>
      </template>
    </el-dialog>
@@ -251,53 +191,32 @@
</template>
<script lang="ts" setup name="processDefinition">
import {
  listProcessDefinition,
  definitionImage,
  definitionXml,
  deleteProcessDefinition,
  updateDefinitionState,
  convertToModel,
  deployProcessFile,
  getListByKey
} from '@/api/workflow/processDefinition';
import { getByTableNameNotDefId, getByDefId, saveOrUpdate } from '@/api/workflow/definitionConfig';
import ProcessPreview from './components/processPreview.vue';
import { listCategory } from '@/api/workflow/category';
import { CategoryVO } from '@/api/workflow/category/types';
import { ProcessDefinitionQuery, ProcessDefinitionVO } from '@/api/workflow/processDefinition/types';
import { DefinitionConfigForm } from '@/api/workflow/definitionConfig/types';
import { UploadRequestOptions, ElMessage, ElMessageBox } from 'element-plus';
import { listDefinition, deleteDefinition, active, importDef, unPublishList, publish, add, edit, getInfo, copy } from '@/api/workflow/definition';
import { categoryTree } from '@/api/workflow/category';
import { CategoryTreeVO } from '@/api/workflow/category/types';
import { FlowDefinitionQuery, FlowDefinitionVo, FlowDefinitionForm } from '@/api/workflow/definition/types';
import { UploadRequestOptions, TabsPaneContext } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const previewRef = ref<InstanceType<typeof ProcessPreview>>();
const queryFormRef = ref<ElFormInstance>();
const categoryTreeRef = ref<ElTreeInstance>();
const definitionConfigForm = ref<DefinitionConfigForm>({});
type CategoryOption = {
  categoryCode: string;
  categoryName: string;
  children?: CategoryOption[];
};
const loading = ref(true);
const ids = ref<Array<any>>([]);
const deploymentIds = ref<Array<any>>([]);
const keys = ref<Array<any>>([]);
const flowCodeList = ref<Array<any>>([]);
const single = ref(true);
const multiple = ref(true);
const showSearch = ref(true);
const total = ref(0);
const uploadDialogLoading = ref(false);
const processDefinitionList = ref<ProcessDefinitionVO[]>([]);
const processDefinitionHistoryList = ref<ProcessDefinitionVO[]>([]);
const categoryOptions = ref<CategoryOption[]>([]);
const processDefinitionList = ref<FlowDefinitionVo[]>([]);
const categoryOptions = ref<CategoryTreeVO[]>([]);
const categoryName = ref('');
/** éƒ¨ç½²æ–‡ä»¶åˆ†ç±»é€‰æ‹© */
const selectCategory = ref();
const defFormRef = ref<ElFormInstance>();
const activeName = ref('0');
const uploadDialog = reactive<DialogOption>({
  visible: false,
  title: '部署流程文件'
@@ -308,30 +227,49 @@
  title: '历史版本'
});
const definitionConfigDialog = reactive<DialogOption>({
const modelDialog = reactive<DialogOption>({
  visible: false,
  title: '流程定义配置'
  title: ''
});
// æŸ¥è¯¢å‚æ•°
const queryParams = ref<ProcessDefinitionQuery>({
const queryParams = ref<FlowDefinitionQuery>({
  pageNum: 1,
  pageSize: 10,
  name: undefined,
  key: undefined,
  categoryCode: undefined
  flowName: undefined,
  flowCode: undefined,
  category: undefined
});
const rules = {
  category: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }],
  flowName: [{ required: true, message: '流程定义名称不能为空', trigger: 'blur' }],
  flowCode: [{ required: true, message: '流程定义编码不能为空', trigger: 'blur' }]
};
const initFormData: FlowDefinitionForm = {
  id: '',
  flowName: '',
  flowCode: '',
  category: '',
  formPath: ''
};
//流程定义参数
const form = ref<FlowDefinitionForm>({
  id: '',
  flowName: '',
  flowCode: '',
  category: '',
  formPath: ''
});
onMounted(() => {
  getList();
  handleQuery();
  getTreeselect();
});
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
const handleNodeClick = (data: CategoryVO) => {
  queryParams.value.categoryCode = data.categoryCode;
  if (data.categoryCode === 'ALL') {
    queryParams.value.categoryCode = '';
const handleNodeClick = (data: CategoryTreeVO) => {
  queryParams.value.category = data.id;
  if (data.id === '0') {
    queryParams.value.category = '';
  }
  handleQuery();
};
@@ -352,22 +290,27 @@
/** æŸ¥è¯¢æµç¨‹åˆ†ç±»ä¸‹æ‹‰æ ‘结构 */
const getTreeselect = async () => {
  const res = await listCategory();
  categoryOptions.value = [];
  const data: CategoryOption = { categoryCode: 'ALL', categoryName: '顶级节点', children: [] };
  data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId');
  categoryOptions.value.push(data);
  const res = await categoryTree();
  categoryOptions.value = res.data;
};
const handleClick = (tab: TabsPaneContext, event: Event) => {
  // v-model处理有延迟 éœ€è¦æ‰‹åŠ¨å¤„ç†
  activeName.value = tab.index;
  handleQuery();
};
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  queryParams.value.pageNum = 1;
  getList();
  if (activeName.value === '0') {
    getList();
  } else {
    getUnPublishList();
  }
};
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
  queryFormRef.value?.resetFields();
  queryParams.value.categoryCode = '';
  queryParams.value.category = '';
  queryParams.value.pageNum = 1;
  queryParams.value.pageSize = 10;
  handleQuery();
@@ -375,73 +318,69 @@
// å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
const handleSelectionChange = (selection: any) => {
  ids.value = selection.map((item: any) => item.id);
  deploymentIds.value = selection.map((item: any) => item.deploymentId);
  keys.value = selection.map((item: any) => item.key);
  flowCodeList.value = selection.map((item: any) => item.flowCode);
  single.value = selection.length !== 1;
  multiple.value = !selection.length;
};
//分页
const getList = async () => {
  loading.value = true;
  const resp = await listProcessDefinition(queryParams.value);
  const resp = await listDefinition(queryParams.value);
  processDefinitionList.value = resp.rows;
  total.value = resp.total;
  loading.value = false;
};
//获取历史流程定义
const getProcessDefinitionHitoryList = async (id: string, key: string) => {
  processDefinitionDialog.visible = true;
//查询未发布的流程定义列表
const getUnPublishList = async () => {
  loading.value = true;
  const resp = await getListByKey(key);
  if (resp.data && resp.data.length > 0) {
    processDefinitionHistoryList.value = resp.data.filter((item: any) => item.id !== id);
  }
  const resp = await unPublishList(queryParams.value);
  processDefinitionList.value = resp.rows;
  total.value = resp.total;
  loading.value = false;
};
type PreviewType = 'xml' | 'bpmn';
//预览 å…¬å…±æ–¹æ³•
const clickPreview = async (id: string, type: PreviewType) => {
  loading.value = true;
  const resp = await definitionXml(id);
  if (previewRef.value) {
    const xmlStr = resp.data.xmlStr;
    loading.value = false;
    previewRef.value.openDialog(xmlStr, type);
  }
};
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
const handleDelete = async (row?: ProcessDefinitionVO) => {
const handleDelete = async (row?: FlowDefinitionVo) => {
  const id = row?.id || ids.value;
  const deployIds = row?.deploymentId || deploymentIds.value;
  const defKeys = row?.key || keys.value;
  await proxy?.$modal.confirm('是否确认删除流程定义KEY为【' + defKeys + '】的数据项?');
  const defList = processDefinitionList.value.filter((x) => id.indexOf(x.id) != -1).map((x) => x.flowCode);
  await proxy?.$modal.confirm('是否确认删除流程定义KEY为【' + defList + '】的数据项?');
  loading.value = true;
  await deleteProcessDefinition(deployIds, id).finally(() => (loading.value = false));
  await getList();
  await deleteDefinition(id).finally(() => (loading.value = false));
  await handleQuery();
  proxy?.$modal.msgSuccess('删除成功');
};
/** æŒ‚èµ·/激活 */
const handleProcessDefState = async (row: ProcessDefinitionVO) => {
  let msg: string;
  if (row.suspensionState === 1) {
    msg = `暂停后,此流程下的所有任务都不允许往后流转,您确定挂起【${row.name || row.key}】吗?`;
  } else {
    msg = `启动后,此流程下的所有任务都允许往后流转,您确定激活【${row.name || row.key}】吗?`;
  }
  await proxy?.$modal.confirm(msg);
/** å‘布流程定义 */
const handlePublish = async (row?: FlowDefinitionVo) => {
  await proxy?.$modal.confirm(
    '是否确认发布流程定义KEY为【' + row.flowCode + '】版本为【' + row.version + '】的数据项?,发布后会将已发布流程定义改为失效!'
  );
  loading.value = true;
  await updateDefinitionState(row.id).finally(() => (loading.value = false));
  await getList();
  proxy?.$modal.msgSuccess('操作成功');
  await publish(row.id).finally(() => (loading.value = false));
  processDefinitionDialog.visible = false;
  await handleQuery();
  proxy?.$modal.msgSuccess('发布成功');
};
/** æµç¨‹å®šä¹‰è½¬æ¢ä¸ºæ¨¡åž‹ */
const handleConvertToModel = async (row: ProcessDefinitionVO) => {
  await proxy?.$modal.confirm('是否确认转换流程定义key为【' + row.key + '】的数据项?');
  await convertToModel(row.id).finally(() => (loading.value = false));
  getList();
  proxy?.$modal.msgSuccess('操作成功');
/** æŒ‚èµ·/激活 */
const handleProcessDefState = async (row: FlowDefinitionVo, status: number | string | boolean) => {
  let msg: string;
  if (status === 0) {
    msg = `暂停后,此流程下的所有任务都不允许往后流转,您确定挂起【${row.flowName || row.flowCode}】吗?`;
  } else {
    msg = `启动后,此流程下的所有任务都允许往后流转,您确定激活【${row.flowName || row.flowCode}】吗?`;
  }
  try {
    loading.value = true;
    await proxy?.$modal.confirm(msg);
    await active(row.id, !!status);
    await handleQuery();
    proxy?.$modal.msgSuccess('操作成功');
  } catch (error) {
    row.activityStatus = status === 0 ? 1 : 0;
    console.error(error);
  } finally {
    loading.value = false;
  }
};
//上传文件前的钩子
@@ -456,12 +395,12 @@
  }
};
//部署文件
const handerDeployProcessFile = (data: UploadRequestOptions): XMLHttpRequest => {
const handlerImportDefinition = (data: UploadRequestOptions): XMLHttpRequest => {
  let formData = new FormData();
  uploadDialogLoading.value = true;
  formData.append('file', data.file);
  formData.append('categoryCode', selectCategory.value);
  deployProcessFile(formData)
  formData.append('category', selectCategory.value);
  importDef(formData)
    .then(() => {
      uploadDialog.visible = false;
      proxy?.$modal.msgSuccess('部署成功');
@@ -472,46 +411,91 @@
    });
  return;
};
//打开流程定义配置
const handleDefinitionConfigOpen = async (row: ProcessDefinitionVO) => {
  definitionConfigDialog.visible = true;
  definitionConfigForm.value.processKey = row.key;
  definitionConfigForm.value.definitionId = row.id;
  definitionConfigForm.value.version = row.version;
  const resp = await getByDefId(row.id);
  if (resp.data) {
    definitionConfigForm.value = resp.data;
  } else {
    definitionConfigForm.value.tableName = undefined;
    definitionConfigForm.value.remark = undefined;
  }
};
//保存表单
const handlerSaveForm = async () => {
  getByTableNameNotDefId(definitionConfigForm.value.tableName, definitionConfigForm.value.definitionId).then((res) => {
    if (res.data && res.data.length > 0) {
      ElMessageBox.confirm('表名已被【' + res.data[0].processKey + '】版本v' + res.data[0].version + '.0绑定确认后将会删除绑定的流程KEY!', '提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        saveOrUpdate(definitionConfigForm.value).then((resp) => {
          if (resp.code === 200) {
            proxy?.$modal.msgSuccess('操作成功');
            definitionConfigDialog.visible = false;
            getList();
          }
        });
      });
    } else {
      saveOrUpdate(definitionConfigForm.value).then((resp) => {
        if (resp.code === 200) {
          proxy?.$modal.msgSuccess('操作成功');
          definitionConfigDialog.visible = false;
          getList();
        }
      });
/**
 * è®¾è®¡æµç¨‹
 * @param row
 */
const design = async (row: FlowDefinitionVo) => {
  proxy.$router.push({
    path: `/workflow/design/index`,
    query: {
      definitionId: row.id,
      disabled: false
    }
  });
};
/**
 * æŸ¥çœ‹æµç¨‹
 * @param row
 */
const designView = async (row: FlowDefinitionVo) => {
  proxy.$router.push({
    path: `/workflow/design/index`,
    query: {
      definitionId: row.id,
      disabled: true
    }
  });
};
/** è¡¨å•重置 */
const reset = () => {
  form.value = { ...initFormData };
  defFormRef.value?.resetFields();
};
/**
 * æ–°å¢ž
 */
const handleAdd = async () => {
  reset();
  modelDialog.visible = true;
  modelDialog.title = '新增流程';
};
/** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
const handleUpdate = async (row?: FlowDefinitionVo) => {
  reset();
  const id = row?.id || ids.value[0];
  const res = await getInfo(id);
  Object.assign(form.value, res.data);
  modelDialog.visible = true;
  modelDialog.title = '修改流程';
};
const handleSubmit = async () => {
  defFormRef.value.validate(async (valid: boolean) => {
    if (valid) {
      loading.value = true;
      if (form.value.id) {
        await edit(form.value).finally(() => loading.value = false);
      } else {
        await add(form.value).finally(() => loading.value = false);
      }
      proxy?.$modal.msgSuccess('操作成功');
      modelDialog.visible = false;
      handleQuery();
    }
  });
};
//复制
const handleCopyDef = async (row: FlowDefinitionVo) => {
  ElMessageBox.confirm(`是否确认复制【${row.flowCode}】版本为【${row.version}】的流程定义!`, '提示', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    loading.value = true;
    copy(row.id).then((resp) => {
      if (resp.code === 200) {
        proxy?.$modal.msgSuccess('操作成功');
        activeName.value = "1"
        handleQuery();
      }
    }).finally(() => loading.value = false);
  });
};
/** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
const handleExportDef = () => {
  proxy?.download(`/workflow/definition/exportDef/${ids.value[0]}`, {}, `${flowCodeList.value[0]}.xml`);
};
</script>
src/views/workflow/processInstance/index.vue
@@ -10,7 +10,7 @@
            class="mt-2"
            node-key="id"
            :data="categoryOptions"
            :props="{ label: 'categoryName', children: 'children' }"
            :props="{ label: 'label', children: 'children' }"
            :expand-on-click-node="false"
            :filter-node-method="filterNode"
            highlight-current
@@ -20,23 +20,31 @@
        </el-card>
      </el-col>
      <el-col :lg="20" :xs="24">
        <div class="mb-[10px]">
          <el-card shadow="hover" class="text-center">
            <el-radio-group v-model="tab" @change="changeTab(tab)">
              <el-radio-button value="running">运行中</el-radio-button>
              <el-radio-button value="finish">已完成</el-radio-button>
            </el-radio-group>
          </el-card>
        </div>
        <!--        <div class="mb-[10px]">
                  <el-card shadow="hover" class="text-center">
                    <el-radio-group v-model="tab" @change="changeTab(tab)">
                      <el-radio-button value="running">运行中</el-radio-button>
                      <el-radio-button value="finish">已完成</el-radio-button>
                    </el-radio-group>
                  </el-card>
                </div>-->
        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
          <div v-show="showSearch" class="mb-[10px]">
            <el-card shadow="hover">
              <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
                <el-form-item label="流程定义名称" prop="name">
                  <el-input v-model="queryParams.name" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
              <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
                <el-form-item>
                  <el-badge :value="userSelectCount" :max="10" class="item">
                    <el-button type="primary" @click="openUserSelect">选择申请人</el-button>
                  </el-badge>
                </el-form-item>
                <el-form-item label="流程定义KEY" prop="key">
                  <el-input v-model="queryParams.key" placeholder="请输入流程定义KEY" @keyup.enter="handleQuery" />
                <el-form-item label="任务名称" prop="nodeName">
                  <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
                </el-form-item>
                <el-form-item label="流程定义名称" label-width="100" prop="flowName">
                  <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
                </el-form-item>
                <el-form-item label="流程定义编码" label-width="100" prop="flowCode">
                  <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" />
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -55,66 +63,74 @@
              <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
            </el-row>
          </template>
          <el-table v-loading="loading" border :data="processInstanceList" @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="55" align="center" />
            <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
            <el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称">
              <template #default="scope">
                <span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span>
              </template>
            </el-table-column>
            <el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column>
            <el-table-column align="center" prop="processDefinitionVersion" label="版本号" width="90">
              <template #default="scope"> v{{ scope.row.processDefinitionVersion }}.0</template>
            </el-table-column>
            <el-table-column v-if="tab === 'running'" align="center" prop="isSuspended" label="状态" min-width="70">
              <template #default="scope">
                <el-tag v-if="!scope.row.isSuspended" type="success">激活</el-tag>
                <el-tag v-else type="danger">挂起</el-tag>
              </template>
            </el-table-column>
            <el-table-column align="center" label="流程状态" min-width="70">
              <template #default="scope">
                <dict-tag :options="wf_business_status" :value="scope.row.businessStatus"></dict-tag>
              </template>
            </el-table-column>
            <el-table-column align="center" prop="startTime" label="启动时间" width="160"></el-table-column>
            <el-table-column v-if="tab === 'finish'" align="center" prop="endTime" label="结束时间" width="160"></el-table-column>
            <el-table-column label="操作" align="center" :width="130">
              <template #default="scope">
                <el-row v-if="tab === 'running'" :gutter="10" class="mb8">
                  <el-col :span="1.5">
                    <el-popover :ref="`popoverRef${scope.$index}`" trigger="click" placement="left" :width="300">
                      <el-input v-model="deleteReason" resize="none" :rows="3" type="textarea" placeholder="请输入作废原因" />
                      <div style="text-align: right; margin: 5px 0px 0px 0px">
                        <el-button size="small" text @click="cancelPopover(scope.$index)">取消</el-button>
                        <el-button size="small" type="primary" @click="handleInvalid(scope.row)">确认</el-button>
                      </div>
                      <template #reference>
                        <el-button link type="primary" size="small" icon="CircleClose">作废</el-button>
                      </template>
                    </el-popover>
                  </el-col>
                  <el-col :span="1.5">
                    <el-button link 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 link type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button>
                  </el-col>
                </el-row>
              </template>
            </el-table-column>
          </el-table>
          <pagination
            v-show="total > 0"
            v-model:page="queryParams.pageNum"
            v-model:limit="queryParams.pageSize"
            :total="total"
            @pagination="handleQuery"
          />
          <el-tabs v-model="tab" @tab-click="changeTab">
            <el-tab-pane name="running" label="运行中"></el-tab-pane>
            <el-tab-pane name="finish" label="已完成"></el-tab-pane>
            <el-table v-loading="loading" border :data="processInstanceList" @selection-change="handleSelectionChange">
              <el-table-column type="selection" width="55" align="center" />
              <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
              <el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称">
                <template #default="scope">
                  <span>{{ scope.row.flowName }}v{{ scope.row.version }}</span>
                </template>
              </el-table-column>
              <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column>
              <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column>
              <el-table-column align="center" prop="createByName" label="申请人"></el-table-column>
              <el-table-column align="center" prop="version" label="版本号" width="90">
                <template #default="scope"> v{{ scope.row.version }}.0</template>
              </el-table-column>
              <el-table-column v-if="tab === 'running'" align="center" prop="isSuspended" label="状态" min-width="70">
                <template #default="scope">
                  <el-tag v-if="!scope.row.isSuspended" type="success">激活</el-tag>
                  <el-tag v-else type="danger">挂起</el-tag>
                </template>
              </el-table-column>
              <el-table-column align="center" label="流程状态" min-width="70">
                <template #default="scope">
                  <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag>
                </template>
              </el-table-column>
              <el-table-column align="center" prop="createTime" label="启动时间" width="160"></el-table-column>
              <el-table-column v-if="tab === 'finish'" align="center" prop="updateTime" label="结束时间" width="160"></el-table-column>
              <el-table-column label="操作" align="center" :width="162">
                <template #default="scope">
                  <el-row v-if="tab === 'running'" :gutter="10" class="mb8">
                    <el-col :span="1.5">
                      <el-popover :ref="`popoverRef${scope.$index}`" trigger="click" placement="left" :width="300">
                        <el-input v-model="deleteReason" resize="none" :rows="3" type="textarea" placeholder="请输入作废原因" />
                        <div style="text-align: right; margin: 5px 0px 0px 0px">
                          <el-button size="small" text @click="cancelPopover(scope.$index)">取消</el-button>
                          <el-button size="small" type="primary" @click="handleInvalid(scope.row)">确认</el-button>
                        </div>
                        <template #reference>
                          <el-button type="danger" size="small" icon="CircleClose">作废</el-button>
                        </template>
                      </el-popover>
                    </el-col>
                    <el-col :span="1.5">
                      <el-button type="danger" 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">
                      <el-button type="primary" size="small" icon="Document" @click="handleInstanceVariable(scope.row)"> å˜é‡ </el-button>
                    </el-col>
                  </el-row>
                </template>
              </el-table-column>
            </el-table>
            <pagination
              v-show="total > 0"
              v-model:page="queryParams.pageNum"
              v-model:limit="queryParams.pageSize"
              :total="total"
              @pagination="handleQuery"
            />
          </el-tabs>
        </el-card>
      </el-col>
    </el-row>
@@ -122,6 +138,7 @@
      <el-table v-loading="loading" :data="processDefinitionHistoryList">
        <el-table-column fixed align="center" type="index" label="序号" width="60"></el-table-column>
        <el-table-column fixed align="center" prop="name" label="流程定义名称"></el-table-column>
        <el-table-column fixed align="center" prop="nodeName" label="任务名称"></el-table-column>
        <el-table-column align="center" prop="key" label="标识Key"></el-table-column>
        <el-table-column align="center" prop="version" label="版本号" width="90">
          <template #default="scope"> v{{ scope.row.version }}.0</template>
@@ -133,42 +150,55 @@
          </template>
        </el-table-column>
        <el-table-column align="center" prop="deploymentTime" label="部署时间" :show-overflow-tooltip="true"></el-table-column>
        <el-table-column fixed="right" label="操作" align="center" width="200" class-name="small-padding fixed-width">
          <template #default="scope">
            <el-button link type="primary" size="small" icon="Sort" @click="handleChange(scope.row.id)">切换</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <!-- æµç¨‹å˜é‡å¼€å§‹ -->
    <el-dialog v-model="variableVisible" draggable title="流程变量" width="60%" :close-on-click-modal="false">
      <el-card v-loading="variableLoading" class="box-card">
        <template #header>
          <div class="clearfix">
            <span
              >流程定义名称:<el-tag>{{ processDefinitionName }}</el-tag></span
            >
          </div>
        </template>
        <div class="max-h-500px overflow-y-auto">
          <VueJsonPretty :data="formatToJsonObject(variables)" />
        </div>
      </el-card>
    </el-dialog>
    <!-- æµç¨‹å˜é‡ç»“束 -->
    <!-- ç”³è¯·äºº -->
    <UserSelect ref="userSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect>
  </div>
</template>
<script lang="ts" setup>
import {
  getPageByRunning,
  getPageByFinish,
  deleteRunAndHisInstance,
  deleteFinishAndHisInstance,
  deleteRunInstance
} from '@/api/workflow/processInstance';
import { getListByKey, migrationDefinition } from '@/api/workflow/processDefinition';
import { listCategory } from '@/api/workflow/category';
import { CategoryVO } from '@/api/workflow/category/types';
import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types';
import { pageByRunning, pageByFinish, deleteByInstanceIds, instanceVariable, invalid } from '@/api/workflow/instance';
import { categoryTree } from '@/api/workflow/category';
import { CategoryTreeVO } from '@/api/workflow/category/types';
import { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types';
import workflowCommon from '@/api/workflow/workflowCommon';
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
import VueJsonPretty from 'vue-json-pretty';
import 'vue-json-pretty/lib/styles.css';
import UserSelect from '@/components/UserSelect/index.vue';
//审批记录组件
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
const queryFormRef = ref<ElFormInstance>();
const categoryTreeRef = ref<ElTreeInstance>();
import { ref } from 'vue';
import { UserVO } from '@/api/system/user/types';
const userSelectRef = ref<InstanceType<typeof UserSelect>>();
// é®ç½©å±‚
const loading = ref(true);
// é€‰ä¸­æ•°ç»„
const ids = ref<Array<any>>([]);
// é€‰ä¸­ä¸šåŠ¡id数组
const businessKeys = ref<Array<any>>([]);
// é€‰ä¸­å®žä¾‹id数组
const instanceIds = ref<Array<number | string>>([]);
// éžå•个禁用
const single = ref(true);
// éžå¤šä¸ªç¦ç”¨
@@ -177,10 +207,15 @@
const showSearch = ref(true);
// æ€»æ¡æ•°
const total = ref(0);
// æµç¨‹å®šä¹‰id
const processDefinitionId = ref<string>('');
// æµç¨‹å˜é‡æ˜¯å¦æ˜¾ç¤º
const variableVisible = ref(false);
const variableLoading = ref(true);
const variables = ref<string>('');
//流程定义名称
const processDefinitionName = ref();
// æ¨¡åž‹å®šä¹‰è¡¨æ ¼æ•°æ®
const processInstanceList = ref<ProcessInstanceVO[]>([]);
const processInstanceList = ref<FlowInstanceVO[]>([]);
const processDefinitionHistoryList = ref<Array<any>>([]);
const categoryOptions = ref<CategoryOption[]>([]);
const categoryName = ref('');
@@ -191,7 +226,7 @@
});
type CategoryOption = {
  categoryCode: string;
  id: string;
  categoryName: string;
  children?: CategoryOption[];
};
@@ -199,20 +234,27 @@
const tab = ref('running');
// ä½œåºŸåŽŸå› 
const deleteReason = ref('');
//申请人id
const selectUserIds = ref<Array<number | string>>([]);
//申请人选择数量
const userSelectCount = ref(0);
// æŸ¥è¯¢å‚æ•°
const queryParams = ref<ProcessInstanceQuery>({
const queryParams = ref<FlowInstanceQuery>({
  pageNum: 1,
  pageSize: 10,
  name: undefined,
  key: undefined,
  categoryCode: undefined
  nodeName: undefined,
  flowName: undefined,
  flowCode: undefined,
  createByIds: [],
  category: undefined
});
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
const handleNodeClick = (data: CategoryVO) => {
  queryParams.value.categoryCode = data.categoryCode;
  if (data.categoryCode === 'ALL') {
    queryParams.value.categoryCode = '';
const handleNodeClick = (data: CategoryTreeVO) => {
  queryParams.value.category = data.id;
  if (data.id === '0') {
    queryParams.value.category = '';
  }
  handleQuery();
};
@@ -233,11 +275,8 @@
/** æŸ¥è¯¢æµç¨‹åˆ†ç±»ä¸‹æ‹‰æ ‘结构 */
const getTreeselect = async () => {
  const res = await listCategory();
  categoryOptions.value = [];
  const data: CategoryOption = { categoryCode: 'ALL', categoryName: '顶级节点', children: [] };
  data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId');
  categoryOptions.value.push(data);
  const res = await categoryTree();
  categoryOptions.value = res.data;
};
/** æœç´¢æŒ‰é’®æ“ä½œ */
@@ -251,22 +290,24 @@
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
  queryFormRef.value?.resetFields();
  queryParams.value.categoryCode = '';
  queryParams.value.category = '';
  queryParams.value.pageNum = 1;
  queryParams.value.pageSize = 10;
  queryParams.value.createByIds = [];
  userSelectCount.value = 0;
  handleQuery();
};
// å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
const handleSelectionChange = (selection: ProcessInstanceVO[]) => {
const handleSelectionChange = (selection: FlowInstanceVO[]) => {
  ids.value = selection.map((item: any) => item.id);
  businessKeys.value = selection.map((item: any) => item.businessKey);
  instanceIds.value = selection.map((item: FlowInstanceVO) => item.id);
  single.value = selection.length !== 1;
  multiple.value = !selection.length;
};
//分页
const getProcessInstanceRunningList = () => {
  loading.value = true;
  getPageByRunning(queryParams.value).then((resp) => {
  pageByRunning(queryParams.value).then((resp) => {
    processInstanceList.value = resp.rows;
    total.value = resp.total;
    loading.value = false;
@@ -275,7 +316,7 @@
//分页
const getProcessInstanceFinishList = () => {
  loading.value = true;
  getPageByFinish(queryParams.value).then((resp) => {
  pageByFinish(queryParams.value).then((resp) => {
    processInstanceList.value = resp.rows;
    total.value = resp.total;
    loading.value = false;
@@ -283,15 +324,15 @@
};
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
const handleDelete = async (row: any) => {
  const businessKey = row.businessKey || businessKeys.value;
  await proxy?.$modal.confirm('是否确认删除业务id为【' + businessKey + '】的数据项?');
const handleDelete = async (row: FlowInstanceVO) => {
  const instanceIdList = row.id || instanceIds.value;
  await proxy?.$modal.confirm('是否确认删除?');
  loading.value = true;
  if ('running' === tab.value) {
    await deleteRunAndHisInstance(businessKey).finally(() => (loading.value = false));
    await deleteByInstanceIds(instanceIdList).finally(() => (loading.value = false));
    getProcessInstanceRunningList();
  } else {
    await deleteFinishAndHisInstance(businessKey).finally(() => (loading.value = false));
    await deleteByInstanceIds(instanceIdList).finally(() => (loading.value = false));
    getProcessInstanceFinishList();
  }
  proxy?.$modal.msgSuccess('删除成功');
@@ -299,22 +340,22 @@
const changeTab = async (data: string) => {
  processInstanceList.value = [];
  queryParams.value.pageNum = 1;
  if ('running' === data) {
  if ('running' === data.paneName) {
    getProcessInstanceRunningList();
  } else {
    getProcessInstanceFinishList();
  }
};
/** ä½œåºŸæŒ‰é’®æ“ä½œ */
const handleInvalid = async (row: ProcessInstanceVO) => {
  await proxy?.$modal.confirm('是否确认作废业务id为【' + row.businessKey + '】的数据项?');
const handleInvalid = async (row: FlowInstanceVO) => {
  await proxy?.$modal.confirm('是否确认作废?');
  loading.value = true;
  if ('running' === tab.value) {
    let param = {
      businessKey: row.businessKey,
      deleteReason: deleteReason.value
      id: row.id,
      comment: deleteReason.value
    };
    await deleteRunInstance(param).finally(() => (loading.value = false));
    await invalid(param).finally(() => (loading.value = false));
    getProcessInstanceRunningList();
    proxy?.$modal.msgSuccess('操作成功');
  }
@@ -322,41 +363,53 @@
const cancelPopover = async (index: any) => {
  (proxy?.$refs[`popoverRef${index}`] as any).hide(); //关闭弹窗
};
//获取流程定义
const getProcessDefinitionHitoryList = (id: string, key: string) => {
  processDefinitionDialog.visible = true;
  processDefinitionId.value = id;
  loading.value = true;
  getListByKey(key).then((resp) => {
    if (resp.data && resp.data.length > 0) {
      processDefinitionHistoryList.value = resp.data.filter((item: any) => item.id !== id);
    }
    loading.value = false;
  });
};
//切换流程版本
const handleChange = async (id: string) => {
  await proxy?.$modal.confirm('是否确认切换?');
  loading.value = true;
  migrationDefinition(processDefinitionId.value, id).then((resp) => {
    proxy?.$modal.msgSuccess('操作成功');
    getProcessInstanceRunningList();
    processDefinitionDialog.visible = false;
    loading.value = false;
  });
};
/** æŸ¥çœ‹æŒ‰é’®æ“ä½œ */
const handleView = (row) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    wfDefinitionConfigVo: row.wfDefinitionConfigVo,
    wfNodeConfigVo: row.wfNodeConfigVo,
    businessKey: row.businessKey,
    businessId: row.businessId,
    taskId: row.id,
    type: 'view'
    type: 'view',
    formCustom: row.formCustom,
    formPath: row.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};
//查询流程变量
const handleInstanceVariable = async (row: FlowInstanceVO) => {
  variableLoading.value = true;
  variableVisible.value = true;
  processDefinitionName.value = row.flowName;
  let data = await instanceVariable(row.id);
  variables.value = data.data.variable;
  variableLoading.value = false;
};
/**
 * json转为对象
 * @param data åŽŸå§‹æ•°æ®
 */
function formatToJsonObject(data: string) {
  try {
    return JSON.parse(data);
  } catch (error) {
    return data;
  }
}
//打开申请人选择
const openUserSelect = () => {
  userSelectRef.value.open();
};
//确认选择申请人
const userSelectCallBack = (data: UserVO[]) => {
  userSelectCount.value = 0;
  if (data && data.length > 0) {
    userSelectCount.value = data.length;
    selectUserIds.value = data.map((item) => item.userId);
    queryParams.value.createByIds = selectUserIds.value;
  }
};
onMounted(() => {
  getProcessInstanceRunningList();
  getTreeselect();
src/views/workflow/task/allTaskWaiting.vue
@@ -1,25 +1,19 @@
<template>
  <div class="p-2">
    <div class="mb-[10px]">
      <el-card shadow="hover" class="text-center">
        <el-radio-group v-model="tab" @change="changeTab(tab)">
          <el-radio-button value="waiting">待办任务</el-radio-button>
          <el-radio-button value="finish">已办任务</el-radio-button>
        </el-radio-group>
      </el-card>
    </div>
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div v-show="showSearch" class="mb-[10px]">
        <el-card shadow="hover">
          <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
            <el-form-item label="任务名称" prop="name">
              <el-input v-model="queryParams.name" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
            <el-form-item>
              <el-badge :value="userSelectCount" :max="10" class="item">
                <el-button type="primary" @click="openUserSelect">选择申请人</el-button>
              </el-badge>
            </el-form-item>
            <el-form-item label="流程定义名称" label-width="100" prop="processDefinitionName">
              <el-input v-model="queryParams.processDefinitionName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
            <el-form-item label="任务名称" prop="nodeName">
              <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="流程定义KEY" label-width="100" prop="processDefinitionKey">
              <el-input v-model="queryParams.processDefinitionKey" placeholder="请输入流程定义KEY" @keyup.enter="handleQuery" />
            <el-form-item label="流程定义名称" label-width="100" prop="flowName">
              <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -32,122 +26,103 @@
    <el-card shadow="hover">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" plain icon="Edit" :disabled="multiple" @click="handleUpdate">修改办理人</el-button>
          <el-col :span="1.5" v-if="tab === 'waiting'">
            <el-button type="primary" plain icon="Edit" :disabled="multiple" @click="handleUpdate">修改办理人 </el-button>
          </el-col>
          <right-toolbar v-model:show-search="showSearch" @query-table="handleQuery"></right-toolbar>
        </el-row>
      </template>
      <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
        <el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称">
          <template #default="scope">
            <span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column>
        <el-table-column align="center" prop="name" label="任务名称"></el-table-column>
        <el-table-column align="center" prop="assigneeName" label="办理人">
          <template v-if="tab === 'waiting'" #default="scope">
            <template v-if="scope.row.participantVo && scope.row.assignee === null">
              <el-tag v-for="(item, index) in scope.row.participantVo.candidateName" :key="index" type="success">
                {{ item }}
              </el-tag>
      <el-tabs v-model="tab" @tab-click="changeTab">
        <el-tab-pane name="waiting" label="待办任务"> </el-tab-pane>
        <el-tab-pane name="finish" label="已办任务"> </el-tab-pane>
        <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
          <el-table-column type="selection" width="55" align="center" />
          <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
          <el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"></el-table-column>
          <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column>
          <el-table-column align="center" prop="version" label="版本号" width="90">
            <template #default="scope"> v{{ scope.row.version }}.0</template>
          </el-table-column>
          <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column>
          <el-table-column align="center" prop="createByName" label="申请人"></el-table-column>
          <el-table-column align="center" label="办理人">
            <template #default="scope">
              <template v-if="tab === 'waiting'">
                <template v-if="scope.row.assigneeNames">
                  <el-tag v-for="(name, index) in scope.row.assigneeNames.split(',')" :key="index" type="success">
                    {{ name }}
                  </el-tag>
                </template>
                <template v-else>
                  <el-tag type="success"> æ— </el-tag>
                </template>
              </template>
              <template v-else>
                <el-tag type="success"> {{ scope.row.approveName }}</el-tag>
              </template>
            </template>
            <template v-else>
              <el-tag type="success">
                {{ scope.row.assigneeName || '无' }}
              </el-tag>
          </el-table-column>
          <el-table-column align="center" label="流程状态" prop="flowStatus" min-width="70">
            <template #default="scope">
              <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag>
            </template>
          </template>
          <template v-else-if="tab === 'finish'" #default="scope">
            <el-tag type="success">
              {{ scope.row.assigneeName || '无' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column align="center" label="流程状态" min-width="70">
          <template #default="scope">
            <dict-tag v-if="tab === 'waiting'" :options="wf_business_status" :value="scope.row.businessStatus"></dict-tag>
            <el-tag v-else type="success">已完成</el-tag>
          </template>
        </el-table-column>
        <el-table-column v-if="tab === 'waiting'" align="center" prop="createTime" label="创建时间" width="160"></el-table-column>
        <el-table-column v-if="tab === 'finish'" align="center" prop="startTime" label="创建时间" width="160"></el-table-column>
        <el-table-column label="操作" align="center" :width="tab === 'finish' ? '80' : '151'">
          <template #default="scope">
            <el-row :gutter="10" class="mb8">
              <el-col :span="1.5">
                <el-button link type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button>
              </el-col>
              <el-col v-if="tab === 'waiting'" :span="1.5">
                <el-button link type="primary" size="small" icon="Document" @click="handleInstanceVariable(scope.row)">流程变量</el-button>
              </el-col>
            </el-row>
            <el-row v-if="scope.row.multiInstance" :gutter="10" class="mb8">
              <el-col :span="1.5">
                <el-button link type="primary" size="small" icon="Remove" @click="deleteMultiInstanceUser(scope.row)">减签</el-button>
              </el-col>
              <el-col :span="1.5">
                <el-button link type="primary" size="small" icon="CirclePlus" @click="addMultiInstanceUser(scope.row)">加签</el-button>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="total > 0"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        :total="total"
        @pagination="handleQuery"
      />
          </el-table-column>
          <el-table-column v-if="tab === 'finish'" align="center" label="任务状态" prop="flowTaskStatus" min-width="70">
            <template #default="scope">
              <dict-tag :options="wf_task_status" :value="scope.row.flowTaskStatus"></dict-tag>
            </template>
          </el-table-column>
          <el-table-column align="center" prop="createTime" label="创建时间" width="160"></el-table-column>
          <el-table-column label="操作" align="center" :width="tab === 'finish' ? '88' : '188'">
            <template #default="scope">
              <el-row :gutter="10" class="mb8">
                <el-col :span="1.5" v-if="tab === 'waiting' || tab === 'finish'">
                  <el-button type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button>
                </el-col>
                <el-col :span="1.5" v-if="tab === 'waiting'">
                  <el-button type="primary" size="small" icon="Setting" @click="handleMeddle(scope.row)">流程干预 </el-button>
                </el-col>
              </el-row>
            </template>
          </el-table-column>
        </el-table>
        <pagination
          v-show="total > 0"
          v-model:page="queryParams.pageNum"
          v-model:limit="queryParams.pageSize"
          :total="total"
          @pagination="handleQuery"
        />
      </el-tabs>
    </el-card>
    <!-- åŠ ç­¾ç»„ä»¶ -->
    <multiInstanceUser ref="multiInstanceUserRef" :title="title" @submit-callback="handleQuery" />
    <!-- é€‰äººç»„ä»¶ -->
    <UserSelect ref="userSelectRef" :multiple="false" @confirm-call-back="submitCallback"></UserSelect>
    <!-- æµç¨‹å˜é‡å¼€å§‹ -->
    <el-dialog v-model="variableVisible" draggable title="流程变量" width="60%" :close-on-click-modal="false">
      <el-card v-loading="variableLoading" class="box-card">
        <template #header>
          <div class="clearfix">
            <span
              >流程定义名称:<el-tag>{{ processDefinitionName }}</el-tag></span
            >
          </div>
        </template>
        <div v-for="(v, index) in variableList" :key="index">
          <el-form v-if="v.key !== '_FLOWABLE_SKIP_EXPRESSION_ENABLED'" :label-position="'right'" label-width="150px">
            <el-form-item :label="v.key + ':'">
              {{ v.value }}
            </el-form-item>
          </el-form>
        </div>
      </el-card>
    </el-dialog>
    <!-- æµç¨‹å˜é‡ç»“束 -->
    <!-- é€‰äººç»„ä»¶ -->
    <processMeddle ref="processMeddleRef" @submitCallback="getWaitingList"></processMeddle>
    <!-- ç”³è¯·äºº -->
    <UserSelect ref="applyUserSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect>
  </div>
</template>
<script lang="ts" setup>
import { getPageByAllTaskWait, getPageByAllTaskFinish, updateAssignee, getInstanceVariable } from '@/api/workflow/task';
import MultiInstanceUser from '@/components/Process/multiInstanceUser.vue';
import { pageByAllTaskWait, pageByAllTaskFinish, updateAssignee } from '@/api/workflow/task';
import UserSelect from '@/components/UserSelect';
import { TaskQuery, TaskVO, VariableVo } from '@/api/workflow/task/types';
import { TaskQuery } from '@/api/workflow/task/types';
import workflowCommon from '@/api/workflow/workflowCommon';
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
//审批记录组件
//加签组件
const multiInstanceUserRef = ref<InstanceType<typeof MultiInstanceUser>>();
import processMeddle from '@/components/Process/processMeddle';
import { UserVO } from '@/api/system/user/types';
import { TabsPaneContext } from 'element-plus';
//选人组件
const userSelectRef = ref<InstanceType<typeof UserSelect>>();
//流程干预组件
const processMeddleRef = ref<InstanceType<typeof processMeddle>>();
//选人组件
const applyUserSelectRef = ref<InstanceType<typeof UserSelect>>();
const queryFormRef = ref<ElFormInstance>();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
const { wf_task_status } = toRefs<any>(proxy?.useDict('wf_task_status'));
// é®ç½©å±‚
const loading = ref(true);
// é€‰ä¸­æ•°ç»„
@@ -163,40 +138,21 @@
// æ¨¡åž‹å®šä¹‰è¡¨æ ¼æ•°æ®
const taskList = ref([]);
const title = ref('');
// æµç¨‹å˜é‡æ˜¯å¦æ˜¾ç¤º
const variableVisible = ref(false);
const variableLoading = ref(true);
// æµç¨‹å˜é‡
const variableList = ref<VariableVo>({
  key: '',
  value: ''
});
//流程定义名称
const processDefinitionName = ref();
//申请人id
const selectUserIds = ref<Array<number | string>>([]);
//申请人选择数量
const userSelectCount = ref(0);
// æŸ¥è¯¢å‚æ•°
const queryParams = ref<TaskQuery>({
  pageNum: 1,
  pageSize: 10,
  name: undefined,
  processDefinitionName: undefined,
  processDefinitionKey: undefined
  nodeName: undefined,
  flowName: undefined,
  flowCode: undefined,
  createByIds: []
});
const tab = ref('waiting');
//加签
const addMultiInstanceUser = (row: TaskVO) => {
  if (multiInstanceUserRef.value) {
    title.value = '加签人员';
    multiInstanceUserRef.value.getAddMultiInstanceList(row.id, []);
  }
};
//减签
const deleteMultiInstanceUser = (row: TaskVO) => {
  if (multiInstanceUserRef.value) {
    title.value = '减签人员';
    multiInstanceUserRef.value.getDeleteMultiInstanceList(row.id);
  }
};
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  if ('waiting' === tab.value) {
@@ -210,6 +166,8 @@
  queryFormRef.value?.resetFields();
  queryParams.value.pageNum = 1;
  queryParams.value.pageSize = 10;
  queryParams.value.createByIds = [];
  userSelectCount.value = 0;
  handleQuery();
};
// å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
@@ -218,10 +176,10 @@
  single.value = selection.length !== 1;
  multiple.value = !selection.length;
};
const changeTab = async (data: string) => {
const changeTab = async (data: TabsPaneContext) => {
  taskList.value = [];
  queryParams.value.pageNum = 1;
  if ('waiting' === data) {
  if ('waiting' === data.paneName) {
    getWaitingList();
  } else {
    getFinishList();
@@ -230,7 +188,7 @@
//分页
const getWaitingList = () => {
  loading.value = true;
  getPageByAllTaskWait(queryParams.value).then((resp) => {
  pageByAllTaskWait(queryParams.value).then((resp) => {
    taskList.value = resp.rows;
    total.value = resp.total;
    loading.value = false;
@@ -238,7 +196,7 @@
};
const getFinishList = () => {
  loading.value = true;
  getPageByAllTaskFinish(queryParams.value).then((resp) => {
  pageByAllTaskFinish(queryParams.value).then((resp) => {
    taskList.value = resp.rows;
    total.value = resp.total;
    loading.value = false;
@@ -260,26 +218,33 @@
    proxy?.$modal.msgWarning('请选择用户!');
  }
};
//查询流程变量
const handleInstanceVariable = async (row: TaskVO) => {
  variableLoading.value = true;
  variableVisible.value = true;
  processDefinitionName.value = row.processDefinitionName;
  let data = await getInstanceVariable(row.id);
  variableList.value = data.data;
  variableLoading.value = false;
};
/** æŸ¥çœ‹æŒ‰é’®æ“ä½œ */
const handleView = (row) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    wfDefinitionConfigVo: row.wfDefinitionConfigVo,
    wfNodeConfigVo: row.wfNodeConfigVo,
    businessKey: row.businessKey,
    businessId: row.businessId,
    taskId: row.id,
    type: 'view'
    type: 'view',
    formCustom: row.formCustom,
    formPath: row.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};
const handleMeddle = (row) => {
  processMeddleRef.value.open(row.id);
};
//打开申请人选择
const openUserSelect = () => {
  applyUserSelectRef.value.open();
};
//确认选择申请人
const userSelectCallBack = (data: UserVO[]) => {
  userSelectCount.value = 0;
  if (data && data.length > 0) {
    userSelectCount.value = data.length;
    selectUserIds.value = data.map((item) => item.userId);
    queryParams.value.createByIds = selectUserIds.value;
  }
};
onMounted(() => {
  getWaitingList();
});
src/views/workflow/task/myDocument.vue
@@ -10,7 +10,7 @@
            class="mt-2"
            node-key="id"
            :data="categoryOptions"
            :props="{ label: 'categoryName', children: 'children' }"
            :props="{ label: 'label', children: 'children' }"
            :expand-on-click-node="false"
            :filter-node-method="filterNode"
            highlight-current
@@ -24,8 +24,8 @@
          <div v-show="showSearch" class="mb-[10px]">
            <el-card shadow="hover">
              <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
                <el-form-item label="流程定义名称" prop="name">
                  <el-input v-model="queryParams.name" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
                <el-form-item label="流程定义编码" prop="flowCode">
                  <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" />
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -46,14 +46,10 @@
            <el-table-column type="selection" width="55" align="center" />
            <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
            <el-table-column v-if="false" align="center" prop="id" label="id"></el-table-column>
            <el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称">
              <template #default="scope">
                <span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span>
              </template>
            </el-table-column>
            <el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column>
            <el-table-column align="center" prop="processDefinitionVersion" label="版本号" width="90">
              <template #default="scope"> v{{ scope.row.processDefinitionVersion }}.0</template>
            <el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"> </el-table-column>
            <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column>
            <el-table-column align="center" prop="version" label="版本号" width="90">
              <template #default="scope"> v{{ scope.row.version }}.0</template>
            </el-table-column>
            <el-table-column v-if="tab === 'running'" align="center" prop="isSuspended" label="状态" min-width="70">
              <template #default="scope">
@@ -63,33 +59,30 @@
            </el-table-column>
            <el-table-column align="center" label="流程状态" min-width="70">
              <template #default="scope">
                <dict-tag :options="wf_business_status" :value="scope.row.businessStatus"></dict-tag>
                <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag>
              </template>
            </el-table-column>
            <el-table-column align="center" prop="startTime" label="启动时间" width="160"></el-table-column>
            <el-table-column v-if="tab === 'finish'" align="center" prop="endTime" label="结束时间" width="160"></el-table-column>
            <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
            <el-table-column align="center" prop="createTime" label="启动时间" width="160"></el-table-column>
            <el-table-column label="操作" align="center" width="162">
              <template #default="scope">
                <el-tooltip
                  v-if="scope.row.businessStatus === 'draft' || scope.row.businessStatus === 'cancel' || scope.row.businessStatus === 'back'"
                  content="修改"
                  placement="top"
                >
                  <el-button link type="primary" icon="Edit" @click="handleOpen(scope.row, 'update')"></el-button>
                </el-tooltip>
                <el-tooltip
                  v-if="scope.row.businessStatus === 'draft' || scope.row.businessStatus === 'cancel' || scope.row.businessStatus === 'back'"
                  content="删除"
                  placement="top"
                >
                  <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
                </el-tooltip>
                <el-tooltip placement="top" content="查看">
                  <el-button link type="primary" icon="View" @click="handleOpen(scope.row, 'view')"></el-button>
                </el-tooltip>
                <el-tooltip v-if="scope.row.businessStatus === 'waiting'" content="撤销" placement="top">
                  <el-button link type="primary" icon="Notification" @click="handleCancelProcessApply(scope.row.businessKey)"></el-button>
                </el-tooltip>
                <el-row :gutter="10" class="mb8">
                  <el-col :span="1.5" v-if="scope.row.flowStatus === 'draft' || scope.row.flowStatus === 'cancel' || scope.row.flowStatus === 'back'">
                    <el-button type="primary" size="small" icon="Edit" @click="handleOpen(scope.row, 'update')">编辑</el-button>
                  </el-col>
                  <el-col :span="1.5" v-if="scope.row.flowStatus === 'draft' || scope.row.flowStatus === 'cancel' || scope.row.flowStatus === 'back'">
                    <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="handleOpen(scope.row, 'view')">查看</el-button>
                  </el-col>
                  <el-col :span="1.5" v-if="scope.row.flowStatus === 'waiting'">
                    <el-button type="primary" size="small" icon="Notification" @click="handleCancelProcessApply(scope.row.businessId)"
                      >撤销</el-button
                    >
                  </el-col>
                </el-row>
              </template>
            </el-table-column>
          </el-table>
@@ -109,10 +102,10 @@
</template>
<script lang="ts" setup>
import { getPageByCurrent, deleteRunAndHisInstance, cancelProcessApply } from '@/api/workflow/processInstance';
import { listCategory } from '@/api/workflow/category';
import { CategoryVO } from '@/api/workflow/category/types';
import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types';
import { pageByCurrent, deleteByInstanceIds, cancelProcessApply } from '@/api/workflow/instance';
import { categoryTree } from '@/api/workflow/category';
import { CategoryTreeVO } from '@/api/workflow/category/types';
import { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types';
import workflowCommon from '@/api/workflow/workflowCommon';
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -123,7 +116,8 @@
// é®ç½©å±‚
const loading = ref(true);
// é€‰ä¸­æ•°ç»„
const businessKeys = ref<Array<any>>([]);
const businessIds = ref<Array<number | string>>([]);
const instanceIds = ref<Array<number | string>>([]);
// éžå•个禁用
const single = ref(true);
// éžå¤šä¸ªç¦ç”¨
@@ -133,24 +127,18 @@
// æ€»æ¡æ•°
const total = ref(0);
// æ¨¡åž‹å®šä¹‰è¡¨æ ¼æ•°æ®
const processInstanceList = ref<ProcessInstanceVO[]>([]);
const processInstanceList = ref<FlowInstanceVO[]>([]);
const categoryOptions = ref<CategoryOption[]>([]);
const categoryOptions = ref<CategoryTreeVO[]>([]);
const categoryName = ref('');
interface CategoryOption {
  categoryCode: string;
  categoryName: string;
  children?: CategoryOption[];
}
const tab = ref('running');
// æŸ¥è¯¢å‚æ•°
const queryParams = ref<ProcessInstanceQuery>({
const queryParams = ref<FlowInstanceQuery>({
  pageNum: 1,
  pageSize: 10,
  name: undefined,
  categoryCode: undefined
  flowCode: undefined,
  category: undefined
});
onMounted(() => {
@@ -159,10 +147,10 @@
});
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
const handleNodeClick = (data: CategoryVO) => {
  queryParams.value.categoryCode = data.categoryCode;
  if (data.categoryCode === 'ALL') {
    queryParams.value.categoryCode = '';
const handleNodeClick = (data: CategoryTreeVO) => {
  queryParams.value.category = data.id;
  if (data.id === '0') {
    queryParams.value.category = '';
  }
  handleQuery();
};
@@ -183,11 +171,8 @@
/** æŸ¥è¯¢æµç¨‹åˆ†ç±»ä¸‹æ‹‰æ ‘结构 */
const getTreeselect = async () => {
  const res = await listCategory();
  categoryOptions.value = [];
  const data: CategoryOption = { categoryCode: 'ALL', categoryName: '顶级节点', children: [] };
  data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId');
  categoryOptions.value.push(data);
  const res = await categoryTree();
  categoryOptions.value = res.data;
};
/** æœç´¢æŒ‰é’®æ“ä½œ */
@@ -197,21 +182,22 @@
/** é‡ç½®æŒ‰é’®æ“ä½œ */
const resetQuery = () => {
  queryFormRef.value?.resetFields();
  queryParams.value.categoryCode = '';
  queryParams.value.category = '';
  queryParams.value.pageNum = 1;
  queryParams.value.pageSize = 10;
  handleQuery();
};
// å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
const handleSelectionChange = (selection: ProcessInstanceVO[]) => {
  businessKeys.value = selection.map((item: any) => item.businessKey);
const handleSelectionChange = (selection: FlowInstanceVO[]) => {
  businessIds.value = selection.map((item: any) => item.businessId);
  instanceIds.value = selection.map((item: FlowInstanceVO) => item.id);
  single.value = selection.length !== 1;
  multiple.value = !selection.length;
};
//分页
const getList = () => {
  loading.value = true;
  getPageByCurrent(queryParams.value).then((resp) => {
  pageByCurrent(queryParams.value).then((resp) => {
    processInstanceList.value = resp.rows;
    total.value = resp.total;
    loading.value = false;
@@ -219,23 +205,27 @@
};
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
const handleDelete = async (row: ProcessInstanceVO) => {
  const businessKey = row.businessKey || businessKeys.value;
  await proxy?.$modal.confirm('是否确认删除业务id为【' + businessKey + '】的数据项?');
const handleDelete = async (row: FlowInstanceVO) => {
  const instanceIdList = row.id || instanceIds.value;
  await proxy?.$modal.confirm('是否确认删除?');
  loading.value = true;
  if ('running' === tab.value) {
    await deleteRunAndHisInstance(businessKey).finally(() => (loading.value = false));
    await deleteByInstanceIds(instanceIdList).finally(() => (loading.value = false));
    getList();
  }
  proxy?.$modal.msgSuccess('删除成功');
};
/** æ’¤é”€æŒ‰é’®æ“ä½œ */
const handleCancelProcessApply = async (businessKey: string) => {
const handleCancelProcessApply = async (businessId: string) => {
  await proxy?.$modal.confirm('是否确认撤销当前单据?');
  loading.value = true;
  if ('running' === tab.value) {
    await cancelProcessApply(businessKey).finally(() => (loading.value = false));
    let data = {
      businessId: businessId,
      message: '申请人撤销流程!'
    };
    await cancelProcessApply(data).finally(() => (loading.value = false));
    getList();
  }
  proxy?.$modal.msgSuccess('撤销成功');
@@ -244,11 +234,11 @@
//办理
const handleOpen = async (row, type) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    wfDefinitionConfigVo: row.wfDefinitionConfigVo,
    wfNodeConfigVo: row.wfNodeConfigVo,
    businessKey: row.businessKey,
    businessId: row.businessId,
    taskId: row.id,
    type: type
    type: type,
    formCustom: row.formCustom,
    formPath: row.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};
src/views/workflow/task/taskCopyList.vue
@@ -4,14 +4,14 @@
      <div v-show="showSearch" class="mb-[10px]">
        <el-card shadow="hover">
          <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
            <el-form-item label="任务名称" prop="name">
              <el-input v-model="queryParams.name" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
            <el-form-item label="任务名称" prop="nodeName">
              <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="流程定义名称" label-width="100" prop="processDefinitionName">
              <el-input v-model="queryParams.processDefinitionName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
            <el-form-item label="流程定义名称" label-width="100" prop="flowName">
              <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="流程定义KEY" label-width="100" prop="processDefinitionKey">
              <el-input v-model="queryParams.processDefinitionKey" placeholder="请输入流程定义KEY" @keyup.enter="handleQuery" />
            <el-form-item label="流程定义编码" label-width="100" prop="flowCode">
              <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -31,30 +31,15 @@
      <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
        <el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称">
          <template #default="scope">
            <span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span>
          </template>
        <el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"></el-table-column>
        <el-table-column align="center" prop="flowCode" label="流程定义KEY"></el-table-column>
        <el-table-column align="center" prop="version" label="版本号" width="90">
          <template #default="scope"> v{{ scope.row.version }}.0</template>
        </el-table-column>
        <el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column>
        <el-table-column align="center" prop="name" label="任务名称"></el-table-column>
        <el-table-column align="center" prop="assigneeName" label="办理人">
          <template #default="scope">
            <template v-if="scope.row.participantVo && scope.row.assignee === null">
              <el-tag v-for="(item, index) in scope.row.participantVo.candidateName" :key="index" type="success">
                {{ item }}
              </el-tag>
            </template>
            <template v-else>
              <el-tag type="success">
                {{ scope.row.assigneeName || '无' }}
              </el-tag>
            </template>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column>
        <el-table-column align="center" label="流程状态" min-width="70">
          <template #default="scope">
            <dict-tag :options="wf_business_status" :value="scope.row.businessStatus"></dict-tag>
            <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" width="200">
@@ -75,7 +60,7 @@
</template>
<script lang="ts" setup>
import { getPageByTaskCopy } from '@/api/workflow/task';
import { pageByTaskCopy } from '@/api/workflow/task';
import { TaskQuery } from '@/api/workflow/task/types';
import workflowCommon from '@/api/workflow/workflowCommon';
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
@@ -101,9 +86,9 @@
const queryParams = ref<TaskQuery>({
  pageNum: 1,
  pageSize: 10,
  name: undefined,
  processDefinitionName: undefined,
  processDefinitionKey: undefined
  nodeName: undefined,
  flowName: undefined,
  flowCode: undefined
});
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
@@ -125,7 +110,7 @@
//分页
const getTaskCopyList = () => {
  loading.value = true;
  getPageByTaskCopy(queryParams.value).then((resp) => {
  pageByTaskCopy(queryParams.value).then((resp) => {
    taskList.value = resp.rows;
    total.value = resp.total;
    loading.value = false;
@@ -135,11 +120,11 @@
/** æŸ¥çœ‹æŒ‰é’®æ“ä½œ */
const handleView = (row) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    wfDefinitionConfigVo: row.wfDefinitionConfigVo,
    wfNodeConfigVo: row.wfNodeConfigVo,
    businessKey: row.businessKey,
    businessId: row.businessId,
    taskId: row.id,
    type: 'view'
    type: 'view',
    formCustom: row.formCustom,
    formPath: row.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};
src/views/workflow/task/taskFinish.vue
@@ -4,14 +4,19 @@
      <div v-show="showSearch" class="mb-[10px]">
        <el-card shadow="hover">
          <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
            <el-form-item label="任务名称" prop="name">
              <el-input v-model="queryParams.name" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
            <el-form-item>
              <el-badge :value="userSelectCount" :max="10" class="item">
                <el-button type="primary" @click="openUserSelect">选择申请人</el-button>
              </el-badge>
            </el-form-item>
            <el-form-item label="流程定义名称" label-width="100" prop="processDefinitionName">
              <el-input v-model="queryParams.processDefinitionName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
            <el-form-item label="任务名称" prop="nodeName">
              <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="流程定义KEY" label-width="100" prop="processDefinitionKey">
              <el-input v-model="queryParams.processDefinitionKey" placeholder="请输入流程定义KEY" @keyup.enter="handleQuery" />
            <el-form-item label="流程定义名称" label-width="100" prop="flowName">
              <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="流程定义编码" label-width="100" prop="flowCode">
              <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -31,21 +36,31 @@
      <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
        <el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称">
          <template #default="scope">
            <span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span>
          </template>
        <el-table-column align="center" prop="flowName" label="流程定义名称"></el-table-column>
        <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column>
        <el-table-column align="center" prop="version" label="版本号" width="90">
          <template #default="scope"> v{{ scope.row.version }}.0</template>
        </el-table-column>
        <el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column>
        <el-table-column align="center" prop="name" label="任务名称"></el-table-column>
        <el-table-column align="center" prop="assigneeName" label="办理人">
        <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column>
        <el-table-column align="center" prop="createByName" label="申请人"></el-table-column>
        <el-table-column align="center" prop="approverName" label="办理人">
          <template #default="scope">
            <el-tag type="success">
              {{ scope.row.assigneeName || '无' }}
              {{ scope.row.approveName || '无' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="startTime" label="创建时间" width="160"></el-table-column>
        <el-table-column align="center" label="流程状态" prop="flowStatus" min-width="70">
          <template #default="scope">
            <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag>
          </template>
        </el-table-column>
        <el-table-column align="center" label="任务状态" prop="flowTaskStatus" min-width="70">
          <template #default="scope">
            <dict-tag :options="wf_task_status" :value="scope.row.flowTaskStatus"></dict-tag>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="createTime" label="创建时间" width="160"></el-table-column>
        <el-table-column label="操作" align="center" width="200">
          <template #default="scope">
            <el-button type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button>
@@ -60,17 +75,26 @@
        @pagination="handleQuery"
      />
    </el-card>
    <!-- ç”³è¯·äºº -->
    <UserSelect ref="userSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect>
  </div>
</template>
<script lang="ts" setup>
import { getPageByTaskFinish } from '@/api/workflow/task';
import { TaskQuery, TaskVO } from '@/api/workflow/task/types';
import { pageByTaskFinish } from '@/api/workflow/task';
import { TaskQuery, FlowTaskVO } from '@/api/workflow/task/types';
import workflowCommon from '@/api/workflow/workflowCommon';
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
//审批记录组件
const queryFormRef = ref<ElFormInstance>();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
const { wf_task_status } = toRefs<any>(proxy?.useDict('wf_task_status'));
import UserSelect from '@/components/UserSelect';
import { ref } from 'vue';
import { UserVO } from '@/api/system/user/types';
const userSelectRef = ref<InstanceType<typeof UserSelect>>();
// é®ç½©å±‚
const loading = ref(true);
// é€‰ä¸­æ•°ç»„
@@ -89,10 +113,15 @@
const queryParams = ref<TaskQuery>({
  pageNum: 1,
  pageSize: 10,
  name: undefined,
  processDefinitionName: undefined,
  processDefinitionKey: undefined
  nodeName: undefined,
  flowName: undefined,
  flowCode: undefined,
  createByIds: []
});
//申请人id
const selectUserIds = ref<Array<number | string>>([]);
//申请人选择数量
const userSelectCount = ref(0);
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  getFinishList();
@@ -102,6 +131,8 @@
  queryFormRef.value?.resetFields();
  queryParams.value.pageNum = 1;
  queryParams.value.pageSize = 10;
  queryParams.value.createByIds = [];
  userSelectCount.value = 0;
  handleQuery();
};
// å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
@@ -112,24 +143,36 @@
};
const getFinishList = () => {
  loading.value = true;
  getPageByTaskFinish(queryParams.value).then((resp) => {
  pageByTaskFinish(queryParams.value).then((resp) => {
    taskList.value = resp.rows;
    total.value = resp.total;
    loading.value = false;
  });
};
/** æŸ¥çœ‹æŒ‰é’®æ“ä½œ */
const handleView = (row: TaskVO) => {
const handleView = (row: FlowTaskVO) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    wfDefinitionConfigVo: row.wfDefinitionConfigVo,
    wfNodeConfigVo: row.wfNodeConfigVo,
    businessKey: row.businessKey,
    businessId: row.businessId,
    taskId: row.id,
    type: 'view'
    type: 'view',
    formCustom: row.formCustom,
    formPath: row.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};
//打开申请人选择
const openUserSelect = () => {
  userSelectRef.value.open();
};
//确认选择申请人
const userSelectCallBack = (data: UserVO[]) => {
  userSelectCount.value = 0;
  if (data && data.length > 0) {
    userSelectCount.value = data.length;
    selectUserIds.value = data.map((item) => item.userId);
    queryParams.value.createByIds = selectUserIds.value;
  }
};
onMounted(() => {
  getFinishList();
});
src/views/workflow/task/taskWaiting.vue
@@ -4,14 +4,19 @@
      <div v-show="showSearch" class="mb-[10px]">
        <el-card shadow="hover">
          <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
            <el-form-item label="任务名称" prop="name">
              <el-input v-model="queryParams.name" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
            <el-form-item>
              <el-badge :value="userSelectCount" :max="10" class="item">
                <el-button type="primary" @click="openUserSelect">选择申请人</el-button>
              </el-badge>
            </el-form-item>
            <el-form-item label="流程定义名称" label-width="100" prop="processDefinitionName">
              <el-input v-model="queryParams.processDefinitionName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
            <el-form-item label="任务名称" prop="nodeName">
              <el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="流程定义KEY" label-width="100" prop="processDefinitionKey">
              <el-input v-model="queryParams.processDefinitionKey" placeholder="请输入流程定义KEY" @keyup.enter="handleQuery" />
            <el-form-item label="流程定义名称" label-width="100" prop="flowName">
              <el-input v-model="queryParams.flowName" placeholder="请输入流程定义名称" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="流程定义编码" label-width="100" prop="flowCode">
              <el-input v-model="queryParams.flowCode" placeholder="请输入流程定义编码" @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -31,30 +36,25 @@
      <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column align="center" type="index" label="序号" width="60"></el-table-column>
        <el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称">
        <el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"></el-table-column>
        <el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column>
        <el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column>
        <el-table-column align="center" prop="createByName" label="申请人"></el-table-column>
        <el-table-column align="center" label="办理人">
          <template #default="scope">
            <span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column>
        <el-table-column align="center" prop="name" label="任务名称"></el-table-column>
        <el-table-column align="center" prop="assigneeName" label="办理人">
          <template #default="scope">
            <template v-if="scope.row.participantVo && scope.row.assignee === null">
              <el-tag v-for="(item, index) in scope.row.participantVo.candidateName" :key="index" type="success">
                {{ item }}
            <template v-if="scope.row.assigneeNames">
              <el-tag v-for="(name, index) in scope.row.assigneeNames.split(',')" :key="index" type="success">
                {{ name }}
              </el-tag>
            </template>
            <template v-else>
              <el-tag type="success">
                {{ scope.row.assigneeName || '无' }}
              </el-tag>
              <el-tag type="success"> æ— </el-tag>
            </template>
          </template>
        </el-table-column>
        <el-table-column align="center" label="流程状态" min-width="70">
        <el-table-column align="center" label="流程状态" prop="flowStatusName" min-width="70">
          <template #default="scope">
            <dict-tag :options="wf_business_status" :value="scope.row.businessStatus"></dict-tag>
            <dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag>
          </template>
        </el-table-column>
        <el-table-column align="center" prop="createTime" label="创建时间" width="160"></el-table-column>
@@ -72,16 +72,24 @@
        @pagination="handleQuery"
      />
    </el-card>
    <!-- ç”³è¯·äºº -->
    <UserSelect ref="userSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect>
  </div>
</template>
<script lang="ts" setup>
import { getPageByTaskWait } from '@/api/workflow/task';
import { TaskQuery, TaskVO } from '@/api/workflow/task/types';
import { pageByTaskWait } from '@/api/workflow/task';
import { TaskQuery, FlowTaskVO } from '@/api/workflow/task/types';
import workflowCommon from '@/api/workflow/workflowCommon';
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
import UserSelect from '@/components/UserSelect';
import { ref } from 'vue';
import { UserVO } from '@/api/system/user/types';
const userSelectRef = ref<InstanceType<typeof UserSelect>>();
//提交组件
const queryFormRef = ref<ElFormInstance>();
// é®ç½©å±‚
@@ -98,13 +106,19 @@
const total = ref(0);
// æ¨¡åž‹å®šä¹‰è¡¨æ ¼æ•°æ®
const taskList = ref([]);
//申请人id
const selectUserIds = ref<Array<number | string>>([]);
//申请人选择数量
const userSelectCount = ref(0);
// æŸ¥è¯¢å‚æ•°
const queryParams = ref<TaskQuery>({
  pageNum: 1,
  pageSize: 10,
  name: undefined,
  processDefinitionName: undefined,
  processDefinitionKey: undefined
  nodeName: undefined,
  flowName: undefined,
  flowCode: undefined,
  createByIds: []
});
onMounted(() => {
  getWaitingList();
@@ -118,6 +132,8 @@
  queryFormRef.value?.resetFields();
  queryParams.value.pageNum = 1;
  queryParams.value.pageSize = 10;
  queryParams.value.createByIds = [];
  userSelectCount.value = 0;
  handleQuery();
};
// å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
@@ -129,21 +145,34 @@
//分页
const getWaitingList = () => {
  loading.value = true;
  getPageByTaskWait(queryParams.value).then((resp) => {
  pageByTaskWait(queryParams.value).then((resp) => {
    taskList.value = resp.rows;
    total.value = resp.total;
    loading.value = false;
  });
};
//办理
const handleOpen = async (row: TaskVO) => {
const handleOpen = async (row: FlowTaskVO) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    wfDefinitionConfigVo: row.wfDefinitionConfigVo,
    wfNodeConfigVo: row.wfNodeConfigVo,
    businessKey: row.businessKey,
    businessId: row.businessId,
    taskId: row.id,
    type: 'approval'
    type: 'approval',
    formCustom: row.formCustom,
    formPath: row.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};
//打开申请人选择
const openUserSelect = () => {
  userSelectRef.value.open();
};
//确认选择申请人
const userSelectCallBack = (data: UserVO[]) => {
  userSelectCount.value = 0;
  if (data && data.length > 0) {
    userSelectCount.value = data.length;
    selectUserIds.value = data.map((item) => item.userId);
    queryParams.value.createByIds = selectUserIds.value;
  }
};
</script>
vite.config.ts
@@ -64,16 +64,6 @@
        'echarts',
        'vue-i18n',
        '@vueup/vue-quill',
        'bpmn-js/lib/Viewer',
        'bpmn-js/lib/Modeler.js',
        'bpmn-js-properties-panel',
        'min-dash',
        'diagram-js/lib/navigation/movecanvas',
        'diagram-js/lib/navigation/zoomscroll',
        'bpmn-js/lib/features/palette/PaletteProvider',
        'bpmn-js/lib/features/context-pad/ContextPadProvider',
        'diagram-js/lib/draw/BaseRenderer',
        'tiny-svg',
        'image-conversion',
        'element-plus/es/components/**/css'
      ]