更新zg
247
src/views/dashboard/allDashboard/BarChart.vue
Normal file
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<div :class="className" :style="{ height: height, width: width }" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
require('echarts/theme/macarons'); // echarts theme
|
||||
import resize from '../mixins/resize';
|
||||
|
||||
const animationDuration = 6000;
|
||||
|
||||
export default {
|
||||
mixins: [resize],
|
||||
props: {
|
||||
echartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: 'chart',
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '380px',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
};
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.chart) {
|
||||
return;
|
||||
}
|
||||
this.chart.dispose();
|
||||
this.chart = null;
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999',
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 100,
|
||||
left: '2%',
|
||||
right: '2%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
legend: {
|
||||
data: [
|
||||
'深加工产量',
|
||||
'原片产量',
|
||||
{
|
||||
name: '总成本',
|
||||
icon: 'path://M1255.570286 1024a512 512 0 1 0 0-1024 512 512 0 0 0 0 1024z m641.609143-512c0 37.376-3.072 74.020571-8.923429 109.714286h393.069714c59.611429 0 107.958857-49.152 107.958857-109.714286s-48.274286-109.714286-107.958857-109.714286h-393.069714c5.851429 35.693714 8.923429 72.338286 8.923429 109.714286zM156.745143 621.714286h453.12a672.914286 672.914286 0 0 1 0-219.428572H156.745143C97.133714 402.285714 48.786286 451.437714 48.786286 512s48.274286 109.714286 107.958857 109.714286z',
|
||||
},
|
||||
],
|
||||
itemWidth: 18,
|
||||
itemHeight: 18,
|
||||
textStyle: {
|
||||
fontSize: 18,
|
||||
color: '#DFF1FE',
|
||||
},
|
||||
top: 15,
|
||||
right: 20,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: this.echartData.map((item) => {
|
||||
return item.time;
|
||||
}),
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '单位/片',
|
||||
min: 0,
|
||||
axisLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#b6c1e1',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '单位/万元',
|
||||
min: 0,
|
||||
axisLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#b6c1e1',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '深加工产量',
|
||||
type: 'bar',
|
||||
barWidth: '14px',
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.deepOut).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' 片';
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#9DEAF5' },
|
||||
{ offset: 1, color: '#6EF9DE' },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '原片产量',
|
||||
type: 'bar',
|
||||
barWidth: '14px',
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.originOut).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' 片';
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#5CB7FF' },
|
||||
{ offset: 1, color: '#364BFE' },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '总成本',
|
||||
type: 'line',
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
yAxisIndex: 1,
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.price).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' 万元';
|
||||
},
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#12FFF5',
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#12FFF5',
|
||||
borderWidth: 1, // 圆点边框宽度(可选)
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.2,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#12FFF5',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'transparent',
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if (this.chart) {
|
||||
this.chart.setOption(option);
|
||||
} else {
|
||||
this.chart = echarts.init(this.$el, 'macarons');
|
||||
this.chart.setOption(option);
|
||||
}
|
||||
window.addEventListener('resize', () => {
|
||||
this.chart.resize();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
522
src/views/dashboard/allDashboard/index.vue
Normal file
@@ -0,0 +1,522 @@
|
||||
<template>
|
||||
<div
|
||||
id="wholePlantContainerB"
|
||||
ref="wholePlantContainerB"
|
||||
style="width: 100%; height: 100%">
|
||||
<div
|
||||
id="wholePlantContainer"
|
||||
ref="wholePlantContainer"
|
||||
class="wholePlantBoard"
|
||||
style="
|
||||
position: absolute;
|
||||
transform-origin: 16px 8px;
|
||||
font-size: 16px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
"
|
||||
:style="{ transform: 'scale(' + scaleNum + ')' }">
|
||||
<KHeader
|
||||
:isFullScreen="isFullScreen"
|
||||
@screenfullChange="screenfullChange" />
|
||||
<div class="main-body">
|
||||
<div style="flex: 3" class="bz25-1"></div>
|
||||
<div style="flex: 5" class="bz25-2 bz-top">
|
||||
<div class="topNum">{{ Number(topData.yestodaySum).toFixed(1) }}</div>
|
||||
<div class="topText">昨日总成本/万元</div>
|
||||
</div>
|
||||
<div style="flex: 5" class="bz25-3 bz-top">
|
||||
<div class="topNum" style="margin-left: 50px">
|
||||
{{ Number(topData.yestodayRatio).toFixed(1) }}%
|
||||
</div>
|
||||
<div class="topText">昨日良品率</div>
|
||||
</div>
|
||||
<div style="flex: 5" class="bz25-4 bz-top">
|
||||
<div class="topNum">{{ Number(topData.monthSum).toFixed(1) }}</div>
|
||||
<div class="topText">本月总成本/万元</div>
|
||||
</div>
|
||||
<div style="flex: 5" class="bz25-5 bz-top">
|
||||
<div class="topNum">
|
||||
{{ Number(topData.monthAreaCost).toFixed(1) }}
|
||||
</div>
|
||||
<div class="topText">本月每平米总成本/元</div>
|
||||
</div>
|
||||
<div style="flex: 3" class="bz25-6"></div>
|
||||
</div>
|
||||
<div class="main-body">
|
||||
<div style="flex: 2" class="middle middle1">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="cost" />
|
||||
成本统计
|
||||
<span style="float: right">成本单位:万元 | 产量单位:万平方米</span>
|
||||
</div>
|
||||
<base-table
|
||||
:id="'table1'"
|
||||
style="margin: 5px 12px 12px 12px"
|
||||
:table-props="tableProps1"
|
||||
:table-data="tableData1"
|
||||
:height="230"></base-table>
|
||||
</div>
|
||||
<div style="flex: 1" class="middle middle2">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="yanqi" />
|
||||
烟气处理
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 10px 30px;
|
||||
gap: 12px;
|
||||
">
|
||||
<div class="yanqi" style="width: 566px;">
|
||||
<div class="content middle2-left" style="margin-left: 50px;width: 210px;">
|
||||
<el-image class="imageClass" :src="imgUrl.so2"></el-image>
|
||||
二氧化硫 排放浓度
|
||||
</div>
|
||||
<div class="content middle2-right">
|
||||
{{ Number(topData.so2).toFixed(1) }}
|
||||
<span style="font-size: 14px; line-height: 43px">mg/m³</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="yanqi">
|
||||
<div class="content middle2-left">
|
||||
<el-image class="imageClass" :src="imgUrl.fc"></el-image>
|
||||
粉尘排放
|
||||
</div>
|
||||
<div class="content middle2-right">
|
||||
{{ Number(topData.fc).toFixed(1) }}
|
||||
<span style="font-size: 14px; line-height: 43px">mg/m³</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="yanqi">
|
||||
<div class="content middle2-left">
|
||||
<el-image class="imageClass" :src="imgUrl.no"></el-image>
|
||||
氮氧化物 排放浓度
|
||||
</div>
|
||||
<div class="content middle2-right">
|
||||
{{ Number(topData.no).toFixed(1) }}
|
||||
<span style="font-size: 14px; line-height: 43px">mg/m³</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-body">
|
||||
<div style="flex: 2" class="footer footer1">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="costchart" />
|
||||
近12个月成本 · 产量趋势
|
||||
</div>
|
||||
<bar-chart
|
||||
ref="chartRef"
|
||||
style="margin-top: -50px"
|
||||
:echart-data="echartData"></bar-chart>
|
||||
</div>
|
||||
<div style="flex: 1" class="footer footer2">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="energy" />
|
||||
能源统计
|
||||
</div>
|
||||
<base-table
|
||||
:id="'table2'"
|
||||
style="margin: 5px 12px 12px 12px"
|
||||
:table-props="tableProps2"
|
||||
:table-data="tableData2"
|
||||
:height="310"></base-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import KHeader from '../components/Header';
|
||||
import screenfull from 'screenfull';
|
||||
import { debounce } from '@/utils/debounce';
|
||||
import baseTable from '../components/baseTable.vue';
|
||||
import BarChart from './BarChart.vue';
|
||||
|
||||
const tableProps1 = [
|
||||
{
|
||||
prop: 'title',
|
||||
label: '',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'priceS',
|
||||
label: '总成本',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'outO',
|
||||
label: '原片产量',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'ratioO',
|
||||
label: '原片良品率',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'outD',
|
||||
label: '深加工产量',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'ratioD',
|
||||
label: '深加工良品率',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'matPriceS',
|
||||
label: '原料成本',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'energyPriceS',
|
||||
label: '能源成本',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'otherPriceS',
|
||||
label: '其他成本',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'areaPriceS',
|
||||
label: '每平米成本/元',
|
||||
width: 140,
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
];
|
||||
|
||||
const tableProps2 = [
|
||||
{
|
||||
prop: 'title',
|
||||
label: '',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'elec',
|
||||
label: '电消耗量/kwh',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'gas',
|
||||
label: '气消耗量/m³',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'price',
|
||||
label: '总价/万元',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
];
|
||||
export default {
|
||||
name: '',
|
||||
components: {
|
||||
KHeader,
|
||||
baseTable,
|
||||
BarChart,
|
||||
},
|
||||
// provide() {
|
||||
// return {
|
||||
// resizeChart: null,
|
||||
// };
|
||||
// },
|
||||
data() {
|
||||
return {
|
||||
isFullScreen: false,
|
||||
url: process.env.VUE_APP_WS_API,
|
||||
websock: '',
|
||||
scaleNum: 0.8,
|
||||
topData: {},
|
||||
imgUrl: {
|
||||
fc: require('@/views/dashboard/assets/fc.png'),
|
||||
no: require('@/views/dashboard/assets/NO.png'),
|
||||
so2: require('@/views/dashboard/assets/SO2.png'),
|
||||
},
|
||||
tableProps1,
|
||||
tableData1: [],
|
||||
tableProps2,
|
||||
tableData2: [],
|
||||
echartData: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
this.initWebSocket();
|
||||
},
|
||||
destroy() {
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
this.boxReset();
|
||||
window.addEventListener('resize', this.boxReset);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('resize', this.boxReset);
|
||||
},
|
||||
methods: {
|
||||
boxReset() {
|
||||
debounce(() => {
|
||||
this.resetSize();
|
||||
}, 300)();
|
||||
},
|
||||
change() {
|
||||
this.isFullScreen = screenfull.isFullscreen;
|
||||
},
|
||||
init() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.on('change', this.change);
|
||||
}
|
||||
},
|
||||
destroy() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.off('change', this.change);
|
||||
}
|
||||
},
|
||||
// 全屏
|
||||
screenfullChange() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.toggle(this.$refs.wholePlantContainerB);
|
||||
},
|
||||
resetSize() {
|
||||
let wholePlantContainerBox = document.getElementById(
|
||||
'wholePlantContainer'
|
||||
);
|
||||
let rw = parseFloat(window.innerWidth);
|
||||
let rh = parseFloat(window.innerHeight);
|
||||
let bw = parseFloat(wholePlantContainerBox.style.width);
|
||||
let bh = parseFloat(wholePlantContainerBox.style.height);
|
||||
let wx = 0;
|
||||
let hx = 0;
|
||||
if (screenfull.isFullscreen) {
|
||||
wx = rw / bw;
|
||||
hx = rh / bh;
|
||||
} else {
|
||||
if (this.$store.state.app.sidebar.opened) {
|
||||
wx = (rw - 280) / bw;
|
||||
hx = (rh - 116) / bh;
|
||||
} else {
|
||||
wx = (rw - 85) / bw;
|
||||
hx = (rh - 116) / bh;
|
||||
}
|
||||
}
|
||||
this.scaleNum = wx;
|
||||
},
|
||||
|
||||
initWebSocket() {
|
||||
// 初始化weosocket
|
||||
const path = `${this.url}/websocket/message?userId=1`;
|
||||
this.websock = new WebSocket(path);
|
||||
this.websock.onmessage = this.websocketonmessage;
|
||||
this.websock.onopen = this.websocketonopen;
|
||||
this.websock.onerror = this.websocketonerror;
|
||||
this.websock.onclose = this.websocketclose;
|
||||
},
|
||||
|
||||
websocketonopen() {
|
||||
// 连接建立之后执行send方法发送数据
|
||||
this.websocketsend();
|
||||
},
|
||||
websocketonerror() {
|
||||
// 连接建立失败重连
|
||||
this.initWebSocket();
|
||||
},
|
||||
websocketonmessage(e) {
|
||||
let dataJson = JSON.parse(e.data);
|
||||
console.log(dataJson);
|
||||
// 数据接收
|
||||
if ('factoryState' in dataJson) {
|
||||
this.topData = dataJson.factoryState;
|
||||
}
|
||||
if ('factoryCostTableList' in dataJson) {
|
||||
this.tableData1 = dataJson.factoryCostTableList;
|
||||
}
|
||||
if ('factoryEnergyTableList' in dataJson) {
|
||||
this.tableData2 = dataJson.factoryEnergyTableList;
|
||||
}
|
||||
if ('factoryCostTrendList' in dataJson) {
|
||||
this.echartData = dataJson.factoryCostTrendList;
|
||||
this.$nextTick(()=>{
|
||||
this.$refs.chartRef.initChart();
|
||||
})
|
||||
}
|
||||
},
|
||||
websocketsend(val) {
|
||||
// 数据发送
|
||||
this.websock.send(val);
|
||||
},
|
||||
websocketclose(e) {
|
||||
// 关闭
|
||||
console.log('断开连接', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.wholePlantBoard {
|
||||
background: url(../assets/bg.png) no-repeat;
|
||||
background-size: cover;
|
||||
background-position: 0 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.main-body {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
.bz-top {
|
||||
text-align: center;
|
||||
}
|
||||
.bz25-1 {
|
||||
background: url(../assets/bz25-1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 130px;
|
||||
}
|
||||
.bz25-2 {
|
||||
background: url(../assets/bz25-2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-3 {
|
||||
background: url(../assets/bz25-3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-4 {
|
||||
background: url(../assets/bz25-4.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-5 {
|
||||
background: url(../assets/bz25-5.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-6 {
|
||||
background: url(../assets/bz25-6.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 130px;
|
||||
}
|
||||
.topNum {
|
||||
font-weight: 600;
|
||||
font-size: 44px;
|
||||
color: #ffffff;
|
||||
line-height: 43px;
|
||||
font-style: normal;
|
||||
margin-top: 50px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
.topText {
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
color: #95caff;
|
||||
line-height: 20px;
|
||||
font-style: normal;
|
||||
margin-top: 3px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
.title {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-weight: 400;
|
||||
font-size: 22px;
|
||||
color: #ffffff;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.middle {
|
||||
height: 322px;
|
||||
}
|
||||
.middle1 {
|
||||
background: url(../assets/1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.middle2 {
|
||||
background: url(../assets/2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.yanqi {
|
||||
width: 275px;
|
||||
height: 108px;
|
||||
background: url(../assets/yanqi.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.content {
|
||||
height: 108px;
|
||||
}
|
||||
.imageClass {
|
||||
width: 40px;
|
||||
height: 30px;
|
||||
display: block;
|
||||
margin: 8px auto;
|
||||
}
|
||||
.middle2-left {
|
||||
font-size: 18px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 17px;
|
||||
letter-spacing: 5px;
|
||||
width: 110px;
|
||||
padding-top: 12px;
|
||||
padding-left: 12px;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.middle2-right {
|
||||
font-weight: 600;
|
||||
font-size: 35px;
|
||||
color: #ffffff;
|
||||
line-height: 106px;
|
||||
}
|
||||
.footer {
|
||||
height: 410px;
|
||||
}
|
||||
.footer1 {
|
||||
background: url(../assets/3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.footer2 {
|
||||
background: url(../assets/4.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 402px;
|
||||
}
|
||||
</style>
|
||||
BIN
src/views/dashboard/assets/1.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
src/views/dashboard/assets/2.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/views/dashboard/assets/3.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
src/views/dashboard/assets/4.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
src/views/dashboard/assets/NO.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/views/dashboard/assets/NO2.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/views/dashboard/assets/O2.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/views/dashboard/assets/SO2.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/views/dashboard/assets/bg.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
src/views/dashboard/assets/bg1.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
src/views/dashboard/assets/bz25-1.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
src/views/dashboard/assets/bz25-2.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
src/views/dashboard/assets/bz25-3.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/views/dashboard/assets/bz25-4.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/views/dashboard/assets/bz25-5.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/views/dashboard/assets/bz25-6.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
src/views/dashboard/assets/bz25-7.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/views/dashboard/assets/bz25-8.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/views/dashboard/assets/bz25-d-1.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
src/views/dashboard/assets/bz25-d-2.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/views/dashboard/assets/bz25-d-3.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/views/dashboard/assets/bz25-d-4.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/views/dashboard/assets/bz25-d-5.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/views/dashboard/assets/fc.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src/views/dashboard/assets/yanqi.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
122
src/views/dashboard/components/Header.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<!--
|
||||
* @Author: zwq
|
||||
* @Date: 2025-02-27 15:04:43
|
||||
* @LastEditors: zwq
|
||||
* @LastEditTime: 2025-03-04 13:47:41
|
||||
* @Description:
|
||||
-->
|
||||
<template>
|
||||
<header class="kiln-header">
|
||||
<h1>{{ topTitle }}</h1>
|
||||
<!-- left: 312px; -->
|
||||
<!-- <div
|
||||
class="firm">
|
||||
单位:
|
||||
</div> -->
|
||||
<div class="datetime">
|
||||
<!-- <DateBtnGroup /> -->
|
||||
<span style="display: inline-block">
|
||||
{{ topTime }}
|
||||
</span>
|
||||
<span>{{ topDate + ' ' + timeZone }}</span>
|
||||
</div>
|
||||
<el-button type="text" class="screen-btn" @click="changeFullScreen">
|
||||
<svg-icon v-if="isFullScreen" icon-class="unFullScreenView" />
|
||||
<svg-icon v-else icon-class="fullScreenView" />
|
||||
</el-button>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
// import DateBtnGroup from './DateBtnGroup.vue';
|
||||
|
||||
export default {
|
||||
name: 'KilnHeader',
|
||||
// components: { DateBtnGroup },
|
||||
props: {
|
||||
isFullScreen: false,
|
||||
topTitle: '',
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timer: '',
|
||||
topDate: '',
|
||||
topTime: '',
|
||||
timeZone: '',
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.getTime();
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
methods: {
|
||||
changeFullScreen() {
|
||||
this.$emit('screenfullChange');
|
||||
},
|
||||
getTime() {
|
||||
let _this = this;
|
||||
this.timer = setInterval(function () {
|
||||
_this.topDate = moment().format('YYYY.MM.DD');
|
||||
let temp = moment().format('d-HH:mm').split('-');
|
||||
_this.timeZone = [
|
||||
'星期天',
|
||||
'星期一',
|
||||
'星期二',
|
||||
'星期三',
|
||||
'星期四',
|
||||
'星期五',
|
||||
'星期六',
|
||||
][temp[0]];
|
||||
_this.topTime = temp[1];
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.kiln-header {
|
||||
height: 96px;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
position: relative;
|
||||
h1 {
|
||||
font-family: HelloFont, HelloFont;
|
||||
font-weight: bold;
|
||||
font-size: 38px;
|
||||
color: #ffffff;
|
||||
letter-spacing: 10px;
|
||||
text-shadow: 1px 7px 2px #002144;
|
||||
}
|
||||
.firm {
|
||||
position: absolute;
|
||||
top: 45px;
|
||||
left: 325px;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.datetime {
|
||||
position: absolute;
|
||||
top: 75px;
|
||||
right: 405px;
|
||||
color: #69b4ff;
|
||||
font-size: 20px;
|
||||
letter-spacing: 1px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
.screen-btn {
|
||||
color: #69b4ff;
|
||||
font-size: 32px;
|
||||
position: absolute;
|
||||
right: 32px;
|
||||
top: 60px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
326
src/views/dashboard/components/baseTable.vue
Normal file
@@ -0,0 +1,326 @@
|
||||
<template>
|
||||
<div class="baseTable" :id="id">
|
||||
<el-table
|
||||
:ref="id"
|
||||
:data="renderData"
|
||||
v-bind="$attrs"
|
||||
:border="cancelBorder ? false : true"
|
||||
@current-change="currentChange"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
:header-cell-style="{
|
||||
backgroundColor: 'rgba(0,106,205,0.1)',
|
||||
color: '#fff',
|
||||
height: 30 + 'px',
|
||||
lineHeight: 30 + 'px',
|
||||
padding: 0,
|
||||
fontSize: 14 + 'px',
|
||||
letterSpacing: '2px',
|
||||
}"
|
||||
:row-style="setRowStyle">
|
||||
<!-- 多选 -->
|
||||
<el-table-column
|
||||
v-if="selectWidth"
|
||||
type="selection"
|
||||
:width="selectWidth" />
|
||||
<!-- 序号 -->
|
||||
<el-table-column
|
||||
v-if="page && limit"
|
||||
prop="_pageIndex"
|
||||
:width="pageWidth"
|
||||
align="center"
|
||||
:fixed="cancelPageFixed ? false : true">
|
||||
<template slot="header">
|
||||
<el-popover placement="bottom-start" width="300" trigger="click">
|
||||
<div
|
||||
class="setting-box"
|
||||
style="max-height: 400px; overflow-y: auto">
|
||||
<el-checkbox
|
||||
v-for="(item, index) in tableProps"
|
||||
:key="'cb' + index"
|
||||
v-model="selectedBox[index]"
|
||||
:label="item.label" />
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-s-tools" />
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
v-for="item in renderTableHeadList"
|
||||
:key="item.prop"
|
||||
v-bind="item"
|
||||
:label="item.label"
|
||||
:prop="item.prop"
|
||||
:fixed="item.fixed || false"
|
||||
:show-overflow-tooltip="item.showOverflowtooltip || false"
|
||||
:sortable="item.sortable || false">
|
||||
<template slot="header">
|
||||
<span>{{ item.label }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 多表头 -->
|
||||
<template v-if="item.children">
|
||||
<el-table-column
|
||||
v-for="sub in item.children"
|
||||
:prop="sub.prop"
|
||||
:key="sub.prop"
|
||||
v-bind="sub"
|
||||
:label="sub.label">
|
||||
<template slot-scope="scopeInner">
|
||||
<component
|
||||
:is="sub.subcomponent"
|
||||
v-if="sub.subcomponent"
|
||||
:key="scopeInner.row.id"
|
||||
:inject-data="{ ...scopeInner.row, ...sub }"
|
||||
@emitData="emitData" />
|
||||
<span v-else>
|
||||
{{ scopeInner.row[sub.prop] | commonFilter(sub.filter) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<component
|
||||
:is="item.subcomponent"
|
||||
v-if="item.subcomponent"
|
||||
:key="scope.row.id"
|
||||
:itemProp="item.prop"
|
||||
:inject-data="{ ...scope.row, ...item }"
|
||||
@emitData="emitData" />
|
||||
<span v-else>
|
||||
{{ scope.row[item.prop] | commonFilter(item.filter) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格底部加号 -->
|
||||
<el-button
|
||||
v-if="addButtonShow"
|
||||
class="addButton"
|
||||
icon="el-icon-plus"
|
||||
@click="emitButtonClick">
|
||||
{{ addButtonShow }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BaseTable',
|
||||
filters: {
|
||||
commonFilter: (source, filterType = (a) => a) => {
|
||||
return filterType(source);
|
||||
},
|
||||
},
|
||||
props: {
|
||||
cancelBorder: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
cancelPageFixed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
tableData: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
tableProps: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0,
|
||||
},
|
||||
pageWidth: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 70,
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0,
|
||||
},
|
||||
selectWidth: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0,
|
||||
},
|
||||
addButtonShow: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedBox: new Array(100).fill(true),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
renderTableHeadList() {
|
||||
return this.tableProps.filter((item, index) => {
|
||||
return this.selectedBox[index];
|
||||
});
|
||||
},
|
||||
renderData() {
|
||||
return this.tableData.map((item, index) => {
|
||||
return {
|
||||
...item,
|
||||
_pageIndex: (this.page - 1) * this.limit + index + 1,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
beforeMount() {
|
||||
this.selectedBox = new Array(100).fill(true);
|
||||
if (this.id === 'table2') {
|
||||
this.$nextTick(() => {
|
||||
document
|
||||
.getElementById('table2')
|
||||
.style.setProperty('--zg-height', '53px');
|
||||
});
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
document
|
||||
.getElementById(this.id)
|
||||
.style.setProperty('--zg-height', '40px');
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
currentChange(newVal, oldVal) {
|
||||
this.$emit('current-change', { newVal, oldVal });
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.$emit('selection-change', val);
|
||||
},
|
||||
emitData(val) {
|
||||
this.$emit('emitFun', val);
|
||||
},
|
||||
emitButtonClick() {
|
||||
this.$emit('emitButtonClick');
|
||||
},
|
||||
setCurrent(name, index) {
|
||||
let _this = this;
|
||||
let obj = _this.$refs[name].data[index];
|
||||
_this.$refs[name].setCurrentRow(obj);
|
||||
},
|
||||
doLayout(name) {
|
||||
this.$refs[name].doLayout();
|
||||
},
|
||||
setRowStyle(v) {
|
||||
if (v.rowIndex % 2 === 0) {
|
||||
return {
|
||||
background: 'rgba(2, 13, 45, 0.3)',
|
||||
height: 30 + 'px',
|
||||
lineHeight: 30 + 'px',
|
||||
padding: 0,
|
||||
fontSize: 14 + 'px',
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
background: 'rgba(0,106,205,0.1)',
|
||||
height: 30 + 'px',
|
||||
lineHeight: 30 + 'px',
|
||||
padding: 0,
|
||||
fontSize: 14 + 'px',
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
:root {
|
||||
--zg-height: 40px; /* 定义变量 */
|
||||
}
|
||||
|
||||
.baseTable .show-col-btn {
|
||||
margin-right: 5px;
|
||||
line-height: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
.baseTable .el-icon-refresh {
|
||||
cursor: pointer;
|
||||
}
|
||||
.baseTable >>> .el-table .el-table__cell {
|
||||
padding: 0;
|
||||
height: var(--zg-height);
|
||||
}
|
||||
.baseTable >>> .el-table {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
.baseTable >>> .el-table::before,
|
||||
.el-table--group::after,
|
||||
.el-table--border::after {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
.baseTable >>> .el-table--border::after,
|
||||
.el-table--group::after,
|
||||
.el-table::before {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
.baseTable >>> .el-table__header-wrapper,
|
||||
.baseTable >>> .el-table__body-wrapper {
|
||||
border: none; /* 去掉表头和表体的外边框 */
|
||||
}
|
||||
|
||||
.baseTable >>> .el-table__row td {
|
||||
border-top: none; /* 去掉单元格的上边框(横线) */
|
||||
border-bottom: none; /* 去掉单元格的下边框(横线) */
|
||||
border-right: 2px solid #305887; /* 设置单元格的右边框(竖线) */
|
||||
}
|
||||
|
||||
.baseTable >>> .el-table__row:last-child td {
|
||||
border-bottom: none; /* 去掉最后一行的下边框 */
|
||||
}
|
||||
|
||||
/* 去掉最后一列的右边框 */
|
||||
.baseTable >>> .el-table__row td:last-child {
|
||||
border-right: transparent;
|
||||
}
|
||||
|
||||
.baseTable >>> .el-table__header th {
|
||||
border-top: none; /* 去掉表头的上边框 */
|
||||
border-bottom: none; /* 去掉表头的下边框 */
|
||||
border-right: 2px solid #305887; /* 设置表头的右边框(竖线) */
|
||||
border-left: none; /* 设置表头的右边框(竖线) */
|
||||
}
|
||||
.baseTable >>> .el-table__header th:nth-last-child(2) {
|
||||
border-right: none;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
@import '~@/styles/index.scss';
|
||||
.baseTable {
|
||||
.el-table tr {
|
||||
background: transparent;
|
||||
}
|
||||
.el-table__row:hover > td {
|
||||
background-color: rgba(79, 114, 136, 0.29) !important;
|
||||
}
|
||||
|
||||
.el-table__row--striped:hover > td {
|
||||
background-color: rgba(79, 114, 136, 0.29) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
307
src/views/dashboard/deepDashboard/BarChart.vue
Normal file
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<div :class="className" :style="{ height: height, width: width }" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
require('echarts/theme/macarons'); // echarts theme
|
||||
import resize from '../mixins/resize';
|
||||
import { max } from 'moment';
|
||||
|
||||
const animationDuration = 6000;
|
||||
|
||||
export default {
|
||||
mixins: [resize],
|
||||
props: {
|
||||
echartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: 'chart',
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '380px',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initChart();
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.chart) {
|
||||
return;
|
||||
}
|
||||
this.chart.dispose();
|
||||
this.chart = null;
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999',
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 100,
|
||||
left: '2%',
|
||||
right: '3%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
legend: {
|
||||
data: [
|
||||
'产量',
|
||||
{
|
||||
name: '成本',
|
||||
icon: 'path://M1255.570286 1024a512 512 0 1 0 0-1024 512 512 0 0 0 0 1024z m641.609143-512c0 37.376-3.072 74.020571-8.923429 109.714286h393.069714c59.611429 0 107.958857-49.152 107.958857-109.714286s-48.274286-109.714286-107.958857-109.714286h-393.069714c5.851429 35.693714 8.923429 72.338286 8.923429 109.714286zM156.745143 621.714286h453.12a672.914286 672.914286 0 0 1 0-219.428572H156.745143C97.133714 402.285714 48.786286 451.437714 48.786286 512s48.274286 109.714286 107.958857 109.714286z',
|
||||
},
|
||||
{
|
||||
name: '良品率',
|
||||
icon: 'path://M1255.570286 1024a512 512 0 1 0 0-1024 512 512 0 0 0 0 1024z m641.609143-512c0 37.376-3.072 74.020571-8.923429 109.714286h393.069714c59.611429 0 107.958857-49.152 107.958857-109.714286s-48.274286-109.714286-107.958857-109.714286h-393.069714c5.851429 35.693714 8.923429 72.338286 8.923429 109.714286zM156.745143 621.714286h453.12a672.914286 672.914286 0 0 1 0-219.428572H156.745143C97.133714 402.285714 48.786286 451.437714 48.786286 512s48.274286 109.714286 107.958857 109.714286z',
|
||||
},
|
||||
],
|
||||
itemWidth: 18,
|
||||
itemHeight: 18,
|
||||
textStyle: {
|
||||
fontSize: 18,
|
||||
color: '#DFF1FE',
|
||||
},
|
||||
top: 15,
|
||||
right: 20,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: this.echartData.map((item) => {
|
||||
return item.time;
|
||||
}),
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '单位/片',
|
||||
min: 0,
|
||||
position: 'left',
|
||||
alignTicks: true,
|
||||
axisLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#b6c1e1',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '%',
|
||||
max: 100,
|
||||
min: 0,
|
||||
minInterval: 1,
|
||||
position: 'right',
|
||||
axisLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#b6c1e1',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '万元',
|
||||
min: 0,
|
||||
position: 'right',
|
||||
alignTicks: true,
|
||||
offset: 40,
|
||||
axisLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#b6c1e1',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '产量',
|
||||
type: 'bar',
|
||||
barWidth: '14px',
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.out).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' 片';
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#5CB7FF' },
|
||||
{ offset: 1, color: '#364BFE' },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '成本',
|
||||
type: 'line',
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
yAxisIndex: 2,
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.price).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' 万元';
|
||||
},
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#FF1295',
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#FF1295',
|
||||
borderWidth: 1, // 圆点边框宽度(可选)
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.2,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#FF1295',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'transparent',
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '良品率',
|
||||
type: 'line',
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
yAxisIndex: 1,
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.ratio).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' %';
|
||||
},
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#12FFF5',
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#12FFF5',
|
||||
borderWidth: 1, // 圆点边框宽度(可选)
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.2,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#12FFF5',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'transparent',
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if (this.chart) {
|
||||
this.chart.setOption(option);
|
||||
} else {
|
||||
this.chart = echarts.init(this.$el, 'macarons');
|
||||
this.chart.setOption(option);
|
||||
}
|
||||
window.addEventListener('resize', () => {
|
||||
this.chart.resize();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
497
src/views/dashboard/deepDashboard/index.vue
Normal file
@@ -0,0 +1,497 @@
|
||||
<template>
|
||||
<div
|
||||
id="wholePlantContainerB"
|
||||
ref="wholePlantContainerB"
|
||||
style="width: 100%; height: 100%">
|
||||
<div
|
||||
id="wholePlantContainer"
|
||||
ref="wholePlantContainer"
|
||||
class="wholePlantBoard"
|
||||
style="
|
||||
position: absolute;
|
||||
transform-origin: 16px 8px;
|
||||
font-size: 16px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
"
|
||||
:style="{ transform: 'scale(' + scaleNum + ')' }">
|
||||
<KHeader
|
||||
:isFullScreen="isFullScreen"
|
||||
@screenfullChange="screenfullChange"
|
||||
topTitle="自贡深加工成本看板" />
|
||||
<div class="main-body">
|
||||
<div style="flex: 1" class="bz25-2 bz-top">
|
||||
<div class="topNum">{{ Number(topData.yestodaySum).toFixed(1) }}</div>
|
||||
<div class="topText">昨日总成本/万元</div>
|
||||
</div>
|
||||
<div style="flex: 1" class="bz25-3 bz-top">
|
||||
<div class="topNum" style="margin-left: 50px">
|
||||
{{ Number(topData.yestodayRatio).toFixed(1) }}%
|
||||
</div>
|
||||
<div class="topText">昨日良品率</div>
|
||||
</div>
|
||||
<div style="flex: 1" class="bz25-4 bz-top">
|
||||
<div class="topNum">{{ Number(topData.yestodayOut).toFixed(1) }}</div>
|
||||
<div class="topText">昨日深加工产量/万m²</div>
|
||||
</div>
|
||||
<div style="flex: 1" class="bz25-7 bz-top">
|
||||
<div class="topNum">{{ Number(topData.monthSum).toFixed(1) }}</div>
|
||||
<div class="topText">本月深加工成本/万元</div>
|
||||
</div>
|
||||
<div style="flex: 1" class="bz25-8 bz-top">
|
||||
<div class="topNum">{{ Number(topData.monthAreaCost).toFixed(1) }}</div>
|
||||
<div class="topText">本月每平米总成本/元</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-body">
|
||||
<div style="flex: 2" class="middle middle1">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="line" />
|
||||
各产线产量及良品率
|
||||
<span style="float: right">产量单位:万平方米</span>
|
||||
</div>
|
||||
<base-table
|
||||
:id="'table3'"
|
||||
style="margin: 5px 12px 12px 12px"
|
||||
:table-props="tableProps3"
|
||||
:table-data="tableData3"
|
||||
:height="230"></base-table>
|
||||
</div>
|
||||
<div style="flex: 1" class="middle middle2">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="energy" />
|
||||
能源统计
|
||||
</div>
|
||||
<base-table
|
||||
:id="'table1'"
|
||||
style="margin: 5px 12px 12px 12px"
|
||||
:table-props="tableProps1"
|
||||
:table-data="tableData1"
|
||||
:height="230"></base-table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-body">
|
||||
<div style="flex: 2" class="footer footer1">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="costchart" />
|
||||
近12个月成本 · 产量趋势
|
||||
</div>
|
||||
<bar-chart
|
||||
ref="chartRef"
|
||||
style="margin-top: -50px"
|
||||
:echart-data="echartData"></bar-chart>
|
||||
</div>
|
||||
<div style="flex: 1" class="footer footer2">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="cost" />
|
||||
成本及产量统计
|
||||
</div>
|
||||
<base-table
|
||||
:id="'table2'"
|
||||
style="margin: 5px 12px 12px 12px"
|
||||
:table-props="tableProps2"
|
||||
:table-data="tableData2"
|
||||
:height="310"></base-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import KHeader from '../components/Header';
|
||||
import screenfull from 'screenfull';
|
||||
import { debounce } from '@/utils/debounce';
|
||||
import baseTable from '../components/baseTable.vue';
|
||||
import BarChart from './BarChart.vue';
|
||||
import interval from './interval.vue';
|
||||
|
||||
const tableProps1 = [
|
||||
{
|
||||
prop: 'title',
|
||||
label: '',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'elec',
|
||||
label: '电消耗量/kwh',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'yure',
|
||||
label: '余热发电量/kwh',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'elecPrice',
|
||||
label: '总价/万元',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
];
|
||||
|
||||
const tableProps2 = [
|
||||
{
|
||||
prop: 'title',
|
||||
label: '',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'priceD',
|
||||
label: '成本/万元',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'outD',
|
||||
label: '产量/万m²',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'ratioD',
|
||||
label: '良品率',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
];
|
||||
const tableProps3 = [
|
||||
{
|
||||
prop: 'title',
|
||||
label: '',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: '1',
|
||||
label: '产线1',
|
||||
subcomponent: interval,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: '2',
|
||||
label: '产线2',
|
||||
subcomponent: interval,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: '3',
|
||||
label: '产线3',
|
||||
subcomponent: interval,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: '4',
|
||||
label: '产线4',
|
||||
subcomponent: interval,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: '5',
|
||||
label: '产线5',
|
||||
subcomponent: interval,
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
export default {
|
||||
name: '',
|
||||
components: {
|
||||
KHeader,
|
||||
baseTable,
|
||||
BarChart,
|
||||
},
|
||||
// provide() {
|
||||
// return {
|
||||
// resizeChart: null,
|
||||
// };
|
||||
// },
|
||||
data() {
|
||||
return {
|
||||
isFullScreen: false,
|
||||
scaleNum: 0.8,
|
||||
url: process.env.VUE_APP_WS_API,
|
||||
websock: '',
|
||||
topData: {},
|
||||
imgUrl: {
|
||||
o2: require('@/views/dashboard/assets/O2.png'),
|
||||
no: require('@/views/dashboard/assets/NO.png'),
|
||||
so2: require('@/views/dashboard/assets/SO2.png'),
|
||||
no2: require('@/views/dashboard/assets/NO2.png'),
|
||||
},
|
||||
tableProps1,
|
||||
tableData1: [],
|
||||
tableProps2,
|
||||
tableData2: [],
|
||||
tableProps3,
|
||||
tableData3: [],
|
||||
echartData: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
this.initWebSocket();
|
||||
},
|
||||
destroy() {
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
this.boxReset();
|
||||
window.addEventListener('resize', this.boxReset);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('resize', this.boxReset);
|
||||
},
|
||||
methods: {
|
||||
boxReset() {
|
||||
debounce(() => {
|
||||
this.resetSize();
|
||||
}, 300)();
|
||||
},
|
||||
change() {
|
||||
this.isFullScreen = screenfull.isFullscreen;
|
||||
},
|
||||
init() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.on('change', this.change);
|
||||
}
|
||||
},
|
||||
destroy() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.off('change', this.change);
|
||||
}
|
||||
},
|
||||
// 全屏
|
||||
screenfullChange() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.toggle(this.$refs.wholePlantContainerB);
|
||||
},
|
||||
resetSize() {
|
||||
let wholePlantContainerBox = document.getElementById(
|
||||
'wholePlantContainer'
|
||||
);
|
||||
let rw = parseFloat(window.innerWidth);
|
||||
let rh = parseFloat(window.innerHeight);
|
||||
let bw = parseFloat(wholePlantContainerBox.style.width);
|
||||
let bh = parseFloat(wholePlantContainerBox.style.height);
|
||||
let wx = 0;
|
||||
let hx = 0;
|
||||
if (screenfull.isFullscreen) {
|
||||
wx = rw / bw;
|
||||
hx = rh / bh;
|
||||
} else {
|
||||
if (this.$store.state.app.sidebar.opened) {
|
||||
wx = (rw - 280) / bw;
|
||||
hx = (rh - 116) / bh;
|
||||
} else {
|
||||
wx = (rw - 85) / bw;
|
||||
hx = (rh - 116) / bh;
|
||||
}
|
||||
}
|
||||
this.scaleNum = wx;
|
||||
},
|
||||
initWebSocket() {
|
||||
// 初始化weosocket
|
||||
const path = `${this.url}/websocket/message?userId=3`;
|
||||
this.websock = new WebSocket(path);
|
||||
this.websock.onmessage = this.websocketonmessage;
|
||||
this.websock.onopen = this.websocketonopen;
|
||||
this.websock.onerror = this.websocketonerror;
|
||||
this.websock.onclose = this.websocketclose;
|
||||
},
|
||||
|
||||
websocketonopen() {
|
||||
// 连接建立之后执行send方法发送数据
|
||||
this.websocketsend();
|
||||
},
|
||||
websocketonerror() {
|
||||
// 连接建立失败重连
|
||||
this.initWebSocket();
|
||||
},
|
||||
websocketonmessage(e) {
|
||||
let dataJson = JSON.parse(e.data);
|
||||
console.log(dataJson);
|
||||
// 数据接收
|
||||
if ('DeepState' in dataJson) {
|
||||
this.topData = dataJson.DeepState;
|
||||
}
|
||||
if ('DeepEnergyTableList' in dataJson) {
|
||||
this.tableData1 = dataJson.DeepEnergyTableList;
|
||||
}
|
||||
if ('DeepCostTableList' in dataJson) {
|
||||
this.tableData2 = dataJson.DeepCostTableList;
|
||||
}
|
||||
if ('DeepPdTables' in dataJson) {
|
||||
this.tableData3 = dataJson.DeepPdTables;
|
||||
}
|
||||
if ('DeepCostTrendList' in dataJson) {
|
||||
this.echartData = dataJson.DeepCostTrendList;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.chartRef.initChart();
|
||||
});
|
||||
}
|
||||
},
|
||||
websocketsend(val) {
|
||||
// 数据发送
|
||||
this.websock.send(val);
|
||||
},
|
||||
websocketclose(e) {
|
||||
// 关闭
|
||||
console.log('断开连接', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.wholePlantBoard {
|
||||
background: url(../assets/bg1.png) no-repeat;
|
||||
background-size: cover;
|
||||
background-position: 0 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.main-body {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
.bz-top {
|
||||
text-align: center;
|
||||
}
|
||||
.bz25-2 {
|
||||
background: url(../assets/bz25-d-1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-3 {
|
||||
background: url(../assets/bz25-d-2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-4 {
|
||||
background: url(../assets/bz25-d-3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-7 {
|
||||
background: url(../assets/bz25-d-4.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-8 {
|
||||
background: url(../assets/bz25-d-5.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.topNum {
|
||||
font-weight: 600;
|
||||
font-size: 44px;
|
||||
color: #ffffff;
|
||||
line-height: 43px;
|
||||
font-style: normal;
|
||||
margin-top: 50px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
.topText {
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
color: #95caff;
|
||||
line-height: 20px;
|
||||
font-style: normal;
|
||||
margin-top: 3px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
.title {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-weight: 400;
|
||||
font-size: 22px;
|
||||
color: #ffffff;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.middle {
|
||||
height: 322px;
|
||||
}
|
||||
.middle1 {
|
||||
background: url(../assets/1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.middle2 {
|
||||
background: url(../assets/2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.yanqi {
|
||||
width: 275px;
|
||||
height: 108px;
|
||||
background: url(../assets/yanqi.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
text-align: center;
|
||||
}
|
||||
.content {
|
||||
height: 108px;
|
||||
}
|
||||
.imageClass {
|
||||
width: 40px;
|
||||
height: 30px;
|
||||
display: block;
|
||||
margin: 8px auto;
|
||||
}
|
||||
.middle2-left {
|
||||
font-size: 18px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 17px;
|
||||
letter-spacing: 5px;
|
||||
width: 110px;
|
||||
padding-top: 12px;
|
||||
padding-left: 12px;
|
||||
float: left;
|
||||
}
|
||||
.middle2-right {
|
||||
font-weight: 600;
|
||||
font-size: 38px;
|
||||
color: #ffffff;
|
||||
line-height: 106px;
|
||||
}
|
||||
.footer {
|
||||
height: 410px;
|
||||
}
|
||||
.footer1 {
|
||||
background: url(../assets/3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.footer2 {
|
||||
background: url(../assets/4.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 402px;
|
||||
}
|
||||
</style>
|
||||
51
src/views/dashboard/deepDashboard/interval.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<!--
|
||||
* @Author: zwq
|
||||
* @Date: 2023-08-03 14:09:18
|
||||
* @LastEditors: zwq
|
||||
* @LastEditTime: 2025-03-06 16:32:48
|
||||
* @Description:
|
||||
-->
|
||||
<template>
|
||||
<div class="tableInner" style="display: flex">
|
||||
<div style="flex: 3; border-right: 2px solid #305887">
|
||||
{{
|
||||
list['out' + list.prop]
|
||||
? Number(list['out' + list.prop]).toFixed(1)
|
||||
: '-'
|
||||
}}
|
||||
</div>
|
||||
<div style="flex: 2">
|
||||
{{
|
||||
list['ratio' + list.prop]
|
||||
? Number(list['ratio' + list.prop]).toFixed(1)
|
||||
: '-'
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
injectData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: this.injectData,
|
||||
};
|
||||
},
|
||||
created() {},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.tableInner {
|
||||
border: none;
|
||||
padding: 0;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
308
src/views/dashboard/rawDashboard/BarChart.vue
Normal file
@@ -0,0 +1,308 @@
|
||||
<template>
|
||||
<div :class="className" :style="{ height: height, width: width }" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
require('echarts/theme/macarons'); // echarts theme
|
||||
import resize from '../mixins/resize';
|
||||
import { max } from 'moment';
|
||||
|
||||
const animationDuration = 6000;
|
||||
|
||||
export default {
|
||||
mixins: [resize],
|
||||
props: {
|
||||
echartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: 'chart',
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '380px',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initChart();
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.chart) {
|
||||
return;
|
||||
}
|
||||
this.chart.dispose();
|
||||
this.chart = null;
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999',
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 100,
|
||||
left: '2%',
|
||||
right: '3%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
legend: {
|
||||
data: [
|
||||
'产量',
|
||||
{
|
||||
name: '成本',
|
||||
icon: 'path://M1255.570286 1024a512 512 0 1 0 0-1024 512 512 0 0 0 0 1024z m641.609143-512c0 37.376-3.072 74.020571-8.923429 109.714286h393.069714c59.611429 0 107.958857-49.152 107.958857-109.714286s-48.274286-109.714286-107.958857-109.714286h-393.069714c5.851429 35.693714 8.923429 72.338286 8.923429 109.714286zM156.745143 621.714286h453.12a672.914286 672.914286 0 0 1 0-219.428572H156.745143C97.133714 402.285714 48.786286 451.437714 48.786286 512s48.274286 109.714286 107.958857 109.714286z',
|
||||
},
|
||||
{
|
||||
name: '良品率',
|
||||
icon: 'path://M1255.570286 1024a512 512 0 1 0 0-1024 512 512 0 0 0 0 1024z m641.609143-512c0 37.376-3.072 74.020571-8.923429 109.714286h393.069714c59.611429 0 107.958857-49.152 107.958857-109.714286s-48.274286-109.714286-107.958857-109.714286h-393.069714c5.851429 35.693714 8.923429 72.338286 8.923429 109.714286zM156.745143 621.714286h453.12a672.914286 672.914286 0 0 1 0-219.428572H156.745143C97.133714 402.285714 48.786286 451.437714 48.786286 512s48.274286 109.714286 107.958857 109.714286z',
|
||||
},
|
||||
],
|
||||
itemWidth: 18,
|
||||
itemHeight: 18,
|
||||
textStyle: {
|
||||
fontSize: 18,
|
||||
color: '#DFF1FE',
|
||||
},
|
||||
top: 15,
|
||||
right: 20,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: this.echartData.map((item) => {
|
||||
return item.time;
|
||||
}),
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '单位/片',
|
||||
min: 0,
|
||||
position: 'left',
|
||||
alignTicks: true,
|
||||
axisLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#b6c1e1',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '%',
|
||||
max: 100,
|
||||
min: 0,
|
||||
minInterval: 1,
|
||||
position: 'right',
|
||||
axisLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#b6c1e1',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '万元',
|
||||
min: 0,
|
||||
position: 'right',
|
||||
alignTicks: true,
|
||||
offset: 40,
|
||||
axisLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'solid',
|
||||
color: '#97B3FF', // 左边线的颜色
|
||||
width: '1', // 坐标线的宽度
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#b6c1e1',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '产量',
|
||||
type: 'bar',
|
||||
barWidth: '14px',
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.out).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' 片';
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#5CB7FF' },
|
||||
{ offset: 1, color: '#364BFE' },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '成本',
|
||||
type: 'line',
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
yAxisIndex: 2,
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.price).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' 万元';
|
||||
},
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#FF1295',
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#FF1295',
|
||||
borderWidth: 1, // 圆点边框宽度(可选)
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.2,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#FF1295',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'transparent',
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '良品率',
|
||||
type: 'line',
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
yAxisIndex: 1,
|
||||
data: this.echartData.map((item) => {
|
||||
return Number(item.ratio).toFixed(1);
|
||||
}),
|
||||
animationDuration,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' %';
|
||||
},
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#12FFF5',
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#12FFF5',
|
||||
borderWidth: 1, // 圆点边框宽度(可选)
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.2,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#12FFF5',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'transparent',
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
if (this.chart) {
|
||||
this.chart.setOption(option);
|
||||
} else {
|
||||
this.chart = echarts.init(this.$el, 'macarons');
|
||||
this.chart.setOption(option);
|
||||
}
|
||||
window.addEventListener('resize', () => {
|
||||
this.chart.resize();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
507
src/views/dashboard/rawDashboard/index.vue
Normal file
@@ -0,0 +1,507 @@
|
||||
<template>
|
||||
<div
|
||||
id="wholePlantContainerB"
|
||||
ref="wholePlantContainerB"
|
||||
style="width: 100%; height: 100%">
|
||||
<div
|
||||
id="wholePlantContainer"
|
||||
ref="wholePlantContainer"
|
||||
class="wholePlantBoard"
|
||||
style="
|
||||
position: absolute;
|
||||
transform-origin: 16px 8px;
|
||||
font-size: 16px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
"
|
||||
:style="{ transform: 'scale(' + scaleNum + ')' }">
|
||||
<KHeader
|
||||
:isFullScreen="isFullScreen"
|
||||
@screenfullChange="screenfullChange"
|
||||
topTitle="自贡原片成本看板" />
|
||||
<div class="main-body">
|
||||
<div style="flex: 1" class="bz25-2 bz-top">
|
||||
<div class="topNum">{{ Number(topData.yestodaySum).toFixed(1) }}</div>
|
||||
<div class="topText">昨日总成本/万元</div>
|
||||
</div>
|
||||
<div style="flex: 1" class="bz25-3 bz-top">
|
||||
<div class="topNum" style="margin-left: 50px">{{ Number(topData.yestodayRatio).toFixed(1) }}%</div>
|
||||
<div class="topText">昨日良品率</div>
|
||||
</div>
|
||||
<div style="flex: 1" class="bz25-5 bz-top">
|
||||
<div class="topNum">{{ Number(topData.yestodayMat).toFixed(1) }}</div>
|
||||
<div class="topText">昨日原料成本/万元</div>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1" class="bz25-4 bz-top">
|
||||
<div class="topNum">{{ Number(topData.monthOut).toFixed(1) }}</div>
|
||||
<div class="topText">本月原片产量/万m²</div>
|
||||
</div>
|
||||
<div style="flex: 1" class="bz25-7 bz-top">
|
||||
<div class="topNum">{{ Number(topData.monthMat).toFixed(1) }}</div>
|
||||
<div class="topText">本月原料成本/万元</div>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1" class="bz25-8 bz-top">
|
||||
<div class="topNum">{{ Number(topData.monthAreaCost).toFixed(1) }}</div>
|
||||
<div class="topText">本月每平米总成本/元</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-body">
|
||||
<div style="flex: 2" class="middle middle1">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="energy" />
|
||||
能源统计
|
||||
</div>
|
||||
<base-table
|
||||
:id="'table1'"
|
||||
style="margin: 5px 12px 12px 12px"
|
||||
:table-props="tableProps1"
|
||||
:table-data="tableData1"
|
||||
:height="230"></base-table>
|
||||
</div>
|
||||
<div style="flex: 1" class="middle middle2">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="yanqi" />
|
||||
烟气处理
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 10px 30px;
|
||||
gap: 12px;
|
||||
">
|
||||
<div class="yanqi" style="width: 566px;">
|
||||
<div class="content middle2-left" style="margin-left: 50px;width: 210px;">
|
||||
<el-image class="imageClass" :src="imgUrl.so2"></el-image>
|
||||
二氧化硫 排放浓度
|
||||
</div>
|
||||
<div class="content middle2-right">
|
||||
{{ Number(topData.so2).toFixed(1) }}
|
||||
<span style="font-size: 14px; line-height: 43px">mg/m³</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="yanqi">
|
||||
<div class="content middle2-left">
|
||||
<el-image class="imageClass" :src="imgUrl.fc"></el-image>
|
||||
粉尘排放
|
||||
</div>
|
||||
<div class="content middle2-right">
|
||||
{{ Number(topData.fc).toFixed(1) }}
|
||||
<span style="font-size: 14px; line-height: 43px">mg/m³</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="yanqi">
|
||||
<div class="content middle2-left">
|
||||
<el-image class="imageClass" :src="imgUrl.no"></el-image>
|
||||
氮氧化物 排放浓度
|
||||
</div>
|
||||
<div class="content middle2-right">
|
||||
{{ Number(topData.no).toFixed(1) }}
|
||||
<span style="font-size: 14px; line-height: 43px">mg/m³</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-body">
|
||||
<div style="flex: 2" class="footer footer1">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="costchart" />
|
||||
近12个月成本 · 产量趋势
|
||||
</div>
|
||||
<bar-chart
|
||||
ref="chartRef"
|
||||
style="margin-top: -50px"
|
||||
:echart-data="echartData"></bar-chart>
|
||||
</div>
|
||||
<div style="flex: 1" class="footer footer2">
|
||||
<div class="title">
|
||||
<svg-icon icon-class="cost" />
|
||||
成本及产量统计
|
||||
</div>
|
||||
<base-table
|
||||
:id="'table2'"
|
||||
style="margin: 5px 12px 12px 12px"
|
||||
:table-props="tableProps2"
|
||||
:table-data="tableData2"
|
||||
:height="310"></base-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import KHeader from '../components/Header';
|
||||
import screenfull from 'screenfull';
|
||||
import { debounce } from '@/utils/debounce';
|
||||
import baseTable from '../components/baseTable.vue';
|
||||
import BarChart from './BarChart.vue';
|
||||
|
||||
const tableProps1 = [
|
||||
{
|
||||
prop: 'title',
|
||||
label: '',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'elec',
|
||||
label: '电消耗量',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'elecPrice',
|
||||
label: '电总价',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'gas',
|
||||
label: '气消耗量',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'gasPrice',
|
||||
label: '气总价',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'price',
|
||||
label: '能源总价',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
];
|
||||
|
||||
const tableProps2 = [
|
||||
{
|
||||
prop: 'title',
|
||||
label: '',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'priceO',
|
||||
label: '成本/万元',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'outO',
|
||||
label: '产量/万m²',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
{
|
||||
prop: 'ratioO',
|
||||
label: '良品率',
|
||||
filter: (val) => (val != null ? Number(val).toFixed(1) : '-'),
|
||||
},
|
||||
];
|
||||
export default {
|
||||
name: '',
|
||||
components: {
|
||||
KHeader,
|
||||
baseTable,
|
||||
BarChart,
|
||||
},
|
||||
// provide() {
|
||||
// return {
|
||||
// resizeChart: null,
|
||||
// };
|
||||
// },
|
||||
data() {
|
||||
return {
|
||||
isFullScreen: false,
|
||||
scaleNum: 0.8,
|
||||
url: process.env.VUE_APP_WS_API,
|
||||
websock: '',
|
||||
topData: {},
|
||||
imgUrl: {
|
||||
fc: require('@/views/dashboard/assets/fc.png'),
|
||||
no: require('@/views/dashboard/assets/NO.png'),
|
||||
so2: require('@/views/dashboard/assets/SO2.png'),
|
||||
},
|
||||
tableProps1,
|
||||
tableData1: [],
|
||||
tableProps2,
|
||||
tableData2: [],
|
||||
echartData: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
this.initWebSocket();
|
||||
},
|
||||
destroy() {
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
this.boxReset();
|
||||
window.addEventListener('resize', this.boxReset);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('resize', this.boxReset);
|
||||
},
|
||||
methods: {
|
||||
boxReset() {
|
||||
debounce(() => {
|
||||
this.resetSize();
|
||||
}, 300)();
|
||||
},
|
||||
change() {
|
||||
this.isFullScreen = screenfull.isFullscreen;
|
||||
},
|
||||
init() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.on('change', this.change);
|
||||
}
|
||||
},
|
||||
destroy() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.off('change', this.change);
|
||||
}
|
||||
},
|
||||
// 全屏
|
||||
screenfullChange() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
screenfull.toggle(this.$refs.wholePlantContainerB);
|
||||
},
|
||||
resetSize() {
|
||||
let wholePlantContainerBox = document.getElementById(
|
||||
'wholePlantContainer'
|
||||
);
|
||||
let rw = parseFloat(window.innerWidth);
|
||||
let rh = parseFloat(window.innerHeight);
|
||||
let bw = parseFloat(wholePlantContainerBox.style.width);
|
||||
let bh = parseFloat(wholePlantContainerBox.style.height);
|
||||
let wx = 0;
|
||||
let hx = 0;
|
||||
if (screenfull.isFullscreen) {
|
||||
wx = rw / bw;
|
||||
hx = rh / bh;
|
||||
} else {
|
||||
if (this.$store.state.app.sidebar.opened) {
|
||||
wx = (rw - 280) / bw;
|
||||
hx = (rh - 116) / bh;
|
||||
} else {
|
||||
wx = (rw - 85) / bw;
|
||||
hx = (rh - 116) / bh;
|
||||
}
|
||||
}
|
||||
this.scaleNum = wx;
|
||||
},
|
||||
|
||||
initWebSocket() {
|
||||
// 初始化weosocket
|
||||
const path = `${this.url}/websocket/message?userId=2`;
|
||||
this.websock = new WebSocket(path);
|
||||
this.websock.onmessage = this.websocketonmessage;
|
||||
this.websock.onopen = this.websocketonopen;
|
||||
this.websock.onerror = this.websocketonerror;
|
||||
this.websock.onclose = this.websocketclose;
|
||||
},
|
||||
|
||||
websocketonopen() {
|
||||
// 连接建立之后执行send方法发送数据
|
||||
this.websocketsend();
|
||||
},
|
||||
websocketonerror() {
|
||||
// 连接建立失败重连
|
||||
this.initWebSocket();
|
||||
},
|
||||
websocketonmessage(e) {
|
||||
let dataJson = JSON.parse(e.data);
|
||||
console.log(dataJson);
|
||||
// 数据接收
|
||||
if ('OriginState' in dataJson) {
|
||||
this.topData = dataJson.OriginState;
|
||||
}
|
||||
if ('OriginEnergyTableList' in dataJson) {
|
||||
this.tableData1 = dataJson.OriginEnergyTableList;
|
||||
}
|
||||
if ('OriginCostTableList' in dataJson) {
|
||||
this.tableData2 = dataJson.OriginCostTableList;
|
||||
}
|
||||
if ('OriginCostTrendList' in dataJson) {
|
||||
this.echartData = dataJson.OriginCostTrendList;
|
||||
this.$nextTick(()=>{
|
||||
this.$refs.chartRef.initChart();
|
||||
})
|
||||
}
|
||||
},
|
||||
websocketsend(val) {
|
||||
// 数据发送
|
||||
this.websock.send(val);
|
||||
},
|
||||
websocketclose(e) {
|
||||
// 关闭
|
||||
console.log('断开连接', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.wholePlantBoard {
|
||||
background: url(../assets/bg1.png) no-repeat;
|
||||
background-size: cover;
|
||||
background-position: 0 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.main-body {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
.bz-top {
|
||||
text-align: center;
|
||||
}
|
||||
.bz25-2 {
|
||||
background: url(../assets/bz25-2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-3 {
|
||||
background: url(../assets/bz25-3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-4 {
|
||||
background: url(../assets/bz25-4.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-5 {
|
||||
background: url(../assets/bz25-5.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-7 {
|
||||
background: url(../assets/bz25-7.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.bz25-8 {
|
||||
background: url(../assets/bz25-8.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 147px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
.topNum {
|
||||
font-weight: 600;
|
||||
font-size: 44px;
|
||||
color: #ffffff;
|
||||
line-height: 43px;
|
||||
font-style: normal;
|
||||
margin-top: 50px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
.topText {
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
color: #95caff;
|
||||
line-height: 20px;
|
||||
font-style: normal;
|
||||
margin-top: 3px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
.title {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-weight: 400;
|
||||
font-size: 22px;
|
||||
color: #ffffff;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.middle {
|
||||
height: 322px;
|
||||
}
|
||||
.middle1 {
|
||||
background: url(../assets/1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.middle2 {
|
||||
background: url(../assets/2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.yanqi {
|
||||
width: 275px;
|
||||
height: 108px;
|
||||
background: url(../assets/yanqi.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.content {
|
||||
height: 108px;
|
||||
}
|
||||
.imageClass {
|
||||
width: 40px;
|
||||
height: 30px;
|
||||
display: block;
|
||||
margin: 8px auto;
|
||||
}
|
||||
.middle2-left {
|
||||
font-size: 18px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 17px;
|
||||
letter-spacing: 5px;
|
||||
width: 110px;
|
||||
padding-top: 12px;
|
||||
padding-left: 12px;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.middle2-right {
|
||||
font-weight: 600;
|
||||
font-size: 35px;
|
||||
color: #ffffff;
|
||||
line-height: 106px;
|
||||
}
|
||||
.footer {
|
||||
height: 410px;
|
||||
}
|
||||
.footer1 {
|
||||
background: url(../assets/3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
.footer2 {
|
||||
background: url(../assets/4.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
height: 402px;
|
||||
}
|
||||
</style>
|
||||
46
src/views/dashboard/utils/index.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import moment from "moment";
|
||||
export const switchShowTime = (type) => {
|
||||
let nowTime = new Date
|
||||
let startTime = ''
|
||||
let endTime = ''
|
||||
let currentYear = nowTime.getFullYear();
|
||||
let startYear = null
|
||||
switch(type) {
|
||||
case '日':
|
||||
let hour = nowTime.getHours()
|
||||
if (hour > 6) {
|
||||
startTime = moment(nowTime).format('yyyy.MM.DD')+' 7点'
|
||||
endTime = moment(moment(nowTime)+86400000).format('yyyy.MM.DD')+' 7点'
|
||||
}else{
|
||||
endTime = moment(nowTime).format('yyyy.MM.DD')+' 7点'
|
||||
startTime = moment(moment(nowTime)-86400000).format('yyyy.MM.DD')+' 7点'
|
||||
}
|
||||
return startTime+'-'+endTime
|
||||
case '周':
|
||||
let timestamp = nowTime- 24 * 60 * 60 * 1000
|
||||
endTime = moment(timestamp).format('yyyy.MM.DD')
|
||||
startTime = moment(timestamp-24 * 60 * 60 * 1000 * 6).format('yyyy.MM.DD')
|
||||
return startTime+'-'+endTime
|
||||
case '月':
|
||||
let day = 29;
|
||||
let lastMonth = nowTime.getMonth() === 0 ? 12 : nowTime.getMonth();
|
||||
if (lastMonth === 2) {
|
||||
day = isLeapYear(currentYear) ? 29 : 28;
|
||||
}
|
||||
if (lastMonth === 12) {
|
||||
startYear = currentYear - 1
|
||||
}else{
|
||||
startYear = currentYear
|
||||
}
|
||||
startTime = startYear+'.'+lastMonth+'.'+day
|
||||
endTime = currentYear+'.'+(nowTime.getMonth()+1)+'.28'
|
||||
return startTime+'-'+endTime
|
||||
default:// 年
|
||||
startTime = (currentYear - 1)+'.12.29'
|
||||
endTime = currentYear+'.12.28'
|
||||
return startTime+'-'+endTime
|
||||
}
|
||||
}
|
||||
const isLeapYear = (year) => {
|
||||
return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
|
||||
}
|
||||
204
src/views/dashboard/utils/websocket.js
Normal file
@@ -0,0 +1,204 @@
|
||||
// websocket实例
|
||||
let wsObj = null;
|
||||
// ws连接地址
|
||||
let wsUrl = null;
|
||||
// let userId = null;
|
||||
// 是否执行重连 true/不执行 ; false/执行
|
||||
let lockReconnect = false;
|
||||
// 重连定时器
|
||||
let wsCreateHandler = null;
|
||||
// 连接成功,执行回调函数
|
||||
let messageCallback = null;
|
||||
// 连接失败,执行回调函数
|
||||
let errorCallback = null;
|
||||
// 发送给后台的数据
|
||||
let sendDatas = {};
|
||||
|
||||
|
||||
/**
|
||||
* 发起websocket请求函数
|
||||
* @param {string} url ws连接地址
|
||||
* @param {Object} agentData 传给后台的参数
|
||||
* @param {function} successCallback 接收到ws数据,对数据进行处理的回调函数
|
||||
* @param {function} errCallback ws连接错误的回调函数
|
||||
*/
|
||||
export const connectWebsocket = (url, agentData, successCallback, errCallback) => {
|
||||
wsUrl = url;
|
||||
createWebSoket();
|
||||
messageCallback = successCallback;
|
||||
errorCallback = errCallback;
|
||||
sendDatas = agentData;
|
||||
}
|
||||
|
||||
// 手动关闭websocket (这里手动关闭会执行onclose事件)
|
||||
export const closeWebsocket = () => {
|
||||
if (wsObj) {
|
||||
writeToScreen('手动关闭websocket');
|
||||
wsObj.close() // 关闭websocket
|
||||
// wsObj.onclose() // 关闭websocket(如果上面的关闭不生效就加上这一条)
|
||||
// 关闭重连
|
||||
lockReconnect = true;
|
||||
wsCreateHandler && clearTimeout(wsCreateHandler);
|
||||
// 关闭心跳检查
|
||||
heartCheck.stop();
|
||||
}
|
||||
}
|
||||
|
||||
// 创建ws函数
|
||||
const createWebSoket = () => {
|
||||
if (typeof (WebSocket) === 'undefined') {
|
||||
writeToScreen("您的浏览器不支持WebSocket,无法获取数据");
|
||||
return false
|
||||
}
|
||||
// const host = window.location.host;
|
||||
// userId = GetQueryString("userId");
|
||||
// wsUrl = "ws://" + host + "/websoket" + userId;
|
||||
|
||||
try {
|
||||
wsObj = new WebSocket(wsUrl);
|
||||
initWsEventHandle();
|
||||
} catch (e) {
|
||||
writeToScreen("连接异常,开始重连");
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
const initWsEventHandle = () => {
|
||||
try {
|
||||
// 连接成功
|
||||
wsObj.onopen = (event) => {
|
||||
onWsOpen(event);
|
||||
heartCheck.start();
|
||||
}
|
||||
|
||||
// 监听服务器端返回的信息
|
||||
wsObj.onmessage = (event) => {
|
||||
onWsMessage(event);
|
||||
heartCheck.start();
|
||||
}
|
||||
|
||||
wsObj.onclose = (event) => {
|
||||
writeToScreen('onclose执行关闭事件');
|
||||
onWsClose(event);
|
||||
}
|
||||
|
||||
wsObj.onerror = (event) => {
|
||||
writeToScreen('onerror执行error事件,开始重连');
|
||||
onWsError(event);
|
||||
reconnect();
|
||||
}
|
||||
} catch (err) {
|
||||
writeToScreen('绑定事件没有成功,开始重连');
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
const onWsOpen = (event) => {
|
||||
writeToScreen('CONNECT');
|
||||
// // 客户端与服务器端通信
|
||||
// wsObj.send('我发送消息给服务端');
|
||||
// 添加状态判断,当为OPEN时,发送消息
|
||||
if (wsObj.readyState === wsObj.OPEN) { // wsObj.OPEN = 1
|
||||
// 发给后端的数据需要字符串化
|
||||
wsObj.send(JSON.stringify(sendDatas));
|
||||
}
|
||||
if (wsObj.readyState === wsObj.CLOSED) { // wsObj.CLOSED = 3
|
||||
writeToScreen('wsObj.readyState=3, ws连接异常,开始重连');
|
||||
reconnect();
|
||||
errorCallback(event);
|
||||
}
|
||||
}
|
||||
const onWsMessage = (event) => {
|
||||
const jsonStr = event.data;
|
||||
writeToScreen('onWsMessage接收到服务器的数据: ', jsonStr);
|
||||
messageCallback(jsonStr);
|
||||
}
|
||||
const onWsClose = (event) => {
|
||||
writeToScreen('DISCONNECT');
|
||||
// e.code === 1000 表示正常关闭。 无论为何目的而创建, 该链接都已成功完成任务。
|
||||
// e.code !== 1000 表示非正常关闭。
|
||||
console.log('onclose event: ', event)
|
||||
if (event && event.code !== 1000) {
|
||||
writeToScreen('非正常关闭');
|
||||
errorCallback(event);
|
||||
// 如果不是手动关闭,这里的重连会执行;如果调用了手动关闭函数,这里重连不会执行
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
const onWsError = (event) => {
|
||||
writeToScreen('onWsError: ', event.data);
|
||||
errorCallback(event);
|
||||
}
|
||||
|
||||
const writeToScreen = (massage) => {
|
||||
console.log(massage);
|
||||
}
|
||||
|
||||
// 重连函数
|
||||
const reconnect = () => {
|
||||
if (lockReconnect) {
|
||||
return;
|
||||
}
|
||||
writeToScreen('3秒后重连');
|
||||
lockReconnect = true;
|
||||
// 没连接上会一直重连,设置延迟避免请求过多
|
||||
wsCreateHandler && clearTimeout(wsCreateHandler);
|
||||
wsCreateHandler = setTimeout(() => {
|
||||
writeToScreen('重连...' + wsUrl);
|
||||
createWebSoket();
|
||||
lockReconnect = false;
|
||||
writeToScreen('重连完成');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 从浏览器地址中获取对应参数
|
||||
const GetQueryString = (name) => {
|
||||
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
|
||||
// 获取url中 ? 符后的字符串并正则匹配
|
||||
let r = window.location.search.substr(1).match(reg);
|
||||
let context = "";
|
||||
r && (context = r[2]);
|
||||
reg = null;
|
||||
r = null;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
// 心跳检查(看看websocket是否还在正常连接中)
|
||||
let heartCheck = {
|
||||
timeout: 15000,
|
||||
timeoutObj: null,
|
||||
serverTimeoutObj: null,
|
||||
// 重启
|
||||
reset() {
|
||||
clearTimeout(this.timeoutObj);
|
||||
clearTimeout(this.serverTimeoutObj);
|
||||
this.start();
|
||||
},
|
||||
// 停止
|
||||
stop() {
|
||||
clearTimeout(this.timeoutObj);
|
||||
clearTimeout(this.serverTimeoutObj);
|
||||
},
|
||||
// 开启定时器
|
||||
start() {
|
||||
this.timeoutObj && clearTimeout(this.timeoutObj);
|
||||
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
|
||||
// 15s之内如果没有收到后台的消息,则认为是连接断开了,需要重连
|
||||
this.timeoutObj = setTimeout(() => {
|
||||
writeToScreen("心跳检查,发送ping到后台");
|
||||
try {
|
||||
const datas = { ping: true };
|
||||
wsObj.send(JSON.stringify(datas));
|
||||
} catch (err) {
|
||||
writeToScreen("发送ping异常");
|
||||
}
|
||||
console.log("内嵌定时器this.serverTimeoutObj: ", this.serverTimeoutObj)
|
||||
// 内嵌定时器
|
||||
this.serverTimeoutObj = setTimeout(() => {
|
||||
writeToScreen("没有收到后台的数据,重新连接");
|
||||
reconnect();
|
||||
}, this.timeout)
|
||||
}, this.timeout)
|
||||
}
|
||||
}
|
||||
160
src/views/dashboard/utils/wsInterface.js
Normal file
@@ -0,0 +1,160 @@
|
||||
import { connectWebsocket, closeWebsocket } from './websocket'
|
||||
import store from "@/store";
|
||||
|
||||
// 创建dcs链接
|
||||
export const getDcsMsg = () => {
|
||||
const userId = 'dcsmsg' + new Date().getTime()
|
||||
connectWebsocket(
|
||||
// 测试地址
|
||||
'ws://10.70.180.10:8081/xc-screen/websocket/'+userId,
|
||||
// 传递给后台的数据
|
||||
'',
|
||||
// 成功拿到后台返回的数据的回调函数
|
||||
(data) => {
|
||||
console.log('dcs成功的回调函数, 接收到的data数据: ', data)
|
||||
let msgData = JSON.parse(data)
|
||||
if (msgData == null) return;
|
||||
switch (msgData?.type) {
|
||||
case "FanFrequencyInfo": {
|
||||
store.dispatch({type: "websocket/setFanFrequencyInfo", payload:msgData.data.FanFrequencyInfo})
|
||||
break;
|
||||
}
|
||||
case "KilnInfo": {
|
||||
store.dispatch({type: "websocket/setKilnInfo", payload: msgData.data.kilnInfo})
|
||||
break;
|
||||
}
|
||||
case "GasInfo": {
|
||||
store.dispatch({type: "websocket/setGasInfo", payload: msgData.data})
|
||||
break;
|
||||
}
|
||||
case "SumGasInfo": {
|
||||
store.dispatch({type: "websocket/setSumGasInfo", payload: msgData.data})
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
},
|
||||
// websocket连接失败的回调函数
|
||||
(err) => {
|
||||
console.log('失败的回调函数', err)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 创建mes链接
|
||||
export const getMesMsg = () => {
|
||||
const sj = new Date().getTime()
|
||||
// ISRA
|
||||
// connectWebsocket(
|
||||
// // 测试地址
|
||||
// 'ws://10.70.2.2:8080/websocket/message?userId=KI'+sj,
|
||||
// // 传递给后台的数据
|
||||
// '',
|
||||
// // 成功拿到后台返回的数据的回调函数
|
||||
// (data) => {
|
||||
// console.log('mes ISRA成功的回调函数, 接收到的data数据: ', data)
|
||||
// let msgData = JSON.parse(data)
|
||||
// if (msgData == null) return;
|
||||
// switch (msgData?.type) {
|
||||
// case "israKiln": {
|
||||
// store.dispatch({type: "websocket/setIsraKiln", payload:msgData.detData.dayStatistic})
|
||||
// break;
|
||||
// }
|
||||
// // case "KilnInfo": {
|
||||
// // // store.dispatch({type: "websocket/setKilnInfo", payload: msgData.data.kilnInfo})
|
||||
// // break;
|
||||
// // }
|
||||
// default:
|
||||
// }
|
||||
// },
|
||||
// // websocket连接失败的回调函数
|
||||
// (err) => {
|
||||
// console.log('失败的回调函数', err)
|
||||
// }
|
||||
// )
|
||||
|
||||
// // 原料 MA
|
||||
// connectWebsocket(
|
||||
// // 测试地址
|
||||
// 'ws://10.70.2.2:8080/websocket/message?userId=MA'+sj,
|
||||
// // 传递给后台的数据
|
||||
// '',
|
||||
// // 成功拿到后台返回的数据的回调函数
|
||||
// (data) => {
|
||||
// console.log('mes 原料成功的回调函数, 接收到的data数据: ', data)
|
||||
// let msgData = JSON.parse(data)
|
||||
// if (msgData == null) return;
|
||||
// switch (msgData?.type) {
|
||||
// case "material": {
|
||||
// store.dispatch({type: "websocket/setMaterial", payload:msgData.data})
|
||||
// break;
|
||||
// }
|
||||
// // case "KilnInfo": {
|
||||
// // // store.dispatch({type: "websocket/setKilnInfo", payload: msgData.data.kilnInfo})
|
||||
// // break;
|
||||
// // }
|
||||
// default:
|
||||
// }
|
||||
// },
|
||||
// // websocket连接失败的回调函数
|
||||
// (err) => {
|
||||
// console.log('失败的回调函数', err)
|
||||
// }
|
||||
// )
|
||||
|
||||
// 能耗 EN
|
||||
// connectWebsocket(
|
||||
// // 测试地址
|
||||
// 'ws://10.70.2.2:8080/websocket/message?userId=ENERGY'+sj,
|
||||
// // 传递给后台的数据
|
||||
// '',
|
||||
// // 成功拿到后台返回的数据的回调函数
|
||||
// (data) => {
|
||||
// console.log('mes 能耗成功的回调函数, 接收到的data数据: ', data)
|
||||
// let msgData = JSON.parse(data)
|
||||
// if (msgData == null) return;
|
||||
// switch (msgData?.type) {
|
||||
// case "EnergyInfo": {
|
||||
// store.dispatch({type: "websocket/setEnergyInfo", payload:msgData.data})
|
||||
// break;
|
||||
// }
|
||||
// default:
|
||||
// }
|
||||
// },
|
||||
// // websocket连接失败的回调函数
|
||||
// (err) => {
|
||||
// console.log('失败的回调函数', err)
|
||||
// }
|
||||
// )
|
||||
|
||||
// 烟气 GAS
|
||||
connectWebsocket(
|
||||
// 测试地址
|
||||
'ws://10.70.2.2:8080/websocket/message?userId=GAS'+sj,
|
||||
// 传递给后台的数据
|
||||
'',
|
||||
// 成功拿到后台返回的数据的回调函数
|
||||
(data) => {
|
||||
console.log('mes 烟气成功的回调函数, 接收到的data数据: ', data)
|
||||
let msgData = JSON.parse(data)
|
||||
if (msgData == null) return;
|
||||
switch (msgData?.type) {
|
||||
case "exhaustGas": {
|
||||
store.dispatch({type: "websocket/setExhaustGasInfo", payload:msgData.realtime})
|
||||
store.dispatch({type: "websocket/setExhaustGasChart", payload:{
|
||||
dayTrend: msgData.dayTrend,
|
||||
weekTrend: msgData.weekTrend,
|
||||
monthTrend: msgData.monthTrend,
|
||||
yearTrend: msgData.yearTrend,
|
||||
}})
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
},
|
||||
// websocket连接失败的回调函数
|
||||
(err) => {
|
||||
console.log('失败的回调函数', err)
|
||||
}
|
||||
)
|
||||
}
|
||||