Merge branch 'dev' of https://gitee.com/yudaocode/yudao-ui-admin-vben into dev
						commit
						e8046f3a48
					
				|  | @ -0,0 +1,163 @@ | ||||||
|  | import type { PageParam, PageResult } from '@vben/request'; | ||||||
|  | 
 | ||||||
|  | import type { BpmModelApi } from '#/api/bpm/model'; | ||||||
|  | import type { CandidateStrategy, NodeType } from '#/utils'; | ||||||
|  | 
 | ||||||
|  | import { requestClient } from '#/api/request'; | ||||||
|  | 
 | ||||||
|  | export namespace BpmProcessInstanceApi { | ||||||
|  |   export type Task = { | ||||||
|  |     id: number; | ||||||
|  |     name: string; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   export type User = { | ||||||
|  |     avatar: string; | ||||||
|  |     id: number; | ||||||
|  |     nickname: string; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   // 审批任务信息
 | ||||||
|  |   export type ApprovalTaskInfo = { | ||||||
|  |     assigneeUser: User; | ||||||
|  |     id: number; | ||||||
|  |     ownerUser: User; | ||||||
|  |     reason: string; | ||||||
|  |     signPicUrl: string; | ||||||
|  |     status: number; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   // 审批节点信息
 | ||||||
|  |   export type ApprovalNodeInfo = { | ||||||
|  |     candidateStrategy?: CandidateStrategy; | ||||||
|  |     candidateUsers?: User[]; | ||||||
|  |     endTime?: Date; | ||||||
|  |     id: number; | ||||||
|  |     name: string; | ||||||
|  |     nodeType: NodeType; | ||||||
|  |     startTime?: Date; | ||||||
|  |     status: number; | ||||||
|  |     tasks: ApprovalTaskInfo[]; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   export type ProcessInstanceVO = { | ||||||
|  |     businessKey: string; | ||||||
|  |     category: string; | ||||||
|  |     createTime: string; | ||||||
|  |     endTime: string; | ||||||
|  |     fields: string[]; | ||||||
|  |     id: number; | ||||||
|  |     name: string; | ||||||
|  |     processDefinition?: BpmModelApi.ProcessDefinitionVO; | ||||||
|  |     processDefinitionId: string; | ||||||
|  |     remark: string; | ||||||
|  |     result: number; | ||||||
|  |     status: number; | ||||||
|  |     tasks: BpmProcessInstanceApi.Task[]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 查询我的流程实例分页 */ | ||||||
|  | export async function getProcessInstanceMyPage(params: PageParam) { | ||||||
|  |   return requestClient.get<PageResult<BpmProcessInstanceApi.ProcessInstanceVO>>( | ||||||
|  |     '/bpm/process-instance/my-page', | ||||||
|  |     { params }, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 查询管理员流程实例分页 */ | ||||||
|  | export async function getProcessInstanceManagerPage(params: PageParam) { | ||||||
|  |   return requestClient.get<PageResult<BpmProcessInstanceApi.ProcessInstanceVO>>( | ||||||
|  |     '/bpm/process-instance/manager-page', | ||||||
|  |     { params }, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 新增流程实例 */ | ||||||
|  | export async function createProcessInstance( | ||||||
|  |   data: BpmProcessInstanceApi.ProcessInstanceVO, | ||||||
|  | ) { | ||||||
|  |   return requestClient.post<BpmProcessInstanceApi.ProcessInstanceVO>( | ||||||
|  |     '/bpm/process-instance/create', | ||||||
|  |     data, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 申请人主动取消流程实例 */ | ||||||
|  | export async function cancelProcessInstanceByStartUser( | ||||||
|  |   id: number, | ||||||
|  |   reason: string, | ||||||
|  | ) { | ||||||
|  |   return requestClient.delete<boolean>( | ||||||
|  |     '/bpm/process-instance/cancel-by-start-user', | ||||||
|  |     { | ||||||
|  |       data: { id, reason }, | ||||||
|  |     }, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 管理员取消流程实例 */ | ||||||
|  | export async function cancelProcessInstanceByAdmin(id: number, reason: string) { | ||||||
|  |   return requestClient.delete<boolean>( | ||||||
|  |     '/bpm/process-instance/cancel-by-admin', | ||||||
|  |     { | ||||||
|  |       data: { id, reason }, | ||||||
|  |     }, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 查询流程实例详情 */ | ||||||
|  | export async function getProcessInstance(id: number) { | ||||||
|  |   return requestClient.get<BpmProcessInstanceApi.ProcessInstanceVO>( | ||||||
|  |     `/bpm/process-instance/get?id=${id}`, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 查询复制流程实例分页 */ | ||||||
|  | export async function getProcessInstanceCopyPage(params: PageParam) { | ||||||
|  |   return requestClient.get<PageResult<BpmProcessInstanceApi.ProcessInstanceVO>>( | ||||||
|  |     '/bpm/process-instance/copy/page', | ||||||
|  |     { params }, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 更新流程实例 */ | ||||||
|  | export async function updateProcessInstance( | ||||||
|  |   data: BpmProcessInstanceApi.ProcessInstanceVO, | ||||||
|  | ) { | ||||||
|  |   return requestClient.put<BpmProcessInstanceApi.ProcessInstanceVO>( | ||||||
|  |     '/bpm/process-instance/update', | ||||||
|  |     data, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 获取审批详情 */ | ||||||
|  | export async function getApprovalDetail(params: any) { | ||||||
|  |   return requestClient.get<BpmProcessInstanceApi.ProcessInstanceVO>( | ||||||
|  |     `/bpm/process-instance/get-approval-detail`, | ||||||
|  |     { params }, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 获取下一个执行的流程节点 */ | ||||||
|  | export async function getNextApprovalNodes(params: any) { | ||||||
|  |   return requestClient.get<BpmProcessInstanceApi.ProcessInstanceVO>( | ||||||
|  |     `/bpm/process-instance/get-next-approval-nodes`, | ||||||
|  |     { params }, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 获取表单字段权限 */ | ||||||
|  | export async function getFormFieldsPermission(params: any) { | ||||||
|  |   return requestClient.get<BpmProcessInstanceApi.ProcessInstanceVO>( | ||||||
|  |     `/bpm/process-instance/get-form-fields-permission`, | ||||||
|  |     { params }, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 获取流程实例 BPMN 模型视图 */ | ||||||
|  | export async function getProcessInstanceBpmnModelView(id: number) { | ||||||
|  |   return requestClient.get<BpmProcessInstanceApi.ProcessInstanceVO>( | ||||||
|  |     `/bpm/process-instance/get-bpmn-model-view?id=${id}`, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | @ -464,3 +464,132 @@ export const BpmAutoApproveType = { | ||||||
|   APPROVE_ALL: 1, // 仅审批一次,后续重复的审批节点均自动通过
 |   APPROVE_ALL: 1, // 仅审批一次,后续重复的审批节点均自动通过
 | ||||||
|   APPROVE_SEQUENT: 2, // 仅针对连续审批的节点自动通过
 |   APPROVE_SEQUENT: 2, // 仅针对连续审批的节点自动通过
 | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | // 候选人策略枚举 ( 用于审批节点。抄送节点 )
 | ||||||
|  | export enum CandidateStrategy { | ||||||
|  |   /** | ||||||
|  |    * 审批人自选 | ||||||
|  |    */ | ||||||
|  |   APPROVE_USER_SELECT = 34, | ||||||
|  |   /** | ||||||
|  |    * 部门的负责人 | ||||||
|  |    */ | ||||||
|  |   DEPT_LEADER = 21, | ||||||
|  |   /** | ||||||
|  |    * 部门成员 | ||||||
|  |    */ | ||||||
|  |   DEPT_MEMBER = 20, | ||||||
|  |   /** | ||||||
|  |    * 流程表达式 | ||||||
|  |    */ | ||||||
|  |   EXPRESSION = 60, | ||||||
|  |   /** | ||||||
|  |    * 表单内部门负责人 | ||||||
|  |    */ | ||||||
|  |   FORM_DEPT_LEADER = 51, | ||||||
|  |   /** | ||||||
|  |    * 表单内用户字段 | ||||||
|  |    */ | ||||||
|  |   FORM_USER = 50, | ||||||
|  |   /** | ||||||
|  |    * 连续多级部门的负责人 | ||||||
|  |    */ | ||||||
|  |   MULTI_LEVEL_DEPT_LEADER = 23, | ||||||
|  |   /** | ||||||
|  |    * 指定岗位 | ||||||
|  |    */ | ||||||
|  |   POST = 22, | ||||||
|  |   /** | ||||||
|  |    * 指定角色 | ||||||
|  |    */ | ||||||
|  |   ROLE = 10, | ||||||
|  |   /** | ||||||
|  |    * 发起人自己 | ||||||
|  |    */ | ||||||
|  |   START_USER = 36, | ||||||
|  |   /** | ||||||
|  |    * 发起人部门负责人 | ||||||
|  |    */ | ||||||
|  |   START_USER_DEPT_LEADER = 37, | ||||||
|  |   /** | ||||||
|  |    * 发起人连续多级部门的负责人 | ||||||
|  |    */ | ||||||
|  |   START_USER_MULTI_LEVEL_DEPT_LEADER = 38, | ||||||
|  |   /** | ||||||
|  |    * 发起人自选 | ||||||
|  |    */ | ||||||
|  |   START_USER_SELECT = 35, | ||||||
|  |   /** | ||||||
|  |    * 指定用户 | ||||||
|  |    */ | ||||||
|  |   USER = 30, | ||||||
|  |   /** | ||||||
|  |    * 指定用户组 | ||||||
|  |    */ | ||||||
|  |   USER_GROUP = 40, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 节点类型 | ||||||
|  |  */ | ||||||
|  | export enum NodeType { | ||||||
|  |   /** | ||||||
|  |    * 子流程节点 | ||||||
|  |    */ | ||||||
|  |   CHILD_PROCESS_NODE = 20, | ||||||
|  |   /** | ||||||
|  |    * 条件分支节点 (对应排他网关) | ||||||
|  |    */ | ||||||
|  |   CONDITION_BRANCH_NODE = 51, | ||||||
|  |   /** | ||||||
|  |    * 条件节点 | ||||||
|  |    */ | ||||||
|  |   CONDITION_NODE = 50, | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * 抄送人节点 | ||||||
|  |    */ | ||||||
|  |   COPY_TASK_NODE = 12, | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * 延迟器节点 | ||||||
|  |    */ | ||||||
|  |   DELAY_TIMER_NODE = 14, | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * 结束节点 | ||||||
|  |    */ | ||||||
|  |   END_EVENT_NODE = 1, | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * 包容分支节点 (对应包容网关) | ||||||
|  |    */ | ||||||
|  |   INCLUSIVE_BRANCH_NODE = 53, | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * 并行分支节点 (对应并行网关) | ||||||
|  |    */ | ||||||
|  |   PARALLEL_BRANCH_NODE = 52, | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * 路由分支节点 | ||||||
|  |    */ | ||||||
|  |   ROUTER_BRANCH_NODE = 54, | ||||||
|  |   /** | ||||||
|  |    * 发起人节点 | ||||||
|  |    */ | ||||||
|  |   START_USER_NODE = 10, | ||||||
|  |   /** | ||||||
|  |    * 办理人节点 | ||||||
|  |    */ | ||||||
|  |   TRANSACTOR_NODE = 13, | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * 触发器节点 | ||||||
|  |    */ | ||||||
|  |   TRIGGER_NODE = 15, | ||||||
|  |   /** | ||||||
|  |    * 审批人节点 | ||||||
|  |    */ | ||||||
|  |   USER_TASK_NODE = 11, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,31 @@ | ||||||
|  | /** | ||||||
|  |  * 将毫秒,转换成时间字符串。例如说,xx 分钟 | ||||||
|  |  * | ||||||
|  |  * @param ms 毫秒 | ||||||
|  |  * @returns {string} 字符串 | ||||||
|  |  */ | ||||||
|  | export function formatPast2(ms: number): string { | ||||||
|  |   // 定义时间单位常量,便于维护
 | ||||||
|  |   const SECOND = 1000; | ||||||
|  |   const MINUTE = 60 * SECOND; | ||||||
|  |   const HOUR = 60 * MINUTE; | ||||||
|  |   const DAY = 24 * HOUR; | ||||||
|  | 
 | ||||||
|  |   // 计算各时间单位
 | ||||||
|  |   const day = Math.floor(ms / DAY); | ||||||
|  |   const hour = Math.floor((ms % DAY) / HOUR); | ||||||
|  |   const minute = Math.floor((ms % HOUR) / MINUTE); | ||||||
|  |   const second = Math.floor((ms % MINUTE) / SECOND); | ||||||
|  | 
 | ||||||
|  |   // 根据时间长短返回不同格式
 | ||||||
|  |   if (day > 0) { | ||||||
|  |     return `${day} 天${hour} 小时 ${minute} 分钟`; | ||||||
|  |   } | ||||||
|  |   if (hour > 0) { | ||||||
|  |     return `${hour} 小时 ${minute} 分钟`; | ||||||
|  |   } | ||||||
|  |   if (minute > 0) { | ||||||
|  |     return `${minute} 分钟`; | ||||||
|  |   } | ||||||
|  |   return second > 0 ? `${second} 秒` : `${0} 秒`; | ||||||
|  | } | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| export * from './constants'; | export * from './constants'; | ||||||
| export * from './dict'; | export * from './dict'; | ||||||
|  | export * from './formatTime'; | ||||||
| export * from './rangePickerProps'; | export * from './rangePickerProps'; | ||||||
| export * from './validator'; | export * from './validator'; | ||||||
|  |  | ||||||
|  | @ -0,0 +1,227 @@ | ||||||
|  | import type { VbenFormSchema } from '#/adapter/form'; | ||||||
|  | import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; | ||||||
|  | import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance'; | ||||||
|  | 
 | ||||||
|  | import { h } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { useAccess } from '@vben/access'; | ||||||
|  | 
 | ||||||
|  | import { Button } from 'ant-design-vue'; | ||||||
|  | 
 | ||||||
|  | import { getCategorySimpleList } from '#/api/bpm/category'; | ||||||
|  | import { getSimpleUserList } from '#/api/system/user'; | ||||||
|  | import { $t } from '#/locales'; | ||||||
|  | import { | ||||||
|  |   DICT_TYPE, | ||||||
|  |   formatPast2, | ||||||
|  |   getDictOptions, | ||||||
|  |   getRangePickerDefaultProps, | ||||||
|  | } from '#/utils'; | ||||||
|  | 
 | ||||||
|  | import { BpmProcessInstanceStatus } from '../../../../utils/constants'; | ||||||
|  | 
 | ||||||
|  | const { hasAccessByCodes } = useAccess(); | ||||||
|  | 
 | ||||||
|  | /** 列表的搜索表单 */ | ||||||
|  | export function useGridFormSchema(): VbenFormSchema[] { | ||||||
|  |   return [ | ||||||
|  |     { | ||||||
|  |       fieldName: 'startUserId', | ||||||
|  |       label: '发起人', | ||||||
|  |       component: 'ApiSelect', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请选择发起人', | ||||||
|  |         allowClear: true, | ||||||
|  |         api: getSimpleUserList, | ||||||
|  |         labelField: 'nickname', | ||||||
|  |         valueField: 'id', | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'name', | ||||||
|  |       label: '流程名称', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入流程名称', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'processDefinitionId', | ||||||
|  |       label: '所属流程', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入流程定义的编号', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     // 流程分类
 | ||||||
|  |     { | ||||||
|  |       fieldName: 'category', | ||||||
|  |       label: '流程分类', | ||||||
|  |       component: 'ApiSelect', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入流程分类', | ||||||
|  |         allowClear: true, | ||||||
|  |         api: getCategorySimpleList, | ||||||
|  |         labelField: 'name', | ||||||
|  |         valueField: 'code', | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     // 流程状态
 | ||||||
|  |     { | ||||||
|  |       fieldName: 'status', | ||||||
|  |       label: '流程状态', | ||||||
|  |       component: 'Select', | ||||||
|  |       componentProps: { | ||||||
|  |         options: getDictOptions( | ||||||
|  |           DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, | ||||||
|  |           'number', | ||||||
|  |         ), | ||||||
|  |         placeholder: '请选择流程状态', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     // 发起时间
 | ||||||
|  |     { | ||||||
|  |       fieldName: 'createTime', | ||||||
|  |       label: '发起时间', | ||||||
|  |       component: 'RangePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         ...getRangePickerDefaultProps(), | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 列表的字段 */ | ||||||
|  | export function useGridColumns<T = BpmProcessInstanceApi.ProcessInstanceVO>( | ||||||
|  |   onActionClick: OnActionClickFn<T>, | ||||||
|  |   onTaskClick: (task: BpmProcessInstanceApi.Task) => void, | ||||||
|  | ): VxeTableGridOptions['columns'] { | ||||||
|  |   return [ | ||||||
|  |     { | ||||||
|  |       field: 'name', | ||||||
|  |       title: '流程名称', | ||||||
|  |       minWidth: 200, | ||||||
|  |       fixed: 'left', | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |       field: 'categoryName', | ||||||
|  |       title: '流程分类', | ||||||
|  |       minWidth: 120, | ||||||
|  |       fixed: 'left', | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |       field: 'startUser.nickname', | ||||||
|  |       title: '流程发起人', | ||||||
|  |       minWidth: 120, | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |       field: 'startUser.deptName', | ||||||
|  |       title: '发起部门', | ||||||
|  |       minWidth: 120, | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     // 流程状态
 | ||||||
|  |     { | ||||||
|  |       field: 'status', | ||||||
|  |       title: '流程状态', | ||||||
|  |       minWidth: 120, | ||||||
|  |       cellRender: { | ||||||
|  |         name: 'CellDict', | ||||||
|  |         props: { type: DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |       field: 'startTime', | ||||||
|  |       title: '发起时间', | ||||||
|  |       minWidth: 180, | ||||||
|  |       formatter: 'formatDateTime', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'endTime', | ||||||
|  |       title: '结束时间', | ||||||
|  |       minWidth: 180, | ||||||
|  |       formatter: 'formatDateTime', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'durationInMillis', | ||||||
|  |       title: '流程耗时', | ||||||
|  |       minWidth: 180, | ||||||
|  |       slots: { | ||||||
|  |         default: ({ row }) => { | ||||||
|  |           return row.durationInMillis > 0 | ||||||
|  |             ? formatPast2(row.durationInMillis) | ||||||
|  |             : '-'; | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     // 当前审批任务 tasks
 | ||||||
|  |     { | ||||||
|  |       field: 'tasks', | ||||||
|  |       title: '当前审批任务', | ||||||
|  |       minWidth: 320, | ||||||
|  |       slots: { | ||||||
|  |         default: ({ row }) => { | ||||||
|  |           if (!row?.tasks?.length) return '-'; | ||||||
|  | 
 | ||||||
|  |           return row.tasks.map((task: BpmProcessInstanceApi.Task) => | ||||||
|  |             h( | ||||||
|  |               Button, | ||||||
|  |               { | ||||||
|  |                 type: 'link', | ||||||
|  |                 size: 'small', | ||||||
|  |                 onClick: () => onTaskClick(task), | ||||||
|  |               }, | ||||||
|  |               { default: () => task.name }, | ||||||
|  |             ), | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |       field: 'id', | ||||||
|  |       title: '流程编号', | ||||||
|  |       minWidth: 320, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'operation', | ||||||
|  |       title: '操作', | ||||||
|  |       minWidth: 180, | ||||||
|  |       align: 'center', | ||||||
|  |       fixed: 'right', | ||||||
|  |       cellRender: { | ||||||
|  |         attrs: { | ||||||
|  |           nameField: 'name', | ||||||
|  |           nameTitle: '流程分类', | ||||||
|  |           onClick: onActionClick, | ||||||
|  |         }, | ||||||
|  |         name: 'CellOperation', | ||||||
|  |         options: [ | ||||||
|  |           { | ||||||
|  |             code: 'detail', | ||||||
|  |             text: $t('ui.actionTitle.detail'), | ||||||
|  |             show: hasAccessByCodes(['bpm:process-instance:query']), | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             code: 'cancel', | ||||||
|  |             text: $t('ui.actionTitle.cancel'), | ||||||
|  |             show: (row: BpmProcessInstanceApi.ProcessInstanceVO) => { | ||||||
|  |               return ( | ||||||
|  |                 row.status === BpmProcessInstanceStatus.RUNNING && | ||||||
|  |                 hasAccessByCodes(['bpm:process-instance:cancel']) | ||||||
|  |               ); | ||||||
|  |             }, | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | @ -1,31 +1,128 @@ | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { Page } from '@vben/common-ui'; | import type { | ||||||
|  |   OnActionClickParams, | ||||||
|  |   VxeTableGridOptions, | ||||||
|  | } from '#/adapter/vxe-table'; | ||||||
|  | import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance'; | ||||||
| 
 | 
 | ||||||
| import { Button } from 'ant-design-vue'; | import { h } from 'vue'; | ||||||
| 
 | 
 | ||||||
|  | import { Page, prompt } from '@vben/common-ui'; | ||||||
|  | 
 | ||||||
|  | import { message, Textarea } from 'ant-design-vue'; | ||||||
|  | 
 | ||||||
|  | import { useVbenVxeGrid } from '#/adapter/vxe-table'; | ||||||
|  | import { | ||||||
|  |   cancelProcessInstanceByAdmin, | ||||||
|  |   getProcessInstanceManagerPage, | ||||||
|  | } from '#/api/bpm/processInstance'; | ||||||
| import { DocAlert } from '#/components/doc-alert'; | import { DocAlert } from '#/components/doc-alert'; | ||||||
|  | 
 | ||||||
|  | import { useGridColumns, useGridFormSchema } from './data'; | ||||||
|  | 
 | ||||||
|  | defineOptions({ name: 'BpmProcessInstanceManager' }); | ||||||
|  | 
 | ||||||
|  | const [Grid, gridApi] = useVbenVxeGrid({ | ||||||
|  |   formOptions: { | ||||||
|  |     schema: useGridFormSchema(), | ||||||
|  |   }, | ||||||
|  |   gridOptions: { | ||||||
|  |     columns: useGridColumns(onActionClick, onTaskClick), | ||||||
|  |     height: 'auto', | ||||||
|  |     keepSource: true, | ||||||
|  |     proxyConfig: { | ||||||
|  |       ajax: { | ||||||
|  |         query: async ({ page }, formValues) => { | ||||||
|  |           return await getProcessInstanceManagerPage({ | ||||||
|  |             pageNo: page.currentPage, | ||||||
|  |             pageSize: page.pageSize, | ||||||
|  |             ...formValues, | ||||||
|  |           }); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     rowConfig: { | ||||||
|  |       keyField: 'id', | ||||||
|  |     }, | ||||||
|  |     toolbarConfig: { | ||||||
|  |       refresh: { code: 'query' }, | ||||||
|  |       search: true, | ||||||
|  |     }, | ||||||
|  |   } as VxeTableGridOptions<BpmProcessInstanceApi.ProcessInstanceVO>, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** 表格操作按钮的回调函数 */ | ||||||
|  | function onActionClick({ | ||||||
|  |   code, | ||||||
|  |   row, | ||||||
|  | }: OnActionClickParams<BpmProcessInstanceApi.ProcessInstanceVO>) { | ||||||
|  |   switch (code) { | ||||||
|  |     case 'cancel': { | ||||||
|  |       onCancel(row); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     case 'detail': { | ||||||
|  |       onDetail(row); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 点击任务 */ | ||||||
|  | function onTaskClick(task: BpmProcessInstanceApi.Task) { | ||||||
|  |   // TODO 待实现 | ||||||
|  |   console.warn(task); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 取消流程实例 */ | ||||||
|  | function onCancel(row: BpmProcessInstanceApi.ProcessInstanceVO) { | ||||||
|  |   prompt({ | ||||||
|  |     async beforeClose(scope) { | ||||||
|  |       if (scope.isConfirm) { | ||||||
|  |         if (scope.value) { | ||||||
|  |           try { | ||||||
|  |             await cancelProcessInstanceByAdmin(row.id, scope.value); | ||||||
|  |             message.success('取消成功'); | ||||||
|  |             onRefresh(); | ||||||
|  |           } catch { | ||||||
|  |             return false; | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           message.error('请输入取消原因'); | ||||||
|  |           return false; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     component: () => { | ||||||
|  |       return h(Textarea, { | ||||||
|  |         placeholder: '请输入取消原因', | ||||||
|  |         allowClear: true, | ||||||
|  |         rows: 2, | ||||||
|  |         rules: [{ required: true, message: '请输入取消原因' }], | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |     content: '请输入取消原因', | ||||||
|  |     title: '取消流程', | ||||||
|  |     modelPropName: 'value', | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 查看流程实例 */ | ||||||
|  | function onDetail(row: BpmProcessInstanceApi.ProcessInstanceVO) { | ||||||
|  |   console.warn(row); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 刷新表格 */ | ||||||
|  | function onRefresh() { | ||||||
|  |   gridApi.query(); | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <Page> |   <Page auto-content-height> | ||||||
|     <DocAlert title="工作流手册" url="https://doc.iocoder.cn/bpm/" /> |     <DocAlert title="工作流手册" url="https://doc.iocoder.cn/bpm" /> | ||||||
|     <Button | 
 | ||||||
|       danger |     <FormModal @success="onRefresh" /> | ||||||
|       type="link" |     <Grid table-title="流程实例" /> | ||||||
|       target="_blank" |  | ||||||
|       href="https://github.com/yudaocode/yudao-ui-admin-vue3" |  | ||||||
|     > |  | ||||||
|       该功能支持 Vue3 + element-plus 版本! |  | ||||||
|     </Button> |  | ||||||
|     <br /> |  | ||||||
|     <Button |  | ||||||
|       type="link" |  | ||||||
|       target="_blank" |  | ||||||
|       href="https://github.com/yudaocode/yudao-ui-admin-vue3/blob/master/src/views/bpm/processInstance/manager/index" |  | ||||||
|     > |  | ||||||
|       可参考 |  | ||||||
|       https://github.com/yudaocode/yudao-ui-admin-vue3/blob/master/src/views/bpm/processInstance/manager/index |  | ||||||
|       代码,pull request 贡献给我们! |  | ||||||
|     </Button> |  | ||||||
|   </Page> |   </Page> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
|     "mobile": "Please input a valid {0}" |     "mobile": "Please input a valid {0}" | ||||||
|   }, |   }, | ||||||
|   "actionTitle": { |   "actionTitle": { | ||||||
|  |     "cancel": "Cancel {0}", | ||||||
|     "edit": "Modify {0}", |     "edit": "Modify {0}", | ||||||
|     "create": "Create {0}", |     "create": "Create {0}", | ||||||
|     "delete": "Delete {0}", |     "delete": "Delete {0}", | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
|     "mobile": "请输入正确的{0}" |     "mobile": "请输入正确的{0}" | ||||||
|   }, |   }, | ||||||
|   "actionTitle": { |   "actionTitle": { | ||||||
|  |     "cancel": "取消{0}", | ||||||
|     "edit": "修改{0}", |     "edit": "修改{0}", | ||||||
|     "create": "新增{0}", |     "create": "新增{0}", | ||||||
|     "delete": "删除{0}", |     "delete": "删除{0}", | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 xingyu4j
						xingyu4j