feat(任务中心): 任务中心静态页面
This commit is contained in:
parent
5a35423d4f
commit
97ae904911
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<MsDrawer
|
||||
v-model:visible="visible"
|
||||
:title="t('settings.navbar.task')"
|
||||
width="100%"
|
||||
class="ms-task-center-drawer"
|
||||
:footer="false"
|
||||
>
|
||||
<TaskCenter type="project" />
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import TaskCenter from '@/views/taskCenter/index.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const visible = defineModel<boolean>('visible', { required: true });
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ms-task-center-drawer {
|
||||
.arco-drawer-body {
|
||||
padding-top: 0;
|
||||
:deep(.arco-tabs-tab) {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -82,7 +82,6 @@
|
|||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
|
||||
import {
|
||||
type AuthScopeType,
|
||||
AuthTableItem,
|
||||
CurrentUserGroupItem,
|
||||
SavePermissions,
|
||||
|
@ -131,18 +130,6 @@
|
|||
|
||||
const loading = ref(false);
|
||||
|
||||
const systemSpan = ref(1);
|
||||
const projectSpan = ref(1);
|
||||
const organizationSpan = ref(1);
|
||||
const workstationSpan = ref(1);
|
||||
const testPlanSpan = ref(1);
|
||||
const bugManagementSpan = ref(1);
|
||||
const caseManagementSpan = ref(1);
|
||||
const uiTestSpan = ref(1);
|
||||
const apiTestSpan = ref(1);
|
||||
const loadTestSpan = ref(1);
|
||||
const personalSpan = ref(1);
|
||||
|
||||
// 表格的总全选
|
||||
const allChecked = ref(false);
|
||||
const allIndeterminate = ref(false);
|
||||
|
@ -171,62 +158,10 @@
|
|||
}) => {
|
||||
const { record, column } = data;
|
||||
if ((column as TableColumnData).dataIndex === 'ability') {
|
||||
if (record.isSystem) {
|
||||
return {
|
||||
rowspan: systemSpan.value,
|
||||
rowspan: record.rowSpan,
|
||||
};
|
||||
}
|
||||
if (record.isOrganization) {
|
||||
return {
|
||||
rowspan: organizationSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isProject) {
|
||||
return {
|
||||
rowspan: projectSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isWorkstation) {
|
||||
return {
|
||||
rowspan: workstationSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isTestPlan) {
|
||||
return {
|
||||
rowspan: testPlanSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isBugManagement) {
|
||||
return {
|
||||
rowspan: bugManagementSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isCaseManagement) {
|
||||
return {
|
||||
rowspan: caseManagementSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isUiTest) {
|
||||
return {
|
||||
rowspan: uiTestSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isApiTest) {
|
||||
return {
|
||||
rowspan: apiTestSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isLoadTest) {
|
||||
return {
|
||||
rowspan: loadTestSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isPersonal) {
|
||||
return {
|
||||
rowspan: personalSpan.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -236,7 +171,7 @@
|
|||
* @param item
|
||||
* @param type
|
||||
*/
|
||||
const makeData = (item: UserGroupAuthSetting, type: AuthScopeType) => {
|
||||
const makeData = (item: UserGroupAuthSetting) => {
|
||||
const result: AuthTableItem[] = [];
|
||||
item.children?.forEach((child, index) => {
|
||||
if (!child.license || (child.license && licenseStore.hasLicense())) {
|
||||
|
@ -261,17 +196,7 @@
|
|||
perChecked,
|
||||
ability: index === 0 ? item.name : undefined,
|
||||
operationObject: t(child.name),
|
||||
isSystem: index === 0 && type === 'SYSTEM',
|
||||
isOrganization: index === 0 && type === 'ORGANIZATION',
|
||||
isProject: index === 0 && type === 'PROJECT',
|
||||
isWorkstation: index === 0 && type === 'WORKSTATION',
|
||||
isTestPlan: index === 0 && type === 'TEST_PLAN',
|
||||
isBugManagement: index === 0 && type === 'BUG_MANAGEMENT',
|
||||
isCaseManagement: index === 0 && type === 'CASE_MANAGEMENT',
|
||||
isUiTest: index === 0 && type === 'UI_TEST',
|
||||
isLoadTest: index === 0 && type === 'LOAD_TEST',
|
||||
isApiTest: index === 0 && type === 'API_TEST',
|
||||
isPersonal: index === 0 && type === 'PERSONAL',
|
||||
rowSpan: index === 0 ? item.children?.length || 1 : undefined,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -281,30 +206,7 @@
|
|||
const transformData = (data: UserGroupAuthSetting[]) => {
|
||||
const result: AuthTableItem[] = [];
|
||||
data.forEach((item) => {
|
||||
if (item.id === 'SYSTEM') {
|
||||
systemSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'PROJECT') {
|
||||
projectSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'ORGANIZATION') {
|
||||
organizationSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'WORKSTATION') {
|
||||
workstationSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'TEST_PLAN') {
|
||||
testPlanSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'BUG_MANAGEMENT') {
|
||||
bugManagementSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'CASE_MANAGEMENT') {
|
||||
caseManagementSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'UI_TEST') {
|
||||
uiTestSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'API_TEST') {
|
||||
apiTestSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'LOAD_TEST') {
|
||||
loadTestSpan.value = item.children?.length || 0;
|
||||
} else if (item.id === 'PERSONAL') {
|
||||
personalSpan.value = item.children?.length || 0;
|
||||
}
|
||||
result.push(...makeData(item, item.id));
|
||||
result.push(...makeData(item));
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
v-for="(item, index) of props.descriptions"
|
||||
:key="item.label"
|
||||
class="ms-description-item"
|
||||
:style="{ marginBottom: props.descriptions.length - index <= props.column ? '' : '16px' }"
|
||||
:class="item.class"
|
||||
:style="{ marginBottom: props.descriptions.length - index <= props.column ? '' : `${props.lineGap}px` }"
|
||||
>
|
||||
<a-tooltip :content="item.label">
|
||||
<div :class="`ms-description-item-label one-line-text max-w-[${props.labelWidth || '120px'}]`">
|
||||
|
@ -153,6 +154,7 @@
|
|||
label: string;
|
||||
value: (string | number) | (string | number)[];
|
||||
key?: string;
|
||||
class?: string;
|
||||
isTag?: boolean; // 是否标签
|
||||
tagClass?: string; // 标签自定义类名
|
||||
tagType?: TagType; // 标签类型
|
||||
|
@ -188,10 +190,12 @@
|
|||
descriptions: Description[];
|
||||
labelWidth?: string;
|
||||
oneLineValue?: boolean;
|
||||
lineGap?: number;
|
||||
addTagFunc?: (val: string, item: Description) => Promise<void>;
|
||||
}>(),
|
||||
{
|
||||
column: 1,
|
||||
lineGap: 16,
|
||||
}
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
|
|
|
@ -167,7 +167,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<TaskCenterModal v-model:visible="taskCenterVisible" />
|
||||
<TaskCenterDrawer v-model:visible="taskCenterVisible" />
|
||||
<MessageCenterDrawer v-model:visible="messageCenterVisible" />
|
||||
<AddProjectModal :visible="projectVisible" @cancel="projectVisible = false" />
|
||||
</template>
|
||||
|
@ -180,13 +180,13 @@
|
|||
|
||||
import MessageBox from '@/components/pure/message-box/index.vue';
|
||||
import MessageCenterDrawer from '@/components/business/ms-message/MessageCenterDrawer.vue';
|
||||
import TaskCenterDrawer from '@/components/business/ms-task-center-drawer/index.vue';
|
||||
import TopMenu from '@/components/business/ms-top-menu/index.vue';
|
||||
import TaskCenterModal from './taskCenterModal.vue';
|
||||
import AddProjectModal from '@/views/setting/organization/project/components/addProjectModal.vue';
|
||||
|
||||
import { getMessageUnReadCount } from '@/api/modules/message';
|
||||
import { switchProject } from '@/api/modules/project-management/project';
|
||||
import { updateBaseInfo, updateLanguage } from '@/api/modules/user';
|
||||
import { updateLanguage } from '@/api/modules/user';
|
||||
import { MENU_LEVEL, type PathMapRoute } from '@/config/pathMap';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import usePathMap from '@/hooks/usePathMap';
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
<template>
|
||||
<a-modal
|
||||
v-model:visible="innerVisible"
|
||||
class="ms-modal-no-padding"
|
||||
width="100%"
|
||||
title-align="start"
|
||||
unmount-on-close
|
||||
:footer="false"
|
||||
modal-class="modalSelf"
|
||||
:body-style="{
|
||||
'height': '100%',
|
||||
'max-height': 'none',
|
||||
}"
|
||||
:modal-style="{
|
||||
padding: '16px 16px 0',
|
||||
}"
|
||||
esc-to-close
|
||||
fullscreen
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title> {{ t('settings.navbar.task') }}</template>
|
||||
|
||||
<div class="divider h-full">
|
||||
<Suspense>
|
||||
<TaskCenter v-if="visible" group="project" mode="modal"></TaskCenter>
|
||||
</Suspense>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import TaskCenter from '@/views/project-management/taskCenter/component/taskCom.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
const innerVisible = useVModel(props, 'visible', emit);
|
||||
|
||||
function handleOk() {}
|
||||
function handleCancel() {
|
||||
innerVisible.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.divider {
|
||||
border-top: 1px solid var(--color-text-n8);
|
||||
}
|
||||
</style>
|
|
@ -331,95 +331,6 @@ export const pathMap: PathMapItem[] = [
|
|||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
children: [
|
||||
{
|
||||
key: 'SETTING_SYSTEM_TASK_CENTER_REAL_TIME', // 系统设置-系统-任务中心-实时任务
|
||||
locale: 'project.taskCenter.realTimeTask',
|
||||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
children: [
|
||||
{
|
||||
key: 'SETTING_SYSTEM_TASK_CENTER_REAL_TIME_API_CASE', // 系统设置-系统-任务中心-实时任务-接口用例
|
||||
locale: 'project.taskCenter.interfaceCase',
|
||||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
routeQuery: {
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.API_CASE,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'SETTING_SYSTEM_TASK_CENTER_REAL_TIME_API_SCENARIO', // 系统设置-系统-任务中心-实时任务-接口场景
|
||||
locale: 'project.taskCenter.apiScenario',
|
||||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
routeQuery: {
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.API_SCENARIO,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'SETTING_SYSTEM_TASK_CENTER_REAL_TIME_TEST_PLAN', // 系统设置-系统-任务中心-实时任务-测试计划
|
||||
locale: 'project.taskCenter.testPlan',
|
||||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
routeQuery: {
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.TEST_PLAN,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'SETTING_SYSTEM_TASK_CENTER_TIME', // 系统设置-系统-任务中心-定时任务
|
||||
locale: 'apiTestManagement.timeTask',
|
||||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
routeQuery: {
|
||||
tab: 'timing',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
key: 'SETTING_SYSTEM_TASK_CENTER_TIME_API_SCENARIO', // 系统设置-系统-任务中心-定时任务-接口场景
|
||||
locale: 'project.taskCenter.apiScenario',
|
||||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
routeQuery: {
|
||||
tab: 'timing',
|
||||
type: TaskCenterEnum.API_SCENARIO,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'SETTING_SYSTEM_TASK_CENTER_TIME_API_IMPORT', // 系统设置-系统-任务中心-定时任务-接口导入
|
||||
locale: 'project.taskCenter.apiImport',
|
||||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
routeQuery: {
|
||||
tab: 'timing',
|
||||
type: TaskCenterEnum.API_IMPORT,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'SETTING_SYSTEM_TASK_CENTER_TIME_TEST_PLAN', // 系统设置-系统-任务中心-定时任务-测试计划
|
||||
locale: 'project.taskCenter.testPlan',
|
||||
route: RouteEnum.SETTING_SYSTEM_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[0],
|
||||
routeQuery: {
|
||||
tab: 'timing',
|
||||
type: TaskCenterEnum.TEST_PLAN,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'SETTING_SYSTEM_PLUGIN_MANAGEMENT', // 系统设置-系统-插件管理
|
||||
|
@ -471,95 +382,6 @@ export const pathMap: PathMapItem[] = [
|
|||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
children: [
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TASK_CENTER_REAL_TIME', // 系统设置-组织-任务中心-实时任务
|
||||
locale: 'project.taskCenter.realTimeTask',
|
||||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
children: [
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TASK_CENTER_REAL_TIME_API_CASE', // 系统设置-组织-任务中心-实时任务-接口用例
|
||||
locale: 'project.taskCenter.interfaceCase',
|
||||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
routeQuery: {
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.API_CASE,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TASK_CENTER_REAL_TIME_API_SCENARIO', // 系统设置-组织-任务中心-实时任务-接口场景
|
||||
locale: 'project.taskCenter.apiScenario',
|
||||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
routeQuery: {
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.API_SCENARIO,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TASK_CENTER_REAL_TIME_TEST_PLAN', // 系统设置-组织-任务中心-实时任务-测试计划
|
||||
locale: 'project.taskCenter.testPlan',
|
||||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
routeQuery: {
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.TEST_PLAN,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TASK_CENTER_TIME', // 系统设置-组织-任务中心-定时任务
|
||||
locale: 'apiTestManagement.timeTask',
|
||||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
routeQuery: {
|
||||
tab: 'timeTask',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TASK_CENTER_TIME_API_SCENARIO', // 系统设置-组织-任务中心-定时任务-接口场景
|
||||
locale: 'project.taskCenter.apiScenario',
|
||||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
routeQuery: {
|
||||
tab: 'timeTask',
|
||||
type: TaskCenterEnum.API_SCENARIO,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TASK_CENTER_TIME_API_IMPORT', // 系统设置-组织-任务中心-定时任务-接口导入
|
||||
locale: 'project.taskCenter.apiImport',
|
||||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
routeQuery: {
|
||||
tab: 'timeTask',
|
||||
type: TaskCenterEnum.API_IMPORT,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TASK_CENTER_TIME_TEST_PLAN', // 系统设置-组织-任务中心-定时任务-测试计划
|
||||
locale: 'project.taskCenter.testPlan',
|
||||
route: RouteEnum.SETTING_ORGANIZATION_TASK_CENTER,
|
||||
permission: [],
|
||||
level: MENU_LEVEL[1],
|
||||
routeQuery: {
|
||||
tab: 'timeTask',
|
||||
type: TaskCenterEnum.TEST_PLAN,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'SETTING_ORGANIZATION_TEMPLATE', // 系统设置-组织-模板管理
|
||||
|
@ -925,98 +747,6 @@ export const pathMap: PathMapItem[] = [
|
|||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
children: [
|
||||
{
|
||||
key: 'PROJECT_MANAGEMENT_TASK_CENTER_REAL_TIME', // 项目管理-任务中心-实时任务
|
||||
locale: 'project.taskCenter.realTimeTask',
|
||||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
children: [
|
||||
{
|
||||
key: 'PROJECT_MANAGEMENT_TASK_CENTER_REAL_TIME_API_CASE', // 项目管理-任务中心-实时任务-接口用例
|
||||
locale: 'project.taskCenter.interfaceCase',
|
||||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
routeQuery: {
|
||||
task: true,
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.API_CASE,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'PROJECT_MANAGEMENT_TASK_CENTER_REAL_TIME_API_SCENARIO', // 项目管理-任务中心-实时任务-接口场景
|
||||
locale: 'project.taskCenter.apiScenario',
|
||||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
routeQuery: {
|
||||
task: true,
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.API_SCENARIO,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'PROJECT_MANAGEMENT_TASK_CENTER_REAL_TIME_TEST_PLAN', // 项目管理-任务中心-实时任务-接口场景
|
||||
locale: 'project.taskCenter.testPlan',
|
||||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
routeQuery: {
|
||||
task: true,
|
||||
tab: 'real',
|
||||
type: TaskCenterEnum.TEST_PLAN,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'PROJECT_MANAGEMENT_TASK_CENTER_TIME', // 项目管理-任务中心-定时任务
|
||||
locale: 'project.taskCenter.scheduledTask',
|
||||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
children: [
|
||||
{
|
||||
key: 'PROJECT_MANAGEMENT_TASK_CENTER_TIME_API_SCENARIO', // 项目管理-任务中心-定时任务-接口场景
|
||||
locale: 'project.taskCenter.apiScenario',
|
||||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
routeQuery: {
|
||||
task: true,
|
||||
tab: 'timing',
|
||||
type: TaskCenterEnum.API_SCENARIO,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'PROJECT_MANAGEMENT_TASK_CENTER_TIME_API_IMPORT', // 项目管理-任务中心-定时任务-接口导入
|
||||
locale: 'project.taskCenter.apiImport',
|
||||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
routeQuery: {
|
||||
task: true,
|
||||
tab: 'timing',
|
||||
type: TaskCenterEnum.API_IMPORT,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'PROJECT_MANAGEMENT_TASK_CENTER_TIME_TEST_PLAN', // 项目管理-任务中心-定时任务-测试计划
|
||||
locale: 'project.taskCenter.testPlan',
|
||||
route: '',
|
||||
permission: [],
|
||||
level: MENU_LEVEL[2],
|
||||
routeQuery: {
|
||||
task: true,
|
||||
tab: 'timing',
|
||||
type: TaskCenterEnum.TEST_PLAN,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
// 模板展示字段icon
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
export enum ReportEnum {
|
||||
API_SCENARIO_REPORT = 'API_SCENARIO_REPORT',
|
||||
API_REPORT = 'API_REPORT',
|
||||
|
|
|
@ -73,9 +73,9 @@ export enum TableKeyEnum {
|
|||
TEST_PLAN_DETAIL_API_CASE = 'testPlanDetailApiCase',
|
||||
TEST_PLAN_DETAIL_API_SCENARIO = 'testPlanDetailApiScenario',
|
||||
TEST_PLAN_REPORT_TABLE = 'testPlanReportTable',
|
||||
TASK_API_CASE_SYSTEM = 'taskCenterApiCaseSystem',
|
||||
TASK_API_CASE_ORGANIZATION = 'taskCenterApiCaseOrganization',
|
||||
TASK_API_CASE_PROJECT = 'taskCenterApiCaseProject',
|
||||
TASK_CENTER_CASE_TASK = 'taskCenterCaseTask',
|
||||
TASK_CENTER_CASE_TASK_DETAIL = 'taskCenterCaseTaskDetail',
|
||||
TASK_CENTER_SYSTEM_TASK = 'taskCenterSystemTask',
|
||||
TASK_SCHEDULE_TASK_API_IMPORT_SYSTEM = 'taskCenterScheduleApiImportSystem',
|
||||
TASK_SCHEDULE_TASK_API_SCENARIO_SYSTEM = 'taskCenterScheduleApiScenarioSystem',
|
||||
TASK_SCHEDULE_TASK_API_IMPORT_ORGANIZATION = 'taskCenterScheduleApiImportOrganization',
|
||||
|
|
|
@ -20,6 +20,8 @@ export enum FilterSlotNameEnum {
|
|||
API_TEST_REPORT_TYPE = 'API_TEST_REPORT_TYPE', // 接口测试-报告-报告类型
|
||||
API_TEST_CASE_API_REPORT_STATUS = 'API_TEST_CASE_API_REPORT_STATUS', // 接口测试-定义-用例列表-报告状态
|
||||
GLOBAL_TASK_CENTER_EXEC_STATUS = 'GLOBAL_TASK_CENTER_EXEC_STATUS', // 任务中心-执行状态
|
||||
GLOBAL_TASK_CENTER_EXEC_RESULT = 'GLOBAL_TASK_CENTER_EXEC_RESULT', // 任务中心-执行结果
|
||||
GLOBAL_TASK_CENTER_EXEC_METHOD = 'GLOBAL_TASK_CENTER_EXEC_METHOD', // 任务中心-执行方式
|
||||
}
|
||||
|
||||
export enum FilterRemoteMethodsEnum {
|
||||
|
|
|
@ -1,20 +1,10 @@
|
|||
// 模板展示字段icon
|
||||
// 任务中心 tab 枚举
|
||||
export enum TaskCenterEnum {
|
||||
API_CASE = 'API_CASE', // 接口用例
|
||||
API_SCENARIO = 'API_SCENARIO', // 接口场景 API场景
|
||||
UI_TEST = 'UI_TEST', // ui测试
|
||||
LOAD_TEST = 'LOAD_TEST', // 性能测试
|
||||
TEST_PLAN = 'TEST_PLAN', // 测试计划
|
||||
TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源
|
||||
API_IMPORT = 'API_IMPORT', // API导入
|
||||
CASE = 'CASE',
|
||||
DETAIL = 'DETAIL',
|
||||
BACKEND = 'BACKEND',
|
||||
API_IMPORT = 'API_IMPORT',
|
||||
}
|
||||
export type ResourceTypeMapKey =
|
||||
| TaskCenterEnum.API_CASE
|
||||
| TaskCenterEnum.API_SCENARIO
|
||||
| TaskCenterEnum.UI_TEST
|
||||
| TaskCenterEnum.LOAD_TEST
|
||||
| TaskCenterEnum.TEST_PLAN;
|
||||
|
||||
// 执行方式
|
||||
export enum ExecutionMethods {
|
||||
SCHEDULE = 'SCHEDULE', // 定时任务
|
||||
|
|
|
@ -14,6 +14,7 @@ export default {
|
|||
'common.end': 'End',
|
||||
'common.enable': 'Enable',
|
||||
'common.disable': 'Disable',
|
||||
'common.open': 'Open',
|
||||
'common.close': 'Close',
|
||||
'common.create': 'Create',
|
||||
'common.newCreate': 'Create',
|
||||
|
@ -142,6 +143,7 @@ export default {
|
|||
'common.stay': 'Stay',
|
||||
'common.apply': 'Apply',
|
||||
'common.stop': 'Stop',
|
||||
'common.stopConfirm': 'Confirm stop',
|
||||
'common.module': 'Module',
|
||||
'common.yes': 'Yes',
|
||||
'common.no': 'No',
|
||||
|
@ -191,9 +193,11 @@ export default {
|
|||
'common.updateUserName': 'Update user name',
|
||||
'common.updateTime': 'Update time',
|
||||
'common.belongProject': 'Belong to Project',
|
||||
'common.belongOrg': 'Belong to Organization',
|
||||
'common.noMatchData': 'No matching data',
|
||||
'common.name': 'name',
|
||||
'common.stopped': 'Stopped',
|
||||
'common.completed': 'Completed',
|
||||
'common.config': 'Config',
|
||||
'common.executionResult': 'Execution result',
|
||||
'common.expandAllSubModule': 'Expand all submodules',
|
||||
|
|
|
@ -14,6 +14,7 @@ export default {
|
|||
'common.end': '结束',
|
||||
'common.enable': '启用',
|
||||
'common.disable': '禁用',
|
||||
'common.open': '开启',
|
||||
'common.close': '关闭',
|
||||
'common.create': '创建',
|
||||
'common.newCreate': '新建',
|
||||
|
@ -142,6 +143,7 @@ export default {
|
|||
'common.stay': '留下',
|
||||
'common.apply': '应用',
|
||||
'common.stop': '停止',
|
||||
'common.stopConfirm': '确认停止',
|
||||
'common.module': '模块',
|
||||
'common.yes': '是',
|
||||
'common.no': '否',
|
||||
|
@ -192,9 +194,11 @@ export default {
|
|||
'common.updateUserName': '更新人',
|
||||
'common.updateTime': '更新时间',
|
||||
'common.belongProject': '所属项目',
|
||||
'common.belongOrg': '所属项目',
|
||||
'common.noMatchData': '暂无匹配数据',
|
||||
'common.name': '名称',
|
||||
'common.stopped': '已停止',
|
||||
'common.completed': '已完成',
|
||||
'common.config': '配置',
|
||||
'common.expandAllSubModule': '展开全部子模块',
|
||||
'common.collapseAllSubModule': '收起全部子模块',
|
||||
|
|
|
@ -112,17 +112,7 @@ export interface AuthTableItem {
|
|||
// 对应表格权限的复选框组的绑定值
|
||||
perChecked?: string[];
|
||||
operationObject?: string;
|
||||
isSystem?: boolean;
|
||||
isOrganization?: boolean;
|
||||
isProject?: boolean;
|
||||
isWorkstation?: boolean;
|
||||
isTestPlan?: boolean;
|
||||
isBugManagement?: boolean;
|
||||
isCaseManagement?: boolean;
|
||||
isApiTest?: boolean;
|
||||
isUiTest?: boolean;
|
||||
isLoadTest?: boolean;
|
||||
isPersonal?: boolean;
|
||||
rowSpan?: number;
|
||||
indeterminate?: boolean;
|
||||
}
|
||||
export interface SavePermissions {
|
||||
|
|
|
@ -22,7 +22,10 @@
|
|||
@change="loadControlLoop"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex w-full items-center justify-between rounded bg-[var(--color-text-n9)] px-[16px] py-[8px]">
|
||||
<div
|
||||
v-if="!props.hideResponseTime"
|
||||
class="flex w-full items-center justify-between rounded bg-[var(--color-text-n9)] px-[16px] py-[8px]"
|
||||
>
|
||||
<div class="font-medium">
|
||||
<span
|
||||
:class="{ 'text-[rgb(var(--primary-5))]': activeType === 'ResContent' }"
|
||||
|
@ -128,7 +131,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
|
@ -148,6 +150,7 @@
|
|||
|
||||
const props = defineProps<{
|
||||
mode: 'tiled' | 'tab'; // 平铺 | tab形式
|
||||
hideResponseTime?: boolean; // 是否隐藏响应时间栏
|
||||
stepItem?: ScenarioItemType; // 步骤详情
|
||||
console?: string;
|
||||
isPriorityLocalExec?: boolean;
|
||||
|
|
|
@ -155,7 +155,7 @@
|
|||
<div v-if="!step.fold" class="line"></div>
|
||||
</div>
|
||||
<!-- 折叠展开内容 -->
|
||||
<div v-if="showResContent(step)" class="foldContent mt-4 pl-2">
|
||||
<div v-if="showResContent(step)" class="foldContent mt-[18px] pl-2">
|
||||
<Suspense>
|
||||
<StepDetailContent
|
||||
:mode="props.activeType"
|
||||
|
@ -167,6 +167,7 @@
|
|||
:report-id="props?.reportId"
|
||||
:steps="steps"
|
||||
:get-report-step-detail="props.getReportStepDetail"
|
||||
hide-response-time
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
|
|
@ -177,7 +177,7 @@
|
|||
import dayjs from 'dayjs';
|
||||
|
||||
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||
import { FilterFormItem, FilterResult } from '@/components/pure/ms-advance-filter/type';
|
||||
import { FilterFormItem } from '@/components/pure/ms-advance-filter/type';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
|
|
|
@ -1,572 +0,0 @@
|
|||
<template>
|
||||
<div class="px-[16px]">
|
||||
<div class="mb-[16px] flex items-center justify-between">
|
||||
<div class="flex items-center"></div>
|
||||
<div class="items-right flex gap-[8px]">
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="t('system.organization.searchIndexPlaceholder')"
|
||||
allow-clear
|
||||
class="mx-[8px] w-[240px]"
|
||||
@search="searchList"
|
||||
@press-enter="searchList"
|
||||
@clear="searchList"
|
||||
></a-input-search>
|
||||
</div>
|
||||
</div>
|
||||
<ms-base-table
|
||||
v-bind="propsRes"
|
||||
ref="tableRef"
|
||||
:action-config="tableBatchActions"
|
||||
:selectable="hasOperationPermission"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #resourceNum="{ record }">
|
||||
<div
|
||||
v-if="!record.integrated"
|
||||
type="text"
|
||||
class="one-line-text w-full"
|
||||
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
|
||||
@click="showDetail(record)"
|
||||
>{{ record.resourceNum }}
|
||||
</div>
|
||||
</template>
|
||||
<template #resourceName="{ record }">
|
||||
<div
|
||||
v-if="!record.integrated"
|
||||
class="one-line-text max-w-[300px]"
|
||||
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
|
||||
@click="showDetail(record)"
|
||||
>{{ record.resourceName }}
|
||||
</div>
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.GLOBAL_TASK_CENTER_API_CASE_STATUS]="{ filterContent }">
|
||||
<ExecutionStatus :module-type="props.moduleType" :status="filterContent.value" />
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<ExecutionStatus
|
||||
:module-type="props.moduleType"
|
||||
:status="record.status"
|
||||
:script-identifier="record.scriptIdentifier"
|
||||
/>
|
||||
</template>
|
||||
<template #execStatus="{ record }">
|
||||
<ExecStatus :status="record.execStatus" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_STATUS]="{ filterContent }">
|
||||
<ExecStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #projectName="{ record }">
|
||||
<a-tooltip :content="`${record.projectName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.projectName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #organizationName="{ record }">
|
||||
<a-tooltip :content="`${record.organizationName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.organizationName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #triggerMode="{ record }">
|
||||
<span>{{ t(ExecutionMethodsLabel[record.triggerMode as keyof typeof ExecutionMethodsLabel]) }}</span>
|
||||
</template>
|
||||
<template #operationTime="{ record }">
|
||||
<span>{{ dayjs(record.operationTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</template>
|
||||
<template #operation="{ record, rowIndex }">
|
||||
<div v-if="record.historyDeleted">
|
||||
<a-tooltip :content="t('project.executionHistory.cleared')">
|
||||
<MsButton
|
||||
class="!mr-0"
|
||||
:disabled="
|
||||
record.historyDeleted || !hasAnyPermission(permissionsMap[props.group][props.moduleType].report)
|
||||
"
|
||||
@click="viewReport(record.id, rowIndex)"
|
||||
>{{ t('project.taskCenter.viewReport') }}
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div v-else>
|
||||
<MsButton
|
||||
class="!mr-0"
|
||||
:disabled="record.historyDeleted || !hasAnyPermission(permissionsMap[props.group][props.moduleType].report)"
|
||||
@click="viewReport(record.id, rowIndex)"
|
||||
>{{ t('project.taskCenter.viewReport') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
|
||||
<a-divider v-if="['RUNNING', 'RERUNNING'].includes(record.execStatus)" direction="vertical" />
|
||||
<MsButton
|
||||
v-if="
|
||||
['RUNNING', 'RERUNNING'].includes(record.execStatus) &&
|
||||
hasAnyPermission(permissionsMap[props.group][props.moduleType].stop)
|
||||
"
|
||||
class="!mr-0"
|
||||
@click="stop(record)"
|
||||
>{{ t('project.taskCenter.stop') }}
|
||||
</MsButton>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</div>
|
||||
<ReportDetailDrawer
|
||||
v-model:visible="showDetailDrawer"
|
||||
:report-id="activeDetailId"
|
||||
:active-report-index="activeReportIndex"
|
||||
:table-data="propsRes.data"
|
||||
:page-change="propsEvent.pageChange"
|
||||
:pagination="propsRes.msPagination!"
|
||||
/>
|
||||
<caseAndScenarioReportDrawer v-model:visible="showCaseDetailDrawer" :report-id="activeDetailId" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import ExecutionStatus from './executionStatus.vue';
|
||||
import caseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
|
||||
import ReportDetailDrawer from '@/views/api-test/report/component/reportDetailDrawer.vue';
|
||||
import ExecStatus from '@/views/test-plan/report/component/execStatus.vue';
|
||||
|
||||
import {
|
||||
batchStopRealOrdApi,
|
||||
batchStopRealProjectApi,
|
||||
batchStopRealSystemApi,
|
||||
getRealOrdApiCaseList,
|
||||
getRealProApiCaseList,
|
||||
getRealSysApiCaseList,
|
||||
stopRealOrdApi,
|
||||
stopRealProjectApi,
|
||||
stopRealSysApi,
|
||||
} from '@/api/modules/project-management/taskCenter';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import useOpenNewPage from '@/hooks/useOpenNewPage';
|
||||
import { useTableStore } from '@/store';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { BatchApiParams } from '@/models/common';
|
||||
import { ReportExecStatus } from '@/enums/apiEnum';
|
||||
import { RouteEnum } from '@/enums/routeEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
import { ExecutionMethodsLabel } from '@/enums/taskCenter';
|
||||
|
||||
import type { ExtractedKeys } from './utils';
|
||||
import { getOrgColumns, getProjectColumns, Group, TaskStatus } from './utils';
|
||||
|
||||
const { openNewPage } = useOpenNewPage();
|
||||
const tableStore = useTableStore();
|
||||
const { openModal } = useModal();
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
group: Group;
|
||||
moduleType: ExtractedKeys;
|
||||
name: string;
|
||||
}>();
|
||||
const keyword = ref<string>('');
|
||||
|
||||
const permissionsMap: Record<Group, any> = {
|
||||
organization: {
|
||||
API_CASE: {
|
||||
stop: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_API_DEFINITION_CASE:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_DEFINITION_CASE:READ'],
|
||||
report: ['PROJECT_API_DEFINITION_CASE:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
|
||||
},
|
||||
API_SCENARIO: {
|
||||
stop: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_API_SCENARIO:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_SCENARIO:READ'],
|
||||
report: ['PROJECT_API_SCENARIO:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
|
||||
},
|
||||
},
|
||||
system: {
|
||||
API_CASE: {
|
||||
stop: ['SYSTEM_TASK_CENTER:READ+STOP', 'PROJECT_API_DEFINITION_CASE:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_DEFINITION_CASE:READ'],
|
||||
report: ['PROJECT_API_DEFINITION_CASE:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
|
||||
},
|
||||
API_SCENARIO: {
|
||||
stop: ['SYSTEM_TASK_CENTER:READ+STOP', 'PROJECT_API_SCENARIO:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_SCENARIO:READ'],
|
||||
report: ['PROJECT_API_SCENARIO:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
|
||||
},
|
||||
},
|
||||
project: {
|
||||
API_CASE: {
|
||||
stop: ['PROJECT_API_DEFINITION_CASE:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_DEFINITION_CASE:READ'],
|
||||
report: ['PROJECT_API_DEFINITION_CASE:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
|
||||
},
|
||||
API_SCENARIO: {
|
||||
stop: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_SCENARIO:READ'],
|
||||
report: ['PROJECT_API_SCENARIO:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const loadRealMap = ref({
|
||||
system: {
|
||||
list: getRealSysApiCaseList,
|
||||
stop: stopRealSysApi,
|
||||
batchStop: batchStopRealSystemApi,
|
||||
},
|
||||
organization: {
|
||||
list: getRealOrdApiCaseList,
|
||||
stop: stopRealOrdApi,
|
||||
batchStop: batchStopRealOrdApi,
|
||||
},
|
||||
project: {
|
||||
list: getRealProApiCaseList,
|
||||
stop: stopRealProjectApi,
|
||||
batchStop: batchStopRealProjectApi,
|
||||
},
|
||||
});
|
||||
const hasJumpPermission = computed(() => hasAnyPermission(permissionsMap[props.group][props.moduleType].jump));
|
||||
const hasOperationPermission = computed(() => hasAnyPermission(permissionsMap[props.group][props.moduleType].stop));
|
||||
|
||||
const statusFilters = computed(() => {
|
||||
return Object.keys(TaskStatus[props.moduleType]).map((key: any) => {
|
||||
return {
|
||||
value: key,
|
||||
...TaskStatus[props.moduleType][key],
|
||||
};
|
||||
});
|
||||
});
|
||||
const ExecStatusList = computed(() => {
|
||||
return Object.values(ReportExecStatus).map((e) => {
|
||||
return {
|
||||
value: e,
|
||||
key: e,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const triggerModeList = [
|
||||
{
|
||||
value: 'SCHEDULE',
|
||||
label: t('project.taskCenter.scheduledTask'),
|
||||
},
|
||||
{
|
||||
value: 'MANUAL',
|
||||
label: t('project.taskCenter.manualExecution'),
|
||||
},
|
||||
{
|
||||
value: 'API',
|
||||
label: t('project.taskCenter.interfaceCall'),
|
||||
},
|
||||
{
|
||||
value: 'BATCH',
|
||||
label: t('project.taskCenter.batchExecution'),
|
||||
},
|
||||
];
|
||||
|
||||
const staticColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'project.taskCenter.resourceID',
|
||||
dataIndex: 'resourceNum',
|
||||
slotName: 'resourceNum',
|
||||
width: 200,
|
||||
sortIndex: 1,
|
||||
fixed: 'left',
|
||||
showTooltip: true,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
columnSelectorDisabled: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.resourceName',
|
||||
slotName: 'resourceName',
|
||||
dataIndex: 'resourceName',
|
||||
width: 300,
|
||||
showDrag: false,
|
||||
showTooltip: true,
|
||||
showInTable: true,
|
||||
columnSelectorDisabled: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.executionResult',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
filterConfig: {
|
||||
options: statusFilters.value,
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_TASK_CENTER_API_CASE_STATUS,
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.status',
|
||||
dataIndex: 'execStatus',
|
||||
slotName: 'execStatus',
|
||||
filterConfig: {
|
||||
options: ExecStatusList.value,
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_STATUS,
|
||||
},
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.executionMode',
|
||||
dataIndex: 'triggerMode',
|
||||
slotName: 'triggerMode',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
filterConfig: {
|
||||
options: triggerModeList,
|
||||
},
|
||||
showInTable: true,
|
||||
width: 150,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.resourcePool',
|
||||
slotName: 'poolName',
|
||||
dataIndex: 'poolName',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.operator',
|
||||
slotName: 'operationName',
|
||||
dataIndex: 'operationName',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.operating',
|
||||
dataIndex: 'operationTime',
|
||||
slotName: 'operationTime',
|
||||
width: 180,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
slotName: 'operation',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: hasOperationPermission.value ? 180 : 100,
|
||||
},
|
||||
];
|
||||
|
||||
const tableKeysMap: Record<string, any> = {
|
||||
system: TableKeyEnum.TASK_API_CASE_SYSTEM,
|
||||
organization: TableKeyEnum.TASK_API_CASE_ORGANIZATION,
|
||||
project: TableKeyEnum.TASK_API_CASE_PROJECT,
|
||||
};
|
||||
|
||||
const groupColumnsMap: Record<string, any> = {
|
||||
system: [getOrgColumns(), getProjectColumns(tableKeysMap[props.group]), ...staticColumns],
|
||||
organization: [getProjectColumns(tableKeysMap[props.group]), ...staticColumns],
|
||||
project: staticColumns,
|
||||
};
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, resetFilterParams } = useTable(
|
||||
loadRealMap.value[props.group].list,
|
||||
{
|
||||
tableKey: tableKeysMap[props.group],
|
||||
scroll: {
|
||||
x: 1400,
|
||||
},
|
||||
showSetting: true,
|
||||
selectable: hasOperationPermission.value,
|
||||
heightUsed: 330,
|
||||
showSelectAll: true,
|
||||
}
|
||||
);
|
||||
|
||||
function initData() {
|
||||
setLoadListParams({
|
||||
keyword: keyword.value,
|
||||
moduleType: props.moduleType,
|
||||
});
|
||||
loadList();
|
||||
}
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'project.taskCenter.batchStop',
|
||||
eventTag: 'batchStop',
|
||||
anyPermission: permissionsMap[props.group][props.moduleType].stop,
|
||||
},
|
||||
// {
|
||||
// label: 'project.taskCenter.batchExecution',
|
||||
// eventTag: 'batchExecution',
|
||||
// },
|
||||
],
|
||||
};
|
||||
const batchParams = ref<BatchApiParams>({
|
||||
selectIds: [],
|
||||
selectAll: false,
|
||||
excludeIds: [] as string[],
|
||||
condition: {},
|
||||
});
|
||||
|
||||
function batchStopRealTask() {
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title: t('project.taskCenter.batchStopTask', { num: batchParams.value.currentSelectCount }),
|
||||
content: t('project.taskCenter.stopTaskContent'),
|
||||
okText: t('project.taskCenter.confirmStop'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
const { selectIds, selectAll, excludeIds } = batchParams.value;
|
||||
await loadRealMap.value[props.group].batchStop({
|
||||
moduleType: props.moduleType,
|
||||
selectIds: selectIds || [],
|
||||
selectAll,
|
||||
excludeIds: excludeIds || [],
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
...propsRes.value.filter,
|
||||
},
|
||||
},
|
||||
});
|
||||
resetSelector();
|
||||
Message.success(t('project.taskCenter.stopSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
batchParams.value = { ...params, selectIds: params?.selectedIds || [], condition: params?.condition || {} };
|
||||
if (event.eventTag === 'batchStop') {
|
||||
batchStopRealTask();
|
||||
}
|
||||
}
|
||||
|
||||
function searchList() {
|
||||
resetSelector();
|
||||
initData();
|
||||
}
|
||||
|
||||
function stop(record: any) {
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title: t('project.taskCenter.stopTask', { name: characterLimit(record.resourceName) }),
|
||||
content: t('project.taskCenter.stopTaskContent'),
|
||||
okText: t('project.taskCenter.confirmStop'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await loadRealMap.value[props.group].stop(props.moduleType, record.id);
|
||||
resetSelector();
|
||||
Message.success(t('project.taskCenter.stopSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function execution(record: any) {}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
initData();
|
||||
});
|
||||
|
||||
/**
|
||||
* 报告详情 showReportDetail
|
||||
*/
|
||||
const activeDetailId = ref<string>('');
|
||||
const activeReportIndex = ref<number>(0);
|
||||
const showDetailDrawer = ref<boolean>(false);
|
||||
const showCaseDetailDrawer = ref<boolean>(false);
|
||||
|
||||
function viewReport(id: string, rowIndex: number) {
|
||||
activeDetailId.value = id;
|
||||
activeReportIndex.value = rowIndex;
|
||||
if (props.moduleType === 'API_CASE') {
|
||||
showCaseDetailDrawer.value = true;
|
||||
} else {
|
||||
showDetailDrawer.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.moduleType,
|
||||
(val) => {
|
||||
if (val) {
|
||||
resetSelector();
|
||||
resetFilterParams();
|
||||
initData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 跳转接口用例详情
|
||||
*/
|
||||
function showDetail(record: any) {
|
||||
if (!hasJumpPermission.value) {
|
||||
return;
|
||||
}
|
||||
if (props.moduleType === 'API_CASE') {
|
||||
openNewPage(RouteEnum.API_TEST_MANAGEMENT, {
|
||||
orgId: record.organizationId,
|
||||
pId: record.projectId,
|
||||
cId: record.resourceId,
|
||||
});
|
||||
}
|
||||
if (props.moduleType === 'API_SCENARIO') {
|
||||
openNewPage(RouteEnum.API_TEST_SCENARIO, {
|
||||
orgId: record.organizationId,
|
||||
pId: record.projectId,
|
||||
id: record.resourceId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (props.moduleType === 'API_CASE') {
|
||||
showCaseDetailDrawer.value = false;
|
||||
} else {
|
||||
showDetailDrawer.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
await tableStore.initColumn(tableKeysMap[props.group], groupColumnsMap[props.group], 'drawer', true);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -1,42 +0,0 @@
|
|||
<template>
|
||||
<a-tag :color="statusMap[props.status]?.color" :class="statusMap[props.status]?.class" :size="props.size">
|
||||
{{ t(statusMap[props.status]?.label) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { ReportExecStatus } from '@/enums/apiEnum';
|
||||
|
||||
const props = defineProps<{
|
||||
status: ReportExecStatus;
|
||||
size?: 'small' | 'medium' | 'large';
|
||||
}>();
|
||||
const { t } = useI18n();
|
||||
|
||||
const statusMap = {
|
||||
PENDING: {
|
||||
label: 'common.unExecute',
|
||||
color: 'var(--color-text-n8)',
|
||||
class: '!text-[var(--color-text-1)]',
|
||||
},
|
||||
RUNNING: {
|
||||
label: 'common.running',
|
||||
color: 'rgb(var(--link-2))',
|
||||
class: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
STOPPED: {
|
||||
label: 'common.stopped',
|
||||
color: 'rgb(var(--warning-2))',
|
||||
class: '!text-[rgb(var(--warning-6))]',
|
||||
},
|
||||
COMPLETED: {
|
||||
label: 'report.completed',
|
||||
color: 'rgb(var(--success-2))',
|
||||
class: '!text-[rgb(var(--success-6))]',
|
||||
},
|
||||
} as const;
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -1,75 +0,0 @@
|
|||
<template>
|
||||
<div class="flex items-center justify-start">
|
||||
<MsIcon :type="getExecutionResult().icon" :class="getExecutionResult()?.color" size="14" />
|
||||
<span class="ml-1">{{ t(getExecutionResult().label) }}</span>
|
||||
<a-tooltip v-if="props.scriptIdentifier" :content="getMsg()">
|
||||
<MsTag
|
||||
class="ml-2"
|
||||
:self-style="{
|
||||
border: `1px solid ${methodColor}`,
|
||||
color: methodColor,
|
||||
backgroundColor: 'white',
|
||||
}"
|
||||
>
|
||||
{{ t('report.detail.script.error') }}
|
||||
</MsTag>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { ReportEnum } from '@/enums/reportEnum';
|
||||
import type { ResourceTypeMapKey } from '@/enums/taskCenter';
|
||||
import { TaskCenterEnum } from '@/enums/taskCenter';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
status: string;
|
||||
moduleType: ResourceTypeMapKey;
|
||||
scriptIdentifier?: string;
|
||||
}>();
|
||||
|
||||
export interface IconType {
|
||||
icon: string;
|
||||
label: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
const iconTypeStatus: Record<string, any> = {
|
||||
SUCCESS: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
label: 'common.success',
|
||||
},
|
||||
ERROR: {
|
||||
icon: 'icon-icon_close_colorful',
|
||||
label: 'common.fail',
|
||||
},
|
||||
FAKE_ERROR: {
|
||||
icon: 'icon-icon_warning_colorful',
|
||||
label: 'common.fakeError',
|
||||
},
|
||||
DEFAULT: {
|
||||
icon: '',
|
||||
label: '-',
|
||||
color: '!text-[var(--color-text-input-border)]',
|
||||
},
|
||||
};
|
||||
|
||||
function getExecutionResult(): IconType {
|
||||
return iconTypeStatus[props.status] ? iconTypeStatus[props.status] : iconTypeStatus.DEFAULT;
|
||||
}
|
||||
const methodColor = 'rgb(var(--warning-7))';
|
||||
|
||||
function getMsg() {
|
||||
if (props.moduleType === TaskCenterEnum.API_SCENARIO && props.scriptIdentifier) {
|
||||
return t('report.detail.scenario.errorTip');
|
||||
}
|
||||
return t('report.detail.api.errorTip');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -1,702 +0,0 @@
|
|||
<template>
|
||||
<div class="p-4 pt-0">
|
||||
<a-radio-group
|
||||
v-if="props.moduleType === 'TEST_PLAN'"
|
||||
v-model:model-value="showType"
|
||||
type="button"
|
||||
class="file-show-type"
|
||||
@change="changeShowType"
|
||||
>
|
||||
<a-radio value="All">{{ t('report.all') }}</a-radio>
|
||||
<a-radio value="TEST_PLAN">{{ t('project.taskCenter.plan') }}</a-radio>
|
||||
<a-radio value="GROUP">{{ t('project.taskCenter.planGroup') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="mb-4 flex items-center justify-end">
|
||||
<!-- TODO这个版本不上 -->
|
||||
<!-- <a-button type="primary">
|
||||
{{ t('project.taskCenter.createTask') }}
|
||||
</a-button>-->
|
||||
<div class="flex items-center"></div>
|
||||
<div class="items-right flex gap-[8px]">
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="
|
||||
props.moduleType === 'API_IMPORT'
|
||||
? t('apiTestManagement.searchTaskPlaceholder')
|
||||
: t('system.organization.searchIndexPlaceholder')
|
||||
"
|
||||
allow-clear
|
||||
class="mx-[8px] w-[240px]"
|
||||
@search="searchList"
|
||||
@press-enter="searchList"
|
||||
@clear="searchList"
|
||||
></a-input-search>
|
||||
</div>
|
||||
</div>
|
||||
<ms-base-table
|
||||
v-bind="propsRes"
|
||||
ref="tableRef"
|
||||
:action-config="tableBatchActions"
|
||||
:selectable="hasOperationPermission"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #resourceNum="{ record }">
|
||||
<div
|
||||
v-if="
|
||||
props.moduleType === TaskCenterEnum.API_SCENARIO ||
|
||||
(props.moduleType === TaskCenterEnum.TEST_PLAN && record.type === TaskCenterEnum.TEST_PLAN)
|
||||
"
|
||||
type="text"
|
||||
class="one-line-text w-full"
|
||||
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
|
||||
@click="showDetail(record)"
|
||||
>{{ record.resourceNum }}
|
||||
</div>
|
||||
</template>
|
||||
<template #resourceName="{ record }">
|
||||
<div
|
||||
v-if="
|
||||
props.moduleType === TaskCenterEnum.API_SCENARIO ||
|
||||
(props.moduleType === TaskCenterEnum.TEST_PLAN && record.type === TaskCenterEnum.TEST_PLAN)
|
||||
"
|
||||
class="one-line-text max-w-[300px]"
|
||||
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
|
||||
@click="showDetail(record)"
|
||||
>{{ record.resourceName }}
|
||||
</div>
|
||||
</template>
|
||||
<template #resourceType="{ record }">
|
||||
<div type="text" class="flex w-full">
|
||||
{{ t(resourceTypeMap[record.resourceType as ResourceTypeMapKey].label) }}
|
||||
</div>
|
||||
</template>
|
||||
<template #projectName="{ record }">
|
||||
<a-tooltip :content="`${record.projectName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.projectName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #organizationName="{ record }">
|
||||
<a-tooltip :content="`${record.organizationName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.organizationName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #value="{ record }">
|
||||
<MsCronSelect
|
||||
v-model:model-value="record.value"
|
||||
class="param-input w-full min-w-[250px]"
|
||||
:disabled="!record.enable || !hasAnyPermission(permissionsMap[props.group][props.moduleType]?.edit)"
|
||||
@change="() => changeRunRules(record)"
|
||||
/>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<a-switch
|
||||
v-model="record.enable"
|
||||
size="small"
|
||||
type="line"
|
||||
:before-change="() => handleBeforeEnableChange(record)"
|
||||
:disabled="!hasAnyPermission(permissionsMap[props.group][props.moduleType]?.edit)"
|
||||
/>
|
||||
<a-divider direction="vertical" />
|
||||
<MsButton
|
||||
class="!mr-0"
|
||||
:disabled="!hasAnyPermission(permissionsMap[props.group][props.moduleType]?.edit)"
|
||||
@click="delSchedule(record)"
|
||||
>{{ t('common.delete') }}
|
||||
</MsButton>
|
||||
<!-- TODO这一版不上 -->
|
||||
<!-- <a-divider direction="vertical" />
|
||||
<MsButton class="!mr-0" @click="edit(record)">{{ t('common.edit') }}</MsButton>
|
||||
<a-divider direction="vertical" />
|
||||
<MsTableMoreAction :list="moreActions" @select="handleMoreActionSelect" /> -->
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCronSelect from '@/components/pure/ms-cron-select/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
|
||||
import {
|
||||
batchDisableScheduleOrgTask,
|
||||
batchDisableScheduleProTask,
|
||||
batchDisableScheduleSysTask,
|
||||
batchEnableScheduleOrgTask,
|
||||
batchEnableScheduleProTask,
|
||||
batchEnableScheduleSysTask,
|
||||
deleteScheduleOrgTask,
|
||||
deleteScheduleProTask,
|
||||
deleteScheduleSysTask,
|
||||
enableScheduleOrgTask,
|
||||
enableScheduleProTask,
|
||||
enableScheduleSysTask,
|
||||
getScheduleOrgApiCaseList,
|
||||
getScheduleProApiCaseList,
|
||||
getScheduleSysApiCaseList,
|
||||
updateRunRules,
|
||||
updateRunRulesOrg,
|
||||
updateRunRulesPro,
|
||||
} from '@/api/modules/project-management/taskCenter';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import useOpenNewPage from '@/hooks/useOpenNewPage';
|
||||
import { useTableStore } from '@/store';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { BatchApiParams } from '@/models/common';
|
||||
import { TimingTaskCenterApiCaseItem } from '@/models/projectManagement/taskCenter';
|
||||
import { RouteEnum } from '@/enums/routeEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import type { ResourceTypeMapKey } from '@/enums/taskCenter';
|
||||
import { TaskCenterEnum } from '@/enums/taskCenter';
|
||||
|
||||
import { getOrgColumns, getProjectColumns, Group, resourceTypeMap } from './utils';
|
||||
|
||||
const { openNewPage } = useOpenNewPage();
|
||||
|
||||
const tableStore = useTableStore();
|
||||
const { openModal } = useModal();
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
group: Group;
|
||||
moduleType: keyof typeof TaskCenterEnum;
|
||||
name: string;
|
||||
}>();
|
||||
|
||||
const keyword = ref<string>('');
|
||||
type ReportShowType = 'All' | 'TEST_PLAN' | 'GROUP';
|
||||
const showType = ref<ReportShowType>('All');
|
||||
|
||||
const loadRealMap = ref({
|
||||
system: {
|
||||
list: getScheduleSysApiCaseList,
|
||||
enable: enableScheduleSysTask,
|
||||
delete: deleteScheduleSysTask,
|
||||
edit: updateRunRules,
|
||||
batchEnable: batchEnableScheduleSysTask,
|
||||
batchDisable: batchDisableScheduleSysTask,
|
||||
},
|
||||
organization: {
|
||||
list: getScheduleOrgApiCaseList,
|
||||
enable: enableScheduleOrgTask,
|
||||
delete: deleteScheduleOrgTask,
|
||||
edit: updateRunRulesOrg,
|
||||
batchEnable: batchEnableScheduleOrgTask,
|
||||
batchDisable: batchDisableScheduleOrgTask,
|
||||
},
|
||||
project: {
|
||||
list: getScheduleProApiCaseList,
|
||||
enable: enableScheduleProTask,
|
||||
delete: deleteScheduleProTask,
|
||||
edit: updateRunRulesPro,
|
||||
batchEnable: batchEnableScheduleProTask,
|
||||
batchDisable: batchDisableScheduleProTask,
|
||||
},
|
||||
});
|
||||
|
||||
const permissionsMap: Record<Group, any> = {
|
||||
organization: {
|
||||
API_IMPORT: {
|
||||
edit: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_API_DEFINITION:READ+IMPORT'],
|
||||
},
|
||||
API_SCENARIO: {
|
||||
edit: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_API_SCENARIO:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_SCENARIO:READ'],
|
||||
},
|
||||
TEST_PLAN: {
|
||||
edit: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_TEST_PLAN:READ+EXECUTE'],
|
||||
jump: ['PROJECT_TEST_PLAN:READ'],
|
||||
},
|
||||
},
|
||||
system: {
|
||||
API_IMPORT: {
|
||||
edit: ['SYSTEM_TASK_CENTER:READ+STOP', 'PROJECT_API_DEFINITION:READ+IMPORT'],
|
||||
},
|
||||
API_SCENARIO: {
|
||||
edit: ['SYSTEM_TASK_CENTER:READ+STOP', 'PROJECT_API_SCENARIO:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_SCENARIO:READ'],
|
||||
},
|
||||
TEST_PLAN: {
|
||||
edit: ['SYSTEM_TASK_CENTER:READ+STOP', 'PROJECT_TEST_PLAN:READ+EXECUTE'],
|
||||
jump: ['PROJECT_TEST_PLAN:READ'],
|
||||
},
|
||||
},
|
||||
project: {
|
||||
API_IMPORT: {
|
||||
edit: ['PROJECT_API_DEFINITION:READ+IMPORT'],
|
||||
},
|
||||
API_SCENARIO: {
|
||||
edit: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
|
||||
jump: ['PROJECT_API_SCENARIO:READ'],
|
||||
},
|
||||
TEST_PLAN: {
|
||||
edit: ['PROJECT_TEST_PLAN:READ+EXECUTE'],
|
||||
jump: ['PROJECT_TEST_PLAN:READ'],
|
||||
},
|
||||
},
|
||||
};
|
||||
const hasOperationPermission = computed(() =>
|
||||
hasAnyPermission([...(permissionsMap[props.group][props.moduleType]?.edit || '')])
|
||||
);
|
||||
|
||||
const resourceColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'project.taskCenter.resourceID',
|
||||
dataIndex: 'resourceNum',
|
||||
slotName: 'resourceNum',
|
||||
width: 140,
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
showDrag: false,
|
||||
sortIndex: 1,
|
||||
columnSelectorDisabled: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.resourceName',
|
||||
slotName: 'resourceName',
|
||||
dataIndex: 'resourceName',
|
||||
width: 300,
|
||||
showDrag: false,
|
||||
showTooltip: true,
|
||||
sortIndex: 2,
|
||||
columnSelectorDisabled: true,
|
||||
showInTable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const staticColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'project.taskCenter.operationRule',
|
||||
dataIndex: 'value',
|
||||
slotName: 'value',
|
||||
showInTable: true,
|
||||
width: 300,
|
||||
showDrag: true,
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.operator',
|
||||
slotName: 'createUserName',
|
||||
dataIndex: 'createUserName',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.operating',
|
||||
slotName: 'createTime',
|
||||
dataIndex: 'createTime',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.nextExecutionTime',
|
||||
slotName: 'nextTime',
|
||||
dataIndex: 'nextTime',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
slotName: 'operation',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
showDrag: false,
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
const swaggerUrlColumn: MsTableColumn = [
|
||||
{
|
||||
title: 'project.taskCenter.swaggerUrl',
|
||||
slotName: 'swaggerUrl',
|
||||
dataIndex: 'swaggerUrl',
|
||||
width: 300,
|
||||
showDrag: false,
|
||||
showTooltip: true,
|
||||
columnSelectorDisabled: true,
|
||||
showInTable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const tableKeyMap: Record<string, any> = {
|
||||
system: {
|
||||
API_IMPORT: TableKeyEnum.TASK_SCHEDULE_TASK_API_IMPORT_SYSTEM,
|
||||
API_SCENARIO: TableKeyEnum.TASK_SCHEDULE_TASK_API_SCENARIO_SYSTEM,
|
||||
TEST_PLAN: TableKeyEnum.TASK_SCHEDULE_TASK_TEST_PLAN_SYSTEM,
|
||||
},
|
||||
organization: {
|
||||
API_IMPORT: TableKeyEnum.TASK_SCHEDULE_TASK_API_IMPORT_ORGANIZATION,
|
||||
API_SCENARIO: TableKeyEnum.TASK_SCHEDULE_TASK_API_SCENARIO_ORGANIZATION,
|
||||
TEST_PLAN: TableKeyEnum.TASK_SCHEDULE_TASK_TEST_PLAN_ORGANIZATION,
|
||||
},
|
||||
project: {
|
||||
API_IMPORT: TableKeyEnum.TASK_SCHEDULE_TASK_API_IMPORT_PROJECT,
|
||||
API_SCENARIO: TableKeyEnum.TASK_SCHEDULE_TASK_API_SCENARIO_PROJECT,
|
||||
TEST_PLAN: TableKeyEnum.TASK_SCHEDULE_TASK_TEST_PLAN_PROJECT,
|
||||
},
|
||||
};
|
||||
|
||||
const groupColumnsMap: Record<string, any> = {
|
||||
system: {
|
||||
API_IMPORT: [
|
||||
getOrgColumns(),
|
||||
getProjectColumns(tableKeyMap[props.group][props.moduleType]),
|
||||
...resourceColumns,
|
||||
...swaggerUrlColumn,
|
||||
...staticColumns,
|
||||
],
|
||||
|
||||
API_SCENARIO: [
|
||||
getOrgColumns(),
|
||||
getProjectColumns(tableKeyMap[props.group][props.moduleType]),
|
||||
...resourceColumns,
|
||||
...staticColumns,
|
||||
],
|
||||
TEST_PLAN: [
|
||||
getOrgColumns(),
|
||||
getProjectColumns(tableKeyMap[props.group][props.moduleType]),
|
||||
...resourceColumns,
|
||||
...staticColumns,
|
||||
],
|
||||
},
|
||||
organization: {
|
||||
API_IMPORT: [
|
||||
getProjectColumns(tableKeyMap[props.group][props.moduleType]),
|
||||
...resourceColumns,
|
||||
...swaggerUrlColumn,
|
||||
...staticColumns,
|
||||
],
|
||||
API_SCENARIO: [
|
||||
getProjectColumns(tableKeyMap[props.group][props.moduleType]),
|
||||
...resourceColumns,
|
||||
...staticColumns,
|
||||
],
|
||||
TEST_PLAN: [getProjectColumns(tableKeyMap[props.group][props.moduleType]), ...resourceColumns, ...staticColumns],
|
||||
},
|
||||
project: {
|
||||
API_IMPORT: [...resourceColumns, ...swaggerUrlColumn, ...staticColumns],
|
||||
API_SCENARIO: [...resourceColumns, ...staticColumns],
|
||||
TEST_PLAN: [...resourceColumns, ...staticColumns],
|
||||
},
|
||||
};
|
||||
|
||||
const typeFilter = computed(() => {
|
||||
if (showType.value === 'All') {
|
||||
return [];
|
||||
}
|
||||
return [showType.value];
|
||||
});
|
||||
|
||||
const hasJumpPermission = computed(() => hasAnyPermission(permissionsMap[props.group][props.moduleType].jump));
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, setPagination, resetSelector, resetFilterParams } =
|
||||
useTable(
|
||||
loadRealMap.value[props.group].list,
|
||||
{
|
||||
tableKey: tableKeyMap[props.group][props.moduleType],
|
||||
scroll: {
|
||||
x: 1200,
|
||||
},
|
||||
showSetting: true,
|
||||
selectable: hasOperationPermission.value,
|
||||
heightUsed: 300,
|
||||
showSelectorAll: true,
|
||||
},
|
||||
// eslint-disable-next-line no-return-assign
|
||||
(item) => ({
|
||||
...item,
|
||||
nextTime: item.nextTime ? dayjs(item.nextTime).format('YYYY-MM-DD HH:mm:ss') : null,
|
||||
})
|
||||
);
|
||||
|
||||
function initData() {
|
||||
const filterParams = {
|
||||
...propsRes.value.filter,
|
||||
};
|
||||
|
||||
setLoadListParams({
|
||||
keyword: keyword.value,
|
||||
scheduleTagType: props.moduleType,
|
||||
filter: {
|
||||
...(props.moduleType === 'TEST_PLAN'
|
||||
? {
|
||||
type: typeFilter.value,
|
||||
...filterParams,
|
||||
}
|
||||
: { ...filterParams }),
|
||||
},
|
||||
});
|
||||
loadList();
|
||||
}
|
||||
|
||||
function changeShowType(val: string | number | boolean) {
|
||||
showType.value = val as ReportShowType;
|
||||
resetFilterParams();
|
||||
resetSelector();
|
||||
// 重置分页
|
||||
setPagination({
|
||||
current: 1,
|
||||
});
|
||||
initData();
|
||||
}
|
||||
|
||||
function searchList() {
|
||||
resetSelector();
|
||||
initData();
|
||||
}
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'project.taskCenter.batchEnable',
|
||||
eventTag: 'batchEnable',
|
||||
anyPermission: permissionsMap[props.group][props.moduleType]?.edit,
|
||||
},
|
||||
{
|
||||
label: 'project.taskCenter.batchDisable',
|
||||
eventTag: 'batchDisable',
|
||||
anyPermission: permissionsMap[props.group][props.moduleType]?.edit,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function delSchedule(record: any) {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('project.taskCenter.delSchedule'),
|
||||
content: t('project.taskCenter.delSchedule.tip'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
maskClosable: false,
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await loadRealMap.value[props.group].delete(props.moduleType, record?.id as string);
|
||||
Message.success(t('project.basicInfo.deleted'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
async function handleBeforeEnableChange(record: TimingTaskCenterApiCaseItem) {
|
||||
try {
|
||||
await loadRealMap.value[props.group].enable(props.moduleType, record?.id as string);
|
||||
Message.success(
|
||||
t(record.enable ? 'project.taskCenter.disableScheduleSuccess' : 'project.taskCenter.enableScheduleSuccess')
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新运行规则
|
||||
*/
|
||||
async function changeRunRules(record: TimingTaskCenterApiCaseItem) {
|
||||
try {
|
||||
await loadRealMap.value[props.group].edit(props.moduleType, record.id, record.value);
|
||||
Message.success(t('common.updateSuccess'));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转接口用例详情
|
||||
*/
|
||||
|
||||
function showDetail(record: any) {
|
||||
if (!hasJumpPermission.value) {
|
||||
return;
|
||||
}
|
||||
if (props.moduleType === TaskCenterEnum.API_SCENARIO) {
|
||||
openNewPage(RouteEnum.API_TEST_SCENARIO, {
|
||||
orgId: record.organizationId,
|
||||
pId: record.projectId,
|
||||
id: record.resourceId,
|
||||
});
|
||||
}
|
||||
if (props.moduleType === TaskCenterEnum.TEST_PLAN) {
|
||||
openNewPage(RouteEnum.TEST_PLAN_INDEX_DETAIL, {
|
||||
orgId: record.organizationId,
|
||||
pId: record.projectId,
|
||||
id: record.resourceId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const batchParams = ref<BatchApiParams>({
|
||||
selectIds: [],
|
||||
selectAll: false,
|
||||
excludeIds: [] as string[],
|
||||
condition: {},
|
||||
});
|
||||
|
||||
function batchEnableTask() {
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title: t('project.taskCenter.batchEnableTask', { num: batchParams.value.currentSelectCount }),
|
||||
content: t('project.taskCenter.batchEnableTaskContent'),
|
||||
okText: t('project.taskCenter.confirmEnable'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
const { selectIds, selectAll, excludeIds } = batchParams.value;
|
||||
|
||||
await loadRealMap.value[props.group].batchEnable({
|
||||
selectIds: selectIds || [],
|
||||
selectAll: !!selectAll,
|
||||
scheduleTagType: props.moduleType,
|
||||
excludeIds,
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
...(props.moduleType === 'TEST_PLAN'
|
||||
? {
|
||||
type: typeFilter.value,
|
||||
...propsRes.value.filter,
|
||||
}
|
||||
: { ...propsRes.value.filter }),
|
||||
},
|
||||
},
|
||||
});
|
||||
resetSelector();
|
||||
Message.success(t('project.taskCenter.enableSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function batchDisableTask() {
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title: t('project.taskCenter.batchDisableTask', { num: batchParams.value.currentSelectCount }),
|
||||
content: t('project.taskCenter.batchDisableTaskContent'),
|
||||
okText: t('project.taskCenter.confirmDisable'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
const { selectIds, selectAll, excludeIds } = batchParams.value;
|
||||
await loadRealMap.value[props.group].batchDisable({
|
||||
selectIds: selectIds || [],
|
||||
selectAll: !!selectAll,
|
||||
excludeIds: excludeIds || [],
|
||||
scheduleTagType: props.moduleType,
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
...(props.moduleType === 'TEST_PLAN'
|
||||
? { type: typeFilter.value, ...propsRes.value.filter }
|
||||
: { ...propsRes.value.filter }),
|
||||
},
|
||||
},
|
||||
});
|
||||
resetSelector();
|
||||
Message.success(t('project.taskCenter.disableSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
batchParams.value = { ...params, selectIds: params?.selectedIds || [], condition: {} };
|
||||
if (event.eventTag === 'batchEnable') {
|
||||
batchEnableTask();
|
||||
} else if (event.eventTag === 'batchDisable') {
|
||||
batchDisableTask();
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
initData();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.moduleType,
|
||||
(val) => {
|
||||
if (val) {
|
||||
resetSelector();
|
||||
initData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
await tableStore.initColumn(
|
||||
tableKeyMap[props.group][props.moduleType],
|
||||
groupColumnsMap[props.group][props.moduleType],
|
||||
'drawer',
|
||||
true
|
||||
);
|
||||
|
||||
const tableRef = ref();
|
||||
watch(
|
||||
() => props.moduleType,
|
||||
(val) => {
|
||||
if (val) {
|
||||
resetFilterParams();
|
||||
tableRef.value.initColumn(groupColumnsMap[props.group][props.moduleType]);
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
:deep(.param-input:not(.arco-input-focus, .arco-select-view-focus)) {
|
||||
&:not(:hover) {
|
||||
border-color: transparent !important;
|
||||
.arco-input::placeholder {
|
||||
@apply invisible;
|
||||
}
|
||||
.arco-select-view-icon {
|
||||
@apply invisible;
|
||||
}
|
||||
.arco-select-view-value {
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,226 +0,0 @@
|
|||
<template>
|
||||
<div class="box">
|
||||
<div class="left" :class="getStyleClass()">
|
||||
<div
|
||||
v-for="item of menuTab"
|
||||
:key="item.value"
|
||||
:class="`${activeTask === item.value ? 'active' : ''} item`"
|
||||
@click="toggleTask(item.value)"
|
||||
>
|
||||
<div class="mr-2">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<a-badge
|
||||
v-if="getTextFunc(item.value) !== ''"
|
||||
:class="`${item.value === activeTask ? 'active-badge' : ''} mt-[2px]`"
|
||||
:max-count="99"
|
||||
:text="getTextFunc(item.value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a-tabs v-model:active-key="activeTab" class="no-content">
|
||||
<a-tab-pane v-for="item of rightTabList" :key="item.value" :title="item.label" />
|
||||
</a-tabs>
|
||||
<a-divider margin="0" class="!mb-[16px]"></a-divider>
|
||||
<!-- 接口用例列表-->
|
||||
<ApiCase
|
||||
v-if="
|
||||
activeTask === 'real' && (activeTab === TaskCenterEnum.API_CASE || activeTab === TaskCenterEnum.API_SCENARIO)
|
||||
"
|
||||
:name="listName"
|
||||
:module-type="activeTab"
|
||||
:group="props.group"
|
||||
/>
|
||||
<!-- 测试计划列表-->
|
||||
<TestPlan
|
||||
v-if="activeTask === 'real' && activeTab === TaskCenterEnum.TEST_PLAN"
|
||||
:name="listName"
|
||||
:group="props.group"
|
||||
/>
|
||||
<ScheduledTask v-if="activeTask === 'timing'" :name="listName" :group="props.group" :module-type="activeTab" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import ApiCase from './apiCase.vue';
|
||||
import ScheduledTask from './scheduledTask.vue';
|
||||
import TestPlan from './testPlan.vue';
|
||||
|
||||
import {
|
||||
getOrgRealTotal,
|
||||
getOrgScheduleTotal,
|
||||
getProjectRealTotal,
|
||||
getProjectScheduleTotal,
|
||||
getSystemRealTotal,
|
||||
getSystemScheduleTotal,
|
||||
} from '@/api/modules/project-management/taskCenter';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { TaskCenterEnum } from '@/enums/taskCenter';
|
||||
|
||||
import type { ExtractedKeys } from './utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
group: 'system' | 'organization' | 'project';
|
||||
mode?: 'modal' | 'normal';
|
||||
}>();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const realTabList = ref([
|
||||
{
|
||||
value: TaskCenterEnum.API_CASE,
|
||||
label: t('project.taskCenter.interfaceCase'),
|
||||
},
|
||||
{
|
||||
value: TaskCenterEnum.API_SCENARIO,
|
||||
label: t('project.taskCenter.apiScenario'),
|
||||
},
|
||||
{
|
||||
value: TaskCenterEnum.TEST_PLAN,
|
||||
label: t('project.taskCenter.testPlan'),
|
||||
},
|
||||
// TODO 第一个版本目前不上以下几类
|
||||
// {
|
||||
// value: TaskCenterEnum.UI_TEST,
|
||||
// label: t('project.taskCenter.uiDefaultFile'),
|
||||
// },
|
||||
// {
|
||||
// value: TaskCenterEnum.LOAD_TEST,
|
||||
// label: t('project.taskCenter.performanceTest'),
|
||||
// },
|
||||
]);
|
||||
|
||||
const timingTabList = ref([
|
||||
{
|
||||
value: TaskCenterEnum.API_SCENARIO,
|
||||
label: t('project.taskCenter.apiScenario'),
|
||||
},
|
||||
{
|
||||
value: TaskCenterEnum.API_IMPORT,
|
||||
label: t('project.taskCenter.apiImport'),
|
||||
},
|
||||
{
|
||||
value: TaskCenterEnum.TEST_PLAN,
|
||||
label: t('project.taskCenter.testPlan'),
|
||||
},
|
||||
]);
|
||||
|
||||
const activeTask = ref<string>((route.query.tab as string) || 'real');
|
||||
const activeTab = ref<ExtractedKeys>((route.query.type as ExtractedKeys) || TaskCenterEnum.API_CASE);
|
||||
|
||||
const rightTabList = computed(() => {
|
||||
return activeTask.value === 'real' ? realTabList.value : timingTabList.value;
|
||||
});
|
||||
|
||||
function toggleTask(activeType: string) {
|
||||
activeTask.value = activeType;
|
||||
if (activeTask.value === 'real') {
|
||||
activeTab.value = TaskCenterEnum.API_CASE;
|
||||
} else {
|
||||
activeTab.value = TaskCenterEnum.API_SCENARIO;
|
||||
}
|
||||
}
|
||||
|
||||
function getStyleClass() {
|
||||
return props.mode === 'modal' ? ['p-0', 'pt-[16px]', 'pr-[16px]'] : ['p-[16px]'];
|
||||
}
|
||||
|
||||
const listName = computed(() => {
|
||||
return rightTabList.value.find((item) => item.value === activeTab.value)?.label || '';
|
||||
});
|
||||
|
||||
export type menuType = 'real' | 'timing';
|
||||
|
||||
const menuTab: { value: menuType; label: string }[] = [
|
||||
{
|
||||
value: 'real',
|
||||
label: t('project.taskCenter.realTimeTask'),
|
||||
},
|
||||
{
|
||||
value: 'timing',
|
||||
label: t('project.taskCenter.scheduledTask'),
|
||||
},
|
||||
];
|
||||
|
||||
const getTotalMap: Record<menuType, any> = {
|
||||
real: {
|
||||
system: getSystemRealTotal,
|
||||
organization: getOrgRealTotal,
|
||||
project: getProjectRealTotal,
|
||||
},
|
||||
timing: {
|
||||
system: getSystemScheduleTotal,
|
||||
organization: getOrgScheduleTotal,
|
||||
project: getProjectScheduleTotal,
|
||||
},
|
||||
};
|
||||
|
||||
const totalMap = ref<Record<menuType, number>>({
|
||||
real: 0,
|
||||
timing: 0,
|
||||
});
|
||||
|
||||
async function getTotal() {
|
||||
try {
|
||||
const [timingTotal, realTotal] = await Promise.all([
|
||||
getTotalMap.timing[props.group](),
|
||||
getTotalMap.real[props.group](),
|
||||
]);
|
||||
totalMap.value.timing = timingTotal;
|
||||
totalMap.value.real = realTotal;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function getTextFunc(activeKey: menuType) {
|
||||
return totalMap.value[activeKey] > 99 ? '99+' : `${totalMap.value[activeKey]}` || '';
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getTotal();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.box {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
.left {
|
||||
width: 252px;
|
||||
height: 100%;
|
||||
border-right: 1px solid var(--color-text-n8);
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
height: 38px;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
line-height: 38px;
|
||||
&.active {
|
||||
color: rgb(var(--primary-5));
|
||||
background: rgb(var(--primary-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
.right {
|
||||
width: calc(100% - 300px);
|
||||
flex-grow: 1; /* 自适应 */
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.no-content {
|
||||
:deep(.arco-tabs-content) {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,516 +0,0 @@
|
|||
<template>
|
||||
<div class="px-[16px]">
|
||||
<div class="mb-[16px] flex items-center justify-between">
|
||||
<div class="flex items-center"></div>
|
||||
<div class="items-right flex gap-[8px]">
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="t('system.organization.searchIndexPlaceholder')"
|
||||
allow-clear
|
||||
class="mx-[8px] w-[240px]"
|
||||
@search="searchList"
|
||||
@press-enter="searchList"
|
||||
@clear="searchList"
|
||||
></a-input-search>
|
||||
</div>
|
||||
</div>
|
||||
<ms-base-table
|
||||
v-bind="propsRes"
|
||||
ref="tableRef"
|
||||
:action-config="tableBatchActions"
|
||||
:selectable="hasOperationPermission"
|
||||
:expanded-keys="expandedKeys"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #resourceNum="{ record }">
|
||||
<div class="flex items-center">
|
||||
<PlanExpandRow
|
||||
v-model:expanded-keys="expandedKeys"
|
||||
num-key="resourceNum"
|
||||
:record="record"
|
||||
:permission="permissionsMap[props.group].jump"
|
||||
@action="showDetail(record)"
|
||||
@expand="expandHandler(record)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #resourceName="{ record }">
|
||||
<div
|
||||
v-if="!record.integrated"
|
||||
class="one-line-text max-w-[300px]"
|
||||
:class="[hasJumpPermission ? 'text-[rgb(var(--primary-5))]' : '']"
|
||||
@click="showDetail(record)"
|
||||
>{{ record.resourceName }}
|
||||
</div>
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<ExecutionStatus :status="record.status" />
|
||||
</template>
|
||||
<template #execStatus="{ record }">
|
||||
<ExecStatus :status="record.execStatus" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.TEST_PLAN_REPORT_EXEC_STATUS]="{ filterContent }">
|
||||
<ExecStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.TEST_PLAN_STATUS_FILTER]="{ filterContent }">
|
||||
<ExecutionStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #projectName="{ record }">
|
||||
<a-tooltip :content="`${record.projectName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.projectName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #organizationName="{ record }">
|
||||
<a-tooltip :content="`${record.organizationName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.organizationName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #triggerMode="{ record }">
|
||||
<span>{{ t(ExecutionMethodsLabel[record.triggerMode as keyof typeof ExecutionMethodsLabel]) }}</span>
|
||||
</template>
|
||||
<template #operationTime="{ record }">
|
||||
<span>{{ dayjs(record.operationTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<div v-if="record.historyDeleted">
|
||||
<a-tooltip :content="t('project.executionHistory.cleared')">
|
||||
<MsButton
|
||||
class="!mr-0"
|
||||
:disabled="record.historyDeleted || !hasAnyPermission(permissionsMap[props.group].report)"
|
||||
@click="viewReport(record)"
|
||||
>{{ t('project.taskCenter.viewReport') }}
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div v-else>
|
||||
<MsButton
|
||||
class="!mr-0"
|
||||
:disabled="record.historyDeleted || !hasAnyPermission(permissionsMap[props.group].report)"
|
||||
@click="viewReport(record)"
|
||||
>{{ t('project.taskCenter.viewReport') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
|
||||
<a-divider v-if="['RUNNING', 'RERUNNING'].includes(record.execStatus)" direction="vertical" />
|
||||
<MsButton
|
||||
v-if="
|
||||
['RUNNING', 'RERUNNING'].includes(record.execStatus) && hasAnyPermission(permissionsMap[props.group].stop)
|
||||
"
|
||||
class="!mr-0"
|
||||
@click="stop(record)"
|
||||
>{{ t('project.taskCenter.stop') }}
|
||||
</MsButton>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import ExecStatus from '@/views/test-plan/report/component/execStatus.vue';
|
||||
import ExecutionStatus from '@/views/test-plan/report/component/reportStatus.vue';
|
||||
import PlanExpandRow from '@/views/test-plan/testPlan/components/planExpandRow.vue';
|
||||
|
||||
import {
|
||||
batchStopRealOrgPlan,
|
||||
batchStopRealProPlan,
|
||||
batchStopRealSysPlan,
|
||||
getRealOrgPlanList,
|
||||
getRealProPlanList,
|
||||
getRealSysPlanList,
|
||||
stopRealOrgPlan,
|
||||
stopRealProPlan,
|
||||
stopRealSysPlan,
|
||||
} from '@/api/modules/project-management/taskCenter';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import useOpenNewPage from '@/hooks/useOpenNewPage';
|
||||
import { useTableStore } from '@/store';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { BatchApiParams } from '@/models/common';
|
||||
import type { TestPlanTaskCenterItem } from '@/models/projectManagement/taskCenter';
|
||||
import { ReportExecStatus } from '@/enums/apiEnum';
|
||||
import { PlanReportStatus } from '@/enums/reportEnum';
|
||||
import { RouteEnum } from '@/enums/routeEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
import { ExecutionMethodsLabel, TaskCenterEnum } from '@/enums/taskCenter';
|
||||
|
||||
import { getOrgColumns, getProjectColumns, Group } from './utils';
|
||||
|
||||
const { openNewPage } = useOpenNewPage();
|
||||
|
||||
const tableStore = useTableStore();
|
||||
const { openModal } = useModal();
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
group: Group;
|
||||
name: string;
|
||||
}>();
|
||||
const keyword = ref<string>('');
|
||||
|
||||
const permissionsMap: Record<Group, any> = {
|
||||
organization: {
|
||||
stop: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_TEST_PLAN:READ+EXECUTE'],
|
||||
jump: ['PROJECT_TEST_PLAN:READ'],
|
||||
report: ['PROJECT_TEST_PLAN:READ+EXECUTE', 'PROJECT_TEST_PLAN_REPORT:READ'],
|
||||
},
|
||||
system: {
|
||||
stop: ['SYSTEM_TASK_CENTER:READ+STOP', 'PROJECT_TEST_PLAN:READ+EXECUTE'],
|
||||
jump: ['PROJECT_TEST_PLAN:READ'],
|
||||
report: ['PROJECT_TEST_PLAN:READ+EXECUTE', 'PROJECT_TEST_PLAN_REPORT:READ'],
|
||||
},
|
||||
project: {
|
||||
stop: ['PROJECT_TEST_PLAN:READ+EXECUTE'],
|
||||
jump: ['PROJECT_TEST_PLAN:READ'],
|
||||
report: ['PROJECT_TEST_PLAN:READ+EXECUTE', 'PROJECT_TEST_PLAN_REPORT:READ'],
|
||||
},
|
||||
};
|
||||
|
||||
const loadRealMap = ref({
|
||||
system: {
|
||||
list: getRealSysPlanList,
|
||||
stop: stopRealSysPlan,
|
||||
batchStop: batchStopRealSysPlan,
|
||||
},
|
||||
organization: {
|
||||
list: getRealOrgPlanList,
|
||||
stop: stopRealOrgPlan,
|
||||
batchStop: batchStopRealOrgPlan,
|
||||
},
|
||||
project: {
|
||||
list: getRealProPlanList,
|
||||
stop: stopRealProPlan,
|
||||
batchStop: batchStopRealProPlan,
|
||||
},
|
||||
});
|
||||
const hasJumpPermission = computed(() => hasAnyPermission(permissionsMap[props.group].jump));
|
||||
const hasOperationPermission = computed(() => hasAnyPermission(permissionsMap[props.group].stop));
|
||||
|
||||
const statusResultOptions = computed(() => {
|
||||
return Object.keys(PlanReportStatus).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: PlanReportStatus[key].statusText,
|
||||
};
|
||||
});
|
||||
});
|
||||
const ExecStatusList = computed(() => {
|
||||
return Object.values(ReportExecStatus).map((e) => {
|
||||
return {
|
||||
value: e,
|
||||
key: e,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const triggerModeList = [
|
||||
{
|
||||
value: 'SCHEDULE',
|
||||
label: t('project.taskCenter.scheduledTask'),
|
||||
},
|
||||
{
|
||||
value: 'MANUAL',
|
||||
label: t('project.taskCenter.manualExecution'),
|
||||
},
|
||||
{
|
||||
value: 'API',
|
||||
label: t('project.taskCenter.interfaceCall'),
|
||||
},
|
||||
{
|
||||
value: 'BATCH',
|
||||
label: t('project.taskCenter.batchExecution'),
|
||||
},
|
||||
];
|
||||
|
||||
const staticColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'project.taskCenter.resourceID',
|
||||
dataIndex: 'resourceNum',
|
||||
slotName: 'resourceNum',
|
||||
width: 200,
|
||||
sortIndex: 1,
|
||||
fixed: 'left',
|
||||
showTooltip: true,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
columnSelectorDisabled: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.resourceName',
|
||||
slotName: 'resourceName',
|
||||
dataIndex: 'resourceName',
|
||||
width: 300,
|
||||
showDrag: false,
|
||||
showTooltip: true,
|
||||
showInTable: true,
|
||||
columnSelectorDisabled: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.executionResult',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
filterConfig: {
|
||||
options: statusResultOptions.value,
|
||||
filterSlotName: FilterSlotNameEnum.TEST_PLAN_STATUS_FILTER,
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.status',
|
||||
dataIndex: 'execStatus',
|
||||
slotName: 'execStatus',
|
||||
filterConfig: {
|
||||
options: ExecStatusList.value,
|
||||
filterSlotName: FilterSlotNameEnum.TEST_PLAN_REPORT_EXEC_STATUS,
|
||||
},
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.executionMode',
|
||||
dataIndex: 'triggerMode',
|
||||
slotName: 'triggerMode',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
filterConfig: {
|
||||
options: triggerModeList,
|
||||
},
|
||||
showInTable: true,
|
||||
width: 150,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.operator',
|
||||
slotName: 'operationName',
|
||||
dataIndex: 'operationName',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'project.taskCenter.operating',
|
||||
dataIndex: 'operationTime',
|
||||
slotName: 'operationTime',
|
||||
width: 180,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
slotName: 'operation',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: hasOperationPermission.value ? 180 : 100,
|
||||
},
|
||||
];
|
||||
|
||||
const tableKeysMap: Record<string, any> = {
|
||||
system: TableKeyEnum.TASK_PLAN_SYSTEM,
|
||||
organization: TableKeyEnum.TASK_PLAN_ORGANIZATION,
|
||||
project: TableKeyEnum.TASK_PLAN_PROJECT,
|
||||
};
|
||||
|
||||
const groupColumnsMap: Record<string, any> = {
|
||||
system: [getOrgColumns(), getProjectColumns(tableKeysMap[props.group]), ...staticColumns],
|
||||
organization: [getProjectColumns(tableKeysMap[props.group]), ...staticColumns],
|
||||
project: staticColumns,
|
||||
};
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, resetFilterParams } = useTable(
|
||||
loadRealMap.value[props.group].list,
|
||||
{
|
||||
tableKey: tableKeysMap[props.group],
|
||||
scroll: {
|
||||
x: 1400,
|
||||
},
|
||||
showSetting: true,
|
||||
selectable: hasOperationPermission.value,
|
||||
heightUsed: 330,
|
||||
showSelectAll: true,
|
||||
rowSelectionDisabledConfig: {
|
||||
parentKey: 'parent',
|
||||
checkStrictly: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
function initData() {
|
||||
setLoadListParams({
|
||||
moduleType: TaskCenterEnum.TEST_PLAN,
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
...propsRes.value.filter,
|
||||
},
|
||||
});
|
||||
loadList();
|
||||
}
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'project.taskCenter.batchStop',
|
||||
eventTag: 'batchStop',
|
||||
anyPermission: permissionsMap[props.group].stop,
|
||||
},
|
||||
],
|
||||
};
|
||||
const batchParams = ref<BatchApiParams>({
|
||||
selectIds: [],
|
||||
selectAll: false,
|
||||
excludeIds: [] as string[],
|
||||
condition: {},
|
||||
});
|
||||
function batchStopRealTask() {
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title: t('project.taskCenter.batchStopTask', { num: batchParams.value.currentSelectCount }),
|
||||
content: t('project.taskCenter.stopTaskContent'),
|
||||
okText: t('project.taskCenter.confirmStop'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
const { selectIds, selectAll, excludeIds } = batchParams.value;
|
||||
await loadRealMap.value[props.group].batchStop({
|
||||
selectIds: selectIds || [],
|
||||
selectAll,
|
||||
excludeIds: excludeIds || [],
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
...propsRes.value.filter,
|
||||
},
|
||||
},
|
||||
});
|
||||
resetSelector();
|
||||
Message.success(t('project.taskCenter.stopSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
batchParams.value = { ...params, selectIds: params?.selectedIds || [], condition: params?.condition || {} };
|
||||
if (event.eventTag === 'batchStop') {
|
||||
batchStopRealTask();
|
||||
}
|
||||
}
|
||||
|
||||
function viewReport(record: any) {
|
||||
openNewPage(RouteEnum.TEST_PLAN_REPORT_DETAIL, {
|
||||
orgId: record.organizationId,
|
||||
pId: record.projectId,
|
||||
id: record.id,
|
||||
type: record.integrated ? 'GROUP' : 'TEST_PLAN',
|
||||
});
|
||||
}
|
||||
|
||||
function showDetail(record: any) {
|
||||
if (!hasJumpPermission.value) {
|
||||
return;
|
||||
}
|
||||
openNewPage(RouteEnum.TEST_PLAN_INDEX_DETAIL, {
|
||||
orgId: record.organizationId,
|
||||
pId: record.projectId,
|
||||
id: record.resourceId,
|
||||
});
|
||||
}
|
||||
|
||||
function stop(record: any) {
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title: t('project.taskCenter.stopTask', { name: characterLimit(record.resourceName) }),
|
||||
content: t('project.taskCenter.stopTaskContent'),
|
||||
okText: t('project.taskCenter.confirmStop'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await loadRealMap.value[props.group].stop(record.id);
|
||||
resetSelector();
|
||||
Message.success(t('project.taskCenter.stopSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
const expandedKeys = ref<string[]>([]);
|
||||
|
||||
function expandHandler(record: TestPlanTaskCenterItem) {
|
||||
if (expandedKeys.value.includes(record.id)) {
|
||||
expandedKeys.value = expandedKeys.value.filter((key) => key !== record.id);
|
||||
} else {
|
||||
expandedKeys.value = [...expandedKeys.value, record.id];
|
||||
}
|
||||
}
|
||||
|
||||
function searchList() {
|
||||
resetSelector();
|
||||
initData();
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
initData();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.group,
|
||||
(val) => {
|
||||
if (val) {
|
||||
resetSelector();
|
||||
resetFilterParams();
|
||||
initData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
await tableStore.initColumn(tableKeysMap[props.group], groupColumnsMap[props.group], 'drawer', true);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
:deep(.arco-table-cell-expand-icon .arco-table-cell-inline-icon) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.arco-table-cell-align-left) > span:first-child {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -1,205 +0,0 @@
|
|||
import type { MsTableColumnData } from '@/components/pure/ms-table/type';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterRemoteMethodsEnum } from '@/enums/tableFilterEnum';
|
||||
import type { ResourceTypeMapKey } from '@/enums/taskCenter';
|
||||
import { TaskCenterEnum } from '@/enums/taskCenter';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const licenseStore = useLicenseStore();
|
||||
const { t } = useI18n();
|
||||
export const TaskStatus: Record<ResourceTypeMapKey, Record<string, { icon: string; label: string; color?: string }>> = {
|
||||
[TaskCenterEnum.API_CASE]: {
|
||||
SUCCESS: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
label: t('common.success'),
|
||||
},
|
||||
ERROR: {
|
||||
icon: 'icon-icon_close_colorful',
|
||||
label: t('common.fail'),
|
||||
},
|
||||
FAKE_ERROR: {
|
||||
icon: 'icon-icon_warning_colorful',
|
||||
label: t('common.fakeError'),
|
||||
},
|
||||
},
|
||||
[TaskCenterEnum.API_SCENARIO]: {
|
||||
SUCCESS: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
label: t('common.success'),
|
||||
},
|
||||
ERROR: {
|
||||
icon: 'icon-icon_close_colorful',
|
||||
label: t('common.fail'),
|
||||
},
|
||||
FAKE_ERROR: {
|
||||
icon: 'icon-icon_warning_colorful',
|
||||
label: t('common.fakeError'),
|
||||
},
|
||||
},
|
||||
[TaskCenterEnum.LOAD_TEST]: {
|
||||
STARTING: {
|
||||
icon: 'icon-icon_restarting',
|
||||
label: t('project.taskCenter.starting'),
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
RUNNING: {
|
||||
icon: 'icon-icon_testing',
|
||||
label: t('common.running'),
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
ERROR: {
|
||||
icon: 'icon-icon_close_colorful',
|
||||
label: t('common.fail'),
|
||||
},
|
||||
SUCCESS: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
label: t('common.success'),
|
||||
},
|
||||
COMPLETED: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
label: t('project.taskCenter.complete'),
|
||||
},
|
||||
STOPPED: {
|
||||
icon: 'icon-icon_block_filled',
|
||||
label: t('project.taskCenter.stop'),
|
||||
color: 'var(--color-text-input-border)',
|
||||
},
|
||||
},
|
||||
[TaskCenterEnum.UI_TEST]: {
|
||||
PENDING: {
|
||||
icon: 'icon-icon_wait',
|
||||
label: t('common.unExecute'),
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
RUNNING: {
|
||||
icon: 'icon-icon_testing',
|
||||
label: t('common.running'),
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
// RERUNNING: {
|
||||
// icon: 'icon-icon_testing',
|
||||
// label: t('project.taskCenter.rerun',
|
||||
// color: '!text-[rgb(var(--link-6))]',
|
||||
// },
|
||||
ERROR: {
|
||||
icon: 'icon-icon_close_colorful',
|
||||
label: t('common.fail'),
|
||||
},
|
||||
SUCCESS: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
label: t('common.success'),
|
||||
},
|
||||
STOPPED: {
|
||||
icon: 'icon-icon_block_filled',
|
||||
label: t('project.taskCenter.stop'),
|
||||
color: 'var(--color-text-input-border)',
|
||||
},
|
||||
},
|
||||
[TaskCenterEnum.TEST_PLAN]: {
|
||||
RUNNING: {
|
||||
icon: 'icon-icon_testing',
|
||||
label: t('common.unExecute'),
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
SUCCESS: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
label: t('common.success'),
|
||||
},
|
||||
STARTING: {
|
||||
icon: 'icon-icon_restarting',
|
||||
label: t('project.taskCenter.starting'),
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export type Group = 'system' | 'organization' | 'project';
|
||||
|
||||
export type ExtractedKeys = Extract<
|
||||
ResourceTypeMapKey,
|
||||
TaskCenterEnum.API_CASE | TaskCenterEnum.API_SCENARIO | TaskCenterEnum.TEST_PLAN
|
||||
>;
|
||||
|
||||
export const resourceTypeMap: Record<ResourceTypeMapKey, Record<string, any>> = {
|
||||
[TaskCenterEnum.API_CASE]: {
|
||||
value: TaskCenterEnum.API_CASE,
|
||||
label: t('project.taskCenter.interfaceCase'),
|
||||
},
|
||||
[TaskCenterEnum.API_SCENARIO]: {
|
||||
value: TaskCenterEnum.API_SCENARIO,
|
||||
label: t('project.taskCenter.apiScenario'),
|
||||
},
|
||||
[TaskCenterEnum.UI_TEST]: {
|
||||
value: TaskCenterEnum.UI_TEST,
|
||||
label: t('project.taskCenter.uiDefaultFile'),
|
||||
},
|
||||
[TaskCenterEnum.LOAD_TEST]: {
|
||||
value: TaskCenterEnum.LOAD_TEST,
|
||||
label: t('project.taskCenter.performanceTest'),
|
||||
},
|
||||
[TaskCenterEnum.TEST_PLAN]: {
|
||||
value: TaskCenterEnum.TEST_PLAN,
|
||||
label: t('project.taskCenter.testPlan'),
|
||||
},
|
||||
};
|
||||
|
||||
export function getOrgColumns(): MsTableColumnData {
|
||||
const config: MsTableColumnData = {
|
||||
title: 'project.belongOrganization',
|
||||
dataIndex: 'organizationIds',
|
||||
slotName: 'organizationName',
|
||||
showDrag: true,
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
};
|
||||
if (licenseStore.hasLicense()) {
|
||||
config.filterConfig = {
|
||||
mode: 'remote',
|
||||
remoteMethod: FilterRemoteMethodsEnum.SYSTEM_ORGANIZATION_LIST,
|
||||
placeholderText: t('project.taskCenter.filterOrgPlaceholderText'),
|
||||
};
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
export function getProjectColumns(key: TableKeyEnum): MsTableColumnData {
|
||||
const systemKey = [
|
||||
TableKeyEnum.TASK_API_CASE_SYSTEM,
|
||||
TableKeyEnum.TASK_SCHEDULE_TASK_API_IMPORT_SYSTEM,
|
||||
TableKeyEnum.TASK_SCHEDULE_TASK_API_SCENARIO_SYSTEM,
|
||||
];
|
||||
const filterKeyPermission = systemKey.includes(key)
|
||||
? hasAnyPermission(['SYSTEM_ORGANIZATION_PROJECT:READ'])
|
||||
: hasAnyPermission(['ORGANIZATION_PROJECT:READ']);
|
||||
const remoteMethod = systemKey.includes(key)
|
||||
? FilterRemoteMethodsEnum.SYSTEM_PROJECT_LIST
|
||||
: FilterRemoteMethodsEnum.SYSTEM_ORGANIZATION_PROJECT;
|
||||
|
||||
const config: MsTableColumnData = {
|
||||
title: 'project.belongProject',
|
||||
dataIndex: 'projectIds',
|
||||
slotName: 'projectName',
|
||||
showDrag: true,
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
};
|
||||
if (filterKeyPermission && remoteMethod) {
|
||||
config.filterConfig = {
|
||||
mode: 'remote',
|
||||
loadOptionParams: {
|
||||
organizationId: appStore.currentOrgId,
|
||||
},
|
||||
remoteMethod,
|
||||
placeholderText: t('project.taskCenter.filterProPlaceholderText'),
|
||||
};
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
export default {};
|
|
@ -1,44 +0,0 @@
|
|||
<template>
|
||||
<MsCard simple no-content-padding>
|
||||
<TaskCenter group="project" />
|
||||
</MsCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import TaskCenter from './component/taskCom.vue';
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.box {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
.left {
|
||||
padding: 24px;
|
||||
width: 252px;
|
||||
height: 100%;
|
||||
border-right: 1px solid var(--color-text-n8);
|
||||
.item {
|
||||
padding: 0 20px;
|
||||
height: 38px;
|
||||
font-size: 14px;
|
||||
line-height: 38px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
&.active {
|
||||
background: rgb(var(--primary-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
.right {
|
||||
width: calc(100% - 300px);
|
||||
flex-grow: 1; /* 自适应 */
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.no-content {
|
||||
:deep(.arco-tabs-content) {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,64 +0,0 @@
|
|||
export default {
|
||||
'project.taskCenter.interfaceCase': 'Interface use cases',
|
||||
'project.taskCenter.apiScenario': 'Interface scenario',
|
||||
'project.taskCenter.uiDefaultFile': 'UI testing',
|
||||
'project.taskCenter.performanceTest': 'Performance test',
|
||||
'project.taskCenter.testPlan': 'Test plan',
|
||||
'project.taskCenter.resourceID': 'Resource ID',
|
||||
'project.taskCenter.resourceName': 'resourceName',
|
||||
'project.taskCenter.executionResult': 'Execution result',
|
||||
'project.taskCenter.status': 'Execution status',
|
||||
'project.taskCenter.executionMode': 'Execution mode',
|
||||
'project.taskCenter.resourcePool': 'Resource pool',
|
||||
'project.taskCenter.operator': 'operator',
|
||||
'project.taskCenter.operating': 'Operating time',
|
||||
'project.taskCenter.batchStop': 'Batch stop',
|
||||
'project.taskCenter.batchExecution': 'Batch execution',
|
||||
'project.taskCenter.stop': 'stop',
|
||||
'project.taskCenter.execution': 'execution',
|
||||
'project.taskCenter.viewReport': 'Execution Result',
|
||||
'project.taskCenter.batchStopTask': 'Are you sure to stop {num} tasks?',
|
||||
'project.taskCenter.stopTask': 'Are you sure to stop {name} task?',
|
||||
'project.taskCenter.stopTaskContent':
|
||||
'Stopping will affect report generation, and the completed report cannot be stopped.',
|
||||
'project.taskCenter.confirmStop': 'Confirm stop',
|
||||
'project.taskCenter.stopSuccess': 'Stop successfully',
|
||||
'project.taskCenter.testResource': 'Test resource',
|
||||
'project.taskCenter.apiImport': 'API import',
|
||||
'project.taskCenter.resourceClassification': 'Resource Classification',
|
||||
'project.taskCenter.operationRule': 'Operation rule',
|
||||
'project.taskCenter.nextExecutionTime': 'Next execution time',
|
||||
'project.taskCenter.rerun': 'Rerun',
|
||||
'project.taskCenter.starting': 'Be starting',
|
||||
'project.taskCenter.complete': 'complete',
|
||||
'project.taskCenter.scheduledTask': 'Scheduled task',
|
||||
'project.taskCenter.manualExecution': 'Manual execution',
|
||||
'project.taskCenter.interfaceCall': 'Interface call',
|
||||
'project.taskCenter.realTimeTask': 'Real Time Task',
|
||||
'project.taskCenter.createTask': 'create',
|
||||
'project.taskCenter.apiCaseList': '{type} list',
|
||||
'project.taskCenter.delSchedule': 'Are you sure to delete the scheduled task?',
|
||||
'project.taskCenter.delScheduleSuccess': 'Delete scheduled task successfully',
|
||||
'project.taskCenter.delSchedule.tip':
|
||||
'Deleting the scheduled task will cause the task to stop. Do you want to continue?',
|
||||
'project.taskCenter.enableScheduleSuccess': 'Enable successfully',
|
||||
'project.taskCenter.disableScheduleSuccess': 'Disable successfully',
|
||||
'project.belongProject': 'Project',
|
||||
'project.belongOrganization': 'Organization',
|
||||
'project.taskCenter.batchEnable': 'Batch enable',
|
||||
'project.taskCenter.batchDisable': 'Batch disable',
|
||||
'project.taskCenter.batchEnableTask': 'Are you sure to enable {num} tasks?',
|
||||
'project.taskCenter.batchDisableTask': 'Are you sure to disable {num} tasks?',
|
||||
'project.taskCenter.batchEnableTaskContent': 'Enabling will execute the task',
|
||||
'project.taskCenter.batchDisableTaskContent': 'Closing will affect the execution of the task',
|
||||
'project.taskCenter.swaggerUrl': 'Swagger URL',
|
||||
'project.taskCenter.confirmEnable': 'Confirm enable',
|
||||
'project.taskCenter.confirmDisable': 'Confirm disable',
|
||||
'project.taskCenter.enableSuccess': 'Enable successfully',
|
||||
'project.taskCenter.disableSuccess': 'Disable successfully',
|
||||
'project.taskCenter.filterPlaceholderText': 'Please select a project',
|
||||
'project.taskCenter.filterOrgPlaceholderText': 'Please select an organization',
|
||||
'project.executionHistory.cleared': 'Execution result has been cleared',
|
||||
'project.taskCenter.plan': 'Plan',
|
||||
'project.taskCenter.planGroup': 'Plan group',
|
||||
};
|
|
@ -1,62 +0,0 @@
|
|||
export default {
|
||||
'project.taskCenter.interfaceCase': '接口用例',
|
||||
'project.taskCenter.apiScenario': '接口场景',
|
||||
'project.taskCenter.uiDefaultFile': 'UI 测试',
|
||||
'project.taskCenter.performanceTest': '性能测试',
|
||||
'project.taskCenter.testPlan': '测试计划',
|
||||
'project.taskCenter.resourceID': '资源 ID',
|
||||
'project.taskCenter.resourceName': '资源名称',
|
||||
'project.taskCenter.executionResult': '执行结果',
|
||||
'project.taskCenter.status': '执行状态',
|
||||
'project.taskCenter.executionMode': '执行方式',
|
||||
'project.taskCenter.resourcePool': '资源池',
|
||||
'project.taskCenter.operator': '操作人',
|
||||
'project.taskCenter.operating': '操作时间',
|
||||
'project.taskCenter.batchStop': '批量停止',
|
||||
'project.taskCenter.batchExecution': '批量执行',
|
||||
'project.taskCenter.stop': '停止',
|
||||
'project.taskCenter.execution': '执行',
|
||||
'project.taskCenter.viewReport': '执行结果',
|
||||
'project.taskCenter.batchStopTask': '确定停止 {num} 个任务吗?',
|
||||
'project.taskCenter.stopTask': '确定停止 {name} 吗?',
|
||||
'project.taskCenter.stopTaskContent': '停止后会影响报告的生成,执行完成的报告不可以停止',
|
||||
'project.taskCenter.confirmStop': '确认停止',
|
||||
'project.taskCenter.stopSuccess': '停止成功',
|
||||
'project.taskCenter.testResource': '测试资源',
|
||||
'project.taskCenter.apiImport': 'API 导入',
|
||||
'project.taskCenter.resourceClassification': '资源分类',
|
||||
'project.taskCenter.operationRule': '运行规则',
|
||||
'project.taskCenter.nextExecutionTime': '下次执行时间',
|
||||
'project.taskCenter.rerun': '重跑中',
|
||||
'project.taskCenter.starting': '启动中',
|
||||
'project.taskCenter.complete': '完成',
|
||||
'project.taskCenter.scheduledTask': '定时任务',
|
||||
'project.taskCenter.manualExecution': '手动执行',
|
||||
'project.taskCenter.interfaceCall': '接口调用',
|
||||
'project.taskCenter.realTimeTask': '实时任务',
|
||||
'project.taskCenter.createTask': '创建定时任务',
|
||||
'project.taskCenter.apiCaseList': '{type}列表',
|
||||
'project.taskCenter.delSchedule': '确定删除定时任务吗?',
|
||||
'project.taskCenter.delScheduleSuccess': '删除定时任务成功',
|
||||
'project.taskCenter.delSchedule.tip': '删除定时任务会导致任务停止,是否继续?',
|
||||
'project.taskCenter.enableScheduleSuccess': '已开启',
|
||||
'project.taskCenter.disableScheduleSuccess': '已关闭',
|
||||
'project.belongProject': '所属项目',
|
||||
'project.belongOrganization': '所属组织',
|
||||
'project.taskCenter.batchEnable': '批量开启',
|
||||
'project.taskCenter.batchDisable': '批量关闭',
|
||||
'project.taskCenter.batchEnableTask': '确定开启 {num} 个任务吗?',
|
||||
'project.taskCenter.batchDisableTask': '确定关闭 {num} 个任务吗?',
|
||||
'project.taskCenter.batchEnableTaskContent': '开启会执行任务',
|
||||
'project.taskCenter.batchDisableTaskContent': '关闭后会影响任务的执行',
|
||||
'project.taskCenter.swaggerUrl': 'Swagger URL',
|
||||
'project.taskCenter.confirmEnable': '确认开启',
|
||||
'project.taskCenter.confirmDisable': '确认关闭',
|
||||
'project.taskCenter.enableSuccess': '开启成功',
|
||||
'project.taskCenter.disableSuccess': '关闭成功',
|
||||
'project.taskCenter.filterProPlaceholderText': '请选择所属项目',
|
||||
'project.taskCenter.filterOrgPlaceholderText': '请选择所属组织',
|
||||
'project.executionHistory.cleared': '执行结果被清理',
|
||||
'project.taskCenter.plan': '计划',
|
||||
'project.taskCenter.planGroup': '计划组',
|
||||
};
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<MsCard simple no-content-padding>
|
||||
<TaskCenter group="organization" />
|
||||
<TaskCenter type="org" />
|
||||
</MsCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import TaskCenter from '@/views/project-management/taskCenter/component/taskCom.vue';
|
||||
import TaskCenter from '@/views/taskCenter/index.vue';
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<MsCard simple no-content-padding>
|
||||
<TaskCenter group="system" />
|
||||
<TaskCenter type="system" />
|
||||
</MsCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import TaskCenter from '@/views/project-management/taskCenter/component/taskCom.vue';
|
||||
import TaskCenter from '@/views/taskCenter/index.vue';
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
<template>
|
||||
<MsDrawer v-model:visible="visible" :title="title" :width="800" :footer="false">
|
||||
<ms-base-table v-bind="propsRes" ref="tableRef" v-on="propsEvent" @filter-change="filterChange">
|
||||
<template #name="{ record, rowIndex }">
|
||||
<a-button type="text" class="max-w-full justify-start px-0" @click="showReportDetail(record.id, rowIndex)">
|
||||
<div class="one-line-text">
|
||||
{{ record.num }}
|
||||
</div>
|
||||
</a-button>
|
||||
</template>
|
||||
<!-- 报告类型 -->
|
||||
<template #integrated="{ record }">
|
||||
<MsTag theme="light" :type="record.integrated ? 'primary' : undefined">
|
||||
{{ record.integrated ? t('report.collection') : t('report.independent') }}
|
||||
</MsTag>
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<ExecutionStatus
|
||||
:module-type="props.moduleType"
|
||||
:status="record.status"
|
||||
:script-identifier="props.moduleType === ReportEnum.API_SCENARIO_REPORT ? record.scriptIdentifier : null"
|
||||
/>
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.API_TEST_CASE_API_REPORT_STATUS]="{ filterContent }">
|
||||
<ExecutionStatus :module-type="props.moduleType" :status="filterContent.value" />
|
||||
</template>
|
||||
<template #execStatus="{ record }">
|
||||
<ExecStatus :status="record.execStatus" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.API_TEST_CASE_API_REPORT_EXECUTE_RESULT]="{ filterContent }">
|
||||
<ExecStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.API_TEST_REPORT_TYPE]="{ filterContent }">
|
||||
<MsTag theme="light" :type="filterContent.value ? 'primary' : undefined">
|
||||
{{ filterContent.value ? t('report.collection') : t('report.independent') }}
|
||||
</MsTag>
|
||||
</template>
|
||||
<template #triggerMode="{ record }">
|
||||
<span>{{ t(TriggerModeLabel[record.triggerMode as keyof typeof TriggerModeLabel]) }}</span>
|
||||
</template>
|
||||
<template #operationTime="{ record }">
|
||||
<span>{{ dayjs(record.operationTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
||||
import ExecStatus from '@/views/test-plan/report/component/execStatus.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useTableStore from '@/hooks/useTableStore';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import { ReportExecStatus } from '@/enums/apiEnum';
|
||||
import { ReportEnum, ReportStatus, TriggerModeLabel } from '@/enums/reportEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
const props = defineProps<{
|
||||
type: 'case' | 'scenario';
|
||||
moduleType: keyof typeof ReportEnum;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
const tableStore = useTableStore();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const visible = defineModel<boolean>('visible', { required: true });
|
||||
const title = computed(() =>
|
||||
props.type === 'case' ? t('ms.taskCenter.batchCaseTask') : t('ms.taskCenter.batchScenarioTask')
|
||||
);
|
||||
const keyword = ref<string>('');
|
||||
|
||||
type ReportShowType = 'All' | 'INDEPENDENT' | 'INTEGRATED';
|
||||
const showType = ref<ReportShowType>('All');
|
||||
|
||||
const typeFilter = computed(() => {
|
||||
if (showType.value === 'All') {
|
||||
return [];
|
||||
}
|
||||
return showType.value === 'INDEPENDENT' ? [false] : [true];
|
||||
});
|
||||
|
||||
const statusList = computed(() => {
|
||||
return Object.keys(ReportStatus).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: t(ReportStatus[key].label),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const ExecStatusList = computed(() => {
|
||||
return Object.values(ReportExecStatus).map((e) => {
|
||||
return {
|
||||
value: e,
|
||||
key: e,
|
||||
};
|
||||
});
|
||||
});
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'report.name',
|
||||
dataIndex: 'name',
|
||||
slotName: 'name',
|
||||
width: 300,
|
||||
showTooltip: true,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'report.type',
|
||||
slotName: 'integrated',
|
||||
dataIndex: 'integrated',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: 'report.result',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
filterConfig: {
|
||||
options: statusList.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_CASE_API_REPORT_STATUS,
|
||||
},
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'report.status',
|
||||
dataIndex: 'execStatus',
|
||||
slotName: 'execStatus',
|
||||
filterConfig: {
|
||||
options: ExecStatusList.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_CASE_API_REPORT_EXECUTE_RESULT,
|
||||
},
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'report.trigger.mode',
|
||||
dataIndex: 'triggerMode',
|
||||
slotName: 'triggerMode',
|
||||
showInTable: true,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: 'report.operator',
|
||||
slotName: 'createUserName',
|
||||
dataIndex: 'createUserName',
|
||||
showInTable: true,
|
||||
width: 300,
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'report.operating',
|
||||
dataIndex: 'startTime',
|
||||
slotName: 'startTime',
|
||||
width: 180,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
await tableStore.initColumn(TableKeyEnum.API_TEST_REPORT, columns, 'drawer');
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(
|
||||
() => Promise.resolve({ list: [], total: 0 }),
|
||||
{
|
||||
tableKey: TableKeyEnum.API_TEST_REPORT,
|
||||
scroll: {
|
||||
x: '100%',
|
||||
},
|
||||
heightUsed: 256,
|
||||
paginationSize: 'mini',
|
||||
},
|
||||
(item) => ({
|
||||
...item,
|
||||
startTime: dayjs(item.startTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
})
|
||||
);
|
||||
|
||||
function initData(dataIndex?: string, value?: string[] | (string | number | boolean)[] | undefined) {
|
||||
const filterParams = {
|
||||
...propsRes.value.filter,
|
||||
};
|
||||
if (dataIndex && value) {
|
||||
filterParams[dataIndex] = value;
|
||||
}
|
||||
setLoadListParams({
|
||||
keyword: keyword.value,
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleType: props.moduleType,
|
||||
filter: {
|
||||
integrated: typeFilter.value,
|
||||
...filterParams,
|
||||
},
|
||||
});
|
||||
loadList();
|
||||
}
|
||||
|
||||
function filterChange(dataIndex: string, value: string[] | (string | number | boolean)[] | undefined) {
|
||||
initData(dataIndex, value);
|
||||
}
|
||||
|
||||
function showReportDetail(id: string, rowIndex: number) {
|
||||
console.log(id, rowIndex);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -0,0 +1,135 @@
|
|||
<template>
|
||||
<MsDrawer v-model:visible="visible" :width="800" :footer="false">
|
||||
<template #title>
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<a-tag :color="executeResultMap[detail.executeResult]?.color">
|
||||
{{ t(executeResultMap[detail.executeResult]?.label) }}
|
||||
</a-tag>
|
||||
<div>{{ detail.name }}</div>
|
||||
</div>
|
||||
<div class="flex flex-1 justify-end">
|
||||
<MsButton type="icon" status="secondary" class="!rounded-[var(--border-radius-small)]" @click="refresh">
|
||||
<MsIcon type="icon-icon_reset_outlined" class="mr-[8px]" size="14" />
|
||||
{{ t('common.refresh') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
<MsDescription :descriptions="detail.description" :column="3" :line-gap="8" one-line-value>
|
||||
<template #value="{ item }">
|
||||
<execStatus v-if="item.key === 'status'" :status="item.value as ReportExecStatus" size="small" />
|
||||
<a-tooltip
|
||||
v-else
|
||||
:content="`${item.value}`"
|
||||
:disabled="item.value === undefined || item.value === null || item.value?.toString() === ''"
|
||||
:position="item.tooltipPosition ?? 'tl'"
|
||||
>
|
||||
<div class="w-[fit-content]">
|
||||
{{ item.value === undefined || item.value === null || item.value?.toString() === '' ? '-' : item.value }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</MsDescription>
|
||||
<div class="mt-[8px]">
|
||||
<StepDetailContent
|
||||
mode="tiled"
|
||||
show-type="CASE"
|
||||
:step-item="detail.scenarioDetail"
|
||||
:console="detail.console"
|
||||
:is-definition="true"
|
||||
:get-report-step-detail="props.getReportStepDetail"
|
||||
:report-id="detail.scenarioDetail?.reportId"
|
||||
/>
|
||||
</div>
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDescription, { Description } from '@/components/pure/ms-description/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import execStatus from './execStatus.vue';
|
||||
import StepDetailContent from '@/views/api-test/components/requestComposition/response/result/index.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { ReportExecStatus } from '@/enums/apiEnum';
|
||||
|
||||
import { executeResultMap } from './utils';
|
||||
|
||||
const props = defineProps<{
|
||||
id: string;
|
||||
getReportStepDetail?: (...args: any) => Promise<any>; // 获取步骤的详情内容接口
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const visible = defineModel<boolean>('visible', { required: true });
|
||||
const detail = ref<any>({ description: [] });
|
||||
|
||||
watch(
|
||||
() => props.id,
|
||||
async () => {
|
||||
if (props.id) {
|
||||
detail.value = {
|
||||
id: props.id,
|
||||
name: '测试用例名称',
|
||||
executeResult: 'SUCCESS',
|
||||
description: [
|
||||
{
|
||||
label: t('ms.taskCenter.executeStatus'),
|
||||
key: 'status',
|
||||
value: 'COMPLETED',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.operationUser'),
|
||||
value: 'admin',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.taskCreateTime'),
|
||||
value: dayjs(1626844800000).format('YYYY-MM-DD HH:mm:ss'),
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.taskResource'),
|
||||
value: '测试计划',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.threadID'),
|
||||
value: '1231231231',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.taskStartTime'),
|
||||
value: dayjs(1626844800000).format('YYYY-MM-DD HH:mm:ss'),
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.executeEnvInfo'),
|
||||
value: 'DEV 资源池1 10.11.1.1',
|
||||
class: '!w-[calc(100%/3*2)]',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.taskEndTime'),
|
||||
value: dayjs(1626844800000).format('YYYY-MM-DD HH:mm:ss'),
|
||||
},
|
||||
] as Description[],
|
||||
};
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function refresh() {
|
||||
console.log('refresh');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ms-description-item) {
|
||||
@apply items-center;
|
||||
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,419 @@
|
|||
<template>
|
||||
<div class="my-[16px] flex items-center justify-end gap-[12px]">
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="t('ms.taskCenter.search')"
|
||||
class="w-[240px]"
|
||||
allow-clear
|
||||
@search="searchTask"
|
||||
@press-enter="searchTask"
|
||||
@clear="searchTask"
|
||||
/>
|
||||
<MsCascader
|
||||
v-model:model-value="resourcePool"
|
||||
mode="native"
|
||||
:options="resourcePoolOptions"
|
||||
:placeholder="t('common.pleaseSelect')"
|
||||
option-size="small"
|
||||
label-key="value"
|
||||
value-key="key"
|
||||
class="w-[240px]"
|
||||
:prefix="t('ms.taskCenter.resourcePool')"
|
||||
@change="searchTask"
|
||||
>
|
||||
</MsCascader>
|
||||
<MsTag no-margin size="large" :tooltip-disabled="true" class="cursor-pointer" theme="outline" @click="searchTask">
|
||||
<MsIcon class="text-[16px] text-[var(color-text-4)]" :size="32" type="icon-icon_reset_outlined" />
|
||||
</MsTag>
|
||||
</div>
|
||||
<ms-base-table
|
||||
v-bind="propsRes"
|
||||
:action-config="tableBatchActions"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #executeStatus="{ record }">
|
||||
<execStatus :status="record.executeStatus" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_STATUS]="{ filterContent }">
|
||||
<execStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #executeResult="{ record }">
|
||||
<executionStatus :status="record.executeResult" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_RESULT]="{ filterContent }">
|
||||
<executionStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #node="{ record }">
|
||||
<div>{{ record.node }}</div>
|
||||
<a-tooltip :content="t('ms.taskCenter.nodeErrorTip')">
|
||||
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="stopTask(record)">
|
||||
{{ t('common.stop') }}
|
||||
</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="deleteTask(record)">
|
||||
{{ t('common.delete') }}
|
||||
</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="rerunTask(record)">
|
||||
{{ t('ms.taskCenter.rerun') }}
|
||||
</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="checkExecuteResult(record)">
|
||||
{{ t('ms.taskCenter.executeResult') }}
|
||||
</MsButton>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
<caseExecuteResultDrawer :id="executeResultId" v-model:visible="caseExecuteResultDrawerVisible" />
|
||||
<scenarioExecuteResultDrawer :id="executeResultId" v-model:visible="scenarioExecuteResultDrawerVisible" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import MsCascader from '@/components/business/ms-cascader/index.vue';
|
||||
import caseExecuteResultDrawer from './caseExecuteResultDrawer.vue';
|
||||
import execStatus from './execStatus.vue';
|
||||
import executionStatus from './executionStatus.vue';
|
||||
import scenarioExecuteResultDrawer from './scenarioExecuteResultDrawer.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import useTableStore from '@/hooks/useTableStore';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { executeMethodMap, executeResultMap, executeStatusMap } from './utils';
|
||||
|
||||
const props = defineProps<{
|
||||
type: 'system' | 'project' | 'org';
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openModal } = useModal();
|
||||
const tableStore = useTableStore();
|
||||
|
||||
const keyword = ref('');
|
||||
const resourcePool = ref([]);
|
||||
const resourcePoolOptions = ref([]);
|
||||
const tableSelected = ref<string[]>([]);
|
||||
const batchModalParams = ref();
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: t('ms.taskCenter.taskID'),
|
||||
dataIndex: 'num',
|
||||
width: 100,
|
||||
columnSelectorDisabled: true,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.taskName',
|
||||
dataIndex: 'name',
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.executeStatus',
|
||||
dataIndex: 'executeStatus',
|
||||
slotName: 'executeStatus',
|
||||
width: 100,
|
||||
filterConfig: {
|
||||
options: Object.keys(executeStatusMap).map((key) => ({
|
||||
label: t(executeStatusMap[key].label),
|
||||
value: key,
|
||||
})),
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_STATUS,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.executeMethod',
|
||||
dataIndex: 'executeMethod',
|
||||
width: 100,
|
||||
filterConfig: {
|
||||
options: Object.keys(executeMethodMap).map((key) => ({
|
||||
label: t(executeMethodMap[key]),
|
||||
value: key,
|
||||
})),
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_METHOD,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.executeResult',
|
||||
dataIndex: 'executeResult',
|
||||
slotName: 'executeResult',
|
||||
width: 100,
|
||||
filterConfig: {
|
||||
options: Object.keys(executeResultMap).map((key) => ({
|
||||
label: t(executeResultMap[key].label),
|
||||
value: key,
|
||||
icon: executeResultMap[key].icon,
|
||||
})),
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_RESULT,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.resourcePool',
|
||||
dataIndex: 'resourcePools',
|
||||
isStringTag: true,
|
||||
isTag: true,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.node',
|
||||
dataIndex: 'node',
|
||||
slotName: 'node',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.queue',
|
||||
dataIndex: 'queue',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.threadID',
|
||||
dataIndex: 'threadID',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.startExecuteTime',
|
||||
dataIndex: 'startExecuteTime',
|
||||
width: 170,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.endExecuteTime',
|
||||
dataIndex: 'endExecuteTime',
|
||||
width: 170,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
slotName: 'action',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: 220,
|
||||
},
|
||||
];
|
||||
|
||||
if (props.type === 'system') {
|
||||
columns.splice(1, 0, [
|
||||
{
|
||||
title: 'common.belongProject',
|
||||
dataIndex: 'belongProject',
|
||||
showTooltip: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'common.belongOrg',
|
||||
dataIndex: 'belongOrg',
|
||||
showTooltip: true,
|
||||
width: 100,
|
||||
},
|
||||
]);
|
||||
} else if (props.type === 'org') {
|
||||
columns.splice(1, 0, [
|
||||
{
|
||||
title: 'common.belongProject',
|
||||
dataIndex: 'belongProject',
|
||||
showTooltip: true,
|
||||
width: 100,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
await tableStore.initColumn(TableKeyEnum.TASK_CENTER_CASE_TASK_DETAIL, columns, 'drawer');
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'common.stop',
|
||||
eventTag: 'stop',
|
||||
},
|
||||
{
|
||||
label: 'ms.taskCenter.rerun',
|
||||
eventTag: 'rerun',
|
||||
},
|
||||
{
|
||||
label: 'common.delete',
|
||||
eventTag: 'delete',
|
||||
},
|
||||
],
|
||||
};
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
() =>
|
||||
Promise.resolve({
|
||||
list: [
|
||||
{
|
||||
id: '1',
|
||||
num: 10086,
|
||||
name: 'test',
|
||||
belongProject: 'test',
|
||||
belongOrg: 'test',
|
||||
executeStatus: 'PENDING',
|
||||
executeMethod: '手动执行',
|
||||
executeResult: 'SUCCESS',
|
||||
resourcePools: ['test'],
|
||||
node: '11.11.1',
|
||||
queue: '10',
|
||||
threadID: '1736',
|
||||
startExecuteTime: 1629782400000,
|
||||
endExecuteTime: 1629782400000,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
}),
|
||||
{
|
||||
tableKey: TableKeyEnum.TASK_CENTER_CASE_TASK_DETAIL,
|
||||
scroll: { x: '1000px' },
|
||||
selectable: true,
|
||||
heightUsed: 288,
|
||||
showSetting: true,
|
||||
size: 'default',
|
||||
},
|
||||
(item) => {
|
||||
return {
|
||||
...item,
|
||||
startExecuteTime: dayjs(item.startExecuteTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
endExecuteTime: dayjs(item.endExecuteTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
function searchTask() {
|
||||
setLoadListParams({ keyword: keyword.value, resourcePools: resourcePool.value });
|
||||
loadList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*/
|
||||
function deleteTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) {
|
||||
let title = t('ms.taskCenter.deleteTaskTitle', { name: characterLimit(record?.name) });
|
||||
let selectIds = [record?.id || ''];
|
||||
if (isBatch) {
|
||||
title = t('ms.taskCenter.deleteCaseTaskTitle', {
|
||||
count: params?.currentSelectCount || tableSelected.value.length,
|
||||
});
|
||||
selectIds = tableSelected.value as string[];
|
||||
}
|
||||
openModal({
|
||||
type: 'error',
|
||||
title,
|
||||
content: t('ms.taskCenter.deleteCaseTaskTip'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
maskClosable: false,
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
// await deleteUserInfo({
|
||||
// selectIds,
|
||||
// selectAll: !!params?.selectAll,
|
||||
// excludeIds: params?.excludeIds || [],
|
||||
// condition: { keyword: keyword.value },
|
||||
// });
|
||||
Message.success(t('common.deleteSuccess'));
|
||||
resetSelector();
|
||||
loadList();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function stopTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) {
|
||||
let title = t('ms.taskCenter.stopTaskTitle', { name: characterLimit(record?.name) });
|
||||
let selectIds = [record?.id || ''];
|
||||
if (isBatch) {
|
||||
title = t('ms.taskCenter.batchStopTaskTitle', {
|
||||
count: params?.currentSelectCount || tableSelected.value.length,
|
||||
});
|
||||
selectIds = tableSelected.value as string[];
|
||||
}
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title,
|
||||
content: t('ms.taskCenter.stopTimeTaskTip'),
|
||||
okText: t('common.stopConfirm'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
maskClosable: false,
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
// await deleteUserInfo({
|
||||
// selectIds,
|
||||
// selectAll: !!params?.selectAll,
|
||||
// excludeIds: params?.excludeIds || [],
|
||||
// condition: { keyword: keyword.value },
|
||||
// });
|
||||
Message.success(t('common.stopped'));
|
||||
resetSelector();
|
||||
loadList();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表格选中后批量操作
|
||||
* @param event 批量操作事件对象
|
||||
*/
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
batchModalParams.value = params;
|
||||
switch (event.eventTag) {
|
||||
case 'delete':
|
||||
deleteTask(undefined, true, params);
|
||||
break;
|
||||
case 'stop':
|
||||
stopTask(undefined, true, params);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function rerunTask(record: any) {
|
||||
console.log('rerunTask', record);
|
||||
}
|
||||
|
||||
const executeResultId = ref('');
|
||||
const caseExecuteResultDrawerVisible = ref(false);
|
||||
const scenarioExecuteResultDrawerVisible = ref(false);
|
||||
function checkExecuteResult(record: any) {
|
||||
executeResultId.value = record.id;
|
||||
scenarioExecuteResultDrawerVisible.value = true;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -0,0 +1,487 @@
|
|||
<template>
|
||||
<div class="my-[16px] flex items-center justify-end">
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="t('ms.taskCenter.search')"
|
||||
class="mr-[12px] w-[240px]"
|
||||
allow-clear
|
||||
@search="searchTask"
|
||||
@press-enter="searchTask"
|
||||
@clear="searchTask"
|
||||
/>
|
||||
<MsTag no-margin size="large" :tooltip-disabled="true" class="cursor-pointer" theme="outline" @click="searchTask">
|
||||
<MsIcon class="text-[16px] text-[var(color-text-4)]" :size="32" type="icon-icon_reset_outlined" />
|
||||
</MsTag>
|
||||
</div>
|
||||
<ms-base-table
|
||||
v-bind="propsRes"
|
||||
:action-config="tableBatchActions"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #num="{ record }">
|
||||
<a-button type="text" class="max-w-full justify-start px-0" @click="showTaskDetail(record.id)">
|
||||
<div class="one-line-text">
|
||||
{{ record.num }}
|
||||
</div>
|
||||
</a-button>
|
||||
</template>
|
||||
<template #executeStatus="{ record }">
|
||||
<execStatus :status="record.executeStatus" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_STATUS]="{ filterContent }">
|
||||
<execStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #executeResult="{ record }">
|
||||
<executionStatus :status="record.executeResult" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_RESULT]="{ filterContent }">
|
||||
<executionStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #executeFinishedRate="{ record }">
|
||||
<a-popover trigger="hover" position="bottom">
|
||||
<div>{{ record.executeFinishedRate }}</div>
|
||||
<template #content>
|
||||
<div class="flex w-[130px] flex-col gap-[8px]">
|
||||
<div class="ms-taskCenter-execute-rate-item">
|
||||
<div class="ms-taskCenter-execute-rate-item-label">{{ t('ms.taskCenter.passThreshold') }}</div>
|
||||
<div class="ms-taskCenter-execute-rate-item-value">{{ record.passThreshold }}</div>
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item">
|
||||
<div class="ms-taskCenter-execute-rate-item-label">
|
||||
{{ record.testPlanId ? t('ms.taskCenter.executeFinishedRate') : t('ms.taskCenter.executeProgress') }}
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item-value">
|
||||
{{ `${((record.unExecuteCount / record.caseCount) * 100).toFixed(2)}%` }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item">
|
||||
<div class="ms-taskCenter-execute-rate-item-label">
|
||||
<div
|
||||
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.UN_EXECUTE.color}]`"
|
||||
></div>
|
||||
{{ t(executeFinishedRateMap.UN_EXECUTE.label) }}
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item-value">{{ record.unExecuteCount }}</div>
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item">
|
||||
<div class="ms-taskCenter-execute-rate-item-label">
|
||||
<div
|
||||
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.SUCCESS.color}]`"
|
||||
></div>
|
||||
{{ t(executeFinishedRateMap.SUCCESS.label) }}
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item-value">{{ record.successCount }}</div>
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item">
|
||||
<div class="ms-taskCenter-execute-rate-item-label">
|
||||
<div
|
||||
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.FAKE_ERROR.color}]`"
|
||||
></div>
|
||||
{{ t(executeFinishedRateMap.FAKE_ERROR.label) }}
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item-value">{{ record.fakeErrorCount }}</div>
|
||||
</div>
|
||||
<div v-if="record.testPlanId" class="ms-taskCenter-execute-rate-item">
|
||||
<div class="ms-taskCenter-execute-rate-item-label">
|
||||
<div
|
||||
:class="`ms-taskCenter-execute-rate-item-label-point`"
|
||||
:style="{ backgroundColor: executeFinishedRateMap.BLOCK.color }"
|
||||
></div>
|
||||
{{ t(executeFinishedRateMap.BLOCK.label) }}
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item-value">{{ record.blockCount }}</div>
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item">
|
||||
<div class="ms-taskCenter-execute-rate-item-label">
|
||||
<div
|
||||
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.ERROR.color}]`"
|
||||
></div>
|
||||
{{ t(executeFinishedRateMap.ERROR.label) }}
|
||||
</div>
|
||||
<div class="ms-taskCenter-execute-rate-item-value">{{ record.errorCount }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="stopTask(record)">
|
||||
{{ t('common.stop') }}
|
||||
</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="deleteTask(record)">
|
||||
{{ t('common.delete') }}
|
||||
</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="rerunTask(record)">
|
||||
{{ t('ms.taskCenter.rerun') }}
|
||||
</MsButton>
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="checkReport(record)">
|
||||
{{ t('ms.taskCenter.checkReport') }}
|
||||
</MsButton>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import execStatus from './execStatus.vue';
|
||||
import executionStatus from './executionStatus.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import useTableStore from '@/hooks/useTableStore';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { executeFinishedRateMap, executeMethodMap, executeResultMap, executeStatusMap } from './utils';
|
||||
|
||||
const props = defineProps<{
|
||||
type: 'system' | 'project' | 'org';
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openModal } = useModal();
|
||||
const tableStore = useTableStore();
|
||||
|
||||
const keyword = ref('');
|
||||
const tableSelected = ref<string[]>([]);
|
||||
const batchModalParams = ref();
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'num',
|
||||
slotName: 'num',
|
||||
width: 100,
|
||||
columnSelectorDisabled: true,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.taskName',
|
||||
dataIndex: 'name',
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.executeStatus',
|
||||
dataIndex: 'executeStatus',
|
||||
slotName: 'executeStatus',
|
||||
width: 90,
|
||||
filterConfig: {
|
||||
options: Object.keys(executeStatusMap).map((key) => ({
|
||||
label: t(executeStatusMap[key].label),
|
||||
value: key,
|
||||
})),
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_STATUS,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.executeMethod',
|
||||
dataIndex: 'executeMethod',
|
||||
width: 90,
|
||||
filterConfig: {
|
||||
options: Object.keys(executeMethodMap).map((key) => ({
|
||||
label: t(executeMethodMap[key]),
|
||||
value: key,
|
||||
})),
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_METHOD,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.executeResult',
|
||||
dataIndex: 'executeResult',
|
||||
slotName: 'executeResult',
|
||||
width: 90,
|
||||
filterConfig: {
|
||||
options: Object.keys(executeResultMap).map((key) => ({
|
||||
label: t(executeResultMap[key].label),
|
||||
value: key,
|
||||
icon: executeResultMap[key].icon,
|
||||
})),
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_TASK_CENTER_EXEC_RESULT,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.caseCount',
|
||||
dataIndex: 'caseCount',
|
||||
width: 90,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.executeFinishedRate',
|
||||
dataIndex: 'executeFinishedRate',
|
||||
slotName: 'executeFinishedRate',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.createTime',
|
||||
dataIndex: 'createTime',
|
||||
width: 170,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.startTime',
|
||||
dataIndex: 'startTime',
|
||||
width: 170,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.endTime',
|
||||
dataIndex: 'endTime',
|
||||
width: 170,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
slotName: 'action',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: 220,
|
||||
},
|
||||
];
|
||||
|
||||
if (props.type === 'system') {
|
||||
columns.splice(
|
||||
1,
|
||||
0,
|
||||
{
|
||||
title: 'common.belongProject',
|
||||
dataIndex: 'belongProject',
|
||||
showTooltip: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'common.belongOrg',
|
||||
dataIndex: 'belongOrg',
|
||||
showTooltip: true,
|
||||
width: 100,
|
||||
}
|
||||
);
|
||||
} else if (props.type === 'org') {
|
||||
columns.splice(1, 0, {
|
||||
title: 'common.belongProject',
|
||||
dataIndex: 'belongProject',
|
||||
showTooltip: true,
|
||||
width: 100,
|
||||
});
|
||||
}
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'common.stop',
|
||||
eventTag: 'stop',
|
||||
},
|
||||
{
|
||||
label: 'ms.taskCenter.rerun',
|
||||
eventTag: 'rerun',
|
||||
},
|
||||
{
|
||||
label: 'common.delete',
|
||||
eventTag: 'delete',
|
||||
},
|
||||
],
|
||||
};
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
() =>
|
||||
Promise.resolve({
|
||||
list: [
|
||||
{
|
||||
id: '1',
|
||||
num: 10086,
|
||||
name: '测试任务',
|
||||
belongProject: '测试项目',
|
||||
belongOrg: '测试组织',
|
||||
executeStatus: 'PENDING',
|
||||
executeMethod: '手动执行',
|
||||
executeResult: 'SUCCESS',
|
||||
caseCount: 100,
|
||||
executeFinishedRate: '100%',
|
||||
startTime: 1630000000000,
|
||||
createTime: 1630000000000,
|
||||
endTime: 1630000000000,
|
||||
passThreshold: '100%',
|
||||
unExecuteCount: 0,
|
||||
successCount: 100,
|
||||
fakeErrorCount: 0,
|
||||
blockCount: 0,
|
||||
errorCount: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
}),
|
||||
{
|
||||
tableKey: TableKeyEnum.TASK_CENTER_CASE_TASK,
|
||||
scroll: { x: '1000px' },
|
||||
selectable: true,
|
||||
showSetting: true,
|
||||
showPagination: true,
|
||||
},
|
||||
(item) => {
|
||||
return {
|
||||
...item,
|
||||
startTime: dayjs(item.startTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
createTime: dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
endTime: dayjs(item.endTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
function searchTask() {
|
||||
setLoadListParams({ keyword: keyword.value });
|
||||
loadList();
|
||||
}
|
||||
|
||||
function showTaskDetail(id: string) {
|
||||
console.log('showTaskDetail', id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*/
|
||||
function deleteTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) {
|
||||
let title = t('ms.taskCenter.deleteTaskTitle', { name: characterLimit(record?.name) });
|
||||
let selectIds = [record?.id || ''];
|
||||
if (isBatch) {
|
||||
title = t('ms.taskCenter.deleteCaseTaskTitle', {
|
||||
count: params?.currentSelectCount || tableSelected.value.length,
|
||||
});
|
||||
selectIds = tableSelected.value as string[];
|
||||
}
|
||||
openModal({
|
||||
type: 'error',
|
||||
title,
|
||||
content: t('ms.taskCenter.deleteCaseTaskTip'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
maskClosable: false,
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
// await deleteUserInfo({
|
||||
// selectIds,
|
||||
// selectAll: !!params?.selectAll,
|
||||
// excludeIds: params?.excludeIds || [],
|
||||
// condition: { keyword: keyword.value },
|
||||
// });
|
||||
Message.success(t('common.deleteSuccess'));
|
||||
resetSelector();
|
||||
loadList();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function stopTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) {
|
||||
let title = t('ms.taskCenter.stopTaskTitle', { name: characterLimit(record?.name) });
|
||||
let selectIds = [record?.id || ''];
|
||||
if (isBatch) {
|
||||
title = t('ms.taskCenter.batchStopTaskTitle', {
|
||||
count: params?.currentSelectCount || tableSelected.value.length,
|
||||
});
|
||||
selectIds = tableSelected.value as string[];
|
||||
}
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title,
|
||||
content: t('ms.taskCenter.stopTimeTaskTip'),
|
||||
okText: t('common.stopConfirm'),
|
||||
cancelText: t('common.cancel'),
|
||||
maskClosable: false,
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
// await deleteUserInfo({
|
||||
// selectIds,
|
||||
// selectAll: !!params?.selectAll,
|
||||
// excludeIds: params?.excludeIds || [],
|
||||
// condition: { keyword: keyword.value },
|
||||
// });
|
||||
Message.success(t('common.stopped'));
|
||||
resetSelector();
|
||||
loadList();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表格选中后批量操作
|
||||
* @param event 批量操作事件对象
|
||||
*/
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
tableSelected.value = params.selectedIds || [];
|
||||
batchModalParams.value = params;
|
||||
switch (event.eventTag) {
|
||||
case 'delete':
|
||||
deleteTask(undefined, true, params);
|
||||
break;
|
||||
case 'stop':
|
||||
stopTask(undefined, true, params);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function rerunTask(record: any) {
|
||||
console.log('rerunTask', record);
|
||||
}
|
||||
|
||||
function checkReport(record: any) {
|
||||
console.log('checkReport', record);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadList();
|
||||
});
|
||||
|
||||
await tableStore.initColumn(TableKeyEnum.TASK_CENTER_CASE_TASK, columns, 'drawer');
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ms-taskCenter-execute-rate-item {
|
||||
@apply flex items-center justify-between;
|
||||
.ms-taskCenter-execute-rate-item-label {
|
||||
@apply flex items-center;
|
||||
|
||||
gap: 4px;
|
||||
color: var(--color-text-4);
|
||||
.ms-taskCenter-execute-rate-item-label-point {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
.ms-taskCenter-execute-rate-item-value {
|
||||
font-weight: 500;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<a-tag
|
||||
:color="executeStatusMap[props.status]?.color"
|
||||
:class="executeStatusMap[props.status]?.class"
|
||||
:size="props.size"
|
||||
>
|
||||
{{ t(executeStatusMap[props.status]?.label) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { ReportExecStatus } from '@/enums/apiEnum';
|
||||
|
||||
import { executeStatusMap } from './utils';
|
||||
|
||||
const props = defineProps<{
|
||||
status: ReportExecStatus;
|
||||
size?: 'small' | 'medium' | 'large';
|
||||
}>();
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<div class="flex items-center justify-start">
|
||||
<MsIcon :type="getExecutionResult().icon" :class="`text-[${getExecutionResult()?.color}]`" size="14" />
|
||||
<span class="ml-1">{{ t(getExecutionResult().label) }}</span>
|
||||
<!-- <a-tooltip v-if="props.scriptIdentifier" :content="getMsg()">
|
||||
<MsTag
|
||||
class="ml-2"
|
||||
:self-style="{
|
||||
border: `1px solid ${methodColor}`,
|
||||
color: methodColor,
|
||||
backgroundColor: 'white',
|
||||
}"
|
||||
>
|
||||
{{ t('report.detail.script.error') }}
|
||||
</MsTag>
|
||||
</a-tooltip> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { TaskCenterEnum } from '@/enums/taskCenter';
|
||||
|
||||
import { executeResultMap } from './utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
status: string;
|
||||
scriptIdentifier?: string;
|
||||
}>();
|
||||
|
||||
export interface IconType {
|
||||
icon: string;
|
||||
label: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
function getExecutionResult(): IconType {
|
||||
return executeResultMap[props.status] ? executeResultMap[props.status] : executeResultMap.DEFAULT;
|
||||
}
|
||||
const methodColor = 'rgb(var(--warning-7))';
|
||||
|
||||
// function getMsg() {
|
||||
// if (props.moduleType === TaskCenterEnum.CASE && props.scriptIdentifier) {
|
||||
// return t('report.detail.scenario.errorTip');
|
||||
// }
|
||||
// return t('report.detail.api.errorTip');
|
||||
// }
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -0,0 +1,163 @@
|
|||
<template>
|
||||
<MsDrawer v-model:visible="visible" :width="800" :footer="false">
|
||||
<template #title>
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<a-tag :color="executeResultMap[detail.executeResult]?.color">
|
||||
{{ t(executeResultMap[detail.executeResult]?.label) }}
|
||||
</a-tag>
|
||||
<div>{{ detail.name }}</div>
|
||||
</div>
|
||||
<div class="flex flex-1 justify-end">
|
||||
<MsButton type="icon" status="secondary" class="!rounded-[var(--border-radius-small)]" @click="refresh">
|
||||
<MsIcon type="icon-icon_reset_outlined" class="mr-[8px]" size="14" />
|
||||
{{ t('common.refresh') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
<MsDescription :descriptions="detail.description" :column="3" :line-gap="8" one-line-value>
|
||||
<template #value="{ item }">
|
||||
<execStatus v-if="item.key === 'status'" :status="item.value as ReportExecStatus" size="small" />
|
||||
<a-tooltip
|
||||
v-else
|
||||
:content="`${item.value}`"
|
||||
:disabled="item.value === undefined || item.value === null || item.value?.toString() === ''"
|
||||
:position="item.tooltipPosition ?? 'tl'"
|
||||
>
|
||||
<div class="w-[fit-content]">
|
||||
{{ item.value === undefined || item.value === null || item.value?.toString() === '' ? '-' : item.value }}
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</MsDescription>
|
||||
<div class="mt-[8px]">
|
||||
<reportInfoHeader
|
||||
v-model:keywordName="keywordName"
|
||||
v-model:keyword="cascaderKeywords"
|
||||
v-model:active-tab="activeTab"
|
||||
show-type="API"
|
||||
@search="searchHandler"
|
||||
@reset="resetHandler"
|
||||
/>
|
||||
<TiledList
|
||||
ref="tiledListRef"
|
||||
v-model:keyword-name="keywordName"
|
||||
:key-words="cascaderKeywords"
|
||||
show-type="API"
|
||||
:get-report-step-detail="props.getReportStepDetail"
|
||||
:active-type="activeTab"
|
||||
:report-detail="detail || []"
|
||||
class="p-[16px]"
|
||||
/>
|
||||
</div>
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDescription, { Description } from '@/components/pure/ms-description/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import execStatus from './execStatus.vue';
|
||||
import reportInfoHeader from '@/views/api-test/report/component/step/reportInfoHeaders.vue';
|
||||
import TiledList from '@/views/api-test/report/component/tiledList.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { ReportExecStatus } from '@/enums/apiEnum';
|
||||
|
||||
import { executeResultMap } from './utils';
|
||||
|
||||
const props = defineProps<{
|
||||
id: string;
|
||||
getReportStepDetail?: (...args: any) => Promise<any>; // 获取步骤的详情内容接口
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const visible = defineModel<boolean>('visible', { required: true });
|
||||
const detail = ref<any>({ description: [], children: [] });
|
||||
|
||||
watch(
|
||||
() => props.id,
|
||||
async () => {
|
||||
if (props.id) {
|
||||
detail.value = {
|
||||
id: props.id,
|
||||
name: '测试用例名称',
|
||||
executeResult: 'SUCCESS',
|
||||
description: [
|
||||
{
|
||||
label: t('ms.taskCenter.executeStatus'),
|
||||
key: 'status',
|
||||
value: 'COMPLETED',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.operationUser'),
|
||||
value: 'admin',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.taskCreateTime'),
|
||||
value: dayjs(1626844800000).format('YYYY-MM-DD HH:mm:ss'),
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.taskResource'),
|
||||
value: '测试计划',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.threadID'),
|
||||
value: '1231231231',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.taskStartTime'),
|
||||
value: dayjs(1626844800000).format('YYYY-MM-DD HH:mm:ss'),
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.executeEnvInfo'),
|
||||
value: 'DEV 资源池1 10.11.1.1',
|
||||
class: '!w-[calc(100%/3*2)]',
|
||||
},
|
||||
{
|
||||
label: t('ms.taskCenter.taskEndTime'),
|
||||
value: dayjs(1626844800000).format('YYYY-MM-DD HH:mm:ss'),
|
||||
},
|
||||
] as Description[],
|
||||
children: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const cascaderKeywords = ref<string>('');
|
||||
const keywordName = ref<string>('');
|
||||
const activeTab = ref<'tiled' | 'tab'>('tiled');
|
||||
const tiledListRef = ref<InstanceType<typeof TiledList>>();
|
||||
|
||||
function searchHandler() {
|
||||
if (keywordName.value) {
|
||||
tiledListRef.value?.updateDebouncedSearch();
|
||||
} else {
|
||||
tiledListRef.value?.initStepTree();
|
||||
}
|
||||
}
|
||||
|
||||
function resetHandler() {
|
||||
tiledListRef.value?.initStepTree();
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
console.log('refresh');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ms-description-item) {
|
||||
@apply items-center;
|
||||
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,258 @@
|
|||
<template>
|
||||
<div class="my-[16px] flex items-center justify-end">
|
||||
<a-input-search
|
||||
v-model:model-value="keyword"
|
||||
:placeholder="t('ms.taskCenter.search')"
|
||||
class="mr-[12px] w-[240px]"
|
||||
allow-clear
|
||||
@search="searchTask"
|
||||
@press-enter="searchTask"
|
||||
@clear="searchTask"
|
||||
/>
|
||||
<MsTag no-margin size="large" :tooltip-disabled="true" class="cursor-pointer" theme="outline" @click="searchTask">
|
||||
<MsIcon class="text-[16px] text-[var(color-text-4)]" :size="32" type="icon-icon_reset_outlined" />
|
||||
</MsTag>
|
||||
</div>
|
||||
<ms-base-table
|
||||
v-bind="propsRes"
|
||||
:action-config="tableBatchActions"
|
||||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #status="{ record }">
|
||||
<a-switch v-model:model-value="record.enable" size="small"></a-switch>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="deleteTask(record)">
|
||||
{{ t('common.delete') }}
|
||||
</MsButton>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import useTableStore from '@/hooks/useTableStore';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openModal } = useModal();
|
||||
const tableStore = useTableStore();
|
||||
|
||||
const keyword = ref('');
|
||||
const tableSelected = ref<string[]>([]);
|
||||
const batchModalParams = ref();
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'num',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.taskName',
|
||||
dataIndex: 'name',
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'common.status',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.type',
|
||||
dataIndex: 'type',
|
||||
slotName: 'type',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.runRule',
|
||||
dataIndex: 'rule',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.operationUser',
|
||||
dataIndex: 'operationUser',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.operationTime',
|
||||
dataIndex: 'operationTime',
|
||||
width: 170,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.lastFinishTime',
|
||||
dataIndex: 'lastFinishTime',
|
||||
width: 170,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'ms.taskCenter.nextExecuteTime',
|
||||
dataIndex: 'nextExecuteTime',
|
||||
width: 170,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
slotName: 'action',
|
||||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
width: 60,
|
||||
},
|
||||
];
|
||||
await tableStore.initColumn(TableKeyEnum.TASK_CENTER_SYSTEM_TASK, columns, 'drawer');
|
||||
|
||||
const tableBatchActions = {
|
||||
baseAction: [
|
||||
{
|
||||
label: 'common.open',
|
||||
eventTag: 'open',
|
||||
},
|
||||
{
|
||||
label: 'common.close',
|
||||
eventTag: 'close',
|
||||
},
|
||||
],
|
||||
};
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
() =>
|
||||
Promise.resolve({
|
||||
list: [
|
||||
{
|
||||
id: '1',
|
||||
num: 10086,
|
||||
name: '测试任务',
|
||||
status: 'success',
|
||||
type: 'API 导入',
|
||||
rule: '每 1 小时',
|
||||
enable: true,
|
||||
operationUser: 'admin',
|
||||
operationTime: '2021-09-01 12:00:00',
|
||||
lastFinishTime: '2021-09-01 12:00:00',
|
||||
nextExecuteTime: '2021-09-01 12:00:00',
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
}),
|
||||
{
|
||||
tableKey: TableKeyEnum.TASK_CENTER_SYSTEM_TASK,
|
||||
scroll: { x: '100%' },
|
||||
selectable: true,
|
||||
heightUsed: 288,
|
||||
showSetting: true,
|
||||
size: 'default',
|
||||
},
|
||||
(item) => {
|
||||
return {
|
||||
...item,
|
||||
operationTime: dayjs(item.operationTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
lastFinishTime: dayjs(item.lastFinishTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
nextExecuteTime: dayjs(item.nextExecuteTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
function searchTask() {
|
||||
setLoadListParams({ keyword: keyword.value });
|
||||
loadList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*/
|
||||
function deleteTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) {
|
||||
let title = t('ms.taskCenter.deleteTaskTitle', { name: characterLimit(record?.name) });
|
||||
let selectIds = [record?.id || ''];
|
||||
if (isBatch) {
|
||||
title = t('ms.taskCenter.deleteTimeTaskTitle', {
|
||||
count: params?.currentSelectCount || tableSelected.value.length,
|
||||
});
|
||||
selectIds = tableSelected.value as string[];
|
||||
}
|
||||
openModal({
|
||||
type: 'error',
|
||||
title,
|
||||
content: t('ms.taskCenter.deleteTimeTaskTip'),
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
maskClosable: false,
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
// await deleteUserInfo({
|
||||
// selectIds,
|
||||
// selectAll: !!params?.selectAll,
|
||||
// excludeIds: params?.excludeIds || [],
|
||||
// condition: { keyword: keyword.value },
|
||||
// });
|
||||
Message.success(t('common.deleteSuccess'));
|
||||
resetSelector();
|
||||
loadList();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
|
||||
function openTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) {
|
||||
console.log(record);
|
||||
}
|
||||
|
||||
function closeTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) {
|
||||
console.log(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表格选中后批量操作
|
||||
* @param event 批量操作事件对象
|
||||
*/
|
||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
batchModalParams.value = params;
|
||||
switch (event.eventTag) {
|
||||
case 'open':
|
||||
openTask(undefined, true, params);
|
||||
break;
|
||||
case 'close':
|
||||
closeTask(undefined, true, params);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -0,0 +1,148 @@
|
|||
import type { MsTableColumnData } from '@/components/pure/ms-table/type';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import useLicenseStore from '@/store/modules/setting/license';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterRemoteMethodsEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// 执行结果
|
||||
export const executeResultMap: Record<string, any> = {
|
||||
SUCCESS: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
label: 'common.success',
|
||||
color: 'rgb(var(--success-6))',
|
||||
},
|
||||
ERROR: {
|
||||
icon: 'icon-icon_close_colorful',
|
||||
label: 'common.fail',
|
||||
color: 'rgb(var(--danger-6))',
|
||||
},
|
||||
FAKE_ERROR: {
|
||||
icon: 'icon-icon_warning_colorful',
|
||||
label: 'common.fakeError',
|
||||
color: 'rgb(var(--warning-6))',
|
||||
},
|
||||
};
|
||||
|
||||
// 执行完成率
|
||||
export const executeFinishedRateMap: Record<string, any> = {
|
||||
SUCCESS: {
|
||||
label: 'common.success',
|
||||
color: 'rgb(var(--success-6))',
|
||||
},
|
||||
ERROR: {
|
||||
label: 'common.fail',
|
||||
color: 'rgb(var(--danger-6))',
|
||||
},
|
||||
FAKE_ERROR: {
|
||||
label: 'common.fakeError',
|
||||
color: 'rgb(var(--warning-6))',
|
||||
},
|
||||
BLOCK: {
|
||||
label: 'common.block',
|
||||
color: 'rgb(179,121,200)',
|
||||
},
|
||||
UN_EXECUTE: {
|
||||
label: 'common.unExecute',
|
||||
color: 'var(--color-text-4)',
|
||||
},
|
||||
};
|
||||
|
||||
// 执行状态
|
||||
export const executeStatusMap: Record<string, any> = {
|
||||
PENDING: {
|
||||
label: 'common.unExecute',
|
||||
color: 'var(--color-text-n8)',
|
||||
class: '!text-[var(--color-text-1)]',
|
||||
},
|
||||
RUNNING: {
|
||||
label: 'common.running',
|
||||
color: 'rgb(var(--link-2))',
|
||||
class: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
STOPPED: {
|
||||
label: 'common.stopped',
|
||||
color: 'rgb(var(--warning-2))',
|
||||
class: '!text-[rgb(var(--warning-6))]',
|
||||
},
|
||||
COMPLETED: {
|
||||
label: 'common.completed',
|
||||
color: 'rgb(var(--success-2))',
|
||||
class: '!text-[rgb(var(--success-6))]',
|
||||
},
|
||||
RERUNNING: {
|
||||
label: 'ms.taskCenter.failRerun',
|
||||
color: 'rgb(var(--link-2))',
|
||||
class: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
};
|
||||
|
||||
// 执行方式
|
||||
export const executeMethodMap: Record<string, any> = {
|
||||
MANUAL: 'ms.taskCenter.execute',
|
||||
BATCH: 'ms.taskCenter.batchExecute',
|
||||
API: 'ms.taskCenter.interfaceCall',
|
||||
SCHEDULE: 'ms.taskCenter.scheduledTask',
|
||||
};
|
||||
|
||||
export type Group = 'system' | 'organization' | 'project';
|
||||
|
||||
export function getOrgColumns(): MsTableColumnData {
|
||||
const licenseStore = useLicenseStore();
|
||||
const config: MsTableColumnData = {
|
||||
title: 'project.belongOrganization',
|
||||
dataIndex: 'organizationIds',
|
||||
slotName: 'organizationName',
|
||||
showDrag: true,
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
};
|
||||
if (licenseStore.hasLicense()) {
|
||||
config.filterConfig = {
|
||||
mode: 'remote',
|
||||
remoteMethod: FilterRemoteMethodsEnum.SYSTEM_ORGANIZATION_LIST,
|
||||
placeholderText: t('project.taskCenter.filterOrgPlaceholderText'),
|
||||
};
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
export function getProjectColumns(key: TableKeyEnum): MsTableColumnData {
|
||||
const appStore = useAppStore();
|
||||
const systemKey = [
|
||||
TableKeyEnum.TASK_CENTER_CASE_TASK,
|
||||
TableKeyEnum.TASK_SCHEDULE_TASK_API_IMPORT_SYSTEM,
|
||||
TableKeyEnum.TASK_SCHEDULE_TASK_API_SCENARIO_SYSTEM,
|
||||
];
|
||||
const filterKeyPermission = systemKey.includes(key)
|
||||
? hasAnyPermission(['SYSTEM_ORGANIZATION_PROJECT:READ'])
|
||||
: hasAnyPermission(['ORGANIZATION_PROJECT:READ']);
|
||||
const remoteMethod = systemKey.includes(key)
|
||||
? FilterRemoteMethodsEnum.SYSTEM_PROJECT_LIST
|
||||
: FilterRemoteMethodsEnum.SYSTEM_ORGANIZATION_PROJECT;
|
||||
|
||||
const config: MsTableColumnData = {
|
||||
title: 'project.belongProject',
|
||||
dataIndex: 'projectIds',
|
||||
slotName: 'projectName',
|
||||
showDrag: true,
|
||||
width: 200,
|
||||
showInTable: true,
|
||||
};
|
||||
if (filterKeyPermission && remoteMethod) {
|
||||
config.filterConfig = {
|
||||
mode: 'remote',
|
||||
loadOptionParams: {
|
||||
organizationId: appStore.currentOrgId,
|
||||
},
|
||||
remoteMethod,
|
||||
placeholderText: t('project.taskCenter.filterProPlaceholderText'),
|
||||
};
|
||||
}
|
||||
return config;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<div>
|
||||
<a-tabs v-model:active-key="activeTab" class="no-content">
|
||||
<a-tab-pane v-for="item of tabList" :key="item.value" :title="item.label" />
|
||||
</a-tabs>
|
||||
<a-divider margin="0"></a-divider>
|
||||
<Suspense>
|
||||
<caseTaskTable v-if="activeTab === TaskCenterEnum.CASE" :type="props.type" />
|
||||
<caseTaskDetailTable v-else-if="activeTab === TaskCenterEnum.DETAIL" :type="props.type" />
|
||||
<systemTaskTable v-else-if="activeTab === TaskCenterEnum.BACKEND" />
|
||||
</Suspense>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import caseTaskDetailTable from './component/caseTaskDetailTable.vue';
|
||||
import caseTaskTable from './component/caseTaskTable.vue';
|
||||
import systemTaskTable from './component/systemTaskTable.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { TaskCenterEnum } from '@/enums/taskCenter';
|
||||
|
||||
const props = defineProps<{
|
||||
type: 'system' | 'org' | 'project';
|
||||
mode?: 'modal' | 'normal';
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
||||
const tabList = ref([
|
||||
{
|
||||
value: TaskCenterEnum.CASE,
|
||||
label: t('ms.taskCenter.caseTaskList'),
|
||||
},
|
||||
{
|
||||
value: TaskCenterEnum.DETAIL,
|
||||
label: t('ms.taskCenter.caseTaskDetailList'),
|
||||
},
|
||||
{
|
||||
value: TaskCenterEnum.BACKEND,
|
||||
label: t('ms.taskCenter.backendTaskList'),
|
||||
},
|
||||
]);
|
||||
|
||||
const activeTab = ref<TaskCenterEnum>((route.query.type as TaskCenterEnum) || TaskCenterEnum.CASE);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.no-content {
|
||||
:deep(.arco-tabs-content) {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,53 @@
|
|||
export default {
|
||||
'ms.taskCenter.caseTaskList': 'Case Execution Task',
|
||||
'ms.taskCenter.caseTaskDetailList': 'Case Execution Task Details',
|
||||
'ms.taskCenter.backendTaskList': 'System Backend Task',
|
||||
'ms.taskCenter.search': 'Search by ID/Name',
|
||||
'ms.taskCenter.rerun': 'Rerun',
|
||||
'ms.taskCenter.checkReport': 'View Report',
|
||||
'ms.taskCenter.taskName': 'Task Name',
|
||||
'ms.taskCenter.executeStatus': 'Execution Status',
|
||||
'ms.taskCenter.executeMethod': 'Execution Method',
|
||||
'ms.taskCenter.executeResult': 'Execution Result',
|
||||
'ms.taskCenter.caseCount': 'Case Count',
|
||||
'ms.taskCenter.executeFinishedRate': 'Execution Completion Rate',
|
||||
'ms.taskCenter.createTime': 'Initiation Time',
|
||||
'ms.taskCenter.startTime': 'Start Time',
|
||||
'ms.taskCenter.endTime': 'End Time',
|
||||
'ms.taskCenter.startExecuteTime': 'Start Execution Time',
|
||||
'ms.taskCenter.endExecuteTime': 'End Execution Time',
|
||||
'ms.taskCenter.taskCreateTime': 'Task Initiation Time',
|
||||
'ms.taskCenter.taskStartTime': 'Task Start Time',
|
||||
'ms.taskCenter.taskEndTime': 'Task End Time',
|
||||
'ms.taskCenter.taskResource': 'Task Source',
|
||||
'ms.taskCenter.executeEnvInfo': 'Execution Environment Information',
|
||||
'ms.taskCenter.passThreshold': 'Pass Threshold',
|
||||
'ms.taskCenter.executeProgress': 'Execution Progress',
|
||||
'ms.taskCenter.taskID': 'Task ID',
|
||||
'ms.taskCenter.resourcePool': 'Resource Pool',
|
||||
'ms.taskCenter.node': 'Node',
|
||||
'ms.taskCenter.nodeErrorTip': 'Node has an exception, please check',
|
||||
'ms.taskCenter.queue': 'Queue',
|
||||
'ms.taskCenter.threadID': 'Thread ID',
|
||||
'ms.taskCenter.type': 'Type',
|
||||
'ms.taskCenter.runRule': 'Run Rule',
|
||||
'ms.taskCenter.operationUser': 'Operator',
|
||||
'ms.taskCenter.operationTime': 'Operation Time',
|
||||
'ms.taskCenter.lastFinishTime': 'Last Finish Time',
|
||||
'ms.taskCenter.nextExecuteTime': 'Next Execution Time',
|
||||
'ms.taskCenter.deleteTaskTitle': 'Confirm delete {name}?',
|
||||
'ms.taskCenter.deleteCaseTaskTitle': 'Confirm delete {count} case tasks?',
|
||||
'ms.taskCenter.deleteTimeTaskTitle': 'Confirm delete {count} scheduled tasks?',
|
||||
'ms.taskCenter.deleteCaseTaskTip': 'After deletion, the case task will stop, please operate with caution!',
|
||||
'ms.taskCenter.deleteTimeTaskTip': 'After deletion, the scheduled task will stop, please operate with caution!',
|
||||
'ms.taskCenter.stopTaskTitle': 'Confirm stop {name}?',
|
||||
'ms.taskCenter.batchStopTaskTitle': 'Confirm stop {count} tasks?',
|
||||
'ms.taskCenter.stopTimeTaskTip': 'After stopping, it will affect task execution, please operate with caution!',
|
||||
'ms.taskCenter.failRerun': 'Fail Rerun',
|
||||
'ms.taskCenter.execute': 'Manual Execution',
|
||||
'ms.taskCenter.batchExecute': 'Batch Execution',
|
||||
'ms.taskCenter.interfaceCall': 'Interface Call',
|
||||
'ms.taskCenter.scheduledTask': 'Scheduled Execution',
|
||||
'ms.taskCenter.batchCaseTask': 'Batch Case Execution Task',
|
||||
'ms.taskCenter.batchScenarioTask': 'Batch Scenario Execution Task',
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
export default {
|
||||
'ms.taskCenter.caseTaskList': '用例执行任务',
|
||||
'ms.taskCenter.caseTaskDetailList': '用例执行任务详情',
|
||||
'ms.taskCenter.backendTaskList': '系统后台任务',
|
||||
'ms.taskCenter.search': '通过 ID/名称搜索',
|
||||
'ms.taskCenter.rerun': '重跑',
|
||||
'ms.taskCenter.checkReport': '查看报告',
|
||||
'ms.taskCenter.taskName': '任务名称',
|
||||
'ms.taskCenter.executeStatus': '执行状态',
|
||||
'ms.taskCenter.executeMethod': '执行方式',
|
||||
'ms.taskCenter.executeResult': '执行结果',
|
||||
'ms.taskCenter.caseCount': '用例数',
|
||||
'ms.taskCenter.executeFinishedRate': '执行完成率',
|
||||
'ms.taskCenter.createTime': '发起时间',
|
||||
'ms.taskCenter.startTime': '开始时间',
|
||||
'ms.taskCenter.endTime': '结束时间',
|
||||
'ms.taskCenter.startExecuteTime': '开始执行时间',
|
||||
'ms.taskCenter.endExecuteTime': '结束执行时间',
|
||||
'ms.taskCenter.taskCreateTime': '任务发起时间',
|
||||
'ms.taskCenter.taskStartTime': '任务开始时间',
|
||||
'ms.taskCenter.taskEndTime': '任务结束时间',
|
||||
'ms.taskCenter.taskResource': '任务来源',
|
||||
'ms.taskCenter.executeEnvInfo': '执行环境信息',
|
||||
'ms.taskCenter.passThreshold': '通过阈值',
|
||||
'ms.taskCenter.executeProgress': '执行进度',
|
||||
'ms.taskCenter.taskID': '任务 ID',
|
||||
'ms.taskCenter.resourcePool': '资源池',
|
||||
'ms.taskCenter.node': '节点',
|
||||
'ms.taskCenter.nodeErrorTip': '节点存在异常,请检查',
|
||||
'ms.taskCenter.queue': '排队',
|
||||
'ms.taskCenter.threadID': '线程 ID',
|
||||
'ms.taskCenter.type': '类型',
|
||||
'ms.taskCenter.runRule': '运行规则',
|
||||
'ms.taskCenter.operationUser': '操作人',
|
||||
'ms.taskCenter.operationTime': '操作时间',
|
||||
'ms.taskCenter.lastFinishTime': '上次完成时间',
|
||||
'ms.taskCenter.nextExecuteTime': '下次执行时间',
|
||||
'ms.taskCenter.deleteTaskTitle': '确认删除 {name} 吗?',
|
||||
'ms.taskCenter.deleteCaseTaskTitle': '确认删除 {count} 项用例任务吗?',
|
||||
'ms.taskCenter.deleteTimeTaskTitle': '确认删除 {count} 项定时任务吗?',
|
||||
'ms.taskCenter.deleteCaseTaskTip': '删除后,用例任务停止,请谨慎操作!',
|
||||
'ms.taskCenter.deleteTimeTaskTip': '删除后,定时任务停止,请谨慎操作!',
|
||||
'ms.taskCenter.stopTaskTitle': '确认停止 {name} 吗?',
|
||||
'ms.taskCenter.batchStopTaskTitle': '确认停止 {count} 项任务吗?',
|
||||
'ms.taskCenter.stopTimeTaskTip': '停止后,影响任务执行,请谨慎操作!',
|
||||
'ms.taskCenter.failRerun': '失败重跑',
|
||||
'ms.taskCenter.execute': '手动执行',
|
||||
'ms.taskCenter.batchExecute': '批量执行',
|
||||
'ms.taskCenter.interfaceCall': '接口调用',
|
||||
'ms.taskCenter.scheduledTask': '定时执行',
|
||||
'ms.taskCenter.batchCaseTask': '用例批量执行任务',
|
||||
'ms.taskCenter.batchScenarioTask': '场景批量执行任务',
|
||||
};
|
Loading…
Reference in New Issue