feat(任务中心): 执行交互&任务中心部分操作接口联调&跳转交互

This commit is contained in:
baiqi 2024-10-17 18:05:06 +08:00 committed by Craftsman
parent 3aa53ef5c4
commit bdf9fe47ec
30 changed files with 982 additions and 371 deletions

View File

@ -1,23 +1,34 @@
import MSR from '@/api/http/index'; import MSR from '@/api/http/index';
import { import {
organizationDeleteTaskUrl,
organizationExecuteTaskDetailListUrl, organizationExecuteTaskDetailListUrl,
organizationExecuteTaskListUrl, organizationExecuteTaskListUrl,
organizationExecuteTaskStatisticsUrl, organizationExecuteTaskStatisticsUrl,
organizationScheduleListUrl, organizationScheduleListUrl,
organizationStopTaskUrl,
organizationTaskCenterResourcePoolsUrl,
projectDeleteTaskUrl,
projectExecuteTaskDetailListUrl, projectExecuteTaskDetailListUrl,
projectExecuteTaskListUrl, projectExecuteTaskListUrl,
projectExecuteTaskStatisticsUrl, projectExecuteTaskStatisticsUrl,
projectScheduleTaskListUrl, projectScheduleTaskListUrl,
projectStopTaskUrl,
projectTaskCenterResourcePoolsUrl,
scheduleProCenterListUrl, scheduleProCenterListUrl,
systemDeleteTaskUrl,
systemExecuteTaskDetailListUrl, systemExecuteTaskDetailListUrl,
systemExecuteTaskListUrl, systemExecuteTaskListUrl,
systemExecuteTaskStatisticsUrl, systemExecuteTaskStatisticsUrl,
systemResourcePoolStatusUrl,
systemScheduleListUrl, systemScheduleListUrl,
systemStopTaskUrl,
systemTaskCenterResourcePoolsUrl,
} from '@/api/requrls/taskCenter'; } from '@/api/requrls/taskCenter';
import type { CommonList, TableQueryParams } from '@/models/common'; import type { CommonList, TableQueryParams } from '@/models/common';
import type { TimingTaskCenterApiCaseItem } from '@/models/projectManagement/taskCenter'; import type { TimingTaskCenterApiCaseItem } from '@/models/projectManagement/taskCenter';
import type { import type {
TaskCenterResourcePoolStatus,
TaskCenterStatisticsItem, TaskCenterStatisticsItem,
TaskCenterSystemTaskItem, TaskCenterSystemTaskItem,
TaskCenterTaskDetailItem, TaskCenterTaskDetailItem,
@ -45,6 +56,21 @@ export function getProjectExecuteTaskStatistics(data: string[]) {
return MSR.post<TaskCenterStatisticsItem[]>({ url: projectExecuteTaskStatisticsUrl, data }); return MSR.post<TaskCenterStatisticsItem[]>({ url: projectExecuteTaskStatisticsUrl, data });
} }
// 项目任务-获取资源池列表
export function getProjectTaskCenterResourcePools() {
return MSR.get<string[]>({ url: projectTaskCenterResourcePoolsUrl });
}
// 项目任务-停止任务
export function projectStopTask(id: string) {
return MSR.get({ url: `${projectStopTaskUrl}/${id}` });
}
// 项目任务-删除任务
export function projectDeleteTask(id: string) {
return MSR.get({ url: `${projectDeleteTaskUrl}/${id}` });
}
// 接口测试-定时任务列表 // 接口测试-定时任务列表
export function getScheduleProApiCaseList(data: TableQueryParams) { export function getScheduleProApiCaseList(data: TableQueryParams) {
return MSR.post<CommonList<TimingTaskCenterApiCaseItem>>({ url: scheduleProCenterListUrl, data }); return MSR.post<CommonList<TimingTaskCenterApiCaseItem>>({ url: scheduleProCenterListUrl, data });
@ -70,6 +96,26 @@ export function getSystemExecuteTaskStatistics(data: string[]) {
return MSR.post<TaskCenterStatisticsItem[]>({ url: systemExecuteTaskStatisticsUrl, data }); return MSR.post<TaskCenterStatisticsItem[]>({ url: systemExecuteTaskStatisticsUrl, data });
} }
// 系统任务-获取资源池列表
export function getSystemTaskCenterResourcePools() {
return MSR.get<string[]>({ url: systemTaskCenterResourcePoolsUrl });
}
// 系统任务-停止任务
export function systemStopTask(id: string) {
return MSR.get({ url: `${systemStopTaskUrl}/${id}` });
}
// 系统任务-删除任务
export function systemDeleteTask(id: string) {
return MSR.get({ url: `${systemDeleteTaskUrl}/${id}` });
}
// 任务中心-资源池状态
export function getResourcePoolsStatus(data: string[]) {
return MSR.post<TaskCenterResourcePoolStatus[]>({ url: systemResourcePoolStatusUrl, data });
}
// 组织任务-系统后台任务列表 // 组织任务-系统后台任务列表
export function getOrganizationScheduleList(data: TableQueryParams) { export function getOrganizationScheduleList(data: TableQueryParams) {
return MSR.post<CommonList<TaskCenterSystemTaskItem>>({ url: organizationScheduleListUrl, data }); return MSR.post<CommonList<TaskCenterSystemTaskItem>>({ url: organizationScheduleListUrl, data });
@ -89,3 +135,18 @@ export function getOrganizationExecuteTaskList(data: TableQueryParams) {
export function getOrganizationExecuteTaskStatistics(data: string[]) { export function getOrganizationExecuteTaskStatistics(data: string[]) {
return MSR.post<TaskCenterStatisticsItem[]>({ url: organizationExecuteTaskStatisticsUrl, data }); return MSR.post<TaskCenterStatisticsItem[]>({ url: organizationExecuteTaskStatisticsUrl, data });
} }
// 组织任务-获取资源池列表
export function getOrgTaskCenterResourcePools() {
return MSR.get<string[]>({ url: organizationTaskCenterResourcePoolsUrl });
}
// 组织任务-停止任务
export function organizationStopTask(id: string) {
return MSR.get({ url: `${organizationStopTaskUrl}/${id}` });
}
// 组织任务-删除任务
export function organizationDeleteTask(id: string) {
return MSR.get({ url: `${organizationDeleteTaskUrl}/${id}` });
}

View File

@ -2,15 +2,24 @@ export const projectScheduleTaskListUrl = '/project/task-center/schedule/page';
export const projectExecuteTaskStatisticsUrl = '/project/task-center/exec-task/statistics'; // 项目任务-获取任务统计 export const projectExecuteTaskStatisticsUrl = '/project/task-center/exec-task/statistics'; // 项目任务-获取任务统计
export const projectExecuteTaskListUrl = '/project/task-center/exec-task/page'; // 项目任务-任务列表 export const projectExecuteTaskListUrl = '/project/task-center/exec-task/page'; // 项目任务-任务列表
export const projectExecuteTaskDetailListUrl = '/project/task-center/exec-task/item/page'; // 项目任务-任务详情列表 export const projectExecuteTaskDetailListUrl = '/project/task-center/exec-task/item/page'; // 项目任务-任务详情列表
// 项目-任务中心-定时任务列表 export const scheduleProCenterListUrl = '/task/center/project/schedule/page'; // 项目-任务中心-定时任务列表
export const scheduleProCenterListUrl = '/task/center/project/schedule/page'; export const projectTaskCenterResourcePoolsUrl = '/project/task-center/resource-pool/options'; // 项目-任务中心-获取资源池列表
export const projectStopTaskUrl = '/project/task-center/exec-task/stop'; // 项目-任务中心-停止任务
export const projectDeleteTaskUrl = '/project/task-center/exec-task/delete'; // 项目-任务中心-删除任务
export const systemScheduleListUrl = '/system/task-center/schedule/page'; // 系统任务-系统后台任务列表 export const systemScheduleListUrl = '/system/task-center/schedule/page'; // 系统任务-系统后台任务列表
export const systemExecuteTaskListUrl = '/system/task-center/exec-task/page'; // 系统任务-执行任务列表 export const systemExecuteTaskListUrl = '/system/task-center/exec-task/page'; // 系统任务-执行任务列表
export const systemExecuteTaskDetailListUrl = '/system/task-center/exec-task/item/page'; // 系统任务-执行任务详情列表 export const systemExecuteTaskDetailListUrl = '/system/task-center/exec-task/item/page'; // 系统任务-执行任务详情列表
export const systemExecuteTaskStatisticsUrl = '/system/task-center/exec-task/statistics'; // 系统任务-获取任务统计 export const systemExecuteTaskStatisticsUrl = '/system/task-center/exec-task/statistics'; // 系统任务-获取任务统计
export const systemTaskCenterResourcePoolsUrl = '/system/task-center/resource-pool/options'; // 系统任务-获取资源池列表
export const systemStopTaskUrl = '/system/task-center/exec-task/stop'; // 系统任务-停止任务
export const systemDeleteTaskUrl = '/system/task-center/exec-task/delete'; // 系统任务-删除任务
export const systemResourcePoolStatusUrl = '/system/task-center/resource-pool/status'; // 系统任务-资源池状态
export const organizationScheduleListUrl = '/organization/task-center/schedule/page'; // 系统任务-系统后台任务列表 export const organizationScheduleListUrl = '/organization/task-center/schedule/page'; // 组织任务-系统后台任务列表
export const organizationExecuteTaskListUrl = '/organization/task-center/exec-task/page'; // 系统任务-执行任务列表 export const organizationExecuteTaskListUrl = '/organization/task-center/exec-task/page'; // 组织任务-执行任务列表
export const organizationExecuteTaskDetailListUrl = '/organization/task-center/exec-task/item/page'; // 系统任务-执行任务详情列表 export const organizationExecuteTaskDetailListUrl = '/organization/task-center/exec-task/item/page'; // 组织任务-执行任务详情列表
export const organizationExecuteTaskStatisticsUrl = '/organization/task-center/exec-task/statistics'; // 系统任务-获取任务统计 export const organizationExecuteTaskStatisticsUrl = '/organization/task-center/exec-task/statistics'; // 组织任务-获取任务统计
export const organizationTaskCenterResourcePoolsUrl = '/organization/task-center/resource-pool/options'; // 组织任务-获取资源池列表
export const organizationStopTaskUrl = '/organization/task-center/exec-task/stop'; // 组织任务-停止任务
export const organizationDeleteTaskUrl = '/organization/task-center/exec-task/delete'; // 组织任务-删除任务

View File

@ -0,0 +1,28 @@
<template>
<div class="flex flex-wrap items-center">
<div class="mr-[8px]">{{ props.content }}</div>
<MsButton v-if="props.showDetail" @click="goDetail">{{ t('common.checkDetail') }}</MsButton>
</div>
</template>
<script setup lang="ts">
import MsButton from '@/components/pure/ms-button/index.vue';
import { useI18n } from '@/hooks/useI18n';
const props = withDefaults(
defineProps<{
content: string;
showDetail?: boolean;
}>(),
{
showDetail: true,
}
);
const emit = defineEmits(['goDetail']);
const { t } = useI18n();
function goDetail() {
emit('goDetail');
}
</script>

View File

@ -193,9 +193,12 @@
import { LOCALE_OPTIONS } from '@/locale'; import { LOCALE_OPTIONS } from '@/locale';
import useLocale from '@/locale/useLocale'; import useLocale from '@/locale/useLocale';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useGlobalStore from '@/store/modules/global';
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
import { getFirstRouteNameByPermission, hasAnyPermission } from '@/utils/permission'; import { getFirstRouteNameByPermission, hasAnyPermission } from '@/utils/permission';
import { GlobalEventNameEnum } from '@/enums/commonEnum';
import { IconInfoCircle } from '@arco-design/web-vue/es/icon'; import { IconInfoCircle } from '@arco-design/web-vue/es/icon';
import type { LocaleType } from '#/global'; import type { LocaleType } from '#/global';
@ -208,6 +211,7 @@
const appStore = useAppStore(); const appStore = useAppStore();
const userStore = useUserStore(); const userStore = useUserStore();
const globalStore = useGlobalStore();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
@ -291,6 +295,15 @@
function goTaskCenter() { function goTaskCenter() {
taskCenterVisible.value = true; taskCenterVisible.value = true;
} }
watch(
() => globalStore.getGlobalEvent,
(event) => {
if (event && event.id && event.name === GlobalEventNameEnum.OPEN_TASK_CENTER) {
goTaskCenter();
}
}
);
function goMessageCenter() { function goMessageCenter() {
messageCenterVisible.value = true; messageCenterVisible.value = true;
} }

View File

@ -40,3 +40,7 @@ export enum TagUpdateTypeEnum {
APPEND = 'APPEND', APPEND = 'APPEND',
CLEAR = 'CLEAR', CLEAR = 'CLEAR',
} }
export enum GlobalEventNameEnum {
OPEN_TASK_CENTER = 'openTaskCenter',
}

View File

@ -33,3 +33,18 @@ export enum ExecuteResultEnum {
ERROR = 'ERROR', ERROR = 'ERROR',
FAKE_ERROR = 'FAKE_ERROR', FAKE_ERROR = 'FAKE_ERROR',
} }
export enum ExecuteTriggerMode {
MANUAL = 'MANUAL',
BATCH = 'BATCH',
API = 'API',
SCHEDULE = 'SCHEDULE',
}
export enum ExecuteTaskType {
API_IMPORT = 'API_IMPORT',
API_SCENARIO = 'API_SCENARIO',
BUG_SYNC = 'BUG_SYNC',
DEMAND_SYNC = 'DEMAND_SYNC',
TEST_PLAN = 'TEST_PLAN',
}

View File

@ -216,4 +216,5 @@ export default {
'common.currentUser': 'Current user', 'common.currentUser': 'Current user',
'common.type': 'Type', 'common.type': 'Type',
'common.batchUpdate': 'Updated to', 'common.batchUpdate': 'Updated to',
'common.checkDetail': 'View details',
}; };

View File

@ -216,4 +216,5 @@ export default {
'common.currentUser': '当前用户', 'common.currentUser': '当前用户',
'common.type': '类型', 'common.type': '类型',
'common.batchUpdate': '更新为', 'common.batchUpdate': '更新为',
'common.checkDetail': '查看详情',
}; };

View File

@ -1,3 +1,5 @@
import type { ExecuteTriggerMode } from '@/enums/taskCenter';
import type { TableQueryParams } from './common'; import type { TableQueryParams } from './common';
export interface TaskCenterSystemTaskItem { export interface TaskCenterSystemTaskItem {
@ -32,7 +34,7 @@ export interface TaskCenterTaskItem {
result: string; // 执行结果 result: string; // 执行结果
taskType: string; // 任务类型 taskType: string; // 任务类型
resourceId: string; resourceId: string;
triggerMode: string; // 触发方式 triggerMode: ExecuteTriggerMode; // 执行方式
projectId: string; projectId: string;
organizationId: string; organizationId: string;
createTime: number; createTime: number;
@ -42,6 +44,7 @@ export interface TaskCenterTaskItem {
organizationName: string; // 所属组织名称 organizationName: string; // 所属组织名称
projectName: string; // 所属项目名称 projectName: string; // 所属项目名称
createUserName: string; // 创建人 createUserName: string; // 创建人
[key: string]: any;
} }
export interface TaskCenterTaskDetailItem { export interface TaskCenterTaskDetailItem {
@ -77,3 +80,8 @@ export interface TaskCenterStatisticsItem {
pendingCount: number; // 待执行数 pendingCount: number; // 待执行数
caseTotal: number; // 用例总数 caseTotal: number; // 用例总数
} }
export interface TaskCenterResourcePoolStatus {
id: string;
status: boolean; // 状态, true: 正常, false: 异常
}

View File

@ -5,11 +5,12 @@ import useTableStore from '@/hooks/useTableStore';
import useAppStore from './modules/app'; import useAppStore from './modules/app';
import useVisitStore from './modules/app/visit'; import useVisitStore from './modules/app/visit';
import useMinderStore from './modules/components/minder-editor'; import useMinderStore from './modules/components/minder-editor';
import useGlobalStore from './modules/global';
import useUserStore from './modules/user'; import useUserStore from './modules/user';
import { debouncePlugin } from './plugins'; import { debouncePlugin } from './plugins';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
const pinia = createPinia().use(debouncePlugin).use(piniaPluginPersistedstate); const pinia = createPinia().use(debouncePlugin).use(piniaPluginPersistedstate);
export { useAppStore, useMinderStore, useTableStore, useUserStore, useVisitStore }; export { useAppStore, useGlobalStore, useMinderStore, useTableStore, useUserStore, useVisitStore };
export default pinia; export default pinia;

View File

@ -12,10 +12,10 @@ export interface AppState {
navbar: boolean; navbar: boolean;
menu: boolean; menu: boolean;
hideMenu: boolean; hideMenu: boolean;
menuCollapse: boolean; menuCollapse: boolean; // 菜单是否折叠
footer: boolean; footer: boolean;
menuWidth: number; menuWidth: number;
collapsedWidth: number; collapsedWidth: number; // 菜单折叠宽度
globalSettings: boolean; globalSettings: boolean;
device: string; device: string;
tabBar: boolean; tabBar: boolean;
@ -45,7 +45,7 @@ export interface AppState {
ordList: { id: string; name: string }[]; ordList: { id: string; name: string }[];
envList: EnvironmentItem[]; envList: EnvironmentItem[];
currentEnvConfig?: EnvConfig; // 当前环境配置信息 currentEnvConfig?: EnvConfig; // 当前环境配置信息
fileMaxSize: number; fileMaxSize: number; // 文件上传最大限制
} }
export interface UploadFileTaskState { export interface UploadFileTaskState {

View File

@ -0,0 +1,20 @@
import { defineStore } from 'pinia';
import type { GlobalState, GlobalStateEvent } from './types';
const useGlobalStore = defineStore('global', {
state: (): GlobalState => ({
globalEvent: undefined,
}),
getters: {
getGlobalEvent(state: GlobalState) {
return state.globalEvent;
},
},
actions: {
dispatchGlobalEvent(event: GlobalStateEvent) {
this.globalEvent = event;
},
},
});
export default useGlobalStore;

View File

@ -0,0 +1,11 @@
import type { GlobalEventNameEnum } from '@/enums/commonEnum';
export interface GlobalStateEvent {
id: string;
name: GlobalEventNameEnum;
params?: Record<string, any>;
}
export interface GlobalState {
globalEvent?: GlobalStateEvent;
}

View File

@ -214,7 +214,7 @@
:max-length="255" :max-length="255"
class="w-[550px]" class="w-[550px]"
></a-input> ></a-input>
<MsButton type="text" @click="taskDrawerVisible = true"> <MsButton type="text" @click="emit('openTaskDrawer')">
{{ t('apiTestManagement.timeTaskList') }} {{ t('apiTestManagement.timeTaskList') }}
</MsButton> </MsButton>
</div> </div>
@ -328,52 +328,20 @@
</template> </template>
</a-form> </a-form>
</MsDrawer> </MsDrawer>
<MsDrawer v-model:visible="taskDrawerVisible" :width="960" :title="t('apiTestManagement.timeTask')" :footer="false">
<div class="mb-[16px] flex items-center justify-end">
<a-input-search
v-model:model-value="keyword"
:placeholder="t('apiTestManagement.searchTaskPlaceholder')"
allow-clear
class="mr-[8px] w-[240px]"
@search="loadTaskList"
@press-enter="loadTaskList"
@clear="loadTaskList"
/>
</div>
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
<template #action="{ record }">
<a-switch
v-model:modelValue="record.enable"
type="line"
size="small"
:before-change="() => handleBeforeEnableChange(record)"
></a-switch>
</template>
</ms-base-table>
</MsDrawer>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useVModel } from '@vueuse/core'; import { useVModel } from '@vueuse/core';
import { FormInstance, Message } from '@arco-design/web-vue'; import { FormInstance, Message } from '@arco-design/web-vue';
import dayjs from 'dayjs';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsCronSelect from '@/components/pure/ms-cron-select/index.vue'; import MsCronSelect from '@/components/pure/ms-cron-select/index.vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; 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 MsUpload from '@/components/pure/ms-upload/index.vue'; import MsUpload from '@/components/pure/ms-upload/index.vue';
import type { MsFileItem } from '@/components/pure/ms-upload/types'; import type { MsFileItem } from '@/components/pure/ms-upload/types';
import { import { createDefinitionSchedule, importDefinition } from '@/api/modules/api-test/management';
createDefinitionSchedule,
importDefinition,
switchDefinitionSchedule,
} from '@/api/modules/api-test/management';
import { getScheduleProApiCaseList } from '@/api/modules/taskCenter';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
@ -381,16 +349,14 @@
import type { ImportApiDefinitionParams, ImportApiDefinitionRequest } from '@/models/apiTest/management'; import type { ImportApiDefinitionParams, ImportApiDefinitionRequest } from '@/models/apiTest/management';
import type { ModuleTreeNode } from '@/models/common'; import type { ModuleTreeNode } from '@/models/common';
import { TimingTaskCenterApiCaseItem } from '@/models/projectManagement/taskCenter';
import { RequestImportFormat, RequestImportType } from '@/enums/apiEnum'; import { RequestImportFormat, RequestImportType } from '@/enums/apiEnum';
import { TaskCenterEnum } from '@/enums/taskCenter';
const props = defineProps<{ const props = defineProps<{
visible: boolean; visible: boolean;
moduleTree: ModuleTreeNode[]; moduleTree: ModuleTreeNode[];
activeModule: string; activeModule: string;
}>(); }>();
const emit = defineEmits(['update:visible', 'done']); const emit = defineEmits(['update:visible', 'done', 'openTaskDrawer']);
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStore(); const appStore = useAppStore();
@ -481,7 +447,6 @@
const cronValue = ref('0 0 0/1 * * ?'); const cronValue = ref('0 0 0/1 * * ?');
const importLoading = ref(false); const importLoading = ref(false);
const taskDrawerVisible = ref(false);
function setActiveImportFormat(format: RequestImportFormat) { function setActiveImportFormat(format: RequestImportFormat) {
importForm.value.platform = format; importForm.value.platform = format;
@ -583,7 +548,7 @@
importType.value = 'time'; importType.value = 'time';
fileList.value = []; fileList.value = [];
moreSettingActive.value = []; moreSettingActive.value = [];
taskDrawerVisible.value = true; emit('openTaskDrawer');
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
@ -604,107 +569,6 @@
}); });
} }
const keyword = ref('');
const columns: MsTableColumn = [
{
title: 'project.taskCenter.resourceID',
dataIndex: 'resourceNum',
slotName: 'resourceNum',
width: 140,
showInTable: true,
showTooltip: true,
},
{
title: 'project.taskCenter.resourceName',
slotName: 'resourceName',
dataIndex: 'resourceName',
width: 200,
showDrag: true,
showTooltip: true,
},
{
title: 'project.taskCenter.swaggerUrl',
slotName: 'swaggerUrl',
dataIndex: 'swaggerUrl',
width: 300,
showDrag: false,
showTooltip: true,
columnSelectorDisabled: true,
showInTable: true,
},
{
title: 'apiTestManagement.taskRunRule',
dataIndex: 'value',
width: 140,
},
{
title: 'apiTestManagement.taskNextRunTime',
dataIndex: 'nextTime',
showTooltip: true,
width: 180,
},
{
title: 'apiTestManagement.taskOperator',
dataIndex: 'createUserName',
showTooltip: true,
width: 150,
},
{
title: 'apiTestManagement.taskOperationTime',
dataIndex: 'createTime',
width: 180,
},
{
title: 'common.operation',
slotName: 'action',
dataIndex: 'operation',
fixed: 'right',
width: 80,
},
];
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(
getScheduleProApiCaseList,
{
columns,
scroll: { x: '100%' },
},
(item) => ({
...item,
operationTime: dayjs(item.operationTime).format('YYYY-MM-DD HH:mm:ss'),
nextTime: item.nextTime ? dayjs(item.nextTime).format('YYYY-MM-DD HH:mm:ss') : '-',
})
);
function loadTaskList() {
setLoadListParams({
keyword: keyword.value,
moduleType: TaskCenterEnum.API_IMPORT,
});
loadList();
}
watch(
() => taskDrawerVisible.value,
(value) => {
if (value) {
loadTaskList();
}
}
);
async function handleBeforeEnableChange(record: TimingTaskCenterApiCaseItem) {
try {
await switchDefinitionSchedule(record.id);
Message.success(
t(record.enable ? 'apiTestManagement.disableTaskSuccess' : 'apiTestManagement.enableTaskSuccess')
);
return true;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
return false;
}
}
function openLink() { function openLink() {
window.open('https://converter.swagger.io/', '_blank'); window.open('https://converter.swagger.io/', '_blank');
} }

View File

@ -0,0 +1,165 @@
<template>
<MsDrawer v-model:visible="taskDrawerVisible" :width="960" :title="t('apiTestManagement.timeTask')" :footer="false">
<div class="mb-[16px] flex items-center justify-end">
<a-input-search
v-model:model-value="keyword"
:placeholder="t('apiTestManagement.searchTaskPlaceholder')"
allow-clear
class="mr-[8px] w-[240px]"
@search="loadTaskList"
@press-enter="loadTaskList"
@clear="loadTaskList"
/>
</div>
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
<template #action="{ record }">
<div class="flex items-center gap-[12px]">
<a-switch
v-model:modelValue="record.enable"
type="line"
size="small"
:before-change="() => handleBeforeEnableChange(record)"
></a-switch>
<MsButton @click="deleteTask(record)">
{{ t('common.delete') }}
</MsButton>
</div>
</template>
</ms-base-table>
</MsDrawer>
</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 MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import { switchDefinitionSchedule } from '@/api/modules/api-test/management';
import { getScheduleProApiCaseList } from '@/api/modules/taskCenter';
import { useI18n } from '@/hooks/useI18n';
import { TimingTaskCenterApiCaseItem } from '@/models/projectManagement/taskCenter';
import { TaskCenterEnum } from '@/enums/taskCenter';
const { t } = useI18n();
const taskDrawerVisible = defineModel<boolean>('visible', { required: true });
const keyword = ref('');
const columns: MsTableColumn = [
{
title: 'apiTestManagement.resourceID',
dataIndex: 'resourceNum',
slotName: 'resourceNum',
width: 140,
showInTable: true,
showTooltip: true,
},
{
title: 'apiTestManagement.resourceName',
slotName: 'resourceName',
dataIndex: 'resourceName',
width: 200,
showDrag: true,
showTooltip: true,
},
{
title: 'apiTestManagement.swaggerUrl',
slotName: 'swaggerUrl',
dataIndex: 'swaggerUrl',
width: 300,
showDrag: false,
showTooltip: true,
columnSelectorDisabled: true,
showInTable: true,
},
{
title: 'apiTestManagement.taskRunRule',
dataIndex: 'value',
width: 140,
},
{
title: 'apiTestManagement.taskNextRunTime',
dataIndex: 'nextTime',
showTooltip: true,
width: 180,
},
{
title: 'apiTestManagement.taskOperator',
dataIndex: 'createUserName',
showTooltip: true,
width: 150,
},
{
title: 'apiTestManagement.taskOperationTime',
dataIndex: 'createTime',
width: 180,
},
{
title: 'common.operation',
slotName: 'action',
dataIndex: 'operation',
fixed: 'right',
width: 110,
},
];
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(
getScheduleProApiCaseList,
{
columns,
scroll: { x: '100%' },
},
(item) => ({
...item,
operationTime: dayjs(item.operationTime).format('YYYY-MM-DD HH:mm:ss'),
nextTime: item.nextTime ? dayjs(item.nextTime).format('YYYY-MM-DD HH:mm:ss') : '-',
})
);
function loadTaskList() {
setLoadListParams({
keyword: keyword.value,
moduleType: TaskCenterEnum.API_IMPORT,
});
loadList();
}
watch(
() => taskDrawerVisible.value,
(value) => {
if (value) {
loadTaskList();
}
}
);
async function handleBeforeEnableChange(record: TimingTaskCenterApiCaseItem) {
try {
await switchDefinitionSchedule(record.id);
Message.success(
t(record.enable ? 'apiTestManagement.disableTaskSuccess' : 'apiTestManagement.enableTaskSuccess')
);
return true;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
return false;
}
}
async function deleteTask(record: TimingTaskCenterApiCaseItem) {
try {
// await switchDefinitionSchedule(record.id);
Message.success(t('common.deleteSuccess'));
loadTaskList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
</script>
<style lang="less" scoped></style>

View File

@ -47,6 +47,7 @@
:active-module="activeModule" :active-module="activeModule"
popup-container="#managementContainer" popup-container="#managementContainer"
@done="handleImportDone" @done="handleImportDone"
@open-task-drawer="taskDrawerVisible = true"
/> />
</div> </div>
<management <management
@ -116,6 +117,7 @@
is-share is-share
/> />
</MsCard> </MsCard>
<importTaskDrawer v-model:visible="taskDrawerVisible" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -131,6 +133,7 @@
import type { BatchActionQueryParams } from '@/components/pure/ms-table/type'; import type { BatchActionQueryParams } from '@/components/pure/ms-table/type';
import { RequestParam } from '../components/requestComposition/index.vue'; import { RequestParam } from '../components/requestComposition/index.vue';
import importApi from './components/import.vue'; import importApi from './components/import.vue';
import importTaskDrawer from './components/importTaskDrawer.vue';
import management from './components/management/index.vue'; import management from './components/management/index.vue';
import moduleTree from './components/moduleTree.vue'; import moduleTree from './components/moduleTree.vue';
import ApiExportModal from '@/views/api-test/management/components/management/api/apiExportModal.vue'; import ApiExportModal from '@/views/api-test/management/components/management/api/apiExportModal.vue';
@ -423,10 +426,14 @@
}); });
} }
const taskDrawerVisible = ref(false);
onBeforeMount(() => { onBeforeMount(() => {
if (docShareId.value) { if (docShareId.value) {
getShareDetail(); getShareDetail();
} }
if (route.query.taskDrawer) {
taskDrawerVisible.value = true;
}
}); });
/** 向子孙组件提供方法和值 */ /** 向子孙组件提供方法和值 */

View File

@ -196,6 +196,8 @@ export default {
'Delete, share a link can lead to user access is to access the link is unusual, please careful operation', 'Delete, share a link can lead to user access is to access the link is unusual, please careful operation',
'apiTestManagement.passwordView': 'Password', 'apiTestManagement.passwordView': 'Password',
'apiTestManagement.publicityView': 'Public', 'apiTestManagement.publicityView': 'Public',
'apiTestManagement.resourceID': 'Resource ID',
'apiTestManagement.swaggerUrl': 'Swagger URL',
'case.execute.selectEnv': 'Select Environment', 'case.execute.selectEnv': 'Select Environment',
'case.execute.defaultEnv': 'Default Environment', 'case.execute.defaultEnv': 'Default Environment',
'case.execute.newEnv': 'New Environment', 'case.execute.newEnv': 'New Environment',

View File

@ -188,6 +188,8 @@ export default {
'apiTestManagement.deleteShareTip': '删除后,分享链接会导致正在访问该链接的用户访问异常,请谨慎操作!', 'apiTestManagement.deleteShareTip': '删除后,分享链接会导致正在访问该链接的用户访问异常,请谨慎操作!',
'apiTestManagement.passwordView': '密码', 'apiTestManagement.passwordView': '密码',
'apiTestManagement.publicityView': '公开', 'apiTestManagement.publicityView': '公开',
'apiTestManagement.resourceID': '资源 ID',
'apiTestManagement.swaggerUrl': 'Swagger URL',
'case.execute.selectEnv': '环境选择', 'case.execute.selectEnv': '环境选择',
'case.execute.defaultEnv': '默认环境', 'case.execute.defaultEnv': '默认环境',
'case.execute.newEnv': '新环境', 'case.execute.newEnv': '新环境',

View File

@ -104,15 +104,21 @@
import { FormInstance, Message } from '@arco-design/web-vue'; import { FormInstance, Message } from '@arco-design/web-vue';
import { BatchActionQueryParams } from '@/components/pure/ms-table/type'; import { BatchActionQueryParams } from '@/components/pure/ms-table/type';
import MsRichMessage from '@/components/business/ms-rich-message/index.vue';
import { getEnvList } from '@/api/modules/api-test/common'; import { getEnvList } from '@/api/modules/api-test/common';
import { getPoolId, getPoolOption } from '@/api/modules/api-test/management'; import { getPoolId, getPoolOption } from '@/api/modules/api-test/management';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useGlobalStore from '@/store/modules/global';
import { getGenerateId } from '@/utils';
import { Environment } from '@/models/apiTest/management'; import { Environment } from '@/models/apiTest/management';
import { ResourcePoolItem } from '@/models/setting/resourcePool'; import { ResourcePoolItem } from '@/models/setting/resourcePool';
import { GlobalEventNameEnum } from '@/enums/commonEnum';
import { TaskCenterEnum } from '@/enums/taskCenter';
const globalStore = useGlobalStore();
const { t } = useI18n(); const { t } = useI18n();
const batchExecuteFormRef = ref<FormInstance>(); const batchExecuteFormRef = ref<FormInstance>();
const batchExecuteForm = ref({ const batchExecuteForm = ref({
@ -213,7 +219,35 @@
versionId: '', versionId: '',
refId: '', refId: '',
}); });
Message.success(t('case.detail.execute.success')); Message.success({
content: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
gap: '4px',
},
},
[
h(MsRichMessage, {
content: t('case.detail.execute.success'),
onGoDetail() {
globalStore.dispatchGlobalEvent({
id: getGenerateId(),
name: GlobalEventNameEnum.OPEN_TASK_CENTER,
params: {
tab: TaskCenterEnum.DETAIL,
},
});
},
}),
]
),
duration: 5000,
closable: true,
});
cancelBatchExecute(); cancelBatchExecute();
resetBatchExecuteForm(); resetBatchExecuteForm();
emit('finished'); emit('finished');

View File

@ -1,8 +1,8 @@
<template> <template>
<MsDrawer v-model:visible="visible" :title="title" :width="800" :footer="false"> <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"> <ms-base-table v-bind="propsRes" ref="tableRef" v-on="propsEvent" @filter-change="filterChange">
<template #name="{ record, rowIndex }"> <template #name="{ record }">
<a-button type="text" class="max-w-full justify-start px-0" @click="showReportDetail(record.id, rowIndex)"> <a-button type="text" class="max-w-full justify-start px-0" @click="showReportDetail(record)">
<div class="one-line-text"> <div class="one-line-text">
{{ record.num }} {{ record.num }}
</div> </div>
@ -43,6 +43,7 @@
</template> </template>
</ms-base-table> </ms-base-table>
</MsDrawer> </MsDrawer>
<ReportDrawer v-model:visible="reportVisible" :report-id="independentReportId" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -55,6 +56,7 @@
import MsTag from '@/components/pure/ms-tag/ms-tag.vue'; import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue'; import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
import ExecStatus from '@/views/test-plan/report/component/execStatus.vue'; import ExecStatus from '@/views/test-plan/report/component/execStatus.vue';
import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useTableStore from '@/hooks/useTableStore'; import useTableStore from '@/hooks/useTableStore';
@ -224,8 +226,12 @@
initData(dataIndex, value); initData(dataIndex, value);
} }
function showReportDetail(id: string, rowIndex: number) { const reportVisible = ref(false);
console.log(id, rowIndex); const independentReportId = ref<string>('');
function showReportDetail(record: any) {
independentReportId.value = record.id;
reportVisible.value = true;
} }
</script> </script>

View File

@ -49,8 +49,8 @@
</template> </template>
<template #resourcePoolNode="{ record }"> <template #resourcePoolNode="{ record }">
<div>{{ record.resourcePoolNode }}</div> <div>{{ record.resourcePoolNode }}</div>
<a-tooltip :content="t('ms.taskCenter.nodeErrorTip')"> <a-tooltip v-if="record.resourcePoolNodeStatus === false" :content="t('ms.taskCenter.nodeErrorTip')">
<icon-exclamation-circle-fill class="!text-[rgb(var(--warning-6))]" :size="18" /> <icon-exclamation-circle-fill class="ml-[4px] !text-[rgb(var(--warning-6))]" :size="18" />
</a-tooltip> </a-tooltip>
</template> </template>
<template #action="{ record }"> <template #action="{ record }">
@ -85,7 +85,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Message } from '@arco-design/web-vue'; import { CascaderOption, Message } from '@arco-design/web-vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
@ -102,8 +102,12 @@
import { import {
getOrganizationExecuteTaskDetailList, getOrganizationExecuteTaskDetailList,
getOrgTaskCenterResourcePools,
getProjectExecuteTaskDetailList, getProjectExecuteTaskDetailList,
getProjectTaskCenterResourcePools,
getResourcePoolsStatus,
getSystemExecuteTaskDetailList, getSystemExecuteTaskDetailList,
getSystemTaskCenterResourcePools,
} from '@/api/modules/taskCenter'; } from '@/api/modules/taskCenter';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
@ -111,6 +115,7 @@
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission'; import { hasAnyPermission } from '@/utils/permission';
import { TaskCenterTaskDetailItem } from '@/models/taskCenter';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum'; import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import { ExecuteResultEnum, ExecuteStatusEnum } from '@/enums/taskCenter'; import { ExecuteResultEnum, ExecuteStatusEnum } from '@/enums/taskCenter';
@ -128,7 +133,7 @@
const keyword = ref(''); const keyword = ref('');
const resourcePool = ref([]); const resourcePool = ref([]);
const resourcePoolOptions = ref([]); const resourcePoolOptions = ref<CascaderOption[]>([]);
const tableSelected = ref<string[]>([]); const tableSelected = ref<string[]>([]);
const batchModalParams = ref(); const batchModalParams = ref();
@ -164,6 +169,7 @@
{ {
title: 'ms.taskCenter.executeMethod', title: 'ms.taskCenter.executeMethod',
dataIndex: 'triggerMode', dataIndex: 'triggerMode',
slotName: 'triggerMode',
width: 100, width: 100,
filterConfig: { filterConfig: {
options: Object.keys(executeMethodMap).map((key) => ({ options: Object.keys(executeMethodMap).map((key) => ({
@ -197,7 +203,7 @@
title: 'ms.taskCenter.node', title: 'ms.taskCenter.node',
dataIndex: 'resourcePoolNode', dataIndex: 'resourcePoolNode',
slotName: 'resourcePoolNode', slotName: 'resourcePoolNode',
width: 100, width: 180,
}, },
{ {
title: 'ms.taskCenter.queue', title: 'ms.taskCenter.queue',
@ -207,7 +213,8 @@
{ {
title: 'ms.taskCenter.threadID', title: 'ms.taskCenter.threadID',
dataIndex: 'threadId', dataIndex: 'threadId',
width: 100, showTooltip: true,
width: 190,
}, },
{ {
title: 'ms.taskCenter.startExecuteTime', title: 'ms.taskCenter.startExecuteTime',
@ -229,7 +236,7 @@
}, },
{ {
title: 'ms.taskCenter.operationUser', title: 'ms.taskCenter.operationUser',
dataIndex: 'executor', dataIndex: 'userName',
width: 100, width: 100,
showTooltip: true, showTooltip: true,
}, },
@ -305,8 +312,8 @@
return { return {
...item, ...item,
resourcePoolName: [item.resourcePoolName], resourcePoolName: [item.resourcePoolName],
startExecuteTime: dayjs(item.startExecuteTime).format('YYYY-MM-DD HH:mm:ss'), startExecuteTime: item.startExecuteTime ? dayjs(item.startExecuteTime).format('YYYY-MM-DD HH:mm:ss') : '-',
endExecuteTime: dayjs(item.endExecuteTime).format('YYYY-MM-DD HH:mm:ss'), endExecuteTime: item.endExecuteTime ? dayjs(item.endExecuteTime).format('YYYY-MM-DD HH:mm:ss') : '-',
}; };
} }
); );
@ -319,7 +326,7 @@
/** /**
* 删除任务 * 删除任务
*/ */
function deleteTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) { function deleteTask(record?: TaskCenterTaskDetailItem, isBatch?: boolean, params?: BatchActionQueryParams) {
let title = t('ms.taskCenter.deleteTaskTitle', { name: characterLimit(record?.taskName) }); let title = t('ms.taskCenter.deleteTaskTitle', { name: characterLimit(record?.taskName) });
let selectIds = [record?.id || '']; let selectIds = [record?.id || ''];
if (isBatch) { if (isBatch) {
@ -358,7 +365,7 @@
}); });
} }
function stopTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) { function stopTask(record?: TaskCenterTaskDetailItem, isBatch?: boolean, params?: BatchActionQueryParams) {
let title = t('ms.taskCenter.stopTaskTitle', { name: characterLimit(record?.taskName) }); let title = t('ms.taskCenter.stopTaskTitle', { name: characterLimit(record?.taskName) });
let selectIds = [record?.id || '']; let selectIds = [record?.id || ''];
if (isBatch) { if (isBatch) {
@ -415,23 +422,67 @@
} }
} }
function rerunTask(record: any) { function rerunTask(record: TaskCenterTaskDetailItem) {
console.log('rerunTask', record); console.log('rerunTask', record);
} }
const executeResultId = ref(''); const executeResultId = ref('');
const caseExecuteResultDrawerVisible = ref(false); const caseExecuteResultDrawerVisible = ref(false);
const scenarioExecuteResultDrawerVisible = ref(false); const scenarioExecuteResultDrawerVisible = ref(false);
function checkExecuteResult(record: any) { function checkExecuteResult(record: TaskCenterTaskDetailItem) {
executeResultId.value = record.id; executeResultId.value = record.id;
scenarioExecuteResultDrawerVisible.value = true; if (record.resourceType === 'API_SCENARIO') {
scenarioExecuteResultDrawerVisible.value = true;
} else {
caseExecuteResultDrawerVisible.value = true;
}
} }
onMounted(() => { const currentResourcePoolRequest = {
system: getProjectTaskCenterResourcePools,
project: getOrgTaskCenterResourcePools,
org: getSystemTaskCenterResourcePools,
}[props.type];
async function initResourcePools() {
try {
const res = await currentResourcePoolRequest();
resourcePoolOptions.value = res.map((item) => ({
key: item,
value: item,
}));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
async function initCurrentPageResourcePoolsStatus() {
const ids = propsRes.value.data.map((item) => item.id);
if (ids.length === 0) {
return;
}
try {
const res = await getResourcePoolsStatus(ids);
res.forEach((item) => {
const target = propsRes.value.data.find((task) => task.id === item.id);
if (target) {
target.resourcePoolNodeStatus = item.status;
}
});
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
onMounted(async () => {
if (props.id) { if (props.id) {
keyword.value = props.id; keyword.value = props.id;
} }
searchTask(); initResourcePools();
await loadList();
initCurrentPageResourcePoolsStatus();
}); });
await tableStore.initColumn(TableKeyEnum.TASK_CENTER_CASE_TASK_DETAIL, columns, 'drawer'); await tableStore.initColumn(TableKeyEnum.TASK_CENTER_CASE_TASK_DETAIL, columns, 'drawer');

View File

@ -44,10 +44,16 @@
{{ t(executeMethodMap[record.triggerMode]) }} {{ t(executeMethodMap[record.triggerMode]) }}
</template> </template>
<template #executeRate="{ record }"> <template #executeRate="{ record }">
<a-popover trigger="hover" position="bottom"> <a-popover
<div>{{ record.executeRate }}%</div> v-model:popup-visible="record.executeRatePopVisible"
trigger="hover"
position="bottom"
:disabled="record.caseTotal === 0 || record.status === ExecuteStatusEnum.PENDING"
@popup-visible-change="($event) => handleExecuteRatePopVisibleChange($event, record)"
>
<div>{{ record.executeRate || '0.00' }}%</div>
<template #content> <template #content>
<div class="flex w-[130px] flex-col gap-[8px]"> <a-spin :loading="record.loading" class="flex w-[130px] flex-col gap-[8px]">
<div class="ms-taskCenter-execute-rate-item"> <div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label"> <div class="ms-taskCenter-execute-rate-item-label">
{{ t('ms.taskCenter.executeFinishedRate') }} {{ t('ms.taskCenter.executeFinishedRate') }}
@ -92,7 +98,7 @@
</div> </div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.errorCount }}</div> <div class="ms-taskCenter-execute-rate-item-value">{{ record.errorCount }}</div>
</div> </div>
</div> </a-spin>
</template> </template>
</a-popover> </a-popover>
</template> </template>
@ -123,6 +129,7 @@
</MsButton> </MsButton>
</template> </template>
</ms-base-table> </ms-base-table>
<batchTaskReportDrawer v-model:visible="taskReportDrawerVisible" type="case" :module-type="reportModuleType" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -135,6 +142,7 @@
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type'; import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue'; import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import batchTaskReportDrawer from './batchTaskReportDrawer.vue';
import execStatus from './execStatus.vue'; import execStatus from './execStatus.vue';
import executionStatus from './executionStatus.vue'; import executionStatus from './executionStatus.vue';
@ -145,16 +153,26 @@
getProjectExecuteTaskStatistics, getProjectExecuteTaskStatistics,
getSystemExecuteTaskList, getSystemExecuteTaskList,
getSystemExecuteTaskStatistics, getSystemExecuteTaskStatistics,
organizationDeleteTask,
organizationStopTask,
projectDeleteTask,
projectStopTask,
systemDeleteTask,
systemStopTask,
} from '@/api/modules/taskCenter'; } from '@/api/modules/taskCenter';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useOpenNewPage from '@/hooks/useOpenNewPage';
import useTableStore from '@/hooks/useTableStore'; import useTableStore from '@/hooks/useTableStore';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission'; import { hasAnyPermission } from '@/utils/permission';
import { TaskCenterTaskItem } from '@/models/taskCenter';
import { ReportEnum } from '@/enums/reportEnum';
import { ApiTestRouteEnum, TestPlanRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum'; import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import { ExecuteResultEnum, ExecuteStatusEnum } from '@/enums/taskCenter'; import { ExecuteResultEnum, ExecuteStatusEnum, ExecuteTaskType, ExecuteTriggerMode } from '@/enums/taskCenter';
import { executeFinishedRateMap, executeMethodMap, executeResultMap, executeStatusMap } from './config'; import { executeFinishedRateMap, executeMethodMap, executeResultMap, executeStatusMap } from './config';
@ -167,6 +185,7 @@
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal(); const { openModal } = useModal();
const { openNewPage } = useOpenNewPage();
const tableStore = useTableStore(); const tableStore = useTableStore();
const keyword = ref(''); const keyword = ref('');
@ -268,7 +287,7 @@
}, },
{ {
title: 'ms.taskCenter.operationUser', title: 'ms.taskCenter.operationUser',
dataIndex: 'createUser', dataIndex: 'createUserName',
width: 100, width: 100,
showTooltip: true, showTooltip: true,
}, },
@ -319,6 +338,18 @@
org: getOrganizationExecuteTaskStatistics, org: getOrganizationExecuteTaskStatistics,
}[props.type]; }[props.type];
const currentStopTask = {
system: projectStopTask,
project: organizationStopTask,
org: systemStopTask,
}[props.type];
const currentDeleteTask = {
system: projectDeleteTask,
project: organizationDeleteTask,
org: systemDeleteTask,
}[props.type];
const tableBatchActions = { const tableBatchActions = {
baseAction: [ baseAction: [
{ {
@ -347,9 +378,11 @@
(item) => { (item) => {
return { return {
...item, ...item,
startTime: dayjs(item.startTime).format('YYYY-MM-DD HH:mm:ss'), loading: false,
createTime: dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss'), executeRatePopVisible: false,
endTime: dayjs(item.endTime).format('YYYY-MM-DD HH:mm:ss'), startTime: item.startTime ? dayjs(item.startTime).format('YYYY-MM-DD HH:mm:ss') : '-',
createTime: item.createTime ? dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') : '-',
endTime: item.endTime ? dayjs(item.endTime).format('YYYY-MM-DD HH:mm:ss') : '-',
}; };
} }
); );
@ -359,115 +392,6 @@
loadList(); loadList();
} }
function showTaskDetail(id: string) {
emit('goDetail', id);
}
/**
* 删除任务
*/
function deleteTask(record?: any, isBatch?: boolean, params?: BatchActionQueryParams) {
let title = t('ms.taskCenter.deleteTaskTitle', { name: characterLimit(record?.taskName) });
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?.taskName) });
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);
}
async function initTaskStatistics() { async function initTaskStatistics() {
try { try {
const ids = propsRes.value.data.map((item) => item.id); const ids = propsRes.value.data.map((item) => item.id);
@ -496,8 +420,156 @@
initTaskStatistics(); initTaskStatistics();
} }
async function handleExecuteRatePopVisibleChange(visible: boolean, record: TaskCenterTaskItem) {
if (visible) {
try {
record.loading = true;
const res = await currentExecuteTaskStatistics([record.id]);
record.executeRate = res[0].executeRate;
record.pendingCount = res[0].pendingCount;
record.successCount = res[0].successCount;
record.fakeErrorCount = res[0].fakeErrorCount;
record.errorCount = res[0].errorCount;
record.caseTotal = res[0].caseTotal;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
record.loading = false;
}
}
}
function showTaskDetail(id: string) {
emit('goDetail', id);
}
/**
* 删除任务
*/
function deleteTask(record?: TaskCenterTaskItem, isBatch?: boolean, params?: BatchActionQueryParams) {
let title = t('ms.taskCenter.deleteTaskTitle', { name: characterLimit(record?.taskName) });
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 {
if (isBatch) {
// await deleteUserInfo({
// selectIds,
// selectAll: !!params?.selectAll,
// excludeIds: params?.excludeIds || [],
// condition: { keyword: keyword.value },
// });
} else {
await currentDeleteTask(record?.id || '');
}
Message.success(t('common.deleteSuccess'));
resetSelector();
refresh();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
}
function stopTask(record?: TaskCenterTaskItem, isBatch?: boolean, params?: BatchActionQueryParams) {
let title = t('ms.taskCenter.stopTaskTitle', { name: characterLimit(record?.taskName) });
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 {
if (isBatch) {
// await deleteUserInfo({
// selectIds,
// selectAll: !!params?.selectAll,
// excludeIds: params?.excludeIds || [],
// condition: { keyword: keyword.value },
// });
} else {
await currentStopTask(record?.id || '');
}
Message.success(t('common.stopped'));
resetSelector();
refresh();
} 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: TaskCenterTaskItem) {
console.log('rerunTask', record);
}
const taskReportDrawerVisible = ref(false);
const reportModuleType = ref();
function checkReport(record: TaskCenterTaskItem) {
if (record.taskType.includes('BATCH')) {
reportModuleType.value = record.taskType.includes('CASE')
? ReportEnum.API_REPORT
: ReportEnum.API_SCENARIO_REPORT;
taskReportDrawerVisible.value = true;
} else if (record.taskType === ExecuteTaskType.API_SCENARIO) {
openNewPage(ApiTestRouteEnum.API_TEST_REPORT);
} else if (record.taskType === ExecuteTaskType.TEST_PLAN) {
openNewPage(TestPlanRouteEnum.TEST_PLAN_REPORT);
}
}
onMounted(async () => { onMounted(async () => {
loadList(); searchTask();
}); });
watch( watch(

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="flex items-center justify-start"> <div class="flex items-center justify-start">
<MsIcon :type="getExecutionResult()?.icon" :class="`text-[${getExecutionResult()?.color}]`" size="14" /> <MsIcon :type="getExecutionResult()?.icon" :class="`text-[${getExecutionResult()?.color}]`" size="14" />
<span class="ml-1">{{ t(getExecutionResult()?.label) }}</span> <span class="ml-1">{{ t(getExecutionResult()?.label || '-') }}</span>
<!-- <a-tooltip v-if="props.scriptIdentifier" :content="getMsg()"> <!-- <a-tooltip v-if="props.scriptIdentifier" :content="getMsg()">
<MsTag <MsTag
class="ml-2" class="ml-2"

View File

@ -30,15 +30,22 @@
</a-button> </a-button>
</template> </template>
<template #status="{ record }"> <template #status="{ record }">
<a-switch v-model:model-value="record.enable" size="small"></a-switch> <a-switch
v-model:model-value="record.enable"
size="small"
:before-change="() => handleBeforeEnableChange(record)"
></a-switch>
</template> </template>
<template #resourceType="{ record }"> <template #resourceType="{ record }">
{{ t(scheduleTaskTypeMap[record.resourceType]) }} {{ t(scheduleTaskTypeMap[record.resourceType]) }}
</template> </template>
<template #action="{ record }"> <template #action="{ record }">
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" @click="deleteTask(record)"> <MsButton v-permission="['SYSTEM_USER:READ+DELETE']" class="!mr-[12px]" @click="deleteTask(record)">
{{ t('common.delete') }} {{ t('common.delete') }}
</MsButton> </MsButton>
<MsButton v-permission="['SYSTEM_USER:READ+DELETE']" class="!mr-0" @click="checkDetail(record)">
{{ t('common.detail') }}
</MsButton>
</template> </template>
</ms-base-table> </ms-base-table>
</template> </template>
@ -57,10 +64,12 @@
import { getOrganizationScheduleList, getProjectScheduleList, getSystemScheduleList } from '@/api/modules/taskCenter'; import { getOrganizationScheduleList, getProjectScheduleList, getSystemScheduleList } from '@/api/modules/taskCenter';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useOpenNewPage from '@/hooks/useOpenNewPage';
import useTableStore from '@/hooks/useTableStore'; import useTableStore from '@/hooks/useTableStore';
import { characterLimit } from '@/utils'; import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission'; import { hasAnyPermission } from '@/utils/permission';
import { ApiTestRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { scheduleTaskTypeMap } from './config'; import { scheduleTaskTypeMap } from './config';
@ -71,6 +80,7 @@
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal(); const { openModal } = useModal();
const { openNewPage } = useOpenNewPage();
const tableStore = useTableStore(); const tableStore = useTableStore();
const keyword = ref(''); const keyword = ref('');
@ -146,7 +156,7 @@
slotName: 'action', slotName: 'action',
dataIndex: 'operation', dataIndex: 'operation',
fixed: 'right', fixed: 'right',
width: 60, width: 110,
}, },
]; ];
if (props.type === 'system') { if (props.type === 'system') {
@ -209,9 +219,9 @@
(item) => { (item) => {
return { return {
...item, ...item,
operationTime: dayjs(item.operationTime).format('YYYY-MM-DD HH:mm:ss'), operationTime: item.operationTime ? dayjs(item.operationTime).format('YYYY-MM-DD HH:mm:ss') : '-',
lastFinishTime: dayjs(item.lastFinishTime).format('YYYY-MM-DD HH:mm:ss'), lastFinishTime: item.lastFinishTime ? dayjs(item.lastFinishTime).format('YYYY-MM-DD HH:mm:ss') : '-',
nextExecuteTime: dayjs(item.nextExecuteTime).format('YYYY-MM-DD HH:mm:ss'), nextExecuteTime: item.nextExecuteTime ? dayjs(item.nextExecuteTime).format('YYYY-MM-DD HH:mm:ss') : '-',
}; };
} }
); );
@ -271,6 +281,23 @@
console.log(record); console.log(record);
} }
function checkDetail(record: any) {
openNewPage(ApiTestRouteEnum.API_TEST_MANAGEMENT, {
taskDrawer: true,
});
}
async function handleBeforeEnableChange(record: any) {
try {
Message.success(t(record.enable ? 'ms.taskCenter.closeTaskSuccess' : 'ms.taskCenter.openTaskSuccess'));
return true;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
return false;
}
}
/** /**
* 处理表格选中后批量操作 * 处理表格选中后批量操作
* @param event 批量操作事件对象 * @param event 批量操作事件对象

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<a-tabs v-model:active-key="activeTab" class="no-content"> <a-tabs v-model:active-key="activeTab" class="no-content" @change="handleTabChange">
<a-tab-pane v-for="item of tabList" :key="item.value" :title="item.label" /> <a-tab-pane v-for="item of tabList" :key="item.value" :title="item.label" />
</a-tabs> </a-tabs>
<a-divider margin="0"></a-divider> <a-divider margin="0"></a-divider>
@ -22,7 +22,10 @@
import systemTaskTable from './component/systemTaskTable.vue'; import systemTaskTable from './component/systemTaskTable.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useLocalForage from '@/hooks/useLocalForage';
import useGlobalStore from '@/store/modules/global';
import { GlobalEventNameEnum } from '@/enums/commonEnum';
import { TaskCenterEnum } from '@/enums/taskCenter'; import { TaskCenterEnum } from '@/enums/taskCenter';
const props = defineProps<{ const props = defineProps<{
@ -32,6 +35,8 @@
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const globalStore = useGlobalStore();
const { getItem, setItem } = useLocalForage();
const tabList = ref([ const tabList = ref([
{ {
@ -55,6 +60,24 @@
activeTaskId.value = id; activeTaskId.value = id;
activeTab.value = TaskCenterEnum.DETAIL; activeTab.value = TaskCenterEnum.DETAIL;
} }
function handleTabChange(key: string | number) {
setItem('taskCenterActiveTab', key);
}
watch(
() => globalStore.getGlobalEvent,
(event) => {
if (event && event.id && event.name === GlobalEventNameEnum.OPEN_TASK_CENTER) {
activeTab.value = event.params?.tab;
setItem('taskCenterActiveTab', event.params?.tab);
}
}
);
onBeforeMount(async () => {
activeTab.value = (await getItem('taskCenterActiveTab')) || TaskCenterEnum.CASE;
});
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

View File

@ -8,7 +8,7 @@ export default {
'ms.taskCenter.taskName': 'Task Name', 'ms.taskCenter.taskName': 'Task Name',
'ms.taskCenter.executeStatus': 'Execution Status', 'ms.taskCenter.executeStatus': 'Execution Status',
'ms.taskCenter.executeMethod': 'Execution Method', 'ms.taskCenter.executeMethod': 'Execution Method',
'ms.taskCenter.executeResult': 'Execution Result', 'ms.taskCenter.executeResult': 'Result',
'ms.taskCenter.caseCount': 'Case Count', 'ms.taskCenter.caseCount': 'Case Count',
'ms.taskCenter.executeFinishedRate': 'Execution Completion Rate', 'ms.taskCenter.executeFinishedRate': 'Execution Completion Rate',
'ms.taskCenter.createTime': 'Initiation Time', 'ms.taskCenter.createTime': 'Initiation Time',
@ -53,4 +53,6 @@ export default {
'ms.taskCenter.apiImport': 'API Import', 'ms.taskCenter.apiImport': 'API Import',
'ms.taskCenter.apiScenario': 'Api Scenario', 'ms.taskCenter.apiScenario': 'Api Scenario',
'ms.taskCenter.thirdPartSync': 'Third-party sync', 'ms.taskCenter.thirdPartSync': 'Third-party sync',
'ms.taskCenter.openTaskSuccess': 'Task started successfully',
'ms.taskCenter.closeTaskSuccess': 'Task closed successfully',
}; };

View File

@ -53,4 +53,6 @@ export default {
'ms.taskCenter.apiImport': 'API导入', 'ms.taskCenter.apiImport': 'API导入',
'ms.taskCenter.apiScenario': '接口场景', 'ms.taskCenter.apiScenario': '接口场景',
'ms.taskCenter.thirdPartSync': '第三方同步', 'ms.taskCenter.thirdPartSync': '第三方同步',
'ms.taskCenter.openTaskSuccess': '任务开启成功',
'ms.taskCenter.closeTaskSuccess': '任务关闭成功',
}; };

View File

@ -362,7 +362,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { FormInstance, Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@ -381,6 +381,7 @@
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue'; import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types'; import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue'; import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import MsRichMessage from '@/components/business/ms-rich-message/index.vue';
import MsStatusTag from '@/components/business/ms-status-tag/index.vue'; import MsStatusTag from '@/components/business/ms-status-tag/index.vue';
import executeHistoryTable from '../detail/executeHistory/index.vue'; import executeHistoryTable from '../detail/executeHistory/index.vue';
import ActionModal from './actionModal.vue'; import ActionModal from './actionModal.vue';
@ -391,7 +392,7 @@
import PlanExpandRow from '@/views/test-plan/testPlan/components/planExpandRow.vue'; import PlanExpandRow from '@/views/test-plan/testPlan/components/planExpandRow.vue';
import { import {
addTestPlan, // addTestPlan,
archivedPlan, archivedPlan,
batchArchivedPlan, batchArchivedPlan,
batchCopyPlan, batchCopyPlan,
@ -414,12 +415,13 @@
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import { useAppStore, useTableStore } from '@/store'; import { useAppStore, useTableStore } from '@/store';
import useCacheStore from '@/store/modules/cache/cache'; import useCacheStore from '@/store/modules/cache/cache';
import { characterLimit } from '@/utils'; import useGlobalStore from '@/store/modules/global';
import { characterLimit, getGenerateId } from '@/utils';
import { hasAnyPermission } from '@/utils/permission'; import { hasAnyPermission } from '@/utils/permission';
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common'; import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
import type { import type {
AddTestPlanParams, // AddTestPlanParams,
BatchExecutePlan, BatchExecutePlan,
BatchMoveParams, BatchMoveParams,
CreateTask, CreateTask,
@ -429,18 +431,20 @@
TestPlanItem, TestPlanItem,
} from '@/models/testPlan/testPlan'; } from '@/models/testPlan/testPlan';
import { LastExecuteResults } from '@/enums/caseEnum'; import { LastExecuteResults } from '@/enums/caseEnum';
import { GlobalEventNameEnum } from '@/enums/commonEnum';
import { RouteEnum, TestPlanRouteEnum } from '@/enums/routeEnum'; import { RouteEnum, TestPlanRouteEnum } from '@/enums/routeEnum';
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum'; import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum'; import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import { TaskCenterEnum } from '@/enums/taskCenter';
import { testPlanTypeEnum } from '@/enums/testPlanEnum'; import { testPlanTypeEnum } from '@/enums/testPlanEnum';
import { planStatusOptions } from '../config'; import { planStatusOptions } from '../config';
import { getModules } from '@/views/case-management/caseManagementFeature/components/utils'; import { getModules } from '@/views/case-management/caseManagementFeature/components/utils';
const cacheStore = useCacheStore(); const cacheStore = useCacheStore();
const tableStore = useTableStore(); const tableStore = useTableStore();
const appStore = useAppStore(); const appStore = useAppStore();
const globalStore = useGlobalStore();
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal(); const { openModal } = useModal();
@ -1001,7 +1005,35 @@
try { try {
await executePlanOrGroup(executeForm.value); await executePlanOrGroup(executeForm.value);
cancelHandler(); cancelHandler();
Message.success(t('case.detail.execute.success')); Message.success({
content: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
gap: '4px',
},
},
[
h(MsRichMessage, {
content: t('case.detail.execute.success'),
onGoDetail() {
globalStore.dispatchGlobalEvent({
id: getGenerateId(),
name: GlobalEventNameEnum.OPEN_TASK_CENTER,
params: {
tab: TaskCenterEnum.CASE,
},
});
},
}),
]
),
duration: 5000,
closable: true,
});
fetchData(); fetchData();
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
@ -1022,7 +1054,35 @@
executionSource: 'MANUAL', executionSource: 'MANUAL',
}; };
await executeSinglePlan(params); await executeSinglePlan(params);
Message.success(t('case.detail.execute.success')); Message.success({
content: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
gap: '4px',
},
},
[
h(MsRichMessage, {
content: t('case.detail.execute.success'),
onGoDetail() {
globalStore.dispatchGlobalEvent({
id: getGenerateId(),
name: GlobalEventNameEnum.OPEN_TASK_CENTER,
params: {
tab: TaskCenterEnum.CASE,
},
});
},
}),
]
),
duration: 5000,
closable: true,
});
fetchData(); fetchData();
cancelHandler(); cancelHandler();
} catch (error) { } catch (error) {
@ -1535,73 +1595,73 @@
emitTableParams(); emitTableParams();
} }
const showQuickCreateForm = ref(false); // const showQuickCreateForm = ref(false);
const quickCreateFormRef = ref<FormInstance>(); // const quickCreateFormRef = ref<FormInstance>();
const initPlanGroupForm: AddTestPlanParams = { // const initPlanGroupForm: AddTestPlanParams = {
groupId: 'NONE', // groupId: 'NONE',
name: '', // name: '',
projectId: appStore.currentProjectId, // projectId: appStore.currentProjectId,
moduleId: '', // moduleId: '',
cycle: [], // cycle: [],
tags: [], // tags: [],
description: '', // description: '',
testPlanning: false, // testPlanning: false,
automaticStatusUpdate: true, // automaticStatusUpdate: true,
repeatCase: false, // repeatCase: false,
passThreshold: 100, // passThreshold: 100,
type: testPlanTypeEnum.GROUP, // type: testPlanTypeEnum.GROUP,
baseAssociateCaseRequest: { selectIds: [], selectAll: false, condition: {} }, // baseAssociateCaseRequest: { selectIds: [], selectAll: false, condition: {} },
}; // };
const quickCreateForm = ref<AddTestPlanParams>(cloneDeep(initPlanGroupForm)); // const quickCreateForm = ref<AddTestPlanParams>(cloneDeep(initPlanGroupForm));
const quickCreateLoading = ref(false); // const quickCreateLoading = ref(false);
function quickCreateCancel() { // function quickCreateCancel() {
showQuickCreateForm.value = false; // showQuickCreateForm.value = false;
quickCreateForm.value = cloneDeep(initPlanGroupForm); // quickCreateForm.value = cloneDeep(initPlanGroupForm);
quickCreateFormRef.value?.resetFields(); // quickCreateFormRef.value?.resetFields();
} // }
/** /**
* 快速创建测试计划或者测试计划组 * 快速创建测试计划或者测试计划组
*/ */
const createType = ref<keyof typeof testPlanTypeEnum>(showType.value); // const createType = ref<keyof typeof testPlanTypeEnum>(showType.value);
// TODO: // TODO:
function quickCreateConfirm() { // function quickCreateConfirm() {
quickCreateFormRef.value?.validate(async (errors) => { // quickCreateFormRef.value?.validate(async (errors) => {
if (!errors) { // if (!errors) {
try { // try {
quickCreateLoading.value = true; // quickCreateLoading.value = true;
const params = { // const params = {
...cloneDeep(quickCreateForm.value), // ...cloneDeep(quickCreateForm.value),
groupId: 'NONE', // groupId: 'NONE',
projectId: appStore.currentProjectId, // projectId: appStore.currentProjectId,
moduleId: props.activeFolder === 'all' ? 'root' : props.activeFolder, // moduleId: props.activeFolder === 'all' ? 'root' : props.activeFolder,
testPlanning: false, // testPlanning: false,
automaticStatusUpdate: true, // automaticStatusUpdate: true,
repeatCase: false, // repeatCase: false,
passThreshold: 100, // passThreshold: 100,
type: showType.value === testPlanTypeEnum.ALL ? createType.value : showType.value, // type: showType.value === testPlanTypeEnum.ALL ? createType.value : showType.value,
}; // };
await addTestPlan(params); // await addTestPlan(params);
Message.success(t('common.createSuccess')); // Message.success(t('common.createSuccess'));
quickCreateCancel(); // quickCreateCancel();
fetchData(); // fetchData();
} catch (error) { // } catch (error) {
// eslint-disable-next-line no-console // // eslint-disable-next-line no-console
console.log(error); // console.log(error);
} finally { // } finally {
quickCreateLoading.value = false; // quickCreateLoading.value = false;
} // }
} // }
}); // });
} // }
// TODO: // TODO:
function handleSelect(value: string | number | Record<string, any> | undefined) { // function handleSelect(value: string | number | Record<string, any> | undefined) {
showQuickCreateForm.value = true; // showQuickCreateForm.value = true;
createType.value = value as keyof typeof testPlanTypeEnum; // createType.value = value as keyof typeof testPlanTypeEnum;
} // }
// //
function archivedChangeHandler() { function archivedChangeHandler() {

View File

@ -150,6 +150,7 @@
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsBugOperation from '@/components/business/ms-bug-operation/index.vue'; import MsBugOperation from '@/components/business/ms-bug-operation/index.vue';
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import MsRichMessage from '@/components/business/ms-rich-message/index.vue';
import ApiMethodName from '@/views/api-test/components/apiMethodName.vue'; import ApiMethodName from '@/views/api-test/components/apiMethodName.vue';
import apiStatus from '@/views/api-test/components/apiStatus.vue'; import apiStatus from '@/views/api-test/components/apiStatus.vue';
import CaseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue'; import CaseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
@ -178,7 +179,8 @@
import useOpenNewPage from '@/hooks/useOpenNewPage'; import useOpenNewPage from '@/hooks/useOpenNewPage';
import useTableStore from '@/hooks/useTableStore'; import useTableStore from '@/hooks/useTableStore';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { characterLimit } from '@/utils'; import useGlobalStore from '@/store/modules/global';
import { characterLimit, getGenerateId } from '@/utils';
import { hasAllPermission, hasAnyPermission } from '@/utils/permission'; import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common'; import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
@ -187,10 +189,12 @@
import { FilterType, ViewTypeEnum } from '@/enums/advancedFilterEnum'; import { FilterType, ViewTypeEnum } from '@/enums/advancedFilterEnum';
import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum'; import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum';
import { CaseLinkEnum } from '@/enums/caseEnum'; import { CaseLinkEnum } from '@/enums/caseEnum';
import { GlobalEventNameEnum } from '@/enums/commonEnum';
import { ReportEnum } from '@/enums/reportEnum'; import { ReportEnum } from '@/enums/reportEnum';
import { ApiTestRouteEnum } from '@/enums/routeEnum'; import { ApiTestRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum'; import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import { TaskCenterEnum } from '@/enums/taskCenter';
import { import {
casePriorityOptions, casePriorityOptions,
@ -222,6 +226,7 @@
const { openModal } = useModal(); const { openModal } = useModal();
const { openNewPage } = useOpenNewPage(); const { openNewPage } = useOpenNewPage();
const appStore = useAppStore(); const appStore = useAppStore();
const globalStore = useGlobalStore();
const keyword = ref(''); const keyword = ref('');
@ -823,7 +828,35 @@
try { try {
tableLoading.value = true; tableLoading.value = true;
await runApiCase(record.id); await runApiCase(record.id);
Message.success(t('common.executionSuccess')); Message.success({
content: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
gap: '4px',
},
},
[
h(MsRichMessage, {
content: t('case.detail.execute.success'),
onGoDetail() {
globalStore.dispatchGlobalEvent({
id: getGenerateId(),
name: GlobalEventNameEnum.OPEN_TASK_CENTER,
params: {
tab: TaskCenterEnum.DETAIL,
},
});
},
}),
]
),
duration: 5000,
closable: true,
});
resetSelectorAndCaseList(); resetSelectorAndCaseList();
emit('refresh'); emit('refresh');
} catch (error) { } catch (error) {
@ -845,7 +878,35 @@
excludeIds: batchParams.value?.excludeIds || [], excludeIds: batchParams.value?.excludeIds || [],
...tableParams, ...tableParams,
}); });
Message.success(t('common.operationSuccess')); Message.success({
content: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
gap: '4px',
},
},
[
h(MsRichMessage, {
content: t('case.detail.execute.success'),
onGoDetail() {
globalStore.dispatchGlobalEvent({
id: getGenerateId(),
name: GlobalEventNameEnum.OPEN_TASK_CENTER,
params: {
tab: TaskCenterEnum.DETAIL,
},
});
},
}),
]
),
duration: 5000,
closable: true,
});
resetSelectorAndCaseList(); resetSelectorAndCaseList();
emit('refresh'); emit('refresh');
} catch (error) { } catch (error) {

View File

@ -150,6 +150,7 @@
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsBugOperation from '@/components/business/ms-bug-operation/index.vue'; import MsBugOperation from '@/components/business/ms-bug-operation/index.vue';
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import MsRichMessage from '@/components/business/ms-rich-message/index.vue';
import apiStatus from '@/views/api-test/components/apiStatus.vue'; import apiStatus from '@/views/api-test/components/apiStatus.vue';
import CaseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue'; import CaseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue'; import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
@ -177,7 +178,8 @@
import useOpenNewPage from '@/hooks/useOpenNewPage'; import useOpenNewPage from '@/hooks/useOpenNewPage';
import useTableStore from '@/hooks/useTableStore'; import useTableStore from '@/hooks/useTableStore';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { characterLimit } from '@/utils'; import useGlobalStore from '@/store/modules/global';
import { characterLimit, getGenerateId } from '@/utils';
import { hasAllPermission, hasAnyPermission } from '@/utils/permission'; import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common'; import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
@ -186,10 +188,12 @@
import { FilterType, ViewTypeEnum } from '@/enums/advancedFilterEnum'; import { FilterType, ViewTypeEnum } from '@/enums/advancedFilterEnum';
import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum'; import { AssociatedBugApiTypeEnum } from '@/enums/associateBugEnum';
import { CaseLinkEnum } from '@/enums/caseEnum'; import { CaseLinkEnum } from '@/enums/caseEnum';
import { GlobalEventNameEnum } from '@/enums/commonEnum';
import { ReportEnum } from '@/enums/reportEnum'; import { ReportEnum } from '@/enums/reportEnum';
import { ApiTestRouteEnum } from '@/enums/routeEnum'; import { ApiTestRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum'; import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import { TaskCenterEnum } from '@/enums/taskCenter';
import { casePriorityOptions, lastReportStatusListOptions } from '@/views/api-test/components/config'; import { casePriorityOptions, lastReportStatusListOptions } from '@/views/api-test/components/config';
import { scenarioStatusOptions } from '@/views/api-test/scenario/components/config'; import { scenarioStatusOptions } from '@/views/api-test/scenario/components/config';
@ -216,6 +220,7 @@
const { openModal } = useModal(); const { openModal } = useModal();
const { openNewPage } = useOpenNewPage(); const { openNewPage } = useOpenNewPage();
const appStore = useAppStore(); const appStore = useAppStore();
const globalStore = useGlobalStore();
const keyword = ref(''); const keyword = ref('');
@ -793,7 +798,35 @@
try { try {
tableLoading.value = true; tableLoading.value = true;
await runApiScenario(record.id); await runApiScenario(record.id);
Message.success(t('common.executionSuccess')); Message.success({
content: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
gap: '4px',
},
},
[
h(MsRichMessage, {
content: t('case.detail.execute.success'),
onGoDetail() {
globalStore.dispatchGlobalEvent({
id: getGenerateId(),
name: GlobalEventNameEnum.OPEN_TASK_CENTER,
params: {
tab: TaskCenterEnum.DETAIL,
},
});
},
}),
]
),
duration: 5000,
closable: true,
});
resetSelectorAndCaseList(); resetSelectorAndCaseList();
emit('refresh'); emit('refresh');
} catch (error) { } catch (error) {
@ -815,7 +848,35 @@
excludeIds: batchParams.value?.excludeIds || [], excludeIds: batchParams.value?.excludeIds || [],
...tableParams, ...tableParams,
}); });
Message.success(t('common.operationSuccess')); Message.success({
content: () =>
h(
'div',
{
style: {
display: 'flex',
alignItems: 'center',
gap: '4px',
},
},
[
h(MsRichMessage, {
content: t('case.detail.execute.success'),
onGoDetail() {
globalStore.dispatchGlobalEvent({
id: getGenerateId(),
name: GlobalEventNameEnum.OPEN_TASK_CENTER,
params: {
tab: TaskCenterEnum.DETAIL,
},
});
},
}),
]
),
duration: 5000,
closable: true,
});
resetSelectorAndCaseList(); resetSelectorAndCaseList();
emit('refresh'); emit('refresh');
} catch (error) { } catch (error) {