From ae2cb4ae0c5e2b2e86acd9327ace31c6de550ab7 Mon Sep 17 00:00:00 2001 From: ziye <278898052@qq.com> Date: Wed, 7 May 2025 23:57:41 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=AF=A6=E6=83=85=E6=A8=A1=E5=9D=97=EF=BC=8C=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=2020%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/api/bpm/model/index.ts | 1 + .../src/api/bpm/processInstance/index.ts | 23 +++++-- .../web-antd/src/router/routes/modules/bpm.ts | 35 ++++++++++ apps/web-antd/src/utils/constants.ts | 45 ++++++++++++- apps/web-antd/src/utils/formCreate.ts | 64 +++++++++++++++++++ apps/web-antd/src/utils/index.ts | 2 + apps/web-antd/src/utils/routerHelper.ts | 15 +++++ .../bpm/processInstance/manager/index.vue | 5 ++ packages/icons/src/svg/icons/bpm-approve.svg | 1 + packages/icons/src/svg/icons/bpm-cancel.svg | 1 + packages/icons/src/svg/icons/bpm-reject.svg | 1 + packages/icons/src/svg/icons/bpm-running.svg | 1 + packages/icons/src/svg/index.ts | 10 +++ 13 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 apps/web-antd/src/router/routes/modules/bpm.ts create mode 100644 apps/web-antd/src/utils/formCreate.ts create mode 100644 apps/web-antd/src/utils/routerHelper.ts create mode 100644 packages/icons/src/svg/icons/bpm-approve.svg create mode 100644 packages/icons/src/svg/icons/bpm-cancel.svg create mode 100644 packages/icons/src/svg/icons/bpm-reject.svg create mode 100644 packages/icons/src/svg/icons/bpm-running.svg diff --git a/apps/web-antd/src/api/bpm/model/index.ts b/apps/web-antd/src/api/bpm/model/index.ts index 4f9a51c10..713fedc47 100644 --- a/apps/web-antd/src/api/bpm/model/index.ts +++ b/apps/web-antd/src/api/bpm/model/index.ts @@ -18,6 +18,7 @@ export namespace BpmModelApi { deploymentTime: number; suspensionState: number; formType?: number; + formCustomViewPath?: string; } /** 流程模型 VO */ diff --git a/apps/web-antd/src/api/bpm/processInstance/index.ts b/apps/web-antd/src/api/bpm/processInstance/index.ts index cec0a1fdd..f287ee0be 100644 --- a/apps/web-antd/src/api/bpm/processInstance/index.ts +++ b/apps/web-antd/src/api/bpm/processInstance/index.ts @@ -1,7 +1,7 @@ import type { PageParam, PageResult } from '@vben/request'; import type { BpmModelApi } from '#/api/bpm/model'; -import type { CandidateStrategy, NodeType } from '#/utils'; +import type { CandidateStrategyEnum, NodeTypeEnum } from '#/utils'; import { requestClient } from '#/api/request'; @@ -29,12 +29,12 @@ export namespace BpmProcessInstanceApi { // 审批节点信息 export type ApprovalNodeInfo = { - candidateStrategy?: CandidateStrategy; + candidateStrategy?: CandidateStrategyEnum; candidateUsers?: User[]; endTime?: Date; id: number; name: string; - nodeType: NodeType; + nodeType: NodeTypeEnum; startTime?: Date; status: number; tasks: ApprovalTaskInfo[]; @@ -46,14 +46,25 @@ export namespace BpmProcessInstanceApi { createTime: string; endTime: string; fields: string[]; + formVariables: Record; id: number; name: string; processDefinition?: BpmModelApi.ProcessDefinitionVO; processDefinitionId: string; remark: string; result: number; + startTime?: Date; + startUser?: User; + status: number; + tasks?: BpmProcessInstanceApi.Task[]; + }; + + export type ApprovalDetail = { + activityNodes: BpmProcessInstanceApi.ApprovalNodeInfo[]; + formFieldsPermission: any; + processDefinition: BpmModelApi.ProcessDefinitionVO; + processInstance: BpmProcessInstanceApi.ProcessInstanceVO; status: number; - tasks: BpmProcessInstanceApi.Task[]; }; } @@ -133,7 +144,7 @@ export async function updateProcessInstance( /** 获取审批详情 */ export async function getApprovalDetail(params: any) { - return requestClient.get( + return requestClient.get( `/bpm/process-instance/get-approval-detail`, { params }, ); @@ -156,7 +167,7 @@ export async function getFormFieldsPermission(params: any) { } /** 获取流程实例 BPMN 模型视图 */ -export async function getProcessInstanceBpmnModelView(id: number) { +export async function getProcessInstanceBpmnModelView(id: string) { return requestClient.get( `/bpm/process-instance/get-bpmn-model-view?id=${id}`, ); diff --git a/apps/web-antd/src/router/routes/modules/bpm.ts b/apps/web-antd/src/router/routes/modules/bpm.ts new file mode 100644 index 000000000..20688f3e3 --- /dev/null +++ b/apps/web-antd/src/router/routes/modules/bpm.ts @@ -0,0 +1,35 @@ +import type { RouteRecordRaw } from 'vue-router'; + +const routes: RouteRecordRaw[] = [ + { + path: '/bpm', + name: 'bpm', + meta: { + title: '工作流', + hideInMenu: true, + }, + children: [ + { + path: 'process-instance/detail', + component: () => import('#/views/bpm/processInstance/detail/index.vue'), + name: 'BpmProcessInstanceDetail', + meta: { + title: '流程详情', + activePath: '/bpm/task/my', + icon: 'ant-design:history-outlined', + keepAlive: false, + hideInMenu: true, + }, + props: (route) => { + return { + id: route.query.id, + taskId: route.query.taskId, + activityId: route.query.activityId, + }; + }, + }, + ], + }, +]; + +export default routes; diff --git a/apps/web-antd/src/utils/constants.ts b/apps/web-antd/src/utils/constants.ts index ec58eec82..78da9f947 100644 --- a/apps/web-antd/src/utils/constants.ts +++ b/apps/web-antd/src/utils/constants.ts @@ -466,7 +466,7 @@ export const BpmAutoApproveType = { }; // 候选人策略枚举 ( 用于审批节点。抄送节点 ) -export enum CandidateStrategy { +export enum CandidateStrategyEnum { /** * 审批人自选 */ @@ -532,7 +532,7 @@ export enum CandidateStrategy { /** * 节点类型 */ -export enum NodeType { +export enum NodeTypeEnum { /** * 子流程节点 */ @@ -593,3 +593,44 @@ export enum NodeType { */ USER_TASK_NODE = 11, } + +/** + * 任务状态枚举 + */ +export enum TaskStatusEnum { + /** + * 审批通过 + */ + APPROVE = 2, + + /** + * 审批通过中 + */ + APPROVING = 7, + /** + * 已取消 + */ + CANCEL = 4, + /** + * 未开始 + */ + NOT_START = -1, + + /** + * 审批不通过 + */ + REJECT = 3, + + /** + * 已退回 + */ + RETURN = 5, + /** + * 审批中 + */ + RUNNING = 1, + /** + * 待审批 + */ + WAIT = 0, +} diff --git a/apps/web-antd/src/utils/formCreate.ts b/apps/web-antd/src/utils/formCreate.ts new file mode 100644 index 000000000..d7f944c0f --- /dev/null +++ b/apps/web-antd/src/utils/formCreate.ts @@ -0,0 +1,64 @@ +/** + * 针对 https://github.com/xaboy/form-create-designer 封装的工具类 + */ + +import { isRef } from 'vue'; + +// 编码表单 Conf +export const encodeConf = (designerRef: object) => { + // @ts-ignore designerRef.value is dynamically added by form-create-designer + return JSON.stringify(designerRef.value.getOption()); +}; + +// 编码表单 Fields +export const encodeFields = (designerRef: object) => { + // @ts-ignore designerRef.value is dynamically added by form-create-designer + const rule = JSON.parse(designerRef.value.getJson()); + const fields: string[] = []; + rule.forEach((item: unknown) => { + fields.push(JSON.stringify(item)); + }); + return fields; +}; + +// 解码表单 Fields +export const decodeFields = (fields: string[]) => { + const rule: object[] = []; + fields.forEach((item) => { + rule.push(JSON.parse(item)); + }); + return rule; +}; + +// 设置表单的 Conf 和 Fields,适用 FcDesigner 场景 +export const setConfAndFields = ( + designerRef: object, + conf: string, + fields: string, +) => { + // @ts-ignore designerRef.value is dynamically added by form-create-designer + designerRef.value.setOption(JSON.parse(conf)); + // @ts-ignore designerRef.value is dynamically added by form-create-designer + designerRef.value.setRule(decodeFields(fields)); +}; + +// 设置表单的 Conf 和 Fields,适用 form-create 场景 +export const setConfAndFields2 = ( + detailPreview: object, + conf: string, + fields: string[], + value?: object, +) => { + if (isRef(detailPreview)) { + // @ts-ignore detailPreview.value is dynamically added by form-create-designer + detailPreview = detailPreview.value; + } + // @ts-ignore detailPreview properties are dynamically added by form-create-designer + detailPreview.option = JSON.parse(conf); + // @ts-ignore detailPreview properties are dynamically added by form-create-designer + detailPreview.rule = decodeFields(fields); + if (value) { + // @ts-ignore detailPreview properties are dynamically added by form-create-designer + detailPreview.value = value; + } +}; diff --git a/apps/web-antd/src/utils/index.ts b/apps/web-antd/src/utils/index.ts index dfcc60466..022e6441d 100644 --- a/apps/web-antd/src/utils/index.ts +++ b/apps/web-antd/src/utils/index.ts @@ -1,5 +1,7 @@ export * from './constants'; export * from './dict'; export * from './formatTime'; +export * from './formCreate'; export * from './rangePickerProps'; +export * from './routerHelper'; export * from './validator'; diff --git a/apps/web-antd/src/utils/routerHelper.ts b/apps/web-antd/src/utils/routerHelper.ts new file mode 100644 index 000000000..d4c7ac5d0 --- /dev/null +++ b/apps/web-antd/src/utils/routerHelper.ts @@ -0,0 +1,15 @@ +import { defineAsyncComponent } from 'vue'; + +const modules = import.meta.glob('../views/**/*.{vue,tsx}'); +/** + * 注册一个异步组件 + * @param componentPath 例:/bpm/oa/leave/detail + */ +export const registerComponent = (componentPath: string) => { + for (const item in modules) { + if (item.includes(componentPath)) { + // 使用异步组件的方式来动态加载组件 + return defineAsyncComponent(modules[item] as any); + } + } +}; diff --git a/apps/web-antd/src/views/bpm/processInstance/manager/index.vue b/apps/web-antd/src/views/bpm/processInstance/manager/index.vue index 3b3ce81b9..576cc2ec0 100644 --- a/apps/web-antd/src/views/bpm/processInstance/manager/index.vue +++ b/apps/web-antd/src/views/bpm/processInstance/manager/index.vue @@ -17,6 +17,7 @@ import { getProcessInstanceManagerPage, } from '#/api/bpm/processInstance'; import { DocAlert } from '#/components/doc-alert'; +import { router } from '#/router'; import { useGridColumns, useGridFormSchema } from './data'; @@ -110,6 +111,10 @@ function onCancel(row: BpmProcessInstanceApi.ProcessInstanceVO) { /** 查看流程实例 */ function onDetail(row: BpmProcessInstanceApi.ProcessInstanceVO) { console.warn(row); + router.push({ + name: 'BpmProcessInstanceDetail', + query: { id: row.id }, + }); } /** 刷新表格 */ diff --git a/packages/icons/src/svg/icons/bpm-approve.svg b/packages/icons/src/svg/icons/bpm-approve.svg new file mode 100644 index 000000000..06aa09d6d --- /dev/null +++ b/packages/icons/src/svg/icons/bpm-approve.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/src/svg/icons/bpm-cancel.svg b/packages/icons/src/svg/icons/bpm-cancel.svg new file mode 100644 index 000000000..ab9b1553b --- /dev/null +++ b/packages/icons/src/svg/icons/bpm-cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/src/svg/icons/bpm-reject.svg b/packages/icons/src/svg/icons/bpm-reject.svg new file mode 100644 index 000000000..21fd5f60e --- /dev/null +++ b/packages/icons/src/svg/icons/bpm-reject.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/src/svg/icons/bpm-running.svg b/packages/icons/src/svg/icons/bpm-running.svg new file mode 100644 index 000000000..5908c13b2 --- /dev/null +++ b/packages/icons/src/svg/icons/bpm-running.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/icons/src/svg/index.ts b/packages/icons/src/svg/index.ts index 3b5cb9953..64d46df75 100644 --- a/packages/icons/src/svg/index.ts +++ b/packages/icons/src/svg/index.ts @@ -12,6 +12,12 @@ const SvgBellIcon = createIconifyIcon('svg:bell'); const SvgCakeIcon = createIconifyIcon('svg:cake'); const SvgAntdvLogoIcon = createIconifyIcon('svg:antdv-logo'); +// bpm 图标 +const SvgBpmRunningIcon = createIconifyIcon('svg:bpm-running'); +const SvgBpmApproveIcon = createIconifyIcon('svg:bpm-approve'); +const SvgBpmRejectIcon = createIconifyIcon('svg:bpm-reject'); +const SvgBpmCancelIcon = createIconifyIcon('svg:bpm-cancel'); + export { SvgAntdvLogoIcon, SvgAvatar1Icon, @@ -19,6 +25,10 @@ export { SvgAvatar3Icon, SvgAvatar4Icon, SvgBellIcon, + SvgBpmApproveIcon, + SvgBpmCancelIcon, + SvgBpmRejectIcon, + SvgBpmRunningIcon, SvgCakeIcon, SvgCardIcon, SvgDownloadIcon, From 654bd3ff8eb39002ddaf9884c62c4874ad618d15 Mon Sep 17 00:00:00 2001 From: ziye <278898052@qq.com> Date: Thu, 8 May 2025 00:02:13 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=AF=A6=E6=83=85=E6=A8=A1=E5=9D=97=EF=BC=8C=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=2021%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/processInstance/detail/index.vue | 345 ++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 apps/web-antd/src/views/bpm/processInstance/detail/index.vue diff --git a/apps/web-antd/src/views/bpm/processInstance/detail/index.vue b/apps/web-antd/src/views/bpm/processInstance/detail/index.vue new file mode 100644 index 000000000..0c6f191bf --- /dev/null +++ b/apps/web-antd/src/views/bpm/processInstance/detail/index.vue @@ -0,0 +1,345 @@ + + + From e40a29ccb4307bc9f60e87b4a91af039a6cb9a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=90=E5=A4=9C?= <278898052@qq.com> Date: Thu, 8 May 2025 16:52:46 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=AF=A6=E6=83=85=E6=A8=A1=E5=9D=97=EF=BC=8C=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=2025%=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E7=BA=BF=E7=BB=84=E4=BB=B6=E5=B9=B6=E8=B0=83=E6=95=B4=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/processInstance/detail/index.vue | 26 +- .../detail/modules/time-line.vue | 442 ++++++++++++++++++ 2 files changed, 459 insertions(+), 9 deletions(-) create mode 100644 apps/web-antd/src/views/bpm/processInstance/detail/modules/time-line.vue diff --git a/apps/web-antd/src/views/bpm/processInstance/detail/index.vue b/apps/web-antd/src/views/bpm/processInstance/detail/index.vue index 0c6f191bf..a469fb9f8 100644 --- a/apps/web-antd/src/views/bpm/processInstance/detail/index.vue +++ b/apps/web-antd/src/views/bpm/processInstance/detail/index.vue @@ -13,7 +13,6 @@ import { } from '@vben/icons'; import { formatDateTime } from '@vben/utils'; -import formCreate from '@form-create/ant-design-vue'; import { Avatar, Button, @@ -40,6 +39,8 @@ import { TaskStatusEnum, } from '#/utils'; +import TimeLine from './modules/time-line.vue'; + defineOptions({ name: 'BpmProcessInstanceDetail' }); const props = defineProps<{ @@ -146,6 +147,9 @@ async function getApprovalDetail() { processDefinition.value.formFields, processInstance.value.formVariables, ); + + detailForm.value.value.Fx21maervo4ratc = undefined; + detailForm.value.value.F3yvmaervlwuanc = undefined; } nextTick().then(() => { fApi.value?.btn.show(false); @@ -232,17 +236,20 @@ onMounted(async () => {