<template>
|
<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, 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() {
|
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 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>
|