feat(报告): 测试计划组报告导出 pdf

This commit is contained in:
baiqi 2024-09-10 17:32:47 +08:00 committed by Craftsman
parent 0a3d9e360d
commit ffa7c29451
7 changed files with 197 additions and 114 deletions

View File

@ -144,7 +144,8 @@ export default async function exportPDF(
pdf.addPage();
}
}
const lastImagePageUseHeight = (canvasHeight - IMAGE_HEIGHT) / PAGE_PDF_WIDTH_RATIO / SCALE_RATIO; // 最后一页带图片的pdf页面被图片占用的高度
const lastImagePageUseHeight =
(canvasHeight > IMAGE_HEIGHT ? canvasHeight - IMAGE_HEIGHT : canvasHeight) / PAGE_PDF_WIDTH_RATIO / SCALE_RATIO; // 最后一页带图片的pdf页面被图片占用的高度
autoTableConfig.forEach((config, index) => {
autoTable(pdf, {
...config,

View File

@ -8,7 +8,7 @@
<script setup lang="ts">
import { useI18n } from '@/hooks/useI18n';
import { ReportStatusEnum } from '@/enums/reportEnum';
import { iconTypeStatus } from '../detail/component/reportConfig';
const { t } = useI18n();
const props = defineProps<{
@ -21,21 +21,6 @@
color?: string;
}
const iconTypeStatus: Record<string, any> = {
SUCCESS: {
icon: 'icon-icon_succeed_colorful',
label: 'common.success',
},
ERROR: {
icon: 'icon-icon_close_colorful',
label: 'common.fail',
},
DEFAULT: {
label: '-',
color: '!text-[var(--color-text-input-border)]',
},
};
function getExecutionResult(): IconType {
return iconTypeStatus[props.status] ? iconTypeStatus[props.status] : iconTypeStatus.DEFAULT;
}

View File

@ -184,4 +184,17 @@ export const detailTableExample: Record<string, any> = {
[ReportCardTypeEnum.SCENARIO_CASE_DETAIL]: createData<ApiOrScenarioCaseItem>(scenarioCaseList),
};
export default {};
export const iconTypeStatus: Record<string, any> = {
SUCCESS: {
icon: 'icon-icon_succeed_colorful',
label: 'common.success',
},
ERROR: {
icon: 'icon-icon_close_colorful',
label: 'common.fail',
},
DEFAULT: {
label: '-',
color: '!text-[var(--color-text-input-border)]',
},
};

View File

@ -20,7 +20,7 @@
v-if="hasAnyPermission(['PROJECT_TEST_PLAN_REPORT:READ+SHARE']) && !props.shareId"
type="icon"
status="secondary"
class="ml-4 !rounded-[var(--border-radius-small)]"
class="!mr-0 ml-4 !rounded-[var(--border-radius-small)]"
:loading="shareLoading"
@click="shareHandler"
>
@ -28,7 +28,7 @@
{{ t('common.share') }}
</MsButton>
<MsButton type="icon" status="secondary" class="ml-4 !rounded-[var(--border-radius-small)]" @click="exportPdf">
导出 PDF
{{ t('report.detail.exportPdf') }}
</MsButton>
</div>
</template>

View File

@ -122,6 +122,7 @@
import MsChart from '@/components/pure/chart/index.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import { lastExecuteResultMap } from '@/components/business/ms-case-associate/utils';
import { IconType } from '@/views/api-test/report/component/reportStatus.vue';
import SingleStatusProgress from '@/views/test-plan/report/component/singleStatusProgress.vue';
import ExecuteAnalysis from '@/views/test-plan/report/detail/component/system-card/executeAnalysis.vue';
import ReportDetailTable from '@/views/test-plan/report/detail/component/system-card/reportDetailTable.vue';
@ -131,6 +132,8 @@
getApiPage,
getReportBugList,
getReportDetail,
getReportDetailPage,
getReportDetailSharePage,
getReportFeatureCaseList,
getReportLayout,
getReportShareBugList,
@ -148,7 +151,6 @@
import exportPDF, { PAGE_PDF_WIDTH_RATIO } from '@/hooks/useExportPDF';
import { useI18n } from '@/hooks/useI18n';
import { addCommasToNumber } from '@/utils';
import exportPdf, { MAX_CANVAS_HEIGHT, SCALE_RATIO } from '@/utils/exportPdf';
import type {
configItem,
@ -159,7 +161,7 @@
} from '@/models/testPlan/testPlanReport';
import { ReportCardTypeEnum } from '@/enums/testPlanReportEnum';
import { defaultGroupConfig, defaultSingleConfig } from './component/reportConfig';
import { defaultGroupConfig, defaultSingleConfig, iconTypeStatus } from './component/reportConfig';
import { getSummaryDetail } from '@/views/test-plan/report/utils';
import { ColumnInput, RowInput } from 'jspdf-autotable';
@ -570,6 +572,53 @@
).list;
}
const groupColumns: MsTableColumn = [
{
title: 'report.plan.name',
dataIndex: 'testPlanName',
width: 180,
},
{
title: 'report.detail.testPlanGroup.result',
dataIndex: 'resultStatus',
width: 200,
},
{
title: 'report.detail.threshold',
dataIndex: 'passThreshold',
width: 150,
},
{
title: 'report.passRate',
dataIndex: 'passRate',
width: 150,
},
{
title: 'report.detail.testPlanGroup.useCasesCount',
dataIndex: 'caseTotal',
width: 100,
},
];
const reportDetailList = () => {
return !shareId.value ? getReportDetailPage : getReportDetailSharePage;
};
const fullGroupList = ref<PlanReportDetail[]>([]);
async function initGroupList() {
fullGroupList.value = (
await reportDetailList()({
current: 1,
pageSize: 500,
reportId: reportId.value,
shareId: shareId.value ?? undefined,
startPager: false,
})
).list;
}
function getExecutionResult(status?: string): IconType {
return status && iconTypeStatus[status] ? iconTypeStatus[status] : iconTypeStatus.DEFAULT;
}
async function getDetail() {
try {
loading.value = true;
@ -580,103 +629,136 @@
reportForm.value.reportName = name;
initOptionsData();
if (!defaultLayout && id) {
getDefaultLayout();
await getDefaultLayout();
await initGroupList();
nextTick(async () => {
exportPDF(
name,
'report-detail',
[
{
columnStyles: {
testPlanName: { cellWidth: 710 / PAGE_PDF_WIDTH_RATIO },
resultStatus: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
passThreshold: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
passRate: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
caseTotal: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: groupColumns.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullGroupList.value.map((e) => ({
...e,
resultStatus: t(getExecutionResult(e.resultStatus).label),
passRate: `${e.passRate}%`,
passThreshold: `${e.passThreshold}%`,
})) as RowInput[],
},
],
() => {
loading.value = false;
Message.success(t('report.detail.exportPdfSuccess'));
}
);
});
} else {
innerCardList.value = (isGroup.value ? cloneDeep(defaultGroupConfig) : cloneDeep(defaultSingleConfig)).filter(
(e: any) => [ReportCardTypeEnum.CUSTOM_CARD, ReportCardTypeEnum.SUMMARY].includes(e.value)
);
await Promise.all([initBugList(), initCaseList(), initApiList(), initScenarioList()]);
nextTick(async () => {
exportPDF(
name,
'report-detail',
[
{
columnStyles: {
num: { cellWidth: 120 / PAGE_PDF_WIDTH_RATIO },
title: { cellWidth: 600 / PAGE_PDF_WIDTH_RATIO },
status: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
handleUserName: { cellWidth: 270 / PAGE_PDF_WIDTH_RATIO },
relationCaseCount: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: bugColumns.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullBugList.value,
},
{
columnStyles: {
num: { cellWidth: 100 / PAGE_PDF_WIDTH_RATIO },
name: { cellWidth: 480 / PAGE_PDF_WIDTH_RATIO },
executeResult: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
priority: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
moduleName: { cellWidth: 200 / PAGE_PDF_WIDTH_RATIO },
executeUser: { cellWidth: 100 / PAGE_PDF_WIDTH_RATIO },
relationCaseCount: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: caseColumns.value.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullCaseList.value.map((e: any) => ({
...e,
executeResult: t(lastExecuteResultMap[e.executeResult]?.statusText || '-'),
executeUser: e.executeUser?.name || '-',
})) as RowInput[],
},
{
columnStyles: {
num: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
name: { cellWidth: 450 / PAGE_PDF_WIDTH_RATIO },
executeResult: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
priority: { cellWidth: 80 / PAGE_PDF_WIDTH_RATIO },
moduleName: { cellWidth: 200 / PAGE_PDF_WIDTH_RATIO },
executeUser: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
bugCount: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: apiColumns.value.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullApiList.value.map((e: any) => ({
...e,
executeResult: t(lastExecuteResultMap[e.executeResult]?.statusText || '-'),
executeUser: e.executeUser?.name || '-',
})) as RowInput[],
},
{
columnStyles: {
num: { cellWidth: 100 / PAGE_PDF_WIDTH_RATIO },
name: { cellWidth: 480 / PAGE_PDF_WIDTH_RATIO },
executeResult: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
priority: { cellWidth: 80 / PAGE_PDF_WIDTH_RATIO },
moduleName: { cellWidth: 200 / PAGE_PDF_WIDTH_RATIO },
executeUser: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
bugCount: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: apiColumns.value.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullScenarioList.value.map((e: any) => ({
...e,
executeResult: t(lastExecuteResultMap[e.executeResult]?.statusText || '-'),
executeUser: e.executeUser?.name || '-',
})) as RowInput[],
},
],
() => {
loading.value = false;
Message.success(t('report.detail.exportPdfSuccess'));
}
);
});
}
await Promise.all([initBugList(), initCaseList(), initApiList(), initScenarioList()]);
nextTick(async () => {
exportPDF(
name,
'report-detail',
[
{
columnStyles: {
num: { cellWidth: 120 / PAGE_PDF_WIDTH_RATIO },
title: { cellWidth: 600 / PAGE_PDF_WIDTH_RATIO },
status: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
handleUserName: { cellWidth: 270 / PAGE_PDF_WIDTH_RATIO },
relationCaseCount: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: bugColumns.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullBugList.value,
},
{
columnStyles: {
num: { cellWidth: 100 / PAGE_PDF_WIDTH_RATIO },
name: { cellWidth: 480 / PAGE_PDF_WIDTH_RATIO },
executeResult: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
priority: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
moduleName: { cellWidth: 200 / PAGE_PDF_WIDTH_RATIO },
executeUser: { cellWidth: 100 / PAGE_PDF_WIDTH_RATIO },
relationCaseCount: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: caseColumns.value.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullCaseList.value.map((e: any) => ({
...e,
executeResult: t(lastExecuteResultMap[e.executeResult]?.statusText || '-'),
executeUser: e.executeUser?.name || '-',
})) as RowInput[],
},
{
columnStyles: {
num: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
name: { cellWidth: 450 / PAGE_PDF_WIDTH_RATIO },
executeResult: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
priority: { cellWidth: 80 / PAGE_PDF_WIDTH_RATIO },
moduleName: { cellWidth: 200 / PAGE_PDF_WIDTH_RATIO },
executeUser: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
bugCount: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: apiColumns.value.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullApiList.value.map((e: any) => ({
...e,
executeResult: t(lastExecuteResultMap[e.executeResult]?.statusText || '-'),
executeUser: e.executeUser?.name || '-',
})) as RowInput[],
},
{
columnStyles: {
num: { cellWidth: 100 / PAGE_PDF_WIDTH_RATIO },
name: { cellWidth: 480 / PAGE_PDF_WIDTH_RATIO },
executeResult: { cellWidth: 110 / PAGE_PDF_WIDTH_RATIO },
priority: { cellWidth: 80 / PAGE_PDF_WIDTH_RATIO },
moduleName: { cellWidth: 200 / PAGE_PDF_WIDTH_RATIO },
executeUser: { cellWidth: 130 / PAGE_PDF_WIDTH_RATIO },
bugCount: { cellWidth: 90 / PAGE_PDF_WIDTH_RATIO },
},
columns: apiColumns.value.map((item) => ({
...item,
title: t(item.title as string),
dataKey: item.dataIndex,
})) as ColumnInput[],
body: fullScenarioList.value.map((e: any) => ({
...e,
executeResult: t(lastExecuteResultMap[e.executeResult]?.statusText || '-'),
executeUser: e.executeUser?.name || '-',
})) as RowInput[],
},
],
() => {
loading.value = false;
Message.success(t('report.detail.exportPdfSuccess'));
}
);
});
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);

View File

@ -57,6 +57,7 @@ export default {
'report.detail.systemInternalTooltip': 'System built-in, not editable',
'report.detail.reportNameNotEmpty': 'The report name cannot be empty',
'report.detail.manualGenReportSuccess': 'The custom generated report was successful',
'report.detail.exportPdf': 'Export PDF',
'report.detail.exportingPdf': 'Exporting PDF report...',
'report.detail.exportPdfSuccess': 'PDF report exported successfully',
};

View File

@ -57,6 +57,7 @@ export default {
'report.detail.systemInternalTooltip': '系统内置,不可编辑',
'report.detail.reportNameNotEmpty': '报告名称不能为空',
'report.detail.manualGenReportSuccess': '自定义生成报告成功',
'report.detail.exportPdf': '导出 PDF',
'report.detail.exportingPdf': 'PDF报告导出中...',
'report.detail.exportPdfSuccess': 'PDF报告导出成功',
};