@ -38,11 +38,11 @@
< / e l - t o o l t i p >
< / e l - t o o l t i p >
< / div >
< / div >
< div class = "stat-value" >
< div class = "stat-value" >
< el -tag : type = "collectorStatus.serviceStatus === 'Running' ? 'success' : (collectorStatus.serviceStatus === 'NotInstalled' ? 'danger' : 'warning') " size = "small" >
< el -tag :type ="collectorTagType " size = "small" >
{ { serviceStatusLabel( collectorStatus . serviceStatus ) } }
{ { collectorStatusText } }
< / e l - t a g >
< / e l - t a g >
< / div >
< / div >
< div class = "stat-sub" v-if ="collectorStatus.serviceStatus === 'Running' "> 运 行 {{ formatUptime ( collectorStatus.uptimeSeconds ) }} < / div >
< div class = "stat-sub" v-if ="collectorStatus.serviceStatus === 'Running' && collectorStatus.status === 'running' "> 运 行 {{ formatUptime ( collectorStatus.uptimeSeconds ) }} < / div >
< / div >
< / div >
< div class = "collector-actions" >
< div class = "collector-actions" >
< el -button v-if ="collectorStatus.serviceStatus !== 'Running'" size="small" type="success" :loading="startLoading" @click="startCollector" > 启 动 采 集 < / el -button >
< el -button v-if ="collectorStatus.serviceStatus !== 'Running'" size="small" type="success" :loading="startLoading" @click="startCollector" > 启 动 采 集 < / el -button >
@ -70,7 +70,7 @@
<!-- 统计卡片 第2行 -- >
<!-- 统计卡片 第2行 -- >
< el -row :gutter ="16" class = "stat-row" >
< el -row :gutter ="16" class = "stat-row" >
< el -col :span =" 6 ">
< el -col :span =" 8 ">
< el -card shadow = "hover" >
< el -card shadow = "hover" >
< div class = "stat-card" >
< div class = "stat-card" >
< div class = "stat-label" >
< div class = "stat-label" >
@ -79,24 +79,11 @@
< span class = "info-icon" > ⓘ < / span >
< span class = "info-icon" > ⓘ < / span >
< / e l - t o o l t i p >
< / e l - t o o l t i p >
< / div >
< / div >
< div class = "stat-value" > { { summary. collectSuccessRate } } < span class = "stat-unit" > % < / span > < / div >
< div class = "stat-value" > { { formatNumber( summary. collectSuccessRate ) } } < span class = "stat-unit" > % < / span > < / div >
< / div >
< / div >
< / e l - c a r d >
< / e l - c a r d >
< / e l - c o l >
< / e l - c o l >
< el -col :span ="6" >
< el -col :span ="8" >
< el -card shadow = "hover" >
< div class = "stat-card" >
< div class = "stat-label" >
今日切削总时
< el -tooltip content = "今日所有机床实际切削加工的时间总和(单位:小时)。仅统计刀具接触工件的切削时间,不含空转和待机时间。" placement = "top" >
< span class = "info-icon" > ⓘ < / span >
< / e l - t o o l t i p >
< / div >
< div class = "stat-value" > { { summary . todayCuttingTime } } < span class = "stat-unit" > h < / span > < / div >
< / div >
< / e l - c a r d >
< / e l - c o l >
< el -col :span ="6" >
< el -card shadow = "hover" >
< el -card shadow = "hover" >
< div class = "stat-card" >
< div class = "stat-card" >
< div class = "stat-label" >
< div class = "stat-label" >
@ -109,7 +96,7 @@
< / div >
< / div >
< / e l - c a r d >
< / e l - c a r d >
< / e l - c o l >
< / e l - c o l >
< el -col :span =" 6 ">
< el -col :span =" 8 ">
< el -card shadow = "hover" >
< el -card shadow = "hover" >
< div class = "stat-card" >
< div class = "stat-card" >
< div class = "stat-label" >
< div class = "stat-label" >
@ -204,8 +191,21 @@
< el -card shadow = "hover" >
< el -card shadow = "hover" >
< template # header >
< template # header >
< div class = "card-header" >
< div class = "card-header" >
< span class = "card-title" > 机床产量排行 TOP10 < el -tooltip content = "单台机床加工零件数由高到低排列,同时显示当前正在执行的程序名。" placement = "top" > < span class = "info-icon" > ⓘ < / span > < / e l - t o o l t i p > < / s p a n >
< span class = "card-title" > 机床产量排行 TOP
< el -select v-model ="machineTopN" size="small" style="width: 72px" @change="loadMachineRankData" >
< el -option :value ="5" label = "5" / >
< el -option :value ="10" label = "10" / >
< el -option :value ="20" label = "20" / >
< el -option :value ="50" label = "50" / >
< el -option :value ="100" label = "100" / >
< / e l - s e l e c t >
< el -tooltip content = "单台机床加工零件数排列,同时显示当前正在执行的程序名。" placement = "top" > < span class = "info-icon" > ⓘ < / span > < / e l - t o o l t i p >
< / span >
< div class = "date-filter" >
< div class = "date-filter" >
< el -radio -group v-model ="machineSortOrder" size="small" @change="loadMachineRankData" style="margin-right: 8px" >
< el -radio -button value = "asc" > 正序 < / e l - r a d i o - b u t t o n >
< el -radio -button value = "desc" > 倒序 < / e l - r a d i o - b u t t o n >
< / e l - r a d i o - g r o u p >
< el -radio -group v-model ="machineDateType" size="small" @change="onMachineDateChange" >
< el -radio -group v-model ="machineDateType" size="small" @change="onMachineDateChange" >
< el -radio -button value = "today" > 今日 < / e l - r a d i o - b u t t o n >
< el -radio -button value = "today" > 今日 < / e l - r a d i o - b u t t o n >
< el -radio -button value = "yesterday" > 昨日 < / e l - r a d i o - b u t t o n >
< el -radio -button value = "yesterday" > 昨日 < / e l - r a d i o - b u t t o n >
@ -225,7 +225,9 @@
< / template >
< / template >
< / e l - t a b l e - c o l u m n >
< / e l - t a b l e - c o l u m n >
< el -table -column prop = "program" label = "当前程序" show -overflow -tooltip / >
< el -table -column prop = "program" label = "当前程序" show -overflow -tooltip / >
< el -table -column prop = "quantity" label = "产量" width = "80" align = "center" / >
< el -table -column label = "产量" width = "80" align = "center" >
< template # default = "{ row }" > { { formatNumber ( row . quantity ) } } < / template >
< / e l - t a b l e - c o l u m n >
< el -table -column label = "状态" width = "70" align = "center" >
< el -table -column label = "状态" width = "70" align = "center" >
< template # default = "{ row }" >
< template # default = "{ row }" >
< el -tag : type = "row.status === 1 ? 'success' : 'danger'" size = "small" > { { row . status === 1 ? '在线' : '离线' } } < / e l - t a g >
< el -tag : type = "row.status === 1 ? 'success' : 'danger'" size = "small" > { { row . status === 1 ? '在线' : '离线' } } < / e l - t a g >
@ -238,8 +240,21 @@
< el -card shadow = "hover" >
< el -card shadow = "hover" >
< template # header >
< template # header >
< div class = "card-header" >
< div class = "card-header" >
< span class = "card-title" > 工人产量排行 TOP10 < el -tooltip content = "工人所绑定的所有机床产量合计,由高到低排列。" placement = "top" > < span class = "info-icon" > ⓘ < / span > < / e l - t o o l t i p > < / s p a n >
< span class = "card-title" > 工人产量排行 TOP
< el -select v-model ="workerTopN" size="small" style="width: 72px" @change="loadWorkerRankData" >
< el -option :value ="5" label = "5" / >
< el -option :value ="10" label = "10" / >
< el -option :value ="20" label = "20" / >
< el -option :value ="50" label = "50" / >
< el -option :value ="100" label = "100" / >
< / e l - s e l e c t >
< el -tooltip content = "工人所绑定的所有机床产量合计。" placement = "top" > < span class = "info-icon" > ⓘ < / span > < / e l - t o o l t i p >
< / span >
< div class = "date-filter" >
< div class = "date-filter" >
< el -radio -group v-model ="workerSortOrder" size="small" @change="loadWorkerRankData" style="margin-right: 8px" >
< el -radio -button value = "asc" > 正序 < / e l - r a d i o - b u t t o n >
< el -radio -button value = "desc" > 倒序 < / e l - r a d i o - b u t t o n >
< / e l - r a d i o - g r o u p >
< el -radio -group v-model ="workerDateType" size="small" @change="onWorkerDateChange" >
< el -radio -group v-model ="workerDateType" size="small" @change="onWorkerDateChange" >
< el -radio -button value = "today" > 今日 < / e l - r a d i o - b u t t o n >
< el -radio -button value = "today" > 今日 < / e l - r a d i o - b u t t o n >
< el -radio -button value = "yesterday" > 昨日 < / e l - r a d i o - b u t t o n >
< el -radio -button value = "yesterday" > 昨日 < / e l - r a d i o - b u t t o n >
@ -255,7 +270,9 @@
< el -table -column prop = "rank" label = "排名" width = "60" align = "center" / >
< el -table -column prop = "rank" label = "排名" width = "60" align = "center" / >
< el -table -column prop = "workerName" label = "工人姓名" / >
< el -table -column prop = "workerName" label = "工人姓名" / >
< el -table -column prop = "machineCount" label = "绑定机床" width = "100" align = "center" / >
< el -table -column prop = "machineCount" label = "绑定机床" width = "100" align = "center" / >
< el -table -column prop = "totalQuantity" label = "总产量" width = "100" align = "center" / >
< el -table -column label = "总产量" width = "100" align = "center" >
< template # default = "{ row }" > { { formatNumber ( row . totalQuantity ) } } < / template >
< / e l - t a b l e - c o l u m n >
< / e l - t a b l e >
< / e l - t a b l e >
< / e l - c a r d >
< / e l - c a r d >
< / e l - c o l >
< / e l - c o l >
@ -274,7 +291,7 @@ import type { ApiResponse, DashboardSummary, CollectorStatus, MachineRankRow, Wo
const { isMock } = useMockMode ( )
const { isMock } = useMockMode ( )
const summary = ref < DashboardSummary > ( { onlineCount : 0 , totalMachines : 0 , todayProduction : 0 , activeAlerts : 0 , collectSuccessRate : 0 , todayCuttingTime: 0 , runningMachines: 0 , dataMissingMachines : 0 } )
const summary = ref < DashboardSummary > ( { onlineCount : 0 , totalMachines : 0 , todayProduction : 0 , activeAlerts : 0 , collectSuccessRate : 0 , runningMachines: 0 , dataMissingMachines : 0 } )
const collectorStatus = ref < CollectorStatus > ( { status : 'stopped' , uptimeSeconds : 0 , serviceStatus : 'NotInstalled' , serviceName : '' } )
const collectorStatus = ref < CollectorStatus > ( { status : 'stopped' , uptimeSeconds : 0 , serviceStatus : 'NotInstalled' , serviceName : '' } )
const machineRank = ref < MachineRankRow [ ] > ( [ ] )
const machineRank = ref < MachineRankRow [ ] > ( [ ] )
const workerRank = ref < WorkerRankRow [ ] > ( [ ] )
const workerRank = ref < WorkerRankRow [ ] > ( [ ] )
@ -296,6 +313,12 @@ const machineDateRange = ref<[string, string]>()
const workerDateType = ref < DateType > ( 'today' )
const workerDateType = ref < DateType > ( 'today' )
const workerDateRange = ref < [ string , string ] > ( )
const workerDateRange = ref < [ string , string ] > ( )
/ / T O P N 和 排 序
const machineTopN = ref ( 10 )
const machineSortOrder = ref < 'asc' | 'desc' > ( 'asc' )
const workerTopN = ref ( 10 )
const workerSortOrder = ref < 'asc' | 'desc' > ( 'asc' )
const dateLabels : Record < DateType , string > = { today : '今日' , yesterday : '昨日' , last3 : '近3天' , last7 : '近7天' , custom : '自定义' }
const dateLabels : Record < DateType , string > = { today : '今日' , yesterday : '昨日' , last3 : '近3天' , last7 : '近7天' , custom : '自定义' }
const workshopDateLabel = computed ( ( ) => dateLabels [ workshopDateType . value ] )
const workshopDateLabel = computed ( ( ) => dateLabels [ workshopDateType . value ] )
const machineDateLabel = computed ( ( ) => dateLabels [ machineDateType . value ] )
const machineDateLabel = computed ( ( ) => dateLabels [ machineDateType . value ] )
@ -374,17 +397,32 @@ function formatUptime(seconds: number | undefined): string {
return ` ${ hours } 时 `
return ` ${ hours } 时 `
}
}
function serviceStatusLabel ( status : string | undefined ) : string {
function formatNumber ( val : number | undefined | null ) : string {
switch ( ( status || '' ) . toString ( ) ) {
if ( val == null ) return '-'
case 'NotInstalled' : return '未安装'
return Number ( val ) . toFixed ( 2 )
case 'Running' : return '运行中'
case 'Starting' : return '启动中'
case 'StartFailed' : return '启动失败'
case 'Stopped' : return '已停止'
default : return status || '-'
}
}
}
/ / 采 集 服 务 状 态 : 综 合 心 跳 + W i n d o w s 服 务 状 态
const collectorTagType = computed ( ( ) => {
const { serviceStatus , status } = collectorStatus . value
if ( serviceStatus === 'Running' && status === 'running' ) return 'success'
if ( serviceStatus === 'Running' && status !== 'running' ) return 'warning' / / 进 程 在 但 心 跳 超 时
if ( serviceStatus === 'NotInstalled' ) return 'danger'
if ( serviceStatus === 'StartFailed' ) return 'danger'
return 'warning'
} )
const collectorStatusText = computed ( ( ) => {
const { serviceStatus , status } = collectorStatus . value
if ( serviceStatus === 'Running' && status === 'running' ) return '运行中'
if ( serviceStatus === 'Running' && status !== 'running' ) return '心跳超时'
if ( serviceStatus === 'NotInstalled' ) return '未安装'
if ( serviceStatus === 'Stopped' ) return '已停止'
if ( serviceStatus === 'Starting' ) return '启动中'
if ( serviceStatus === 'StartFailed' ) return '启动失败'
return serviceStatus || '-'
} )
function alertTypeTag ( type : string ) : string {
function alertTypeTag ( type : string ) : string {
const map : Record < string , string > = { collect _fail : 'danger' , data _missing : 'warning' , device _offline : 'danger' , new _device : 'info' }
const map : Record < string , string > = { collect _fail : 'danger' , data _missing : 'warning' , device _offline : 'danger' , new _device : 'info' }
return map [ type ] || 'warning'
return map [ type ] || 'warning'
@ -481,7 +519,7 @@ async function loadWorkshopData() {
async function loadMachineRankData ( ) {
async function loadMachineRankData ( ) {
try {
try {
const { startDate , endDate } = getDateRange ( machineDateType . value , machineDateRange . value )
const { startDate , endDate } = getDateRange ( machineDateType . value , machineDateRange . value )
const res : ApiResponse < { items : MachineRankRow [ ] } > = await request . get ( '/admin/dashboard/machine-rank' , { params : { startDate , endDate } } )
const res : ApiResponse < { items : MachineRankRow [ ] } > = await request . get ( '/admin/dashboard/machine-rank' , { params : { startDate , endDate , top : machineTopN . value , sortOrder : machineSortOrder . value } } )
machineRank . value = res . data ? . items || [ ]
machineRank . value = res . data ? . items || [ ]
} catch { /* */ }
} catch { /* */ }
}
}
@ -489,7 +527,7 @@ async function loadMachineRankData() {
async function loadWorkerRankData ( ) {
async function loadWorkerRankData ( ) {
try {
try {
const { startDate , endDate } = getDateRange ( workerDateType . value , workerDateRange . value )
const { startDate , endDate } = getDateRange ( workerDateType . value , workerDateRange . value )
const res : ApiResponse < { items : WorkerRankRow [ ] } > = await request . get ( '/admin/dashboard/worker-rank' , { params : { startDate , endDate } } )
const res : ApiResponse < { items : WorkerRankRow [ ] } > = await request . get ( '/admin/dashboard/worker-rank' , { params : { startDate , endDate , top : workerTopN . value , sortOrder : workerSortOrder . value } } )
workerRank . value = res . data ? . items || [ ]
workerRank . value = res . data ? . items || [ ]
} catch { /* */ }
} catch { /* */ }
}
}