feat-wip(projects): 流程定义完成

This commit is contained in:
AN
2025-06-13 00:20:45 +08:00
parent f52fa40326
commit 997f4a2d61
10 changed files with 138 additions and 16 deletions

View File

@ -36,3 +36,6 @@ UPDATE `sys_menu` SET `path` = 'https://gitee.com/xlsea/ruoyi-plus-soybean', `co
-- plus-ui 需要禁用的页面
UPDATE `sys_menu` SET `status` = '1' WHERE `menu_id` IN ( '116', '130', '131', '132', '11700', '11701' );
-- 工作流菜单
UPDATE `sys_menu` SET `component` = 'workflow/processDefinition/index', WHERE `menu_id` = 11620;

View File

@ -236,6 +236,7 @@ const local: App.I18n.Schema = {
exception_404: '404',
exception_500: '500',
'workflow_process-definition': 'Process Definition',
'workflow_process-definition_design': 'Process Definition Design',
'workflow_process-instance': 'Process Instance',
workflow_leave: 'Leave Apply'
},

View File

@ -236,6 +236,7 @@ const local: App.I18n.Schema = {
exception_404: '404',
exception_500: '500',
'workflow_process-definition': '流程定义',
'workflow_process-definition_design': '流程设计',
'workflow_process-instance': '流程实例',
workflow_leave: '请假申请'
},

View File

@ -45,6 +45,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
tool_gen: () => import("@/views/tool/gen/index.vue"),
workflow_category: () => import("@/views/workflow/category/index.vue"),
workflow_leave: () => import("@/views/workflow/leave/index.vue"),
"workflow_process-definition": () => import("@/views/workflow/process-definition/index.vue"),
"workflow_process-definition": () => import("@/views/workflow/process-definition/definition/index.vue"),
"workflow_process-definition_design": () => import("@/views/workflow/process-definition/design/index.vue"),
"workflow_process-instance": () => import("@/views/workflow/process-instance/index.vue"),
};

View File

@ -361,13 +361,14 @@ export const generatedRoutes: GeneratedRoute[] = [
},
{
name: 'workflow_process-definition',
path: '/workflow/process-definition',
path: '/workflow/process-definition/definition',
component: 'view.workflow_process-definition',
meta: {
title: 'workflow_process-definition',
i18nKey: 'route.workflow_process-definition'
}
},
{
name: 'workflow_process-instance',
path: '/workflow/process-instance',

View File

@ -202,7 +202,8 @@ const routeMap: RouteMap = {
"workflow": "/workflow",
"workflow_category": "/workflow/category",
"workflow_leave": "/workflow/leave",
"workflow_process-definition": "/workflow/process-definition",
"workflow_process-definition": "/workflow/process-definition/definition",
"workflow_process-definition_design": "/workflow/process-definition/design",
"workflow_process-instance": "/workflow/process-instance"
};

View File

@ -62,3 +62,11 @@ export function fetchPublishDefinition(id: CommonType.IdType) {
method: 'put'
});
}
/** 复制流程定义 */
export function fetchCopyDefinition(id: CommonType.IdType) {
return request<boolean>({
url: `/workflow/definition/copy/${id}`,
method: 'post'
});
}

View File

@ -56,7 +56,8 @@ declare module "@elegant-router/types" {
"workflow": "/workflow";
"workflow_category": "/workflow/category";
"workflow_leave": "/workflow/leave";
"workflow_process-definition": "/workflow/process-definition";
"workflow_process-definition": "/workflow/process-definition/definition";
"workflow_process-definition_design": "/workflow/process-definition/design";
"workflow_process-instance": "/workflow/process-instance";
};
@ -154,6 +155,7 @@ declare module "@elegant-router/types" {
| "workflow_category"
| "workflow_leave"
| "workflow_process-definition"
| "workflow_process-definition_design"
| "workflow_process-instance"
>;
@ -229,7 +231,7 @@ declare module "@elegant-router/types" {
component: `view.${K}`;
}
: never;
/**
* the center level route
*/
@ -252,7 +254,7 @@ declare module "@elegant-router/types" {
children: (CenterLevelRoute<GetChildRouteKey<K>> | LastLevelRoute<GetChildRouteKey<K>>)[];
}
: never;
/**
* the custom first level route
*/

View File

@ -7,6 +7,7 @@ import { workflowPublishStatusRecord } from '@/constants/workflow';
import {
fetchActiveDefinition,
fetchBatchDeleteDefinition,
fetchCopyDefinition,
fetchGetCategoryTree,
fetchGetDefinitionList,
fetchGetUnPublishDefinitionList,
@ -16,11 +17,12 @@ import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useDownload } from '@/hooks/business/download';
import { useTable, useTableOperate } from '@/hooks/common/table';
import { useRouterPush } from '@/hooks/common/router';
import { $t } from '@/locales';
import ButtonIcon from '@/components/custom/button-icon.vue';
import DefinitionOperateDrawer from './modules/definition-operate-drawer.vue';
import DefinitionSearch from './modules/definition-search.vue';
import DefinitionImportModal from './modules/definition-import-modal.vue';
import DefinitionOperateDrawer from '../modules/definition-operate-drawer.vue';
import DefinitionSearch from '../modules/definition-search.vue';
import DefinitionImportModal from '../modules/definition-import-modal.vue';
defineOptions({
name: 'DefinitionList'
@ -34,9 +36,9 @@ interface IsPublishOption {
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const { routerPushByKey } = useRouterPush();
const { bool: importVisible, setTrue: showImportModal } = useBoolean();
const isPublish = ref<boolean>(true);
const isPublishOptions = ref<IsPublishOption[]>([
{
@ -196,9 +198,23 @@ const {
onPositiveClick={() => handleDelete(row.id)}
/>
),
design: <ButtonIcon text type="primary" icon="material-symbols:design-services" tooltipContent="流程设计" />,
design: (
<ButtonIcon
text
type="primary"
icon="material-symbols:design-services"
tooltipContent="流程设计"
onClick={() => handleDesign(row.id)}
/>
),
preview: (
<ButtonIcon text type="primary" icon="material-symbols:visibility-outline" tooltipContent="查看流程" />
<ButtonIcon
text
type="primary"
icon="material-symbols:visibility-outline"
tooltipContent="查看流程"
onClick={() => handlePreview(row.id)}
/>
),
publish: (
<ButtonIcon
@ -206,10 +222,20 @@ const {
type="primary"
icon="material-symbols:publish"
tooltipContent="发布流程"
onClick={() => handlePublish(row.id)}
popconfirmContent={`确定要发布 ${row.flowName} 吗?`}
onPositiveClick={() => handlePublish(row.id)}
/>
),
copy: (
<ButtonIcon
text
type="primary"
icon="material-symbols:content-copy"
tooltipContent="复制流程"
popconfirmContent={`确定要复制 ${row.flowName} 吗?`}
onPositiveClick={() => handleCopy(row.id)}
/>
),
copy: <ButtonIcon text type="primary" icon="material-symbols:content-copy" tooltipContent="复制流程" />,
export: (
<ButtonIcon
text
@ -287,6 +313,36 @@ async function handlePublish(id: CommonType.IdType) {
getDataByPage();
}
async function handleCopy(id: CommonType.IdType) {
const { error } = await fetchCopyDefinition(id);
if (error) return;
window.$message?.success('复制成功');
//
if (isPublish.value) {
isPublish.value = false;
} else {
getDataByPage();
}
}
function handleDesign(id: CommonType.IdType) {
routerPushByKey('workflow_process-definition_design', {
query: {
definitionId: id.toString(),
disabled: 'false'
}
});
}
function handlePreview(id: CommonType.IdType) {
routerPushByKey('workflow_process-definition_design', {
query: {
definitionId: id.toString(),
disabled: 'true'
}
});
}
function handleExport(row: TableDataWithIndex<Api.Workflow.Definition>) {
download(`/workflow/definition/exportDef/${row.id}`, {}, `${row.flowCode}.json`);
}
@ -325,7 +381,7 @@ const selectable = computed(() => {
</script>
<template>
<TableSiderLayout :sider-title="$t('page.system.dept.title')">
<TableSiderLayout sider-title="流程分类">
<template #header-extra>
<NButton size="small" text class="h-18px" @click.stop="() => handleResetTreeData()">
<template #icon>
@ -352,7 +408,7 @@ const selectable = computed(() => {
@update:selected-keys="handleClickTree"
>
<template #empty>
<NEmpty :description="$t('page.system.dept.empty')" class="h-full min-h-200px justify-center" />
<NEmpty description="暂无流程分类" class="h-full min-h-200px justify-center" />
</template>
</NTree>
</NSpin>

View File

@ -0,0 +1,48 @@
<script setup lang="ts">
import { useRoute } from 'vue-router';
import { useEventListener } from '@vueuse/core';
import { stringify } from 'qs';
import { getToken } from '@/store/modules/auth/shared';
import { getTabIdByRoute } from '@/store/modules/tab/shared';
import { useTabStore } from '@/store/modules/tab';
import { useRouterPush } from '@/hooks/common/router';
import { getServiceBaseURL } from '@/utils/service';
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
const { removeTab } = useTabStore();
const { routerPushByKey } = useRouterPush();
const route = useRoute();
const disabled = route.query.disabled === 'true';
const urlParams = {
Authorization: `Bearer ${getToken()}`,
id: route.query.definitionId,
clientid: import.meta.env.VITE_APP_CLIENT_ID,
disabled
};
const iframeUrl = `${baseURL}/warm-flow-ui/index.html?${stringify(urlParams)}`;
function messageHandler(event: MessageEvent) {
switch (event.data.method) {
case 'close': {
const tabId = getTabIdByRoute(route);
removeTab(tabId);
routerPushByKey('workflow_process-definition');
break;
}
default: {
break;
}
}
}
// iframe监听组件内设计器保存事件
useEventListener('message', messageHandler);
</script>
<template>
<iframe :src="iframeUrl" class="size-full"></iframe>
</template>