feat(sj_1.0.0): 接入工作流

This commit is contained in:
opensnail 2024-04-23 14:31:09 +08:00
parent 8ac203b885
commit 6adbedd185
17 changed files with 401 additions and 32 deletions

View File

@ -30,7 +30,7 @@ const onChange = (value: string) => {
<template> <template>
<NDropdown v-if="appStore.isMobile" :value="namespaceId" :options="dropOptions" trigger="hover" @select="onChange"> <NDropdown v-if="appStore.isMobile" :value="namespaceId" :options="dropOptions" trigger="hover" @select="onChange">
<div> <div>
<ButtonIcon :tooltip-content="$t('icon.namepase')" tooltip-placement="left"> <ButtonIcon :tooltip-content="$t('icon.namespace')" tooltip-placement="left">
<SvgIcon icon="oui:app-spaces" /> <SvgIcon icon="oui:app-spaces" />
</ButtonIcon> </ButtonIcon>
</div> </div>

View File

@ -173,7 +173,7 @@ const local: App.I18n.Schema = {
'function_toggle-auth': 'Toggle Auth', 'function_toggle-auth': 'Toggle Auth',
'function_super-page': 'Super Admin Visible', 'function_super-page': 'Super Admin Visible',
pods: 'Online Machine', pods: 'Online Machine',
namepase: 'Namepase', namespace: 'namespace',
manage: 'System Manage', manage: 'System Manage',
manage_user: 'User Manage', manage_user: 'User Manage',
notify: 'notify', notify: 'notify',
@ -183,6 +183,8 @@ const local: App.I18n.Schema = {
retry_task: 'Retry task', retry_task: 'Retry task',
retry_scene: 'Retry scene', retry_scene: 'Retry scene',
workflow: 'Workflow', workflow: 'Workflow',
workflow_task: 'Workflow Task',
workflow_batch: 'Workflow Batch',
job: 'Schedule Task Management', job: 'Schedule Task Management',
job_task: 'Schedule Task List', job_task: 'Schedule Task List',
'manage_user-detail': 'User Detail', 'manage_user-detail': 'User Detail',
@ -701,6 +703,22 @@ const local: App.I18n.Schema = {
round: '轮询' round: '轮询'
} }
}, },
workflowBatch: {
title: 'Workflow Batch List',
workflowName: 'Workflow name',
groupName: 'Group name',
executionAt: 'Execution time',
taskBatchStatus: 'State',
operationReason: 'Reason for operation',
createDt: 'Creation time',
form: {
workflowName: 'Please enter Workflow name',
taskBatchStatus: 'Please enter State',
groupName: 'Please enter Group name'
},
addWorkflowBatch: 'Add Workflow batch',
editWorkflowBatch: 'Add Workflow batch'
},
workflow: { workflow: {
title: 'Workflow List', title: 'Workflow List',
workflowName: 'Workflow name', workflowName: 'Workflow name',
@ -810,7 +828,7 @@ const local: App.I18n.Schema = {
expand: 'Expand Menu', expand: 'Expand Menu',
pin: 'Pin', pin: 'Pin',
unpin: 'Unpin', unpin: 'Unpin',
namepase: 'Switch Namepase' namespace: 'Switch namespace'
} }
}; };

View File

@ -173,7 +173,7 @@ const local: App.I18n.Schema = {
'function_toggle-auth': '切换权限', 'function_toggle-auth': '切换权限',
'function_super-page': '超级管理员可见', 'function_super-page': '超级管理员可见',
pods: '在线机器', pods: '在线机器',
namepase: '命名空间', namespace: '命名空间',
group: '组管理', group: '组管理',
manage: '系统管理', manage: '系统管理',
manage_user: '用户管理', manage_user: '用户管理',
@ -184,8 +184,10 @@ const local: App.I18n.Schema = {
retry_task: '重试任务', retry_task: '重试任务',
retry_scene: '重试场景', retry_scene: '重试场景',
workflow: '工作流', workflow: '工作流',
job: '定时任务管理', workflow_task: '任务管理',
job_task: '定时任务信息', workflow_batch: '执行批次',
job: '定时任务',
job_task: '任务管理',
'manage_user-detail': '用户详情', 'manage_user-detail': '用户详情',
manage_role: '角色管理', manage_role: '角色管理',
manage_menu: '菜单管理', manage_menu: '菜单管理',
@ -715,6 +717,22 @@ const local: App.I18n.Schema = {
addWorkflow: '新增工作流', addWorkflow: '新增工作流',
editWorkflow: '编辑工作流' editWorkflow: '编辑工作流'
}, },
workflowBatch: {
title: '工作流批次列表',
workflowName: '工作流名称',
groupName: '组名称',
executionAt: '执行时间',
taskBatchStatus: '状态',
operationReason: '操作原因',
createDt: '创建时间',
form: {
workflowName: '请输入工作流名称',
taskBatchStatus: '请输入状态',
groupName: '请输入组名称'
},
addWorkflowBatch: '新增工作流批次',
editWorkflowBatch: '编辑工作流批次'
},
jobTask: { jobTask: {
title: '定时任务列表', title: '定时任务列表',
groupName: '组名称', groupName: '组名称',
@ -806,7 +824,7 @@ const local: App.I18n.Schema = {
expand: '展开菜单', expand: '展开菜单',
pin: '固定', pin: '固定',
unpin: '取消固定', unpin: '取消固定',
namepase: '切换空间' namespace: '切换空间'
} }
}; };

View File

@ -37,12 +37,13 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
manage_user: () => import("@/views/manage/user/index.vue"), manage_user: () => import("@/views/manage/user/index.vue"),
"multi-menu_first_child": () => import("@/views/multi-menu/first_child/index.vue"), "multi-menu_first_child": () => import("@/views/multi-menu/first_child/index.vue"),
"multi-menu_second_child_home": () => import("@/views/multi-menu/second_child_home/index.vue"), "multi-menu_second_child_home": () => import("@/views/multi-menu/second_child_home/index.vue"),
namepase: () => import("@/views/namepase/index.vue"), namespace: () => import("@/views/namespace/index.vue"),
notify_recipient: () => import("@/views/notify/recipient/index.vue"), notify_recipient: () => import("@/views/notify/recipient/index.vue"),
notify_scene: () => import("@/views/notify/scene/index.vue"), notify_scene: () => import("@/views/notify/scene/index.vue"),
pods: () => import("@/views/pods/index.vue"), pods: () => import("@/views/pods/index.vue"),
retry_scene: () => import("@/views/retry/scene/index.vue"), retry_scene: () => import("@/views/retry/scene/index.vue"),
retry_task: () => import("@/views/retry/task/index.vue"), retry_task: () => import("@/views/retry/task/index.vue"),
"user-center": () => import("@/views/user-center/index.vue"), "user-center": () => import("@/views/user-center/index.vue"),
workflow: () => import("@/views/workflow/index.vue"), workflow_batch: () => import("@/views/workflow/batch/index.vue"),
workflow_task: () => import("@/views/workflow/task/index.vue"),
}; };

View File

@ -45,7 +45,9 @@ export const generatedRoutes: GeneratedRoute[] = [
component: 'layout.base$view.about', component: 'layout.base$view.about',
meta: { meta: {
title: 'about', title: 'about',
i18nKey: 'route.about' i18nKey: 'route.about',
order: 1000,
icon: 'material-symbols:help-outline-rounded'
} }
}, },
{ {
@ -173,7 +175,9 @@ export const generatedRoutes: GeneratedRoute[] = [
component: 'layout.base$view.group', component: 'layout.base$view.group',
meta: { meta: {
title: 'group', title: 'group',
i18nKey: 'route.group' i18nKey: 'route.group',
order: 30,
icon: 'material-symbols:group-work-outline'
} }
}, },
{ {
@ -193,7 +197,9 @@ export const generatedRoutes: GeneratedRoute[] = [
component: 'layout.base', component: 'layout.base',
meta: { meta: {
title: 'job', title: 'job',
i18nKey: 'route.job' i18nKey: 'route.job',
order: 50,
icon:'eos-icons:cronjob'
}, },
children: [ children: [
{ {
@ -348,12 +354,12 @@ export const generatedRoutes: GeneratedRoute[] = [
] ]
}, },
{ {
name: 'namepase', name: 'namespace',
path: '/namepase', path: '/namespace',
component: 'layout.base$view.namepase', component: 'layout.base$view.namespace',
meta: { meta: {
title: 'namepase', title: 'namespace',
i18nKey: 'route.namepase', i18nKey: 'route.namespace',
icon: 'oui:app-spaces', icon: 'oui:app-spaces',
order: 20 order: 20
} }
@ -365,7 +371,8 @@ export const generatedRoutes: GeneratedRoute[] = [
meta: { meta: {
title: 'notify', title: 'notify',
i18nKey: 'route.notify', i18nKey: 'route.notify',
order: 100 order: 100,
icon: 'material-symbols:notifications-active-outline-rounded'
}, },
children: [ children: [
{ {
@ -406,7 +413,8 @@ export const generatedRoutes: GeneratedRoute[] = [
meta: { meta: {
title: 'retry', title: 'retry',
i18nKey: 'route.retry', i18nKey: 'route.retry',
order: 50 order: 70,
icon: 'carbon:retry-failed'
}, },
children: [ children: [
{ {
@ -442,10 +450,32 @@ export const generatedRoutes: GeneratedRoute[] = [
{ {
name: 'workflow', name: 'workflow',
path: '/workflow', path: '/workflow',
component: 'layout.base$view.workflow', component: 'layout.base',
meta: { meta: {
title: 'workflow', title: 'workflow',
i18nKey: 'route.workflow' i18nKey: 'route.workflow',
order: 60,
icon: 'lucide:workflow'
},
children: [
{
name: 'workflow_batch',
path: '/workflow/batch',
component: 'view.workflow_batch',
meta: {
title: 'workflow_batch',
i18nKey: 'route.workflow_batch'
} }
},
{
name: 'workflow_task',
path: '/workflow/task',
component: 'view.workflow_task',
meta: {
title: 'workflow_task',
i18nKey: 'route.workflow_task'
}
}
]
} }
]; ];

View File

@ -177,7 +177,7 @@ const routeMap: RouteMap = {
"multi-menu_second": "/multi-menu/second", "multi-menu_second": "/multi-menu/second",
"multi-menu_second_child": "/multi-menu/second/child", "multi-menu_second_child": "/multi-menu/second/child",
"multi-menu_second_child_home": "/multi-menu/second/child/home", "multi-menu_second_child_home": "/multi-menu/second/child/home",
"namepase": "/namepase", "namespace": "/namespace",
"notify": "/notify", "notify": "/notify",
"notify_recipient": "/notify/recipient", "notify_recipient": "/notify/recipient",
"notify_scene": "/notify/scene", "notify_scene": "/notify/scene",
@ -186,7 +186,9 @@ const routeMap: RouteMap = {
"retry_scene": "/retry/scene", "retry_scene": "/retry/scene",
"retry_task": "/retry/task", "retry_task": "/retry/task",
"user-center": "/user-center", "user-center": "/user-center",
"workflow": "/workflow" "workflow": "/workflow",
"workflow_batch": "/workflow/batch",
"workflow_task": "/workflow/task"
}; };
/** /**

View File

@ -1,6 +1,6 @@
import { request } from '../request'; import { request } from '../request';
/** get namespace list */ /** get workflow page list */
export function fetchGetWorkflowPageList(params?: Api.Workflow.WorkflowSearchParams) { export function fetchGetWorkflowPageList(params?: Api.Workflow.WorkflowSearchParams) {
return request<Api.Workflow.WorkflowList>({ return request<Api.Workflow.WorkflowList>({
url: '/workflow/page/list', url: '/workflow/page/list',
@ -8,3 +8,21 @@ export function fetchGetWorkflowPageList(params?: Api.Workflow.WorkflowSearchPar
params params
}); });
} }
/** get namespace list */
export function fetchGetWorkflowNameList(params?: Api.WorkflowBatch.WorkflowBatchSearchParams) {
return request<Api.Workflow.Workflow[]>({
url: '/workflow/workflow-name/list',
method: 'get',
params
});
}
/** get workflow batch list */
export function fetchGetWorkflowBatchList(params?: Api.WorkflowBatch.WorkflowBatchSearchParams) {
return request<Api.WorkflowBatch.WorkflowBatchList>({
url: '/workflow/batch/page/list',
method: 'get',
params
});
}

35
src/typings/api.d.ts vendored
View File

@ -874,4 +874,39 @@ declare namespace Api {
/** JobTask list */ /** JobTask list */
type JobTaskList = Common.PaginatingQueryRecord<JobTask>; type JobTaskList = Common.PaginatingQueryRecord<JobTask>;
} }
/**
* namespace WorkflowBatch
*
* backend api module: "workflowBatch"
*/
namespace WorkflowBatch {
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'page' | 'size'>;
/** workflowBatch */
type WorkflowBatch = Common.CommonRecord<{
/** 工作流名称 */
workflowName: string;
/** 工作流ID */
workflowId?: number;
/** 组名称 */
groupName: string;
/** 执行时间 */
executionAt: string;
/** 状态 */
taskBatchStatus: string;
/** 操作原因 */
operationReason: string;
/** 创建时间 */
createDt: string;
}>;
/** workflowBatch search params */
type WorkflowBatchSearchParams = CommonType.RecordNullable<
Pick<Api.WorkflowBatch.WorkflowBatch, 'workflowId' | 'groupName' | 'taskBatchStatus'> & CommonSearchParams
>;
/** workflowBatch list */
type WorkflowBatchList = Common.PaginatingQueryRecord<WorkflowBatch>;
}
} }

18
src/typings/app.d.ts vendored
View File

@ -884,6 +884,22 @@ declare namespace App {
addWorkflow: string; addWorkflow: string;
editWorkflow: string; editWorkflow: string;
}; };
workflowBatch: {
title: string;
workflowName: string;
groupName: string;
executionAt: string;
taskBatchStatus: string;
operationReason: string;
createDt: string;
form: {
workflowName: string;
taskBatchStatus: string;
groupName: string;
};
addWorkflowBatch: string;
editWorkflowBatch: string;
};
jobTask: { jobTask: {
title: string; title: string;
groupName: string; groupName: string;
@ -951,7 +967,7 @@ declare namespace App {
expand: string; expand: string;
pin: string; pin: string;
unpin: string; unpin: string;
namepase: string; namespace: string;
}; };
}; };

View File

@ -51,7 +51,7 @@ declare module "@elegant-router/types" {
"multi-menu_second": "/multi-menu/second"; "multi-menu_second": "/multi-menu/second";
"multi-menu_second_child": "/multi-menu/second/child"; "multi-menu_second_child": "/multi-menu/second/child";
"multi-menu_second_child_home": "/multi-menu/second/child/home"; "multi-menu_second_child_home": "/multi-menu/second/child/home";
"namepase": "/namepase"; "namespace": "/namespace";
"notify": "/notify"; "notify": "/notify";
"notify_recipient": "/notify/recipient"; "notify_recipient": "/notify/recipient";
"notify_scene": "/notify/scene"; "notify_scene": "/notify/scene";
@ -61,6 +61,8 @@ declare module "@elegant-router/types" {
"retry_task": "/retry/task"; "retry_task": "/retry/task";
"user-center": "/user-center"; "user-center": "/user-center";
"workflow": "/workflow"; "workflow": "/workflow";
"workflow_batch": "/workflow/batch";
"workflow_task": "/workflow/task";
}; };
/** /**
@ -107,7 +109,7 @@ declare module "@elegant-router/types" {
| "login" | "login"
| "manage" | "manage"
| "multi-menu" | "multi-menu"
| "namepase" | "namespace"
| "notify" | "notify"
| "pods" | "pods"
| "retry" | "retry"
@ -152,14 +154,15 @@ declare module "@elegant-router/types" {
| "manage_user" | "manage_user"
| "multi-menu_first_child" | "multi-menu_first_child"
| "multi-menu_second_child_home" | "multi-menu_second_child_home"
| "namepase" | "namespace"
| "notify_recipient" | "notify_recipient"
| "notify_scene" | "notify_scene"
| "pods" | "pods"
| "retry_scene" | "retry_scene"
| "retry_task" | "retry_task"
| "user-center" | "user-center"
| "workflow" | "workflow_batch"
| "workflow_task"
>; >;
/** /**

View File

@ -0,0 +1,169 @@
<script setup lang="tsx">
import { NButton, NPopconfirm } from 'naive-ui';
import { fetchGetWorkflowBatchList } from '@/service/api';
import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app';
import { useTable, useTableOperate } from '@/hooks/common/table';
import WorkflowBatchSearch from './modules/workflow-batch-search.vue';
const appStore = useAppStore();
const { columns, columnChecks, data, getData, loading, mobilePagination, searchParams, resetSearchParams } = useTable({
apiFn: fetchGetWorkflowBatchList,
apiParams: {
page: 1,
size: 10,
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
// the value can not be undefined, otherwise the property in Form will not be reactive
workflowId: null,
groupName: null,
taskBatchStatus: null
},
columns: () => [
{
type: 'selection',
align: 'center',
width: 48
},
{
key: 'index',
title: $t('common.index'),
align: 'center',
width: 64
},
{
key: 'workflowName',
title: $t('page.workflowBatch.workflowName'),
align: 'left',
minWidth: 120
},
{
key: 'groupName',
title: $t('page.workflowBatch.groupName'),
align: 'left',
minWidth: 120
},
{
key: 'executionAt',
title: $t('page.workflowBatch.executionAt'),
align: 'left',
minWidth: 120
},
{
key: 'taskBatchStatus',
title: $t('page.workflowBatch.taskBatchStatus'),
align: 'left',
minWidth: 120
},
{
key: 'operationReason',
title: $t('page.workflowBatch.operationReason'),
align: 'left',
minWidth: 120
},
{
key: 'createDt',
title: $t('page.workflowBatch.createDt'),
align: 'left',
minWidth: 120
},
{
key: 'operate',
title: $t('common.operate'),
align: 'center',
width: 130,
render: row => (
<div class="flex-center gap-8px">
<NButton type="primary" ghost size="small" onClick={() => edit(row.id!)}>
{$t('common.edit')}
</NButton>
<NPopconfirm onPositiveClick={() => handleDelete(row.id!)}>
{{
default: () => $t('common.confirmDelete'),
trigger: () => (
<NButton type="error" ghost size="small">
{$t('common.delete')}
</NButton>
)
}}
</NPopconfirm>
</div>
)
}
]
});
const {
drawerVisible,
operateType,
editingData,
handleAdd,
handleEdit,
checkedRowKeys,
onBatchDeleted,
onDeleted
// closeDrawer
} = useTableOperate(data, getData);
async function handleBatchDelete() {
// request
console.log(checkedRowKeys.value);
onBatchDeleted();
}
function handleDelete(id: string) {
// request
console.log(id);
onDeleted();
}
function edit(id: string) {
handleEdit(id);
}
</script>
<template>
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
<WorkflowBatchSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getData" />
<NCard
:title="$t('page.workflowBatch.title')"
:bordered="false"
size="small"
class="sm:flex-1-hidden card-wrapper"
header-class="view-card-header"
>
<template #header-extra>
<TableHeaderOperation
v-model:columns="columnChecks"
:disabled-delete="checkedRowKeys.length === 0"
:loading="loading"
@add="handleAdd"
@delete="handleBatchDelete"
@refresh="getData"
/>
</template>
<NDataTable
v-model:checked-row-keys="checkedRowKeys"
:columns="columns"
:data="data"
:flex-height="!appStore.isMobile"
:scroll-x="962"
:loading="loading"
remote
:row-key="row => row.id"
:pagination="mobilePagination"
class="sm:h-full"
/>
<WorkflowBatchOperateDrawer
v-model:visible="drawerVisible"
:operate-type="operateType"
:row-data="editingData"
@submitted="getData"
/>
</NCard>
</div>
</template>
<style scoped></style>

View File

@ -0,0 +1,59 @@
<script setup lang="ts">
import { ref } from 'vue';
import { $t } from '@/locales';
import SelectGroup from '@/components/common/select-group.vue';
import { fetchGetWorkflowNameList } from '@/service/api';
defineOptions({
name: 'WorkflowBatchSearch'
});
interface Emits {
(e: 'reset'): void;
(e: 'search'): void;
}
const emit = defineEmits<Emits>();
/** 组列表 */
const workflowList = ref<Api.Workflow.Workflow[]>([]);
const model = defineModel<Api.WorkflowBatch.WorkflowBatchSearchParams>('model', { required: true });
function reset() {
emit('reset');
}
function search() {
emit('search');
}
async function groupNameUpdate(groupName: string) {
const res = await fetchGetWorkflowNameList({ groupName });
workflowList.value = res.data as Api.Workflow.Workflow[];
}
</script>
<template>
<SearchForm :model="model" @search="search" @reset="reset">
<NFormItemGi span="24 s:12 m:6" :label="$t('page.workflowBatch.groupName')" path="userName" class="pr-24px">
<SelectGroup v-model:value="model.groupName" @update:value="groupNameUpdate" />
</NFormItemGi>
<NFormItemGi span="24 s:12 m:6" :label="$t('page.workflowBatch.workflowName')" path="userName" class="pr-24px">
<NSelect
v-model:value="model.workflowId"
:placeholder="$t('page.workflowBatch.form.workflowName')"
value-field="id"
label-field="workflowName"
:options="workflowList"
clearable
filterable
/>
</NFormItemGi>
<NFormItemGi span="24 s:12 m:6" :label="$t('page.workflowBatch.taskBatchStatus')" path="userName" class="pr-24px">
<NInput v-model:value="model.taskBatchStatus" :placeholder="$t('page.workflowBatch.form.taskBatchStatus')" />
</NFormItemGi>
</SearchForm>
</template>
<style scoped></style>