修改产线图
This commit is contained in:
116
src/views/base/dataBoard/components/CenterBottomL.vue
Normal file
116
src/views/base/dataBoard/components/CenterBottomL.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div class='centerBottomL'>
|
||||
<div class='title'>
|
||||
<svg-icon icon-class="dataBoard3" class='icon'/>
|
||||
<span>本月数据</span>
|
||||
</div>
|
||||
<div class='dataBox' style='top:50px'>
|
||||
<p>
|
||||
<span class='text'>总投入片数</span>
|
||||
<span class='precent' :class='{precentR:monthData?.inputNumChange>=0,precentG:monthData?.inputNumChange<0}'>{{monthData?.inputNumChange || '-'}}%</span>
|
||||
<img v-show='monthData?.inputNumChange<0' src="../../../../assets/images/dataBoard/arrDown.png" alt="" width='5' height='15'>
|
||||
<img v-show='monthData?.inputNumChange>=0' src="../../../../assets/images/dataBoard/arrUp.png" alt="" width='5' height='15'>
|
||||
</p>
|
||||
<p class='num'>{{monthData?.inputNum ? formatThousands(monthData.inputNum) : '-'}}</p>
|
||||
</div>
|
||||
<div class='dataBox'style='top:180px'>
|
||||
<p>
|
||||
<span class='text'>总生产片数</span>
|
||||
<span class='precent' :class='{precentR:monthData?.outputNumChange>=0,precentG:monthData?.outputNumChange<0}'>{{monthData?.outputNumChange || '-'}}%</span>
|
||||
<img v-show='monthData?.outputNumChange<0' src="../../../../assets/images/dataBoard/arrDown.png" alt="" width='5' height='15'>
|
||||
<img v-show='monthData?.outputNumChange>=0' src="../../../../assets/images/dataBoard/arrUp.png" alt="" width='5' height='15'>
|
||||
</p>
|
||||
<p class='num'>{{monthData?.outputNum ? formatThousands(monthData.outputNum) : '-'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CenterBottomL',
|
||||
props: {
|
||||
dataObj: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dataObj(val) {
|
||||
val.monthAndLastMonth && val.monthAndLastMonth.forEach(item => {
|
||||
if (item.dataType === "本月") {
|
||||
this.monthData = item
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
monthData:{}
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.centerBottomL {
|
||||
width: 337px;
|
||||
height: 332px;
|
||||
background: url('../../../../assets/images/dataBoard/center-bottom.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
left: 440px;
|
||||
bottom:23px;
|
||||
.title {
|
||||
margin: 7px 0 0 15px;
|
||||
.icon {
|
||||
width: 33px;
|
||||
height: 33px;
|
||||
margin-right: 5px;
|
||||
vertical-align:middle;
|
||||
margin-top: 5px;
|
||||
}
|
||||
span {
|
||||
font-size: 24px;
|
||||
color: #52FFF1;
|
||||
line-height: 24px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
}
|
||||
.dataBox {
|
||||
width: 290px;
|
||||
height: 135px;
|
||||
background: url('../../../../assets/images/dataBoard/numberBox.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
padding:22px 0 0 16px;
|
||||
left: 24px;
|
||||
p{
|
||||
margin: 0;
|
||||
}
|
||||
.text {
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
color: #FFFFFF;
|
||||
letter-spacing: 2px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.precent {
|
||||
font-size: 18px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.precentR {
|
||||
color: #FF271D;
|
||||
}
|
||||
.precentG {
|
||||
color: #34F716;
|
||||
}
|
||||
.num {
|
||||
font-weight: 500;
|
||||
font-size: 38px;
|
||||
color: #FFFFFF;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
100
src/views/base/dataBoard/components/CenterBottomR.vue
Normal file
100
src/views/base/dataBoard/components/CenterBottomR.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div class='centerBottomR'>
|
||||
<div class='title'>
|
||||
<svg-icon icon-class="dataBoard3" class='icon'/>
|
||||
<span>上月数据</span>
|
||||
</div>
|
||||
<div class='dataBox' style='top:50px'>
|
||||
<p>
|
||||
<span class='text'>总投入片数</span>
|
||||
</p>
|
||||
<p class='num'>{{lastMonthData?.inputNum ? formatThousands(lastMonthData.inputNum) : '-'}}</p>
|
||||
</div>
|
||||
<div class='dataBox'style='top:180px'>
|
||||
<p>
|
||||
<span class='text'>总生产片数</span>
|
||||
</p>
|
||||
<p class='num'>{{lastMonthData?.outputNum ? formatThousands(lastMonthData.outputNum) : '-'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CenterBottomR',
|
||||
props: {
|
||||
dataObj: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dataObj(val) {
|
||||
val.monthAndLastMonth && val.monthAndLastMonth.forEach(item => {
|
||||
if (item.dataType === "上月") {
|
||||
this.lastMonthData = item
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lastMonthData:{}
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.centerBottomR {
|
||||
width: 337px;
|
||||
height: 332px;
|
||||
background: url('../../../../assets/images/dataBoard/center-bottom.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
left: 791px;
|
||||
bottom:23px;
|
||||
.title {
|
||||
margin: 7px 0 0 15px;
|
||||
.icon {
|
||||
width: 33px;
|
||||
height: 33px;
|
||||
margin-right: 5px;
|
||||
vertical-align:middle;
|
||||
margin-top: 5px;
|
||||
}
|
||||
span {
|
||||
font-size: 24px;
|
||||
color: #52FFF1;
|
||||
line-height: 24px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
}
|
||||
.dataBox {
|
||||
width: 290px;
|
||||
height: 135px;
|
||||
background: url('../../../../assets/images/dataBoard/numberBox.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
padding:22px 0 0 16px;
|
||||
left: 24px;
|
||||
p{
|
||||
margin: 0;
|
||||
}
|
||||
.text {
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
color: #FFFFFF;
|
||||
letter-spacing: 2px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.num {
|
||||
font-weight: 500;
|
||||
font-size: 38px;
|
||||
color: #FFFFFF;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
352
src/views/base/dataBoard/components/CenterTop.vue
Normal file
352
src/views/base/dataBoard/components/CenterTop.vue
Normal file
@@ -0,0 +1,352 @@
|
||||
<template>
|
||||
<div ref="centerTopBox" class='centerTopBox'>
|
||||
<div>
|
||||
<video src="/static/videos/01.webm" muted autoplay loop class='videoStyle'></video>
|
||||
<div
|
||||
class='eqTipBox'
|
||||
v-show='showTooltip'
|
||||
:style="'left:'+tooltipStyle.left+'px;top:'+tooltipStyle.top+'px;'"
|
||||
>
|
||||
<p><span class='eqTipTitle'>设备名称:</span><span class='eqTipNum'>{{eqTipMsg.name}}</span></p>
|
||||
<p><span class='eqTipTitle'>进口数量:</span><span class='eqTipNum'>{{eqTipMsg.input}}</span></p>
|
||||
<p><span class='eqTipTitle'>出口数量:</span><span class='eqTipNum'>{{eqTipMsg.output}}</span></p>
|
||||
<p><span class='eqTipTitle'>报警状态:</span>
|
||||
<span class='eqTipNum'>
|
||||
<img v-show='eqTipMsg.alarm' :src='dotY' width='16'/>
|
||||
<img v-show='!eqTipMsg.alarm' :src='dotG' width='16'/>
|
||||
{{eqTipMsg.alarm?'报警':'未报警'}}
|
||||
</span>
|
||||
</p>
|
||||
<p><span class='eqTipTitle'>在线状态:</span>
|
||||
<span class='eqTipNum'>
|
||||
<img v-show='eqTipMsg.status' :src='dotG' width='16'/>
|
||||
<img v-show='!eqTipMsg.status' :src='dotR' width='16'/>
|
||||
{{eqTipMsg.status?'在线':'离线'}}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<!-- 设备 -->
|
||||
<div class='eqBox'>
|
||||
<!-- line-从上到下-从右往左 -->
|
||||
<span
|
||||
v-for='(item,index) in eqList'
|
||||
:key='index'
|
||||
:style="'width:'+item.w+'px;height:'+item.h+'px;left:'+item.l+'px;top:'+item.t+'px'"
|
||||
@mouseenter="handleMouseEnter(item, $event)"
|
||||
@mouseleave="handleMouseLeave"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class='centerTopTopBox'>
|
||||
<div style='display: inline-block;'>
|
||||
<img src="../../../../assets/images/dataBoard/centerNumB.png" alt="" width='203'>
|
||||
<p class='num'>{{dataObj?.productRate || '-'}}%</p>
|
||||
<p class='title'>成品率</p>
|
||||
</div>
|
||||
<div style='display: inline-block;'>
|
||||
<img src="../../../../assets/images/dataBoard/centerNumY.png" alt="" width='261'>
|
||||
<p class='num' style='width: 260px;padding-left: 20px;'>{{dataObj?.todayProduct ? formatThousands(dataObj.todayProduct) : '-'}}</p>
|
||||
<p class='title' style='color:#FFB625'>今日产量</p>
|
||||
</div>
|
||||
<div style='display: inline-block;'>
|
||||
<img src="../../../../assets/images/dataBoard/centerNumY.png" alt="" width='261'>
|
||||
<p class='num' style='width: 260px;padding-left: 20px;'>{{dataObj?.monthProduct ? formatThousands(dataObj.monthProduct) : '-'}}</p>
|
||||
<p class='title' style='color:#FFB625'>本月产量</p>
|
||||
</div>
|
||||
<div style='display: inline-block;'>
|
||||
<img src="../../../../assets/images/dataBoard/centerNumB.png" alt="" width='203'>
|
||||
<p class='num'>{{dataObj?.alarmNum ? formatThousands(dataObj.alarmNum) : '-'}}</p>
|
||||
<p class='title'>设备报警数</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'CenterTop',
|
||||
data() {
|
||||
return {
|
||||
showTooltip:false,
|
||||
tooltipStyle: {
|
||||
left: 0,
|
||||
top: 0
|
||||
},
|
||||
dotY:require('../../../../assets/images/dataBoard/dotY.png'),
|
||||
dotR:require('../../../../assets/images/dataBoard/dotR.png'),
|
||||
dotG:require('../../../../assets/images/dataBoard/dotG.png'),
|
||||
eqList:[
|
||||
{name:'磨边机1',id:'1',w:70,h:18,l:830,t:160},
|
||||
{name:'磨边机2',id:'2',w:70,h:18,l:830,t:183},
|
||||
{name:'磨边机3',id:'3',w:70,h:18,l:832,t:206},
|
||||
{name:'清洗机1',id:'4',w:30,h:15,l:798,t:160},
|
||||
{name:'清洗机2',id:'5',w:30,h:15,l:798,t:183},
|
||||
{name:'清洗机3',id:'6',w:30,h:15,l:800,t:206},
|
||||
{name:'打孔机1',id:'7',w:13,h:12,l:730,t:163},
|
||||
{name:'打孔机2',id:'8',w:13,h:12,l:730,t:187},
|
||||
{name:'打孔机3',id:'9',w:13,h:12,l:730,t:210},
|
||||
{name:'清洗机1',id:'10',w:32,h:15,l:665,t:160},
|
||||
{name:'清洗机2',id:'11',w:32,h:15,l:665,t:183},
|
||||
{name:'清洗机3',id:'12',w:32,h:15,l:665,t:206},
|
||||
{name:'丝印机1',id:'13',w:30,h:12,l:605,t:163},
|
||||
{name:'丝印机2',id:'14',w:30,h:12,l:605,t:187},
|
||||
{name:'丝印机3',id:'15',w:30,h:12,l:605,t:210},
|
||||
{name:'固化炉1',id:'16',w:37,h:12,l:558,t:163},
|
||||
{name:'固化炉2',id:'17',w:37,h:12,l:558,t:187},
|
||||
{name:'固化炉3',id:'18',w:37,h:12,l:558,t:210},
|
||||
{name:'钢化炉',id:'19',w:75,h:15,l:382,t:209},
|
||||
{name:'清洗机1',id:'20',w:30,h:15,l:228,t:173},
|
||||
{name:'清洗机2',id:'21',w:30,h:15,l:228,t:206},
|
||||
{name:'铺纸机1',id:'22',w:18,h:15,l:188,t:175},
|
||||
{name:'铺纸机2',id:'23',w:18,h:15,l:188,t:206},
|
||||
|
||||
{name:'磨边机1',id:'24',w:70,h:18,l:832,t:233},
|
||||
{name:'磨边机2',id:'25',w:70,h:18,l:833,t:257},
|
||||
{name:'磨边机3',id:'26',w:70,h:18,l:834,t:281},
|
||||
{name:'清洗机1',id:'27',w:30,h:15,l:800,t:233},
|
||||
{name:'清洗机2',id:'28',w:30,h:15,l:801,t:257},
|
||||
{name:'清洗机3',id:'29',w:30,h:15,l:802,t:281},
|
||||
{name:'打孔机1',id:'30',w:13,h:12,l:731,t:240},
|
||||
{name:'打孔机2',id:'31',w:13,h:12,l:731,t:262},
|
||||
{name:'打孔机3',id:'32',w:13,h:12,l:731,t:285},
|
||||
{name:'清洗机1',id:'33',w:32,h:15,l:666,t:234},
|
||||
{name:'清洗机2',id:'34',w:32,h:15,l:666,t:258},
|
||||
{name:'清洗机3',id:'35',w:32,h:15,l:666,t:282},
|
||||
{name:'丝印机1',id:'36',w:30,h:12,l:605,t:238},
|
||||
{name:'丝印机2',id:'37',w:30,h:12,l:605,t:262},
|
||||
{name:'丝印机3',id:'38',w:30,h:12,l:605,t:286},
|
||||
{name:'固化炉1',id:'39',w:37,h:12,l:558,t:238},
|
||||
{name:'固化炉2',id:'40',w:37,h:12,l:558,t:262},
|
||||
{name:'固化炉3',id:'41',w:37,h:12,l:558,t:286},
|
||||
{name:'钢化炉',id:'42',w:75,h:15,l:382,t:238},
|
||||
{name:'清洗机1',id:'43',w:30,h:15,l:228,t:234},
|
||||
{name:'清洗机2',id:'44',w:30,h:15,l:228,t:267},
|
||||
{name:'铺纸机1',id:'45',w:18,h:15,l:187,t:234},
|
||||
{name:'铺纸机2',id:'46',w:18,h:15,l:186,t:267},
|
||||
|
||||
{name:'磨边机1',id:'47',w:70,h:18,l:834,t:318},
|
||||
{name:'磨边机2',id:'48',w:70,h:18,l:834,t:342},
|
||||
{name:'清洗机1',id:'49',w:30,h:15,l:802,t:319},
|
||||
{name:'清洗机2',id:'50',w:30,h:15,l:802,t:342},
|
||||
{name:'打孔机1',id:'51',w:13,h:12,l:731,t:324},
|
||||
{name:'打孔机2',id:'52',w:13,h:12,l:731,t:348},
|
||||
{name:'清洗机1',id:'53',w:32,h:15,l:666,t:320},
|
||||
{name:'清洗机2',id:'54',w:32,h:15,l:666,t:342},
|
||||
{name:'丝印机1',id:'55',w:30,h:12,l:605,t:324},
|
||||
{name:'丝印机2',id:'56',w:30,h:12,l:605,t:348},
|
||||
{name:'镀膜机1',id:'57',w:20,h:15,l:553,t:322},
|
||||
{name:'镀膜机2',id:'58',w:20,h:15,l:553,t:346},
|
||||
{name:'固化炉1',id:'59',w:37,h:12,l:506,t:324},
|
||||
{name:'固化炉2',id:'60',w:37,h:12,l:506,t:347},
|
||||
{name:'钢化炉',id:'61',w:75,h:15,l:340,t:346},
|
||||
{name:'清洗机1',id:'62',w:30,h:15,l:240,t:343},
|
||||
{name:'铺纸机1',id:'63',w:18,h:15,l:200,t:343},
|
||||
{name:'铺纸机2',id:'64',w:18,h:15,l:170,t:343},
|
||||
|
||||
{name:'磨边机1',id:'65',w:70,h:18,l:838,t:380},
|
||||
{name:'磨边机2',id:'66',w:70,h:18,l:838,t:405},
|
||||
{name:'磨边机3',id:'67',w:70,h:18,l:839,t:428},
|
||||
{name:'清洗机1',id:'68',w:30,h:15,l:804,t:380},
|
||||
{name:'清洗机2',id:'69',w:30,h:15,l:805,t:405},
|
||||
{name:'清洗机3',id:'70',w:30,h:15,l:806,t:427},
|
||||
{name:'镀膜机1',id:'71',w:20,h:15,l:707,t:381},
|
||||
{name:'镀膜机2',id:'72',w:20,h:15,l:707,t:407},
|
||||
{name:'镀膜机3',id:'73',w:20,h:15,l:707,t:429},
|
||||
{name:'固化炉1',id:'74',w:37,h:12,l:660,t:383},
|
||||
{name:'固化炉2',id:'75',w:37,h:12,l:660,t:409},
|
||||
{name:'固化炉3',id:'76',w:37,h:12,l:660,t:431},
|
||||
{name:'镀膜机1',id:'77',w:20,h:15,l:605,t:382},
|
||||
{name:'镀膜机2',id:'78',w:20,h:15,l:605,t:408},
|
||||
{name:'镀膜机3',id:'79',w:20,h:15,l:605,t:430},
|
||||
{name:'固化炉1',id:'80',w:37,h:12,l:557,t:383},
|
||||
{name:'固化炉2',id:'81',w:37,h:12,l:557,t:409},
|
||||
{name:'固化炉3',id:'82',w:37,h:12,l:557,t:431},
|
||||
{name:'钢化炉',id:'83',w:75,h:15,l:379,t:381},
|
||||
{name:'清洗机1',id:'84',w:30,h:15,l:220,t:379},
|
||||
{name:'清洗机2',id:'85',w:30,h:18,l:220,t:410},
|
||||
{name:'铺纸机1',id:'86',w:18,h:15,l:180,t:381},
|
||||
{name:'铺纸机2',id:'87',w:18,h:15,l:180,t:414},
|
||||
|
||||
{name:'磨边机1',id:'88',w:70,h:18,l:817,t:465},
|
||||
{name:'磨边机2',id:'89',w:70,h:18,l:817,t:488},
|
||||
{name:'磨边机3',id:'90',w:70,h:18,l:819,t:512},
|
||||
{name:'清洗机1',id:'91',w:30,h:15,l:784,t:462},
|
||||
{name:'清洗机2',id:'92',w:30,h:15,l:784,t:488},
|
||||
{name:'清洗机3',id:'93',w:30,h:15,l:785,t:512},
|
||||
{name:'镀膜机1',id:'94',w:20,h:15,l:685,t:466},
|
||||
{name:'镀膜机2',id:'95',w:20,h:15,l:685,t:490},
|
||||
{name:'镀膜机3',id:'96',w:20,h:15,l:685,t:513},
|
||||
{name:'固化炉1',id:'97',w:37,h:12,l:638,t:468},
|
||||
{name:'固化炉2',id:'98',w:37,h:12,l:638,t:491},
|
||||
{name:'固化炉3',id:'99',w:37,h:12,l:638,t:514},
|
||||
{name:'镀膜机1',id:'100',w:20,h:15,l:584,t:468},
|
||||
{name:'镀膜机2',id:'101',w:20,h:15,l:584,t:490},
|
||||
{name:'镀膜机3',id:'102',w:20,h:15,l:584,t:513},
|
||||
{name:'固化炉1',id:'103',w:37,h:12,l:535,t:468},
|
||||
{name:'固化炉2',id:'104',w:37,h:12,l:535,t:492},
|
||||
{name:'固化炉3',id:'105',w:37,h:12,l:535,t:514},
|
||||
{name:'钢化炉',id:'106',w:75,h:15,l:344,t:513},
|
||||
{name:'清洗机1',id:'107',w:30,h:18,l:185,t:473},
|
||||
{name:'清洗机2',id:'108',w:30,h:18,l:185,t:511},
|
||||
{name:'铺纸机1',id:'109',w:18,h:15,l:144,t:475},
|
||||
{name:'铺纸机2',id:'110',w:18,h:15,l:144,t:511}
|
||||
],
|
||||
eqTipMsg:{
|
||||
name:'',
|
||||
input:null,
|
||||
output:null,
|
||||
alarm:'未报警',
|
||||
status:'在线'
|
||||
}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
scaleNum: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
dataObj: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scaleNum(val) {
|
||||
this.scaleNum = val
|
||||
},
|
||||
dataObj(val) {
|
||||
val.equipmentDets && val.equipmentDets.forEach(item => {
|
||||
this.eqList.forEach(eq => {
|
||||
if (eq.id == item.id) {
|
||||
eq.name = item.name
|
||||
eq.input = item.input
|
||||
eq.output = item.output
|
||||
eq.alarm = item.isError
|
||||
eq.status = item.isRun
|
||||
}
|
||||
})
|
||||
})
|
||||
console.log(this.eqList)
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
// 鼠标hover事件
|
||||
handleMouseEnter(item, event) {
|
||||
this.showTooltip = true;
|
||||
this.eqTipMsg.name = item.name;
|
||||
this.eqTipMsg.input = item.input;
|
||||
this.eqTipMsg.output = item.output;
|
||||
this.eqTipMsg.alarm = item.alarm;
|
||||
this.eqTipMsg.status = item.status;
|
||||
this.updateTooltipPosition(event);
|
||||
},
|
||||
handleMouseLeave() {
|
||||
this.showTooltip = false;
|
||||
},
|
||||
updateTooltipPosition(event) {
|
||||
const rect = this.$refs.centerTopBox.getBoundingClientRect()
|
||||
const offset = 15;
|
||||
const tooltipWidth = 230*this.scaleNum;
|
||||
const tooltipHeight = 170*this.scaleNum;
|
||||
const startX = rect.left;
|
||||
const startY = rect.top;
|
||||
const endX = rect.width;
|
||||
const endY = rect.height;
|
||||
let posX = event.clientX-startX + offset;
|
||||
let posY = event.clientY-startY + offset;
|
||||
if (posX + tooltipWidth > endX) {
|
||||
posX = event.clientX-startX - tooltipWidth - offset;
|
||||
}
|
||||
if (posY + tooltipHeight > endY) {
|
||||
posY = event.clientY -startY - tooltipHeight - offset;
|
||||
}
|
||||
this.tooltipStyle.left = posX/this.scaleNum;
|
||||
this.tooltipStyle.top = posY/this.scaleNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
p{
|
||||
margin: 0;
|
||||
}
|
||||
.centerTopBox {
|
||||
width: 1041px;
|
||||
height: 600px;
|
||||
background: url('../../../../assets/images/dataBoard/center-top.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
left: 440px;
|
||||
top:113px;
|
||||
overflow: hidden;
|
||||
.videoStyle {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
position: absolute;
|
||||
left:-440px;
|
||||
top:-113px;
|
||||
}
|
||||
.eqTipBox {
|
||||
width: 230px;
|
||||
height: 170px;
|
||||
background: url('../../../../assets/images/dataBoard/eq-tip.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
padding-top: 10px;
|
||||
z-index: 1;
|
||||
span{
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
color: #FFFFFF;
|
||||
letter-spacing: 1px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.eqTipTitle {
|
||||
width: 112px;
|
||||
height: 30px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.eqTipNum {
|
||||
width: 112px;
|
||||
height: 30px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.eqBox {
|
||||
span{
|
||||
display: inline-block;
|
||||
// border: 1px solid red;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
.centerTopTopBox {
|
||||
padding-left: 48px;
|
||||
position: absolute;
|
||||
top:30px;
|
||||
.num {
|
||||
width: 203px;
|
||||
height: 65px;
|
||||
line-height: 65px;
|
||||
padding-left: 10px;
|
||||
box-sizing: border-box;
|
||||
font-weight: 500;
|
||||
font-size: 38px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 5px 2px rgba(0,0,0,0.62);
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top:0px;
|
||||
}
|
||||
.title {
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
color: #00C8F7;
|
||||
letter-spacing: 2px;
|
||||
text-shadow: 0px 5px 2px rgba(0,0,0,0.62);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
108
src/views/base/dataBoard/components/Header.vue
Normal file
108
src/views/base/dataBoard/components/Header.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<header class="dataBoardHeader">
|
||||
<div class='topTitle'></div>
|
||||
<!-- <div class='time-chsoose'>
|
||||
<span class='title'>时间选择</span>
|
||||
<span class='time-show'>{{time}}</span>
|
||||
<el-date-picker
|
||||
v-model="time"
|
||||
type="date"
|
||||
value-format='yyyy-MM-dd'
|
||||
:clearable='false'
|
||||
style='position: absolute;right: 0px;width: 119px;top:-2px;opacity: 0;'
|
||||
>
|
||||
</el-date-picker>
|
||||
</div> -->
|
||||
<div
|
||||
type="text"
|
||||
class="screen-btn"
|
||||
:title="isFullScreen?'退出全屏':'全屏'"
|
||||
@click="changeFullScreen"
|
||||
>
|
||||
<svg-icon v-if="isFullScreen" icon-class="unFullScreenView" />
|
||||
<svg-icon v-else icon-class="fullScreenView" />
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import moment from 'moment'
|
||||
export default {
|
||||
name: 'DataBoardHeader',
|
||||
props: {
|
||||
isFullScreen: {
|
||||
type: Boolean,
|
||||
default: () => {
|
||||
return false
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// time: moment().format('YYYY-MM-DD')
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
changeFullScreen() {
|
||||
this.$emit('screenfullChange')
|
||||
},
|
||||
exportPDF() {
|
||||
this.$emit('exportPDF')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dataBoardHeader {
|
||||
background: url('../../../../assets/images/dataBoard/head.png') no-repeat;
|
||||
height: 99px;
|
||||
background-size: 100%;
|
||||
background-position: 0 0;
|
||||
position: relative;
|
||||
.topTitle{
|
||||
width: 465px;
|
||||
height: 77px;
|
||||
background: url('../../../../assets/images/dataBoard/data-board-title.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
left: 731px;
|
||||
top:19px;
|
||||
}
|
||||
.time-chsoose {
|
||||
width: 212px;
|
||||
height: 33px;
|
||||
background: url('../../../../assets/images/dataBoard/time-choose.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
right: 63px;
|
||||
top:49px;
|
||||
.title {
|
||||
font-size: 18px;
|
||||
color: #082049;
|
||||
letter-spacing: 1px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
left: 8px
|
||||
}
|
||||
.time-show {
|
||||
font-size: 18px;
|
||||
color: #FFFFFF;
|
||||
line-height: 18px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
left: 28px;
|
||||
}
|
||||
}
|
||||
.screen-btn{
|
||||
color: #00fff0;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
font-size: 32px;
|
||||
position: absolute;
|
||||
right: 22px;
|
||||
top:47px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
284
src/views/base/dataBoard/components/LeftBottom.vue
Normal file
284
src/views/base/dataBoard/components/LeftBottom.vue
Normal file
@@ -0,0 +1,284 @@
|
||||
<template>
|
||||
<div class='leftBottomBox'>
|
||||
<div class='title'>
|
||||
<svg-icon icon-class="dataBoard2" class='icon'/>
|
||||
<span>投入产出及良品率</span>
|
||||
</div>
|
||||
<div v-if='xData.length === 0' class='noData'>暂无数据</div>
|
||||
<div v-else>
|
||||
<div class="top_legend">
|
||||
<span class="chart_legend_icon1">投入</span>
|
||||
<span class="chart_legend_icon2">产出</span>
|
||||
<span><span class="chart_legend_icon3"></span>良品率</span>
|
||||
</div>
|
||||
<div id='inOutputChart' style='width: 400px;height: 290px;'></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
export default {
|
||||
name: 'LeftBottom',
|
||||
props: {
|
||||
dataObj: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dataObj(val) {
|
||||
this.xData = []
|
||||
this.inputData = []
|
||||
this.outputData = []
|
||||
this.goodRateData = []
|
||||
val.monthBar && val.monthBar.forEach(item => {
|
||||
this.xData.push(item.dataType)
|
||||
this.inputData.push(item.inputNum)
|
||||
this.outputData.push(item.outputNum)
|
||||
this.goodRateData.push(item.goodRate)
|
||||
})
|
||||
this.initChart();
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chartDom: '',
|
||||
chart: '',
|
||||
xData:[],
|
||||
inputData:[],
|
||||
outputData:[],
|
||||
goodRateData:[],
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
initChart() {
|
||||
if (
|
||||
this.chart !== null &&
|
||||
this.chart !== '' &&
|
||||
this.chart !== undefined
|
||||
) {
|
||||
this.chart.dispose() // 页面多次刷新会出现警告,Dom已经初始化了一个实例,这是销毁实例
|
||||
}
|
||||
this.chartDom = document.getElementById('inOutputChart')
|
||||
this.chart = echarts.init(this.chartDom)
|
||||
var option;
|
||||
option = {
|
||||
grid: { top: 40, right: 10, bottom: 5, left: 10, containLabel: true },
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: this.xData,
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
fontSize: 10,
|
||||
interval: 0,
|
||||
rotate:30
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "#5982B2",
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: [{
|
||||
name: "单位/片",
|
||||
nameTextStyle: {
|
||||
color: "#DFF1FE",
|
||||
fontSize: 12,
|
||||
},
|
||||
type: "value",
|
||||
axisLabel: {
|
||||
color: "#DFF1FE",
|
||||
fontSize: 12,
|
||||
formatter: "{value}",
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "#5982B2",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "#5982B2",
|
||||
},
|
||||
},
|
||||
},{
|
||||
name: "良品率/%",
|
||||
nameTextStyle: {
|
||||
color: "#DFF1FE",
|
||||
fontSize: 12,
|
||||
},
|
||||
type: "value",
|
||||
axisLabel: {
|
||||
color: "#DFF1FE",
|
||||
fontSize: 12,
|
||||
formatter: "{value}",
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "#5982B2",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "#5982B2",
|
||||
},
|
||||
},
|
||||
}],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
},
|
||||
className: "qhd-chart-tooltip",
|
||||
show: true,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: this.inputData,
|
||||
type: "bar",
|
||||
barWidth: 10,
|
||||
barGap:0,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(157, 234, 245, 1)' },
|
||||
{ offset: 1, color: 'rgba(110, 249, 222, 1)' },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
data:this.outputData,
|
||||
type: "bar",
|
||||
barWidth: 10,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(92, 183, 255, 1)' },
|
||||
{ offset: 1, color: 'rgba(54, 75, 254, 1)' },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
data:this.goodRateData,
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
symbol:'circle',
|
||||
symbolSize: 7,
|
||||
color:'rgba(18, 255, 245, 1)',
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(18, 255, 245, 0.8)' },
|
||||
{ offset: 0.2, color: 'rgba(18, 255, 245, 0.2)' },
|
||||
{ offset: 0.4, color: 'rgba(18, 255, 245, 0)' },
|
||||
]),
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
||||
option && this.chart.setOption(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
.leftBottomBox {
|
||||
width: 402px;
|
||||
height: 332px;
|
||||
background: url('../../../../assets/images/dataBoard/left-bottom.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
left: 23px;
|
||||
bottom:23px;
|
||||
.title {
|
||||
margin: 7px 0 0 15px;
|
||||
.icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 5px;
|
||||
vertical-align:middle;
|
||||
margin-top: 5px;
|
||||
}
|
||||
span {
|
||||
font-size: 24px;
|
||||
color: #52FFF1;
|
||||
line-height: 24px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
}
|
||||
.top_legend {
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
position: absolute;
|
||||
left:120px;
|
||||
top:50px;
|
||||
.chart_legend_icon1{
|
||||
margin-right: 10px;
|
||||
}
|
||||
.chart_legend_icon2{
|
||||
margin-right: 14px;
|
||||
}
|
||||
.chart_legend_icon1:before {
|
||||
display: inline-block;
|
||||
content: "";
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
border-radius: 2px;
|
||||
background: #73F8E0;
|
||||
}
|
||||
.chart_legend_icon2:before {
|
||||
display: inline-block;
|
||||
content: "";
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
border-radius: 2px;
|
||||
background: #497EFF;
|
||||
}
|
||||
.chart_legend_icon3 {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 8px;
|
||||
border-radius: 4px;
|
||||
background: #73F8E0;
|
||||
position:relative;
|
||||
}
|
||||
.chart_legend_icon3:before {
|
||||
display: inline-block;
|
||||
content: "";
|
||||
width: 16px;
|
||||
height:2px;
|
||||
background: #73F8E0;
|
||||
position:absolute;
|
||||
top:3px;
|
||||
left:-4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.noData {
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
padding-top: 100px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.qhd-chart-tooltip {
|
||||
background: #0a2b4f77 !important;
|
||||
border: none !important;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
.qhd-chart-tooltip * {
|
||||
color: #fff !important;
|
||||
}
|
||||
</style>
|
||||
162
src/views/base/dataBoard/components/LeftTop.vue
Normal file
162
src/views/base/dataBoard/components/LeftTop.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div class='leftTopBox'>
|
||||
<div class='title'>
|
||||
<svg-icon icon-class="dataBoard1" class='icon'/>
|
||||
<span>近期数据对比</span>
|
||||
</div>
|
||||
<div class='title-split'>
|
||||
<img src="../../../../assets//images/dataBoard/leftbar.png" alt="">
|
||||
<span class='text'>本日</span>
|
||||
<img src="../../../../assets//images/dataBoard/rightbar.png" alt="">
|
||||
</div>
|
||||
<div class='data-box'>
|
||||
<div class='left-icon' style="top:19px;">
|
||||
<img src="../../../../assets//images/dataBoard/leftTopIcon1.png" alt="" width='54'>
|
||||
<div>总投入</div>
|
||||
</div>
|
||||
<div class='left-icon' style="top:139px;">
|
||||
<img src="../../../../assets//images/dataBoard/leftTopIcon2.png" alt="" width='48'>
|
||||
<div>总生产</div>
|
||||
</div>
|
||||
<div class='right-data' style="top:15px;">
|
||||
<p><span class='num'>{{todayData?.inputNum ? formatThousands(todayData.inputNum) : '-'}}</span><span class='text'>片数</span></p>
|
||||
<p><span class='num'>{{todayData?.inputArea ? formatThousands(todayData.inputArea) : '-'}}</span><span class='text'>面积/㎡</span></p>
|
||||
</div>
|
||||
<div class='right-data' style="top:132px;">
|
||||
<p><span class='num'>{{todayData?.outputNum ? formatThousands(todayData.outputNum) : '-'}}</span><span class='text'>片数</span></p>
|
||||
<p><span class='num'>{{todayData?.outputArea ? formatThousands(todayData.outputArea) : '-'}}</span><span class='text'>面积/㎡</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class='title-split'>
|
||||
<img src="../../../../assets//images/dataBoard/leftbar.png" alt="">
|
||||
<span class='text'>昨日</span>
|
||||
<img src="../../../../assets//images/dataBoard/rightbar.png" alt="">
|
||||
</div>
|
||||
<div class='data-box'>
|
||||
<div class='left-icon' style="top:19px;">
|
||||
<img src="../../../../assets//images/dataBoard/leftTopIcon1.png" alt="" width='54'>
|
||||
<div>总投入</div>
|
||||
</div>
|
||||
<div class='left-icon' style="top:139px;">
|
||||
<img src="../../../../assets//images/dataBoard/leftTopIcon2.png" alt="" width='48'>
|
||||
<div>总生产</div>
|
||||
</div>
|
||||
<div class='right-data' style="top:15px;">
|
||||
<p><span class='num'>{{yesterdayData?.inputNum ? formatThousands(yesterdayData.inputNum) : '-'}}</span><span class='text'>片数</span></p>
|
||||
<p><span class='num'>{{yesterdayData?.inputArea ? formatThousands(yesterdayData.inputArea) : '-'}}</span><span class='text'>面积/㎡</span></p>
|
||||
</div>
|
||||
<div class='right-data' style="top:132px;">
|
||||
<p><span class='num'>{{yesterdayData?.outputNum ? formatThousands(yesterdayData.outputNum) : '-'}}</span><span class='text'>片数</span></p>
|
||||
<p><span class='num'>{{yesterdayData?.outputArea ? formatThousands(yesterdayData.outputArea) : '-'}}</span><span class='text'>面积/㎡</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'LeftTop',
|
||||
props: {
|
||||
dataObj: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dataObj(val) {
|
||||
val.todayAndYesterday && val.todayAndYesterday.forEach(item => {
|
||||
if (item.dataType === "今日") {
|
||||
this.todayData = item
|
||||
} else {
|
||||
this.yesterdayData = item
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
todayData:{},
|
||||
yesterdayData:{}
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
.leftTopBox {
|
||||
width: 402px;
|
||||
height: 600px;
|
||||
background: url('../../../../assets/images/dataBoard/left-top.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
left: 23px;
|
||||
top:113px;
|
||||
.title {
|
||||
margin: 10px 0 0 15px;
|
||||
.icon {
|
||||
width: 33px;
|
||||
height: 33px;
|
||||
margin-right: 5px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
span {
|
||||
font-size: 24px;
|
||||
color: #52FFF1;
|
||||
line-height: 24px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
}
|
||||
.title-split {
|
||||
margin-left: 95px;
|
||||
margin-top: 10px;
|
||||
.text{
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
font-size: 22px;
|
||||
color: #01CFCC;
|
||||
line-height: 24px;
|
||||
letter-spacing: 7px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.data-box {
|
||||
width: 358px;
|
||||
height: 230px;
|
||||
background: url('../../../../assets/images/dataBoard/leftTopDataBox.png') no-repeat;
|
||||
background-size: 100%;
|
||||
margin-top: 8px;
|
||||
position: relative;
|
||||
left: 24px;
|
||||
.left-icon {
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #9DEAF5;
|
||||
line-height: 22px;
|
||||
letter-spacing: 1px;
|
||||
text-shadow: 0px 4px 2px rgba(0,0,0,0.62);
|
||||
position: absolute;
|
||||
left: 30px;
|
||||
}
|
||||
.right-data {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
p{
|
||||
margin: 0;
|
||||
};
|
||||
.num {
|
||||
font-weight: 500;
|
||||
font-size: 32px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 4px 2px rgba(0,0,0,0.62);
|
||||
margin-right: 5px;
|
||||
}
|
||||
.text {
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
letter-spacing: 1px;
|
||||
text-shadow: 0px 4px 2px rgba(0,0,0,0.62);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
198
src/views/base/dataBoard/components/RightBottom.vue
Normal file
198
src/views/base/dataBoard/components/RightBottom.vue
Normal file
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div class='rightBottomBox'>
|
||||
<div class='title'>
|
||||
<svg-icon icon-class="dataBoard3" class='icon'/>
|
||||
<span>本月<span class='dotted'></span>班组生产排名</span>
|
||||
</div>
|
||||
<div class='rankingLeft'>
|
||||
<div class='rankingLeftTitle'>产量</div>
|
||||
<div class='rankingTypeBox'>
|
||||
<div style='margin-bottom: 10px;' v-for='(item,index) in teamProductionRank' :key='index'>
|
||||
<img :src="require(`../../../../assets/images/dataBoard/ranking${index+1}.png`)" alt="" width="50">
|
||||
<div class='rankingTextBox'>
|
||||
<p class='text1'>{{item.name}}/片</p>
|
||||
<p class='text2'>{{item?.value ? formatThousands(item.value) : '-'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='rankingRight'>
|
||||
<div class='rankingRightTitle'>
|
||||
成品率
|
||||
</div>
|
||||
<div class='rankingTypeBox' style='left: 120px;'>
|
||||
<div style='margin-bottom: 10px;' v-for='(item,index) in teamRateRank' :key='index'>
|
||||
<img :src="require(`../../../../assets/images/dataBoard/ranking${index+1}.png`)" alt="" width="50">
|
||||
<div class='rankingTextBox'>
|
||||
<p class='text1'>{{item.name}}</p>
|
||||
<p class='text2'>{{Math.trunc(item.value)}}<span style='font-size: 20px;'>.{{item.value1}}%</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div>
|
||||
<img src="../../../../assets//images//dataBoard/ranking2.png" alt="" width='50'>
|
||||
<div class='rankingTextBox'>
|
||||
<p class='text1'>班组1</p>
|
||||
<p class='text2'>94<span style='font-size: 20px;'>.13%</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../../../../assets//images//dataBoard/ranking3.png" alt="" width='50'>
|
||||
<div class='rankingTextBox'>
|
||||
<p class='text1'>班组1</p>
|
||||
<p class='text2'>90<span style='font-size: 20px;'>.42%</span></p>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'RightBottom',
|
||||
props: {
|
||||
dataObj: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dataObj(val) {
|
||||
this.teamProductionRank = []
|
||||
this.teamRateRank = []
|
||||
val.teamProductionRank && val.teamProductionRank.forEach(item => {
|
||||
let obj = {
|
||||
name: item.name,
|
||||
value: item.value,
|
||||
rank: item.rank,
|
||||
}
|
||||
this.teamProductionRank.push(obj)
|
||||
})
|
||||
val.teamRateRank && val.teamRateRank.forEach(item => {
|
||||
let obj = {
|
||||
name: item.name,
|
||||
value: item.value,
|
||||
rank: item.rank,
|
||||
value1: this.getPositiveDecimal(item.value)
|
||||
}
|
||||
this.teamRateRank.push(obj)
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
teamProductionRank:[],
|
||||
teamRateRank:[]
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
getPositiveDecimal(num) {
|
||||
const str = Math.abs(num).toString();
|
||||
const [, decimal] = str.split('.');
|
||||
return decimal || '00';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
p{
|
||||
margin: 0;
|
||||
}
|
||||
.rightBottomBox {
|
||||
width: 755px;
|
||||
height: 332px;
|
||||
background: url('../../../../assets/images/dataBoard/right-bottom.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
right: 23px;
|
||||
bottom:23px;
|
||||
.title {
|
||||
margin: 10px 0 0 15px;
|
||||
.icon {
|
||||
width: 33px;
|
||||
height: 33px;
|
||||
margin-right: 5px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
span {
|
||||
font-size: 24px;
|
||||
color: #52FFF1;
|
||||
line-height: 24px;
|
||||
vertical-align:middle;
|
||||
.dotted {
|
||||
display: inline-block;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background-color: #52FFF1;
|
||||
margin: 0 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.rankingLeft {
|
||||
width: 405px;
|
||||
height: 265px;
|
||||
background: url('../../../../assets/images/dataBoard/rankingBg1.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 48px;
|
||||
.rankingLeftTitle {
|
||||
width: 24px;
|
||||
height: 73px;
|
||||
font-weight: 500;
|
||||
font-size: 24px;
|
||||
color: #52FFF1;
|
||||
line-height: 55px;
|
||||
position: relative;
|
||||
left: 37px;
|
||||
top: 63px;
|
||||
}
|
||||
}
|
||||
.rankingRight {
|
||||
width: 338px;
|
||||
height: 265px;
|
||||
background: url('../../../../assets/images/dataBoard/rankingBg2.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 48px;
|
||||
.rankingRightTitle {
|
||||
width: 24px;
|
||||
height: 132px;
|
||||
font-weight: 500;
|
||||
font-size: 24px;
|
||||
color: #52FFF1;
|
||||
line-height: 55px;
|
||||
position: relative;
|
||||
left: 37px;
|
||||
top: 43px;
|
||||
}
|
||||
}
|
||||
.rankingTypeBox {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
top:13px;
|
||||
.rankingTextBox {
|
||||
display: inline-block;
|
||||
margin-left: 16px;
|
||||
vertical-align: top;
|
||||
.text1 {
|
||||
font-weight: 500;
|
||||
font-size: 17px;
|
||||
color: #FFFFFF;
|
||||
line-height: 22px;
|
||||
letter-spacing: 1px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.text2 {
|
||||
font-weight: 500;
|
||||
font-size: 32px;
|
||||
color: #FFFFFF;
|
||||
line-height: 22px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
352
src/views/base/dataBoard/components/RightTop.vue
Normal file
352
src/views/base/dataBoard/components/RightTop.vue
Normal file
@@ -0,0 +1,352 @@
|
||||
<template>
|
||||
<div class='rightTopBox'>
|
||||
<div class='title'>
|
||||
<svg-icon icon-class="dataBoard4" class='icon'/>
|
||||
<span>缺陷情况</span>
|
||||
</div>
|
||||
<div class='title-split'>
|
||||
<img src="../../../../assets//images/dataBoard/leftbar.png" alt="">
|
||||
<span class='text'>总数</span>
|
||||
<img src="../../../../assets//images/dataBoard/rightbar.png" alt="">
|
||||
</div>
|
||||
<div class='dataBox'>
|
||||
<div class='row'>
|
||||
<div class='box' style='width: 105px;'>
|
||||
<p class='name'>
|
||||
<span style='margin-right: 3px;'>当日</span>
|
||||
<img v-show='nokSumDet.today >= nokSumDet.yesterday' src="../../../../assets/images/dataBoard/arrUp.png" alt="" width='5' height='15'>
|
||||
<img v-show='nokSumDet.today < nokSumDet.yesterday' src="../../../../assets/images/dataBoard/arrDown.png" alt="" width='5' height='15'>
|
||||
</p>
|
||||
<p class='num'>{{nokSumDet?.today ? formatThousands(nokSumDet.today) : '-'}}</p>
|
||||
</div>
|
||||
<div class='box' style='width: 115px;'>
|
||||
<p class='name'>
|
||||
<span style='margin-right: 3px;'>本月</span>
|
||||
<img v-show='nokSumDet.month >= nokSumDet.lastMonth' src="../../../../assets/images/dataBoard/arrUp.png" alt="" width='5' height='15'>
|
||||
<img v-show='nokSumDet.month < nokSumDet.lastMonth' src="../../../../assets/images/dataBoard/arrDown.png" alt="" width='5' height='15'>
|
||||
</p>
|
||||
<p class='num'>{{nokSumDet?.month ? formatThousands(nokSumDet.month) : '-'}}</p>
|
||||
</div>
|
||||
<div class='box' style='width: 110px;'>
|
||||
<p class='name'>
|
||||
<span style='margin-right: 3px;'>本年</span>
|
||||
<img v-show='nokSumDet.year >= nokSumDet.lastYear' src="../../../../assets/images/dataBoard/arrUp.png" alt="" width='5' height='15'>
|
||||
<img v-show='nokSumDet.year < nokSumDet.lastYear' src="../../../../assets/images/dataBoard/arrDown.png" alt="" width='5' height='15'>
|
||||
</p>
|
||||
<p class='num'>{{nokSumDet?.year ? formatThousands(nokSumDet.year) : '-'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class='row' style='padding-top: 5px;'>
|
||||
<div class='box' style='width: 105px;'>
|
||||
<p class='name'>
|
||||
<span>昨日</span>
|
||||
</p>
|
||||
<p class='num'>{{nokSumDet?.yesterday ? formatThousands(nokSumDet.yesterday) : '-'}}</p>
|
||||
</div>
|
||||
<div class='box' style='width: 115px;'>
|
||||
<p class='name'>
|
||||
<span>上月</span>
|
||||
</p>
|
||||
<p class='num'>{{nokSumDet?.lastMonth ? formatThousands(nokSumDet.lastMonth) : '-'}}</p>
|
||||
</div>
|
||||
<div class='box' style='width: 110px;'>
|
||||
<p class='name'>
|
||||
<span>上年</span>
|
||||
</p>
|
||||
<p class='num'>{{nokSumDet?.lastYear ? formatThousands(nokSumDet.lastYear) : '-'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='title-split2'>
|
||||
<img src="../../../../assets//images/dataBoard/leftbar.png" alt="">
|
||||
<span class='text'>全厂缺陷汇总</span>
|
||||
<img src="../../../../assets//images/dataBoard/rightbar.png" alt="">
|
||||
</div>
|
||||
<div id='defectSumChart' style='width: 400px;height: 315px;'></div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
const colors = [
|
||||
"rgb(39, 96, 255)",
|
||||
"rgb(91, 155, 255)",
|
||||
"rgb(153, 214, 108)",
|
||||
"rgb(18, 255, 245)",
|
||||
"rgb(221, 177, 18)",
|
||||
];
|
||||
export default {
|
||||
name: 'RightTop',
|
||||
props: {
|
||||
dataObj: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dataObj(val) {
|
||||
this.nokSumDet = val.nokSumDet
|
||||
this.dataProps = []
|
||||
val.nokPieDet && val.nokPieDet.forEach(item => {
|
||||
let obj = {
|
||||
value: item.num,
|
||||
name: item.type
|
||||
}
|
||||
this.dataProps.push(obj)
|
||||
})
|
||||
this.initChart()
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
nokSumDet:{},
|
||||
chartDom: '',
|
||||
chart: '',
|
||||
dataProps:[],
|
||||
rangArrValue:[],
|
||||
dataList:[],
|
||||
totalValue:0
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
initChart() {
|
||||
if (
|
||||
this.chart !== null &&
|
||||
this.chart !== '' &&
|
||||
this.chart !== undefined
|
||||
) {
|
||||
this.chart.dispose() // 页面多次刷新会出现警告,Dom已经初始化了一个实例,这是销毁实例
|
||||
}
|
||||
this.chartDom = document.getElementById('defectSumChart')
|
||||
this.chart = echarts.init(this.chartDom)
|
||||
var option;
|
||||
this.getPersonnelList(this.dataProps)
|
||||
option = {
|
||||
color: colors,
|
||||
graphic: [
|
||||
{
|
||||
type: "text",
|
||||
left: "center",
|
||||
top: "44%",
|
||||
style: {
|
||||
text: this.totalValue,
|
||||
fill: "#fff",
|
||||
width: 150,
|
||||
height: 44,
|
||||
fontSize: 31,
|
||||
fontWeight: 400,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
left: "center",
|
||||
top: "55%",
|
||||
style: {
|
||||
text: "总数/件",
|
||||
fill: "rgba(255, 255, 255, 0.70)",
|
||||
width: 32,
|
||||
height: 16,
|
||||
fontSize: 16,
|
||||
fontWeight: 400,
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "产线缺陷分类",
|
||||
type: "pie",
|
||||
radius: ["45%", "60%"],
|
||||
center: ["50%", "50%"],
|
||||
label:{
|
||||
formatter:function(params){
|
||||
return `{color${params.dataIndex}|${params.percent}%}\n{style2|${params.name}}`
|
||||
},
|
||||
rich:{
|
||||
color0:{color:'rgb(39, 96, 255)',fontSize:22},
|
||||
color1:{color:'rgb(91, 155, 255)',fontSize:22},
|
||||
color2:{color:'rgb(153, 214, 108)',fontSize:22},
|
||||
color3:{color:'rgb(18, 255, 245)',fontSize:22},
|
||||
color4:{color:'rgb(221, 177, 18)',fontSize:22},
|
||||
color5:{color:'rgb(39, 96, 255)',fontSize:22},
|
||||
color6:{color:'rgb(91, 155, 255)',fontSize:22},
|
||||
color7:{color:'rgb(153, 214, 108)',fontSize:22},
|
||||
color8:{color:'rgb(18, 255, 245)',fontSize:22},
|
||||
color9:{color:'rgb(221, 177, 18)',fontSize:22},
|
||||
style2:{
|
||||
color:'#fff',
|
||||
fontSize:14
|
||||
}
|
||||
}
|
||||
},
|
||||
data: this.dataList,
|
||||
},
|
||||
],
|
||||
}
|
||||
option && this.chart.setOption(option);
|
||||
},
|
||||
getCoordinates(startArc, endArc) {
|
||||
const posi = [
|
||||
Math.sin(startArc),
|
||||
-Math.cos(startArc),
|
||||
Math.sin(endArc),
|
||||
-Math.cos(endArc),
|
||||
];
|
||||
const dx = posi[2] - posi[0];
|
||||
const dy = posi[3] - posi[1];
|
||||
|
||||
return this.getLocation(dx, dy);
|
||||
},
|
||||
getLocation(dx,dy) {
|
||||
const tanV = dx / dy;
|
||||
const directSign = Math.abs(tanV) < 1;
|
||||
const t = directSign ? tanV : 1 / tanV;
|
||||
|
||||
const sign1 = t > 0 ? 1 : -1;
|
||||
const sign2 = dx > 0 ? 1 : -1;
|
||||
const sign = directSign ? sign1 * sign2 : sign2;
|
||||
|
||||
const group1 = [0.5 - (sign * t) / 2, 0.5 + (sign * t) / 2];
|
||||
const group2 = sign > 0 ? [0, 1] : [1, 0];
|
||||
const group = [...group1, ...group2];
|
||||
const keys = directSign ? ["x", "x2", "y", "y2"] : ["y", "y2", "x", "x2"];
|
||||
|
||||
let res = {};
|
||||
keys.forEach((k, idx) => {
|
||||
res[k] = group[idx];
|
||||
});
|
||||
return res;
|
||||
},
|
||||
async getPersonnelList(dataProps){
|
||||
this.rangArrValue = [];
|
||||
this.totalValue = 0;
|
||||
this.dataList = [];
|
||||
this.totalValue = dataProps.reduce(
|
||||
(total, value) => total + value.value,
|
||||
0
|
||||
);
|
||||
let cacheNum = 0;
|
||||
for (let i = 0; i < dataProps.length; i++) {
|
||||
const endNum = cacheNum + dataProps[i].value;
|
||||
this.rangArrValue.push([cacheNum, endNum]);
|
||||
cacheNum = endNum;
|
||||
}
|
||||
const angleArr = this.rangArrValue.map((arr) =>
|
||||
arr.map((num) => (num / this.totalValue) * Math.PI * 2)
|
||||
);
|
||||
this.dataList = dataProps.map((item, index) => {
|
||||
const range = this.getCoordinates(angleArr[index][0], angleArr[index][1]);
|
||||
const startColor = colors[index%5];
|
||||
const color = {
|
||||
type: "linear",
|
||||
x: range.x,
|
||||
x2: range.x2,
|
||||
y: range.y,
|
||||
y2: range.y2,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: startColor, // 起始颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: `${startColor.substring(0, startColor.length - 1)}, 0.2)`, // 终点颜色
|
||||
},
|
||||
],
|
||||
global: false,
|
||||
};
|
||||
|
||||
return {
|
||||
name: item.name,
|
||||
value: item.value,
|
||||
itemStyle: {
|
||||
color: color,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
p{
|
||||
margin: 0;
|
||||
}
|
||||
.rightTopBox {
|
||||
width: 402px;
|
||||
height: 600px;
|
||||
background: url('../../../../assets/images/dataBoard/left-top.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
right: 23px;
|
||||
top:113px;
|
||||
.title {
|
||||
margin: 10px 0 0 15px;
|
||||
.icon {
|
||||
width: 33px;
|
||||
height: 33px;
|
||||
margin-right: 5px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
span {
|
||||
font-size: 24px;
|
||||
color: #52FFF1;
|
||||
line-height: 24px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
}
|
||||
.title-split {
|
||||
margin-left: 95px;
|
||||
margin-top: 10px;
|
||||
.text{
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
font-size: 22px;
|
||||
color: #01CFCC;
|
||||
line-height: 24px;
|
||||
letter-spacing: 7px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.title-split2 {
|
||||
margin-left: 66px;
|
||||
margin-top: 20px;
|
||||
.text{
|
||||
display: inline-block;
|
||||
width: 160px;
|
||||
font-size: 22px;
|
||||
color: #01CFCC;
|
||||
line-height: 24px;
|
||||
letter-spacing: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.dataBox {
|
||||
width: 358px;
|
||||
height: 160px;
|
||||
background: url('../../../../assets/images/dataBoard/defectNum.png') no-repeat;
|
||||
background-size: 100%;
|
||||
position: relative;
|
||||
left: 21px;
|
||||
top:8px;
|
||||
padding-left: 24px;
|
||||
.row {
|
||||
.box{
|
||||
display: inline-block;
|
||||
padding-top: 10px;
|
||||
.name {
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
color: #FFFFFF;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.num {
|
||||
font-weight: 500;
|
||||
font-size: 28px;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 5px 2px rgba(0,0,0,0.62);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,100 +1,234 @@
|
||||
<!--
|
||||
filename: index.vue
|
||||
author: liubin
|
||||
date: 2023-10-11 09:32:04
|
||||
description: 设备看板
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div ref="dataBoard" class="data-board">
|
||||
<el-button type="text" @click="goback" class="go-back--btn">返回</el-button>
|
||||
<div ref='dataBoardBoxB' class='dataBoardBoxB'>
|
||||
<div id="dataBoardBox" class='dataBoardBox' style="width: 1920px;height: 1080px;" :style="{ transform: 'scale(' + scaleNum + ')' }">
|
||||
<DataBoardHeader
|
||||
:is-full-screen="isFullScreen"
|
||||
@screenfullChange="screenfullChange"
|
||||
/>
|
||||
<LeftTop :dataObj='dataObj'/>
|
||||
<LeftBottom :dataObj='dataObj'/>
|
||||
<CenterTop :scaleNum='scaleNum' :dataObj='dataObj'/>
|
||||
<CenterBottomL :dataObj='dataObj'/>
|
||||
<CenterBottomR :dataObj='dataObj'/>
|
||||
<RightTop :dataObj='dataObj'/>
|
||||
<RightBottom :dataObj='dataObj'/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DataBoardHeader from './components/Header.vue';
|
||||
import LeftTop from './components/LeftTop.vue';
|
||||
import LeftBottom from './components/LeftBottom.vue';
|
||||
import CenterTop from './components/CenterTop.vue';
|
||||
import CenterBottomL from './components/CenterBottomL.vue';
|
||||
import CenterBottomR from './components/CenterBottomR.vue';
|
||||
import RightTop from './components/RightTop.vue';
|
||||
import RightBottom from './components/RightBottom.vue';
|
||||
import { debounce } from '@/utils/debounce';
|
||||
import screenfull from 'screenfull';
|
||||
import { getAccessToken } from '@/utils/auth';
|
||||
import store from "@/store";
|
||||
export default {
|
||||
name: 'DataBoard',
|
||||
components: {},
|
||||
components: { DataBoardHeader,LeftTop,LeftBottom,CenterTop,CenterBottomL,CenterBottomR,RightTop,RightBottom },
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
appMain: null, // dom
|
||||
parentStyle: {
|
||||
margin: '8px 14px 0px 16px',
|
||||
minHeight: 'calc(100vh - 120px - 8px)',
|
||||
}, // object
|
||||
mainFooter: null, // dom
|
||||
isFullScreen: false,
|
||||
scaleNum: 0.8,
|
||||
dataObj:{},
|
||||
sseReader: null, // 保存流读取器
|
||||
abortController: null, // 用于中止 fetch 请求
|
||||
retryCount: 0, // 当前重试次数
|
||||
isDestroyed: false // 标记组件是否已销毁
|
||||
};
|
||||
},
|
||||
// mounted() {
|
||||
// this.$nextTick(() => {
|
||||
// this.modify();
|
||||
// });
|
||||
// },
|
||||
// activated() {
|
||||
// this.modify();
|
||||
// },
|
||||
// deactivated() {
|
||||
// this.recover();
|
||||
// },
|
||||
// beforeDestroy() {
|
||||
// this.recover();
|
||||
// },
|
||||
methods: {
|
||||
// modify() {
|
||||
// // 在这个页面临时修改下父类的margin,结束时需还原
|
||||
// this.appMain = document.querySelector('.app-main');
|
||||
// // this.appMain.style.minHeight = 'calc(100vh - 90px)';
|
||||
// this.appMain.style.margin = 0;
|
||||
// // 在这个页面临时删除 main-footer 元素,结束时需还原
|
||||
// // this.mainFooter = document.querySelector('.main-footer').cloneNode(true);
|
||||
// // document.querySelector('.main-footer').remove();
|
||||
// this.$refs.dataBoard.classList.add('data-board');
|
||||
// },
|
||||
// recover() {
|
||||
// this.$refs.dataBoard.classList.remove('data-board');
|
||||
// this.$nextTick(() => {
|
||||
// this.appMain.style.margin = this.parentStyle.margin;
|
||||
// // this.appMain.style.minHeight = this.parentStyle.minHeight;
|
||||
// // this.appMain.insertAdjacentElement('afterend', this.mainFooter);
|
||||
// });
|
||||
// },
|
||||
goback() {
|
||||
this.$router.go(-1);
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
mounted() {
|
||||
this.boxReset = debounce(() => {
|
||||
this.resetSize()
|
||||
}, 300)
|
||||
this.boxReset()
|
||||
window.addEventListener('resize', () => {
|
||||
this.boxReset()
|
||||
})
|
||||
this.getData()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.closeSSE();
|
||||
},
|
||||
computed: {
|
||||
sidebarOpened() {
|
||||
return this.$store.state.app.sidebar.opened
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
sidebarOpened(newVal, oldVal) {
|
||||
this.boxReset()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
let _this = this;
|
||||
if (_this.isDestroyed) return;
|
||||
const url = process.env.VUE_APP_BASE_API+'/admin-api/monitoring/message/subscribe/'+store.getters.userId+'-'+Date.now();
|
||||
const token = getAccessToken()
|
||||
const headers = new Headers({
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'text/event-stream'
|
||||
});
|
||||
try {
|
||||
// 创建中止控制器
|
||||
this.abortController = new AbortController();
|
||||
// 发起 fetch 请求(替换为你的接口地址)
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: headers,
|
||||
signal: _this.abortController.signal // 绑定中止信号
|
||||
});
|
||||
|
||||
// 获取流读取器
|
||||
_this.sseReader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
// 持续读取流数据
|
||||
while (true) {
|
||||
const { done, value } = await _this.sseReader.read();
|
||||
if (done) {
|
||||
console.log('SSE 连接正常关闭');
|
||||
_this.handleReconnect(); // 触发重连
|
||||
break;
|
||||
}
|
||||
// 处理 SSE 事件数据
|
||||
const data = decoder.decode(value);
|
||||
console.log('收到消息:', data);
|
||||
if (_this.isValidData(data)){
|
||||
_this.upDateMsg(data);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// 主动中止的请求不报错
|
||||
if (error.name === 'AbortError') return;
|
||||
console.error('SSE 连接异常:', error);
|
||||
_this.handleReconnect(); // 触发重连
|
||||
}
|
||||
},
|
||||
closeSSE() {
|
||||
this.isDestroyed = true; // 标记销毁
|
||||
if (this.abortController) {
|
||||
this.abortController.abort(); // 中止 fetch 请求
|
||||
}
|
||||
if (this.sseReader) {
|
||||
this.sseReader.cancel(); // 关闭流读取器
|
||||
this.sseReader = null;
|
||||
}
|
||||
console.log('SSE 连接已强制关闭');
|
||||
},
|
||||
handleReconnect() {
|
||||
if (this.isDestroyed) return;
|
||||
// 指数退避策略(最大重试 5 次)
|
||||
const maxRetries = 5;
|
||||
if (this.retryCount < maxRetries) {
|
||||
const delay = Math.pow(2, this.retryCount) * 1000;
|
||||
setTimeout(() => {
|
||||
this.retryCount++;
|
||||
this.initSSE();
|
||||
}, delay);
|
||||
} else {
|
||||
console.error('SSE 重连次数已达上限');
|
||||
}
|
||||
},
|
||||
isValidData (data) {
|
||||
return data.trim().startsWith('data:{') && !data.includes('heartbeat');
|
||||
},
|
||||
upDateMsg(data) {
|
||||
const jsonStr = data.replace(/^data:/, '').trim();
|
||||
try {
|
||||
const dataObj = JSON.parse(jsonStr);
|
||||
this.dataObj = dataObj
|
||||
console.log('dataObj',this.dataObj)
|
||||
} catch (e) {
|
||||
console.error('JSON 解析失败:', e);
|
||||
}
|
||||
},
|
||||
change() {
|
||||
this.isFullScreen = screenfull.isFullscreen
|
||||
},
|
||||
init() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
screenfull.on('change', this.change)
|
||||
},
|
||||
destroy() {
|
||||
if (!screenfull.isEnabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
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.dataBoardBoxB)
|
||||
},
|
||||
resetSize() {
|
||||
const dataBoardBox = document.getElementById('dataBoardBox')
|
||||
const rw = parseFloat(window.innerWidth)
|
||||
const rh = parseFloat(window.innerHeight)
|
||||
const bw = parseFloat(dataBoardBox.style.width)
|
||||
const bh = parseFloat(dataBoardBox.style.height)
|
||||
let wx = 0
|
||||
let hy = 0
|
||||
if (screenfull.isFullscreen) {
|
||||
wx = rw / bw
|
||||
hy = rh / bh
|
||||
} else {
|
||||
if (this.$store.state.app.sidebar.opened) {
|
||||
wx = (rw - 283) / bw
|
||||
} else {
|
||||
wx = (rw - 88) / bw
|
||||
}
|
||||
hy = (rh - 150) / bh
|
||||
}
|
||||
this.scaleNum = wx < hy ? wx : hy
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.data-board {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('../../../assets/images/DataBoard.png') 100% 100% / contain
|
||||
no-repeat;
|
||||
}
|
||||
|
||||
.go-back--btn {
|
||||
position: fixed;
|
||||
top: 28px;
|
||||
left: 24px;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
letter-spacing: 6px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
.dataBoardBoxB {
|
||||
width: 100%;
|
||||
height: calc(100vh - 150px);
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
.dataBoardBox {
|
||||
position: absolute;
|
||||
transform-origin: 16px 8px;
|
||||
font-size: 16px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background: url('../../../assets/images/dataBoard/background.png') no-repeat;
|
||||
background-size: cover;
|
||||
background-position: 0 0;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "\2BAA";
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: -26px;
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user