| | |
| | | <template> |
| | | <div class="title"></div> |
| | | <div id="big-data-container" class="big-data-container"> |
| | | <div class="head"> |
| | | <h1>WMSç³»ç»çæ§ä¸å¿</h1> |
| | | <div class="head-actions"> |
| | | <el-button type="primary" @click="toggleFullScreen" size="small" round> |
| | | <el-icon><FullScreen /></el-icon> |
| | | {{ isFullScreen ? 'éåºå
¨å±' : 'å
¨å±æ¾ç¤º' }} |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <div class="data-container"> |
| | | <div class="data-left"> |
| | | <div class="data-left-item"> |
| | | <div class="title">å¨åºå
¥åºç»è®¡</div> |
| | | <div id="chart-week-inout" style="height: calc(50% - 10px)"></div> |
| | | </div> |
| | | <div class="data-left-item"> |
| | | <div class="title">æåºå
¥åºè¶å¿</div> |
| | | <div id="chart-month-inout" style="height: calc(50% - 10px)"></div> |
| | | </div> |
| | | </div> |
| | | <div class="data-center"> |
| | | <div class="data-center-item"> |
| | | <div class="title">åºåæ°æ®</div> |
| | | <div class="center-top-num"> |
| | | <div class="item"> |
| | | <div class="text">æ»è´§ä½æ°é</div> |
| | | <div class="num">{{ totalLocations }}</div> |
| | | </div> |
| | | <div class="item"> |
| | | <div class="text">仿¥å
¥åº</div> |
| | | <div class="num">{{ todayInbound }}</div> |
| | | </div> |
| | | <div class="item"> |
| | | <div class="text">仿¥åºåº</div> |
| | | <div class="num">{{ todayOutbound }}</div> |
| | | </div> |
| | | <div class="item"> |
| | | <div class="text">æ¬å¨å
¥åº</div> |
| | | <div class="num">{{ weekInbound }}</div> |
| | | </div> |
| | | <div class="item"> |
| | | <div class="text">æ¬å¨åºåº</div> |
| | | <div class="num">{{ weekOutbound }}</div> |
| | | </div> |
| | | <div class="item"> |
| | | <div class="text">æ¬æå
¥åº</div> |
| | | <div class="num">{{ monthInbound }}</div> |
| | | </div> |
| | | <div class="item"> |
| | | <div class="text">æ¬æåºåº</div> |
| | | <div class="num">{{ monthOutbound }}</div> |
| | | </div> |
| | | <!-- <div class="item"> |
| | | <div class="text">å¾
å¤ç订å</div> |
| | | <div class="num">{{ pendingOrders }}</div> |
| | | </div> --> |
| | | </div> |
| | | </div> |
| | | <div class="data-center-item"> |
| | | <div class="title">æ¥åºå
¥åºæç»</div> |
| | | <div id="chart-daily-inout" style="height: calc(100% - 30px)"></div> |
| | | </div> |
| | | </div> |
| | | <div class="data-right"> |
| | | <div class="data-right-item"> |
| | | <div class="title">åºåååè¶å¿</div> |
| | | <div id="chart-stock-trend" style="height: calc(50% - 10px)"></div> |
| | | </div> |
| | | <div class="data-right-item"> |
| | | <div class="title">è´§ä½ç¶æåå¸</div> |
| | | <div id="chart-warehouse-utilization" style="height: calc(50% - 10px)"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { ref, reactive } from 'vue' |
| | | |
| | | import { ref, reactive, onMounted, onUnmounted } from 'vue' |
| | | import * as echarts from 'echarts' |
| | | import http from '@/api/http.js' |
| | | import { FullScreen } from '@element-plus/icons-vue' |
| | | |
| | | let chartDailyInout, chartWeekInout, chartMonthInout, chartWarehouseUtilization, chartStockTrend |
| | | |
| | | export default { |
| | | setup() { |
| | | return { |
| | | const totalLocations = ref('0') |
| | | const todayInbound = ref('0') |
| | | const todayOutbound = ref('0') |
| | | const weekInbound = ref('0') |
| | | const weekOutbound = ref('0') |
| | | const monthInbound = ref('0') |
| | | const monthOutbound = ref('0') |
| | | const pendingOrders = ref('0') |
| | | |
| | | // å
¨å±ç¶æ |
| | | const isFullScreen = ref(false) |
| | | |
| | | const realTimeTasks = reactive([ |
| | | ]) |
| | | |
| | | // å
¨å±åæ¢æ¹æ³ |
| | | const toggleFullScreen = () => { |
| | | // è·åé¦é¡µå
容容å¨å
ç´ |
| | | const element = document.getElementById('big-data-container') |
| | | if (!element) return |
| | | |
| | | if (!isFullScreen.value) { |
| | | // è¿å
¥å
¨å± |
| | | if (element.requestFullscreen) { |
| | | element.requestFullscreen() |
| | | } else if (element.mozRequestFullScreen) { |
| | | element.mozRequestFullScreen() |
| | | } else if (element.webkitRequestFullscreen) { |
| | | element.webkitRequestFullscreen() |
| | | } else if (element.msRequestFullscreen) { |
| | | element.msRequestFullscreen() |
| | | } |
| | | } else { |
| | | // éåºå
¨å± |
| | | if (document.exitFullscreen) { |
| | | document.exitFullscreen() |
| | | } else if (document.mozCancelFullScreen) { |
| | | document.mozCancelFullScreen() |
| | | } else if (document.webkitExitFullscreen) { |
| | | document.webkitExitFullscreen() |
| | | } else if (document.msExitFullscreen) { |
| | | document.msExitFullscreen() |
| | | } |
| | | } |
| | | } |
| | | |
| | | // çå¬å
¨å±ç¶æåå |
| | | const handleFullScreenChange = () => { |
| | | isFullScreen.value = !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) |
| | | // å
³é®ï¼å
¨å±ç¶æååæ¶å¼ºå¶è§¦åå¾è¡¨resize |
| | | handleResize() |
| | | } |
| | | |
| | | // è·å宿¶æ°æ® |
| | | const fetchData = async () => { |
| | | try { |
| | | // è·ååºåç»è®¡æ°æ® |
| | | const stockStatistics = await http.post('/api/Home/GetDt_TaskHty', {}, false) |
| | | |
| | | console.log('åºåç»è®¡æ°æ®:', stockStatistics) |
| | | |
| | | if (stockStatistics) { |
| | | if (stockStatistics.status) { |
| | | const data = stockStatistics.data; |
| | | console.log('åºåæ°æ®:', data) |
| | | totalLocations.value = data.totalLocations ? data.totalLocations.toLocaleString() : '0'; |
| | | todayInbound.value = data.todayInbound ? data.todayInbound.toLocaleString() : '0'; |
| | | todayOutbound.value = data.todayOutbound ? data.todayOutbound.toLocaleString() : '0'; |
| | | weekInbound.value = data.weekInbound ? data.weekInbound.toLocaleString() : '0'; |
| | | weekOutbound.value = data.weekOutbound ? data.weekOutbound.toLocaleString() : '0'; |
| | | monthInbound.value = data.monthInbound ? data.monthInbound.toLocaleString() : '0'; |
| | | monthOutbound.value = data.monthOutbound ? data.monthOutbound.toLocaleString() : '0'; |
| | | pendingOrders.value = data.pendingOrders ? data.pendingOrders.toLocaleString() : '0'; |
| | | |
| | | // æ´æ°å¾è¡¨æ°æ® |
| | | updateCharts(data); |
| | | } else { |
| | | console.error('åºåç»è®¡APIè¿å失败:', stockStatistics.message) |
| | | } |
| | | } else { |
| | | console.error('åºåç»è®¡APIè¿åæ°æ®ä¸ºç©º') |
| | | } |
| | | } catch (error) { |
| | | console.error('è·åæ°æ®å¤±è´¥:', error) |
| | | // 使ç¨é»è®¤æ°æ®ï¼ç¡®ä¿å¤§å±æ£å¸¸æ¾ç¤º |
| | | console.log('使ç¨é»è®¤æ°æ®æ¾ç¤º') |
| | | } |
| | | } |
| | | |
| | | // æ´æ°å¾è¡¨æ°æ® |
| | | const updateCharts = (stockData) => { |
| | | if (!stockData) return |
| | | |
| | | console.log('æ´æ°å¾è¡¨æ°æ®:', stockData) |
| | | |
| | | // æ´æ°åºåååè¶å¿å¾ |
| | | if (chartStockTrend) { |
| | | // çæææ°çæè¿7å¤©æ¥æ |
| | | const recentDays = generateRecentDays() |
| | | chartStockTrend.setOption({ |
| | | xAxis: { |
| | | data: recentDays |
| | | }, |
| | | series: [{ |
| | | data: stockData.stockTrend || [] |
| | | }] |
| | | }) |
| | | } |
| | | |
| | | // æ´æ°æ¥åºå
¥åºæç» |
| | | if (chartDailyInout) { |
| | | chartDailyInout.setOption({ |
| | | series: [ |
| | | { name: 'å
¥åº', data: stockData.dailyInout?.inbound || [] }, |
| | | { name: 'åºåº', data: stockData.dailyInout?.outbound || [] } |
| | | ] |
| | | }) |
| | | } |
| | | |
| | | // æ´æ°å¨åºå
¥åºç»è®¡ |
| | | if (chartWeekInout) { |
| | | chartWeekInout.setOption({ |
| | | series: [ |
| | | { name: 'å
¥åº', data: stockData.weekInout?.inbound || [] }, |
| | | { name: 'åºåº', data: stockData.weekInout?.outbound || [] } |
| | | ] |
| | | }) |
| | | } |
| | | |
| | | // æ´æ°æåºå
¥åºè¶å¿ |
| | | if (chartMonthInout) { |
| | | chartMonthInout.setOption({ |
| | | series: [ |
| | | { name: 'å
¥åº', data: stockData.monthInout?.inbound || [] }, |
| | | { name: 'åºåº', data: stockData.monthInout?.outbound || [] } |
| | | ] |
| | | }) |
| | | } |
| | | |
| | | // æ´æ°è´§ä½ç¶æåå¸ |
| | | if (chartWarehouseUtilization) { |
| | | chartWarehouseUtilization.setOption({ |
| | | series: [{ |
| | | data: [ |
| | | { value: stockData.warehouseUtilization?.inStock || 0, name: 'æè´§' }, |
| | | { value: stockData.warehouseUtilization?.free || 0, name: '空é²' }, |
| | | { value: stockData.warehouseUtilization?.inStockLock || 0, name: 'æè´§éå®' }, |
| | | // { value: stockData.warehouseUtilization?.lockLocations || 0, name: 'éå®' }, |
| | | // { value: stockData.warehouseUtilization?.freeLock || 0, name: '空é²éå®' }, |
| | | // { value: stockData.warehouseUtilization?.palletLock || 0, name: '大æçéå®' } |
| | | ] |
| | | }] |
| | | }) |
| | | } |
| | | } |
| | | |
| | | // çææè¿7天çè¿ç»æ¥æï¼æ ¼å¼ä¸º"ddæ¥" |
| | | const generateRecentDays = () => { |
| | | const days = [] |
| | | const today = new Date() |
| | | // çææè¿7å¤©çæ¥æï¼ä»6天åå°ä»å¤© |
| | | for (let i = 6; i >= 0; i--) { |
| | | const date = new Date(today) |
| | | date.setDate(today.getDate() - i) |
| | | days.push(`${date.getDate().toString().padStart(2, '0')}æ¥`) |
| | | } |
| | | return days |
| | | } |
| | | |
| | | // åå§åå¾è¡¨ |
| | | const initCharts = () => { |
| | | // æ¥åºå
¥åºæç» - æå°æ¶ç»è®¡ |
| | | chartDailyInout = echarts.init(document.getElementById('chart-daily-inout')) |
| | | chartDailyInout.setOption({ |
| | | tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, |
| | | grid: { left: '0%', top: '10px', right: '0%', bottom: '4%', containLabel: true }, |
| | | xAxis: { type: 'category', data: ['08æ¶', '09æ¶', '10æ¶', '11æ¶', '12æ¶', '13æ¶', '14æ¶', '15æ¶', '16æ¶', '17æ¶'], axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,.5)' } }, axisLabel: { color: 'rgba(255,255,255,.8)' } }, |
| | | yAxis: { type: 'value', axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,.5)' } }, axisLabel: { color: 'rgba(255,255,255,.8)' } }, |
| | | series: [ |
| | | { name: 'å
¥åº', type: 'bar', data: [], barWidth: '25%', itemStyle: { normal: { color: '#2f89cf' } } }, |
| | | { name: 'åºåº', type: 'bar', data: [], barWidth: '25%', itemStyle: { normal: { color: '#46d000' } } } |
| | | ] |
| | | }) |
| | | |
| | | // å¨åºå
¥åºç»è®¡ |
| | | chartWeekInout = echarts.init(document.getElementById('chart-week-inout')) |
| | | chartWeekInout.setOption({ |
| | | tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, |
| | | grid: { left: '0%', top: '10px', right: '0%', bottom: '4%', containLabel: true }, |
| | | xAxis: { type: 'category', data: ['å¨ä¸', 'å¨äº', 'å¨ä¸', 'å¨å', 'å¨äº', 'å¨å
', '卿¥'], axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,.5)' } }, axisLabel: { color: 'rgba(255,255,255,.8)' } }, |
| | | yAxis: { type: 'value', axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,.5)' } }, axisLabel: { color: 'rgba(255,255,255,.8)' } }, |
| | | series: [ |
| | | { name: 'å
¥åº', type: 'bar', data: [], barWidth: '25%', itemStyle: { normal: { color: '#2f89cf' } } }, |
| | | { name: 'åºåº', type: 'bar', data: [], barWidth: '25%', itemStyle: { normal: { color: '#46d000' } } } |
| | | ] |
| | | }) |
| | | |
| | | // æåºå
¥åºè¶å¿ |
| | | chartMonthInout = echarts.init(document.getElementById('chart-month-inout')) |
| | | chartMonthInout.setOption({ |
| | | tooltip: { trigger: 'axis' }, |
| | | grid: { left: '0%', top: '10px', right: '0%', bottom: '4%', containLabel: true }, |
| | | xAxis: { type: 'category', data: ['01æ¥', '05æ¥', '10æ¥', '15æ¥', '20æ¥', '25æ¥', '30æ¥'], axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,.5)' } }, axisLabel: { color: 'rgba(255,255,255,.8)' } }, |
| | | yAxis: { type: 'value', axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,.5)' } }, axisLabel: { color: 'rgba(255,255,255,.8)' } }, |
| | | series: [ |
| | | { name: 'å
¥åº', type: 'line', data: [], smooth: true, lineStyle: { color: '#2f89cf' }, areaStyle: { color: 'rgba(47, 137, 207, 0.3)' } }, |
| | | { name: 'åºåº', type: 'line', data: [], smooth: true, lineStyle: { color: '#46d000' }, areaStyle: { color: 'rgba(70, 208, 0, 0.3)' } } |
| | | ] |
| | | }) |
| | | |
| | | // è´§ä½ç¶æåå¸ |
| | | chartWarehouseUtilization = echarts.init(document.getElementById('chart-warehouse-utilization')) |
| | | chartWarehouseUtilization.setOption({ |
| | | tooltip: { trigger: 'item' }, |
| | | legend: { orient: 'vertical', left: 'left', textStyle: { color: 'rgba(255,255,255,.8)' } }, |
| | | series: [ |
| | | { name: 'è´§ä½ç¶æåå¸', type: 'pie', radius: '60%', data: [], emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } } |
| | | ] |
| | | }) |
| | | |
| | | // åºåååè¶å¿ |
| | | chartStockTrend = echarts.init(document.getElementById('chart-stock-trend')) |
| | | const recentDays = generateRecentDays() |
| | | chartStockTrend.setOption({ |
| | | tooltip: { trigger: 'axis' }, |
| | | grid: { left: '0%', top: '10px', right: '0%', bottom: '4%', containLabel: true }, |
| | | xAxis: { type: 'category', data: recentDays, axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,.5)' } }, axisLabel: { color: 'rgba(255,255,255,.8)' } }, |
| | | yAxis: { type: 'value', axisLine: { show: true, lineStyle: { color: 'rgba(255,255,255,.5)' } }, axisLabel: { color: 'rgba(255,255,255,.8)' } }, |
| | | series: [{ type: 'line', data: [], smooth: true, lineStyle: { color: '#4ecdc4' }, areaStyle: { color: 'rgba(78, 205, 196, 0.3)' } }] |
| | | }) |
| | | } |
| | | |
| | | // çªå£å¤§å°ååæ¶éæ°è°æ´å¾è¡¨ |
| | | const handleResize = () => { |
| | | chartDailyInout && chartDailyInout.resize() |
| | | chartWeekInout && chartWeekInout.resize() |
| | | chartMonthInout && chartMonthInout.resize() |
| | | chartWarehouseUtilization && chartWarehouseUtilization.resize() |
| | | chartStockTrend && chartStockTrend.resize() |
| | | } |
| | | |
| | | let dataTimer = null |
| | | |
| | | onMounted(() => { |
| | | initCharts() |
| | | window.addEventListener('resize', handleResize) |
| | | |
| | | // æ·»å å
¨å±ç¶æååçå¬ |
| | | document.addEventListener('fullscreenchange', handleFullScreenChange) |
| | | document.addEventListener('mozfullscreenchange', handleFullScreenChange) |
| | | document.addEventListener('webkitfullscreenchange', handleFullScreenChange) |
| | | document.addEventListener('msfullscreenchange', handleFullScreenChange) |
| | | |
| | | // åå§è·åæ°æ® |
| | | fetchData() |
| | | |
| | | |
| | | dataTimer = setInterval(() => { |
| | | fetchData() |
| | | }, 600000)//ååéæ´æ°ä¸æ¬¡ |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | window.removeEventListener('resize', handleResize) |
| | | |
| | | // ç§»é¤å
¨å±ç¶æååçå¬ |
| | | document.removeEventListener('fullscreenchange', handleFullScreenChange) |
| | | document.removeEventListener('mozfullscreenchange', handleFullScreenChange) |
| | | document.removeEventListener('webkitfullscreenchange', handleFullScreenChange) |
| | | document.removeEventListener('msfullscreenchange', handleFullScreenChange) |
| | | |
| | | // æ¸
é¤å®æ¶å¨ |
| | | if (dataTimer) { |
| | | clearInterval(dataTimer) |
| | | dataTimer = null |
| | | } |
| | | |
| | | // 鿝å¾è¡¨å®ä¾ |
| | | chartDailyInout && chartDailyInout.dispose() |
| | | chartWeekInout && chartWeekInout.dispose() |
| | | chartMonthInout && chartMonthInout.dispose() |
| | | chartWarehouseUtilization && chartWarehouseUtilization.dispose() |
| | | chartStockTrend && chartStockTrend.dispose() |
| | | }) |
| | | |
| | | return { |
| | | totalLocations, |
| | | todayInbound, |
| | | todayOutbound, |
| | | weekInbound, |
| | | weekOutbound, |
| | | monthInbound, |
| | | monthOutbound, |
| | | pendingOrders, |
| | | isFullScreen, |
| | | toggleFullScreen |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .title { |
| | | line-height: 70vh; |
| | | text-align: center; |
| | | font-size: 28px; |
| | | color: orange; |
| | | <style lang="less" scoped> |
| | | .big-data-container { |
| | | width: 100%; |
| | | height: 100vh; |
| | | background: #000000; |
| | | color: #fff; |
| | | padding: 20px; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | |
| | | .head { |
| | | height: 60px; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #00ccff; |
| | | padding: 0 20px; |
| | | box-sizing: border-box; |
| | | margin-bottom: 10px; |
| | | position: relative; |
| | | } |
| | | |
| | | .head-actions { |
| | | position: absolute; |
| | | right: 20px; |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .data-container { |
| | | display: flex; |
| | | height: calc(100% - 80px); |
| | | gap: 20px; |
| | | overflow: hidden; |
| | | |
| | | .data-left { |
| | | width: 30%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | |
| | | .data-left-item { |
| | | flex: 1; |
| | | background: rgba(10, 30, 50, 0.6); |
| | | border-radius: 12px; |
| | | padding: 10px; |
| | | box-sizing: border-box; |
| | | min-height: 0; |
| | | } |
| | | } |
| | | |
| | | .data-center { |
| | | width: 40%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | |
| | | .center-top-num { |
| | | flex: 1; |
| | | display: grid; |
| | | grid-template-columns: repeat(4, 1fr); |
| | | grid-template-rows: repeat(2, 1fr); |
| | | gap: 15px; |
| | | background: rgba(10, 30, 50, 0.6); |
| | | border-radius: 12px; |
| | | padding: 10px; |
| | | box-sizing: border-box; |
| | | min-height: 0; |
| | | |
| | | .item { |
| | | background: rgba(10, 40, 70, 0.7); |
| | | border-radius: 12px; |
| | | padding: 15px; |
| | | box-sizing: border-box; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-items: center; |
| | | font-size: 14px; |
| | | |
| | | .text { |
| | | margin-bottom: 8px; |
| | | color: rgba(255, 255, 255, 0.7); |
| | | } |
| | | |
| | | .num { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #00ccff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .data-center-item { |
| | | flex: 1; |
| | | background: rgba(10, 30, 50, 0.6); |
| | | border-radius: 12px; |
| | | padding: 10px; |
| | | box-sizing: border-box; |
| | | display: flex; |
| | | flex-direction: column; |
| | | min-height: 0; |
| | | |
| | | > div[id^="chart-"] { |
| | | flex: 1; |
| | | width: 100%; |
| | | height: 100% !important; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .data-right { |
| | | width: 30%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | |
| | | .data-right-item { |
| | | flex: 1; |
| | | background: rgba(10, 30, 50, 0.6); |
| | | border-radius: 12px; |
| | | padding: 10px; |
| | | box-sizing: border-box; |
| | | min-height: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .title { |
| | | height: 30px; |
| | | line-height: 30px; |
| | | text-align: center; |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #00ccff; |
| | | } |
| | | } |
| | | </style> |