<template>
|
<div class="main" ref="main">
|
<div class="container" ref="container">
|
<div
|
class="item chart"
|
v-for="item in chartList"
|
:ref="item + 'wrap'"
|
:key="'list_' + item"
|
>
|
<div class="bar">
|
<div class="title">{{ titles[item] }}</div>
|
<div class="btn-grp">
|
<div
|
:class="[
|
'btn',
|
'iconfont',
|
{
|
'icon-quanping': !fullScreen,
|
'icon-tuichuquanping': fullScreen,
|
},
|
]"
|
:title="fullScreen ? '还原' : '全屏'"
|
@click="toggleScreen(item)"
|
></div>
|
<div
|
class="btn iconfont icon-guanbi"
|
title="关闭"
|
@click="closeItem(item)"
|
></div>
|
</div>
|
</div>
|
<div class="content">
|
<compare-bar
|
:ref="item"
|
:marks="marks[item]"
|
@contextmenu.native="(e) => chartContextClick(e, item)"
|
></compare-bar>
|
</div>
|
</div>
|
|
<span
|
class="item table"
|
v-for="item in tableList"
|
:ref="item + 'wrap'"
|
:key="'list_' + item"
|
>
|
<div class="bar">
|
<div class="title">{{ titles[item] }}</div>
|
<div class="btn-grp">
|
<div
|
:class="[
|
'btn',
|
'iconfont',
|
{
|
'icon-quanping': !fullScreen,
|
'icon-tuichuquanping': fullScreen,
|
},
|
]"
|
:title="fullScreen ? '还原' : '全屏'"
|
@click="toggleScreen(item)"
|
></div>
|
<div
|
class="btn iconfont icon-guanbi"
|
title="关闭"
|
@click="closeItem(item)"
|
></div>
|
</div>
|
</div>
|
<div class="content">
|
<div class="table-wrap">
|
<el-table
|
:data="item == 'resTable' ? resTableData : volTableData"
|
style="width: 100%"
|
stripe
|
:ref="item"
|
size="small"
|
height="100%"
|
class="tableCent"
|
tooltip-effect="light"
|
>
|
<el-table-column
|
v-for="header in headers"
|
:key="header.prop"
|
:prop="header.prop"
|
:label="header.label"
|
:width="header.width"
|
:fixed="header.fixed"
|
:min-width="header.minWidth"
|
show-overflow-tooltip
|
align="center"
|
></el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</span>
|
</div>
|
<!-- 图表右键菜单 -->
|
<chart-context-menu
|
:getParentNode="getChartContextParentNode"
|
v-model="contextMenu.visible"
|
:disabled-list="disabledList"
|
:context-data="contextMenu.node"
|
:style="{ left: contextMenu.x + 'px', top: contextMenu.y + 'px' }"
|
@toggleLabel="toggleLabel"
|
></chart-context-menu>
|
</div>
|
</template>
|
|
<script>
|
import CompareBar from "@/components/myCharts/CompareBar";
|
import ChartContextMenu from "@/components/chartContextMenu";
|
import offset from "@/assets/js/offset";
|
import { comparedList, testCompareReport } from "@/apis";
|
import { mapGetters } from "vuex";
|
import { toFixed } from "@/assets/js/util";
|
// 保留三位小数
|
const BIT = 3;
|
|
export default {
|
name: "",
|
|
data() {
|
const titles = {
|
resChart: "内阻(mΩ)",
|
volChart: "电压(V)",
|
resTable: "数据表(内阻/mΩ)",
|
volTable: "数据表(电压/V)",
|
};
|
const marks = {
|
resChart: [
|
{
|
name: "内阻告警",
|
y: 0,
|
type: "high",
|
color: "#ff0",
|
},
|
{
|
name: "内阻更换",
|
y: 0,
|
type: "high",
|
color: "#d9001b",
|
},
|
],
|
volChart: [
|
{
|
name: "高压告警",
|
y: 0,
|
type: "high",
|
color: "#ff0",
|
},
|
{
|
name: "低压告警",
|
y: 0,
|
type: "low",
|
color: "#d9001b",
|
},
|
],
|
};
|
return {
|
resPic: "",
|
volPic: "",
|
disabledList: [],
|
marks,
|
baseFileId: this.$route.query.baseFileId,
|
fileId: this.$route.query.fileId,
|
opts: this.$route.query.opts,
|
titles,
|
fullScreen: false,
|
fileData: {
|
data1: [],
|
data2: [],
|
data3: {},
|
},
|
resTableData: [],
|
volTableData: [],
|
headers: [],
|
windowList: [],
|
contextMenu: {
|
x: 0,
|
y: 0,
|
visible: false,
|
node: {},
|
},
|
};
|
},
|
components: {
|
CompareBar,
|
ChartContextMenu,
|
},
|
computed: {
|
resChart() {
|
return this.opts >= 2;
|
},
|
resTable() {
|
return this.opts >= 2;
|
},
|
volChart() {
|
return this.opts == 1 || this.opts == 3;
|
},
|
volTable() {
|
return this.opts == 1 || this.opts == 3;
|
},
|
chartList() {
|
return this.windowList.filter((v) => v.indexOf("Chart") > -1);
|
},
|
tableList() {
|
return this.windowList.filter((v) => v.indexOf("Table") > -1);
|
},
|
...mapGetters("setting", ["params"]),
|
},
|
methods: {
|
getWindowList() {
|
this.windowList = ["resChart", "volChart", "resTable", "volTable"].filter(
|
(v) => this[v]
|
);
|
},
|
comparedList() {
|
comparedList(this.baseFileId, this.fileId).then((res) => {
|
let { code, data, data2, data3 } = res.data;
|
if (code) {
|
this.fileData.data1 = data;
|
this.fileData.data2 = data2;
|
this.fileData.data3 = data3;
|
const {
|
resBadCoeK4,
|
resGoodCoeK3,
|
vol1d2HighCoeK2,
|
vol1d2LowCoeK1,
|
vol2HighCoeK2,
|
vol2LowCoeK1,
|
vol6HighCoeK2,
|
vol6LowCoeK1,
|
vol12HighCoeK2,
|
vol12LowCoeK1,
|
} = this.params;
|
const { battRes, battVol } = data3.fileParamBase;
|
this.marks.resChart[0].y = toFixed(
|
(resGoodCoeK3 * battRes) / 100,
|
BIT
|
);
|
this.marks.resChart[1].y = toFixed(
|
(resBadCoeK4 * battRes) / 100,
|
BIT
|
);
|
|
if (!this.marks.volChart.length) {
|
this.marks.volChart = [
|
{
|
name: "高压告警",
|
y: 0,
|
type: "high",
|
color: "#ff0",
|
},
|
{
|
name: "低压告警",
|
y: 0,
|
type: "low",
|
color: "#d9001b",
|
},
|
];
|
}
|
switch (battVol) {
|
case 1.2:
|
this.marks.volChart[0].y = toFixed(vol1d2HighCoeK2, BIT);
|
this.marks.volChart[1].y = toFixed(vol1d2LowCoeK1, BIT);
|
break;
|
case 2:
|
this.marks.volChart[0].y = toFixed(vol2HighCoeK2, BIT);
|
this.marks.volChart[1].y = toFixed(vol2LowCoeK1, BIT);
|
break;
|
case 6:
|
this.marks.volChart[0].y = toFixed(vol6HighCoeK2, BIT);
|
this.marks.volChart[1].y = toFixed(vol6LowCoeK1, BIT);
|
break;
|
case 12:
|
this.marks.volChart[0].y = toFixed(vol12HighCoeK2, BIT);
|
this.marks.volChart[1].y = toFixed(vol12LowCoeK1, BIT);
|
break;
|
default:
|
this.marks.volChart = [];
|
break;
|
}
|
this.$nextTick(() => {
|
this.initChart();
|
});
|
} else {
|
this.$message.error("文件解析失败");
|
}
|
});
|
},
|
initChart() {
|
let { headers, xLabel, resData, volData, resTableData, volTableData } =
|
this.formatData(this.fileData);
|
this.resTableData = resTableData;
|
this.volTableData = volTableData;
|
this.$nextTick(() => {
|
this.$refs.resTable && this.$refs.resTable[0].doLayout();
|
this.$refs.volTable && this.$refs.volTable[0].doLayout();
|
});
|
this.headers = headers;
|
const obj = {
|
resChart: resData,
|
volChart: volData,
|
};
|
this.chartList.forEach((v) => {
|
let chart = this.$refs[v];
|
// debugger;
|
if (!chart || !chart.length) {
|
return;
|
}
|
chart[0].setData({
|
xLabel,
|
sData: obj[v],
|
});
|
chart[0].resize();
|
|
// 把base64图保存下来
|
if (v == "resChart") {
|
// console.log(chart[0]);
|
this.resPic = chart[0].getDataURL();
|
}
|
if (v == "volChart") {
|
this.volPic = chart[0].getDataURL();
|
}
|
});
|
},
|
addListener() {
|
document.addEventListener("fullscreenchange", this.fullScreenListener);
|
document.addEventListener(
|
"webkitfullscreenchange",
|
this.fullScreenListener
|
);
|
|
this.$bus.$on("export", this.exportReport);
|
this.$bus.$on("paramsUpdated", () => {
|
this.refreshPage(true);
|
});
|
},
|
removeListener() {
|
document.removeEventListener("fullscreenchange", this.fullScreenListener);
|
document.removeEventListener(
|
"webkitfullscreenchange",
|
this.fullScreenListener
|
);
|
},
|
fullScreenListener() {
|
// console.log(e);
|
this.fullScreen = !this.fullScreen;
|
this.resize();
|
},
|
toggleScreen(item) {
|
if (this.fullScreen) {
|
this.outFullScreen(item);
|
} else {
|
this.inFullScreen(item + "wrap");
|
}
|
},
|
inFullScreen(item) {
|
const el = this.$refs[item][0];
|
if (el.requestFullscreen) {
|
el.requestFullscreen();
|
return true;
|
} else if (el.webkitRequestFullScreen) {
|
el.webkitRequestFullScreen();
|
return true;
|
}
|
return false;
|
},
|
outFullScreen() {
|
if (document.exitFullscreen) {
|
document.exitFullscreen();
|
} else if (document.webkitCancelFullScreen) {
|
document.webkitCancelFullScreen();
|
} else if (document.mozCancelFullScreen) {
|
document.mozCancelFullScreen();
|
} else if (document.msExitFullscreen) {
|
document.msExitFullscreen();
|
}
|
},
|
formatData(data) {
|
let xLabel = [],
|
headers = [];
|
let {
|
data1,
|
data2,
|
data3: { volBalanceRate, resBalanceRate, volChangeRate, resChangeRate },
|
} = data;
|
volChangeRate = volChangeRate.map((v) => v);
|
resChangeRate = resChangeRate.map((v) => v);
|
const maxLen = data1.length >= data2.length ? data1.length : data2.length;
|
let time1 = data1[0].testTime,
|
time2 = data2[0].testTime;
|
let resData = [
|
{ name: time1, data: [] },
|
{ name: time2, data: [] },
|
],
|
volData = [
|
{ name: time1, data: [] },
|
{ name: time2, data: [] },
|
],
|
resTableData = [],
|
volTableData = [];
|
|
resTableData.push(
|
{ name: time1, balanceRate: resBalanceRate[0] },
|
{ name: time2, balanceRate: resBalanceRate[1] },
|
{ name: "变化率", balanceRate: resChangeRate.pop() }
|
);
|
volTableData.push(
|
{ name: time1, balanceRate: volBalanceRate[0] },
|
{ name: time2, balanceRate: volBalanceRate[1] },
|
{ name: "变化率", balanceRate: volChangeRate.pop() }
|
);
|
headers.push({
|
prop: "name",
|
label: "数据",
|
minWidth: 180,
|
fixed: "left",
|
});
|
for (let i = 0; i < maxLen; i++) {
|
let itemData1 = data1[i],
|
itemData2 = data2[i];
|
let monNum = "#" + (itemData1 ? itemData1.monNum : itemData2.monNum);
|
xLabel.push(monNum);
|
if (itemData1) {
|
resData[0]["data"].push(itemData1.br);
|
volData[0]["data"].push(itemData1.bv);
|
resTableData[0]["v" + i] = itemData1.br;
|
volTableData[0]["v" + i] = itemData1.bv;
|
} else {
|
resTableData[0]["v" + i] = "--";
|
volTableData[0]["v" + i] = "--";
|
}
|
if (itemData2) {
|
resData[1]["data"].push(itemData2.br);
|
volData[1]["data"].push(itemData2.bv);
|
resTableData[1]["v" + i] = itemData2.br;
|
volTableData[1]["v" + i] = itemData2.bv;
|
} else {
|
resTableData[1]["v" + i] = "--";
|
volTableData[1]["v" + i] = "--";
|
}
|
if (resChangeRate[i] != undefined) {
|
resTableData[2]["v" + i] = resChangeRate[i];
|
} else {
|
resTableData[2]["v" + i] = "--";
|
}
|
if (volChangeRate[i] != undefined) {
|
volTableData[2]["v" + i] = volChangeRate[i];
|
} else {
|
volTableData[2]["v" + i] = "--";
|
}
|
headers.push({
|
prop: "v" + i,
|
label: monNum,
|
});
|
}
|
headers.push({
|
prop: "balanceRate",
|
label: "均一性",
|
fixed: "right",
|
minWidth: 80,
|
});
|
return {
|
headers,
|
xLabel,
|
resData,
|
volData,
|
resTableData,
|
volTableData,
|
};
|
},
|
resize() {
|
this.$nextTick(() => {
|
this.windowList.forEach((v) => {
|
let chart = this.$refs[v];
|
if (!chart || !chart.length) {
|
return;
|
}
|
chart[0].resize();
|
});
|
});
|
},
|
closeItem(item) {
|
if (this.fullScreen) {
|
this.toggleScreen(item);
|
}
|
if (this.windowList.length <= 1) {
|
this.$message.warning("最少保留一个模块");
|
return;
|
}
|
const idx = this.windowList.indexOf(item);
|
// console.log(idx)
|
this.windowList.splice(idx, 1);
|
this.$nextTick(() => {
|
this.resize();
|
});
|
},
|
chartContextClick($e, item) {
|
const { clientX, clientY } = $e;
|
const container = this.$refs.container;
|
let { left, top } = offset(container);
|
if (this.fullScreen) {
|
left = 0;
|
top = 0;
|
}
|
let y = clientY - top;
|
let x = clientX - left;
|
let { clientHeight: bodyHeight, clientWidth: bodyWidth } = document.body;
|
if (clientY + 105 > bodyHeight) {
|
y = bodyHeight - 105 - top;
|
}
|
if (clientX + 120 > bodyWidth) {
|
x = bodyWidth - 120 - left;
|
}
|
this.contextMenu.x = x;
|
this.contextMenu.y = y;
|
this.contextMenu.node = { ref: item };
|
this.disabledList = [1, 2];
|
this.contextMenu.visible = true;
|
},
|
toggleLabel(data) {
|
this.$refs[data][0].toggleLabelVisible();
|
},
|
getChartContextParentNode() {
|
const ref = this.contextMenu.node.ref + "wrap";
|
if (!this.fullScreen) {
|
return this.$refs.main;
|
} else {
|
return this.$refs[ref][0];
|
}
|
},
|
activeFN() {
|
this.$nextTick(() => {
|
this.resize();
|
});
|
},
|
refreshPage(force) {
|
if (!force && (this._isDestroyed || this._directInactive)) {
|
return false;
|
}
|
this.comparedList();
|
},
|
exportReport() {
|
// console.log(this, 'export')
|
if (this._isDestroyed || this._directInactive) {
|
return false;
|
}
|
const {
|
resPic,
|
volPic,
|
$route: {
|
query: { baseFileId: fileId, fileId: fileId2 },
|
},
|
} = this;
|
let params = {
|
fileId,
|
fileId2,
|
};
|
testCompareReport(params, { resPic, volPic }).then((res) => {
|
let { headers, data, status } = res;
|
if (200 == status && data) {
|
let url = window.URL.createObjectURL(data);
|
const matchRes = /filename=(.*)/.exec(headers["content-disposition"]);
|
const fileName = matchRes
|
? decodeURI(matchRes[1].trim())
|
: "未知文件名.xls";
|
let link = document.createElement("a");
|
link.style.display = "none";
|
link.href = url;
|
link.download = fileName;
|
document.body.appendChild(link);
|
link.click();
|
document.body.removeChild(link);
|
window.URL.revokeObjectURL(url);
|
} else {
|
this.$message.error("操作失败");
|
}
|
});
|
},
|
},
|
|
mounted() {
|
this.getWindowList();
|
this.comparedList();
|
this.addListener();
|
},
|
};
|
</script>
|
|
<style lang="less" scoped>
|
.container {
|
width: 100%;
|
height: 100%;
|
display: flex;
|
flex-wrap: wrap;
|
}
|
.item {
|
display: flex;
|
flex-direction: column;
|
.bar {
|
display: flex;
|
justify-content: space-between;
|
background: #f0f0f0;
|
padding-left: 8px;
|
padding-right: 8px;
|
.btn-grp {
|
display: flex;
|
align-items: center;
|
.btn {
|
margin: 0 4px;
|
cursor: pointer;
|
&:hover {
|
background: rgba(200, 200, 200, 0.6);
|
}
|
}
|
}
|
}
|
.content {
|
flex: 1;
|
background: #0029a0;
|
position: relative;
|
.table-wrap {
|
position: absolute;
|
top: 0;
|
right: 0;
|
left: 0;
|
bottom: 0;
|
:deep(.el-table__footer) tr {
|
background: #fa8e34;
|
td {
|
background: transparent;
|
color: #fff;
|
}
|
}
|
}
|
}
|
}
|
.item:only-child {
|
width: 100%;
|
height: 100%;
|
}
|
.item ~ .item {
|
margin-left: 4px;
|
}
|
.item:first-child:nth-last-child(2) ~ .item,
|
.item.table {
|
margin-left: 0;
|
}
|
.item.item.item:first-child:nth-last-child(2),
|
.item.item.item:first-child:nth-last-child(2) ~ .item {
|
width: 100%;
|
height: 50%;
|
}
|
.item:first-child:nth-last-child(3),
|
.item:first-child:nth-last-child(3) ~ .item {
|
width: calc(50% - 2px);
|
height: 50%;
|
}
|
.item:first-child:nth-last-child(3) ~ .item.table {
|
width: 100%;
|
height: 50%;
|
}
|
.item:first-child:nth-last-child(3) {
|
width: 100%;
|
}
|
.item.chart:first-child:nth-last-of-type(2),
|
.item.chart:first-child:nth-last-of-type(2) + .chart {
|
width: calc(50% - 2px);
|
height: 50%;
|
}
|
.item.item.table:nth-child(2):nth-last-child(2),
|
.item.item.table:nth-child(2):nth-last-child(2) ~ .item {
|
height: 25%;
|
}
|
.item:first-child:nth-last-child(4) ~ .item.table {
|
width: 100%;
|
height: 25%;
|
}
|
.tableCent :deep(.el-table__row:last-of-type) {
|
background: #fa8e34;
|
td {
|
background: transparent;
|
color: #fff;
|
}
|
}
|
</style>
|