feat(mes/roll,cost/trend): 优化轧辊报表和成本趋势页面
1. 轧辊报表:修复产线关联逻辑,通过轧辊映射获取产线信息,移除冗余的lineId请求参数 2. 成本趋势页:重构为迷你多图表布局,优化筛选栏样式和交互细节
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container cost-trend-page">
|
<div class="app-container cost-trend-page">
|
||||||
<!-- 筛选区 -->
|
<!-- 筛选区 -->
|
||||||
<el-card class="mb8">
|
<el-card class="mb8 filter-card">
|
||||||
<div class="filter-bar">
|
<div class="filter-bar">
|
||||||
<el-radio-group
|
<el-radio-group
|
||||||
v-model="selectedLine"
|
v-model="selectedLine"
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
{{ line.lineName }}
|
{{ line.lineName }}
|
||||||
</el-radio-button>
|
</el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
|
||||||
<el-button type="primary" size="small" icon="el-icon-search" :loading="loading" @click="fetchData">
|
<el-button type="primary" size="small" icon="el-icon-search" :loading="loading" @click="fetchData">
|
||||||
查询
|
查询
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -47,10 +46,10 @@
|
|||||||
multiple
|
multiple
|
||||||
collapse-tags
|
collapse-tags
|
||||||
placeholder="成本类别(全部)"
|
placeholder="成本类别(全部)"
|
||||||
size="small"
|
|
||||||
style="width:160px"
|
|
||||||
@change="onCategoryChange"
|
|
||||||
clearable
|
clearable
|
||||||
|
size="small"
|
||||||
|
style="width:150px"
|
||||||
|
@change="onCategoryChange"
|
||||||
>
|
>
|
||||||
<el-option label="原料" value="原料" />
|
<el-option label="原料" value="原料" />
|
||||||
<el-option label="能耗" value="能耗" />
|
<el-option label="能耗" value="能耗" />
|
||||||
@@ -67,10 +66,10 @@
|
|||||||
collapse-tags
|
collapse-tags
|
||||||
filterable
|
filterable
|
||||||
placeholder="成本项(全部)"
|
placeholder="成本项(全部)"
|
||||||
size="small"
|
|
||||||
style="width:220px"
|
|
||||||
@change="onItemChange"
|
|
||||||
clearable
|
clearable
|
||||||
|
size="small"
|
||||||
|
style="width:200px"
|
||||||
|
@change="onItemChange"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="it in filteredItemOptions"
|
v-for="it in filteredItemOptions"
|
||||||
@@ -81,13 +80,21 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 图表区 -->
|
<!-- 迷你图表网格 -->
|
||||||
<div class="chart-box" v-loading="loading">
|
<div v-loading="loading" class="mini-charts-grid">
|
||||||
<div ref="trendChart" class="chart-body" />
|
<template v-if="seriesList.length">
|
||||||
</div>
|
<div v-for="s in seriesList" :key="s.key" class="mini-chart-card">
|
||||||
|
<div class="mini-chart-header">
|
||||||
<div v-if="summary.seriesCount > 15" class="legend-hint">
|
<span class="mini-chart-dot" :style="{ background: s.color }" />
|
||||||
<i class="el-icon-info" /> 图例较多,可在下方图例区滚动查看,或缩小筛选范围以减少趋势线数量
|
<span class="mini-chart-name">{{ s.name }}</span>
|
||||||
|
<span class="mini-chart-max">峰值 {{ formatMiniMax(s.maxVal) }}</span>
|
||||||
|
</div>
|
||||||
|
<div ref="miniCharts" class="mini-chart-body" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div v-else-if="!loading && reports.length" class="empty-hint">
|
||||||
|
暂无匹配的成本项数据
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -116,7 +123,8 @@ export default {
|
|||||||
selectedItems: [],
|
selectedItems: [],
|
||||||
allItems: [],
|
allItems: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
chart: null,
|
chartInstances: [],
|
||||||
|
seriesList: [],
|
||||||
reports: [],
|
reports: [],
|
||||||
cachedDetails: [],
|
cachedDetails: [],
|
||||||
summary: { seriesCount: 0, maxLabel: '-' }
|
summary: { seriesCount: 0, maxLabel: '-' }
|
||||||
@@ -128,10 +136,6 @@ export default {
|
|||||||
if (!this.selectedLine || !this.productionLines.length) return null
|
if (!this.selectedLine || !this.productionLines.length) return null
|
||||||
return this.productionLines.find(l => l.lineId === this.selectedLine) || null
|
return this.productionLines.find(l => l.lineId === this.selectedLine) || null
|
||||||
},
|
},
|
||||||
lineNameDisplay() {
|
|
||||||
const line = this.selectedLineObj
|
|
||||||
return line ? line.lineName : ''
|
|
||||||
},
|
|
||||||
filteredItemOptions() {
|
filteredItemOptions() {
|
||||||
if (!this.selectedCategories.length) return this.allItems
|
if (!this.selectedCategories.length) return this.allItems
|
||||||
return this.allItems.filter(it => this.selectedCategories.includes(it.category))
|
return this.allItems.filter(it => this.selectedCategories.includes(it.category))
|
||||||
@@ -143,12 +147,12 @@ export default {
|
|||||||
this.$nextTick(() => this.fetchData())
|
this.$nextTick(() => this.fetchData())
|
||||||
})
|
})
|
||||||
this.loadItems()
|
this.loadItems()
|
||||||
this._resizeHandler = () => { if (this.chart) this.chart.resize() }
|
this._resizeHandler = () => this.resizeAllCharts()
|
||||||
window.addEventListener('resize', this._resizeHandler)
|
window.addEventListener('resize', this._resizeHandler)
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
window.removeEventListener('resize', this._resizeHandler)
|
window.removeEventListener('resize', this._resizeHandler)
|
||||||
if (this.chart) { this.chart.dispose(); this.chart = null }
|
this.disposeAllCharts()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initDefaultLine() {
|
initDefaultLine() {
|
||||||
@@ -188,9 +192,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async fetchData() {
|
async fetchData() {
|
||||||
if (this.selectedLine == null) {
|
if (this.selectedLine == null) return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loading = true
|
this.loading = true
|
||||||
try {
|
try {
|
||||||
@@ -204,13 +206,13 @@ export default {
|
|||||||
const allReports = (reportRes.rows || []).sort((a, b) => {
|
const allReports = (reportRes.rows || []).sort((a, b) => {
|
||||||
return (a.reportDate || '').localeCompare(b.reportDate || '')
|
return (a.reportDate || '').localeCompare(b.reportDate || '')
|
||||||
})
|
})
|
||||||
console.log('[CostTrend] reports:', allReports.length, allReports.map(r => ({ id: r.reportId, title: r.reportTitle, date: r.reportDate })))
|
|
||||||
|
|
||||||
if (!allReports.length) {
|
if (!allReports.length) {
|
||||||
this.$modal.msgWarning('该产线暂无报表')
|
this.$modal.msgWarning('该产线暂无报表')
|
||||||
this.reports = []
|
this.reports = []
|
||||||
|
this.seriesList = []
|
||||||
this.summary = { seriesCount: 0, maxLabel: '-' }
|
this.summary = { seriesCount: 0, maxLabel: '-' }
|
||||||
if (this.chart) this.chart.clear()
|
this.disposeAllCharts()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.reports = allReports
|
this.reports = allReports
|
||||||
@@ -224,15 +226,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ==================== 成本项模式 ====================
|
|
||||||
async fetchDetailsAndCache(reports) {
|
async fetchDetailsAndCache(reports) {
|
||||||
const allDetailResults = await Promise.all(
|
const allDetailResults = await Promise.all(
|
||||||
reports.map(r =>
|
reports.map(r =>
|
||||||
listProdDetail({ reportId: r.reportId, pageNum: 1, pageSize: 99999 })
|
listProdDetail({ reportId: r.reportId, pageNum: 1, pageSize: 99999 })
|
||||||
.then(res => {
|
.then(res => ({ reportId: r.reportId, rows: res.rows || [] }))
|
||||||
console.log('[CostTrend] detail for report', r.reportId, 'rows:', (res.rows || []).length)
|
|
||||||
return { reportId: r.reportId, rows: res.rows || [] }
|
|
||||||
})
|
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.error('[CostTrend] detail fetch error for report', r.reportId, e)
|
console.error('[CostTrend] detail fetch error for report', r.reportId, e)
|
||||||
return { reportId: r.reportId, rows: [] }
|
return { reportId: r.reportId, rows: [] }
|
||||||
@@ -279,7 +277,7 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const xLabels = reports.map(r => this.reportLabel(r))
|
const xLabels = reports.map(r => this.reportLabel(r))
|
||||||
const series = []
|
const list = []
|
||||||
let globalMax = 0
|
let globalMax = 0
|
||||||
|
|
||||||
Array.from(allItemIds).forEach((key, idx) => {
|
Array.from(allItemIds).forEach((key, idx) => {
|
||||||
@@ -288,115 +286,121 @@ export default {
|
|||||||
const data = reports.map(r => {
|
const data = reports.map(r => {
|
||||||
const sums = reportSums[r.reportId] || {}
|
const sums = reportSums[r.reportId] || {}
|
||||||
const val = sums[key] ?? null
|
const val = sums[key] ?? null
|
||||||
if (val != null && val > globalMax) globalMax = val
|
|
||||||
return val
|
return val
|
||||||
})
|
})
|
||||||
if (data.every(v => v === null)) return
|
if (data.every(v => v === null)) return
|
||||||
|
|
||||||
series.push({
|
const maxVal = Math.max(...data.filter(v => v != null))
|
||||||
|
if (maxVal > globalMax) globalMax = maxVal
|
||||||
|
|
||||||
|
list.push({
|
||||||
|
key,
|
||||||
name,
|
name,
|
||||||
type: 'line',
|
color: COLORS[idx % COLORS.length],
|
||||||
data,
|
data,
|
||||||
smooth: true,
|
xLabels,
|
||||||
symbol: 'circle',
|
maxVal
|
||||||
symbolSize: 6,
|
|
||||||
lineStyle: { width: 2, color: COLORS[idx % COLORS.length] },
|
|
||||||
itemStyle: { color: COLORS[idx % COLORS.length] },
|
|
||||||
emphasis: { focus: 'series' }
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.seriesList = list
|
||||||
this.summary = {
|
this.summary = {
|
||||||
seriesCount: series.length,
|
seriesCount: list.length,
|
||||||
maxLabel: this.formatMoney(globalMax)
|
maxLabel: this.formatMoney(globalMax)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => this.renderMiniCharts())
|
||||||
setTimeout(() => this.renderChart(xLabels, series, '数量'), 50)
|
},
|
||||||
|
|
||||||
|
// ==================== 迷你图表渲染 ====================
|
||||||
|
disposeAllCharts() {
|
||||||
|
this.chartInstances.forEach(c => {
|
||||||
|
try { c.dispose() } catch (e) { /* ignore */ }
|
||||||
|
})
|
||||||
|
this.chartInstances = []
|
||||||
|
},
|
||||||
|
|
||||||
|
resizeAllCharts() {
|
||||||
|
this.chartInstances.forEach(c => {
|
||||||
|
try { c.resize() } catch (e) { /* ignore */ }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// ==================== 图表渲染 ====================
|
renderMiniCharts() {
|
||||||
renderChart(xLabels, series, yAxisName) {
|
this.disposeAllCharts()
|
||||||
console.log('[CostTrend] renderChart called, ref:', !!this.$refs.trendChart, 'series:', series.length, 'xLabels:', xLabels.length)
|
|
||||||
if (!this.$refs.trendChart) return
|
|
||||||
if (this.chart) this.chart.dispose()
|
|
||||||
this.chart = echarts.init(this.$refs.trendChart)
|
|
||||||
|
|
||||||
if (!series.length) {
|
const containers = this.$refs.miniCharts
|
||||||
this.chart.setOption({
|
if (!containers || !containers.length) return
|
||||||
title: { text: '暂无数据', left: 'center', top: 'center', textStyle: { color: '#999', fontSize: 14 } },
|
|
||||||
xAxis: { show: false },
|
|
||||||
yAxis: { show: false },
|
|
||||||
series: []
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.chart.setOption({
|
this.seriesList.forEach((s, idx) => {
|
||||||
tooltip: {
|
const el = containers[idx]
|
||||||
trigger: 'axis',
|
if (!el) return
|
||||||
formatter: function (params) {
|
|
||||||
if (!params || !params.length) return ''
|
const chart = echarts.init(el)
|
||||||
let html = '<b>' + params[0].axisValue + '</b><br/>'
|
chart.setOption({
|
||||||
params.forEach(p => {
|
tooltip: {
|
||||||
if (p.value != null) {
|
trigger: 'axis',
|
||||||
html += '<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' +
|
formatter: function(params) {
|
||||||
p.color + ';margin-right:5px;"></span>' +
|
if (!params || !params.length) return ''
|
||||||
p.seriesName + ': <b>' +
|
const p = params[0]
|
||||||
Number(p.value).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) +
|
return '<b>' + p.axisValue + '</b><br/>' +
|
||||||
'</b><br/>'
|
'<span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:' +
|
||||||
}
|
p.color + ';margin-right:4px;"></span>' +
|
||||||
})
|
p.seriesName + ': <b>' +
|
||||||
return html
|
Number(p.value).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) +
|
||||||
}
|
'</b>'
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
type: 'scroll',
|
|
||||||
bottom: 0,
|
|
||||||
textStyle: { fontSize: 11 },
|
|
||||||
pageIconSize: 12,
|
|
||||||
pageTextStyle: { fontSize: 11 }
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '3%',
|
|
||||||
right: '4%',
|
|
||||||
top: '3%',
|
|
||||||
bottom: series.length > 20 ? '18%' : (series.length > 10 ? '14%' : '10%'),
|
|
||||||
containLabel: true
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
data: xLabels,
|
|
||||||
boundaryGap: false,
|
|
||||||
axisLabel: {
|
|
||||||
fontSize: 11,
|
|
||||||
rotate: xLabels.length > 8 ? 30 : 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'value',
|
|
||||||
name: yAxisName,
|
|
||||||
axisLabel: {
|
|
||||||
fontSize: 11,
|
|
||||||
formatter: function (v) {
|
|
||||||
if (v >= 10000) return (v / 10000).toFixed(1) + '万'
|
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
splitLine: { lineStyle: { type: 'dashed', color: '#e8e8e8' } }
|
grid: {
|
||||||
},
|
left: 8,
|
||||||
dataZoom: xLabels.length > 10 ? [
|
right: 12,
|
||||||
{
|
top: 8,
|
||||||
type: 'slider',
|
bottom: 24,
|
||||||
bottom: series.length > 10 ? (series.length > 20 ? 60 : 50) : 35,
|
containLabel: true
|
||||||
height: 16,
|
|
||||||
textStyle: { fontSize: 10 }
|
|
||||||
},
|
},
|
||||||
{ type: 'inside' }
|
xAxis: {
|
||||||
] : [],
|
type: 'category',
|
||||||
series
|
data: s.xLabels,
|
||||||
}, true)
|
boundaryGap: false,
|
||||||
|
axisLabel: {
|
||||||
|
fontSize: 10,
|
||||||
|
rotate: s.xLabels.length > 8 ? 25 : 0,
|
||||||
|
interval: s.xLabels.length > 12 ? 'auto' : 0
|
||||||
|
},
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLine: { lineStyle: { color: '#ddd' }}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
axisLabel: {
|
||||||
|
fontSize: 10,
|
||||||
|
formatter: function(v) {
|
||||||
|
if (v >= 10000) return (v / 10000).toFixed(1) + '万'
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: { lineStyle: { type: 'dashed', color: '#eee' }},
|
||||||
|
splitNumber: 3
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: s.name,
|
||||||
|
type: 'line',
|
||||||
|
data: s.data,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
lineStyle: { width: 1.5, color: s.color },
|
||||||
|
itemStyle: { color: s.color },
|
||||||
|
areaStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{ offset: 0, color: s.color + '30' },
|
||||||
|
{ offset: 1, color: s.color + '05' }
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
this.chartInstances.push(chart)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
reportLabel(r) {
|
reportLabel(r) {
|
||||||
@@ -411,78 +415,132 @@ export default {
|
|||||||
const num = Number(val)
|
const num = Number(val)
|
||||||
if (num >= 10000) return (num / 10000).toFixed(2) + '万'
|
if (num >= 10000) return (num / 10000).toFixed(2) + '万'
|
||||||
return num.toFixed(2)
|
return num.toFixed(2)
|
||||||
|
},
|
||||||
|
|
||||||
|
formatMiniMax(val) {
|
||||||
|
if (val == null || isNaN(val)) return '-'
|
||||||
|
if (val >= 10000) return (val / 10000).toFixed(1) + '万'
|
||||||
|
return Number(val).toFixed(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.mb8 { margin-bottom: 10px; }
|
.mb8 { margin-bottom: 8px; }
|
||||||
|
|
||||||
|
.filter-card {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.filter-card >>> .el-card__body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.filter-bar {
|
.filter-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 统计摘要 */
|
||||||
.stats-row {
|
.stats-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 6px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.stat-item {
|
.stat-item {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 100px;
|
min-width: 80px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid #ebeef5;
|
border: 1px solid #ebeef5;
|
||||||
border-radius: 2px;
|
border-radius: 4px;
|
||||||
padding: 10px 12px;
|
padding: 8px 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.stat-val {
|
.stat-val {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 22px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
.stat-label {
|
.stat-label {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
margin-top: 2px;
|
margin-top: 1px;
|
||||||
}
|
}
|
||||||
.stat-blue .stat-val { color: #409eff; }
|
.stat-blue .stat-val { color: #409eff; }
|
||||||
.stat-orange .stat-val { color: #e6a23c; }
|
.stat-orange .stat-val { color: #e6a23c; }
|
||||||
.stat-green .stat-val { color: #67c23a; }
|
.stat-green .stat-val { color: #67c23a; }
|
||||||
|
|
||||||
.chart-box {
|
/* 图表筛选 */
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #ebeef5;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
.chart-filter-bar {
|
.chart-filter-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.chart-filter-bar .filter-label {
|
.chart-filter-bar .filter-label {
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.chart-body {
|
|
||||||
width: 100%;
|
/* 迷你图表网格 */
|
||||||
height: 480px;
|
.mini-charts-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
.legend-hint {
|
|
||||||
margin-top: 8px;
|
.mini-chart-card {
|
||||||
font-size: 12px;
|
background: #fff;
|
||||||
color: #909399;
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-chart-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 6px;
|
||||||
|
padding: 8px 10px 0 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
.mini-chart-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.mini-chart-name {
|
||||||
|
font-weight: 500;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.mini-chart-max {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #909399;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-chart-body {
|
||||||
|
width: 100%;
|
||||||
|
height: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-hint {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 60px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #909399;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -244,8 +244,8 @@ export default {
|
|||||||
this.stats = statsRes.data || {}
|
this.stats = statsRes.data || {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 获取全部轧辊(用于辊型映射)
|
// 2. 获取全部轧辊(用于辊型映射和产线关联)
|
||||||
const rollRes = await listRollInfo({ pageNum: 1, pageSize: 99999, lineId: this.lineId || undefined })
|
const rollRes = await listRollInfo({ pageNum: 1, pageSize: 99999 })
|
||||||
const rolls = rollRes.rows || []
|
const rolls = rollRes.rows || []
|
||||||
const rollMap = {}
|
const rollMap = {}
|
||||||
rolls.forEach(r => { rollMap[r.rollId] = r })
|
rolls.forEach(r => { rollMap[r.rollId] = r })
|
||||||
@@ -270,7 +270,7 @@ export default {
|
|||||||
if (this._beginTime) allParams.beginTime = this._beginTime
|
if (this._beginTime) allParams.beginTime = this._beginTime
|
||||||
if (this._endTime) allParams.endTime = this._endTime + ' 23:59:59'
|
if (this._endTime) allParams.endTime = this._endTime + ' 23:59:59'
|
||||||
const allGrindRes = await listRollGrindAll(allParams)
|
const allGrindRes = await listRollGrindAll(allParams)
|
||||||
this.computeMonthlyPivot(allGrindRes.data || [])
|
this.computeMonthlyPivot(allGrindRes.data || [], rollMap)
|
||||||
|
|
||||||
this.updateCharts()
|
this.updateCharts()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -528,13 +528,14 @@ export default {
|
|||||||
document.body.removeChild(link)
|
document.body.removeChild(link)
|
||||||
URL.revokeObjectURL(url)
|
URL.revokeObjectURL(url)
|
||||||
},
|
},
|
||||||
computeMonthlyPivot(records) {
|
computeMonthlyPivot(records, rollMap) {
|
||||||
const lineMonthMap = {}
|
const lineMonthMap = {}
|
||||||
const monthSet = new Set()
|
const monthSet = new Set()
|
||||||
records.forEach(r => {
|
records.forEach(r => {
|
||||||
if (!r.grindTime) return
|
if (!r.grindTime) return
|
||||||
const month = r.grindTime.substring(0, 7)
|
const month = r.grindTime.substring(0, 7)
|
||||||
const lid = Number(r.lineId) || 0
|
const roll = rollMap[r.rollId]
|
||||||
|
const lid = Number(roll?.lineId) || 0
|
||||||
if (!lineMonthMap[lid]) {
|
if (!lineMonthMap[lid]) {
|
||||||
const line = this.productionLines.find(l => Number(l.lineId) === lid)
|
const line = this.productionLines.find(l => Number(l.lineId) === lid)
|
||||||
lineMonthMap[lid] = { lineId: lid, lineName: line ? line.lineName : (r.lineName || '未知产线'), months: {} }
|
lineMonthMap[lid] = { lineId: lid, lineName: line ? line.lineName : (r.lineName || '未知产线'), months: {} }
|
||||||
|
|||||||
Reference in New Issue
Block a user