-
查询
@@ -47,10 +46,10 @@
multiple
collapse-tags
placeholder="成本类别(全部)"
- size="small"
- style="width:160px"
- @change="onCategoryChange"
clearable
+ size="small"
+ style="width:150px"
+ @change="onCategoryChange"
>
@@ -67,10 +66,10 @@
collapse-tags
filterable
placeholder="成本项(全部)"
- size="small"
- style="width:220px"
- @change="onItemChange"
clearable
+ size="small"
+ style="width:200px"
+ @change="onItemChange"
>
-
-
-
-
-
图例较多,可在下方图例区滚动查看,或缩小筛选范围以减少趋势线数量
+
+
@@ -116,7 +123,8 @@ export default {
selectedItems: [],
allItems: [],
loading: false,
- chart: null,
+ chartInstances: [],
+ seriesList: [],
reports: [],
cachedDetails: [],
summary: { seriesCount: 0, maxLabel: '-' }
@@ -128,10 +136,6 @@ export default {
if (!this.selectedLine || !this.productionLines.length) return null
return this.productionLines.find(l => l.lineId === this.selectedLine) || null
},
- lineNameDisplay() {
- const line = this.selectedLineObj
- return line ? line.lineName : ''
- },
filteredItemOptions() {
if (!this.selectedCategories.length) return this.allItems
return this.allItems.filter(it => this.selectedCategories.includes(it.category))
@@ -143,12 +147,12 @@ export default {
this.$nextTick(() => this.fetchData())
})
this.loadItems()
- this._resizeHandler = () => { if (this.chart) this.chart.resize() }
+ this._resizeHandler = () => this.resizeAllCharts()
window.addEventListener('resize', this._resizeHandler)
},
beforeDestroy() {
window.removeEventListener('resize', this._resizeHandler)
- if (this.chart) { this.chart.dispose(); this.chart = null }
+ this.disposeAllCharts()
},
methods: {
initDefaultLine() {
@@ -186,11 +190,9 @@ export default {
this.allItems = r.rows || []
} catch (e) { /* ignore */ }
},
-
+
async fetchData() {
- if (this.selectedLine == null) {
- return
- }
+ if (this.selectedLine == null) return
this.loading = true
try {
@@ -204,13 +206,13 @@ export default {
const allReports = (reportRes.rows || []).sort((a, b) => {
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) {
this.$modal.msgWarning('该产线暂无报表')
this.reports = []
+ this.seriesList = []
this.summary = { seriesCount: 0, maxLabel: '-' }
- if (this.chart) this.chart.clear()
+ this.disposeAllCharts()
return
}
this.reports = allReports
@@ -224,15 +226,11 @@ export default {
}
},
- // ==================== 成本项模式 ====================
async fetchDetailsAndCache(reports) {
const allDetailResults = await Promise.all(
reports.map(r =>
listProdDetail({ reportId: r.reportId, pageNum: 1, pageSize: 99999 })
- .then(res => {
- console.log('[CostTrend] detail for report', r.reportId, 'rows:', (res.rows || []).length)
- return { reportId: r.reportId, rows: res.rows || [] }
- })
+ .then(res => ({ reportId: r.reportId, rows: res.rows || [] }))
.catch(e => {
console.error('[CostTrend] detail fetch error for report', r.reportId, e)
return { reportId: r.reportId, rows: [] }
@@ -279,7 +277,7 @@ export default {
})
const xLabels = reports.map(r => this.reportLabel(r))
- const series = []
+ const list = []
let globalMax = 0
Array.from(allItemIds).forEach((key, idx) => {
@@ -288,115 +286,121 @@ export default {
const data = reports.map(r => {
const sums = reportSums[r.reportId] || {}
const val = sums[key] ?? null
- if (val != null && val > globalMax) globalMax = val
return val
})
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,
- type: 'line',
+ color: COLORS[idx % COLORS.length],
data,
- smooth: true,
- symbol: 'circle',
- symbolSize: 6,
- lineStyle: { width: 2, color: COLORS[idx % COLORS.length] },
- itemStyle: { color: COLORS[idx % COLORS.length] },
- emphasis: { focus: 'series' }
+ xLabels,
+ maxVal
})
})
+ this.seriesList = list
this.summary = {
- seriesCount: series.length,
+ seriesCount: list.length,
maxLabel: this.formatMoney(globalMax)
}
- this.$nextTick(() => {
- setTimeout(() => this.renderChart(xLabels, series, '数量'), 50)
+ this.$nextTick(() => this.renderMiniCharts())
+ },
+
+ // ==================== 迷你图表渲染 ====================
+ disposeAllCharts() {
+ this.chartInstances.forEach(c => {
+ try { c.dispose() } catch (e) { /* ignore */ }
+ })
+ this.chartInstances = []
+ },
+
+ resizeAllCharts() {
+ this.chartInstances.forEach(c => {
+ try { c.resize() } catch (e) { /* ignore */ }
})
},
- // ==================== 图表渲染 ====================
- renderChart(xLabels, series, yAxisName) {
- 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)
+ renderMiniCharts() {
+ this.disposeAllCharts()
- if (!series.length) {
- this.chart.setOption({
- title: { text: '暂无数据', left: 'center', top: 'center', textStyle: { color: '#999', fontSize: 14 } },
- xAxis: { show: false },
- yAxis: { show: false },
- series: []
- })
- return
- }
+ const containers = this.$refs.miniCharts
+ if (!containers || !containers.length) return
- this.chart.setOption({
- tooltip: {
- trigger: 'axis',
- formatter: function (params) {
- if (!params || !params.length) return ''
- let html = '' + params[0].axisValue + '
'
- params.forEach(p => {
- if (p.value != null) {
- html += '' +
- p.seriesName + ': ' +
- Number(p.value).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) +
- '
'
- }
- })
- return html
- }
- },
- 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
+ this.seriesList.forEach((s, idx) => {
+ const el = containers[idx]
+ if (!el) return
+
+ const chart = echarts.init(el)
+ chart.setOption({
+ tooltip: {
+ trigger: 'axis',
+ formatter: function(params) {
+ if (!params || !params.length) return ''
+ const p = params[0]
+ return '' + p.axisValue + '
' +
+ '' +
+ p.seriesName + ': ' +
+ Number(p.value).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) +
+ ''
}
},
- splitLine: { lineStyle: { type: 'dashed', color: '#e8e8e8' } }
- },
- dataZoom: xLabels.length > 10 ? [
- {
- type: 'slider',
- bottom: series.length > 10 ? (series.length > 20 ? 60 : 50) : 35,
- height: 16,
- textStyle: { fontSize: 10 }
+ grid: {
+ left: 8,
+ right: 12,
+ top: 8,
+ bottom: 24,
+ containLabel: true
},
- { type: 'inside' }
- ] : [],
- series
- }, true)
+ xAxis: {
+ type: 'category',
+ data: s.xLabels,
+ 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) {
@@ -411,78 +415,132 @@ export default {
const num = Number(val)
if (num >= 10000) return (num / 10000).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)
}
}
}
diff --git a/klp-ui/src/views/crm/contract/detail/index.vue b/klp-ui/src/views/crm/contract/detail/index.vue
index 3f8d7cc94..c3d5f88ca 100644
--- a/klp-ui/src/views/crm/contract/detail/index.vue
+++ b/klp-ui/src/views/crm/contract/detail/index.vue
@@ -66,6 +66,7 @@
/>
筛选
重置
+ 导出
共 {{ total }} 条记录