fix(报表统计): 优化饼状图的展示方式以及导出细节

--bug=1021171 --user=宋天阳 【报表统计】github#20870,测试用例统计图,报表展示数值重叠,导出后缺少图表
https://www.tapd.cn/55049933/s/1351691
This commit is contained in:
song-tianyang 2023-03-16 18:26:40 +08:00 committed by 建国
parent 1c7ef48abd
commit 1d124b57f4
10 changed files with 780 additions and 366 deletions

View File

@ -8,6 +8,14 @@ import {
import i18n from "../i18n";
import html2canvas from "html2canvas";
import JsPDF from "jspdf";
/**
* 同一行的多个文本框高度保持一致
* 同时支持 autosize 的功能
* @param size 同一行中文本框的个数
* @param index 编辑行的下标
* 如果编辑某一行则只调整某一行提升效率
*/
import calcTextareaHeight from "element-ui/packages/input/src/calcTextareaHeight";
export function setCustomizeColor(color) {
// 自定义主题风格
@ -309,10 +317,10 @@ export function sizeToByte(size) {
let k = 1024,
sizeUnits = ["B", "K", "M", "G", "T", "P", "E", "Z", "Y"];
let i = 1;
for (i++; i < sizeUnits.length;) {
for (i++; i < sizeUnits.length; ) {
let unit = sizeUnits[i];
if (size.indexOf(unit) !== -1) {
return size.toString().replace(unit, "") * Math.pow(k, i)
return size.toString().replace(unit, "") * Math.pow(k, i);
}
}
}
@ -325,15 +333,6 @@ export function getTypeByFileName(filename) {
return type.toUpperCase();
}
/**
* 同一行的多个文本框高度保持一致
* 同时支持 autosize 的功能
* @param size 同一行中文本框的个数
* @param index 编辑行的下标
* 如果编辑某一行则只调整某一行提升效率
*/
import calcTextareaHeight from "element-ui/packages/input/src/calcTextareaHeight";
export function resizeTextarea(size = 2, index) {
let textareaList = document.querySelectorAll(
".sync-textarea .el-textarea__inner"
@ -404,7 +403,7 @@ export function downloadPDF(ele, pdfName) {
let scale = canvas.height / ((canvas.width / 592.28) * 841.89);
scale = scale > 3 ? 1 : 2;
context.translate(-eleOffsetLeft - abs, -eleOffsetTop);
let scrollWidth = document.getElementById("apiTestReport").scrollWidth;
let scrollWidth = ele.scrollWidth;
html2canvas(ele, {
scale: scale, // 背景灰色
background: "#FFFFFF",

View File

@ -2,6 +2,7 @@ package io.metersphere.reportstatistics.service;
import io.metersphere.base.domain.CustomField;
import io.metersphere.base.domain.User;
import io.metersphere.commons.constants.MicroServiceName;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.JSON;
import io.metersphere.i18n.Translator;
@ -15,15 +16,16 @@ import io.metersphere.reportstatistics.service.remote.apitest.ScenarioRemoteServ
import io.metersphere.reportstatistics.service.remote.performance.PerformanceRemoteService;
import io.metersphere.reportstatistics.service.remote.projectmanagement.TestCaseTemplateRemoteService;
import io.metersphere.reportstatistics.service.remote.track.TestCaseRemoteService;
import io.metersphere.reportstatistics.utils.DiscoveryUtil;
import io.metersphere.request.member.QueryMemberRequest;
import io.metersphere.service.BaseUserService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*;
@Service
@ -126,7 +128,6 @@ public class TestCaseCountService {
} else if (StringUtils.equalsIgnoreCase(request.getTimeRangeUnit(), "year")) {
dateCountType = Calendar.YEAR;
}
if (dateCountType != 0 && request.getTimeRange() != 0) {
long startTime = DateUtils.dateSum(new Date(), (0 - request.getTimeRange()), dateCountType).getTime();
request.setStartTime(startTime);
@ -246,7 +247,7 @@ public class TestCaseCountService {
}
if (yAxisSelectTestCase) {
if (yAxisSelectTestCase && DiscoveryUtil.hasService(MicroServiceName.TEST_TRACK)) {
functionCaseCountResult = testCaseRemoteService.countTestCaseByRequest(request);
if (functionCaseCountResult.isEmpty() && StringUtils.equalsIgnoreCase(request.getXaxis(), "casetype")) {
TestCaseCountChartResult result = new TestCaseCountChartResult();
@ -255,7 +256,7 @@ public class TestCaseCountService {
functionCaseCountResult.add(result);
}
}
if (yAxisSelectApi) {
if (yAxisSelectApi && DiscoveryUtil.hasService(MicroServiceName.API_TEST)) {
Map<String, List<String>> apiCaseFilterList = new HashMap<>();
if (MapUtils.isNotEmpty(request.getFilterSearchList())) {
for (Map.Entry<String, List<String>> entry : request.getFilterSearchList().entrySet()) {
@ -274,7 +275,7 @@ public class TestCaseCountService {
apiCaseCountResult.add(result);
}
}
if (yAxisSelectScenarioCase) {
if (yAxisSelectScenarioCase && DiscoveryUtil.hasService(MicroServiceName.API_TEST)) {
scenarioCaseCount = scenarioRemoteService.countTestCaseByRequest(request);
if (scenarioCaseCount.isEmpty() && StringUtils.equalsIgnoreCase(request.getXaxis(), "casetype")) {
TestCaseCountChartResult result = new TestCaseCountChartResult();
@ -283,7 +284,7 @@ public class TestCaseCountService {
scenarioCaseCount.add(result);
}
}
if (yAxisSelectLoad) {
if (yAxisSelectLoad && DiscoveryUtil.hasService(MicroServiceName.PERFORMANCE_TEST)) {
Map<String, List<String>> loadCaseFilterMap = new HashMap<>();
if (MapUtils.isNotEmpty(request.getFilterSearchList())) {
for (Map.Entry<String, List<String>> entry : request.getFilterSearchList().entrySet()) {

View File

@ -0,0 +1,30 @@
package io.metersphere.reportstatistics.utils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.dto.ServiceDTO;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class DiscoveryUtil {
public static boolean hasService(String serviceId) {
return getServiceIdSet().contains(serviceId);
}
public static Set<String> getServiceIdSet() {
DiscoveryClient discoveryClient = CommonBeanFactory.getBean(DiscoveryClient.class);
return discoveryClient.getServices()
.stream()
.collect(Collectors.toSet());
}
public static List<ServiceDTO> getServices() {
DiscoveryClient discoveryClient = CommonBeanFactory.getBean(DiscoveryClient.class);
return discoveryClient.getServices().stream()
.map(service -> new ServiceDTO(service, discoveryClient.getInstances(service).get(0).getPort()))
.collect(Collectors.toList());
}
}

View File

@ -1,35 +1,55 @@
<template>
<div class="ms-header">
<el-row>
<div class="ms-div">{{ title }}
<div class="ms-div">
{{ title }}
<span v-if="historyReportName" class="history-report-name">
{{ historyReportName }}
</span>
</div>
<div class="ms-header-right">
<el-button type="primary" v-if="isSaveAsButtonShow" size="mini" @click="handleSaveAs" :disabled="readOnly">
{{ $t('commons.save_as') }}<i class="el-icon-files el-icon--right"></i></el-button>
<el-button type="primary" v-if="isSaveButtonShow" size="mini" @click="handleSave" :disabled="readOnly">
{{ $t('commons.save') }}<i class="el-icon-files el-icon--right"></i></el-button>
<el-button type="" size="mini" @click="handleExport" :disabled="readOnly">{{ $t('report.export') }}<i
class="el-icon-download el-icon--right"></i></el-button>
<el-button
type="primary"
v-if="isSaveAsButtonShow"
size="mini"
@click="handleSaveAs"
:disabled="readOnly"
>
{{ $t("commons.save_as") }}<i class="el-icon-files el-icon--right"></i
></el-button>
<el-button
type="primary"
v-if="isSaveButtonShow"
size="mini"
@click="handleSave"
:disabled="readOnly"
>
{{ $t("commons.save") }}<i class="el-icon-files el-icon--right"></i
></el-button>
<el-button
type=""
size="mini"
@click="handleExport"
:disabled="readOnly"
>{{ $t("report.export")
}}<i class="el-icon-download el-icon--right"></i
></el-button>
<span class="ms-span">|</span>
<i class="el-icon-close report-alt-ico" @click="close"/>
<i class="el-icon-close report-alt-ico" @click="close" />
</div>
</el-row>
</div>
</template>
<script>
import {exportPdf,} from "metersphere-frontend/src/utils";
import {hasPermission} from "metersphere-frontend/src/utils/permission";
import html2canvas from 'html2canvas';
import { hasPermission } from "metersphere-frontend/src/utils/permission";
import html2canvas from "html2canvas";
export default {
name: "ReportHeader",
components: {},
data() {
return {}
return {};
},
props: {
title: String,
@ -37,20 +57,22 @@ export default {
historyReportName: String,
},
watch: {
historyReportName() {
}
},
created() {
historyReportName() {},
},
created() {},
computed: {
readOnly() {
return !hasPermission('PROJECT_REPORT_ANALYSIS:READ+EXPORT');
return !hasPermission("PROJECT_REPORT_ANALYSIS:READ+EXPORT");
},
isSaveAsButtonShow() {
if (!this.historyReportId || this.historyReportId === null || this.historyReportId === '') {
if (
!this.historyReportId ||
this.historyReportId === null ||
this.historyReportId === ""
) {
return false;
} else {
if (hasPermission('PROJECT_REPORT_ANALYSIS:READ+CREATE')) {
if (hasPermission("PROJECT_REPORT_ANALYSIS:READ+CREATE")) {
return true;
} else {
return false;
@ -58,28 +80,23 @@ export default {
}
},
isSaveButtonShow() {
if (hasPermission('PROJECT_REPORT_ANALYSIS:READ+UPDATE')) {
if (hasPermission("PROJECT_REPORT_ANALYSIS:READ+UPDATE")) {
return true;
} else {
return false;
}
}
},
},
methods: {
handleExport() {
let name = this.title;
this.$nextTick(function () {
setTimeout(() => {
html2canvas(document.getElementById('reportAnalysis'), {
scale: 2
}).then(function (canvas) {
exportPdf(name, [canvas]);
});
}, 1000);
});
this.$emit("exportReport", this.title);
},
handleSave() {
if (!this.historyReportId || this.historyReportId === null || this.historyReportId === '') {
if (
!this.historyReportId ||
this.historyReportId === null ||
this.historyReportId === ""
) {
this.$emit("selectAndSaveReport");
} else {
this.$emit("updateReport");
@ -89,16 +106,16 @@ export default {
this.$emit("selectAndSaveReport");
},
close() {
this.$emit('closePage');
this.$emit("closePage");
},
},
}
};
</script>
<style scoped>
.ms-header {
border-bottom: 1px solid #E6E6E6;
background-color: #FFF;
border-bottom: 1px solid #e6e6e6;
background-color: #fff;
}
.ms-div {

View File

@ -2,56 +2,101 @@
<div>
<el-row type="flex">
<p class="tip">
<span class="ms-span">{{ $t('commons.report_statistics.name') }}</span>
<el-select v-model="reportType" class="ms-col-type" size="mini" style="width: 120px">
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in reportTypes"/>
<span class="ms-span">{{ $t("commons.report_statistics.name") }}</span>
<el-select
v-model="reportType"
class="ms-col-type"
size="mini"
style="width: 120px"
>
<el-option
:key="t.id"
:value="t.id"
:label="t.name"
v-for="t in reportTypes"
/>
</el-select>
</p>
</el-row>
<transition>
<keep-alive>
<report-card @openCard="openCard"/>
<report-card @openCard="openCard" />
</keep-alive>
</transition>
<!-- 测试用例趋势页面 -->
<ms-drawer :visible="testCaseTrendDrawer" :size="100" @close="close" direction="right" :show-full-screen="false"
:is-show-close="false" style="overflow: hidden">
<ms-drawer
:visible="testCaseTrendDrawer"
:size="100"
@close="close"
direction="right"
:show-full-screen="false"
:is-show-close="false"
style="overflow: hidden"
>
<template v-slot:header>
<report-header :title="$t('commons.report_statistics.test_case_analysis')" :history-report-id="historyReportId"
:history-report-name="historyReportName"
@closePage="close" @updateReport="updateReport"
@selectAndSaveReport="openSaveReportDialog('saveAs')"/>
<report-header
:title="$t('commons.report_statistics.test_case_analysis')"
:history-report-id="historyReportId"
:history-report-name="historyReportName"
@closePage="close"
@updateReport="updateReport"
@exportReport="exportReport"
@selectAndSaveReport="openSaveReportDialog('saveAs')"
/>
</template>
<test-analysis-container @initHistoryReportId="initHistoryReportId" ref="testAnalysisContainer"/>
<test-analysis-container
@initHistoryReportId="initHistoryReportId"
ref="testAnalysisContainer"
/>
</ms-drawer>
<!-- 测试用例分析页面 -->
<ms-drawer :visible="testCaseCountDrawer" :size="100" @close="close" direction="right" :show-full-screen="false"
:is-show-close="false" style="overflow: hidden">
<ms-drawer
:visible="testCaseCountDrawer"
:size="100"
@close="close"
direction="right"
:show-full-screen="false"
:is-show-close="false"
style="overflow: hidden"
>
<template v-slot:header>
<report-header :title="$t('commons.report_statistics.test_case_count')" :history-report-id="historyReportId"
@closePage="close"
:history-report-name="historyReportName"
@updateReport="updateReport"
@selectAndSaveReport="openSaveReportDialog('saveAs')"/>
<report-header
:title="$t('commons.report_statistics.test_case_count')"
:history-report-id="historyReportId"
@closePage="close"
:history-report-name="historyReportName"
@updateReport="updateReport"
@exportReport="exportReport"
@selectAndSaveReport="openSaveReportDialog('saveAs')"
/>
</template>
<test-case-count-container @initHistoryReportId="initHistoryReportId" ref="testCaseCountContainer"/>
<test-case-count-container
@initHistoryReportId="initHistoryReportId"
ref="testCaseCountContainer"
/>
</ms-drawer>
<el-dialog
:title="$t('commons.save')"
:visible.sync="dialogFormVisible"
width="30%"
:before-close="handleCloseSaveReportDialog">
:before-close="handleCloseSaveReportDialog"
>
<el-form :model="form" :rules="saveReportRules" ref="saveReportRuleForm">
<el-form-item :label="$t('commons.input_name')" prop="reportName" label-width="120px">
<el-form-item
:label="$t('commons.input_name')"
prop="reportName"
label-width="120px"
>
<el-input v-model="form.reportName" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="saveReport">{{ $t('commons.confirm') }}</el-button>
<el-button type="primary" @click="saveReport">{{
$t("commons.confirm")
}}</el-button>
</div>
</el-dialog>
</div>
@ -63,11 +108,17 @@ import TestAnalysisContainer from "@/business/projectstatistics/track/TestAnalys
import MsDrawer from "metersphere-frontend/src/components/MsDrawer";
import ReportHeader from "@/business/base/ReportHeader";
import TestCaseCountContainer from "@/business/projectstatistics/casecount/TestCaseCountContainer";
import html2canvas from "html2canvas";
export default {
name: "ReportAnalysis",
components: {ReportCard, TestAnalysisContainer, MsDrawer, ReportHeader, TestCaseCountContainer},
components: {
ReportCard,
TestAnalysisContainer,
MsDrawer,
ReportHeader,
TestCaseCountContainer,
},
data() {
return {
reportType: "track",
@ -75,7 +126,7 @@ export default {
testCaseCountDrawer: false,
historyReportId: "",
historyReportName: "",
reportTypes: [{id: 'track', name: this.$t('test_track.test_track')}],
reportTypes: [{ id: "track", name: this.$t("test_track.test_track") }],
dialogFormVisible: false,
form: {
reportName: "",
@ -83,19 +134,30 @@ export default {
},
saveReportRules: {
reportName: [
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
{min: 1, max: 20, message: '长度不大于20个字符', trigger: 'blur'}
{
required: true,
message: this.$t("commons.input_name"),
trigger: "blur",
},
{ min: 1, max: 20, message: "长度不大于20个字符", trigger: "blur" },
],
}
}
},
};
},
methods: {
exportReport(title) {
if (this.testCaseCountDrawer && this.$refs.testCaseCountContainer) {
this.$refs.testCaseCountContainer.handleExport();
} else if (this.testCaseTrendDrawer) {
this.$refs.testAnalysisContainer.handleExport();
}
},
openCard(type) {
this.historyReportName = "";
this.historyReportId = "";
if (type === 'trackTestCase') {
if (type === "trackTestCase") {
this.testCaseTrendDrawer = true;
} else if (type === 'countTestCase') {
} else if (type === "countTestCase") {
this.testCaseCountDrawer = true;
}
},
@ -119,12 +181,18 @@ export default {
}
},
saveReport() {
this.$refs['saveReportRuleForm'].validate((valid) => {
this.$refs["saveReportRuleForm"].validate((valid) => {
if (valid) {
if (this.testCaseTrendDrawer) {
this.$refs.testAnalysisContainer.saveAndSaveAsReport(this.form.reportName, this.form.saveType);
this.$refs.testAnalysisContainer.saveAndSaveAsReport(
this.form.reportName,
this.form.saveType
);
} else if (this.testCaseCountDrawer) {
this.$refs.testCaseCountContainer.saveAndSaveAsReport(this.form.reportName, this.form.saveType);
this.$refs.testCaseCountContainer.saveAndSaveAsReport(
this.form.reportName,
this.form.saveType
);
}
this.form.reportName = "";
this.form.saveType = "";
@ -142,14 +210,14 @@ export default {
this.form.reportName = "";
this.form.saveType = "";
this.dialogFormVisible = false;
}
},
},
}
};
</script>
<style scoped>
.ms-span {
margin: 10px 10px 0px
margin: 10px 10px 0px;
}
.tip {

View File

@ -1,24 +1,53 @@
<template>
<div>
<el-container v-loading="loading" :style="{ 'max-height': (h-50) + 'px', 'overflow': 'auto'}">
<el-aside v-if="!isHide" :width="!isHide ?'235px':'0px'" :style="{ 'margin-left': '5px'}">
<history-report-data report-type="TEST_CASE_COUNT"
@selectReport="selectReport" @removeHistoryReportId="removeHistoryReportId"
ref="historyReport"/>
<el-container
v-loading="loading"
:style="{ 'max-height': h - 50 + 'px', overflow: 'auto' }"
>
<el-aside
v-if="!isHide"
:width="!isHide ? '235px' : '0px'"
:style="{ 'margin-left': '5px' }"
>
<history-report-data
report-type="TEST_CASE_COUNT"
@selectReport="selectReport"
@removeHistoryReportId="removeHistoryReportId"
ref="historyReport"
/>
</el-aside>
<el-main class="ms-main" id="reportAnalysis" style="padding: 0px 5px 0px">
<div>
<test-case-count-chart @hidePage="hidePage" @orderCharts="orderCharts"
ref="analysisChart" @updateChartType="updateChartType"
:chart-width="chartWidth" :load-option="loadOption" :pie-option="pieOption"/>
</div>
<div class="ms-row" v-if="!isHide">
<test-case-count-table :group-name="getGroupNameStr(options.xaxis)" :show-columns="options.yaxis"
:tableData="tableData"/>
<div id="testCaseCountPicDiv">
<div>
<test-case-count-chart
@hidePage="hidePage"
@orderCharts="orderCharts"
ref="analysisChart"
@updateChartType="updateChartType"
:chart-width="chartWidth"
:load-option="loadOption"
:pie-option="pieOption"
/>
</div>
<div class="ms-row">
<test-case-count-table
:group-name="getGroupNameStr(options.xaxis)"
:show-columns="options.yaxis"
ref="caseCountTable"
:tableData="tableData"
/>
</div>
</div>
</el-main>
<el-aside v-if="!isHide" style="height: 100%" :width="!isHide ?'485px':'0px'">
<test-case-count-filter @filterCharts="filterCharts" ref="countFilter"/>
<el-aside
v-if="!isHide"
style="height: 100%"
:width="!isHide ? '485px' : '0px'"
>
<test-case-count-filter
@filterCharts="filterCharts"
ref="countFilter"
/>
</el-aside>
</el-container>
</div>
@ -28,16 +57,24 @@
import TestCaseCountChart from "./chart/TestCaseCountChart";
import TestCaseCountTable from "@/business/projectstatistics/casecount/table/TestCaseCountTable";
import TestCaseCountFilter from "./filter/TestCaseCountFilter";
import {exportPdf} from "metersphere-frontend/src/utils";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import html2canvas from 'html2canvas';
import {getCountReport} from "@/api/report";
import { getCurrentProjectID } from "metersphere-frontend/src/utils/token";
import { downloadPDF } from "metersphere-frontend/src/utils";
import { getCountReport } from "@/api/report";
import HistoryReportData from "../../base/HistoryReportData";
import {createHistoryReport, selectHistoryReportById, updateHistoryReport} from "@/api/history-report";
import {
createHistoryReport,
selectHistoryReportById,
updateHistoryReport,
} from "@/api/history-report";
export default {
name: "TestCaseCountContainer",
components: {TestCaseCountChart, TestCaseCountTable, TestCaseCountFilter, HistoryReportData},
components: {
TestCaseCountChart,
TestCaseCountTable,
TestCaseCountFilter,
HistoryReportData,
},
data() {
return {
isHide: false,
@ -52,7 +89,7 @@ export default {
yAxis: {},
label: {},
tooltip: {},
series: []
series: [],
},
pieOption: {
legend: {},
@ -71,26 +108,29 @@ export default {
this.chartType = value;
},
handleExport() {
let name = this.$t('commons.report_statistics.test_case_analysis');
this.hidePage(true);
let name = this.$t("commons.report_statistics.test_case_count");
this.$nextTick(function () {
setTimeout(() => {
html2canvas(document.getElementById('reportAnalysis'), {
scale: 2
}).then(function (canvas) {
exportPdf(name, [canvas]);
});
downloadPDF(
document.getElementById("testCaseCountPicDiv"),
name || "MeterSphere-report"
);
}, 1000);
});
},
hidePage(isHide) {
this.isHide = isHide;
this.$refs.analysisChart.reCountWidth(isHide);
this.$refs.caseCountTable.reCountWidth(isHide);
},
close() {
this.$emit('closePage');
this.$emit("closePage");
},
init(opt) {
this.options = opt;
this.loading = getCountReport(opt).then(response => {
this.loading = getCountReport(opt).then((response) => {
let data = response.data.barChartDTO;
let pieData = response.data.pieChartDTO;
let selectTableData = response.data.tableDTOs;
@ -101,19 +141,18 @@ export default {
if (!formatData) {
return;
}
if (typeof (formatData.legend) === 'string') {
if (typeof formatData.legend === "string") {
formatData.legend = JSON.parse(formatData.legend);
}
if (typeof (formatData.xaxis) === 'string') {
if (typeof formatData.xaxis === "string") {
formatData.xaxis = JSON.parse(formatData.xaxis);
}
if (typeof (formatData.series) === 'string') {
if (typeof formatData.series === "string") {
formatData.series = JSON.parse(formatData.series);
}
if (typeof (formatData.title) === 'string') {
if (typeof formatData.title === "string") {
formatData.title = JSON.parse(formatData.title);
}
},
initPic(barData, pieData, selectTableData) {
this.loading = true;
@ -126,9 +165,9 @@ export default {
this.loadOption.xaxis = barData.xaxis;
this.loadOption.series = barData.series;
this.loadOption.grid = {
bottom: '75px',//
bottom: "75px", //
};
this.loadOption.series.forEach(item => {
this.loadOption.series.forEach((item) => {
if (this.$refs.analysisChart) {
item.type = this.$refs.analysisChart.chartType;
}
@ -141,14 +180,14 @@ export default {
this.pieOption.series = pieData.series;
this.pieOption.title = pieData.title;
this.pieOption.grid = {
bottom: '75px',//
bottom: "75px", //
};
if (pieData.width) {
this.pieOption.width = pieData.width;
this.chartWidth = pieData.width;
}
if (this.pieOption.series) {
this.pieOption.series.forEach(item => {
this.pieOption.series.forEach((item) => {
if (this.$refs.analysisChart) {
item.type = this.$refs.analysisChart.chartType;
}
@ -158,7 +197,10 @@ export default {
if (selectTableData) {
this.tableData = selectTableData;
}
this.$refs.analysisChart.setPieOptionAndBarOption(this.loadOption, this.pieOption);
this.$refs.analysisChart.setPieOptionAndBarOption(
this.loadOption,
this.pieOption
);
this.loading = false;
this.$refs.analysisChart.generateOption(this.chartType);
},
@ -181,9 +223,9 @@ export default {
chartType: this.chartType,
};
obj.dataOption = JSON.stringify(dataOptionObj);
obj.reportType = 'TEST_CASE_COUNT';
obj.reportType = "TEST_CASE_COUNT";
updateHistoryReport(obj).then(() => {
this.$alert(this.$t('commons.save_success'));
this.$alert(this.$t("commons.save_success"));
this.$refs.historyReport.initReportData();
});
},
@ -199,9 +241,9 @@ export default {
chartType: this.chartType,
};
obj.dataOption = JSON.stringify(dataOptionObj);
obj.reportType = 'TEST_CASE_COUNT';
obj.reportType = "TEST_CASE_COUNT";
createHistoryReport(obj).then(() => {
this.$alert(this.$t('commons.save_success'));
this.$alert(this.$t("commons.save_success"));
this.$refs.historyReport.initReportData();
});
},
@ -210,54 +252,71 @@ export default {
if (selectId) {
this.loading = true;
let paramObj = {
id: selectId
}
selectHistoryReportById(paramObj).then((response) => {
let reportData = response.data;
if (reportData) {
selectName = reportData.name;
if (reportData.dataOption) {
let dataOptionObj = JSON.parse(reportData.dataOption);
if (dataOptionObj.chartType) {
if (dataOptionObj.chartType === "\"bar\"") {
this.chartType = "bar";
} else if (dataOptionObj.chartType === "\"pie\"") {
this.chartType = "pie";
id: selectId,
};
selectHistoryReportById(paramObj).then(
(response) => {
let reportData = response.data;
if (reportData) {
selectName = reportData.name;
if (reportData.dataOption) {
let dataOptionObj = JSON.parse(reportData.dataOption);
if (dataOptionObj.chartType) {
if (dataOptionObj.chartType === '"bar"') {
this.chartType = "bar";
} else if (dataOptionObj.chartType === '"pie"') {
this.chartType = "pie";
} else {
this.chartType = dataOptionObj.chartType;
}
} else {
this.chartType = dataOptionObj.chartType;
this.chartType = "bar";
}
} else {
this.chartType = "bar";
this.initPic(
dataOptionObj.loadOption,
dataOptionObj.pieOption,
dataOptionObj.tableData
);
}
this.initPic(dataOptionObj.loadOption, dataOptionObj.pieOption, dataOptionObj.tableData);
}
if (reportData.selectOption) {
let selectOptionObj = JSON.parse(reportData.selectOption);
this.$refs.countFilter.initSelectOption(selectOptionObj);
if (reportData.selectOption) {
let selectOptionObj = JSON.parse(reportData.selectOption);
this.$refs.countFilter.initSelectOption(selectOptionObj);
}
this.loading = false;
}
this.$emit("initHistoryReportId", selectId, selectName);
},
(error) => {
this.loading = false;
this.removeHistoryReportId();
}
this.$emit('initHistoryReportId', selectId, selectName);
}, (error) => {
this.loading = false;
this.removeHistoryReportId();
});
);
}
},
removeHistoryReportId() {
this.$emit('initHistoryReportId', "", "");
this.$emit("initHistoryReportId", "", "");
},
getGroupNameStr(groupName) {
if (groupName === 'creator') {
return this.$t('commons.report_statistics.report_filter.select_options.creator');
} else if (groupName === 'maintainer') {
return this.$t('commons.report_statistics.report_filter.select_options.maintainer');
} else if (groupName === 'casetype') {
return this.$t('commons.report_statistics.report_filter.select_options.case_type');
} else if (groupName === 'casestatus') {
return this.$t('commons.report_statistics.report_filter.select_options.case_status');
} else if (groupName === 'caselevel') {
return this.$t('commons.report_statistics.report_filter.select_options.case_level');
if (groupName === "creator") {
return this.$t(
"commons.report_statistics.report_filter.select_options.creator"
);
} else if (groupName === "maintainer") {
return this.$t(
"commons.report_statistics.report_filter.select_options.maintainer"
);
} else if (groupName === "casetype") {
return this.$t(
"commons.report_statistics.report_filter.select_options.case_type"
);
} else if (groupName === "casestatus") {
return this.$t(
"commons.report_statistics.report_filter.select_options.case_status"
);
} else if (groupName === "caselevel") {
return this.$t(
"commons.report_statistics.report_filter.select_options.case_level"
);
} else {
return "";
}
@ -269,7 +328,7 @@ export default {
yAxis: {},
label: {},
tooltip: {},
series: []
series: [],
};
this.pieOption = {
legend: {},
@ -286,12 +345,12 @@ export default {
this.saveReport(reportName);
},
saveAndSaveAsReport(reportName, saveType) {
if (saveType === 'save') {
if (saveType === "save") {
this.saveReport(reportName);
} else if (saveType === 'saveAs') {
} else if (saveType === "saveAs") {
this.selectAndSaveReport(reportName);
}
}
},
},
};
</script>
@ -301,7 +360,7 @@ export default {
padding-top: 5px;
}
:deep(.el-main ) {
:deep(.el-main) {
padding: 0px 20px 0px;
}
</style>

View File

@ -1,12 +1,20 @@
<template>
<div v-loading="loading">
<el-card class="ms-test-chart" :style="{ width: w+'px', height: h + 'px'}" ref="msDrawer">
<el-card
class="ms-test-chart"
:style="{ width: w + 'px', height: h + 'px' }"
ref="msDrawer"
>
<el-row class="ms-row">
<p class="tip"><span style="margin-left: 5px"></span> {{ $t('commons.report_statistics.chart') }} </p>
<p class="tip">
<span style="margin-left: 5px"></span>
{{ $t("commons.report_statistics.chart") }}
</p>
<div class="ms-test-chart-header" v-if="!readOnly">
<el-dropdown @command="exportCommand" :hide-on-click="false">
<span class="el-dropdown-link">
{{ $t('commons.export') }}<i class="el-icon-arrow-down el-icon--right"></i>
{{ $t("commons.export")
}}<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="jpg">JPG</el-dropdown-item>
@ -14,26 +22,63 @@
</el-dropdown-menu>
</el-dropdown>
<span style="margin: 0px 10px 10px">|</span>
<el-select v-model="chartType" class="ms-col-type" size="mini" style="width: 100px" @change="generateOption">
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in charts"/>
<el-select
v-model="chartType"
class="ms-col-type"
size="mini"
style="width: 100px"
@change="generateOption"
>
<el-option
:key="t.id"
:value="t.id"
:label="t.name"
v-for="t in charts"
/>
</el-select>
<span style="margin: 0px 10px 10px">|</span>
<el-select v-model="order" class="ms-col-type" size="mini" style="width: 120px" @change="orderCharts">
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in orders"/>
<el-select
v-model="order"
class="ms-col-type"
size="mini"
style="width: 120px"
@change="orderCharts"
>
<el-option
:key="t.id"
:value="t.id"
:label="t.name"
v-for="t in orders"
/>
</el-select>
<span style="margin: 0px 10px 10px">|</span>
<font-awesome-icon v-if="!isFullScreen && showFullScreen" class="report-alt-ico" :icon="['fa', 'expand-alt']"
size="lg" @click="fullScreen"/>
<font-awesome-icon v-if="isFullScreen && showFullScreen" class="report-alt-ico" :icon="['fa', 'compress-alt']"
size="lg" @click="unFullScreen"/>
<font-awesome-icon
v-if="!isFullScreen && showFullScreen"
class="report-alt-ico"
:icon="['fa', 'expand-alt']"
size="lg"
@click="fullScreen"
/>
<font-awesome-icon
v-if="isFullScreen && showFullScreen"
class="report-alt-ico"
:icon="['fa', 'compress-alt']"
size="lg"
@click="unFullScreen"
/>
</div>
</el-row>
<el-row>
<div class="chart-style">
<ms-chart ref="chart1" v-if="!loading" :options="dataOption"
:style="{width: chartWidthNumber+'px', height: (h-70) + 'px'}" class="chart-config"
:autoresize="true"
id="picChart"/>
<ms-chart
ref="chart1"
v-if="!loading"
:options="dataOption"
:style="{ width: chartWidthNumber + 'px', height: h - 70 + 'px' }"
class="chart-config"
:autoresize="true"
id="picChart"
/>
</div>
</el-row>
</el-card>
@ -42,10 +87,11 @@
<script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
import html2canvas from "html2canvas";
export default {
name: "TestCaseCountChart",
components: {MsChart},
components: { MsChart },
props: {
chartWidth: Number,
needFullScreen: Boolean,
@ -68,24 +114,28 @@ export default {
type: Boolean,
default() {
return true;
}
},
},
charts: [
{id: 'bar', name: this.$t('commons.report_statistics.bar')},
{id: 'pie', name: this.$t('commons.report_statistics.pie')}
{ id: "bar", name: this.$t("commons.report_statistics.bar") },
{ id: "pie", name: this.$t("commons.report_statistics.pie") },
],
order: "",
orders: [{id: '', name: this.$t('commons.sort_default')}, {
id: 'desc',
name: this.$t('commons.report_statistics.desc')
}, {
id: 'asc',
name: this.$t('commons.report_statistics.asc')
}],
orders: [
{ id: "", name: this.$t("commons.sort_default") },
{
id: "desc",
name: this.$t("commons.report_statistics.desc"),
},
{
id: "asc",
name: this.$t("commons.report_statistics.asc"),
},
],
loading: false,
options: {},
chartType: "bar",
}
};
},
created() {
this.dataOption = this.loadOption;
@ -104,32 +154,109 @@ export default {
},
},
methods: {
reCountWidth(isHideOther) {
if (isHideOther) {
this.w = document.documentElement.clientWidth - 50;
} else {
this.w = document.documentElement.clientWidth - 760;
}
this.generateOption(this.chartType);
this.countChartWidth();
this.reload();
},
countChartWidth() {
if (this.chartWidth === 0 || this.chartType === 'bar') {
if (this.chartWidth === 0 || this.chartType === "bar") {
this.chartWidthNumber = this.w;
} else if (
this.chartType === "pie" &&
this.dataOption.width &&
this.dataOption.width > 0
) {
this.chartWidthNumber = this.dataOption.width;
} else {
this.chartWidthNumber = this.chartWidth;
}
},
orderCharts() {
this.$emit('orderCharts', this.order);
this.$emit("orderCharts", this.order);
},
generateOption(chartTypeParam) {
if (chartTypeParam) {
this.chartType = chartTypeParam;
}
if (this.chartType === 'pie') {
this.dataOption = this.pieOption;
if (this.chartType === "pie") {
this.dataOption = this.formatPieOption(this.pieOption);
} else {
this.dataOption = this.loadOption;
}
if (this.dataOption.series) {
this.dataOption.series.forEach(item => {
item.type = this.chartType;
this.dataOption.series.forEach((item) => {
item.type = chartTypeParam;
});
}
this.reload();
},
formatPieOption(reformatPieOption) {
let finalPieOption = reformatPieOption;
/**
* 根据现有的 width动态计算饼图各个模块的位置
* 假设饼图共n个 一行为c一共r行
* r 200 + 350 * c <= width 的最大值
* 高度为 n/r 进一法取整数 height = 200*n
* 第一行
* 第一个饼图位置(center属性)"center": ["200", "150"],title位置"left": "200","top": "200",
* 第二个饼图位置(center属性)"center": ["550", "150"],title位置"left": "550","top": "200",
* 第二行
* 第一个饼图位置(center属性)"center": ["200", "350"],title位置"left": "200","top": "400",
* 第二个饼图位置(center属性)"center": ["550", "350"],title位置"left": "550","top": "400",
*/
this.h = document.documentElement.clientHeight * 0.5;
// "series" "title"
if (
finalPieOption.series &&
finalPieOption.title &&
finalPieOption.series.length > 0 &&
finalPieOption.series.length === finalPieOption.title.length
) {
let cNum = 0;
let rNum = 0;
let countWidth = this.w;
let countHeight = 0;
let allPieCount = finalPieOption.series.length;
if (countWidth >= 550) {
countWidth = countWidth - 200;
do {
cNum++;
countWidth = countWidth - 350;
} while (countWidth > 350);
if (cNum > 0) {
rNum = Math.ceil(allPieCount / cNum);
countHeight = 200 * rNum + 100;
if (countHeight > this.h) {
this.h = countHeight;
}
let pieRowIndex = 1; //
for (let pieIndex = 0; pieIndex < allPieCount; pieIndex++) {
if (pieIndex >= cNum * pieRowIndex) {
pieRowIndex++;
}
let pieInRow = pieIndex;
if (pieIndex >= cNum) {
pieInRow = pieIndex % cNum;
}
finalPieOption.series[pieIndex].center = [
200 + 350 * pieInRow,
200 * pieRowIndex - 60,
];
finalPieOption.title[pieIndex].left = 200 + 350 * pieInRow;
finalPieOption.title[pieIndex].top = 200 * pieRowIndex;
}
finalPieOption.width = this.w;
}
}
}
return finalPieOption;
},
setPieOptionAndBarOption(barOption, pieOption) {
if (barOption) {
this.loadOption = barOption;
@ -139,33 +266,32 @@ export default {
}
},
reload() {
this.loading = true
this.loading = true;
this.$nextTick(() => {
this.loading = false;
})
});
},
fullScreen() {
this.originalW = this.w;
this.originalH = this.h;
this.w = document.body.clientWidth - 50;
this.h = document.body.clientHeight;
this.isFullScreen = true;
this.$emit('hidePage', true);
this.$emit("hidePage", true);
},
unFullScreen() {
this.w = this.originalW;
this.h = this.originalH;
this.isFullScreen = false;
this.$emit('hidePage', false);
this.$emit("hidePage", false);
},
getImages(command) {
let imageType = 'image/png';
if (command === 'jpg') {
imageType = 'image/jpg';
let imageType = "image/png";
if (command === "jpg") {
imageType = "image/jpg";
}
let returnImageData = "";
if (document.getElementById('picChart')) {
let chartsCanvas = document.getElementById('picChart').querySelectorAll('canvas')[0];
if (document.getElementById("picChart")) {
let chartsCanvas = document
.getElementById("picChart")
.querySelectorAll("canvas")[0];
if (chartsCanvas) {
// toDataURL()canvascanvasbase64
returnImageData = chartsCanvas && chartsCanvas.toDataURL(imageType);
@ -175,46 +301,50 @@ export default {
return returnImageData;
},
exportCommand(command) {
let fileName = 'report_pic.' + command;
if (document.getElementById('picChart')) {
let chartsCanvas = document.getElementById('picChart').querySelectorAll('canvas')[0]
let mime = 'image/png';
if (command === 'jpg') {
mime = 'image/jpg';
let fileName = "report_pic." + command;
if (document.getElementById("picChart")) {
let chartsCanvas = document
.getElementById("picChart")
.querySelectorAll("canvas")[0];
let mime = "image/png";
if (command === "jpg") {
mime = "image/jpg";
}
if (chartsCanvas) {
// toDataURL()canvascanvasbase64
let imageUrl = chartsCanvas && chartsCanvas.toDataURL(mime)
if (navigator.userAgent.indexOf('Trident') > -1) {
let imageUrl = chartsCanvas && chartsCanvas.toDataURL(mime);
if (navigator.userAgent.indexOf("Trident") > -1) {
// IE11
let arr = imageUrl.split(',')
let arr = imageUrl.split(",");
// atob() 使base64
let bstr = atob(arr[1])
let bstrLen = bstr.length
let bstr = atob(arr[1]);
let bstrLen = bstr.length;
// Uint8Array, 8 0
let u8arr = new Uint8Array(bstrLen)
let u8arr = new Uint8Array(bstrLen);
while (bstrLen--) {
// charCodeAt() Unicode
u8arr[bstrLen] = bstr.charCodeAt(bstrLen)
u8arr[bstrLen] = bstr.charCodeAt(bstrLen);
}
// msSaveOrOpenBlob Internet
window.navigator.msSaveOrOpenBlob(new Blob([u8arr], {type: mime}), fileName);
window.navigator.msSaveOrOpenBlob(
new Blob([u8arr], { type: mime }),
fileName
);
} else {
//
let $a = document.createElement('a')
$a.setAttribute('href', imageUrl)
$a.setAttribute('download', fileName)
$a.click()
let $a = document.createElement("a");
$a.setAttribute("href", imageUrl);
$a.setAttribute("download", fileName);
$a.click();
}
}
}
},
},
}
};
</script>
<style scoped>
.ms-test-chart-header {
z-index: 999;
width: 380px;
@ -234,7 +364,7 @@ export default {
font-size: 18px;
}
:deep(.echarts ) {
:deep(.echarts) {
height: calc(100vh / 1.95);
}
@ -258,8 +388,7 @@ export default {
width: 100%;
}
:deep(.el-card__body ) {
:deep(.el-card__body) {
padding: 0px;
}
</style>

View File

@ -1,46 +1,63 @@
<template>
<div v-loading="loading" class="ms-div">
<el-card :style="{ width: w+'px'}">
<el-card :style="{ width: w + 'px' }">
<el-row style="padding-top: 10px">
<p class="tip"><span style="margin-left: 5px"></span>{{ $t('commons.report_statistics.excel') }} </p>
<p class="tip">
<span style="margin-left: 5px"></span
>{{ $t("commons.report_statistics.excel") }}
</p>
</el-row>
<el-row>
<el-table
:data="tableData"
:max-height="tableHeight"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
row-key="id"
border
class="ms-table">
<el-table-column
prop="name"
:label="groupName">
</el-table-column>
class="ms-table"
>
<el-table-column prop="name" :label="groupName"> </el-table-column>
<el-table-column
prop="allCount"
:label="$t('commons.report_statistics.count')">
:label="$t('commons.report_statistics.count')"
>
</el-table-column>
<el-table-column
prop="testCaseCount"
:label="$t('api_test.home_page.failed_case_list.table_value.case_type.functional')"
:label="
$t(
'api_test.home_page.failed_case_list.table_value.case_type.functional'
)
"
v-if="isShowColumn('testCase')"
>
</el-table-column>
<el-table-column
prop="apiCaseCount"
:label="$t('api_test.home_page.failed_case_list.table_value.case_type.api')"
:label="
$t(
'api_test.home_page.failed_case_list.table_value.case_type.api'
)
"
v-if="isShowColumn('apiCase')"
>
</el-table-column>
<el-table-column
prop="scenarioCaseCount"
:label="$t('api_test.home_page.failed_case_list.table_value.case_type.scene')"
:label="
$t(
'api_test.home_page.failed_case_list.table_value.case_type.scene'
)
"
v-if="isShowColumn('scenarioCase')"
>
</el-table-column>
<el-table-column
prop="loadCaseCount"
:label="$t('api_test.home_page.failed_case_list.table_value.case_type.load')"
:label="
$t(
'api_test.home_page.failed_case_list.table_value.case_type.load'
)
"
v-if="isShowColumn('loadCase')"
>
</el-table-column>
@ -62,15 +79,15 @@ export default {
type: Boolean,
default() {
return false;
}
}
},
},
},
data() {
return {
tableHeight: "100px",
w: document.documentElement.clientWidth - 760,
loading: false,
}
};
},
created() {
this.getTableHeight();
@ -79,25 +96,30 @@ export default {
}
},
methods: {
reCountWidth(isHideOther) {
if (isHideOther) {
this.w = document.documentElement.clientWidth - 50;
} else {
this.w = document.documentElement.clientWidth - 760;
}
},
isShowColumn(type) {
if (this.showColumns) {
return this.showColumns.findIndex(item => item === type) >= 0;
return this.showColumns.findIndex((item) => item === type) >= 0;
} else {
return false;
}
},
getTableHeight() {
let countNumber = document.documentElement.clientHeight * 0.4 / 1 - 140;
let countNumber = (document.documentElement.clientHeight * 0.4) / 1 - 140;
countNumber = Math.ceil(countNumber);
this.tableHeight = countNumber + 'px';
}
this.tableHeight = countNumber + "px";
},
},
}
};
</script>
<style scoped>
.tip {
float: left;
font-size: 14px;
@ -115,8 +137,7 @@ export default {
margin: 20px;
}
:deep( .el-card__body ) {
:deep(.el-card__body) {
padding: 0px;
}
</style>

View File

@ -1,23 +1,36 @@
<template>
<div :style="{ height: h + 'px'}">
<div :style="{ height: h + 'px' }">
<el-container v-loading="loading" style="overflow: scroll">
<el-container class="ms-row">
<el-aside :width="!isHide ?'235px':'0px'" style="margin-left: 5px; max-height: 843px">
<history-report-data report-type="TEST_CASE_ANALYSIS"
@selectReport="selectReport" @removeHistoryReportId="removeHistoryReportId"
ref="historyReport"/>
<el-aside
:width="!isHide ? '235px' : '0px'"
style="margin-left: 5px; max-height: 843px"
>
<history-report-data
report-type="TEST_CASE_ANALYSIS"
@selectReport="selectReport"
@removeHistoryReportId="removeHistoryReportId"
ref="historyReport"
/>
</el-aside>
<el-main class="ms-main" id="reportAnalysis">
<div>
<test-analysis-chart @hidePage="hidePage" @orderCharts="orderCharts" ref="analysisChart"
:load-option="loadOption"/>
<test-analysis-chart
@hidePage="hidePage"
@orderCharts="orderCharts"
ref="analysisChart"
:load-option="loadOption"
/>
</div>
<div class="ms-row" v-if="!isHide">
<test-analysis-table :tableData="tableData"/>
<test-analysis-table :tableData="tableData" />
</div>
</el-main>
<el-aside :width="!isHide ?'485px':'0px'">
<test-analysis-filter @filterCharts="filterCharts" ref="analysisFilter"/>
<el-aside :width="!isHide ? '485px' : '0px'">
<test-analysis-filter
@filterCharts="filterCharts"
ref="analysisFilter"
/>
</el-aside>
</el-container>
</el-container>
@ -28,16 +41,25 @@
import TestAnalysisChart from "./chart/TestAnalysisChart";
import TestAnalysisTable from "./table/TestAnalysisTable";
import TestAnalysisFilter from "./filter/TestAnalysisFilter";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {exportPdf} from "metersphere-frontend/src/utils";
import {getAnalysisReport} from "@/api/report";
import html2canvas from 'html2canvas';
import { getCurrentProjectID } from "metersphere-frontend/src/utils/token";
import { exportPdf } from "metersphere-frontend/src/utils";
import { getAnalysisReport } from "@/api/report";
import html2canvas from "html2canvas";
import HistoryReportData from "../../base/HistoryReportData";
import {createHistoryReport, selectHistoryReportById, updateHistoryReport} from "@/api/history-report";
import {
createHistoryReport,
selectHistoryReportById,
updateHistoryReport,
} from "@/api/history-report";
export default {
name: "TestAnalysisContainer",
components: {TestAnalysisChart, TestAnalysisTable, TestAnalysisFilter, HistoryReportData},
components: {
TestAnalysisChart,
TestAnalysisTable,
TestAnalysisFilter,
HistoryReportData,
},
data() {
return {
isHide: false,
@ -49,35 +71,41 @@ export default {
yAxis: {},
label: {},
tooltip: {},
series: []
series: [],
},
tableData: [],
h: document.documentElement.clientHeight - 40,
}
};
},
methods: {
handleExport() {
let name = this.$t('commons.report_statistics.test_case_analysis');
this.hidePage(true);
let name = this.$t("commons.report_statistics.test_case_analysis");
this.$nextTick(function () {
setTimeout(() => {
html2canvas(document.getElementById('reportAnalysis'), {
scale: 2
}).then(function (canvas) {
exportPdf(name, [canvas]);
});
html2canvas(document.getElementById("reportAnalysis"), {
scale: 2,
})
.then(function (canvas) {
exportPdf(name, [canvas]);
})
.then(() => {
this.hidePage(false);
});
}, 1000);
});
},
hidePage(isHide) {
this.isHide = isHide;
this.$refs.analysisChart.reCountWidth(isHide);
},
close() {
this.$emit('closePage');
this.$emit("closePage");
},
init(opt) {
this.loading = true;
this.options = opt;
getAnalysisReport(opt).then(response => {
getAnalysisReport(opt).then((response) => {
let data = response.data.chartDTO;
let tableDTOs = response.data.tableDTOs;
this.initPic(data, tableDTOs);
@ -102,9 +130,9 @@ export default {
tableData: this.tableData,
};
obj.dataOption = JSON.stringify(dataOptionObj);
obj.reportType = 'TEST_CASE_ANALYSIS';
obj.reportType = "TEST_CASE_ANALYSIS";
updateHistoryReport(obj).then(() => {
this.$alert(this.$t('commons.save_success'));
this.$alert(this.$t("commons.save_success"));
this.$refs.historyReport.initReportData();
});
},
@ -119,9 +147,9 @@ export default {
tableData: this.tableData,
};
obj.dataOption = JSON.stringify(dataOptionObj);
obj.reportType = 'TEST_CASE_ANALYSIS';
obj.reportType = "TEST_CASE_ANALYSIS";
createHistoryReport(obj).then(() => {
this.$alert(this.$t('commons.save_success'));
this.$alert(this.$t("commons.save_success"));
this.$refs.historyReport.initReportData();
});
},
@ -132,11 +160,11 @@ export default {
this.loadOption.xAxis = loadOptionParam.xaxis;
this.loadOption.series = loadOptionParam.series;
this.loadOption.grid = {
bottom: '75px',//
}
this.loadOption.series.forEach(item => {
bottom: "75px", //
};
this.loadOption.series.forEach((item) => {
item.type = this.$refs.analysisChart.chartType;
})
});
}
if (tableData) {
this.tableData = tableData;
@ -148,32 +176,37 @@ export default {
if (selectId) {
this.loading = true;
let paramObj = {
id: selectId
}
selectHistoryReportById(paramObj).then(response => {
let reportData = response.data;
if (reportData) {
selectName = reportData.name;
if (reportData.dataOption) {
let dataOptionObj = JSON.parse(reportData.dataOption);
this.initPic(dataOptionObj.loadOption, dataOptionObj.pieOption, dataOptionObj.tableData);
id: selectId,
};
selectHistoryReportById(paramObj)
.then((response) => {
let reportData = response.data;
if (reportData) {
selectName = reportData.name;
if (reportData.dataOption) {
let dataOptionObj = JSON.parse(reportData.dataOption);
this.initPic(
dataOptionObj.loadOption,
dataOptionObj.pieOption,
dataOptionObj.tableData
);
}
if (reportData.selectOption) {
let selectOptionObj = JSON.parse(reportData.selectOption);
this.$refs.analysisFilter.initSelectOption(selectOptionObj);
}
}
if (reportData.selectOption) {
let selectOptionObj = JSON.parse(reportData.selectOption);
this.$refs.analysisFilter.initSelectOption(selectOptionObj);
}
}
this.$emit('initHistoryReportId', selectId, selectName);
this.loading = false;
}).catch(() => {
this.loading = false;
this.removeHistoryReportId();
});
this.$emit("initHistoryReportId", selectId, selectName);
this.loading = false;
})
.catch(() => {
this.loading = false;
this.removeHistoryReportId();
});
}
},
removeHistoryReportId() {
this.$emit('initHistoryReportId', "", "");
this.$emit("initHistoryReportId", "", "");
},
selectAndSaveReport(reportName) {
let opt = this.$refs.analysisFilter.getOption();
@ -181,14 +214,14 @@ export default {
this.saveReport(reportName);
},
saveAndSaveAsReport(reportName, saveType) {
if (saveType === 'save') {
if (saveType === "save") {
this.saveReport(reportName);
} else if (saveType === 'saveAs') {
} else if (saveType === "saveAs") {
this.selectAndSaveReport(reportName);
}
}
},
},
}
};
</script>
<style scoped>
@ -196,7 +229,7 @@ export default {
padding-top: 10px;
}
:deep(.el-main ) {
:deep(.el-main) {
padding: 0px 20px 0px;
}
</style>

View File

@ -1,25 +1,69 @@
<template>
<div v-loading="loading">
<el-card class="ms-test-chart" :style="{ width: w+'px', height: h + 'px'}" ref="msDrawer">
<el-card
class="ms-test-chart"
:style="{ width: w + 'px', height: h + 'px' }"
ref="msDrawer"
>
<el-row class="ms-row">
<p class="tip"><span style="margin-left: 5px"></span> {{ $t('commons.report_statistics.chart') }} </p>
<p class="tip">
<span style="margin-left: 5px"></span>
{{ $t("commons.report_statistics.chart") }}
</p>
<div class="ms-test-chart-header">
<el-select v-model="chartType" class="ms-col-type" size="mini" style="width: 100px" @change="generateOption">
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in charts"/>
<el-select
v-model="chartType"
class="ms-col-type"
size="mini"
style="width: 100px"
@change="generateOption"
>
<el-option
:key="t.id"
:value="t.id"
:label="t.name"
v-for="t in charts"
/>
</el-select>
<span style="margin: 0px 10px 10px">|</span>
<el-select v-model="order" class="ms-col-type" size="mini" style="width: 120px" @change="orderCharts">
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in orders"/>
<el-select
v-model="order"
class="ms-col-type"
size="mini"
style="width: 120px"
@change="orderCharts"
>
<el-option
:key="t.id"
:value="t.id"
:label="t.name"
v-for="t in orders"
/>
</el-select>
<span style="margin: 0px 10px 10px">|</span>
<font-awesome-icon v-if="!isFullScreen && showFullScreen" class="report-alt-ico" :icon="['fa', 'expand-alt']" size="lg"
@click="fullScreen"/>
<font-awesome-icon v-if="isFullScreen && showFullScreen" class="report-alt-ico" :icon="['fa', 'compress-alt']" size="lg"
@click="unFullScreen"/>
<font-awesome-icon
v-if="!isFullScreen && showFullScreen"
class="report-alt-ico"
:icon="['fa', 'expand-alt']"
size="lg"
@click="fullScreen"
/>
<font-awesome-icon
v-if="isFullScreen && showFullScreen"
class="report-alt-ico"
:icon="['fa', 'compress-alt']"
size="lg"
@click="unFullScreen"
/>
</div>
</el-row>
<el-row>
<ms-chart ref="chart1" :options="loadOption" class="chart-config" :autoresize="true"/>
<ms-chart
ref="chart1"
:options="loadOption"
class="chart-config"
:autoresize="true"
/>
</el-row>
</el-card>
</div>
@ -32,7 +76,7 @@ import MsChart from "metersphere-frontend/src/components/chart/MsChart";
export default {
name: "TestAnalysisChart",
components: {MsChart},
components: { MsChart },
props: {
loadOption: {},
},
@ -49,35 +93,50 @@ export default {
type: Boolean,
default() {
return true;
}
},
},
//
chartType: "line",
charts: [{id: 'line', name: this.$t('commons.report_statistics.line')}, {id: 'bar', name: this.$t('commons.report_statistics.bar')}],
charts: [
{ id: "line", name: this.$t("commons.report_statistics.line") },
{ id: "bar", name: this.$t("commons.report_statistics.bar") },
],
order: "",
orders: [{id: '', name: this.$t('commons.sort_default')}, {id: 'desc', name: this.$t('commons.report_statistics.desc')}, {
id: 'asc',
name: this.$t('commons.report_statistics.asc')
}],
orders: [
{ id: "", name: this.$t("commons.sort_default") },
{ id: "desc", name: this.$t("commons.report_statistics.desc") },
{
id: "asc",
name: this.$t("commons.report_statistics.asc"),
},
],
loading: false,
options: {},
}
};
},
methods: {
reCountWidth(isHideOther) {
if (isHideOther) {
this.w = document.documentElement.clientWidth - 20;
} else {
this.w = document.documentElement.clientWidth - 760;
}
this.reload();
},
orderCharts() {
this.$emit('orderCharts', this.order);
this.$emit("orderCharts", this.order);
},
generateOption() {
this.loadOption.series.forEach(item => {
this.loadOption.series.forEach((item) => {
item.type = this.chartType;
})
});
this.reload();
},
reload() {
this.loading = true
this.loading = true;
this.$nextTick(() => {
this.loading = false
})
this.loading = false;
});
},
fullScreen() {
this.originalW = this.w;
@ -85,23 +144,22 @@ export default {
this.w = document.body.clientWidth - 50;
this.h = document.body.clientHeight;
this.isFullScreen = true;
this.$emit('hidePage', true);
this.$emit("hidePage", true);
},
unFullScreen() {
this.w = this.originalW;
this.h = this.originalH;
this.isFullScreen = false;
this.$emit('hidePage', false);
this.$emit("hidePage", false);
},
getOptions() {
return this.loadOption;
}
},
},
}
};
</script>
<style scoped>
.ms-test-chart-header {
z-index: 999;
width: 320px;
@ -121,7 +179,7 @@ export default {
font-size: 18px;
}
:deep(.echarts ) {
:deep(.echarts) {
height: calc(100vh / 1.95);
}
@ -141,8 +199,7 @@ export default {
width: 100%;
}
:deep(.el-card__body ) {
:deep(.el-card__body) {
padding: 0px;
}
</style>