From 6b8a6b0591e97aa7d175c5f6c61d64534f038124 Mon Sep 17 00:00:00 2001 From: zhaowei <zhaowei> Date: 星期一, 12 五月 2025 14:56:03 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- src/views/mdc/base/modules/GradeSignage/WorkshopSignage.vue | 1079 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 1,079 insertions(+), 0 deletions(-) diff --git a/src/views/mdc/base/modules/GradeSignage/WorkshopSignage.vue b/src/views/mdc/base/modules/GradeSignage/WorkshopSignage.vue new file mode 100644 index 0000000..4d7c7f5 --- /dev/null +++ b/src/views/mdc/base/modules/GradeSignage/WorkshopSignage.vue @@ -0,0 +1,1079 @@ +<template> + <div class="component-container"> + <slot name="loading"/> + + <div class="left-container"> + <div class="left-single-container"> + <div class="title-container"> + <img src="@/assets/signage/title.png"/> + <span>璁惧鐘舵��</span> + </div> + <div class="left-chart-container" id="left-chart-1"></div> + </div> + + <div class="left-single-container"> + <div class="title-container"> + <img src="@/assets/signage/title.png"/> + <span>缁翠繚鐘舵��</span> + </div> + <div class="left-chart-container" id="left-chart-2"></div> + </div> + + <div + :style="{justifyContent:workshopList.length<=3?'center':'space-between'}"> + <div v-for="(item,index) in workshopList" class="navigator-container" @mouseenter="activeIndex=index" + @mouseleave="activeIndex=null" @click="$emit('nextSignage', item)"> + <template v-if="workshopList.length<=3"> + <img v-if="activeIndex!==index" src="@/assets/signage/workshop/navigator-long.png" style="height: 3.38vw"/> + <img v-else src="@/assets/signage/workshop/navigator-long-active.png" style="height: 3.38vw"/> + <span style="font-size: 1.2vw;letter-spacing: 0.25vw;padding-left: 0.25vw">{{item.productionName}}</span> + </template> + + <template v-else> + <img v-if="activeIndex!==index" src="@/assets/signage/workshop/navigator-middle.png" style="height: 3.1vw"/> + <img v-else src="@/assets/signage/workshop/navigator-middle-active.png" style="height: 3.1vw"/> + <span style="font-size: 0.8vw;letter-spacing:0.1vw;padding-left: 0.1vw">{{item.productionName }}</span> + </template> + </div> + </div> + </div> + + <div class="right-container"> + <div> + <img src="@/assets/signage/company/rate-analysis-container.png"/> + <div class="right-chart-container" id="right-top-chart"></div> + </div> + <div> + <div> + <img src="@/assets/signage/company/repair-analysis.png"/> + <div class="right-chart-container" id="right-bottom-chart-1"></div> + </div> + <div> + <img src="@/assets/signage/company/inspection-analysis.png"/> + <div class="right-chart-container" id="right-bottom-chart-2"></div> + </div> + <div> + <img src="@/assets/signage/company/maintenance-analysis.png"/> + <div class="right-chart-container" id="right-bottom-chart-3"></div> + </div> + </div> + </div> + </div> +</template> + +<script> + import signageApi from '@/api/signage' + + export default { + name: 'WorkshopSignage', + props: { + currentProductionId: { + type: String + } + }, + data() { + return { + leftChart1: null, + leftChart2: null, + rightTopChart: null, + rightBottomChart1: null, + rightBottomChart2: null, + rightBottomChart3: null, + leftChart1Data: [], + leftChart2Data: [], + rightTopChartData: [], + rightBottomChart1Data: [], + rightBottomChart2Data: [], + rightBottomChart3Data: [], + chartQuantity: 6, + hasLoadedChartDataQuantity: 0, + workshopList: [], + activeIndex: null + } + }, + watch: { + hasLoadedChartDataQuantity: { + handler(val) { + if (val === this.chartQuantity) this.$emit('loadFinished') + } + } + }, + mounted() { + this.getWorkshopListByApi() + this.handleWindowResize() + + window.addEventListener('resize', this.handleWindowResize) + }, + beforeDestroy() { + window.removeEventListener('resize', this.handleWatchHistory) + }, + methods: { + getWorkshopListByApi() { + signageApi.getWorkshopListByProductionIdApi(this.currentProductionId) + .then(res => { + if (res.success) { + this.getLeftChartContainerHeight(res.result ? res.result : []) + this.getChartDataByApi() + } + }) + }, + + getLeftChartContainerHeight(workshopList) { + const outerHeight = workshopList.length <= 3 ? `calc((100% - 3.38vw * ${workshopList.length}) / 2)` : `calc((100% - 3.1vw * ${Math.round(workshopList.length / 2)}) / 2)` + document.querySelectorAll('.left-single-container').forEach(item => item.style.height = outerHeight) + this.workshopList = workshopList + }, + + getChartDataByApi() { + this.getLeftChart1DataByApi() + this.getLeftChart2DataByApi() + this.geRightTopChartDataByApi() + this.geRightBottomChartData1ByApi() + this.geRightBottomChartData2ByApi() + this.geRightBottomChartData3ByApi() + }, + + getLeftChart1DataByApi() { + const that = this + signageApi.getEquipmentStatusAnalysisApi(this.currentProductionId) + .then(res => { + if (res.success) { + this.leftChart1Data = res.result.equipmentStatus + } + this.initLeftChart1() + }) + .finally(() => { + that.hasLoadedChartDataQuantity++ + }) + }, + + getLeftChart2DataByApi() { + const that = this + signageApi.getRepairAndMaintenanceStatusApi(this.currentProductionId) + .then(res => { + if (res.success) { + this.leftChart2Data = res.result.map(item => { + return { + name: item.statusText, + value: item.totalNumber + } + }) + } + this.initLeftChart2() + }) + .finally(() => { + that.hasLoadedChartDataQuantity++ + }) + }, + + geRightTopChartDataByApi() { + const that = this + console.log('this.currentProductionId', this.currentProductionId) + signageApi.getRateAnalysisTrendApi(this.currentProductionId) + .then(res => { + console.log('res', res) + if (res.success) this.rightTopChartData = res.result + this.initRightTopChart() + }) + .finally(() => { + that.hasLoadedChartDataQuantity++ + }) + }, + + geRightBottomChartData1ByApi() { + const that = this + signageApi.getRepairAnalysisApi(this.currentProductionId) + .then(res => { + if (res.success) this.rightBottomChart1Data = res.result + this.initRightBottomChart1() + }) + .finally(() => { + that.hasLoadedChartDataQuantity++ + }) + }, + + geRightBottomChartData2ByApi() { + const that = this + signageApi.getInspectionAnalysisApi(this.currentProductionId) + .then(res => { + if (res.success) this.rightBottomChart2Data = res.result + this.initRightBottomChart2() + }) + .finally(() => { + that.hasLoadedChartDataQuantity++ + }) + }, + + geRightBottomChartData3ByApi() { + const that = this + signageApi.getMaintenanceAnalysisApi(this.currentProductionId) + .then(res => { + if (res.success) this.rightBottomChart3Data = res.result + this.initRightBottomChart3() + }) + .finally(() => { + that.hasLoadedChartDataQuantity++ + }) + }, + + initLeftChart1() { + this.leftChart1 = this.$echarts.init(document.getElementById('left-chart-1')) + const { alarmCount, closeCount, runCount, waitCount } = this.leftChart1Data + const dataList = [ + { + 'value': closeCount, + 'name': '鍏虫満' + }, + { + 'value': waitCount, + 'name': '寰呮満' + }, + { + 'value': runCount, + 'name': '杩愯' + }, + { + 'value': alarmCount, + 'name': '鎶ヨ' + } + ] + const option = { + tooltip: { + show: true + }, + title: { + text: `{a|${dataList.reduce((total, item) => total + +item.value, 0)}}`, + x: 'center', + y: '50%', + textStyle: { + rich: { + a: { + fontSize: 30, + color: '#eee' + } + } + } + }, + legend: { + top: 10, + left: 'center', + itemGap: 15, + textStyle: { + color: '#eee', + fontSize: 14, + fontFamily: 'LanTing', + height: 10, + rich: { + a: { + verticalAlign: 'bottom' + } + } + }, + data: ['鍏虫満', '寰呮満', '杩愯', '鎶ヨ'] + }, + grid: { + containLabel: true + }, + series: [ + { + type: 'pie', + radius: ['30%', '55%'], + center: ['50%', '55%'], + color: [ + '#238DF5', + '#6FDB6F', + '#10ABAE', + '#C7A46C' + ], + label: { + position: 'outside', + show: true, + color: 'inherit', + fontSize: 16, + fontWeight: 'bold', + formatter: function(params) { + return params.value + } + }, + labelLine: { + show: true + }, + data: dataList + } + ] + } + this.$nextTick(() => this.leftChart1.setOption(option, true)) + }, + + initLeftChart2() { + this.leftChart2 = this.$echarts.init(document.getElementById('left-chart-2')) + const option = { + tooltip: { + show: true + }, + title: { + text: '', + x: 'center', + y: '50%', + textStyle: { + rich: { + a: { + fontSize: 30, + color: '#eee' + } + } + } + }, + legend: { + top: 10, + left: 'center', + itemGap: 15, + textStyle: { + color: '#eee', + fontSize: 14, + fontFamily: 'LanTing', + height: 10, + rich: { + a: { + verticalAlign: 'bottom' + } + } + }, + data: ['姝e父', '缁翠慨', '鐐规', '淇濆吇'] + }, + grid: { + containLabel: true + }, + series: [ + { + type: 'pie', + radius: ['30%', '55%'], + center: ['50%', '55%'], + color: ['#238DF5', '#6FDB6F', '#10ABAE', '#C7A46C'], + label: { + position: 'outside', + show: true, + color: 'inherit', + fontWeight: 'bold', + fontSize: 16, + formatter: function(params) { + return params.value + } + }, + labelLine: { + show: true + }, + data: [] + } + ] + } + option.series[0].data = this.leftChart2Data + option.title.text = `{a|${this.leftChart2Data.reduce((total, item) => total + +item.value, 0)}}` + this.$nextTick(() => this.leftChart2.setOption(option, true)) + }, + + initRightTopChart() { + this.rightTopChart = this.$echarts.init(document.getElementById('right-top-chart')) + const { dataList, dateList } = this.rightTopChartData + const newData = { + xAxis: dateList, + yAxis: [ + { + name: 'OEE', + value: dataList.map(item => item.oee) + }, + { + name: '鍒╃敤鐜�', + value: dataList.map(item => item.utilizationRate) + }, + { + name: '寮�鏈虹巼', + value: dataList.map(item => item.openRate) + }, + { + name: '寮�鍔ㄧ巼', + value: dataList.map(item => item.startRate) + } + ] + } + let legendData = [] + let seriesData = [] + let colorArr = ['#4D9BEF', '#FFA800', '#00FF18', '#C06FFF'] + legendData = newData.yAxis.map((item) => item.name) + seriesData = newData.yAxis.map((item1, index1) => { + return { + name: item1.name, + type: 'line', + symbol: 'circle', + symbolSize: 8, + itemStyle: { + color: colorArr[index1] + }, + yAxisIndex: 1, + data: item1.value // 鎶樼嚎鍥剧殑鏁版嵁 + } + }) + const option = { + grid: { + containLabel: true, + bottom: '3%', + top: '25%', + left: '5%', + right: '5%' + }, + tooltip: { + trigger: 'axis' + }, + legend: { + top: 70, + right: '5%', + data: legendData, + itemGap: 30, + textStyle: { + fontSize: 14, + color: '#eee', + fontFamily: 'LanTing', + height: 10, + rich: { + a: { + verticalAlign: 'bottom' + } + } + } + }, + xAxis: { + triggerEvent: true, + data: newData.xAxis || [], + axisLabel: { + interval: 0, + show: true, + fontSize: 14, + color: '#eee', + margin: 14, + fontFamily: 'LanTing' + }, + axisLine: { + show: true, + lineStyle: { + color: '#eee' + } + }, + axisTick: { + show: true + }, + splitLine: { + show: true + } + }, + yAxis: [ + { + type: 'value', + position: 'left', + axisLine: { + show: true, + lineStyle: { + color: '#eee' + } + }, + splitLine: { + show: false + } + }, + { + type: 'value', + position: 'left', + axisLabel: { + show: true, + color: '#eee', + margin: 14, + fontSize: 14, + fontWeight: 'bold', + formatter(value) { + return value + '%' + } + }, + axisLine: { + show: true, + lineStyle: { + color: '#eee' + } + }, + axisTick: { + show: true + }, + splitLine: { + show: false + } + } + ], + series: seriesData + } + this.rightTopChart.setOption(option, true) + }, + + initRightBottomChart1() { + this.rightBottomChart1 = this.$echarts.init(document.getElementById('right-bottom-chart-1')) + const option = { + tooltip: { + trigger: 'axis' + }, + grid: { + bottom: '5%', + top: '30%', + left: '10%', + right: '10%', + containLabel: true + }, + legend: { + top: 80, + right: '10%', + itemGap: 15, + textStyle: { + fontSize: 14, + fontFamily: 'LanTing', + color: '#eee', + height: 10, + rich: { + a: { + verticalAlign: 'bottom' + } + } + }, + data: ['鎶ヤ慨鏁�', '瀹屾垚鏁�'] + }, + xAxis: { + type: 'category', + data: [], + axisLine: { + lineStyle: { + color: '#eee' + } + }, + axisLabel: { + interval: 0, + margin: 14, + fontSize: 14, + color: '#eee', + fontFamily: 'LanTing', + rotate: 45 + }, + axisTick: { + show: true + } + }, + yAxis: [ + { + type: 'value', + axisLine: { + show: true, + lineStyle: { + color: '#eee' + } + }, + axisTick: { + show: true + }, + splitLine: { + show: false + + }, + axisLabel: { + fontSize: 14, + color: '#eee', + fontWeight: 'bold', + margin: 14 + } + } + ], + series: [ + { + type: 'bar', + barWidth: 12, + name: '鎶ヤ慨鏁�', + data: [], + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'inside', + textStyle: { + color: '#eee', + fontSize: 12 + } + }, + itemStyle: { + color: new this.$echarts.graphic.LinearGradient(0, 1, 0, 0, + [ + {//鍙淇敼鍓嶅洓涓弬鏁板氨ok + offset: 0, + color: '#295485' + }, //鏌卞浘娓愬彉鑹� + { + offset: 1, + color: '#2F95F9' + } + ] + ) + } + }, + { + type: 'bar', + barWidth: 12, + name: '瀹屾垚鏁�', + data: [], + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'inside', + textStyle: { + color: '#eee', + fontSize: 12 + } + }, + itemStyle: { + color: new this.$echarts.graphic.LinearGradient(0, 1, 0, 0, + [ + {//鍙淇敼鍓嶅洓涓弬鏁板氨ok + offset: 0, + color: '#35535E' + }, //鏌卞浘娓愬彉鑹� + { + offset: 1, + color: '#92F7AD' + } + ] + ) + } + } + ] + } + option.xAxis.data = this.rightBottomChart1Data.map(item => item.monthStr) + option.series[0].data = this.rightBottomChart1Data.map(item => { + return { + name: item.monthStr, + value: item.reportNumber + } + }) + option.series[1].data = this.rightBottomChart1Data.map(item => { + return { + name: item.monthStr, + value: item.repairedNumber + } + }) + this.$nextTick(() => this.rightBottomChart1.setOption(option, true)) + }, + + initRightBottomChart2() { + this.rightBottomChart2 = this.$echarts.init(document.getElementById('right-bottom-chart-2')) + const option = { + tooltip: { + trigger: 'axis' + }, + grid: { + bottom: '5%', + top: '30%', + left: '10%', + right: '10%', + containLabel: true + }, + legend: { + top: 80, + right: '10%', + itemGap: 15, + textStyle: { + fontSize: 14, + fontFamily: 'LanTing', + color: '#eee', + height: 10, + rich: { + a: { + verticalAlign: 'bottom' + } + } + }, + data: ['鐐规璁″垝鏁�', '鐐规瀹屾垚鏁�'] + }, + xAxis: { + type: 'category', + data: [], + axisLine: { + lineStyle: { + color: '#eee' + } + }, + axisLabel: { + margin: 14, + fontSize: 14, + color: '#eee', + fontFamily: 'LanTing', + interval: 0, + rotate: 45 + }, + axisTick: { + show: true + } + }, + yAxis: [ + { + type: 'value', + minInterval: 1, + axisLine: { + show: true, + lineStyle: { + color: '#eee' + } + }, + axisTick: { + show: true + }, + splitLine: { + show: false + + }, + axisLabel: { + fontSize: 14, + color: '#eee', + fontWeight: 'bold', + margin: 14 + } + } + ], + series: [ + { + type: 'bar', + barWidth: 12, + name: '鐐规璁″垝鏁�', + data: [], + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'inside', + textStyle: { + color: '#eee', + fontSize: 12 + } + }, + itemStyle: { + color: new this.$echarts.graphic.LinearGradient(0, 1, 0, 0, + [ + {//鍙淇敼鍓嶅洓涓弬鏁板氨ok + offset: 0, + color: '#295485' + }, //鏌卞浘娓愬彉鑹� + { + offset: 1, + color: '#2F95F9' + } + ] + ) + } + }, + { + type: 'bar', + barWidth: 12, + name: '鐐规瀹屾垚鏁�', + data: [], + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'inside', + textStyle: { + color: '#eee', + fontSize: 12 + } + }, + itemStyle: { + color: new this.$echarts.graphic.LinearGradient(0, 1, 0, 0, + [ + {//鍙淇敼鍓嶅洓涓弬鏁板氨ok + offset: 0, + color: '#35535E' + }, //鏌卞浘娓愬彉鑹� + { + offset: 1, + color: '#92F7AD' + } + ] + ) + } + } + ] + } + option.xAxis.data = this.rightBottomChart2Data.map(item => item.monthStr) + option.series[0].data = this.rightBottomChart2Data.map(item => { + return { + name: item.monthStr, + value: item.planNumber + } + }) + option.series[1].data = this.rightBottomChart2Data.map(item => { + return { + name: item.monthStr, + value: item.completeNumber + } + }) + this.$nextTick(() => this.rightBottomChart2.setOption(option, true)) + }, + + initRightBottomChart3() { + this.rightBottomChart3 = this.$echarts.init(document.getElementById('right-bottom-chart-3')) + const option = { + tooltip: { + trigger: 'axis' + }, + grid: { + bottom: '5%', + top: '30%', + left: '10%', + right: '10%', + containLabel: true + }, + legend: { + top: 80, + right: '10%', + itemGap: 15, + textStyle: { + fontSize: 14, + fontFamily: 'LanTing', + color: '#eee', + height: 10, + rich: { + a: { + verticalAlign: 'bottom' + } + } + }, + data: ['淇濆吇璁″垝鏁�', '淇濆吇瀹屾垚鏁�'] + }, + xAxis: { + type: 'category', + data: [], + axisLine: { + lineStyle: { + color: '#eee' + } + }, + axisLabel: { + margin: 14, + fontSize: 14, + color: '#eee', + fontFamily: 'LanTing', + interval: 0, + rotate: 45 + }, + axisTick: { + show: true + } + }, + yAxis: [ + { + type: 'value', + minInterval: 1, + axisLine: { + show: true, + lineStyle: { + color: '#eee' + } + }, + axisTick: { + show: true + }, + splitLine: { + show: false + + }, + axisLabel: { + fontSize: 14, + color: '#eee', + fontWeight: 'bold', + margin: 14 + } + } + ], + series: [ + { + type: 'bar', + barWidth: 12, + name: '淇濆吇璁″垝鏁�', + data: [], + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'inside', + textStyle: { + color: '#eee', + fontSize: 12 + } + }, + itemStyle: { + color: new this.$echarts.graphic.LinearGradient(0, 1, 0, 0, + [ + {//鍙淇敼鍓嶅洓涓弬鏁板氨ok + offset: 0, + color: '#295485' + }, //鏌卞浘娓愬彉鑹� + { + offset: 1, + color: '#2F95F9' + } + ] + ) + } + }, + { + type: 'bar', + barWidth: 12, + name: '淇濆吇瀹屾垚鏁�', + data: [], + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'inside', + textStyle: { + color: '#eee', + fontSize: 12 + } + }, + itemStyle: { + color: new this.$echarts.graphic.LinearGradient(0, 1, 0, 0, + [ + {//鍙淇敼鍓嶅洓涓弬鏁板氨ok + offset: 0, + color: '#35535E' + }, //鏌卞浘娓愬彉鑹� + { + offset: 1, + color: '#92F7AD' + } + ] + ) + } + } + ] + } + option.xAxis.data = this.rightBottomChart3Data.map(item => item.monthStr) + option.series[0].data = this.rightBottomChart3Data.map(item => { + return { + name: item.monthStr, + value: item.planNumber + } + }) + option.series[1].data = this.rightBottomChart3Data.map(item => { + return { + name: item.monthStr, + value: item.completeNumber + } + }) + this.$nextTick(() => this.rightBottomChart3.setOption(option, true)) + }, + + handleWindowResize() { + if (this.leftChart1) this.leftChart1.resize() + if (this.leftChart2) this.leftChart2.resize() + if (this.rightTopChart) this.rightTopChart.resize() + if (this.rightBottomChart1) this.rightBottomChart1.resize() + if (this.rightBottomChart2) this.rightBottomChart2.resize() + if (this.rightBottomChart3) this.rightBottomChart3.resize() + } + } + } +</script> + +<style scoped lang="less"> + .component-container { + display: flex; + height: 100%; + justify-content: space-between; + + .left-container { + width: 18%; + display: flex; + flex-direction: column; + justify-content: space-between; + + /*鍥捐〃鍖哄煙*/ + > div:not(div:last-child) { + + .title-container { + position: relative; + width: 100%; + height: 3.6vw; + display: flex; + + img { + height: 100%; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 0; + } + + span { + position: relative; + z-index: 1; + font-size: 1.2vw; + font-family: 'ZongYi'; + margin: auto; + letter-spacing: 0.25vw; + } + } + + .left-chart-container { + height: calc(100% - 3.6vw); + } + } + + /*瀵艰埅鍖哄煙*/ + > div:last-child { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + + .navigator-container { + position: relative; + /*width: 100%;*/ + cursor: pointer; + text-align: center; + + img { + height: 3.38vw; + } + + span { + width: 100%; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-family: 'ZongYi'; + } + } + } + } + } +</style> \ No newline at end of file -- Gitblit v1.9.3