feat(报告): 测试计划组报告导出 pdf
This commit is contained in:
parent
0a3d9e360d
commit
ffa7c29451
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)]',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
};
|
||||
|
|
|
@ -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报告导出成功',
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue