feat(接口测试): 统一替换接口测试所有的table表头筛选
This commit is contained in:
parent
c191e40a14
commit
37deac293a
|
@ -16,6 +16,7 @@ import {
|
|||
DeleteTestPlanModuleUrl,
|
||||
DisassociateCaseUrl,
|
||||
followPlanUrl,
|
||||
GetAssociatedBugUrl,
|
||||
GetFeatureCaseModuleCountUrl,
|
||||
GetFeatureCaseModuleUrl,
|
||||
GetPlanDetailFeatureCaseListUrl,
|
||||
|
@ -29,6 +30,8 @@ import {
|
|||
planPassRateUrl,
|
||||
RunFeatureCaseUrl,
|
||||
SortFeatureCaseUrl,
|
||||
TestPlanAssociateBugUrl,
|
||||
TestPlanCancelBugUrl,
|
||||
updateTestPlanModuleUrl,
|
||||
UpdateTestPlanUrl,
|
||||
} from '@/api/requrls/test-plan/testPlan';
|
||||
|
@ -188,3 +191,15 @@ export function batchUpdateCaseExecutor(data: BatchUpdateCaseExecutorParams) {
|
|||
export function runFeatureCase(data: RunFeatureCaseParams) {
|
||||
return MSR.post({ url: RunFeatureCaseUrl, data });
|
||||
}
|
||||
// 测试计划-用例详情-缺陷列表
|
||||
export function associatedBugPage(data: TableQueryParams) {
|
||||
return MSR.post({ url: GetAssociatedBugUrl, data });
|
||||
}
|
||||
// 测试计划-用例详情-关联缺陷
|
||||
export function associateBugToPlan(data: TableQueryParams) {
|
||||
return MSR.post({ url: TestPlanAssociateBugUrl, data });
|
||||
}
|
||||
// 测试计划-用例详情-关联缺陷
|
||||
export function testPlanCancelBug(id: string) {
|
||||
return MSR.get({ url: `${TestPlanCancelBugUrl}/${id}` });
|
||||
}
|
||||
|
|
|
@ -56,6 +56,12 @@ export const DisassociateCaseUrl = '/test-plan/functional/case/disassociate';
|
|||
export const BatchDisassociateCaseUrl = '/test-plan/functional/case/batch/disassociate';
|
||||
// 计划详情-功能用例-执行
|
||||
export const RunFeatureCaseUrl = '/test-plan/functional/case/run';
|
||||
// 测试计划-用例详情-缺陷列表
|
||||
export const GetAssociatedBugUrl = '/test-plan/functional/case/has/associate/bug/page';
|
||||
// 测试计划-用例详情-关联缺陷
|
||||
export const TestPlanAssociateBugUrl = '/test-plan/functional/case/associate/bug';
|
||||
// 测试计划-用例详情-取消关联缺陷
|
||||
export const TestPlanCancelBugUrl = '/test-plan/functional/case/disassociate/bug';
|
||||
// 计划详情-功能用例-批量执行
|
||||
export const BatchRunCaseUrl = '/test-plan/functional/case/batch/run';
|
||||
// 计划详情-功能用例-批量更新执行人
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
:type="lastExecuteResultMap[props.executeResult]?.icon || ''"
|
||||
class="mr-1"
|
||||
:size="16"
|
||||
:style="{ color: lastExecuteResultMap[props.executeResult].color }"
|
||||
:style="{ color: lastExecuteResultMap[props.executeResult]?.color }"
|
||||
></MsIcon>
|
||||
<span class="text-[14px]">{{ status?.text || '' }}</span>
|
||||
<span class="text-[14px]">{{ lastExecuteResultMap[props.executeResult]?.statusText || '-' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -24,46 +24,42 @@
|
|||
}>();
|
||||
|
||||
const lastExecuteResultMap = {
|
||||
UN_EXECUTED: {
|
||||
label: 'UN_EXECUTED',
|
||||
icon: StatusType.UN_EXECUTED,
|
||||
statusText: 'caseManagement.featureCase.nonExecution',
|
||||
PENDING: {
|
||||
label: 'PENDING',
|
||||
icon: StatusType.PENDING,
|
||||
statusText: t('caseManagement.featureCase.nonExecution'),
|
||||
color: 'var(--color-text-brand)',
|
||||
},
|
||||
PASSED: {
|
||||
label: 'PASSED',
|
||||
icon: StatusType.PASSED,
|
||||
statusText: 'common.success',
|
||||
SUCCESS: {
|
||||
label: 'SUCCESS',
|
||||
icon: StatusType.SUCCESS,
|
||||
statusText: t('common.success'),
|
||||
color: '',
|
||||
},
|
||||
SKIPPED: {
|
||||
label: 'SKIPPED',
|
||||
icon: StatusType.SKIPPED,
|
||||
statusText: 'caseManagement.featureCase.skip',
|
||||
color: 'rgb(var(--link-6))',
|
||||
},
|
||||
BLOCKED: {
|
||||
label: 'BLOCKED',
|
||||
icon: StatusType.BLOCKED,
|
||||
statusText: 'caseManagement.featureCase.chokeUp',
|
||||
statusText: t('caseManagement.featureCase.chokeUp'),
|
||||
color: 'rgb(var(--warning-6))',
|
||||
},
|
||||
FAILED: {
|
||||
label: 'FAILED',
|
||||
icon: StatusType.FAILED,
|
||||
statusText: 'caseManagement.featureCase.failure',
|
||||
ERROR: {
|
||||
label: 'ERROR',
|
||||
icon: StatusType.ERROR,
|
||||
statusText: t('caseManagement.featureCase.failure'),
|
||||
color: '',
|
||||
},
|
||||
};
|
||||
|
||||
const status = computed(() => {
|
||||
if (props.executeResult) {
|
||||
const config = lastExecuteResultMap[props.executeResult];
|
||||
return {
|
||||
text: t(config?.statusText || ''),
|
||||
};
|
||||
}
|
||||
});
|
||||
// const status = computed(() => {
|
||||
// if (props.executeResult) {
|
||||
// const config = lastExecuteResultMap[props.executeResult];
|
||||
// if (config) {
|
||||
// return {
|
||||
// text: t(config?.statusText || ''),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -66,8 +66,8 @@
|
|||
:sortable="item.sortable"
|
||||
:filterable="item.filterable"
|
||||
:cell-class="item.cellClass"
|
||||
:header-cell-class="`${
|
||||
item.headerCellClass || (item.filterConfig && hasSelectedFilter(item)) ? 'header-cell-filter' : ''
|
||||
:header-cell-class="`${item.filterConfig && hasSelectedFilter(item) ? 'header-cell-filter' : ''} ${
|
||||
item.headerCellClass
|
||||
}`"
|
||||
:body-cell-class="item.bodyCellClass"
|
||||
:summary-cell-class="item.summaryCellClass"
|
||||
|
@ -101,7 +101,7 @@
|
|||
@init-data="handleInitColumn"
|
||||
/>
|
||||
<DefaultFilter
|
||||
v-else-if="item.filterConfig"
|
||||
v-else-if="(item.filterConfig && item.filterConfig.options?.length) || item?.filterConfig?.remoteMethod"
|
||||
class="ml-[4px]"
|
||||
:options="item.filterConfig.options"
|
||||
:data-index="item.dataIndex"
|
||||
|
@ -639,6 +639,10 @@
|
|||
columnSelectorVisible.value = true;
|
||||
};
|
||||
|
||||
const filterData = computed(() => {
|
||||
return (attrs.filter || {}) as Record<string, any>;
|
||||
});
|
||||
|
||||
const handleFilterConfirm = (
|
||||
value: string[] | (string | number)[] | undefined,
|
||||
dataIndex: string,
|
||||
|
@ -652,10 +656,6 @@
|
|||
batchLeft.value = getBatchLeft();
|
||||
});
|
||||
|
||||
const filterData = computed(() => {
|
||||
return (attrs.filter || {}) as Record<string, any>;
|
||||
});
|
||||
|
||||
function hasSelectedFilter(item: MsTableColumnData) {
|
||||
if (item.filterConfig && item.dataIndex) {
|
||||
return (filterData.value[item.dataIndex] || []).length > 0;
|
||||
|
|
|
@ -160,7 +160,7 @@
|
|||
const isNoFilter = computed(() => {
|
||||
if (props.filter && JSON.stringify(props.filter) !== '{}') {
|
||||
return !Object.keys(props.filter).some((key: any) => {
|
||||
return props.filter[key].length > 0;
|
||||
return (props.filter[key] || []).length > 0;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { getProjectMemberOptions } from '@/api/modules/project-management/projectMember';
|
||||
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
|
||||
import { getProjectList } from '@/api/modules/setting/member';
|
||||
import { getOrgOptions, getSystemProjectList } from '@/api/modules/system';
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { FilterRemoteMethodsEnum } from '@/enums/tableFilterEnum';
|
|||
export function initRemoteOptionsFunc(remoteMethod: string, params: Record<string, any>) {
|
||||
switch (remoteMethod) {
|
||||
case FilterRemoteMethodsEnum.PROJECT_PERMISSION_MEMBER:
|
||||
return getProjectMemberOptions(params.projectId, params.keyword);
|
||||
return getProjectOptions(params.projectId, params.keyword);
|
||||
case FilterRemoteMethodsEnum.SYSTEM_ORGANIZATION_LIST:
|
||||
return getOrgOptions();
|
||||
case FilterRemoteMethodsEnum.SYSTEM_PROJECT_LIST:
|
||||
|
|
|
@ -2,22 +2,21 @@
|
|||
export enum StatusType {
|
||||
UN_REVIEWED = 'icon-icon_block_filled', // 未评审
|
||||
UNDER_REVIEWED = 'icon-icon_testing', // 评审中
|
||||
SUCCESS = 'icon-icon_succeed_colorful', // 成功
|
||||
PASS = 'icon-icon_succeed_colorful', // 已通过
|
||||
UN_PASS = 'icon-icon_close_colorful', // 未通过
|
||||
RE_REVIEWED = 'icon-icon_resubmit_filled', // 重新提审
|
||||
UN_EXECUTED = 'icon-icon_block_filled', // 未执行
|
||||
PASSED = 'icon-icon_succeed_colorful', // 已执行
|
||||
FAILED = 'icon-icon_close_colorful', // 失败
|
||||
ERROR = 'icon-icon_close_colorful', // 失败
|
||||
BLOCKED = 'icon-icon_block_filled', // 阻塞
|
||||
SKIPPED = 'icon-icon_skip_planarity', // 跳过
|
||||
PENDING = 'icon-icon_block_filled', // 未执行
|
||||
}
|
||||
|
||||
export enum LastExecuteResults {
|
||||
UN_EXECUTED = 'UN_EXECUTED',
|
||||
PASSED = 'PASSED',
|
||||
SKIPPED = 'SKIPPED',
|
||||
PENDING = 'PENDING',
|
||||
SUCCESS = 'SUCCESS',
|
||||
BLOCKED = 'BLOCKED',
|
||||
FAILED = 'FAILED',
|
||||
ERROR = 'ERROR',
|
||||
}
|
||||
|
||||
export enum CaseLinkEnum {
|
||||
|
|
|
@ -18,7 +18,14 @@ export enum TriggerModeLabel {
|
|||
BATCH = 'report.trigger.batch.execution', // 批量执行
|
||||
API = 'report.trigger.interface', // 接口调用
|
||||
}
|
||||
export const ReportStatus = {
|
||||
export enum TriggerModeLabelEnum {
|
||||
MANUAL = 'MANUAL', // 手动执行
|
||||
SCHEDULE = 'SCHEDULE', // 定时任务
|
||||
BATCH = 'BATCH', // 批量执行
|
||||
API = 'API', // 接口调用
|
||||
}
|
||||
|
||||
export const ReportStatus: Record<ReportEnum, Record<string, { icon: string; label: string; color?: string }>> = {
|
||||
[ReportEnum.API_REPORT]: {
|
||||
SUCCESS: {
|
||||
icon: 'icon-icon_succeed_colorful',
|
||||
|
@ -30,16 +37,16 @@ export const ReportStatus = {
|
|||
},
|
||||
FAKE_ERROR: {
|
||||
icon: 'icon-icon_warning_colorful',
|
||||
label: 'report.falseAlarm',
|
||||
label: 'report.fake.error',
|
||||
},
|
||||
STOPPED: {
|
||||
icon: 'icon-icon_block_filled',
|
||||
label: 'report.stop',
|
||||
label: 'report.stopped',
|
||||
color: '!var(--color-text-input-border)',
|
||||
},
|
||||
RUNNING: {
|
||||
icon: 'icon-icon_testing',
|
||||
label: 'report.inExecution',
|
||||
label: 'report.status.running',
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
// RERUNNING: {
|
||||
|
@ -49,7 +56,7 @@ export const ReportStatus = {
|
|||
// },
|
||||
PENDING: {
|
||||
icon: 'icon-icon_wait',
|
||||
label: 'report.queuing',
|
||||
label: 'report.status.pending',
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
},
|
||||
|
@ -64,16 +71,16 @@ export const ReportStatus = {
|
|||
},
|
||||
FAKE_ERROR: {
|
||||
icon: 'icon-icon_warning_colorful',
|
||||
label: 'report.falseAlarm',
|
||||
label: 'report.fake.error',
|
||||
},
|
||||
STOPPED: {
|
||||
icon: 'icon-icon_block_filled',
|
||||
label: 'report.stop',
|
||||
label: 'report.stopped',
|
||||
color: 'var(--color-text-input-border)',
|
||||
},
|
||||
RUNNING: {
|
||||
icon: 'icon-icon_testing',
|
||||
label: 'report.inExecution',
|
||||
label: 'report.status.running',
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
// RERUNNING: {
|
||||
|
@ -83,7 +90,7 @@ export const ReportStatus = {
|
|||
// },
|
||||
PENDING: {
|
||||
icon: 'icon-icon_wait',
|
||||
label: 'report.queuing',
|
||||
label: 'report.status.pending',
|
||||
color: '!text-[rgb(var(--link-6))]',
|
||||
},
|
||||
},
|
||||
|
@ -130,4 +137,5 @@ export const PlanReportStatus: Record<string, any> = {
|
|||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -11,6 +11,13 @@ export enum FilterSlotNameEnum {
|
|||
PROJECT_MANAGEMENT_COMMON_SCRIPT = 'PROJECT_MANAGEMENT_COMMON_SCRIPT', // 项目管理公共脚本脚本状态
|
||||
GLOBAL_TASK_CENTER_API_CASE_STATUS = 'GLOBAL_TASK_CENTER_API_CASE_STATUS', // 任务中心执行状态
|
||||
GLOBAL_TASK_CENTER_API_CASE_TRIGGED_MODE = 'GLOBAL_TASK_CENTER_API_CASE_TRIGGED_MODE', // 任务中心触发方式
|
||||
API_TEST_CASE_API_STATUS = 'API_TEST_CASE_API_STATUS', // 接口测试-定义-用例列表-接口状态
|
||||
API_TEST_CASE_API_LAST_EXECUTE_STATUS = 'API_TEST_CASE_API_LAST_EXECUTE_STATUS', // 接口测试-定义-用例列表-最后执行状态
|
||||
API_TEST_CASE_API_REPORT_TRIGGED_METHOD = 'API_TEST_CASE_API_REPORT_TRIGGED_METHOD', // 接口测试-定义-用例列表-最后执行状态
|
||||
API_TEST_CASE_API_REPORT_EXECUTE_RESULT = 'API_TEST_CASE_API_REPORT_EXECUTE_RESULT', // 接口测试-定义-用例变更历史-最后执行结果
|
||||
GLOBAL_CHANGE_HISTORY_TYPE = 'GLOBAL_CHANGE_HISTORY_TYPE', // 变更历史类型
|
||||
API_TEST_SCENARIO_EXECUTE_RESULT = 'API_TEST_SCENARIO_EXECUTE_RESULT', // 接口测试-场景-变更历史-执行结果
|
||||
API_TEST_REPORT_TYPE = 'API_TEST_REPORT_TYPE', // 接口测试-报告-报告类型
|
||||
}
|
||||
|
||||
export enum FilterRemoteMethodsEnum {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<ms-base-table
|
||||
ref="apiTableRef"
|
||||
v-bind="propsRes"
|
||||
:action-config="batchActions"
|
||||
:first-column-width="44"
|
||||
|
@ -30,67 +31,11 @@
|
|||
@drag-change="handleTableDragSort"
|
||||
@module-change="loadApiList(false)"
|
||||
>
|
||||
<template v-if="props.protocol === 'HTTP'" #methodFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="methodFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="methodFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="methodFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="methodFilters" direction="vertical">
|
||||
<a-checkbox v-for="key of RequestMethods" :key="key" :value="key">
|
||||
<apiMethodName :method="key" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetMethodFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<template v-if="props.protocol === 'HTTP'" #[FilterSlotNameEnum.API_TEST_API_REQUEST_METHODS]="{ filterContent }">
|
||||
<apiMethodName :method="filterContent.value" />
|
||||
</template>
|
||||
<template #statusFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="statusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="statusFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical">
|
||||
<a-checkbox v-for="val of Object.values(RequestDefinitionStatus)" :key="val" :value="val">
|
||||
<apiStatus :status="val" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<template #[FilterSlotNameEnum.API_TEST_API_REQUEST_API_STATUS]="{ filterContent }">
|
||||
<apiStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #num="{ record }">
|
||||
<MsButton type="text" @click="openApiTab(record)">{{ record.num }}</MsButton>
|
||||
|
@ -115,6 +60,11 @@
|
|||
<template #caseTotal="{ record }">
|
||||
{{ record.caseTotal }}
|
||||
</template>
|
||||
<template #createUserName="{ record }">
|
||||
<a-tooltip :content="`${record.createUserName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.createUserName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<a-select
|
||||
v-if="hasAnyPermission(['PROJECT_API_DEFINITION:READ+UPDATE'])"
|
||||
|
@ -132,20 +82,6 @@
|
|||
</a-select>
|
||||
<apiStatus v-else :status="record.status" />
|
||||
</template>
|
||||
<template #createUserFilter="{ columnConfig }">
|
||||
<TableFilter
|
||||
v-model:visible="createUserFilterVisible"
|
||||
v-model:status-filters="createUserFilters"
|
||||
:title="(columnConfig.title as string)"
|
||||
:list="memberOptions"
|
||||
label-key="label"
|
||||
@search="loadApiList(false)"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
{{ item.label }}
|
||||
</template>
|
||||
</TableFilter>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<MsButton
|
||||
v-permission="['PROJECT_API_DEFINITION:READ+UPDATE']"
|
||||
|
@ -342,7 +278,6 @@
|
|||
import apiMethodSelect from '@/views/api-test/components/apiMethodSelect.vue';
|
||||
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
||||
import moduleTree from '@/views/api-test/management/components/moduleTree.vue';
|
||||
import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||
|
||||
import {
|
||||
batchDeleteDefinition,
|
||||
|
@ -364,6 +299,7 @@
|
|||
import { DragSortParams } from '@/models/common';
|
||||
import { RequestDefinitionStatus, RequestMethods } from '@/enums/apiEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
const props = defineProps<{
|
||||
class?: string;
|
||||
|
@ -404,6 +340,24 @@
|
|||
'PROJECT_API_DEFINITION:READ+UPDATE',
|
||||
])
|
||||
);
|
||||
|
||||
const requestMethodsOptions = computed(() => {
|
||||
return Object.values(RequestMethods).map((e) => {
|
||||
return {
|
||||
value: e,
|
||||
key: e,
|
||||
};
|
||||
});
|
||||
});
|
||||
const requestApiStatus = computed(() => {
|
||||
return Object.values(RequestDefinitionStatus).map((e) => {
|
||||
return {
|
||||
value: e,
|
||||
key: e,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
let columns: MsTableColumn = [
|
||||
{
|
||||
title: 'ID',
|
||||
|
@ -433,15 +387,21 @@
|
|||
title: 'apiTestManagement.apiType',
|
||||
dataIndex: 'method',
|
||||
slotName: 'method',
|
||||
titleSlotName: 'methodFilter',
|
||||
width: 140,
|
||||
showDrag: true,
|
||||
filterConfig: {
|
||||
options: requestMethodsOptions.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_API_REQUEST_METHODS,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'apiTestManagement.apiStatus',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
titleSlotName: 'statusFilter',
|
||||
filterConfig: {
|
||||
options: requestApiStatus.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_API_REQUEST_API_STATUS,
|
||||
},
|
||||
width: 130,
|
||||
showDrag: true,
|
||||
},
|
||||
|
@ -498,10 +458,16 @@
|
|||
{
|
||||
title: 'common.creator',
|
||||
slotName: 'createUserName',
|
||||
dataIndex: 'createUserName',
|
||||
titleSlotName: 'createUserFilter',
|
||||
dataIndex: 'createUser',
|
||||
filterConfig: {
|
||||
mode: 'remote',
|
||||
loadOptionParams: {
|
||||
projectId: appStore.currentProjectId,
|
||||
},
|
||||
remoteMethod: FilterRemoteMethodsEnum.PROJECT_PERMISSION_MEMBER,
|
||||
placeholderText: t('caseManagement.featureCase.PleaseSelect'),
|
||||
},
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
},
|
||||
|
@ -514,6 +480,21 @@
|
|||
},
|
||||
];
|
||||
|
||||
function initFilterColumn() {
|
||||
columns = columns.map((item) => {
|
||||
if (item.dataIndex === 'method') {
|
||||
return {
|
||||
...item,
|
||||
filterConfig: {
|
||||
...item.filterConfig,
|
||||
options: props.protocol === 'HTTP' ? requestMethodsOptions.value : [],
|
||||
},
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
await initFilterColumn();
|
||||
await tableStore.initColumn(TableKeyEnum.API_TEST, columns, 'drawer', true);
|
||||
if (props.readOnly) {
|
||||
columns = columns.filter(
|
||||
|
@ -581,13 +562,6 @@
|
|||
},
|
||||
];
|
||||
|
||||
const methodFilterVisible = ref(false);
|
||||
const methodFilters = ref<string[]>([]);
|
||||
const statusFilterVisible = ref(false);
|
||||
const statusFilters = ref<string[]>([]);
|
||||
const createUserFilterVisible = ref(false);
|
||||
const createUserFilters = ref<string[]>([]);
|
||||
|
||||
async function getModuleIds() {
|
||||
let moduleIds: string[] = [];
|
||||
if (props.activeModule !== 'all') {
|
||||
|
@ -607,21 +581,13 @@
|
|||
projectId: appStore.currentProjectId,
|
||||
moduleIds,
|
||||
protocol: props.protocol,
|
||||
filter: {
|
||||
status: statusFilters.value,
|
||||
method: methodFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
};
|
||||
|
||||
if (!hasRefreshTree && typeof refreshModuleTreeCount === 'function') {
|
||||
refreshModuleTreeCount({
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
status: statusFilters.value,
|
||||
method: methodFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
moduleIds: [],
|
||||
protocol: props.protocol,
|
||||
projectId: appStore.currentProjectId,
|
||||
|
@ -657,14 +623,6 @@
|
|||
}
|
||||
);
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
loadApiList(false);
|
||||
methodFilterVisible.value = false;
|
||||
statusFilterVisible.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleMethodChange(record: ApiDefinitionDetail) {
|
||||
try {
|
||||
await updateDefinition({
|
||||
|
@ -734,11 +692,7 @@
|
|||
excludeIds: params?.excludeIds || [],
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
status: statusFilters.value,
|
||||
method: methodFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
},
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds: await getModuleIds(),
|
||||
|
@ -861,11 +815,7 @@
|
|||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
status: statusFilters.value,
|
||||
method: methodFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
},
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds: await getModuleIds(),
|
||||
|
@ -906,11 +856,7 @@
|
|||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
status: statusFilters.value,
|
||||
method: methodFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
},
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds: await getModuleIds(),
|
||||
|
@ -943,18 +889,6 @@
|
|||
selectedModuleKeys.value = [];
|
||||
}
|
||||
|
||||
function resetMethodFilter() {
|
||||
methodFilters.value = [];
|
||||
methodFilterVisible.value = false;
|
||||
loadApiList(false);
|
||||
}
|
||||
|
||||
function resetStatusFilter() {
|
||||
statusFilters.value = [];
|
||||
statusFilterVisible.value = false;
|
||||
loadApiList(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件夹树节点选中事件
|
||||
*/
|
||||
|
@ -1013,6 +947,17 @@
|
|||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const apiTableRef = ref();
|
||||
watch(
|
||||
() => props.protocol,
|
||||
(val) => {
|
||||
if (val) {
|
||||
initFilterColumn();
|
||||
apiTableRef.value.initColumn(columns);
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -68,32 +68,9 @@
|
|||
</a-select>
|
||||
<span v-else class="text-[var(--color-text-2)]"> <caseLevel :case-level="record.priority" /></span>
|
||||
</template>
|
||||
<template #caseLevelFilter="{ columnConfig }">
|
||||
<a-trigger v-model:popup-visible="caseFilterVisible" trigger="click" @popup-visible-change="handleFilterHidden">
|
||||
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="caseFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="caseFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="caseFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="item of casePriorityOptions" :key="item.value" :value="item.value">
|
||||
<caseLevel :case-level="item.label as CaseLevel" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetCaseFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<!-- 用例等级 -->
|
||||
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL]="{ filterContent }">
|
||||
<caseLevel :case-level="filterContent.value" />
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<a-select
|
||||
|
@ -112,85 +89,16 @@
|
|||
</a-select>
|
||||
<apiStatus v-else :status="record.status" />
|
||||
</template>
|
||||
<template #statusFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="statusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="statusFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="val of Object.values(RequestCaseStatus)" :key="val" :value="val">
|
||||
<apiStatus :status="val" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<template #[FilterSlotNameEnum.API_TEST_CASE_API_STATUS]="{ filterContent }">
|
||||
<apiStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #createUserFilter="{ columnConfig }">
|
||||
<TableFilter
|
||||
v-model:visible="createUserFilterVisible"
|
||||
v-model:status-filters="createUserFilters"
|
||||
:title="(columnConfig.title as string)"
|
||||
:list="memberOptions"
|
||||
label-key="label"
|
||||
@search="loadCaseList"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
{{ item.label }}
|
||||
</template>
|
||||
</TableFilter>
|
||||
<template #createName="{ record }">
|
||||
<a-tooltip :content="`${record.createName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.createName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #lastReportStatusFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="lastReportStatusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton
|
||||
type="text"
|
||||
class="arco-btn-text--secondary ml-[10px]"
|
||||
@click="lastReportStatusFilterVisible = true"
|
||||
>
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="lastReportStatusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="lastReportStatusFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="val of lastReportStatusList" :key="val" :value="val">
|
||||
<ExecutionStatus :module-type="ReportEnum.API_REPORT" :status="val" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetLastReportStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<template #[FilterSlotNameEnum.API_TEST_CASE_API_LAST_EXECUTE_STATUS]="{ filterContent }">
|
||||
<apiStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #lastReportStatus="{ record }">
|
||||
<ExecutionStatus
|
||||
|
@ -391,7 +299,6 @@
|
|||
import BatchRunModal from '@/views/api-test/components/batchRunModal.vue';
|
||||
import caseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
|
||||
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
||||
import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||
|
||||
import {
|
||||
batchDeleteCase,
|
||||
|
@ -416,6 +323,7 @@
|
|||
import { RequestCaseStatus } from '@/enums/apiEnum';
|
||||
import { ReportEnum, ReportStatus } from '@/enums/reportEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { casePriorityOptions, caseStatusOptions } from '@/views/api-test/components/config';
|
||||
import type { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
|
||||
|
@ -448,6 +356,23 @@
|
|||
'PROJECT_API_DEFINITION_CASE:READ+EXECUTE',
|
||||
])
|
||||
);
|
||||
|
||||
const requestCaseStatusOptions = computed(() => {
|
||||
return Object.values(RequestCaseStatus).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: key,
|
||||
};
|
||||
});
|
||||
});
|
||||
const lastReportStatusListOptions = computed(() => {
|
||||
return Object.keys(ReportStatus[ReportEnum.API_REPORT]).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
...Object.keys(ReportStatus[ReportEnum.API_REPORT][key]),
|
||||
};
|
||||
});
|
||||
});
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'ID',
|
||||
|
@ -479,10 +404,9 @@
|
|||
title: 'case.caseLevel',
|
||||
dataIndex: 'priority',
|
||||
slotName: 'caseLevel',
|
||||
titleSlotName: 'caseLevelFilter',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
filterConfig: {
|
||||
options: casePriorityOptions,
|
||||
filterSlotName: FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL,
|
||||
},
|
||||
width: 150,
|
||||
showDrag: true,
|
||||
|
@ -491,11 +415,14 @@
|
|||
title: 'apiTestManagement.apiStatus',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
titleSlotName: 'statusFilter',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
filterConfig: {
|
||||
options: requestCaseStatusOptions.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_CASE_API_STATUS,
|
||||
},
|
||||
width: 150,
|
||||
showDrag: true,
|
||||
},
|
||||
|
@ -518,7 +445,10 @@
|
|||
title: 'case.lastReportStatus',
|
||||
dataIndex: 'lastReportStatus',
|
||||
slotName: 'lastReportStatus',
|
||||
titleSlotName: 'lastReportStatusFilter',
|
||||
filterConfig: {
|
||||
options: lastReportStatusListOptions.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_CASE_API_LAST_EXECUTE_STATUS,
|
||||
},
|
||||
showInTable: false,
|
||||
width: 150,
|
||||
showDrag: true,
|
||||
|
@ -563,8 +493,15 @@
|
|||
{
|
||||
title: 'case.tableColumnCreateUser',
|
||||
slotName: 'createName',
|
||||
dataIndex: 'createName',
|
||||
titleSlotName: 'createUserFilter',
|
||||
dataIndex: 'createUser',
|
||||
filterConfig: {
|
||||
mode: 'remote',
|
||||
loadOptionParams: {
|
||||
projectId: appStore.currentProjectId,
|
||||
},
|
||||
remoteMethod: FilterRemoteMethodsEnum.PROJECT_PERMISSION_MEMBER,
|
||||
placeholderText: t('caseManagement.featureCase.PleaseSelect'),
|
||||
},
|
||||
showInTable: true,
|
||||
showTooltip: true,
|
||||
width: 180,
|
||||
|
@ -636,18 +573,6 @@
|
|||
},
|
||||
];
|
||||
|
||||
const statusFilterVisible = ref(false);
|
||||
const statusFilters = ref<string[]>([]);
|
||||
const caseFilterVisible = ref(false);
|
||||
const caseFilters = ref<string[]>([]);
|
||||
const createUserFilterVisible = ref(false);
|
||||
const createUserFilters = ref<string[]>([]);
|
||||
const lastReportStatusFilterVisible = ref(false);
|
||||
const lastReportStatusList = computed(() => {
|
||||
return Object.keys(ReportStatus[ReportEnum.API_REPORT]);
|
||||
});
|
||||
const lastReportStatusFilters = ref<string[]>([]);
|
||||
|
||||
async function getModuleIds() {
|
||||
let moduleIds: string[] = [];
|
||||
if (props.activeModule !== 'all') {
|
||||
|
@ -667,12 +592,6 @@
|
|||
projectId: appStore.currentProjectId,
|
||||
moduleIds: selectModules,
|
||||
protocol: props.protocol,
|
||||
filter: {
|
||||
status: statusFilters.value,
|
||||
priority: caseFilters.value,
|
||||
lastReportStatus: lastReportStatusFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
},
|
||||
};
|
||||
setLoadListParams(params);
|
||||
loadList();
|
||||
|
@ -686,33 +605,6 @@
|
|||
loadCaseList();
|
||||
});
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
caseFilterVisible.value = false;
|
||||
statusFilterVisible.value = false;
|
||||
lastReportStatusFilterVisible.value = false;
|
||||
loadCaseList();
|
||||
}
|
||||
}
|
||||
|
||||
function resetCaseFilter() {
|
||||
caseFilters.value = [];
|
||||
caseFilterVisible.value = false;
|
||||
loadCaseList();
|
||||
}
|
||||
|
||||
function resetStatusFilter() {
|
||||
statusFilterVisible.value = false;
|
||||
statusFilters.value = [];
|
||||
loadCaseList();
|
||||
}
|
||||
|
||||
function resetLastReportStatusFilter() {
|
||||
lastReportStatusFilterVisible.value = false;
|
||||
lastReportStatusFilters.value = [];
|
||||
loadCaseList();
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.activeModule,
|
||||
() => {
|
||||
|
@ -773,12 +665,7 @@
|
|||
return {
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
status: statusFilters.value,
|
||||
priority: caseFilters.value,
|
||||
lastReportStatus: lastReportStatusFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
},
|
||||
projectId: appStore.currentProjectId,
|
||||
protocol: props.protocol,
|
||||
|
|
|
@ -6,46 +6,13 @@
|
|||
<span class="text-[14px]">{{ t('common.notRemind') }}</span>
|
||||
</template>
|
||||
</a-alert>
|
||||
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
|
||||
<template #typeFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="statusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary" @click="statusFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="typeFilter" direction="vertical" size="small">
|
||||
<a-checkbox v-for="val of typeOptions" :key="val.value" :value="val.value">
|
||||
<span>{{ t(val.label) }}</span>
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetTypeFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent" @filter-change="filterChange"> </ms-base-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/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';
|
||||
|
@ -58,10 +25,7 @@
|
|||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const typeFilter = ref<string[]>([]);
|
||||
|
||||
const statusFilterVisible = ref(false);
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
const props = defineProps<{
|
||||
sourceId: string | number;
|
||||
|
@ -74,15 +38,15 @@
|
|||
|
||||
const typeOptions = [
|
||||
{
|
||||
label: 'system.log.operateType.add',
|
||||
label: t('system.log.operateType.add'),
|
||||
value: 'ADD',
|
||||
},
|
||||
{
|
||||
label: 'system.log.operateType.update',
|
||||
label: t('system.log.operateType.update'),
|
||||
value: 'UPDATE',
|
||||
},
|
||||
{
|
||||
label: 'system.log.operateType.import',
|
||||
label: t('system.log.operateType.import'),
|
||||
value: 'IMPORT',
|
||||
},
|
||||
];
|
||||
|
@ -97,7 +61,10 @@
|
|||
title: 'apiTestManagement.type',
|
||||
dataIndex: 'type',
|
||||
slotName: 'type',
|
||||
titleSlotName: 'typeFilter',
|
||||
filterConfig: {
|
||||
options: typeOptions,
|
||||
filterSlotName: FilterSlotNameEnum.GLOBAL_CHANGE_HISTORY_TYPE,
|
||||
},
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
|
@ -139,27 +106,18 @@
|
|||
})
|
||||
);
|
||||
|
||||
function loadHistory() {
|
||||
function loadHistory(types?: string[]) {
|
||||
setLoadListParams({
|
||||
projectId: appStore.currentProjectId,
|
||||
sourceId: props.sourceId,
|
||||
modules: 'API_TEST_MANAGEMENT_CASE',
|
||||
types: typeFilter.value,
|
||||
types,
|
||||
});
|
||||
loadList();
|
||||
}
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
statusFilterVisible.value = false;
|
||||
loadHistory();
|
||||
}
|
||||
}
|
||||
|
||||
function resetTypeFilter() {
|
||||
typeFilter.value = [];
|
||||
statusFilterVisible.value = false;
|
||||
loadHistory();
|
||||
function filterChange(dataIndex: string, value: string[] | (string | number)[] | undefined) {
|
||||
loadHistory(value as string[]);
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
|
|
|
@ -12,69 +12,8 @@
|
|||
/>-->
|
||||
</div>
|
||||
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
|
||||
<template #triggerModeFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="triggerModeFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary" @click="triggerModeFilterVisible = true">
|
||||
<div class="font-medium">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
</div>
|
||||
<icon-down :class="triggerModeFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="triggerModeListFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="(key, value) of TriggerModeLabel" :key="key" :value="value">
|
||||
<div class="font-medium">{{ t(key) }}</div>
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetModeFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</template>
|
||||
<template #statusFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="statusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary" @click="statusFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="val of statusList" :key="val" :value="val">
|
||||
<ExecutionStatus :module-type="ReportEnum.API_REPORT" :status="val" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<template #[FilterSlotNameEnum.API_TEST_CASE_API_REPORT_EXECUTE_RESULT]="{ filterContent }">
|
||||
<ExecutionStatus :module-type="ReportEnum.API_REPORT" :status="filterContent.value" />
|
||||
</template>
|
||||
<template #triggerMode="{ record }">
|
||||
<span>{{ t(TriggerModeLabel[record.triggerMode as keyof typeof TriggerModeLabel]) }}</span>
|
||||
|
@ -130,13 +69,19 @@
|
|||
|
||||
import { ApiCaseExecuteHistoryItem } from '@/models/apiTest/management';
|
||||
import { ReportEnum, ReportStatus, TriggerModeLabel } from '@/enums/reportEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
const triggerModeListFilters = ref<string[]>();
|
||||
const triggerModeFilterVisible = ref(false);
|
||||
const statusFilterVisible = ref(false);
|
||||
const statusFilters = ref<string[]>();
|
||||
import { triggerModeOptions } from '@/views/api-test/report/utils';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
const statusList = computed(() => {
|
||||
return Object.keys(ReportStatus[ReportEnum.API_REPORT]);
|
||||
return Object.keys(ReportStatus[ReportEnum.API_REPORT]).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: t(ReportStatus[ReportEnum.API_REPORT][key].label),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const showResponse = ref(false);
|
||||
|
@ -147,9 +92,6 @@
|
|||
protocol: string;
|
||||
}>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const keyword = ref('');
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
|
@ -164,7 +106,9 @@
|
|||
title: 'apiTestManagement.executeMethod',
|
||||
dataIndex: 'triggerMode',
|
||||
slotName: 'triggerMode',
|
||||
titleSlotName: 'triggerModeFilter',
|
||||
filterConfig: {
|
||||
options: triggerModeOptions,
|
||||
},
|
||||
showTooltip: true,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
|
@ -176,11 +120,14 @@
|
|||
title: 'apiTestManagement.executeResult',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
titleSlotName: 'statusFilter',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
filterConfig: {
|
||||
options: statusList.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_CASE_API_REPORT_EXECUTE_RESULT,
|
||||
},
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
|
@ -228,34 +175,10 @@
|
|||
projectId: appStore.currentProjectId,
|
||||
keyword: keyword.value,
|
||||
id: props.sourceId,
|
||||
filter: {
|
||||
triggerMode: triggerModeListFilters.value,
|
||||
status: statusFilters.value,
|
||||
},
|
||||
});
|
||||
loadList();
|
||||
}
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
loadExecuteList();
|
||||
triggerModeFilterVisible.value = false;
|
||||
statusFilterVisible.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function resetModeFilter() {
|
||||
triggerModeListFilters.value = [];
|
||||
triggerModeFilterVisible.value = false;
|
||||
loadExecuteList();
|
||||
}
|
||||
|
||||
function resetStatusFilter() {
|
||||
statusFilters.value = [];
|
||||
statusFilterVisible.value = false;
|
||||
loadExecuteList();
|
||||
}
|
||||
|
||||
const activeReportIndex = ref<number>(0);
|
||||
const activeReportId = ref('');
|
||||
async function showResult(record: ApiCaseExecuteHistoryItem, rowIndex: number) {
|
||||
|
|
|
@ -38,102 +38,6 @@
|
|||
{{ record.integrated ? t('report.collection') : t('report.independent') }}
|
||||
</MsTag>
|
||||
</template>
|
||||
<template #integratedFilter="{ columnConfig }">
|
||||
<TableFilter
|
||||
v-model:visible="reportTypeVisible"
|
||||
v-model:status-filters="integratedFiltersMap[showType]"
|
||||
:title="(columnConfig.title as string)"
|
||||
:list="reportTypeList"
|
||||
@search="initData()"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<MsTag theme="light" :type="item.value === 'INTEGRATED' ? 'primary' : undefined">
|
||||
{{ item.value === 'INTEGRATED' ? t('report.collection') : t('report.independent') }}
|
||||
</MsTag>
|
||||
</template>
|
||||
</TableFilter>
|
||||
</template>
|
||||
<!-- 报告触发方式筛选 -->
|
||||
<template #triggerModeFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="triggerModeFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<a-button
|
||||
type="text"
|
||||
class="arco-btn-text--secondary p-[8px_4px]"
|
||||
@click.stop="triggerModeFilterVisible = true"
|
||||
>
|
||||
<div class="font-medium">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
</div>
|
||||
<icon-down :class="triggerModeFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</a-button>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group
|
||||
v-model:model-value="triggerModeListFiltersMaps[showType]"
|
||||
direction="vertical"
|
||||
size="small"
|
||||
>
|
||||
<a-checkbox v-for="(key, value) of TriggerModeLabel" :key="key" :value="value">
|
||||
<div class="font-medium">{{ t(key) }}</div>
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetTriggerModeFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</template>
|
||||
<!-- 报告结果筛选 -->
|
||||
<template #statusFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="statusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<a-button type="text" class="arco-btn-text--secondary p-[8px_4px]" @click.stop="statusFilterVisible = true">
|
||||
<div class="font-medium">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
</div>
|
||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</a-button>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="flex items-center justify-center px-[6px] py-[2px]">
|
||||
<a-checkbox-group
|
||||
v-model:model-value="statusListFiltersMap[showType]"
|
||||
direction="vertical"
|
||||
size="small"
|
||||
>
|
||||
<a-checkbox v-for="key of statusFilters" :key="key" :value="key">
|
||||
<ExecutionStatus :module-type="props.moduleType" :status="key" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</template>
|
||||
|
||||
<template #status="{ record }">
|
||||
<ExecutionStatus
|
||||
:module-type="props.moduleType"
|
||||
|
@ -141,6 +45,14 @@
|
|||
:script-identifier="props.moduleType === ReportEnum.API_SCENARIO_REPORT ? record.scriptIdentifier : null"
|
||||
/>
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.API_TEST_CASE_API_REPORT_EXECUTE_RESULT]="{ filterContent }">
|
||||
<ExecutionStatus :module-type="ReportEnum.API_REPORT" :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>
|
||||
|
@ -192,7 +104,6 @@
|
|||
import CaseReportDrawer from './caseReportDrawer.vue';
|
||||
import ReportDetailDrawer from './reportDetailDrawer.vue';
|
||||
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
||||
import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||
|
||||
import {
|
||||
getShareTime,
|
||||
|
@ -211,6 +122,9 @@
|
|||
import { BatchApiParams } from '@/models/common';
|
||||
import { ReportEnum, ReportStatus, TriggerModeLabel } from '@/enums/reportEnum';
|
||||
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { triggerModeOptions } from '@/views/api-test/report/utils';
|
||||
|
||||
const { openModal } = useModal();
|
||||
|
||||
|
@ -224,14 +138,19 @@
|
|||
name: string;
|
||||
}>();
|
||||
const keyword = ref<string>('');
|
||||
const statusFilterVisible = ref(false);
|
||||
const triggerModeFilterVisible = ref(false);
|
||||
|
||||
const triggerModeListFilters = ref<string[]>([]);
|
||||
|
||||
type ReportShowType = 'All' | 'INDEPENDENT' | 'INTEGRATED';
|
||||
const showType = ref<ReportShowType>('All');
|
||||
|
||||
const statusList = computed(() => {
|
||||
return Object.keys(ReportStatus[ReportEnum.API_REPORT]).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: t(ReportStatus[ReportEnum.API_REPORT][key].label),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'report.name',
|
||||
|
@ -253,7 +172,6 @@
|
|||
title: 'report.type',
|
||||
slotName: 'integrated',
|
||||
dataIndex: 'integrated',
|
||||
titleSlotName: 'integratedFilter',
|
||||
width: 150,
|
||||
showDrag: true,
|
||||
},
|
||||
|
@ -261,7 +179,10 @@
|
|||
title: 'report.result',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
titleSlotName: 'statusFilter',
|
||||
filterConfig: {
|
||||
options: statusList.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_CASE_API_REPORT_EXECUTE_RESULT,
|
||||
},
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
|
@ -279,9 +200,11 @@
|
|||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
filterConfig: {
|
||||
options: triggerModeOptions,
|
||||
},
|
||||
width: 150,
|
||||
showDrag: true,
|
||||
titleSlotName: 'triggerModeFilter',
|
||||
},
|
||||
{
|
||||
title: 'report.operator',
|
||||
|
@ -323,7 +246,7 @@
|
|||
return false;
|
||||
}
|
||||
};
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, resetFilterParams } = useTable(
|
||||
reportList,
|
||||
{
|
||||
tableKey: TableKeyEnum.API_TEST_REPORT,
|
||||
|
@ -342,72 +265,12 @@
|
|||
}),
|
||||
rename
|
||||
);
|
||||
// 全部过滤条件
|
||||
const allListFilters = ref<string[]>([]);
|
||||
const independentListFilters = ref<string[]>([]);
|
||||
const integratedListFilters = ref<string[]>([]);
|
||||
|
||||
const statusListFiltersMap = ref<Record<string, string[]>>({
|
||||
All: allListFilters.value,
|
||||
INDEPENDENT: independentListFilters.value,
|
||||
INTEGRATED: integratedListFilters.value,
|
||||
});
|
||||
|
||||
const allTriggerModeFilters = ref<string[]>([]);
|
||||
const independentTriggerModeFilters = ref<string[]>([]);
|
||||
const integratedTriggerModeFilters = ref<string[]>([]);
|
||||
const triggerModeListFiltersMaps = ref<Record<string, string[]>>({
|
||||
All: allTriggerModeFilters.value,
|
||||
INDEPENDENT: independentTriggerModeFilters.value,
|
||||
INTEGRATED: integratedTriggerModeFilters.value,
|
||||
});
|
||||
// 全部过滤条件
|
||||
const allIntegratedFilters = ref<string[]>([]);
|
||||
const independentIntegratedFilters = ref<string[]>([]);
|
||||
const integratedIntegratedFilters = ref<string[]>([]);
|
||||
|
||||
const reportTypeVisible = ref<boolean>(false);
|
||||
|
||||
const integratedFiltersMap = ref<Record<string, string[]>>({
|
||||
All: allIntegratedFilters.value,
|
||||
INDEPENDENT: independentIntegratedFilters.value,
|
||||
INTEGRATED: integratedIntegratedFilters.value,
|
||||
});
|
||||
|
||||
const reportTypeList = ref([
|
||||
{
|
||||
value: 'INDEPENDENT',
|
||||
label: t('report.independent'),
|
||||
},
|
||||
{
|
||||
value: 'INTEGRATED',
|
||||
label: t('report.collection'),
|
||||
},
|
||||
]);
|
||||
|
||||
const integratedFilters = computed(() => {
|
||||
if (showType.value === 'All') {
|
||||
if (integratedFiltersMap.value[showType.value].length === 1) {
|
||||
return integratedFiltersMap.value[showType.value].includes('INDEPENDENT') ? [false] : [true];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
if (showType.value === 'INTEGRATED') {
|
||||
return [true];
|
||||
}
|
||||
return [false];
|
||||
});
|
||||
|
||||
function initData() {
|
||||
setLoadListParams({
|
||||
keyword: keyword.value,
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleType: props.moduleType,
|
||||
filter: {
|
||||
status: statusListFiltersMap.value[showType.value],
|
||||
integrated: integratedFilters.value,
|
||||
triggerMode: triggerModeListFiltersMaps.value[showType.value],
|
||||
},
|
||||
});
|
||||
loadList();
|
||||
}
|
||||
|
@ -435,11 +298,7 @@
|
|||
...params,
|
||||
selectIds: params?.selectedIds || [],
|
||||
condition: {
|
||||
filter: {
|
||||
status: statusListFiltersMap.value[showType.value],
|
||||
integrated: integratedFilters.value,
|
||||
triggerMode: triggerModeListFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
keyword: keyword.value,
|
||||
},
|
||||
projectId: appStore.currentProjectId,
|
||||
|
@ -503,32 +362,9 @@
|
|||
initData();
|
||||
});
|
||||
|
||||
const statusFilters = computed(() => {
|
||||
return Object.keys(ReportStatus[props.moduleType]) || [];
|
||||
});
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
triggerModeFilterVisible.value = false;
|
||||
statusFilterVisible.value = false;
|
||||
initData();
|
||||
}
|
||||
}
|
||||
|
||||
function resetTriggerModeFilter() {
|
||||
triggerModeFilterVisible.value = false;
|
||||
triggerModeListFilters.value = [];
|
||||
initData();
|
||||
}
|
||||
|
||||
function resetStatusFilter() {
|
||||
statusFilterVisible.value = false;
|
||||
statusListFiltersMap.value[showType.value] = [];
|
||||
initData();
|
||||
}
|
||||
|
||||
function changeShowType(val: string | number | boolean) {
|
||||
showType.value = val as ReportShowType;
|
||||
resetFilterParams();
|
||||
resetSelector();
|
||||
initData();
|
||||
}
|
||||
|
@ -602,6 +438,7 @@
|
|||
(val) => {
|
||||
if (val) {
|
||||
resetSelector();
|
||||
resetFilterParams();
|
||||
initData();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import type { ScenarioItemType } from '@/models/apiTest/report';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import type { ScenarioItemType } from '@/models/apiTest/report';
|
||||
import { TriggerModeLabelEnum } from '@/enums/reportEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
export function addFoldField(node: ScenarioItemType) {
|
||||
if (node.children && node.children.length > 0) {
|
||||
node.fold = true;
|
||||
|
@ -22,4 +26,23 @@ export function getIndicators(value: any) {
|
|||
return value;
|
||||
}
|
||||
|
||||
export const triggerModeOptions = [
|
||||
{
|
||||
value: TriggerModeLabelEnum.MANUAL,
|
||||
label: t('report.trigger.manual'),
|
||||
},
|
||||
{
|
||||
value: TriggerModeLabelEnum.SCHEDULE,
|
||||
label: t('report.trigger.scheduled'),
|
||||
},
|
||||
{
|
||||
value: TriggerModeLabelEnum.BATCH,
|
||||
label: t('report.trigger.batch.execution'),
|
||||
},
|
||||
{
|
||||
value: TriggerModeLabelEnum.API,
|
||||
label: t('report.trigger.interface'),
|
||||
},
|
||||
];
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -4,69 +4,8 @@
|
|||
<template #num="{ record }">
|
||||
<span type="text" class="px-0">{{ record.num }}</span>
|
||||
</template>
|
||||
<template #triggerModeFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="triggerModeFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary p-[8px_4px]" @click="triggerModeFilterVisible = true">
|
||||
<div class="font-medium">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
</div>
|
||||
<icon-down :class="triggerModeFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="triggerModeListFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="(key, value) of TriggerModeLabel" :key="key" :value="value">
|
||||
<div class="font-medium">{{ t(key) }}</div>
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetTriggerModeFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</template>
|
||||
<template #statusFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="statusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="statusFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="val of Object.values(ExecuteStatusFilters)" :key="val" :value="val">
|
||||
<executeStatus :status="val" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<template #[FilterSlotNameEnum.API_TEST_SCENARIO_EXECUTE_RESULT]="{ filterContent }">
|
||||
<executeStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #triggerMode="{ record }">
|
||||
<span>{{ t(TriggerModeLabel[record.triggerMode as keyof typeof TriggerModeLabel]) }}</span>
|
||||
|
@ -124,11 +63,10 @@
|
|||
import { ExecuteHistoryItem } from '@/models/apiTest/scenario';
|
||||
import { ExecuteStatusFilters } from '@/enums/apiEnum';
|
||||
import { TriggerModeLabel } from '@/enums/reportEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { triggerModeOptions } from '@/views/api-test/report/utils';
|
||||
|
||||
const triggerModeListFilters = ref<string[]>([]);
|
||||
const triggerModeFilterVisible = ref(false);
|
||||
const statusFilterVisible = ref(false);
|
||||
const statusFilters = ref<string[]>([]);
|
||||
const tableQueryParams = ref<any>();
|
||||
|
||||
const keyword = ref('');
|
||||
|
@ -137,6 +75,16 @@
|
|||
scenarioId?: string | number; // 详情 id
|
||||
readOnly?: boolean;
|
||||
}>();
|
||||
|
||||
const executeStatusFilters = computed(() => {
|
||||
return Object.values(ExecuteStatusFilters).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: key,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'apiScenario.executeHistory.num',
|
||||
|
@ -150,14 +98,19 @@
|
|||
dataIndex: 'triggerMode',
|
||||
slotName: 'triggerMode',
|
||||
showTooltip: true,
|
||||
titleSlotName: 'triggerModeFilter',
|
||||
filterConfig: {
|
||||
options: triggerModeOptions,
|
||||
},
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'apiScenario.executeHistory.execution.status',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
titleSlotName: 'statusFilter',
|
||||
filterConfig: {
|
||||
options: executeStatusFilters.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_SCENARIO_EXECUTE_RESULT,
|
||||
},
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
|
@ -207,10 +160,6 @@
|
|||
const params = {
|
||||
keyword: keyword.value,
|
||||
id: props.scenarioId,
|
||||
filter: {
|
||||
triggerMode: triggerModeListFilters.value,
|
||||
status: statusFilters.value,
|
||||
},
|
||||
};
|
||||
setLoadListParams(params);
|
||||
loadList();
|
||||
|
@ -221,26 +170,6 @@
|
|||
};
|
||||
}
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
triggerModeFilterVisible.value = false;
|
||||
statusFilterVisible.value = false;
|
||||
loadExecuteHistoryList();
|
||||
}
|
||||
}
|
||||
|
||||
function resetTriggerModeFilter() {
|
||||
triggerModeFilterVisible.value = false;
|
||||
triggerModeListFilters.value = [];
|
||||
loadExecuteHistoryList();
|
||||
}
|
||||
|
||||
function resetStatusFilter() {
|
||||
statusFilterVisible.value = false;
|
||||
statusFilters.value = [];
|
||||
loadExecuteHistoryList();
|
||||
}
|
||||
|
||||
const showScenarioReportVisible = ref(false);
|
||||
const reportId = ref('');
|
||||
function showResult(record: ExecuteHistoryItem) {
|
||||
|
|
|
@ -31,68 +31,6 @@
|
|||
@drag-change="changeHandler"
|
||||
@module-change="loadScenarioList(false)"
|
||||
>
|
||||
<template #statusFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="statusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="statusFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical">
|
||||
<a-checkbox v-for="val of Object.values(ApiScenarioStatus)" :key="val" :value="val">
|
||||
<apiStatus :status="val" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</template>
|
||||
<template #priorityFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="priorityFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="priorityFilterVisible = true">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
<icon-down :class="priorityFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</MsButton>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="priorityFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="item of casePriorityOptions" :key="item.value" :value="item.value">
|
||||
<caseLevel :case-level="item.label as CaseLevel" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetPriorityFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</template>
|
||||
<template #num="{ record }">
|
||||
<div>
|
||||
<MsButton type="text" class="float-left" style="margin-right: 4px" @click="openScenarioTab(record)">
|
||||
|
@ -133,23 +71,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<a-select
|
||||
v-if="hasAnyPermission(['PROJECT_API_SCENARIO:READ+UPDATE'])"
|
||||
v-model:model-value="record.status"
|
||||
class="param-input w-full"
|
||||
size="mini"
|
||||
@change="() => handleStatusChange(record)"
|
||||
>
|
||||
<template #label>
|
||||
<apiStatus :status="record.status" />
|
||||
</template>
|
||||
<a-option v-for="item of Object.values(ApiScenarioStatus)" :key="item" :value="item">
|
||||
<apiStatus :status="item" />
|
||||
</a-option>
|
||||
</a-select>
|
||||
<apiStatus v-else :status="record.status" />
|
||||
</template>
|
||||
<template #priority="{ record }">
|
||||
<a-select
|
||||
v-if="hasAnyPermission(['PROJECT_API_SCENARIO:READ+UPDATE'])"
|
||||
|
@ -169,44 +90,42 @@
|
|||
</a-select>
|
||||
<span v-else class="text-[var(--color-text-2)]"> <caseLevel :case-level="record.priority" /></span>
|
||||
</template>
|
||||
<!-- 报告结果筛选 -->
|
||||
<template #lastReportStatusFilter="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="lastReportStatusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL]="{ filterContent }">
|
||||
<caseLevel :case-level="filterContent.value" />
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.API_TEST_CASE_API_STATUS]="{ filterContent }">
|
||||
<apiStatus :status="filterContent.value" />
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<a-select
|
||||
v-if="hasAnyPermission(['PROJECT_API_SCENARIO:READ+UPDATE'])"
|
||||
v-model:model-value="record.status"
|
||||
class="param-input w-full"
|
||||
size="mini"
|
||||
@change="() => handleStatusChange(record)"
|
||||
>
|
||||
<a-button
|
||||
type="text"
|
||||
class="arco-btn-text--secondary p-[8px_4px] text-[14px]"
|
||||
size="mini"
|
||||
@click="lastReportStatusFilterVisible = true"
|
||||
>
|
||||
<div class="font-medium">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
</div>
|
||||
<icon-down :class="lastReportStatusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</a-button>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="flex items-center justify-center px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="lastReportStatusListFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="key of lastReportStatusFilters" :key="key" :value="key">
|
||||
<ExecutionStatus :module-type="ReportEnum.API_SCENARIO_REPORT" :status="key" />
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetLastReportStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<template #label>
|
||||
<apiStatus :status="record.status" />
|
||||
</template>
|
||||
</a-trigger>
|
||||
<a-option v-for="item of Object.values(ApiScenarioStatus)" :key="item" :value="item">
|
||||
<apiStatus :status="item" />
|
||||
</a-option>
|
||||
</a-select>
|
||||
<apiStatus v-else :status="record.status" />
|
||||
</template>
|
||||
<template #createUserName="{ record }">
|
||||
<a-tooltip :content="`${record.createName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.createUserName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #updateUserName="{ record }">
|
||||
<a-tooltip :content="`${record.createName}`" position="tl">
|
||||
<div class="one-line-text">{{ characterLimit(record.updateUserName) }}</div>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<!-- 报告结果筛选 -->
|
||||
<template #[FilterSlotNameEnum.API_TEST_CASE_API_REPORT_EXECUTE_RESULT]="{ filterContent }">
|
||||
<ExecutionStatus :module-type="ReportEnum.API_REPORT" :status="filterContent.value" />
|
||||
</template>
|
||||
<template #lastReportStatus="{ record }">
|
||||
<ExecutionStatus
|
||||
|
@ -215,32 +134,6 @@
|
|||
:script-identifier="record.scriptIdentifier"
|
||||
/>
|
||||
</template>
|
||||
<template #createUserFilter="{ columnConfig }">
|
||||
<TableFilter
|
||||
v-model:visible="createUserFilterVisible"
|
||||
v-model:status-filters="createUserFilters"
|
||||
:title="(columnConfig.title as string)"
|
||||
:list="memberOptions"
|
||||
@search="loadScenarioList"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
{{ item.label }}
|
||||
</template>
|
||||
</TableFilter>
|
||||
</template>
|
||||
<template #updateUserFilter="{ columnConfig }">
|
||||
<TableFilter
|
||||
v-model:visible="updateUserFilterVisible"
|
||||
v-model:status-filters="updateUserFilters"
|
||||
:title="(columnConfig.title as string)"
|
||||
:list="memberOptions"
|
||||
@search="loadScenarioList"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
{{ item.label }}
|
||||
</template>
|
||||
</TableFilter>
|
||||
</template>
|
||||
<template #stepTotal="{ record }">
|
||||
{{ record.stepTotal }}
|
||||
</template>
|
||||
|
@ -612,7 +505,6 @@
|
|||
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
||||
import BatchRunModal from '@/views/api-test/scenario/components/batchRunModal.vue';
|
||||
import operationScenarioModuleTree from '@/views/api-test/scenario/components/operationScenarioModuleTree.vue';
|
||||
import TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||
|
||||
import { getEnvList, getPoolId, getPoolOption } from '@/api/modules/api-test/management';
|
||||
import {
|
||||
|
@ -633,6 +525,7 @@
|
|||
import useModal from '@/hooks/useModal';
|
||||
import useTableStore from '@/hooks/useTableStore';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { translateTextToPX } from '@/utils/css';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
|
@ -649,6 +542,7 @@
|
|||
import { ApiScenarioStatus } from '@/enums/apiEnum';
|
||||
import { ReportEnum, ReportStatus } from '@/enums/reportEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterRemoteMethodsEnum, FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { casePriorityOptions } from '@/views/api-test/components/config';
|
||||
|
||||
|
@ -664,14 +558,8 @@
|
|||
(e: 'createScenario'): void;
|
||||
}>();
|
||||
|
||||
const lastReportStatusFilterVisible = ref(false);
|
||||
const lastReportStatusListFilters = ref<string[]>([]);
|
||||
const lastReportStatusFilters = computed(() => {
|
||||
return Object.keys(ReportStatus[ReportEnum.API_SCENARIO_REPORT]);
|
||||
});
|
||||
const createUserFilterVisible = ref(false);
|
||||
const createUserFilters = ref<string[]>([]);
|
||||
const updateUserFilterVisible = ref(false);
|
||||
const updateUserFilters = ref<string[]>([]);
|
||||
const memberOptions = ref<{ label: string; value: string }[]>([]);
|
||||
const appStore = useAppStore();
|
||||
|
@ -679,7 +567,6 @@
|
|||
const { openModal } = useModal();
|
||||
const tableRecord = ref<ApiScenarioTableItem>();
|
||||
const scheduleModalTitle = ref('');
|
||||
const priorityFilterVisible = ref(false);
|
||||
const priorityFilters = ref<string[]>([]);
|
||||
const scheduleConfig = ref<ApiScenarioScheduleConfig>({
|
||||
scenarioId: '',
|
||||
|
@ -736,6 +623,24 @@
|
|||
const isBatchCopy = ref(false); // 是否批量复制场景
|
||||
const showBatchExecute = ref(false);
|
||||
|
||||
const requestApiScenarioStatusOptions = computed(() => {
|
||||
return Object.values(ApiScenarioStatus).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: key,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const statusList = computed(() => {
|
||||
return Object.keys(ReportStatus[ReportEnum.API_REPORT]).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: t(ReportStatus[ReportEnum.API_REPORT][key].label),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
let columns: MsTableColumn = [
|
||||
{
|
||||
title: 'ID',
|
||||
|
@ -772,7 +677,10 @@
|
|||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
titleSlotName: 'priorityFilter',
|
||||
filterConfig: {
|
||||
options: casePriorityOptions,
|
||||
filterSlotName: FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL,
|
||||
},
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
|
@ -784,16 +692,23 @@
|
|||
sortDirections: ['ascend', 'descend'],
|
||||
sorter: true,
|
||||
},
|
||||
filterConfig: {
|
||||
options: requestApiScenarioStatusOptions.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_CASE_API_STATUS,
|
||||
},
|
||||
showDrag: true,
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: 'apiScenario.table.columns.runResult',
|
||||
titleSlotName: 'lastReportStatusFilter',
|
||||
dataIndex: 'lastReportStatus',
|
||||
slotName: 'lastReportStatus',
|
||||
showTooltip: false,
|
||||
showDrag: true,
|
||||
filterConfig: {
|
||||
options: statusList.value,
|
||||
filterSlotName: FilterSlotNameEnum.API_TEST_CASE_API_REPORT_EXECUTE_RESULT,
|
||||
},
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
|
@ -857,23 +772,37 @@
|
|||
},
|
||||
{
|
||||
title: 'apiScenario.table.columns.createUser',
|
||||
dataIndex: 'createUserName',
|
||||
dataIndex: 'createUser',
|
||||
slotName: 'createUserName',
|
||||
showInTable: false,
|
||||
titleSlotName: 'createUserFilter',
|
||||
showTooltip: true,
|
||||
showDrag: true,
|
||||
width: 109,
|
||||
filterConfig: {
|
||||
mode: 'remote',
|
||||
loadOptionParams: {
|
||||
projectId: appStore.currentProjectId,
|
||||
},
|
||||
remoteMethod: FilterRemoteMethodsEnum.PROJECT_PERMISSION_MEMBER,
|
||||
placeholderText: t('caseManagement.featureCase.PleaseSelect'),
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'apiScenario.table.columns.updateUser',
|
||||
dataIndex: 'updateUserName',
|
||||
dataIndex: 'updateUser',
|
||||
slotName: 'updateUserName',
|
||||
showInTable: false,
|
||||
titleSlotName: 'updateUserFilter',
|
||||
showTooltip: true,
|
||||
showDrag: true,
|
||||
width: 109,
|
||||
filterConfig: {
|
||||
mode: 'remote',
|
||||
loadOptionParams: {
|
||||
projectId: appStore.currentProjectId,
|
||||
},
|
||||
remoteMethod: FilterRemoteMethodsEnum.PROJECT_PERMISSION_MEMBER,
|
||||
placeholderText: t('caseManagement.featureCase.PleaseSelect'),
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'common.operation',
|
||||
|
@ -979,8 +908,6 @@
|
|||
},
|
||||
];
|
||||
}
|
||||
|
||||
const statusFilterVisible = ref(false);
|
||||
const statusFilters = ref<string[]>([]);
|
||||
const tableStore = useTableStore();
|
||||
|
||||
|
@ -999,13 +926,6 @@
|
|||
keyword: keyword.value,
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds,
|
||||
filter: {
|
||||
lastReportStatus: lastReportStatusListFilters.value,
|
||||
status: statusFilters.value,
|
||||
priority: priorityFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
updateUser: updateUserFilters.value,
|
||||
},
|
||||
};
|
||||
setLoadListParams(params);
|
||||
await loadList();
|
||||
|
@ -1014,33 +934,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
lastReportStatusFilterVisible.value = false;
|
||||
statusFilterVisible.value = false;
|
||||
priorityFilterVisible.value = false;
|
||||
loadScenarioList(true);
|
||||
}
|
||||
}
|
||||
|
||||
function resetStatusFilter() {
|
||||
statusFilterVisible.value = false;
|
||||
statusFilters.value = [];
|
||||
loadScenarioList(true);
|
||||
}
|
||||
|
||||
function resetPriorityFilter() {
|
||||
priorityFilterVisible.value = false;
|
||||
priorityFilters.value = [];
|
||||
loadScenarioList(true);
|
||||
}
|
||||
|
||||
function resetLastReportStatusFilter() {
|
||||
lastReportStatusFilterVisible.value = false;
|
||||
lastReportStatusListFilters.value = [];
|
||||
loadScenarioList(true);
|
||||
}
|
||||
|
||||
async function handleStatusChange(record: ApiScenarioUpdateDTO) {
|
||||
try {
|
||||
await updateScenarioStatus(record.id, record.status);
|
||||
|
@ -1112,7 +1005,7 @@
|
|||
selectIds,
|
||||
selectAll: !!params?.selectAll,
|
||||
excludeIds: params?.excludeIds || [],
|
||||
condition: { ...params?.condition, keyword: keyword.value },
|
||||
condition: { ...params?.condition, keyword: keyword.value, filter: propsRes.value.filter },
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds: params?.moduleIds || [],
|
||||
deleteAll: true,
|
||||
|
@ -1328,13 +1221,7 @@
|
|||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
lastReportStatus: lastReportStatusListFilters.value,
|
||||
status: statusFilters.value,
|
||||
priority: priorityFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
updateUser: updateUserFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
},
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds: batchParams.value?.moduleIds || [],
|
||||
|
@ -1397,13 +1284,7 @@
|
|||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
filter: {
|
||||
lastReportStatus: lastReportStatusListFilters.value,
|
||||
status: statusFilters.value,
|
||||
priority: priorityFilters.value,
|
||||
createUser: createUserFilters.value,
|
||||
updateUser: updateUserFilters.value,
|
||||
},
|
||||
filter: propsRes.value.filter,
|
||||
},
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleIds: batchParams.value?.moduleIds || [],
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
const emit = defineEmits(['update:stepList']);
|
||||
|
||||
const executionResultList = computed(() =>
|
||||
Object.values(executionResultMap).filter((item) => item.key !== LastExecuteResults.UN_EXECUTED)
|
||||
Object.values(executionResultMap).filter((item) => item.key !== LastExecuteResults.PENDING)
|
||||
);
|
||||
|
||||
// 步骤描述
|
||||
|
|
|
@ -95,7 +95,8 @@
|
|||
<span>{{ statusIconMap[record.reviewStatus]?.statusText || '' }} </span>
|
||||
</template>
|
||||
<template #lastExecuteResult="{ record }">
|
||||
<ExecuteStatusTag :execute-result="record.lastExecuteResult" />
|
||||
<ExecuteStatusTag v-if="record.lastExecuteResult" :execute-result="record.lastExecuteResult" />
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
<template #moduleId="{ record }">
|
||||
<a-tree-select
|
||||
|
@ -571,7 +572,6 @@
|
|||
title: 'caseManagement.featureCase.tableColumnExecutionResult',
|
||||
dataIndex: 'lastExecuteResult',
|
||||
slotName: 'lastExecuteResult',
|
||||
titleSlotName: 'executeResultFilter',
|
||||
filterConfig: {
|
||||
options: executeResultOptions.value,
|
||||
filterSlotName: FilterSlotNameEnum.CASE_MANAGEMENT_EXECUTE_RESULT,
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
caseId: string;
|
||||
extraParams?: Record<string, any>;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
@ -106,7 +107,7 @@
|
|||
drawerLoading.value = true;
|
||||
try {
|
||||
await createOrUpdateBug({
|
||||
request: { ...form.value, customFields: templateCustomFields.value, caseId: props.caseId },
|
||||
request: { ...form.value, customFields: templateCustomFields.value, ...props.extraParams },
|
||||
fileList: [],
|
||||
});
|
||||
emit('success');
|
||||
|
|
|
@ -12,20 +12,6 @@
|
|||
</template>
|
||||
</a-popover>
|
||||
</template>
|
||||
<template #severityFilter="{ columnConfig }">
|
||||
<TableFilter
|
||||
v-model:visible="severityFilterVisible"
|
||||
v-model:status-filters="severityFilterValue"
|
||||
:title="(columnConfig.title as string)"
|
||||
:list="severityFilterOptions"
|
||||
value-key="value"
|
||||
@search="searchData()"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
{{ item.text }}
|
||||
</template>
|
||||
</TableFilter>
|
||||
</template>
|
||||
<template #statusName="{ record }">
|
||||
<div class="one-line-text">{{ record.statusName || '-' }}</div>
|
||||
</template>
|
||||
|
@ -65,20 +51,19 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/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 TableFilter from '@/views/case-management/caseManagementFeature/components/tableFilter.vue';
|
||||
|
||||
import { getLinkedCaseBugList } from '@/api/modules/case-management/featureCase';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { BugOptionItem } from '@/models/bug-management';
|
||||
import type { CommonList, TableQueryParams } from '@/models/common';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
|
@ -87,43 +72,41 @@
|
|||
keyword: string;
|
||||
bugColumns: MsTableColumn;
|
||||
bugTotal: number; // 平台缺陷总数决定是否新建还是关联
|
||||
loadParams?: Record<string, any>;
|
||||
loadBugListApi: (params: TableQueryParams) => Promise<CommonList<Record<string, any>>>; // 获取列表请求函数
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'link'): void;
|
||||
(e: 'new'): void;
|
||||
(e: 'cancelLink', bugId: string): void;
|
||||
(e: 'update:keyword'): void;
|
||||
}>();
|
||||
|
||||
const severityFilterVisible = ref(false);
|
||||
const severityFilterOptions = ref<BugOptionItem[]>([]);
|
||||
const bugTableRef = ref();
|
||||
const {
|
||||
propsRes: linkPropsRes,
|
||||
propsEvent: linkTableEvent,
|
||||
loadList: loadLinkList,
|
||||
setLoadListParams: setLinkListParams,
|
||||
} = useTable(getLinkedCaseBugList, {
|
||||
} = useTable(props.loadBugListApi, {
|
||||
columns: props.bugColumns,
|
||||
scroll: { x: 'auto' },
|
||||
heightUsed: 340,
|
||||
enableDrag: false,
|
||||
});
|
||||
const severityColumnId = ref('');
|
||||
const severityFilterValue = ref<string[]>([]);
|
||||
function initTableParams() {
|
||||
return {
|
||||
keyword: props.keyword,
|
||||
caseId: props.caseId,
|
||||
|
||||
const innerKeyword = useVModel(props, 'keyword', emit);
|
||||
function searchData() {
|
||||
setLinkListParams({
|
||||
...props.loadParams,
|
||||
keyword: innerKeyword.value,
|
||||
projectId: appStore.currentProjectId,
|
||||
condition: {
|
||||
keyword: props.keyword,
|
||||
filter: { ...linkPropsRes.value.filter, [severityColumnId.value]: severityFilterValue.value },
|
||||
keyword: innerKeyword.value,
|
||||
filter: linkPropsRes.value.filter,
|
||||
},
|
||||
};
|
||||
}
|
||||
function searchData() {
|
||||
setLinkListParams(initTableParams());
|
||||
});
|
||||
loadLinkList();
|
||||
}
|
||||
|
||||
|
@ -152,6 +135,15 @@
|
|||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.caseId,
|
||||
(val) => {
|
||||
if (val) {
|
||||
searchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
searchData,
|
||||
});
|
||||
|
|
|
@ -59,10 +59,14 @@
|
|||
<BugList
|
||||
v-if="showType === 'link'"
|
||||
ref="bugTableListRef"
|
||||
v-model:keyword="keyword"
|
||||
:case-id="props.caseId"
|
||||
:keyword="keyword"
|
||||
:bug-total="total"
|
||||
:bug-columns="columns"
|
||||
:load-bug-list-api="getLinkedCaseBugList"
|
||||
:load-params="{
|
||||
caseId: props.caseId,
|
||||
}"
|
||||
@link="linkDefect"
|
||||
@new="createDefect"
|
||||
@cancel-link="cancelLink"
|
||||
|
@ -111,7 +115,12 @@
|
|||
</div>
|
||||
</template>
|
||||
</ms-base-table>
|
||||
<AddDefectDrawer v-model:visible="showDrawer" :case-id="props.caseId" @success="getFetch()" />
|
||||
<AddDefectDrawer
|
||||
v-model:visible="showDrawer"
|
||||
:case-id="props.caseId"
|
||||
:extra-params="{ caseId: props.caseId }"
|
||||
@success="getFetch()"
|
||||
/>
|
||||
<LinkDefectDrawer
|
||||
v-model:visible="showLinkDrawer"
|
||||
:case-id="props.caseId"
|
||||
|
|
|
@ -56,33 +56,27 @@ export const statusIconMap: Record<string, any> = {
|
|||
};
|
||||
// 图标执行结果 TODO:TS 类型 key
|
||||
export const executionResultMap: Record<string, any> = {
|
||||
UN_EXECUTED: {
|
||||
key: 'UN_EXECUTED',
|
||||
icon: StatusType.UN_EXECUTED,
|
||||
PENDING: {
|
||||
key: 'PENDING',
|
||||
icon: StatusType.PENDING,
|
||||
statusText: t('caseManagement.featureCase.nonExecution'),
|
||||
color: 'text-[var(--color-text-brand)]',
|
||||
},
|
||||
PASSED: {
|
||||
key: 'PASSED',
|
||||
icon: StatusType.PASSED,
|
||||
SUCCESS: {
|
||||
key: 'SUCCESS',
|
||||
icon: StatusType.SUCCESS,
|
||||
statusText: t('common.success'),
|
||||
color: '',
|
||||
},
|
||||
/* SKIPPED: {
|
||||
key: 'SKIPPED',
|
||||
icon: StatusType.SKIPPED,
|
||||
statusText: t('caseManagement.featureCase.skip'),
|
||||
color: 'text-[rgb(var(--link-6))]',
|
||||
}, */
|
||||
BLOCKED: {
|
||||
key: 'BLOCKED',
|
||||
icon: StatusType.BLOCKED,
|
||||
statusText: t('caseManagement.featureCase.chokeUp'),
|
||||
color: 'text-[rgb(var(--warning-6))]',
|
||||
},
|
||||
FAILED: {
|
||||
key: 'FAILED',
|
||||
icon: StatusType.FAILED,
|
||||
ERROR: {
|
||||
key: 'ERROR',
|
||||
icon: StatusType.ERROR,
|
||||
statusText: t('caseManagement.featureCase.failure'),
|
||||
color: '',
|
||||
},
|
||||
|
|
|
@ -32,40 +32,13 @@
|
|||
v-on="propsEvent"
|
||||
@batch-action="handleTableBatch"
|
||||
>
|
||||
<template #resultTitle="{ columnConfig }">
|
||||
<a-trigger
|
||||
v-model:popup-visible="statusFilterVisible"
|
||||
trigger="click"
|
||||
@popup-visible-change="handleFilterHidden"
|
||||
>
|
||||
<a-button type="text" class="arco-btn-text--secondary p-[8px_4px]" @click="statusFilterVisible = true">
|
||||
<div class="font-medium">
|
||||
{{ t(columnConfig.title as string) }}
|
||||
</div>
|
||||
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
|
||||
</a-button>
|
||||
<template #content>
|
||||
<div class="arco-table-filters-content">
|
||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
||||
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical" size="small">
|
||||
<a-checkbox v-for="key of Object.keys(reviewResultMap)" :key="key" :value="key">
|
||||
<a-tag :color="reviewResultMap[key as ReviewResult].color" class="px-[4px]" size="small">
|
||||
{{ t(reviewResultMap[key as ReviewResult].label) }}
|
||||
</a-tag>
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
<div class="filter-button">
|
||||
<a-button size="mini" class="mr-[8px]" @click="resetReviewStatusFilter">
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
|
||||
{{ t('system.orgTemplate.confirm') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_REVIEW_RESULT]="{ filterContent }">
|
||||
<a-tag :color="reviewResultMap[filterContent.value as ReviewResult].color" class="px-[4px]" size="small">
|
||||
{{ t(reviewResultMap[filterContent.value as ReviewResult].label) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL]="{ filterContent }">
|
||||
<caseLevel :case-level="filterContent.text" />
|
||||
</template>
|
||||
<template #num="{ record }">
|
||||
<a-tooltip :content="record.num">
|
||||
|
@ -77,20 +50,6 @@
|
|||
<template #caseLevel="{ record }">
|
||||
<span class="text-[var(--color-text-2)]"> <caseLevel :case-level="record.caseLevel" /></span>
|
||||
</template>
|
||||
<template #caseLevelFilter="{ columnConfig }">
|
||||
<TableFilter
|
||||
v-model:visible="caseFilterVisible"
|
||||
v-model:status-filters="caseFilters"
|
||||
:title="(columnConfig.title as string)"
|
||||
:list="caseLevelList"
|
||||
value-key="value"
|
||||
@search="searchCase()"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<div class="flex"> <caseLevel :case-level="item.text" /></div>
|
||||
</template>
|
||||
</TableFilter>
|
||||
</template>
|
||||
<template #reviewNames="{ record }">
|
||||
<MsTagGroup
|
||||
v-if="record.showModuleTree"
|
||||
|
@ -304,6 +263,7 @@
|
|||
import { ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { FormInstance, Message, SelectOptionData } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
|
||||
|
@ -343,12 +303,11 @@
|
|||
import { BatchApiParams, ModuleTreeNode } from '@/models/common';
|
||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { getCaseLevels } from '@/views/case-management/caseManagementFeature/components/utils';
|
||||
|
||||
const caseLevelFields = ref<Record<string, any>>({});
|
||||
const caseFilterVisible = ref(false);
|
||||
const caseFilters = ref<string[]>([]);
|
||||
const caseLevelList = computed(() => {
|
||||
return caseLevelFields.value?.options || [];
|
||||
});
|
||||
|
@ -381,7 +340,16 @@
|
|||
const hasOperationPermission = computed(() =>
|
||||
hasAnyPermission(['CASE_REVIEW:READ+REVIEW', 'CASE_REVIEW:READ+RELEVANCE'])
|
||||
);
|
||||
const columns: MsTableColumn = [
|
||||
|
||||
const reviewResultOptions = computed(() => {
|
||||
return Object.keys(reviewResultMap).map((key) => {
|
||||
return {
|
||||
value: key,
|
||||
label: t(reviewResultMap[key as ReviewResult].label),
|
||||
};
|
||||
});
|
||||
});
|
||||
let columns: MsTableColumn = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'num',
|
||||
|
@ -408,10 +376,13 @@
|
|||
title: 'caseManagement.featureCase.tableColumnLevel',
|
||||
slotName: 'caseLevel',
|
||||
dataIndex: 'caseLevel',
|
||||
titleSlotName: 'caseLevelFilter',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
filterConfig: {
|
||||
options: caseLevelList.value,
|
||||
filterSlotName: FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'caseManagement.caseReview.reviewer',
|
||||
|
@ -424,7 +395,10 @@
|
|||
title: 'caseManagement.caseReview.reviewResult',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
titleSlotName: 'resultTitle',
|
||||
filterConfig: {
|
||||
options: reviewResultOptions.value,
|
||||
filterSlotName: FilterSlotNameEnum.CASE_MANAGEMENT_REVIEW_RESULT,
|
||||
},
|
||||
width: 110,
|
||||
},
|
||||
// {
|
||||
|
@ -500,7 +474,6 @@
|
|||
moduleIds: props.activeFolder === 'all' ? [] : [props.activeFolder, ...props.offspringIds],
|
||||
keyword: keyword.value,
|
||||
viewFlag: props.onlyMine,
|
||||
filter: { status: statusFilters.value, caseLevel: caseFilters.value },
|
||||
combine: filter
|
||||
? {
|
||||
...filter.combine,
|
||||
|
@ -518,19 +491,6 @@
|
|||
});
|
||||
}
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
searchCase();
|
||||
statusFilterVisible.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function resetReviewStatusFilter() {
|
||||
statusFilters.value = [];
|
||||
statusFilterVisible.value = false;
|
||||
searchCase();
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
searchCase();
|
||||
});
|
||||
|
@ -677,6 +637,23 @@
|
|||
async function getCaseLevelFields() {
|
||||
const result = await getCaseDefaultFields(appStore.currentProjectId);
|
||||
caseLevelFields.value = result.customFields.find((item: any) => item.internal && item.fieldName === '用例等级');
|
||||
columns = columns.map((item) => {
|
||||
if (item.dataIndex === 'caseLevel') {
|
||||
return {
|
||||
title: 'caseManagement.featureCase.tableColumnLevel',
|
||||
slotName: 'caseLevel',
|
||||
dataIndex: 'caseLevel',
|
||||
showInTable: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
filterConfig: {
|
||||
options: cloneDeep(caseLevelFields.value.options),
|
||||
filterSlotName: FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL,
|
||||
},
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
// 批量重新评审
|
||||
|
@ -851,7 +828,6 @@
|
|||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
getCaseLevelFields();
|
||||
const [, memberRes] = await Promise.all([
|
||||
initReviewers(),
|
||||
getProjectMemberCommentOptions(appStore.currentProjectId, keyword.value),
|
||||
|
@ -905,7 +881,7 @@
|
|||
searchCase,
|
||||
resetSelector,
|
||||
});
|
||||
|
||||
await getCaseLevelFields();
|
||||
await tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_REVIEW_CASE, columns, 'drawer');
|
||||
</script>
|
||||
|
||||
|
|
|
@ -503,7 +503,7 @@
|
|||
const selectedModuleKeys = ref<string[]>([]);
|
||||
const tableStore = useTableStore();
|
||||
await tableStore.initColumn(TableKeyEnum.CASE_MANAGEMENT_REVIEW, columns, 'drawer', true);
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, resetFilterParams } = useTable(
|
||||
getReviewList,
|
||||
{
|
||||
tableKey: TableKeyEnum.CASE_MANAGEMENT_REVIEW,
|
||||
|
@ -540,8 +540,6 @@
|
|||
],
|
||||
};
|
||||
|
||||
const statusFilterVisible = ref(false);
|
||||
const statusFilters = ref<string[]>([]);
|
||||
const tableQueryParams = ref<any>();
|
||||
async function searchReview(filter?: FilterResult) {
|
||||
let moduleIds: string[] = [];
|
||||
|
@ -583,22 +581,11 @@
|
|||
watch(
|
||||
() => innerShowType.value,
|
||||
() => {
|
||||
resetFilterParams();
|
||||
searchReview();
|
||||
}
|
||||
);
|
||||
|
||||
function handleFilterHidden(val: boolean) {
|
||||
if (!val) {
|
||||
searchReview();
|
||||
}
|
||||
}
|
||||
|
||||
function resetStatusFilter() {
|
||||
statusFilters.value = [];
|
||||
statusFilterVisible.value = false;
|
||||
searchReview();
|
||||
}
|
||||
|
||||
const batchParams = ref<BatchActionQueryParams>({
|
||||
selectedIds: [],
|
||||
selectAll: false,
|
||||
|
|
|
@ -350,7 +350,7 @@
|
|||
(record) => {
|
||||
return {
|
||||
...record,
|
||||
lastExecResult: record.lastExecResult ?? LastExecuteResults.UN_EXECUTED,
|
||||
lastExecResult: record.lastExecResult ?? LastExecuteResults.PENDING,
|
||||
caseLevel: getCaseLevels(record.customFields),
|
||||
moduleId: getModules(record.moduleId, props.moduleTree),
|
||||
};
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
const formRef = ref<FormInstance>();
|
||||
|
||||
const executionResultList = computed(() =>
|
||||
Object.values(executionResultMap).filter((item) => item.key !== LastExecuteResults.UN_EXECUTED)
|
||||
Object.values(executionResultMap).filter((item) => item.key !== LastExecuteResults.PENDING)
|
||||
);
|
||||
|
||||
async function handleUploadImage(file: File) {
|
||||
|
|
|
@ -53,10 +53,15 @@
|
|||
</div>
|
||||
<BugList
|
||||
ref="bugTableListRef"
|
||||
v-model:keyword="keyword"
|
||||
:case-id="props.caseId"
|
||||
:keyword="keyword"
|
||||
:bug-total="total"
|
||||
:bug-columns="columns"
|
||||
:load-bug-list-api="associatedBugPage"
|
||||
:load-params="{
|
||||
testPlanCaseId: route.query.testPlanCaseId,
|
||||
caseId: props.caseId,
|
||||
}"
|
||||
@link="linkDefect"
|
||||
@new="createDefect"
|
||||
@cancel-link="cancelLink"
|
||||
|
@ -67,12 +72,22 @@
|
|||
:drawer-loading="drawerLoading"
|
||||
@save="saveHandler"
|
||||
/>
|
||||
<AddDefectDrawer v-model:visible="showDrawer" :case-id="props.caseId" @success="initData()" />
|
||||
<AddDefectDrawer
|
||||
v-model:visible="showDrawer"
|
||||
:case-id="props.caseId"
|
||||
::extra-params="{
|
||||
testPlanCaseId: route.query.testPlanCaseId,
|
||||
caseId: props.caseId,
|
||||
testPlanId:props.testPlanId,
|
||||
}"
|
||||
@success="initData()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
|
@ -82,7 +97,7 @@
|
|||
import LinkDefectDrawer from '@/views/case-management/caseManagementFeature/components/tabContent/tabBug/linkDefectDrawer.vue';
|
||||
|
||||
import { getBugList, getCustomOptionHeader } from '@/api/modules/bug-management';
|
||||
import { associatedDrawerDebug, cancelAssociatedDebug } from '@/api/modules/case-management/featureCase';
|
||||
import { associateBugToPlan, associatedBugPage, testPlanCancelBug } from '@/api/modules/test-plan/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
@ -96,6 +111,7 @@
|
|||
const appStore = useAppStore();
|
||||
const props = defineProps<{
|
||||
caseId: string;
|
||||
testPlanId: string;
|
||||
}>();
|
||||
|
||||
const keyword = ref<string>('');
|
||||
|
@ -216,11 +232,11 @@
|
|||
}
|
||||
|
||||
const cancelLoading = ref<boolean>(false);
|
||||
// 取消关联
|
||||
// 取消关联缺陷
|
||||
async function cancelLink(id: string) {
|
||||
cancelLoading.value = true;
|
||||
try {
|
||||
await cancelAssociatedDebug(id);
|
||||
await testPlanCancelBug(id);
|
||||
Message.success(t('caseManagement.featureCase.cancelLinkSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
|
@ -244,12 +260,18 @@
|
|||
columns.value = makeColumns(optionsMap, columns.value);
|
||||
}
|
||||
}
|
||||
|
||||
const route = useRoute();
|
||||
const drawerLoading = ref<boolean>(false);
|
||||
// 关联缺陷
|
||||
async function saveHandler(params: TableQueryParams) {
|
||||
try {
|
||||
drawerLoading.value = true;
|
||||
await associatedDrawerDebug(params);
|
||||
await associateBugToPlan({
|
||||
...params,
|
||||
caseId: props.caseId,
|
||||
testPlanId: props.testPlanId,
|
||||
testPlanCaseId: route.query.testPlanCaseId as string,
|
||||
});
|
||||
Message.success(t('caseManagement.featureCase.associatedSuccess'));
|
||||
initData();
|
||||
showLinkDrawer.value = false;
|
||||
|
@ -260,6 +282,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.caseId,
|
||||
(val) => {
|
||||
if (val) {
|
||||
initBugList();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeMount(() => {
|
||||
initFilterOptions();
|
||||
initData();
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
const submitLoading = ref(false);
|
||||
const submitDisabled = computed(
|
||||
() =>
|
||||
form.value.lastExecResult !== 'PASSED' &&
|
||||
form.value.lastExecResult !== 'SUCCESS' &&
|
||||
(form.value.content === '' || form.value.content?.trim() === '<p style=""></p>')
|
||||
);
|
||||
|
||||
|
@ -70,12 +70,12 @@
|
|||
() => props.stepExecutionResult,
|
||||
() => {
|
||||
const executionResultList = props.stepExecutionResult?.map((item) => item.executeResult);
|
||||
if (executionResultList?.includes(LastExecuteResults.FAILED)) {
|
||||
form.value.lastExecResult = LastExecuteResults.FAILED;
|
||||
if (executionResultList?.includes(LastExecuteResults.ERROR)) {
|
||||
form.value.lastExecResult = LastExecuteResults.ERROR;
|
||||
} else if (executionResultList?.includes(LastExecuteResults.BLOCKED)) {
|
||||
form.value.lastExecResult = LastExecuteResults.BLOCKED;
|
||||
} else {
|
||||
form.value.lastExecResult = LastExecuteResults.PASSED;
|
||||
form.value.lastExecResult = LastExecuteResults.SUCCESS;
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
<template>
|
||||
<!-- TODO: 待联调 -->
|
||||
<div class="review-history-list">
|
||||
<div v-for="item of executeHistoryList" :key="item.id" class="review-history-list-item">
|
||||
<div class="flex items-center">
|
||||
<MsAvatar :avatar="item.userLogo" />
|
||||
<div class="ml-[8px] flex items-center">
|
||||
<a-tooltip :content="item.userName" :mouse-enter-delay="300">
|
||||
<div class="one-line-text max-w-[300px] font-medium text-[var(--color-text-1)]">{{ item.userName }}</div>
|
||||
</a-tooltip>
|
||||
<a-divider direction="vertical" margin="8px"></a-divider>
|
||||
<div v-if="item.status === 'PASS'" class="flex items-center">
|
||||
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
|
||||
{{ t('caseManagement.caseReview.pass') }}
|
||||
</div>
|
||||
<div v-else-if="item.status === 'UN_PASS'" class="flex items-center">
|
||||
<MsIcon type="icon-icon_close_filled" class="mr-[4px] text-[rgb(var(--danger-6))]" />
|
||||
{{ t('caseManagement.caseReview.fail') }}
|
||||
</div>
|
||||
<div v-else-if="item.status === 'UNDER_REVIEWED'" class="flex items-center">
|
||||
<MsIcon type="icon-icon_warning_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
|
||||
{{ t('caseManagement.caseReview.suggestion') }}
|
||||
</div>
|
||||
<div v-else-if="item.status === 'RE_REVIEWED'" class="flex items-center">
|
||||
<MsIcon type="icon-icon_resubmit_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
|
||||
{{ t('caseManagement.caseReview.reReview') }}
|
||||
</div>
|
||||
<div v-if="item.status === 'PASSED'" class="flex items-center">
|
||||
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
|
||||
{{ t('caseManagement.featureCase.execute.success') }}
|
||||
</div>
|
||||
<div v-if="item.status === 'BLOCKED'" class="flex items-center">
|
||||
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
|
||||
{{ t('caseManagement.featureCase.execute.blocked') }}
|
||||
</div>
|
||||
<div v-if="item.status === 'FAILED'" class="flex items-center">
|
||||
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
|
||||
{{ t('caseManagement.featureCase.execute.failed') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="markdown-body" style="margin-left: 48px" v-html="item.contentText"></div>
|
||||
<div class="ml-[48px] mt-[8px] flex text-[var(--color-text-4)]">
|
||||
{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
<div>
|
||||
<a-tooltip :content="item.reviewName" :mouse-enter-delay="300">
|
||||
<span v-if="item.deleted" class="one-line-text ml-[16px] max-w-[300px] break-words break-all">
|
||||
{{ characterLimit(item.reviewName) }}
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-else
|
||||
class="one-line-text ml-[16px] max-w-[300px] cursor-pointer break-words break-all text-[rgb(var(--primary-5))]"
|
||||
>
|
||||
{{ characterLimit(item.reviewName) }}
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<MsEmpty v-if="executeHistoryList.length === 0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsAvatar from '@/components/pure/ms-avatar/index.vue';
|
||||
import MsEmpty from '@/components/pure/ms-empty/index.vue';
|
||||
import { CommentItem, CommentParams } from '@/components/business/ms-comment/types';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
caseId: string;
|
||||
}>();
|
||||
|
||||
const executeHistoryList = ref<CommentItem[]>([]);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -37,7 +37,7 @@
|
|||
>
|
||||
<div class="mb-[8px] flex items-center justify-between">
|
||||
<div class="text-[var(--color-text-4)]">{{ item.num }}</div>
|
||||
<ExecuteResult :execute-result="item.lastExecResult ?? LastExecuteResults.UN_EXECUTED" />
|
||||
<ExecuteResult :execute-result="item.lastExecResult ?? LastExecuteResults.PENDING" />
|
||||
</div>
|
||||
<a-tooltip :content="item.name">
|
||||
<div class="one-line-text">{{ item.name }}</div>
|
||||
|
@ -120,9 +120,12 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<BugList v-if="activeTab === 'defectList'" :case-id="caseDetail.id" />
|
||||
<!-- TODO 待写页面 还未提交 -->
|
||||
<!-- <ExecutionHistory v-if="activeTab === 'executionHistory'" :case-id="caseDetail.id" /> -->
|
||||
<BugList
|
||||
v-if="activeTab === 'defectList'"
|
||||
:case-id="caseDetail.id"
|
||||
:test-plan-id="route.query.id as string"
|
||||
/>
|
||||
<ExecutionHistory v-if="activeTab === 'executionHistory'" :case-id="caseDetail.id" />
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
|
@ -145,9 +148,9 @@
|
|||
import ExecuteSubmit from './executeSubmit.vue';
|
||||
import CaseTabDetail from '@/views/case-management/caseManagementFeature/components/tabContent/tabDetail.vue';
|
||||
import EditCaseDetailDrawer from '@/views/case-management/caseReview/components/editCaseDetailDrawer.vue';
|
||||
import ExecutionHistory from '@/views/test-plan/testPlan/detail/featureCase/detail/executionHistory/index.vue';
|
||||
|
||||
import { getCaseDetail } from '@/api/modules/case-management/featureCase';
|
||||
// import ExecutionHistory from '@/views/test-plan/testPlan/detail/featureCase/detail/executionHistory/index.vue';
|
||||
import { getPlanDetailFeatureCaseList, getTestPlanDetail } from '@/api/modules/test-plan/testPlan';
|
||||
import { testPlanDefaultDetail } from '@/config/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
|
Loading…
Reference in New Issue