mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-11-30 11:08:38 +08:00
feat(测试计划): 测试计划独立报告接口用例分析&接口场景分析&测试计划执行接口调整
This commit is contained in:
parent
f1f48388c0
commit
5f36c2343e
@ -3,7 +3,12 @@ import * as reportUrl from '@/api/requrls/test-plan/report';
|
||||
|
||||
import type { GetShareId } from '@/models/apiTest/report';
|
||||
import { CommonList, TableQueryParams } from '@/models/common';
|
||||
import { FeatureCaseItem, ReportBugItem, UpdateReportDetailParams } from '@/models/testPlan/report';
|
||||
import {
|
||||
ApiOrScenarioCaseItem,
|
||||
FeatureCaseItem,
|
||||
ReportBugItem,
|
||||
UpdateReportDetailParams,
|
||||
} from '@/models/testPlan/report';
|
||||
|
||||
// 报告列表
|
||||
export function reportList(data: TableQueryParams) {
|
||||
@ -79,5 +84,21 @@ export function planGetShareHref(id: string) {
|
||||
export function getShareValidity(id: string) {
|
||||
return MSR.get({ url: `${reportUrl.GetShareValidityUrl}/${id}` });
|
||||
}
|
||||
// 测试计划-独立报告-接口用例
|
||||
export function getApiPage(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<ApiOrScenarioCaseItem>>({ url: reportUrl.ReportIndependentApiUrl, data });
|
||||
}
|
||||
// 测试计划-报告-获取分享链接时效
|
||||
export function getScenarioPage(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<ApiOrScenarioCaseItem>>({ url: reportUrl.ReportIndependentScenarioUrl, data });
|
||||
}
|
||||
// 测试计划-独立报告-接口用例
|
||||
export function getShareApiPage(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<ApiOrScenarioCaseItem>>({ url: reportUrl.ReportShareApiUrl, data });
|
||||
}
|
||||
// 测试计划-报告-获取分享链接时效
|
||||
export function getShareScenarioPage(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<ApiOrScenarioCaseItem>>({ url: reportUrl.ReportShareScenarioUrl, data });
|
||||
}
|
||||
|
||||
export default {};
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
BatchDisassociateApiScenarioUrl,
|
||||
BatchDisassociateCaseUrl,
|
||||
BatchEditTestPlanUrl,
|
||||
BatchExecutePlanUrl,
|
||||
BatchMoveApiCaseUrl,
|
||||
BatchMoveApiScenarioUrl,
|
||||
BatchMoveFeatureCaseUrl,
|
||||
@ -36,7 +37,7 @@ import {
|
||||
dragPlanOnGroupUrl,
|
||||
EditPlanMinderUrl,
|
||||
ExecuteHistoryUrl,
|
||||
ExecutePlanUrl,
|
||||
ExecuteSinglePlanUrl,
|
||||
followPlanUrl,
|
||||
GenerateReportUrl,
|
||||
GetApiCaseModuleCountUrl,
|
||||
@ -90,6 +91,7 @@ import type {
|
||||
AssociateCaseRequestType,
|
||||
BatchApiCaseParams,
|
||||
BatchExecuteFeatureCaseParams,
|
||||
BatchExecutePlan,
|
||||
BatchFeatureCaseParams,
|
||||
BatchMoveApiCaseParams,
|
||||
BatchUpdateApiCaseExecutorParams,
|
||||
@ -423,9 +425,13 @@ export function dragPlanOnGroup(data: DragSortParams) {
|
||||
export function configSchedule(data: CreateTask) {
|
||||
return MSR.post({ url: ConfigScheduleUrl, data });
|
||||
}
|
||||
// 测试计划-计划&计划组-执行
|
||||
export function executeSinglePlan(data: ExecutePlan) {
|
||||
return MSR.post({ url: ExecuteSinglePlanUrl, data });
|
||||
}
|
||||
// 测试计划-计划&计划组-执行&批量执行
|
||||
export function executePlanOrGroup(data: ExecutePlan) {
|
||||
return MSR.post({ url: ExecutePlanUrl, data });
|
||||
export function executePlanOrGroup(data: BatchExecutePlan) {
|
||||
return MSR.post({ url: BatchExecutePlanUrl, data });
|
||||
}
|
||||
// 测试计划-计划&计划组-执行&批量执行
|
||||
export function deleteScheduleTask(testPlanId: string) {
|
||||
|
@ -28,3 +28,11 @@ export const PlanGetShareHrefDetailUrl = '/test-plan/report/share/get';
|
||||
export const GetShareValidityUrl = '/test-plan/report/share/get-share-time';
|
||||
// 测试计划-报告-详情-富文本编辑器上传图片文件
|
||||
export const EditorUploadFileUrl = '/test-plan/report/upload/md/file';
|
||||
// 测试计划-独立报告-接口用例
|
||||
export const ReportIndependentApiUrl = '/test-plan/report/detail/api/case/page';
|
||||
// 测试计划-独立报告-场景用例
|
||||
export const ReportIndependentScenarioUrl = '/test-plan/report/detail/scenario/case/page';
|
||||
// 测试计划-独立报告-接口用例-分享
|
||||
export const ReportShareApiUrl = '/test-plan/report/share/detail/api/case/page';
|
||||
// 测试计划-独立报告-场景用例-分享
|
||||
export const ReportShareScenarioUrl = '/test-plan/report/share/detail/scenario/case/page';
|
||||
|
@ -96,8 +96,10 @@ export const TestPlanGroupOptionsUrl = 'test-plan/group-list';
|
||||
export const dragPlanOnGroupUrl = '/test-plan/sort';
|
||||
// 测试计划-创建定时任务
|
||||
export const ConfigScheduleUrl = '/test-plan/schedule-config';
|
||||
// 测试计划-计划&计划组-执行
|
||||
export const ExecuteSinglePlanUrl = '/test-plan-execute/single';
|
||||
// 测试计划-计划&计划组-执行&批量执行
|
||||
export const ExecutePlanUrl = '/test-plan-execute/start';
|
||||
export const BatchExecutePlanUrl = '/test-plan-execute/batch';
|
||||
// 测试计划-删除定时任务
|
||||
export const DeleteScheduleTaskUrl = 'test-plan/schedule-config-delete';
|
||||
|
||||
|
@ -128,4 +128,36 @@ export const statusConfig: StatusListType[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const commonConfig = {
|
||||
tooltip: {
|
||||
show: false,
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const seriesConfig = {
|
||||
name: '',
|
||||
type: 'pie',
|
||||
radius: ['62%', '80%'],
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center',
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: 40,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default {};
|
||||
|
@ -23,3 +23,15 @@ export interface UpdateReportDetailParams {
|
||||
summary: string;
|
||||
richTextTmpFileIds: string[];
|
||||
}
|
||||
|
||||
export interface ApiOrScenarioCaseItem {
|
||||
id: string;
|
||||
num: number;
|
||||
name: string;
|
||||
moduleName: string;
|
||||
priority: string;
|
||||
executeResult: string;
|
||||
executeUser: string;
|
||||
bugCount: number;
|
||||
reportId: string;
|
||||
}
|
||||
|
@ -367,10 +367,15 @@ export interface CreateTask {
|
||||
cron: string;
|
||||
runConfig: { runMode: 'SERIAL' | 'PARALLEL' };
|
||||
}
|
||||
export interface ExecutePlan {
|
||||
projectId: string;
|
||||
executeIds: string[];
|
||||
executeMode: RunModeType;
|
||||
export interface BatchExecutePlan {
|
||||
projectId?: string;
|
||||
executeIds?: string[];
|
||||
runMode: RunModeType;
|
||||
executionSource: string;
|
||||
}
|
||||
|
||||
export interface ExecutePlan extends BatchExecutePlan {
|
||||
executeId: string;
|
||||
}
|
||||
|
||||
export interface PlanMinderNodeData extends MinderJsonNodeData {
|
||||
|
@ -131,7 +131,7 @@
|
||||
<TabTestPlan :case-id="detail.id" />
|
||||
</template>
|
||||
<template v-if="activeTab === 'comments'">
|
||||
<TabComment ref="commentRef" :case-id="detail.id" />
|
||||
<TabComment ref="commentRef" :case-id="detail.id" :comment-value="detail.commentList" />
|
||||
</template>
|
||||
<template v-if="activeTab === 'changeHistory'">
|
||||
<TabChangeHistory :case-id="detail.id" />
|
||||
|
@ -62,6 +62,7 @@
|
||||
|
||||
const props = defineProps<{
|
||||
caseId: string;
|
||||
commentValue: { id: string; name: string }[];
|
||||
}>();
|
||||
|
||||
const activeComment = ref('caseComment');
|
||||
@ -191,14 +192,6 @@
|
||||
}
|
||||
}
|
||||
);
|
||||
// watch(
|
||||
// () => activeTab.value,
|
||||
// (val) => {
|
||||
// if (val === 'comments') {
|
||||
// getAllCommentList();
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
|
||||
async function handleUploadImage(file: File) {
|
||||
const { data } = await editorUploadFile({
|
||||
@ -223,6 +216,10 @@
|
||||
defineExpose({
|
||||
getAllCommentList,
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
activeComment.value = props.commentValue.find((item) => Number(item.name) > 0)?.id || 'caseComment';
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
|
||||
<template #num="{ record }">
|
||||
<MsButton type="text">{{ record.num }}</MsButton>
|
||||
<MsButton type="text" @click="showReport(record)">{{ record.num }}</MsButton>
|
||||
</template>
|
||||
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL]="{ filterContent }">
|
||||
<CaseLevel :case-level="filterContent.value" />
|
||||
<caseLevel :case-level="filterContent.value" />
|
||||
</template>
|
||||
<template #caseLevel="{ record }">
|
||||
<CaseLevel :case-level="record.caseLevel" />
|
||||
@ -14,43 +14,43 @@
|
||||
</template>
|
||||
<template #lastExecResult="{ record }">
|
||||
<ExecuteResult :execute-result="record.lastExecResult" />
|
||||
<MsIcon
|
||||
<!-- TOTO 暂时不上 -->
|
||||
<!-- <MsIcon
|
||||
v-show="record.lastExecResult !== LastExecuteResults.PENDING"
|
||||
type="icon-icon_take-action_outlined"
|
||||
class="ml-[8px] cursor-pointer text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
@click="showReport(record)"
|
||||
/>
|
||||
/> -->
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<CaseAndScenarioReportDrawer v-model:visible="reportVisible" :report-id="apiReportId" do-not-show-share />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onBeforeMount } from 'vue';
|
||||
|
||||
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 CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
||||
import CaseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
|
||||
|
||||
import { getReportBugList, getReportShareBugList } from '@/api/modules/test-plan/report';
|
||||
import { getPlanDetailApiCaseList } from '@/api/modules/test-plan/testPlan';
|
||||
import { useTableStore } from '@/store';
|
||||
import { getApiPage, getShareApiPage } from '@/api/modules/test-plan/report';
|
||||
|
||||
import type { PlanDetailApiScenarioItem } from '@/models/testPlan/testPlan';
|
||||
import { ApiOrScenarioCaseItem } from '@/models/testPlan/report';
|
||||
import { LastExecuteResults } from '@/enums/caseEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
|
||||
import { casePriorityOptions } from '@/views/api-test/components/config';
|
||||
import { executionResultMap, getCaseLevels } from '@/views/case-management/caseManagementFeature/components/utils';
|
||||
import { executionResultMap } from '@/views/case-management/caseManagementFeature/components/utils';
|
||||
|
||||
const props = defineProps<{
|
||||
reportId: string;
|
||||
shareId?: string;
|
||||
}>();
|
||||
|
||||
const tableStore = useTableStore();
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'ID',
|
||||
@ -68,7 +68,7 @@
|
||||
},
|
||||
{
|
||||
title: 'report.detail.level',
|
||||
dataIndex: 'caseLevel',
|
||||
dataIndex: 'priority',
|
||||
slotName: 'caseLevel',
|
||||
filterConfig: {
|
||||
options: casePriorityOptions,
|
||||
@ -92,7 +92,7 @@
|
||||
},
|
||||
{
|
||||
title: 'common.belongModule',
|
||||
dataIndex: 'moduleId',
|
||||
dataIndex: 'moduleName',
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
showDrag: true,
|
||||
@ -107,14 +107,7 @@
|
||||
},
|
||||
{
|
||||
title: 'testPlan.featureCase.executor',
|
||||
dataIndex: 'executeUserName',
|
||||
showTooltip: true,
|
||||
width: 130,
|
||||
showDrag: true,
|
||||
},
|
||||
{
|
||||
title: 'testPlan.featureCase.executor',
|
||||
dataIndex: 'executeUserName',
|
||||
dataIndex: 'executeUser',
|
||||
showTooltip: true,
|
||||
width: 130,
|
||||
showDrag: true,
|
||||
@ -127,15 +120,24 @@
|
||||
showDrag: true,
|
||||
},
|
||||
];
|
||||
const reportBugList = () => {
|
||||
return !props.shareId ? getPlanDetailApiCaseList : getReportShareBugList;
|
||||
const reportApiList = () => {
|
||||
return !props.shareId ? getShareApiPage : getApiPage;
|
||||
};
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getPlanDetailApiCaseList, {
|
||||
scroll: { x: '100%' },
|
||||
columns,
|
||||
tableKey: TableKeyEnum.TEST_PLAN_REPORT_DETAIL_BUG,
|
||||
showSelectorAll: false,
|
||||
});
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(
|
||||
reportApiList(),
|
||||
{
|
||||
scroll: { x: '100%' },
|
||||
columns,
|
||||
tableKey: TableKeyEnum.TEST_PLAN_REPORT_DETAIL_BUG,
|
||||
showSelectorAll: false,
|
||||
},
|
||||
(record) => {
|
||||
return {
|
||||
...record,
|
||||
lastExecResult: record.executeResult ?? LastExecuteResults.PENDING,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
async function loadCaseList() {
|
||||
setLoadListParams({ reportId: props.reportId, shareId: props.shareId ?? undefined });
|
||||
@ -151,12 +153,10 @@
|
||||
// 显示执行报告
|
||||
const reportVisible = ref(false);
|
||||
|
||||
const apiReportId = ref('');
|
||||
const apiReportId = ref<string>('');
|
||||
|
||||
function showReport(record: PlanDetailApiScenarioItem) {
|
||||
function showReport(record: ApiOrScenarioCaseItem) {
|
||||
reportVisible.value = true;
|
||||
apiReportId.value = record.lastExecReportId;
|
||||
apiReportId.value = record.reportId;
|
||||
}
|
||||
|
||||
await tableStore.initColumn(TableKeyEnum.TEST_PLAN_REPORT_DETAIL_BUG, columns, 'drawer');
|
||||
</script>
|
||||
|
@ -14,7 +14,7 @@
|
||||
<SetReportChart
|
||||
size="160px"
|
||||
:legend-data="legendData"
|
||||
:options="charOptions"
|
||||
:options="executeCharOptions"
|
||||
:request-total="getIndicators(detail.caseTotal) || 0"
|
||||
/>
|
||||
</div>
|
||||
@ -66,18 +66,18 @@
|
||||
<div class="text-[12px] !text-[var(--color-text-4)]">{{ t('report.passRate') }}</div>
|
||||
<a-popover position="bottom" content-class="response-popover-content">
|
||||
<div class="flex justify-center text-[18px] font-medium">
|
||||
<div class="one-line-text max-w-[80px] text-[var(--color-text-1)]">{{ functionCasePassRate }} </div>
|
||||
<div class="one-line-text max-w-[80px] text-[var(--color-text-1)]">{{ apiCasePassRate }} </div>
|
||||
</div>
|
||||
<template #content>
|
||||
<div class="min-w-[95px] max-w-[400px] p-4 text-[14px]">
|
||||
<div class="text-[12px] font-medium text-[var(--color-text-4)]">{{ t('report.passRate') }}</div>
|
||||
<div class="mt-2 text-[18px] font-medium text-[var(--color-text-1)]">{{ functionCasePassRate }}</div>
|
||||
<div class="mt-2 text-[18px] font-medium text-[var(--color-text-1)]">{{ apiCasePassRate }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</div>
|
||||
<div class="flex h-full w-full min-w-[150px] items-center justify-center">
|
||||
<MsChart width="150px" height="150px" :options="functionCaseOptions"
|
||||
<MsChart width="150px" height="150px" :options="apiCaseOptions"
|
||||
/></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -96,18 +96,18 @@
|
||||
<div class="text-[12px] !text-[var(--color-text-4)]">{{ t('report.passRate') }}</div>
|
||||
<a-popover position="bottom" content-class="response-popover-content">
|
||||
<div class="flex justify-center text-[18px] font-medium">
|
||||
<div class="one-line-text max-w-[80px] text-[var(--color-text-1)]">{{ functionCasePassRate }} </div>
|
||||
<div class="one-line-text max-w-[80px] text-[var(--color-text-1)]">{{ scenarioCasePassRate }} </div>
|
||||
</div>
|
||||
<template #content>
|
||||
<div class="min-w-[95px] max-w-[400px] p-4 text-[14px]">
|
||||
<div class="text-[12px] font-medium text-[var(--color-text-4)]">{{ t('report.passRate') }}</div>
|
||||
<div class="mt-2 text-[18px] font-medium text-[var(--color-text-1)]">{{ functionCasePassRate }}</div>
|
||||
<div class="mt-2 text-[18px] font-medium text-[var(--color-text-1)]">{{ scenarioCasePassRate }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</div>
|
||||
<div class="flex h-full w-full min-w-[150px] items-center justify-center">
|
||||
<MsChart width="150px" height="150px" :options="functionCaseOptions"
|
||||
<MsChart width="150px" height="150px" :options="scenarioCaseOptions"
|
||||
/></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -157,7 +157,7 @@
|
||||
import Summary from '@/views/test-plan/report/detail/component/summary.vue';
|
||||
|
||||
import { updateReportDetail } from '@/api/modules/test-plan/report';
|
||||
import { defaultReportDetail, statusConfig } from '@/config/testPlan';
|
||||
import { commonConfig, defaultCount, defaultReportDetail, seriesConfig, statusConfig } from '@/config/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
|
||||
@ -196,34 +196,11 @@
|
||||
|
||||
const legendData = ref<LegendData[]>([]);
|
||||
|
||||
const charOptions = ref({
|
||||
tooltip: {
|
||||
show: false,
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
// 执行分析
|
||||
const executeCharOptions = ref({
|
||||
...commonConfig,
|
||||
series: {
|
||||
name: '',
|
||||
type: 'pie',
|
||||
radius: ['62%', '80%'],
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center',
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: 40,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
...seriesConfig,
|
||||
data: [
|
||||
{
|
||||
value: 0,
|
||||
@ -264,33 +241,43 @@
|
||||
},
|
||||
});
|
||||
|
||||
// 功能用例分析
|
||||
const functionCaseOptions = ref({
|
||||
tooltip: {
|
||||
show: false,
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
...commonConfig,
|
||||
series: {
|
||||
name: '',
|
||||
type: 'pie',
|
||||
radius: ['62%', '80%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center',
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: 40,
|
||||
fontWeight: 'bold',
|
||||
...seriesConfig,
|
||||
data: [
|
||||
{
|
||||
value: 0,
|
||||
name: t('common.success'),
|
||||
itemStyle: {
|
||||
color: '#00C261',
|
||||
},
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
// 接口用例分析
|
||||
const apiCaseOptions = ref({
|
||||
...commonConfig,
|
||||
series: {
|
||||
...seriesConfig,
|
||||
data: [
|
||||
{
|
||||
value: 0,
|
||||
name: t('common.success'),
|
||||
itemStyle: {
|
||||
color: '#00C261',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
// 场景用例分析
|
||||
const scenarioCaseOptions = ref({
|
||||
...commonConfig,
|
||||
series: {
|
||||
...seriesConfig,
|
||||
data: [
|
||||
{
|
||||
value: 0,
|
||||
@ -303,9 +290,9 @@
|
||||
},
|
||||
});
|
||||
|
||||
// 初始化图表
|
||||
function initOptionsData() {
|
||||
charOptions.value.series.data = statusConfig.map((item: StatusListType) => {
|
||||
// 初始化执行分析
|
||||
function initExecuteOptions() {
|
||||
executeCharOptions.value.series.data = statusConfig.map((item: StatusListType) => {
|
||||
return {
|
||||
value: detail.value.executeCount[item.value] || 0,
|
||||
name: t(item.label),
|
||||
@ -325,15 +312,17 @@
|
||||
rote: `${Number.isNaN(rate) ? 0 : rate.toFixed(2)}%`,
|
||||
};
|
||||
}) as unknown as LegendData[];
|
||||
}
|
||||
|
||||
// 获取通过率
|
||||
function getPassRateData(caseDetailCount: countDetail) {
|
||||
const caseCountDetail = caseDetailCount || defaultCount;
|
||||
const passRateData = statusConfig.filter((item) => ['success'].includes(item.value));
|
||||
const { functionalCount } = detail.value;
|
||||
const { success } = functionalCount;
|
||||
const { success } = caseCountDetail;
|
||||
const valueList = success ? statusConfig : passRateData;
|
||||
|
||||
functionCaseOptions.value.series.data = valueList.map((item: StatusListType) => {
|
||||
return valueList.map((item: StatusListType) => {
|
||||
return {
|
||||
value: detail.value.functionalCount[item.value] || 0,
|
||||
value: caseCountDetail[item.value] || 0,
|
||||
name: t(item.label),
|
||||
itemStyle: {
|
||||
color: success ? item.color : '#D4D4D8',
|
||||
@ -344,6 +333,15 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化图表
|
||||
function initOptionsData() {
|
||||
initExecuteOptions();
|
||||
const { functionalCount, apiCaseCount, apiScenarioCount } = detail.value;
|
||||
functionCaseOptions.value.series.data = getPassRateData(functionalCount);
|
||||
apiCaseOptions.value.series.data = getPassRateData(apiCaseCount);
|
||||
scenarioCaseOptions.value.series.data = getPassRateData(apiScenarioCount);
|
||||
}
|
||||
|
||||
async function handleUpdateReportDetail() {
|
||||
try {
|
||||
await updateReportDetail({
|
||||
@ -387,11 +385,51 @@
|
||||
},
|
||||
]);
|
||||
|
||||
function getSummaryDetail(detailCount: countDetail) {
|
||||
if (detailCount) {
|
||||
const { success, error, fakeError, pending, block } = detailCount;
|
||||
// 已执行用例
|
||||
const hasExecutedCase = success + error + fakeError + block;
|
||||
// 用例总数
|
||||
const caseTotal = hasExecutedCase + pending;
|
||||
// 执行率
|
||||
const executedCount = (hasExecutedCase / caseTotal) * 100;
|
||||
const apiExecutedRate = `${Number.isNaN(executedCount) ? 0 : executedCount.toFixed(2)}%`;
|
||||
// 通过率
|
||||
const successCount = (success / caseTotal) * 100;
|
||||
const successRate = `${Number.isNaN(successCount) ? 0 : successCount.toFixed(2)}%`;
|
||||
return {
|
||||
hasExecutedCase,
|
||||
caseTotal,
|
||||
apiExecutedRate,
|
||||
successRate,
|
||||
pending,
|
||||
success,
|
||||
};
|
||||
}
|
||||
return {
|
||||
hasExecutedCase: 0,
|
||||
caseTotal: 0,
|
||||
apiExecutedRate: 0,
|
||||
successRate: 0,
|
||||
pending: 0,
|
||||
success: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const functionCasePassRate = computed(() => {
|
||||
const { functionalCount } = detail.value;
|
||||
const { success, error, pending, block } = functionalCount;
|
||||
const successRate = (success / (success + error + pending + block)) * 100;
|
||||
return `${Number.isNaN(successRate) ? 0 : successRate.toFixed(2)}%`;
|
||||
const apiCaseDetail = getSummaryDetail(detail.value.functionalCount || defaultCount);
|
||||
return apiCaseDetail.successRate;
|
||||
});
|
||||
|
||||
const apiCasePassRate = computed(() => {
|
||||
const apiCaseDetail = getSummaryDetail(detail.value.apiCaseCount || defaultCount);
|
||||
return apiCaseDetail.successRate;
|
||||
});
|
||||
|
||||
const scenarioCasePassRate = computed(() => {
|
||||
const apiScenarioDetail = getSummaryDetail(detail.value.apiScenarioCount || defaultCount);
|
||||
return apiScenarioDetail.successRate;
|
||||
});
|
||||
|
||||
const activeTab = ref('bug');
|
||||
@ -431,38 +469,6 @@
|
||||
});
|
||||
});
|
||||
|
||||
function getSummaryDetail(detailCount: countDetail) {
|
||||
if (detailCount) {
|
||||
const { success, error, fakeError, pending, block } = detailCount;
|
||||
// 已执行用例
|
||||
const hasExecutedCase = success + error + fakeError + block;
|
||||
// 用例总数
|
||||
const caseTotal = hasExecutedCase + pending;
|
||||
// 执行率
|
||||
const executedCount = (hasExecutedCase / caseTotal) * 100;
|
||||
const apiExecutedRate = `${Number.isNaN(executedCount) ? 0 : executedCount.toFixed(2)}%`;
|
||||
// 通过率
|
||||
const successCount = (success / caseTotal) * 100;
|
||||
const successRate = `${Number.isNaN(successCount) ? 0 : successCount.toFixed(2)}%`;
|
||||
return {
|
||||
hasExecutedCase,
|
||||
caseTotal,
|
||||
apiExecutedRate,
|
||||
successRate,
|
||||
pending,
|
||||
success,
|
||||
};
|
||||
}
|
||||
return {
|
||||
hasExecutedCase: 0,
|
||||
caseTotal: 0,
|
||||
apiExecutedRate: 0,
|
||||
successRate: 0,
|
||||
pending: 0,
|
||||
success: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const summaryContent = computed(() => {
|
||||
const { functionalCount, apiCaseCount, apiScenarioCount } = detail.value;
|
||||
const functionalCaseDetail = getSummaryDetail(functionalCount);
|
||||
|
@ -288,7 +288,7 @@
|
||||
<template #title>
|
||||
{{ t('testPlan.testPlanIndex.batchExecution') }}
|
||||
</template>
|
||||
<a-radio-group v-model="executeForm.executeMode">
|
||||
<a-radio-group v-model="executeForm.runMode">
|
||||
<a-radio value="SERIAL">{{ t('testPlan.testPlanIndex.serial') }}</a-radio>
|
||||
<a-radio value="PARALLEL">{{ t('testPlan.testPlanIndex.parallel') }}</a-radio>
|
||||
</a-radio-group>
|
||||
@ -373,6 +373,7 @@
|
||||
deleteScheduleTask,
|
||||
dragPlanOnGroup,
|
||||
executePlanOrGroup,
|
||||
executeSinglePlan,
|
||||
getPlanPassRate,
|
||||
getTestPlanDetail,
|
||||
getTestPlanList,
|
||||
@ -389,6 +390,7 @@
|
||||
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
|
||||
import type {
|
||||
AddTestPlanParams,
|
||||
BatchExecutePlan,
|
||||
BatchMoveParams,
|
||||
CreateTask,
|
||||
ExecutePlan,
|
||||
@ -431,13 +433,14 @@
|
||||
const hasOperationPermission = computed(() =>
|
||||
hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE', 'PROJECT_TEST_PLAN:READ+EXECUTE', 'PROJECT_TEST_PLAN:READ+ADD'])
|
||||
);
|
||||
const showType = ref<keyof typeof testPlanTypeEnum>(testPlanTypeEnum.ALL);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'testPlan.testPlanIndex.ID',
|
||||
slotName: 'num',
|
||||
dataIndex: 'num',
|
||||
width: 150,
|
||||
width: 180,
|
||||
showInTable: true,
|
||||
showDrag: false,
|
||||
showTooltip: true,
|
||||
@ -581,8 +584,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const showType = ref<keyof typeof testPlanTypeEnum>(testPlanTypeEnum.ALL);
|
||||
|
||||
// 设置对齐缩进
|
||||
function hasIndent(record: TestPlanItem) {
|
||||
return (showType.value === 'ALL' || showType.value === 'GROUP') &&
|
||||
@ -873,19 +874,18 @@
|
||||
/**
|
||||
* 批量执行
|
||||
*/
|
||||
const initExecuteForm: ExecutePlan = {
|
||||
const initExecuteForm: BatchExecutePlan = {
|
||||
projectId: appStore.currentProjectId,
|
||||
executeIds: [],
|
||||
executeMode: 'SERIAL',
|
||||
runMode: 'SERIAL',
|
||||
executionSource: 'JENKINS',
|
||||
};
|
||||
|
||||
const executeForm = ref<ExecutePlan>(cloneDeep(initExecuteForm));
|
||||
const executeForm = ref<BatchExecutePlan>(cloneDeep(initExecuteForm));
|
||||
const executeVisible = ref<boolean>(false);
|
||||
|
||||
function handleExecute(isBatch: boolean) {
|
||||
if (isBatch) {
|
||||
executeForm.value.executeIds = batchParams.value.selectedIds || [];
|
||||
}
|
||||
function handleExecute() {
|
||||
executeForm.value.executeIds = batchParams.value.selectedIds || [];
|
||||
executeVisible.value = true;
|
||||
}
|
||||
|
||||
@ -915,13 +915,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function singleExecute(id: string) {
|
||||
try {
|
||||
const params: ExecutePlan = {
|
||||
executeId: id,
|
||||
runMode: 'SERIAL',
|
||||
executionSource: 'JENKINS',
|
||||
};
|
||||
await executeSinglePlan(params);
|
||||
Message.success(t('case.detail.execute.success'));
|
||||
fetchData();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试计划详情
|
||||
function executePlan(record: TestPlanItem) {
|
||||
const { type, id } = record;
|
||||
|
||||
if (type === testPlanTypeEnum.GROUP) {
|
||||
handleExecute(false);
|
||||
executeForm.value.executeIds = [id];
|
||||
singleExecute(record.id);
|
||||
return;
|
||||
}
|
||||
if (type === testPlanTypeEnum.TEST_PLAN) {
|
||||
@ -936,8 +950,7 @@
|
||||
},
|
||||
});
|
||||
} else {
|
||||
executeForm.value.executeIds = [id];
|
||||
executeHandler();
|
||||
singleExecute(record.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1019,6 +1032,7 @@
|
||||
},
|
||||
type: showType.value,
|
||||
scheduleOpen: enable,
|
||||
editColumn: 'SCHEDULE',
|
||||
};
|
||||
await batchEditTestPlan(params);
|
||||
Message.success(
|
||||
@ -1143,7 +1157,7 @@
|
||||
batchParams.value = params;
|
||||
switch (event.eventTag) {
|
||||
case 'execute':
|
||||
handleExecute(true);
|
||||
handleExecute();
|
||||
break;
|
||||
case 'copy':
|
||||
handleCopyOrMove('copy');
|
||||
|
Loading…
Reference in New Issue
Block a user