From 5636ee8eb5d1108668d0abf1e425268bde14922d Mon Sep 17 00:00:00 2001 From: hyingbo <1363390067@qq.com> Date: 星期一, 01 九月 2025 18:01:02 +0800 Subject: [PATCH] mdc首页开发 --- src/views/dashboard/TodoList.vue | 2 src/assets/index.png | 0 src/components/page/GlobalHeader.vue | 3 src/views/dashboard/Analysis.vue | 39 + src/views/dashboard/mdcIndex/MdcManagerSignage.vue | 1144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/api/signage.js | 12 6 files changed, 1,188 insertions(+), 12 deletions(-) diff --git a/src/api/signage.js b/src/api/signage.js index 8c0a115..68f02af 100644 --- a/src/api/signage.js +++ b/src/api/signage.js @@ -1,6 +1,18 @@ import { getAction, deleteAction, putAction, postAction, httpAction } from '@/api/manage' export default { + // 鑾峰彇鎵�鏈夎溅闂翠俊鎭� + getAllWorkShop: id => getAction('/mdc/home/getAllWorkShop', {}), // 鏍规嵁鐢ㄦ埛ID鑾峰彇鐢ㄦ埛淇℃伅 getUserByIdApi: id => getAction('sys/api/getUserById', { id }), + // 璁惧杩愯鐘舵�� + getEquipmentStatusStatisticsApi: productionId => getAction('/mdc/home/equipmentStatusStatistics', { productionId }), + // 璁惧鍒╃敤鐜� + getEquipmentUtilizationStatisticsApi: productionId => getAction('/mdc/home/equipmentUtilizationStatistics', { productionId }), + // 鍏ㄥ巶鍓�15澶╁埄鐢ㄧ巼鎶樼嚎鍥� + getEquipmentDayUtilizationStatisticsApi: productionId => getAction('/mdc/home/equipmentDayUtilizationStatistics', { productionId }), + // 璁惧OEE缁熻 + getEquipmentOEEStatistics: productionId => getAction('/mdc/home/equipmentOEEStatistics', { productionId }), + // 璁惧OEE鍜屽埄鐢ㄧ巼瀵规瘮 + getEquipmentMonthStatisticsApi: productionId => getAction('/mdc/home/equipmentMonthStatistics', { productionId }), } \ No newline at end of file diff --git a/src/assets/index.png b/src/assets/index.png new file mode 100644 index 0000000..b6fb451 --- /dev/null +++ b/src/assets/index.png Binary files differ diff --git a/src/components/page/GlobalHeader.vue b/src/components/page/GlobalHeader.vue index 4463912..68f95cd 100644 --- a/src/components/page/GlobalHeader.vue +++ b/src/components/page/GlobalHeader.vue @@ -17,8 +17,7 @@ :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="toggle"/> - <span v-if="device === 'desktop'">娆㈣繋杩涘叆 Jeecg-Boot 浼佷笟绾т綆浠g爜骞冲彴</span> - <span v-else>Jeecg-Boot</span> + <span v-if="device === 'desktop'">娆㈣繋杩涘叆 MDC鏅烘収杞﹂棿</span> <user-menu :theme="theme"/> </div> diff --git a/src/views/dashboard/Analysis.vue b/src/views/dashboard/Analysis.vue index 156fa95..f3a16fb 100644 --- a/src/views/dashboard/Analysis.vue +++ b/src/views/dashboard/Analysis.vue @@ -1,17 +1,25 @@ <template> - <Component :is="currentSignage" :userType="userType" :productionCode="productionCode" + <Component :is="currentSignage" + :userType="userType" + :productionCode="productionCode" :workshopSectionProductionCode="workshopSectionProductionCode" + v-if="[1,2,3,4].includes(userType)" > </Component> + <div v-else> <!-- 涓庣粍浠舵覆鏌撲簰鏂� --> + <img src="@/assets/index.png" style="width: 100%;height: 785px"> + </div> </template> <script> import signageApi from '@/api/signage' + import MdcManagerSignage from './mdcIndex/MdcManagerSignage.vue' import DncManagerSignage from './dncIndex/DncManagerSignage.vue' export default { name: "Analysis", components: { + MdcManagerSignage, DncManagerSignage }, data() { @@ -20,7 +28,7 @@ productionCode: '', branchFactoryProductionCode: '', workshopSectionProductionCode: '', - userType: '' + userType: '', } }, created() { @@ -28,20 +36,27 @@ }, methods: { showModuleByUserInfo() { - const id = JSON.parse(localStorage.getItem('pro__Login_Userinfo')).value.id + // 瀹夊叏澶勭悊锛氬厛鍒ゆ柇localStorage涓槸鍚﹀瓨鍦ㄧ敤鎴蜂俊鎭紝閬垮厤JSON.parse鎶ラ敊 + const userInfoStr = localStorage.getItem('pro__Login_Userinfo') + if (!userInfoStr) { + this.currentSignage = '' // 鏃犵敤鎴蜂俊鎭椂涓嶆覆鏌撶粍浠� + return + } + + const id = JSON.parse(userInfoStr).value.id signageApi.getUserByIdApi(id) .then(res => { - console.log("res", res.userType) - this.userType = res.userType + this.userType = res.userType // 璧嬪�煎悗鑷姩瑙﹀彂鏉′欢娓叉煋鍒ゆ柇 + // 鏍规嵁userType鍖归厤瀵瑰簲缁勪欢锛堟仮澶峜ase1鍜宑ase4鐨勯�昏緫锛� switch (this.userType) { // case 1: // //鍒�鍏风鐞� // this.currentSignage = 'EquipmentSignage' // break - // case 2: - // //mdc - // this.currentSignage = 'WorkshopSectionSignage' - // break + case 2: + // mdc + this.currentSignage = 'MdcManagerSignage' + break case 3: //dnc this.currentSignage = 'DncManagerSignage' @@ -55,6 +70,12 @@ break } }) + .catch(err => { + // 鎺ュ彛璇锋眰澶辫触鏃讹紝榛樿鏄剧ず鍥剧墖 + console.error('鑾峰彇鐢ㄦ埛绫诲瀷澶辫触锛�', err) + this.userType = '' + this.currentSignage = '' + }) } } } diff --git a/src/views/dashboard/TodoList.vue b/src/views/dashboard/TodoList.vue index 724d8b5..b1bec77 100644 --- a/src/views/dashboard/TodoList.vue +++ b/src/views/dashboard/TodoList.vue @@ -587,7 +587,7 @@ margin: 0; box-sizing: border-box; /* 鏂板锛氳缃鍣ㄦ渶澶ч珮搴︼紙鍙牴鎹〉闈㈠竷灞�璋冩暣锛屽500px/80vh锛� */ - max-height: 80vh; + max-height: 100vh; /* 鏂板锛氬瀭鐩存柟鍚戞孩鍑烘椂鏄剧ず婊氬姩鏉★紝姘村钩鏂瑰悜婧㈠嚭闅愯棌锛堥伩鍏嶅竷灞�閿欎贡锛� */ overflow-y: auto; overflow-x: hidden; diff --git a/src/views/dashboard/mdcIndex/MdcManagerSignage.vue b/src/views/dashboard/mdcIndex/MdcManagerSignage.vue new file mode 100644 index 0000000..276a717 --- /dev/null +++ b/src/views/dashboard/mdcIndex/MdcManagerSignage.vue @@ -0,0 +1,1144 @@ +<template> + <div class="home-container"> + <div class="tab-nav"> + <div + v-for="(tab, index) in tabList" + :key="index" + :class="['tab-item', activeTab === index ? 'tab-active' : '']" + @click="handleTabChange(index)" + > + {{ tab.label }} + </div> + </div> + + + <div class="chart-container"> + <div class="left-cards"> + <div class="card left-cards-card"> + <div id="running_state_chart" style="width:100%;height: 45%;max-height: 45vh"></div> + <div id="efficiency_chart" style="width: 100%;height: 55%;max-height: 55vh"></div> + </div> + </div> + + <div class="right-cards"> + <div class="card right-top-card"> + <div id="first15DaysEfficiency_chart" style="width:100%;height: 100%;max-height: 50vh"></div> + </div> + + <div class="right-bottom-card"> + <div class="card right-bottom-left-card"> + <div id="bar_chart" style="width:100%;height: 100%;max-height: 50vh"></div> + </div> + <div class="card right-bottom-right-card"> + <div id="double_bar_chart" style="width:100%;height: 100%;max-height: 50vh"></div> + </div> + </div> + </div> + </div> + </div> +</template> + +<script> + +import signageApi from '@/api/signage' +import moment from 'moment' + +export default { + name: 'DncManagerSignage', + components: {}, + data() { + return { + tabList: [], + activeTab: -1, // 鍒濆鏃犻�変腑椤电锛�-1琛ㄧず鏈�夋嫨鐘舵�侊級 + firstEnterClientWidth: null, + pieChartRadius: ['45%', '55%'], + normalPieChartRadius: ['45%', '55%'], + currentPageProductionId: null, + runningStateChart: '', + efficiencyChart: '', + efficiencyData: [], + barChart: '', + barChartData: [], + doubleBarChart: '', + doubleBarChartData: {}, + runningStateChartDataRequireFinished: false, + first15DaysEfficiencyChart: '', + first15DaysEfficiencyData: { + dataList: [], + dateList: [] + }, + runningStateData: [ + { value: '0', name: '鍏虫満' }, + { value: '0', name: '鎶ヨ' }, + { value: '0', name: '寰呮満' }, + { value: '0', name: '杩愯' } + ] + } + }, + mounted() { + window.addEventListener('resize', this.handleWindowResize) + // this.re_drawPieChart() + this.getAllWorkShop() + this.getChartDataByApi() + }, + beforeDestroy() { + // 缁勪欢閿�姣佸墠绉婚櫎鐩戝惉 + window.removeEventListener('resize', this.handleWindowResize) + this.destroyEchartsInstances() + }, + methods: { + + getAllWorkShop() { + this.tabList = [] + signageApi.getAllWorkShop() + .then(res => { + if (res.success) { + this.tabList = res.result.map(workshop => ({ + label: workshop.productionName, + factoryId: workshop.id + })) + + if (this.tabList.length > 0) { + this.activeTab = -1 + this.destroyEchartsInstances() + this.getChartDataByApi() + } + } else { + this.tabList = [] + this.activeTab = -1 + } + }) + .catch(err => { + this.tabList = [] + this.activeTab = -1 + this.destroyEchartsInstances() + this.getChartDataByApi() + }) + }, + + destroyEchartsInstances() { + const charts = [ + this.runningStateChart, + this.efficiencyChart, + this.first15DaysEfficiencyChart, + this.barChart, + this.doubleBarChart + ] + charts.forEach(chart => { + if (chart && chart.dispose) chart.dispose() + }) + }, + + handleTabChange(index) { + // 1. 濡傛灉鐐瑰嚮鐨勬槸鈥滃凡閫変腑鐨勯〉绛锯�濓紝鎵ц鈥滃彇娑堥�変腑鈥濋�昏緫 + if (this.activeTab === index) { + this.activeTab = -1; // 閲嶇疆涓烘湭閫変腑鐘舵�� + this.destroyEchartsInstances(); // 閿�姣佹墍鏈夊浘琛ㄥ疄渚� + this.getChartDataByApi(); + return; + } + + // 2. 甯歌鍒囨崲椤电閫昏緫锛堝師鏈夐�昏緫淇濈暀锛� + this.activeTab = index; + this.destroyEchartsInstances(); + this.getChartDataByApi(); + }, + + /* 璋冪敤鎺ュ彛鑾峰彇鍥捐〃鏁版嵁姹囨�绘柟娉� */ + getChartDataByApi() { + let currentFactoryId = '' + if (this.tabList[this.activeTab] != null && this.tabList[this.activeTab] !== undefined) { + currentFactoryId = this.tabList[this.activeTab].factoryId + } + console.log('currentFactoryId', currentFactoryId) + this.getRunningStateDataByApi(currentFactoryId) + this.getEfficiencyDataByApi(currentFactoryId) + this.getFirst15DaysEfficiencyDataByApi(currentFactoryId) + this.getBarChartDataByApi(currentFactoryId) + this.getDoubleBarChartDataByApi(currentFactoryId) + }, + + /* 璋冪敤鎺ュ彛鑾峰彇璁惧杩愯鐘舵�� */ + getRunningStateDataByApi(productionCode) { + this.runningStateChart = this.$echarts.init(document.getElementById('running_state_chart')) + this.runningStateChart.showLoading({ + text: '鏁版嵁鍔犺浇涓� ...', + color: '#0696e1', // 鍔犺浇鍔ㄧ敾棰滆壊 + textColor: '#fff', + maskColor: 'transparent' // 閬僵灞� + }) + signageApi.getEquipmentStatusStatisticsApi(productionCode) + .then(res => { + if (res.success) { + this.runningStateData = res.result.list + this.currentPageProductionId = res.result.productionId + this.runningStateChartDataRequireFinished = true + this.drawRunningStateChart(res.result.productionId) + } + }) + }, + + /* 璋冪敤鎺ュ彛鑾峰彇璁惧鍒╃敤鐜� */ + getEfficiencyDataByApi(productionCode) { + this.efficiencyChart = this.$echarts.init(document.getElementById('efficiency_chart')) + this.efficiencyChart.showLoading({ + text: '鏁版嵁鍔犺浇涓� ...', + color: '#0696e1', // 鍔犺浇鍔ㄧ敾棰滆壊 + textColor: '#fff' + }) + signageApi.getEquipmentUtilizationStatisticsApi(productionCode) + .then(res => { + if (res.success) { + this.efficiencyData = res.result + this.drawEfficiencyChart() + } + }) + }, + + /* 璋冪敤鎺ュ彛鑾峰彇鍓�15澶╁埄鐢ㄧ巼 */ + getFirst15DaysEfficiencyDataByApi(productionCode) { + this.first15DaysEfficiencyChart = this.$echarts.init(document.getElementById('first15DaysEfficiency_chart')) + this.first15DaysEfficiencyChart.showLoading({ + text: '鏁版嵁鍔犺浇涓� ...', + color: '#0696e1', // 鍔犺浇鍔ㄧ敾棰滆壊 + textColor: '#000000', + maskColor: 'transparent' // 閬僵灞� + }) + signageApi.getEquipmentDayUtilizationStatisticsApi(productionCode) + .then(res => { + if (res.success) { + this.first15DaysEfficiencyData = res.result + this.drawFirst15DaysEfficiencyDataChart() + } + }) + }, + /* 缁樺埗鍓�7澶╁埄鐢ㄧ巼鏌卞浘 */ + drawFirst15DaysEfficiencyDataChart() { + this.first15DaysEfficiencyData.dateList.forEach(item => { + if (!this.first15DaysEfficiencyData.dataList.map(item => item.date).includes(item)) { + const dateObj = { + date: item.date, + openRate: 0, + startRate: 0, + utilizationRate: 0 + } + this.first15DaysEfficiencyData.dataList.push(dateObj) + } + }) + const dateList = this.first15DaysEfficiencyData.dataList.map(item => item.date) + const newData = { + xAxis: dateList, + yAxis: [ + { + name: '鍒╃敤鐜�', + value: this.first15DaysEfficiencyData.dataList.map(item => item.utilizationRate) + }, + { + name: '寮�鍔ㄧ巼', + value: this.first15DaysEfficiencyData.dataList.map(item => item.startRate) + }, + { + name: '寮�鏈虹巼', + value: this.first15DaysEfficiencyData.dataList.map(item => item.openRate) + } + ], + yAxisName: '鍓�15澶╁埄鐢ㄧ巼(%)' + } + let legendData = [] + let seriesData = [] + let colorArr = ['#A7F0C1', '#FAE893', '#66DFE2'] + legendData = newData.yAxis.map((item) => item.name) + seriesData = newData.yAxis.map((item1, index1) => { + return { + name: item1.name, + type: 'bar', + symbol: 'circle', + symbolSize: 8, + itemStyle: { + color: colorArr[index1], + barBorderRadius: 100 + }, + lineStyle: { + width: 2 + }, + markPoint: { + show: true + }, + yAxisIndex: 1, + data: item1.value // 鎶樼嚎鍥剧殑鏁版嵁 + } + }) + const option = { + grid: { + containLabel: true, + bottom: '1%', + top: '20%', + left: '2%', + right: '1%' + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + }, + formatter: function(params) { + let result = '' + params.forEach((item, index) => { + let dom = `<span style="display:inline-block;width:10px;height:10px;border-radius:100px;margin-right:5px;background:${item.color}"></span>${item.seriesName}锛�${item.value}%` + if (index === 0) { + result = `<span style="font-weight:bolder;">${item.name}</span>` + } + result += '<br />' + dom + }) + return result + } + }, + legend: { + top: 20, + right: 'center', + data: legendData, + itemGap: 10, + textStyle: { + fontSize: 14, + color: '#000000' + } + }, + xAxis: { + data: newData.xAxis || [], + axisLabel: { + interval: 0, + show: true, + fontSize: 14, + color: '#000000' + // rotate: -30, + }, + axisLine: { + show: true, + lineStyle: { + color: '#000000' + } + }, + axisTick: { + show: true, + alignWithLabel: true + } + }, + yAxis: [ + { + name: newData.yAxisName, + nameTextStyle: { + color: '#1AD8DE', + fontSize: 18, + padding: [0, 0, 0, 110] + }, + nameGap: 30, + type: 'value', + position: 'left', + axisLine: { + show: true, + lineStyle: { + color: '#000000' + } + }, + axisTick: { + show: false + }, + splitLine: { + show: false, + lineStyle: { + color: '#000000' + } + } + }, + { + type: 'value', + position: 'right', + splitNumber: 5, + max: 100, + axisLabel: { + show: true, + color: '#000000', + fontSize: 14 + }, + axisLine: { + show: true, + lineStyle: { + color: '#000000' + } + }, + axisTick: { + show: true + }, + splitLine: { + show: false, + lineStyle: { + color: '#000000' + } + } + } + ], + series: seriesData, + dataZoom: { + show: false, + startValue: 0, // 浠庡ご寮�濮嬨�� + endValue: 14 // 涓�娆℃�у睍绀哄嚑涓� + } + // toolbox: { + // show: true, + // feature: { + // mark: { show: true }, + // magicType: { show: true, type: ['line', 'bar'] }, + // restore: { show: true }, + // saveAsImage: { show: true, name: '鍓�7澶╁埄鐢ㄧ巼缁熻鍥�', pixelRatio: 1 } + // } + // } + } + this.first15DaysEfficiencyChart.setOption(option, true) + this.first15DaysEfficiencyChart.hideLoading() + this.first15DaysEfficiencyChart.on('click', params => { + this.$router.push({ + name: 'mdc-base-StatisticsChart', + params: { + isEquipment: true, + productionId: params.name, + tierName: this.first15DaysEfficiencyData.dataList.find(item => item.date === params.name).date + } + }) + }) + }, + + + /* 璋冪敤鎺ュ彛鑾峰彇璁惧OEE缁熻 */ + getBarChartDataByApi(productionCode) { + this.barChart = this.$echarts.init(document.getElementById('bar_chart')) + this.barChart.showLoading({ + text: '鏁版嵁鍔犺浇涓� ...', + color: '#0696e1', // 鍔犺浇鍔ㄧ敾棰滆壊 + textColor: '#fff' + }) + signageApi.getEquipmentOEEStatistics(productionCode) + .then(res => { + if (res.success && res.result) { + this.barChartData = res.result + this.drawBarChart() + } + }) + .finally(() => { + this.barChart.hideLoading() + }) + }, + + /* 缁樺埗鍗曟煴鍥� */ + drawBarChart() { + const defaultData = [] + const colorArray = ['#79CEAA', '#F589A2', '#6FBF9D', '#66DFE2', '#A7F0C1', '#FAE893', '#F7B7A0'] + const dataMax = this.barChartData.length > 0 ? +this.barChartData.sort((x, y) => +y.value - +x.value)[0].value : 0 + let yAxisMax + if (dataMax === 0) yAxisMax = 1 // 鑻ユ暟鎹腑鏈�澶у�间负0锛屽垯灏嗚儗鏅粯璁ゅ�艰缃负1 + else yAxisMax = Math.ceil(dataMax / 5) * 5 // 璁剧疆鏌卞浘鑳屾櫙闃村奖榛樿鍊硷紝鎬濊矾涓烘暟鎹渶澶у�兼渶鎺ヨ繎鐨勮兘琚�5鏁撮櫎鐨勬暟瀛� + const yAxisInterval = yAxisMax / 5 // 鍚屾椂灏嗗埢搴﹀�煎垎鎴�5浠� + this.barChartData.forEach(item => defaultData.push(yAxisMax)) + const option = { + title: { + show: true, // 鏄惁鏄剧ず鏍囬锛岄粯璁や负true + text: '', // 涓绘爣棰樻枃鏈� + x: 'left', // 鏍囬姘村钩瀹夋斁浣嶇疆锛屽彲閫夊�间负'left'銆�'center'銆�'right'鎴栧叿浣撶殑姘村钩鍧愭爣鍊� + y: 'top', // 鏍囬鍨傜洿瀹夋斁浣嶇疆锛屽彲閫夊�间负'top'銆�'bottom'銆�'center'鎴栧叿浣撶殑鍨傜洿鍧愭爣鍊� + textStyle: { + // 涓绘爣棰樻枃鏈牱寮� + fontSize: 18, + fontWeight: 'normal', + color: '#1AD8DE' + } + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + }, + formatter: function(params) { + return '<span style="font-weight:bolder;">' + params[0].name + '</span><br/>' + + '<span style="display:inline-block; width:10px; height:10px; border-radius:100px; margin-right:5px; background:' + params[0].color + '"></span>' + ' OEE: ' + params[0].value + '%' + }, + // backgroundColor: 'rgba(9, 24, 48, 0.5)', + borderColor: 'rgba(75, 253, 238, 0.4)', + textStyle: { + // color: '#CFE3FC' + }, + borderWidth: 1 + }, + grid: { + top: '20%', + left: '10%' + }, + xAxis: [{ + name: '', + nameLocation: 'middle', + nameGap: 40, // x杞磏ame涓庢í鍧愭爣杞寸嚎鐨勯棿璺� + type: 'category', + data: this.barChartData.map(item => item.productionId), + axisLine: { + lineStyle: { + color: '#000000' + } + }, + axisLabel: { + show: true, // 鏄惁鏄剧ず鍒诲害鏍囩锛岄粯璁ゆ樉绀� + interval: 0, // 鍧愭爣杞村埢搴︽爣绛剧殑鏄剧ず闂撮殧锛屽湪绫荤洰杞翠腑鏈夋晥锛涢粯璁や細閲囩敤鏍囩涓嶉噸鍙犵殑绛栫暐闂撮殧鏄剧ず鏍囩锛涘彲浠ヨ缃垚0寮哄埗鏄剧ず鎵�鏈夋爣绛撅紱濡傛灉璁剧疆涓�1锛岃〃绀恒�庨殧涓�涓爣绛炬樉绀轰竴涓爣绛俱�忥紝濡傛灉鍊间负2锛岃〃绀洪殧涓や釜鏍囩鏄剧ず涓�涓爣绛撅紝浠ユ绫绘帹銆� + rotate: this.barChartData.length >= 6 ? -30 : 0, // 鍒诲害鏍囩鏃嬭浆鐨勮搴︼紝鍦ㄧ被鐩酱鐨勭被鐩爣绛炬樉绀轰笉涓嬬殑鏃跺�欏彲浠ラ�氳繃鏃嬭浆闃叉鏍囩涔嬮棿閲嶅彔锛涙棆杞殑瑙掑害浠�-90搴﹀埌90搴� + inside: false, // 鍒诲害鏍囩鏄惁鏈濆唴锛岄粯璁ゆ湞澶� + margin: 10, // 鍒诲害鏍囩涓庤酱绾夸箣闂寸殑璺濈 + formatter: value => { + return `${this.barChartData.find(item => item.productionId === value).name}` + }, + fontSize: 14 + }, + axisTick: { + show: true, + alignWithLabel: true + } + }], + yAxis: [{ + name: '%', + min: 0, + max: yAxisMax, + interval: yAxisInterval, + axisLabel: { + formatter: '{value}', + color: '#000000', + fontSize: 14 + }, + axisTick: { + show: false + }, + axisLine: { + show: false, + lineStyle: { + color: '#000000' + } + }, + splitLine: { + show: false, + lineStyle: { + color: 'rgba(255,255,255,0.12)' + } + } + }], + series: [{ + type: 'bar', + data: this.barChartData, + barWidth: this.barChartData.length > 5 ? '40%' : 30, + itemStyle: { + color: function(params) { + let num = colorArray.length + return colorArray[params.dataIndex % num] + }, + barBorderRadius: 100 + }, + zlevel: 1, + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'top', + textStyle: { + color: '#000000', + fontSize: 16 + } + } + }] + } + option.title.text = moment().subtract(1, 'month').format('M鏈�') + `OEE` + this.barChart.setOption(option, true) + }, + + /* 缁樺埗璁惧杩愯鐘舵�佺帿鐟伴ゼ鍥� */ + drawRunningStateChart() { + const option = { + height: 300, + title: { + show: true, // 鏄惁鏄剧ず鏍囬锛岄粯璁や负true + text: '璁惧鐘舵��', // 涓绘爣棰樻枃鏈� + x: 'left', // 鏍囬姘村钩瀹夋斁浣嶇疆锛屽彲閫夊�间负'left'銆�'center'銆�'right'鎴栧叿浣撶殑姘村钩鍧愭爣鍊� + y: 'top', // 鏍囬鍨傜洿瀹夋斁浣嶇疆锛屽彲閫夊�间负'top'銆�'bottom'銆�'center'鎴栧叿浣撶殑鍨傜洿鍧愭爣鍊� + textStyle: { + // 涓绘爣棰樻枃鏈牱寮� + fontSize: 18, + fontWeight: 'normal', + color: '#1AD8DE' + } + }, + tooltip: { + trigger: 'item', + formatter: function(params) { + return '<span style="font-weight:bolder;">' + params.name + '</span><br/>' + + '<span style="display:inline-block; width:10%; height:10%; border-radius:100px; margin-right:5px; background:' + params.color + '"></span>' + `${params.value}锛�${params.percent}%锛塦 + } + }, + legend: { + top: 'auto', + left: 'center', + bottom: '10%', // 搴曢儴璺濈 + orient: 'horizontal', // 姘村钩鎺掑垪 + right: '10%', + // bottom: "0", + itemWidth: 14, + itemHeight: 14, + icon: 'roundRect', + itemGap: 15, + textStyle: { + color: '#000', + fontSize: 14, + padding: [0, 0, 0, 0] + }, + data: ['鍏虫満', '鎶ヨ', '寰呮満', '杩愯'] + }, + grid: { + containLabel: true + }, + series: [ + { + type: 'pie', + roseType: 'angle', // 鐜懓鍥� + // selectedMode: "single", + radius: this.pieChartRadius, + center: ['45%', '55%'], + color: [ + '#8B8B8B', + '#F56436', + '#FFFF40', + '#0FC61A' + ], + label: { + position: 'outside', + show: true, + color: '#000', + // textBorderColor: 'inherit', + // textBorderWidth: 1, + fontSize: 16, + formatter: function(params) { + if (params.name !== '') { + return `${params.name}:${params.value}` + } + } + }, + labelLine: { + show: true, + length2: 10, + length: 10 + }, + data: this.runningStateData + } + ] + } + this.runningStateChart.setOption(option, true) + this.runningStateChart.hideLoading() + }, + + /* 缁樺埗璁惧鍒╃敤鐜囪兌鍥婂浘 */ + drawEfficiencyChart() { + const data = this.efficiencyData || [] + + // 鏃犺鏁版嵁鏄惁涓虹┖锛屽厛鍙栨秷loading鐘舵�� + this.efficiencyChart.hideLoading() + + // 鏍囬鏂囨湰缁熶竴澶勭悊 + const titleText = `${moment().subtract(1, 'days').format('M鏈圖鏃�')}鍚勮溅闂村埄鐢ㄧ巼鎺掕` + + if (data.length === 0) { + // 鏁版嵁涓虹┖鏃跺彧灞曠ず鏍囬 + const option = { + title: { + show: true, + text: titleText, + x: 'left', + y: 'top', + textStyle: { + fontSize: 18, + fontWeight: 'normal', + color: '#1AD8DE' + } + }, + // 闅愯棌鎵�鏈夎酱鍜岀綉鏍� + xAxis: { show: false }, + yAxis: [{ show: false }, { show: false }], + grid: { show: false }, + series: [] + } + this.efficiencyChart.setOption(option, true) + return + } + + // 鏁版嵁涓嶄负绌烘椂鐨勬甯稿鐞嗛�昏緫锛堜繚鎸佷笉鍙橈級 + const colorArray = [ + { top: '#79CEAA', bottom: '#79CEAA' }, + { top: '#F589A2', bottom: '#F589A2' }, + { top: '#6FBF9D', bottom: '#6FBF9D' }, + { top: '#66DFE2', bottom: '#66DFE2' }, + { top: '#A7F0C1', bottom: '#A7F0C1' }, + { top: '#FAE893', bottom: '#FAE893' }, + { top: '#F7B7A0', bottom: '#F7B7A0' } + ] + + const dataMax = +data.sort((x, y) => +y.value - +x.value)[0].value + let yAxisMax = dataMax === 0 ? 1 : Math.ceil(dataMax / 5) * 5 + const yAxisInterval = yAxisMax / 5 + + const option = { + title: { + show: true, + text: titleText, + x: 'left', + y: 'top', + textStyle: { + fontSize: 18, + fontWeight: 'normal', + color: '#1AD8DE' + } + }, + grid: { + left: '3%', + right: '5%', + bottom: '0%', + top: '6%', + containLabel: true + }, + tooltip: { + trigger: 'axis', + axisPointer: { type: 'none' }, + formatter: function(params) { + return `<span style="font-weight:bolder;">${params[0].name}</span><br/> + <span style="display:inline-block; width:10px; height:10px; border-radius:100px; margin-right:5px; background:${params[0].color.colorStops[params[0].dataIndex].color}"></span> + ${params[0].seriesName} : ${params[0].value}%` + } + }, + xAxis: { + name: '', + nameTextStyle: { color: '#000000' }, + axisLabel: { + margin: 20, + textStyle: { color: '#000000' } + }, + show: true, + min: 0, + max: 'dataMax', + interval: yAxisInterval, + type: 'value', + axisTick: { show: false }, + splitLine: { show: false } + }, + yAxis: [{ + type: 'category', + inverse: true, + triggerEvent: true, + axisLabel: { + show: true, + textStyle: { color: '#000000', fontSize: '14', fontWeight: 'bolder' }, + formatter: function(value) { + return `${data.find(item => item.productionCode === value).name}` + } + }, + splitLine: { show: false }, + axisTick: { show: false }, + axisLine: { show: false }, + data: data.map(item => item.productionCode) + }, { + type: 'category', + inverse: true, + axisTick: 'none', + axisLine: 'none', + show: true, + axisLabel: { + textStyle: { color: '#000000', fontSize: '14' }, + formatter: '{value}%' + }, + data: data + }], + series: [{ + name: '鍒╃敤鐜�', + type: 'bar', + zlevel: 1, + itemStyle: { + barBorderRadius: 100, + color: function(params) { + const num = colorArray.length + return { + type: 'linear', + colorStops: [{ + offset: 0, + color: colorArray[params.dataIndex % num].bottom + }, { + offset: 1, + color: colorArray[params.dataIndex % num].top + }] + } + } + }, + barWidth: 12, + data: data + }] + } + + this.efficiencyChart.setOption(option, true) + }, + + re_drawPieChart() { + const clientWidth = document.body.clientWidth || document.documentElement.clientWidth + if (this.firstEnterClientWidth != 1920) { + this.pieChartRadius = this.normalPieChartRadius.map(item => item = (+item.slice(0, -1) * (clientWidth / 1920)) + '%') + } else { + this.pieChartRadius = this.normalPieChartRadius.map(item => item = (+item.slice(0, -1) * (clientWidth / this.firstEnterClientWidth)) + '%') + } + console.log('pieChartRadius', this.pieChartRadius) + }, + + + /* 璋冪敤鎺ュ彛鑾峰彇璁惧OEE鍜屽埄鐢ㄧ巼瀵规瘮 */ + getDoubleBarChartDataByApi(productionCode) { + this.doubleBarChart = this.$echarts.init(document.getElementById('double_bar_chart')) + this.doubleBarChart.showLoading({ + text: '鏁版嵁鍔犺浇涓� ...', + color: '#0696e1', // 鍔犺浇鍔ㄧ敾棰滆壊 + textColor: '#000000', + maskColor: 'transparent' // 閬僵灞� + }) + signageApi.getEquipmentMonthStatisticsApi(productionCode) + .then(res => { + if (res.success) { + this.doubleBarChartData = res.result + this.drawDoubleBarChart() + } + }) + }, + /* 缁樺埗鍙屾煴鍥� */ + drawDoubleBarChart() { + const option = { + title: { + text: '鏈堝埄鐢ㄧ巼OEE缁熻', + left: 'left', + top: 'top', + textStyle: { + fontSize: 18, + fontWeight: 'normal', + color: '#1AD8DE' + } + }, + color: ['#66DFE2', '#79CEAA'], + tooltip: { + confine: true, + formatter: function(params) { + return '<span style="font-weight:bolder;">' + params.name + '</span><br/>' + + '<span style="display:inline-block; width:10px; height:10px; border-radius:100px; margin-right:5px; background:' + params.color + '"></span>' + params.seriesName + ' : ' + params.value + '%' + } + }, + grid: { + left: '5%', + right: '4%', + bottom: '10%', + top: '20%', + containLabel: true + }, + legend: { + icon: 'roundRect', + orient: 'horizontal', + left: 'center', + itemWidth: 14, + itemHeight: 14, + formatter: ['{a|{name}}'].join('\n'), + textStyle: { + fontSize: 14, + color: '#000000', + height: 8, + rich: { + a: { + verticalAlign: 'bottom' + } + } + }, + data: ['OEE', 'TEEP'] + }, + xAxis: { + type: 'category', + data: this.doubleBarChartData.dateList, + axisLine: { + lineStyle: { + color: 'rgba(0,0,0)' + } + }, + axisLabel: { + fontSize: 14, + color: '#000000' + }, + axisTick: { + show: true + } + }, + yAxis: [ + { + name: '%', + nameTextStyle: { + color: '#000000' + }, + type: 'value', + min: 0, + minInterval: 1, + axisLine: { + show: true + }, + axisTick: { + show: true + }, + splitLine: { + show: false, + lineStyle: { + color: 'rgba(255, 255, 255, 0.15)' + // type: 'dashed', // dotted 铏氱嚎 + } + }, + axisLabel: { + fontSize: 14, + color: '#000000', + fontFamily: 'Bebas' + } + }, + { + type: 'value', + axisLine: { + show: true + }, + axisTick: { + show: false + }, + splitLine: { + show: false + }, + axisLabel: { + fontSize: 14, + formatter: '{value}%', // 鍙充晶Y杞存枃瀛楁樉绀� + fontFamily: 'Bebas', + color: '#6A93B9' + }, + splitArea: { + show: false + } + }], + series: [{ + type: 'bar', + barWidth: 15, + itemStyle: { barBorderRadius: 100 }, + name: 'OEE', + data: this.doubleBarChartData.oeeList, + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'inside', + textStyle: { + color: '#000000', + fontSize: 12 + } + } + }, { + type: 'bar', + barWidth: 15, + itemStyle: { barBorderRadius: 100 }, + name: 'TEEP', + data: this.doubleBarChartData.utilizationList, + label: { + show: false, + lineHeight: 10, + formatter: params => { + if (+params.value === 0) return '' + else return params.value + }, + position: 'inside', + textStyle: { + color: '#000000', + fontSize: 12 + } + } + } + ] + } + this.doubleBarChart.setOption(option, true) + this.doubleBarChart.hideLoading() + }, + + /** + * 绐楀彛灏哄鍙樺寲鏃惰Е鍙� + * 璋冩暣鍥捐〃灏哄浠ラ�傚簲鍒嗚鲸鐜� + */ + handleWindowResize() { + // this.re_drawPieChart() + if (this.runningStateChart) this.runningStateChart.resize() + if (this.efficiencyChart) this.efficiencyChart.resize() + if (this.first15DaysEfficiencyChart) this.first15DaysEfficiencyChart.resize() + if (this.barChart) this.barChart.resize() + if (this.doubleBarChart) this.doubleBarChart.resize() + } + } +} +</script> + +<style scoped> +/* 椤电瀵艰埅鏍峰紡 */ +.tab-nav { + display: flex; + gap: 8px; + padding: 10px 16px; + background-color: #ffffff; + border-radius: 8px; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); + overflow-x: auto; + scrollbar-width: none; +} + +.tab-nav::-webkit-scrollbar { + display: none; +} + +.tab-item { + padding: 8px 16px; + font-size: 14px; + color: #666666; + border-radius: 20px; + cursor: pointer; + white-space: nowrap; + transition: all 0.3s ease; +} + +.tab-active { + background-color: #0696e1; + color: #ffffff; + font-weight: 500; +} + +.tab-item:hover { + background-color: #f0f5ff; + color: #0696e1; +} + +/* 涓诲鍣ㄦ牱寮� */ +.home-container { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 1px; + box-sizing: border-box; + gap: 16px; + background-color: #f0f2f7; +} + +/* 鍥捐〃瀹瑰櫒鏍峰紡 */ +.chart-container { + display: flex; + gap: 16px; + flex: 1; + min-width: 0; +} + +/* 宸︿晶鍗$墖鍖哄煙 */ +.left-cards { + flex: 1; + min-width: 0; +} + +/* 鍙充晶鍗$墖鍖哄煙 */ +.right-cards { + flex: 2; + min-width: 0; + display: flex; + flex-direction: column; + gap: 16px; +} + +/* 閫氱敤鍗$墖鏍峰紡 */ +.card { + background: #ffffff; + border-radius: 8px; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); + padding: 16px; + display: flex; + flex-direction: column; + overflow: hidden; + justify-content: flex-start; +} + +/* 宸︿晶鍗$墖 */ +.left-cards-card { + height: 100%; + min-height: 100vh; +} + +/* 鍙充晶椤堕儴鍗$墖 */ +.right-top-card { + flex: 1; + min-height: 50vh; +} + +/* 鍙充晶搴曢儴瀹瑰櫒 */ +.right-bottom-card { + flex: 1; + min-width: 0; + min-height: 50vh; + display: flex; + gap: 16px; +} + +/* 鍙充晶搴曢儴宸﹀彸鍗$墖 */ +.right-bottom-left-card, +.right-bottom-right-card { + flex: 1; +} + +/* 鍝嶅簲寮忚皟鏁� */ +@media (max-width: 1200px) { + .chart-container { + gap: 12px; + } + + .card { + padding: 12px; + } +} + +@media (max-width: 992px) { + .chart-container { + flex-direction: column; + } + + .left-cards, .right-cards { + width: 100%; + } + + .left-cards { + margin-bottom: 16px; + } + + .right-bottom-card { + flex-direction: column; + } + + .tab-item { + padding: 6px 12px; + font-size: 13px; + } +} + +@media (max-width: 768px) { + .home-container { + padding: 8px; + } + + .tab-nav { + padding: 8px; + margin-bottom: 8px; + } +} +</style> \ No newline at end of file -- Gitblit v1.9.3