mes-vue/src/views/biz/submitLog/statistics.vue
2026-06-02 15:20:51 +08:00

202 lines
5.5 KiB
Vue

<template>
<div class="page-container">
<n-card class="page-layout">
<!-- 搜索表单 -->
<div class="search-form">
<n-form inline :model="searchForm" label-placement="left">
<n-form-item label="统计方式">
<n-select
v-model:value="searchForm.type"
:options="statisticTypeOptions"
placeholder="请选择统计方式"
clearable
style="width: 200px"
/>
</n-form-item>
<n-form-item label="统计时间">
<n-date-picker
v-model:formatted-value="searchForm.timestamp"
format="yyyy-MM-dd"
type="date"
clearable
style="width: 200px"
/>
</n-form-item>
<n-form-item>
<n-space>
<n-button type="primary" @click="handleSearch">
<template #icon><n-icon><SearchOutline /></n-icon></template>
搜索
</n-button>
<n-button @click="handleReset">
<template #icon><n-icon><RefreshOutline /></n-icon></template>
重置
</n-button>
</n-space>
</n-form-item>
</n-form>
</div>
<div class="stats-section">
<div class="stats-cards">
<n-card class="stat-card" size="small" :bordered="false" content-style="background: transparent">
<div class="stat-item">
<span class="stat-label">提交总数</span>
<span class="stat-value">{{ stats.totalQty }}</span>
</div>
</n-card>
<n-card class="stat-card success" size="small" :bordered="false" content-style="background: transparent">
<div class="stat-item">
<span class="stat-label">合格</span>
<span class="stat-value">{{ stats.successQty }}</span>
</div>
</n-card>
<n-card class="stat-card fail" size="small" :bordered="false" content-style="background: transparent">
<div class="stat-item">
<span class="stat-label">报废</span>
<span class="stat-value">{{ stats.scrapQty }}</span>
</div>
</n-card>
</div>
<n-grid :cols="1" :x-gap="24" class="stats-charts">
<n-gi>
<n-card title="汇报统计图" size="small" :bordered="false" content-style="background: transparent">
<div ref="statisticChartRef" class="chart-box"></div>
</n-card>
</n-gi>
</n-grid>
</div>
</n-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, h, onMounted } from 'vue'
import { dictDataApi } from '@/api/org'
import { submitLogApi } from '@/api/submitLog'
//字典数据
const statisticTypeOptions = ref<{ label: string; value: any }[]>([])
//统计属性
const searchForm =reactive({
type: null as string,
timestamp: null as string
})
const stats = reactive({
totalQty:0,
successQty:0,
scrapQty:0,
outputRate:0,
scrapRate:0,
})
const statisticChartRef = ref<HTMLElement | null>(null)
let statisticChart: any = null
function handleSearch() {
loadStatistics()
}
function handleReset(){
searchForm.type = null
searchForm.timestamp = null
handleSearch()
}
async function loadStatistics() {
try{
const res = await submitLogApi.statistics({
type: searchForm.type,
time: searchForm.timestamp
})
Object.assign(stats,res)
updateCharts()
}catch{}
}
function updateCharts(){
import('echarts').then((echarts)=>{
if(statisticChartRef.value) {
if (!statisticChart) statisticChart = echarts.init(statisticChartRef.value)
const data = [{name:"产出率",value:stats.outputRate},{name:"报废率",value:stats.scrapRate}]
statisticChart.setOption({
tooltip: { trigger: 'item' },
series: [{ type: 'pie', radius: '60%', data }]
})
}
})
}
//加载字典选项
async function loadDictOptions() {
try{
const data = await dictDataApi.listByType('statistic_type')
statisticTypeOptions.value = data.map(d=>({label:d.dictLabel,value: (Number(d.dictValue) || d.dictValue) }))
}catch{}
}
onMounted(()=>{
loadStatistics()
loadDictOptions()
})
</script>
<style lang="scss" scoped>
.page-layout {
.stats-section {
margin-bottom: 20px;
}
.stats-cards {
display: flex;
gap: 16px;
margin-bottom: 16px;
}
.stat-card {
flex: 1;
.stat-item {
display: flex;
flex-direction: column;
gap: 4px;
.stat-value {
font-size: 24px;
font-weight: 700;
color: #111827;
}
.stat-label {
font-size: 13px;
color: #6b7280;
}
}
&.success .stat-value { color: #18a058; }
&.fail .stat-value { color: #d03050; }
}
.stats-charts {
margin-bottom: 16px;
}
.chart-box {
height: 260px;
text-align: center;
}
.search-form {
margin-bottom: 16px;
}
.pagination-container {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
}
</style>