You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
6.8 KiB
Vue
192 lines
6.8 KiB
Vue
|
|
<script setup lang="ts">
|
|
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
|
|
import * as echarts from 'echarts'
|
|
import { ElMessage } from 'element-plus'
|
|
import request from '@/utils/request'
|
|
|
|
const filterWorkshop = ref('')
|
|
const filterBrand = ref('')
|
|
const workshopOptions = ref<string[]>([])
|
|
const brandOptions = ref<string[]>([])
|
|
const currentTime = ref('')
|
|
let timeTimer: ReturnType<typeof setInterval> | null = null
|
|
|
|
const statCards = reactive([
|
|
{ key: 'online', label: '在线机床', value: '--', sub: '', color: '#00e5ff' },
|
|
{ key: 'production', label: '今日总产量', value: '--', sub: '', color: '#76ff03' },
|
|
{ key: 'collector', label: '采集服务', value: '--', sub: '', color: '#69f0ae' },
|
|
{ key: 'alerts', label: '活跃告警', value: '--', sub: '', color: '#ffd740' },
|
|
{ key: 'avg', label: '平均产量/台', value: '--', sub: '', color: '#e0e0e0' },
|
|
])
|
|
|
|
const barChartRef = ref<HTMLElement>()
|
|
const lineChartRef = ref<HTMLElement>()
|
|
let barChart: echarts.ECharts | null = null
|
|
let lineChart: echarts.ECharts | null = null
|
|
|
|
const machineRank = ref<any[]>([])
|
|
const workerRank = ref<any[]>([])
|
|
const machineStatus = ref<any[]>([])
|
|
|
|
let refreshTimer: ReturnType<typeof setInterval> | null = null
|
|
const REFRESH_INTERVAL = 10000
|
|
|
|
function updateTime() {
|
|
const now = new Date()
|
|
currentTime.value = now.toLocaleString('zh-CN', {
|
|
year: 'numeric', month: '2-digit', day: '2-digit',
|
|
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false,
|
|
})
|
|
}
|
|
|
|
function filterParams(): Record<string, string> {
|
|
const p: Record<string, string> = {}
|
|
if (filterWorkshop.value) p.workshop = filterWorkshop.value
|
|
if (filterBrand.value) p.brand = filterBrand.value
|
|
return p
|
|
}
|
|
|
|
async function loadFilters() {
|
|
try {
|
|
const r: any = await request.get('/screen/filters')
|
|
const items = r.data?.items || []
|
|
workshopOptions.value = items.filter((i: any) => i.filterType === 'workshop').map((i: any) => i.filterValue)
|
|
brandOptions.value = items.filter((i: any) => i.filterType === 'brand').map((i: any) => i.filterValue)
|
|
const defW = items.find((i: any) => i.filterType === 'workshop' && i.isDefault === 1)
|
|
if (defW) filterWorkshop.value = defW.filterValue
|
|
const defB = items.find((i: any) => i.filterType === 'brand' && i.isDefault === 1)
|
|
if (defB) filterBrand.value = defB.filterValue
|
|
} catch { /* 静默 */ }
|
|
}
|
|
|
|
async function loadSummary() {
|
|
try {
|
|
const r: any = await request.get('/screen/summary', { params: filterParams() })
|
|
const d = r.data || {}
|
|
statCards[0].value = d.onlineCount != null ? String(d.onlineCount) : '--'
|
|
statCards[0].sub = d.totalMachines ? '/ ' + d.totalMachines : ''
|
|
statCards[1].value = d.todayProduction != null ? d.todayProduction.toLocaleString() : '--'
|
|
statCards[3].value = d.activeAlerts != null ? String(d.activeAlerts) : '--'
|
|
statCards[4].value = d.avgQuantityPerMachine != null ? String(d.avgQuantityPerMachine) : '--'
|
|
} catch { /* 静默 */ }
|
|
}
|
|
|
|
async function loadCollectorStatus() {
|
|
try {
|
|
const r: any = await request.get('/screen/collector-status')
|
|
const d = r.data || {}
|
|
if (d.status === 'running') {
|
|
statCards[2].value = '运行中'
|
|
statCards[2].sub = d.uptime || ''
|
|
statCards[2].color = '#69f0ae'
|
|
} else {
|
|
statCards[2].value = '已停止'
|
|
statCards[2].sub = ''
|
|
statCards[2].color = '#ff5252'
|
|
}
|
|
} catch { /* 静默 */ }
|
|
}
|
|
|
|
async function loadWorkshopProduction() {
|
|
try {
|
|
const r: any = await request.get('/screen/workshop-production', { params: filterParams() })
|
|
const items = r.data?.items || []
|
|
if (!barChart) return
|
|
barChart.setOption({
|
|
tooltip: { trigger: 'axis' },
|
|
grid: { left: 60, right: 20, top: 20, bottom: 30 },
|
|
xAxis: { type: 'category', data: items.map((i: any) => i.name), axisLabel: { color: '#aaa' }, axisLine: { lineStyle: { color: '#333' } } },
|
|
yAxis: { type: 'value', axisLabel: { color: '#aaa' }, splitLine: { lineStyle: { color: '#222' } } },
|
|
series: [{ type: 'bar', data: items.map((i: any) => i.quantity), itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#00e5ff' }, { offset: 1, color: '#006064' }]) }, barWidth: 30 }],
|
|
})
|
|
} catch { /* 静默 */ }
|
|
}
|
|
|
|
async function loadProductionTrend() {
|
|
try {
|
|
const r: any = await request.get('/screen/production-trend', { params: filterParams() })
|
|
const items = r.data?.items || []
|
|
if (!lineChart) return
|
|
lineChart.setOption({
|
|
tooltip: { trigger: 'axis' },
|
|
grid: { left: 60, right: 20, top: 20, bottom: 30 },
|
|
xAxis: { type: 'category', data: items.map((i: any) => i.date), axisLabel: { color: '#aaa' }, axisLine: { lineStyle: { color: '#333' } } },
|
|
yAxis: { type: 'value', axisLabel: { color: '#aaa' }, splitLine: { lineStyle: { color: '#222' } } },
|
|
series: [{
|
|
type: 'line', data: items.map((i: any) => i.quantity), smooth: true,
|
|
lineStyle: { color: '#76ff03', width: 2 }, itemStyle: { color: '#76ff03' },
|
|
areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(118,255,3,0.3)' }, { offset: 1, color: 'rgba(118,255,3,0)' }]) },
|
|
}],
|
|
})
|
|
} catch { /* 静默 */ }
|
|
}
|
|
|
|
async function loadMachineRank() {
|
|
try {
|
|
const r: any = await request.get('/screen/machine-rank', { params: filterParams() })
|
|
machineRank.value = r.data?.items || []
|
|
} catch { /* 静默 */ }
|
|
}
|
|
|
|
async function loadWorkerRank() {
|
|
try {
|
|
const r: any = await request.get('/screen/worker-rank', { params: filterParams() })
|
|
workerRank.value = r.data?.items || []
|
|
} catch { /* 静默 */ }
|
|
}
|
|
|
|
async function loadMachineStatus() {
|
|
try {
|
|
const r: any = await request.get('/screen/machine-status', { params: filterParams() })
|
|
machineStatus.value = r.data?.items || []
|
|
} catch { /* 静默 */ }
|
|
}
|
|
|
|
function refreshAll() {
|
|
loadSummary()
|
|
loadCollectorStatus()
|
|
loadWorkshopProduction()
|
|
loadProductionTrend()
|
|
loadMachineRank()
|
|
loadWorkerRank()
|
|
loadMachineStatus()
|
|
}
|
|
|
|
function initCharts() {
|
|
if (barChartRef.value) {
|
|
barChart = echarts.init(barChartRef.value)
|
|
barChart.setOption({ backgroundColor: 'transparent' })
|
|
}
|
|
if (lineChartRef.value) {
|
|
lineChart = echarts.init(lineChartRef.value)
|
|
lineChart.setOption({ backgroundColor: 'transparent' })
|
|
}
|
|
}
|
|
|
|
function handleResize() {
|
|
barChart?.resize()
|
|
lineChart?.resize()
|
|
}
|
|
|
|
onMounted(async () => {
|
|
updateTime()
|
|
timeTimer = setInterval(updateTime, 1000)
|
|
ElMessage({ message: '按F11进入全屏模式', type: 'info', duration: 5000 })
|
|
await loadFilters()
|
|
await nextTick()
|
|
initCharts()
|
|
refreshAll()
|
|
refreshTimer = setInterval(refreshAll, REFRESH_INTERVAL)
|
|
window.addEventListener('resize', handleResize)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
if (timeTimer) clearInterval(timeTimer)
|
|
if (refreshTimer) clearInterval(refreshTimer)
|
|
barChart?.dispose()
|
|
lineChart?.dispose()
|
|
window.removeEventListener('resize', handleResize)
|
|
})
|
|
</script>
|