feat(报告): 接口测试批量导出 PDF 报告
This commit is contained in:
parent
36d920e6d3
commit
cef35278b9
|
@ -43,6 +43,7 @@ import {
|
|||
ExecuteCaseUrl,
|
||||
ExportDefinitionUrl,
|
||||
GetApiDownloadFileUrl,
|
||||
GetCaseBatchExportParamsUrl,
|
||||
GetCaseDetailUrl,
|
||||
GetCaseReportByIdUrl,
|
||||
GetCaseReportDetailUrl,
|
||||
|
@ -629,3 +630,8 @@ export function logCaseReportExport(reportId: string) {
|
|||
export function logCaseReportBatchExport(data: BatchApiParams) {
|
||||
return MSR.post({ url: `${CaseBatchExportLogUrl}`, data });
|
||||
}
|
||||
|
||||
// 接口用例导出报告id集合
|
||||
export function getCaseBatchExportParams(data: BatchApiParams) {
|
||||
return MSR.post({ url: `${GetCaseBatchExportParamsUrl}`, data });
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
FollowScenarioUrl,
|
||||
GetModuleCountUrl,
|
||||
GetModuleTreeUrl,
|
||||
GetScenarioBatchExportParamsUrl,
|
||||
GetScenarioStepUrl,
|
||||
GetScenarioUrl,
|
||||
GetStepProjectInfoUrl,
|
||||
|
@ -317,3 +318,8 @@ export function logScenarioReportExport(reportId: string) {
|
|||
export function logScenarioReportBatchExport(data: BatchApiParams) {
|
||||
return MSR.post({ url: `${ScenarioBatchExportLogUrl}`, data });
|
||||
}
|
||||
|
||||
// 场景导出报告id集合
|
||||
export function getScenarioBatchExportParams(data: BatchApiParams) {
|
||||
return MSR.post({ url: `${GetScenarioBatchExportParamsUrl}`, data });
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ export const GetCaseReportByIdUrl = '/api/report/case/get/'; // 接口用例报
|
|||
export const GetCaseReportDetailUrl = '/api/report/case/get/detail/'; // 接口用例报告获取
|
||||
export const CaseExportLogUrl = '/api/report/case/export'; // 接口用例导出报告日志记录
|
||||
export const CaseBatchExportLogUrl = '/api/report/case/batch-export'; // 接口用例批量导出报告日志记录
|
||||
export const GetCaseBatchExportParamsUrl = '/api/report/case/batch-param'; // 接口用例批量导出报告id集合
|
||||
|
||||
/**
|
||||
* 接口用例回收站
|
||||
|
|
|
@ -43,3 +43,4 @@ export const ExecuteHistoryUrl = '/api/scenario/execute/page'; // 场景执行
|
|||
export const ScenarioHistoryUrl = '/api/scenario/operation-history/page'; // 场景变更历史
|
||||
export const ScenarioExportLogUrl = '/api/report/scenario/export'; // 场景导出报告日志记录
|
||||
export const ScenarioBatchExportLogUrl = '/api/report/scenario/batch-export'; // 场景批量导出报告日志记录
|
||||
export const GetScenarioBatchExportParamsUrl = '/api/report/scenario/batch-param'; // 场景批量导出报告id 集合
|
||||
|
|
|
@ -146,7 +146,7 @@
|
|||
const appStore = useAppStore();
|
||||
const tableStore = useTableStore();
|
||||
const route = useRoute();
|
||||
const { openNewPage } = useOpenNewPage();
|
||||
const { openNewPage, openNewPageWithParams } = useOpenNewPage();
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
|
@ -271,7 +271,7 @@
|
|||
dataIndex: 'operation',
|
||||
fixed: 'right',
|
||||
title: hasAnyPermission(['PROJECT_API_REPORT:READ+DELETE']) ? 'common.operation' : '',
|
||||
width: hasAnyPermission(['PROJECT_API_REPORT:READ+DELETE']) ? 100 : 50,
|
||||
width: hasAnyPermission(['PROJECT_API_REPORT:READ+DELETE']) ? 130 : 50,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -340,6 +340,11 @@
|
|||
eventTag: 'batchStop',
|
||||
permission: ['PROJECT_API_REPORT:READ+DELETE'],
|
||||
},
|
||||
{
|
||||
label: 'common.export',
|
||||
eventTag: 'batchExport',
|
||||
permission: ['PROJECT_TEST_PLAN_REPORT:READ+EXPORT'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -364,31 +369,42 @@
|
|||
},
|
||||
projectId: appStore.currentProjectId,
|
||||
};
|
||||
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('report.delete.tip', {
|
||||
count: params?.currentSelectCount || params?.selectedIds?.length,
|
||||
}),
|
||||
content: '',
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await reportBathDelete(props.moduleType, batchParams.value);
|
||||
Message.success(t('apiTestDebug.deleteSuccess'));
|
||||
resetSelector();
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
if (event.eventTag === 'batchExport') {
|
||||
openNewPageWithParams(
|
||||
props.moduleType === ReportEnum.API_SCENARIO_REPORT
|
||||
? FullPageEnum.FULL_PAGE_SCENARIO_EXPORT_PDF
|
||||
: FullPageEnum.FULL_PAGE_API_CASE_EXPORT_PDF,
|
||||
{
|
||||
type: showType.value,
|
||||
},
|
||||
batchParams.value
|
||||
);
|
||||
} else {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('report.delete.tip', {
|
||||
count: params?.currentSelectCount || params?.selectedIds?.length,
|
||||
}),
|
||||
content: '',
|
||||
okText: t('common.confirmDelete'),
|
||||
cancelText: t('common.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await reportBathDelete(props.moduleType, batchParams.value);
|
||||
Message.success(t('apiTestDebug.deleteSuccess'));
|
||||
resetSelector();
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function searchList() {
|
||||
|
|
|
@ -235,6 +235,9 @@
|
|||
const activeTab = ref<'tiled' | 'tab'>('tiled');
|
||||
|
||||
function getRote(count: number, countTotal: number) {
|
||||
if (Number.isNaN(count) || Number.isNaN(countTotal) || countTotal === 0) {
|
||||
return '0.00';
|
||||
}
|
||||
return (((count || 0) / countTotal) * 100).toFixed(2);
|
||||
}
|
||||
function initOptionsData() {
|
||||
|
|
|
@ -77,7 +77,11 @@
|
|||
<div v-show="step.code" class="mr-2 text-[var(--color-text-4)]">
|
||||
{{ t('report.detail.api.statusCode') }}</div
|
||||
>
|
||||
<div v-show="step.code" class="max-w-[200px]" :style="{ color: statusCodeColor(step.code) }">
|
||||
<div
|
||||
v-show="step.code"
|
||||
class="max-w-[200px] break-all"
|
||||
:style="{ color: statusCodeColor(step.code) }"
|
||||
>
|
||||
{{ step.code || '-' }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
<template>
|
||||
<a-spin :loading="loading" :tip="t('report.detail.exportingPdf')" class="report-detail-container">
|
||||
<a-spin
|
||||
:loading="batchLoading || loading"
|
||||
:tip="batchLoading ? batchExportTip : t('report.detail.exportingPdf')"
|
||||
class="report-detail-container"
|
||||
>
|
||||
<div id="report-detail" class="report-detail">
|
||||
<div class="mb-[16px] rounded-[var(--border-radius-small)] bg-white p-[16px]">{{ reportStepDetail?.name }}</div>
|
||||
<div class="mb-[16px] break-all rounded-[var(--border-radius-small)] bg-white p-[16px]">
|
||||
{{ reportStepDetail?.name }}
|
||||
</div>
|
||||
<CaseReportCom :detail-info="reportStepDetail" is-export />
|
||||
</div>
|
||||
</a-spin>
|
||||
|
@ -13,12 +19,17 @@
|
|||
|
||||
import CaseReportCom from './component/caseReportCom.vue';
|
||||
|
||||
import { logCaseReportExport } from '@/api/modules/api-test/management';
|
||||
import {
|
||||
getCaseBatchExportParams,
|
||||
logCaseReportBatchExport,
|
||||
logCaseReportExport,
|
||||
} from '@/api/modules/api-test/management';
|
||||
import { reportCaseDetail } from '@/api/modules/api-test/report';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import exportPDF from '@/utils/exportPdf';
|
||||
|
||||
import { ReportDetail } from '@/models/apiTest/report';
|
||||
import { BatchApiParams } from '@/models/common';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
@ -26,10 +37,10 @@
|
|||
const loading = ref(false);
|
||||
const reportStepDetail = ref<ReportDetail>();
|
||||
|
||||
async function initReportDetail() {
|
||||
async function initReportDetail(id?: string) {
|
||||
try {
|
||||
loading.value = true;
|
||||
reportStepDetail.value = await reportCaseDetail(route.query.id as string);
|
||||
reportStepDetail.value = await reportCaseDetail(id || (route.query.id as string));
|
||||
setTimeout(() => {
|
||||
nextTick(async () => {
|
||||
await exportPDF(reportStepDetail.value?.name || '', 'report-detail');
|
||||
|
@ -43,16 +54,55 @@
|
|||
}
|
||||
}
|
||||
|
||||
async function logExport() {
|
||||
try {
|
||||
async function logExport(params?: BatchApiParams) {
|
||||
if (params) {
|
||||
await logCaseReportBatchExport(params);
|
||||
} else {
|
||||
await logCaseReportExport(route.query.id as string);
|
||||
}
|
||||
}
|
||||
|
||||
const batchLoading = ref<boolean>(false);
|
||||
const batchIds = ref<string[]>([]);
|
||||
const exportCurrent = ref<number>(0);
|
||||
const exportTotal = ref<number>(0);
|
||||
const batchExportTip = computed(() =>
|
||||
t('report.detail.batchExportingPdf', { current: exportCurrent.value, total: exportTotal.value })
|
||||
);
|
||||
|
||||
async function initBatchIds(params: BatchApiParams) {
|
||||
try {
|
||||
batchLoading.value = true;
|
||||
batchIds.value = await getCaseBatchExportParams(params);
|
||||
exportTotal.value = batchIds.value.length;
|
||||
while (batchIds.value.length > 0) {
|
||||
exportCurrent.value += 1;
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await initReportDetail(batchIds.value.shift());
|
||||
}
|
||||
nextTick(() => {
|
||||
// 等最后一条成功提示后清空
|
||||
Message.clear();
|
||||
Message.success(t('report.detail.batchExportPdfSuccess'));
|
||||
});
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
batchLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.origin !== window.location.origin) {
|
||||
return;
|
||||
}
|
||||
// 初始化批量导出报告 id 集合
|
||||
const batchParams = event.data;
|
||||
initBatchIds(batchParams);
|
||||
logExport(batchParams);
|
||||
});
|
||||
if (route.query.id) {
|
||||
initReportDetail();
|
||||
logExport();
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
<template>
|
||||
<a-spin :loading="loading" :tip="t('report.detail.exportingPdf')" class="report-detail-container">
|
||||
<a-spin
|
||||
:loading="batchLoading || loading"
|
||||
:tip="batchLoading ? batchExportTip : t('report.detail.exportingPdf')"
|
||||
class="report-detail-container"
|
||||
>
|
||||
<div id="report-detail" class="report-detail">
|
||||
<div class="mb-[16px] rounded-[var(--border-radius-small)] bg-white p-[16px]">{{ reportStepDetail?.name }}</div>
|
||||
<div class="mb-[16px] break-all rounded-[var(--border-radius-small)] bg-white p-[16px]">
|
||||
{{ reportStepDetail?.name }}
|
||||
</div>
|
||||
<ScenarioCom :detail-info="reportStepDetail" is-export />
|
||||
</div>
|
||||
</a-spin>
|
||||
|
@ -14,11 +20,16 @@
|
|||
import ScenarioCom from './component/scenarioCom.vue';
|
||||
|
||||
import { reportScenarioDetail } from '@/api/modules/api-test/report';
|
||||
import { logScenarioReportExport } from '@/api/modules/api-test/scenario';
|
||||
import {
|
||||
getScenarioBatchExportParams,
|
||||
logScenarioReportBatchExport,
|
||||
logScenarioReportExport,
|
||||
} from '@/api/modules/api-test/scenario';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import exportPDF from '@/utils/exportPdf';
|
||||
|
||||
import { ReportDetail } from '@/models/apiTest/report';
|
||||
import { BatchApiParams } from '@/models/common';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
@ -26,33 +37,75 @@
|
|||
const loading = ref(false);
|
||||
const reportStepDetail = ref<ReportDetail>();
|
||||
|
||||
async function initReportDetail() {
|
||||
async function initReportDetail(id?: string) {
|
||||
try {
|
||||
loading.value = true;
|
||||
reportStepDetail.value = await reportScenarioDetail(route.query.id as string);
|
||||
setTimeout(() => {
|
||||
nextTick(async () => {
|
||||
await exportPDF(reportStepDetail.value?.name || '', 'report-detail');
|
||||
loading.value = false;
|
||||
Message.success(t('report.detail.exportPdfSuccess'));
|
||||
});
|
||||
}, 500);
|
||||
reportStepDetail.value = await reportScenarioDetail(id || (route.query.id as string));
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(async () => {
|
||||
await nextTick(async () => {
|
||||
await exportPDF(reportStepDetail.value?.name || '', 'report-detail');
|
||||
loading.value = false;
|
||||
Message.success(t('report.detail.exportPdfSuccess'));
|
||||
resolve(true);
|
||||
});
|
||||
}, 500); // TODO:树组件渲染延迟导致导出 pdf 时内容不全,暂时延迟 500ms
|
||||
});
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function logExport() {
|
||||
try {
|
||||
async function logExport(params?: BatchApiParams) {
|
||||
if (params) {
|
||||
await logScenarioReportBatchExport(params);
|
||||
} else {
|
||||
await logScenarioReportExport(route.query.id as string);
|
||||
}
|
||||
}
|
||||
|
||||
const batchLoading = ref<boolean>(false);
|
||||
const batchIds = ref<string[]>([]);
|
||||
const exportCurrent = ref<number>(0);
|
||||
const exportTotal = ref<number>(0);
|
||||
const batchExportTip = computed(() =>
|
||||
t('report.detail.batchExportingPdf', { current: exportCurrent.value, total: exportTotal.value })
|
||||
);
|
||||
|
||||
async function initBatchIds(params: BatchApiParams) {
|
||||
try {
|
||||
batchLoading.value = true;
|
||||
batchIds.value = await getScenarioBatchExportParams(params);
|
||||
exportTotal.value = batchIds.value.length;
|
||||
while (batchIds.value.length > 0) {
|
||||
exportCurrent.value += 1;
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await initReportDetail(batchIds.value.shift());
|
||||
}
|
||||
nextTick(() => {
|
||||
// 等最后一条成功提示后清空
|
||||
Message.clear();
|
||||
Message.success(t('report.detail.batchExportPdfSuccess'));
|
||||
});
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
batchLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.origin !== window.location.origin) {
|
||||
return;
|
||||
}
|
||||
// 初始化批量导出报告 id 集合
|
||||
const batchParams = event.data;
|
||||
initBatchIds(batchParams);
|
||||
logExport(batchParams);
|
||||
});
|
||||
if (route.query.id) {
|
||||
initReportDetail();
|
||||
logExport();
|
||||
|
|
Loading…
Reference in New Issue