feat(sj_1.1.0-beta3): 命名空间与组管理新增删除功能

This commit is contained in:
xlsea 2024-07-09 09:55:26 +08:00
parent e54bb8c534
commit 66496636e8
10 changed files with 150 additions and 113 deletions

View File

@ -4,9 +4,9 @@ import { NButton, NCode, NTag } from 'naive-ui';
import hljs from 'highlight.js/lib/core';
import json from 'highlight.js/lib/languages/json';
import { ref, render } from 'vue';
import { taskStatusRecord } from '@/constants/business';
import { taskStatusRecord, taskStatusRecordOptions } from '@/constants/business';
import { $t } from '@/locales';
import { parseArgsJson } from '@/utils/common';
import { parseArgsJson, translateOptions } from '@/utils/common';
import { useTable } from '@/hooks/common/table';
import { fetchGetJobTaskList, fetchGetJobTaskTree } from '@/service/api';
@ -19,11 +19,15 @@ hljs.registerLanguage('json', json);
interface Props {
/** row data */
rowData?: Api.JobBatch.JobBatch | null;
isRetry?: boolean;
}
const props = defineProps<Props>();
const props = withDefaults(defineProps<Props>(), {
rowData: null
});
interface Emits {
(e: 'retry'): void;
(e: 'showLog', rowData: Api.Job.JobTask): void;
}
@ -33,7 +37,7 @@ const expandedRowKeys = ref<DataTableRowKey[]>([]);
const argsDomMap = ref<Map<string, boolean>>(new Map());
const { columns, columnChecks, data, loading, mobilePagination } = useTable({
const { columns, searchParams, columnChecks, data, getData, loading, mobilePagination } = useTable({
apiFn: fetchGetJobTaskList,
apiParams: {
page: 1,
@ -41,7 +45,8 @@ const { columns, columnChecks, data, loading, mobilePagination } = useTable({
groupName: props.rowData?.groupName,
taskBatchId: props.rowData?.id,
startId: 0,
fromIndex: 0
fromIndex: 0,
taskStatus: undefined
// 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
},
@ -217,6 +222,21 @@ const onUpdatePage = (_: number) => {
expandedRowKeys.value = [];
};
async function flushed() {
searchParams.taskStatus = undefined;
await getData();
}
const retry = async () => {
emit('retry');
};
const isRetry = () => {
return (
props.rowData?.taskBatchStatus === 4 || props.rowData?.taskBatchStatus === 5 || props.rowData?.taskBatchStatus === 6
);
};
const init = () => {
columnChecks.value = columnChecks.value.filter(column => {
if (!['4', '5'].includes(String(props.rowData?.taskType) || '-1')) {
@ -231,24 +251,56 @@ init();
</script>
<template>
<NDataTable
:columns="columns"
:data="data"
:loading="loading"
remote
:scroll-x="1000"
:row-key="row => row.id"
:pagination="mobilePagination"
:indent="16"
:cascade="false"
allow-checking-not-loaded
:expanded-row-keys="expandedRowKeys"
class="sm:h-full"
:row-props="row => ({ id: `job-task-${row.id}` })"
@update:expanded-row-keys="onExpandedRowKeys"
@update:page="onUpdatePage"
@load="onLoad"
/>
<NCard
:bordered="false"
size="small"
class="sm:flex-1-hidden card-wrapper pt-16px"
:content-style="{ padding: 0 }"
:header-style="{ padding: 0 }"
>
<template #header>
<NSelect
v-model:value="searchParams.taskStatus"
clearable
class="max-w-180px"
:options="translateOptions(taskStatusRecordOptions)"
placeholder="请选择状态"
@update:value="getData"
/>
</template>
<template #header-extra>
<NButton class="mr-16px" @click="flushed">
<template #icon>
<icon-ant-design:sync-outlined class="text-icon" />
</template>
刷新
</NButton>
<NButton v-if="isRetry()" @click="retry">
<template #icon>
<icon-ant-design:redo-outlined class="text-icon" />
</template>
重试
</NButton>
</template>
<NDataTable
:columns="columns"
:data="data"
:loading="loading"
remote
:scroll-x="1000"
:row-key="row => row.id"
:pagination="mobilePagination"
:indent="16"
:cascade="false"
allow-checking-not-loaded
:expanded-row-keys="expandedRowKeys"
class="mt-16px sm:h-full"
:row-props="row => ({ id: `job-task-${row.id}` })"
@update:expanded-row-keys="onExpandedRowKeys"
@update:page="onUpdatePage"
@load="onLoad"
/>
</NCard>
</template>
<style scoped></style>

View File

@ -1,19 +1,13 @@
<script setup lang="tsx">
import { nextTick, ref, useSlots, watch } from 'vue';
import { NButton, NTag } from 'naive-ui';
import { NTag } from 'naive-ui';
import hljs from 'highlight.js/lib/core';
import json from 'highlight.js/lib/languages/json';
import { isNotNull, translateOptions } from '@/utils/common';
import {
jobExecutorEnum,
jobOperationReasonEnum,
jobStatusEnum,
taskBatchStatusEnum,
taskStatusRecordOptions
} from '@/constants/business';
import { isNotNull } from '@/utils/common';
import { jobExecutorEnum, jobOperationReasonEnum, jobStatusEnum, taskBatchStatusEnum } from '@/constants/business';
import { useWorkflowStore } from '@/store/modules/workflow';
import { $t } from '@/locales';
import { fetchGetJobBatchDetail, fetchGetJobDetail, fetchGetJobTaskList, fetchWorkflowNodeRetry } from '@/service/api';
import { fetchGetJobBatchDetail, fetchGetJobDetail, fetchWorkflowNodeRetry } from '@/service/api';
defineOptions({
name: 'DetailCard'
@ -45,11 +39,8 @@ const store = useWorkflowStore();
const visible = ref(false);
const logOpen = ref(false);
const spinning = ref(false);
const loading = ref(false);
const currentIndex = ref(1);
const taskStatusSearch = ref();
const jobData = ref<Workflow.JobTaskType>({});
const dataSource = ref<Workflow.JobBatchType[]>([]);
const pagination = ref({
page: 1,
@ -61,13 +52,11 @@ const pagination = ref({
pagination.value.page = page;
const id = props.ids[currentIndex.value - 1];
getBatchDetail(id);
getRows(id, page);
},
onUpdatePageSize: async (pageSize: number) => {
pagination.value.pageSize = pageSize;
const id = props.ids[currentIndex.value - 1];
getBatchDetail(id);
getRows(id, pagination.value.page);
}
});
@ -104,27 +93,6 @@ async function getBatchDetail(id: string) {
}
}
async function getRows(id: string, page: number = 1) {
loading.value = true;
const { data, error } = await fetchGetJobTaskList({
groupName: store.groupName!,
taskBatchId: id ?? '0',
taskStatus: taskStatusSearch.value,
page,
size: pagination.value.pageSize
});
if (!error) {
pagination.value.pageCount = data.total;
dataSource.value = data.data;
loading.value = false;
}
}
async function flushed(id: string) {
taskStatusSearch.value = null;
await getRows(id);
}
const idList = ref<string[]>([]);
function onLoad() {
@ -133,11 +101,9 @@ function onLoad() {
nextTick(() => {
if (props.ids.length > 0) {
getBatchDetail(props.ids[0]);
getRows(props.ids[0]);
} else if (props.id) {
idList.value = [jobData.value.taskBatchId!];
getDetail(props.id);
getRows(jobData.value.taskBatchId!);
}
});
}
@ -149,17 +115,13 @@ const getLogRows = (task: Workflow.JobTaskType) => {
logOpen.value = true;
};
const retry = async (item: Workflow.JobTaskType) => {
const { error } = await fetchWorkflowNodeRetry(store.id!, item.workflowNodeId!);
const retry = async () => {
const { error } = await fetchWorkflowNodeRetry(store.id!, jobData.value.workflowNodeId!);
if (!error) {
window.$message?.success('执行重试成功');
}
};
const isRetry = (taskBatchStatus: number) => {
return taskBatchStatus === 4 || taskBatchStatus === 5 || taskBatchStatus === 6;
};
function getTagColor(color: string) {
return {
color: `${color}18`,
@ -172,7 +134,6 @@ const onUpdatePage = (page: number) => {
currentIndex.value = page;
const id = props.ids[page - 1];
getBatchDetail(id);
getRows(id, page);
};
</script>
@ -240,39 +201,7 @@ const onUpdatePage = (page: number) => {
<template #tab>
<span>任务项列表</span>
</template>
<NCard
:bordered="false"
size="small"
class="sm:flex-1-hidden card-wrapper pt-16px"
:content-style="{ padding: 0 }"
:header-style="{ padding: 0 }"
>
<template #header>
<NSelect
v-model:value="taskStatusSearch"
clearable
class="max-w-180px"
:options="translateOptions(taskStatusRecordOptions)"
placeholder="请选择状态"
@update:value="getRows(item)"
/>
</template>
<template #header-extra>
<NButton class="mr-16px" @click="flushed(item)">
<template #icon>
<icon-ant-design:sync-outlined class="text-icon" />
</template>
刷新
</NButton>
<NButton v-if="isRetry(jobData.taskBatchStatus!)" @click="retry(jobData)">
<template #icon>
<icon-ant-design:redo-outlined class="text-icon" />
</template>
重试
</NButton>
</template>
<JobTaskListTable class="mt-16px" :row-data="jobData as any" @show-log="getLogRows" />
</NCard>
<JobTaskListTable :row-data="jobData as any" @show-log="getLogRows" @retry="retry" />
</NTabPane>
</NTabs>
</NTabPane>

View File

@ -59,3 +59,11 @@ export function fetchGetAllGroupConfigList(data: string[]) {
data
});
}
/** delete Group by id */
export function fetchDeleteGroup(id: string) {
return request<boolean>({
url: `/group/${id}`,
method: 'delete'
});
}

View File

@ -26,3 +26,11 @@ export function fetchEditNamespace(data: Api.Namespace.Namespace) {
data
});
}
/** delete namespace by id */
export function fetchDeleteNamespace(id: string) {
return request<boolean>({
url: `/namespace/${id}`,
method: 'delete'
});
}

View File

@ -60,7 +60,7 @@ export function fetchStopWorkflowBatch(id: string) {
export function fetchWorkflowNodeRetry(id: string, workflowNodeId: string) {
return request<null>({
url: `/workflow/node/retry/${workflowNodeId}/${id}`,
method: 'get'
method: 'post'
});
}

View File

@ -59,7 +59,7 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
const { setWatermark, clearWatermark } = useWatermark({ id: 'global_watermark_id' });
/** 开启水印 */
function toggleWatermark(visible: boolean) {
function toggleWatermark(visible: boolean = false) {
visible ? setWatermark(settings.value.watermark.text) : clearWatermark();
}

View File

@ -2,7 +2,7 @@
import { NButton, NPopconfirm, NTag } from 'naive-ui';
import { ref } from 'vue';
import { useBoolean } from '@sa/hooks';
import { fetchGetGroupConfigList, fetchUpdateGroupStatus } from '@/service/api';
import { fetchDeleteGroup, fetchGetGroupConfigList, fetchUpdateGroupStatus } from '@/service/api';
import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app';
import { useTable, useTableOperate } from '@/hooks/common/table';
@ -142,6 +142,17 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
<NButton type="primary" text ghost size="small" onClick={() => edit(row.id!)}>
{$t('common.edit')}
</NButton>
<n-divider vertical />
<NPopconfirm onPositiveClick={() => handleDelete(row.id!)}>
{{
default: () => $t('common.confirmDelete'),
trigger: () => (
<NButton type="error" text ghost size="small">
{$t('common.delete')}
</NButton>
)
}}
</NPopconfirm>
</div>
);
}
@ -155,7 +166,8 @@ const {
editingData,
handleAdd,
handleEdit,
checkedRowKeys
checkedRowKeys,
onDeleted
// closeDrawer
} = useTableOperate(data, getData);
@ -163,6 +175,12 @@ function edit(id: string) {
handleEdit(id);
}
async function handleDelete(id: string) {
const { error } = await fetchDeleteGroup(id);
if (error) return;
onDeleted();
}
function body(): Api.GroupConfig.ExportGroupConfig {
return {
groupName: searchParams.groupName,

View File

@ -36,7 +36,7 @@ async function openLog(row: Api.Job.JobTask) {
<DetailDrawer v-model="visible" :title="$t('page.jobBatch.detail')" :width="['50%', '90%']">
<NTabs type="segment" animated :default-value="log ? 1 : 0">
<NTabPane :name="0" :tab="$t('page.log.info')">
<NDescriptions label-placement="top" bordered :column="2">
<NDescriptions class="pt-16px" label-placement="top" bordered :column="2">
<NDescriptionsItem :label="$t('page.jobBatch.groupName')">{{ rowData?.groupName }}</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.jobBatch.jobName')">{{ rowData?.jobName }}</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.jobBatch.taskBatchStatus')">
@ -69,4 +69,8 @@ async function openLog(row: Api.Job.JobTask) {
<LogDrawer v-model:show="logShow" :title="$t('page.log.title')" :task-data="taskData" />
</template>
<style scoped></style>
<style scoped>
:deep(.n-tab-pane) {
padding-top: 0 !important;
}
</style>

View File

@ -26,7 +26,7 @@ const visible = defineModel<boolean>('visible', {
</script>
<template>
<OperateDrawer v-model="visible" :title="$t('page.jobTask.detail')">
<DetailDrawer v-model="visible" :title="$t('page.jobTask.detail')" :width="['50%', '90%']">
<NDescriptions label-placement="top" bordered :column="2">
<NDescriptionsItem :label="$t('page.jobTask.groupName')">{{ rowData?.groupName }}</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.jobTask.jobName')">{{ rowData?.jobName }}</NDescriptionsItem>
@ -74,7 +74,7 @@ const visible = defineModel<boolean>('visible', {
{{ rowData?.description }}
</NDescriptionsItem>
</NDescriptions>
</OperateDrawer>
</DetailDrawer>
</template>
<style scoped></style>

View File

@ -1,7 +1,7 @@
<script setup lang="tsx">
import { NButton } from 'naive-ui';
import { NButton, NPopconfirm } from 'naive-ui';
import { ref } from 'vue';
import { fetchGetNamespaceList } from '@/service/api';
import { fetchDeleteNamespace, fetchGetNamespaceList } from '@/service/api';
import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app';
import { useTable, useTableOperate } from '@/hooks/common/table';
@ -77,7 +77,7 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
key: 'operate',
title: $t('common.operate'),
align: 'center',
width: 64,
width: 80,
render: row => (
<div class="flex-center gap-8px">
<NButton type="primary" text ghost size="small" onClick={() => edit(row.id!)}>
@ -89,6 +89,17 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
<NButton type="warning" text ghost size="small" onClick={() => handleChange(row.uniqueId!)}>
{$t('common.switch')}
</NButton>
<n-divider vertical />
<NPopconfirm onPositiveClick={() => handleDelete(row.id!)}>
{{
default: () => $t('common.confirmDelete'),
trigger: () => (
<NButton type="error" text ghost size="small">
{$t('common.delete')}
</NButton>
)
}}
</NPopconfirm>
</>
) : (
''
@ -105,13 +116,20 @@ const {
editingData,
handleAdd,
handleEdit,
checkedRowKeys
checkedRowKeys,
onDeleted
// closeDrawer
} = useTableOperate(data, getData);
function edit(id: string) {
handleEdit(id);
}
async function handleDelete(id: string) {
const { error } = await fetchDeleteNamespace(id);
if (error) return;
onDeleted();
}
</script>
<template>