fix(项目报告): 修复项目报告预览中看不到统计图表的问题

修复项目报告预览中看不到统计图表的问题
This commit is contained in:
song-tianyang 2023-02-22 14:35:27 +08:00 committed by 建国
parent 07cd82ac25
commit cce4190dfa
4 changed files with 291 additions and 195 deletions

View File

@ -374,8 +374,8 @@ public class EnterpriseTestReportService {
}
reportContent.append(previweContent);
} else if (isReportStep(step.getType())) {
if (isSchedule) {
//定时任务触发的数据需要检查图片是否需要重新生成如果生成不成功就不贴图
if (isSchedule && syncReportMap.containsKey(step.getReportRecordId())) {
//定时任务触发的数据需要检查图片是否需要重新生成如果生成失败syncReportMap里有对应的步骤id但是没有图片数据
String imageFile = syncReportMap.get(step.getReportRecordId());
if (StringUtils.isNotEmpty(imageFile)) {
step.setRecordImageContent(imageFile);

View File

@ -47,10 +47,6 @@ public class ChromeUtil {
try {
driver = new RemoteWebDriver(new URL(seleniumUrl), options);
} catch (Exception e) {
if (driver != null) {
driver.quit();
driver = null;
}
LogUtil.error(e);
}
return driver;
@ -66,6 +62,7 @@ public class ChromeUtil {
for (Map.Entry<String, String> urlEntry : request.getUrlMap().entrySet()) {
String id = urlEntry.getKey();
String url = urlEntry.getValue();
String files = null;
try {
driver.get(url);
driver.manage().window().fullscreen();
@ -77,20 +74,14 @@ public class ChromeUtil {
" imageUrl = chartsCanvas && chartsCanvas.toDataURL('image/png');" +
"return imageUrl;" +
"}";
String files = ((JavascriptExecutor) driver).executeScript(js).toString();
if (StringUtils.isNotEmpty(files)) {
returnMap.put(id, files);
}
files = ((JavascriptExecutor) driver).executeScript(js).toString();
Thread.sleep(1 * 1000);
} catch (Exception e) {
LogUtil.error("使用selenium获取图片报错!", e);
}
}
if (driver != null) {
driver.quit();
returnMap.put(id, files);
}
driver.quit();
}
return returnMap;
}

View File

@ -1,12 +1,16 @@
<template>
<div v-loading="loading">
<el-card class="ms-test-chart" :style="{height: h + 'px'}" ref="msDrawer">
<el-card class="ms-test-chart" :style="{ 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,24 +18,62 @@
</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 style="overflow: auto">
<ms-chart ref="chart1" v-if="!loading" :options="dataOption"
:style="{width: '100%', height: (h-70) + 'px'}" class="chart-config" :autoresize="true"
id="picChart"/>
<ms-chart
ref="chart1"
v-if="!loading"
:options="dataOption"
:style="{ width: '100%', height: h - 70 + 'px' }"
class="chart-config"
:autoresize="true"
:id="reportId"
/>
</el-row>
</el-card>
</div>
@ -42,7 +84,7 @@ import MsChart from "metersphere-frontend/src/components/chart/MsChart";
export default {
name: "ReportChart",
components: {MsChart},
components: { MsChart },
props: {
loadOption: {},
pieOption: {},
@ -51,7 +93,7 @@ export default {
type: String,
default() {
return "bar";
}
},
},
chartWidth: Number,
needFullScreen: Boolean,
@ -72,96 +114,118 @@ 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: {},
pieItemOption: {
dataset: [{
source: [
['Product', 'Sales', 'Price', 'Year'],
['Cake', 123, 32, 2011],
['Cereal', 231, 14, 2011],
['Tofu', 235, 5, 2011],
['Dumpling', 341, 25, 2011],
['Biscuit', 122, 29, 2011],
['Cake', 143, 30, 2012],
['Cereal', 201, 19, 2012],
['Tofu', 255, 7, 2012],
['Dumpling', 241, 27, 2012],
['Biscuit', 102, 34, 2012],
['Cake', 153, 28, 2013],
['Cereal', 181, 21, 2013],
['Tofu', 395, 4, 2013],
['Dumpling', 281, 31, 2013],
['Biscuit', 92, 39, 2013],
['Cake', 223, 29, 2014],
['Cereal', 211, 17, 2014],
['Tofu', 345, 3, 2014],
['Dumpling', 211, 35, 2014],
['Biscuit', 72, 24, 2014],
],
}, {
transform: {
type: 'filter',
config: {dimension: 'Year', value: 2011}
dataset: [
{
source: [
["Product", "Sales", "Price", "Year"],
["Cake", 123, 32, 2011],
["Cereal", 231, 14, 2011],
["Tofu", 235, 5, 2011],
["Dumpling", 341, 25, 2011],
["Biscuit", 122, 29, 2011],
["Cake", 143, 30, 2012],
["Cereal", 201, 19, 2012],
["Tofu", 255, 7, 2012],
["Dumpling", 241, 27, 2012],
["Biscuit", 102, 34, 2012],
["Cake", 153, 28, 2013],
["Cereal", 181, 21, 2013],
["Tofu", 395, 4, 2013],
["Dumpling", 281, 31, 2013],
["Biscuit", 92, 39, 2013],
["Cake", 223, 29, 2014],
["Cereal", 211, 17, 2014],
["Tofu", 345, 3, 2014],
["Dumpling", 211, 35, 2014],
["Biscuit", 72, 24, 2014],
],
},
}, {
transform: {
type: 'filter',
config: {dimension: 'Year', value: 2012}
}
}, {
transform: {
type: 'filter',
config: {dimension: 'Year', value: 2013}
}
}],
series: [{
type: 'pie', radius: 50, center: ['50%', '25%'],
datasetIndex: 1
}, {
type: 'pie', radius: 50, center: ['50%', '50%'],
datasetIndex: 2
}, {
type: 'pie', radius: 50, center: ['50%', '75%'],
datasetIndex: 3
}],
media: [{
query: {minAspectRatio: 1},
option: {
series: [
{center: ['25%', '50%']},
{center: ['50%', '50%']},
{center: ['75%', '50%']}
]
}
}, {
option: {
series: [
{center: ['50%', '25%']},
{center: ['50%', '50%']},
{center: ['50%', '75%']}
]
}
}]
{
transform: {
type: "filter",
config: { dimension: "Year", value: 2011 },
},
},
{
transform: {
type: "filter",
config: { dimension: "Year", value: 2012 },
},
},
{
transform: {
type: "filter",
config: { dimension: "Year", value: 2013 },
},
},
],
series: [
{
type: "pie",
radius: 50,
center: ["50%", "25%"],
datasetIndex: 1,
},
{
type: "pie",
radius: 50,
center: ["50%", "50%"],
datasetIndex: 2,
},
{
type: "pie",
radius: 50,
center: ["50%", "75%"],
datasetIndex: 3,
},
],
media: [
{
query: { minAspectRatio: 1 },
option: {
series: [
{ center: ["25%", "50%"] },
{ center: ["50%", "50%"] },
{ center: ["75%", "50%"] },
],
},
},
{
option: {
series: [
{ center: ["50%", "25%"] },
{ center: ["50%", "50%"] },
{ center: ["50%", "75%"] },
],
},
},
],
},
}
};
},
created() {
if (this.chartType === 'pie') {
if (this.chartType === "pie") {
this.dataOption = this.pieOption;
} else {
this.dataOption = this.loadOption;
@ -184,53 +248,53 @@ export default {
},
methods: {
countChartWidth() {
if (this.chartWidth === 0 || this.chartType === 'bar') {
if (this.chartWidth === 0 || this.chartType === "bar") {
this.chartWidthNumber = this.w;
} else {
this.chartWidthNumber = this.chartWidth;
}
},
orderCharts() {
this.$emit('orderCharts', this.order);
this.$emit("orderCharts", this.order);
},
formatData(formatData) {
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.xAxis) === 'string') {
if (typeof formatData.xAxis === "string") {
formatData.xAxis = JSON.parse(formatData.xAxis);
}
if (typeof (formatData.yAxis) === 'string') {
if (typeof formatData.yAxis === "string") {
formatData.yAxis = JSON.parse(formatData.yAxis);
}
if (typeof (formatData.series) === 'string') {
if (typeof formatData.series === "string") {
formatData.series = JSON.parse(formatData.series);
}
},
generateOption() {
if (this.chartType === 'pie') {
if (this.chartType === "pie") {
this.dataOption = this.pieOption;
} else {
this.dataOption = this.loadOption;
}
this.formatData(this.dataOption);
this.dataOption.series.forEach(item => {
this.dataOption.series.forEach((item) => {
item.type = this.chartType;
});
// this.reload();
},
reload() {
this.loading = true
this.loading = true;
this.generateOption();
this.$nextTick(() => {
this.loading = false;
})
});
},
fullScreen() {
this.originalW = this.w;
@ -238,22 +302,24 @@ 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);
},
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(this.reportId)) {
let chartsCanvas = document.getElementById(this.reportId).querySelectorAll('canvas')[0];
let chartsCanvas = document
.getElementById(this.reportId)
.querySelectorAll("canvas")[0];
if (chartsCanvas) {
// toDataURL()canvascanvasbase64
returnImageData = chartsCanvas && chartsCanvas.toDataURL(imageType);
@ -263,46 +329,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;
@ -345,5 +415,4 @@ export default {
:deep(.el-card__body) {
padding: 0px;
}
</style>

View File

@ -4,35 +4,50 @@
<div v-if="!reportDetail.nameIsEdit" style="line-height: 30px">
<span style="margin-left: 5px">{{ reportDetail.name }}</span>
<i class="el-icon-edit" @click="editAttachDataName(true)"></i>
<i class="el-icon-delete" @click="deleteDetail" style="float: right;margin-top: 6px; margin-right: 10px"></i>
<i
class="el-icon-delete"
@click="deleteDetail"
style="float: right; margin-top: 6px; margin-right: 10px"
></i>
</div>
<el-input v-else v-model="reportDetail.name" @blur="editAttachDataName(false)"></el-input>
<el-input
v-else
v-model="reportDetail.name"
@blur="editAttachDataName(false)"
></el-input>
</div>
<div class="ms-row">
<report-chart :report-id="reportDetail.id" :chart-width="pieOption.width" :read-only="true"
:need-full-screen="false" :chart-type="chartType"
ref="analysisChart" :load-option="loadOption" :pie-option="pieOption"/>
<report-chart
:report-id="reportDetail.id"
:chart-width="pieOption.width"
:read-only="true"
:need-full-screen="false"
:chart-type="chartType"
ref="analysisChart"
:load-option="loadOption"
:pie-option="pieOption"
/>
</div>
<div class="ms-row">
<report-table :full-screen="false" :group-name="options.xaxis" :show-columns="options.yaxis"
:tableData="tableData"/>
<report-table
:full-screen="false"
:group-name="options.xaxis"
:show-columns="options.yaxis"
:tableData="tableData"
/>
</div>
</div>
</template>
<script>
import ReportChart from "@/business/enterprisereport/components/chart/ReportChart";
import ReportTable from "@/business/enterprisereport/components/chart/ReportTable";
export default {
name: "ReportPic",
components: {ReportChart, ReportTable},
components: { ReportChart, ReportTable },
data() {
return {
chartType: "bar",
loading: false,
options: {},
@ -42,7 +57,7 @@ export default {
yAxis: {},
label: {},
tooltip: {},
series: []
series: [],
},
pieOption: {
legend: {},
@ -61,7 +76,7 @@ export default {
type: Boolean,
default() {
return false;
}
},
},
},
created() {
@ -80,9 +95,9 @@ export default {
let selectTableData = this.reportDetail.reportRecordData.tableData;
let selectOption = this.reportDetail.reportRecordData.selectOption;
if (this.reportDetail.reportRecordData.chartType) {
if (this.reportDetail.reportRecordData.chartType === "\"bar\"") {
if (this.reportDetail.reportRecordData.chartType === '"bar"') {
this.chartType = "bar";
} else if (this.reportDetail.reportRecordData.chartType === "\"pie\"") {
} else if (this.reportDetail.reportRecordData.chartType === '"pie"') {
this.chartType = "pie";
} else {
this.chartType = this.reportDetail.reportRecordData.chartType;
@ -91,16 +106,26 @@ export default {
if (selectOption) {
this.options = selectOption;
if (this.options.xaxis) {
if (this.options.xaxis === 'creator') {
this.options.xaxis = this.$t('commons.report_statistics.report_filter.select_options.creator');
} else if (this.options.xaxis === 'maintainer') {
this.options.xaxis = this.$t('commons.report_statistics.report_filter.select_options.maintainer');
} else if (this.options.xaxis === 'casetype') {
this.options.xaxis = this.$t('commons.report_statistics.report_filter.select_options.case_type');
} else if (this.options.xaxis === 'casestatus') {
this.options.xaxis = this.$t('commons.report_statistics.report_filter.select_options.case_status');
} else if (this.options.xaxis === 'caselevel') {
this.options.xaxis = this.$t('commons.report_statistics.report_filter.select_options.case_level');
if (this.options.xaxis === "creator") {
this.options.xaxis = this.$t(
"commons.report_statistics.report_filter.select_options.creator"
);
} else if (this.options.xaxis === "maintainer") {
this.options.xaxis = this.$t(
"commons.report_statistics.report_filter.select_options.maintainer"
);
} else if (this.options.xaxis === "casetype") {
this.options.xaxis = this.$t(
"commons.report_statistics.report_filter.select_options.case_type"
);
} else if (this.options.xaxis === "casestatus") {
this.options.xaxis = this.$t(
"commons.report_statistics.report_filter.select_options.case_status"
);
} else if (this.options.xaxis === "caselevel") {
this.options.xaxis = this.$t(
"commons.report_statistics.report_filter.select_options.case_level"
);
}
}
}
@ -113,9 +138,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) => {
item.type = "bar";
});
}
@ -125,13 +150,13 @@ 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;
}
this.pieOption.series.forEach(item => {
this.pieOption.series.forEach((item) => {
item.type = "pie";
});
}
@ -147,39 +172,50 @@ 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);
}
},
initData() {
this.reportDetail.recordImageContent = this.$refs.analysisChart.getImages("png");
this.reportDetail.recordImageContent =
this.$refs.analysisChart.getImages("png");
},
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 "";
}
},
}
}
},
};
</script>
<style scoped>