From 788871a5b315dc41f1a8729f333e1919edb0c1ca Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Thu, 25 Jun 2026 10:03:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B9=B3=E5=9D=87=E7=94=9F=E4=BA=A7=E5=91=A8?= =?UTF-8?q?=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../longtron/screen-factory-overview.vue | 207 +++++++++++++++--- 1 file changed, 176 insertions(+), 31 deletions(-) diff --git a/src/views/modules/longtron/screen-factory-overview.vue b/src/views/modules/longtron/screen-factory-overview.vue index 59bdaa08..d2c534d8 100644 --- a/src/views/modules/longtron/screen-factory-overview.vue +++ b/src/views/modules/longtron/screen-factory-overview.vue @@ -47,7 +47,7 @@
-
最近 7 天完工趋势
+
平均生产周期(天)
@@ -91,6 +91,16 @@ const NODE_DISPLAY_NAME_ALIAS = { 线缆生产: '线缆/COP', COP生产: '线缆/COP' } +const AVERAGE_CYCLE_CATEGORY_LIST = [ + { key: 'VW', name: 'VW', orderType: 'HOME_LIFT' }, + { key: 'VC', name: 'VC', orderType: 'HOME_LIFT' }, + { key: 'Y18', name: 'Y18', orderType: 'HOME_LIFT' }, + { key: 'VL3.0', name: 'VL3.0', orderType: 'HOME_LIFT' }, + { key: 'VC2.0', name: 'VC2.0', orderType: 'HOME_LIFT' }, + { key: 'Y18 2.0', name: 'Y18 2.0', orderType: 'HOME_LIFT' }, + { key: 'VL2.5', name: 'VL2.5', orderType: 'RENOVATION' }, + { key: '机加工', name: '机加工', orderType: 'MACHINING' } +] export default { name: 'ScreenFactoryOverview', @@ -164,6 +174,10 @@ export default { return (sourceList || []) .filter(item => STATUS_ALLOW_LIST.includes(item.status)) .map(item => ({ + orderNo: item.orderNo || '', + taskNo: item.taskNo || '', + projectNo: item.projectNo || '', + modelNo: item.modelNo || '', status: item.status || '', planDeliveryDate: item.planDeliveryDate || '', planFinishDate: item.planFinishDate || '', @@ -213,7 +227,7 @@ export default { this.$nextTick(() => { this.renderBarChart() this.renderPieChart() - this.renderLineChart() + this.renderCycleChart() }) }, countByMonth(list, monthStart) { @@ -416,44 +430,175 @@ export default { }] }, true) }, - renderLineChart() { + renderCycleChart() { const el = document.getElementById('overviewLineChart') if (!el) return if (!this.chartLine) this.chartLine = echarts.init(el) - const xAxis = [] - const wholeSeries = [] - const renovationSeries = [] - const taskSeries = [] - const machiningSeries = [] - for (let i = 6; i >= 0; i--) { - const day = this.dayjs().subtract(i, 'day') - xAxis.push(day.format('MM-DD')) - wholeSeries.push(this.countFinishByDay(this.wholeList, day)) - renovationSeries.push(this.countFinishByDay(this.renovationList, day)) - taskSeries.push(this.countFinishByDay(this.taskList, day)) - machiningSeries.push(this.countFinishByDay(this.machiningList, day)) - } + const cycleCategoryList = this.buildAverageCycleCategoryList() this.chartLine.setOption({ animation: false, - color: ['#6cc7ff', '#74e0b3', '#7fa6d9', '#f5c15e'], - grid: { left: 35, right: 20, top: 34, bottom: 20, containLabel: true }, - tooltip: { trigger: 'axis' }, - legend: { textStyle: { color: '#cbe7ff', fontSize: 13 }, data: ['整梯完工', 'VL2.5升级完工', '线缆/COP完工', '机加工完工'] }, - xAxis: { type: 'category', axisLabel: { color: '#cbe7ff', fontSize: 13 }, data: xAxis }, - yAxis: { type: 'value', axisLabel: { color: '#cbe7ff', fontSize: 13 }, splitLine: { lineStyle: { color: 'rgba(160,200,240,0.15)' } } }, + color: ['#4f73bd'], + grid: { left: 35, right: 20, top: 34, bottom: 26, containLabel: true }, + tooltip: { + trigger: 'axis', + formatter: (params) => { + const point = (params && params[0]) || {} + return `${point.axisValue}
平均生产周期:${point.value || 0} 天` + } + }, + xAxis: { + type: 'category', + axisTick: { alignWithLabel: true }, + axisLabel: { color: '#cbe7ff', fontSize: 13, interval: 0 }, + axisLine: { lineStyle: { color: 'rgba(160,200,240,0.35)' } }, + data: cycleCategoryList.map(item => item.name) + }, + yAxis: { + type: 'value', + min: 0, + minInterval: 1, + max: (value) => { + const maxValue = Number(value && value.max ? value.max : 0) + if (maxValue <= 0) { + return 5 + } + return maxValue + Math.max(1, Math.ceil(maxValue * 0.15)) + }, + axisLabel: { color: '#cbe7ff', fontSize: 13 }, + splitLine: { lineStyle: { color: 'rgba(160,200,240,0.15)' } } + }, series: [ - { name: '整梯完工', type: 'line', smooth: true, symbol: 'circle', symbolSize: 7, data: wholeSeries, itemStyle: { color: '#6cc7ff' }, lineStyle: { color: '#6cc7ff' }, areaStyle: { color: 'rgba(108,199,255,0.18)' } }, - { name: 'VL2.5升级完工', type: 'line', smooth: true, symbol: 'circle', symbolSize: 7, data: renovationSeries, itemStyle: { color: '#74e0b3' }, lineStyle: { color: '#74e0b3' }, areaStyle: { color: 'rgba(116,224,179,0.18)' } }, - { name: '线缆/COP完工', type: 'line', smooth: true, symbol: 'circle', symbolSize: 7, data: taskSeries, itemStyle: { color: '#7fa6d9' }, lineStyle: { color: '#7fa6d9' }, areaStyle: { color: 'rgba(127,166,217,0.16)' } }, - { name: '机加工完工', type: 'line', smooth: true, symbol: 'circle', symbolSize: 7, data: machiningSeries, itemStyle: { color: '#f5c15e' }, lineStyle: { color: '#f5c15e' }, areaStyle: { color: 'rgba(245,193,94,0.15)' } } + { + name: '平均生产周期', + type: 'bar', + barWidth: 26, + data: cycleCategoryList.map(item => item.value), + itemStyle: { color: '#4f73bd' }, + label: { + normal: { + show: true, + position: 'top', + distance: 6, + color: '#d4ebff', + fontSize: 20, + formatter: ({ value }) => this.formatCycleLabel(value) + } + } + } ] }, true) }, - countFinishByDay(list, day) { - return list.filter(item => { - const finishDate = this.toDayjs(item.finishDate) - return finishDate && finishDate.format('YYYY-MM-DD') === day.format('YYYY-MM-DD') - }).length + buildAverageCycleCategoryList() { + const wholeCategoryList = this.buildWholeLiftAverageCycleMap() + const renovationAverageCycle = this.calcAverageCycleByList(this.renovationList) + const machiningAverageCycle = this.calcAverageCycleByList(this.machiningList) + return AVERAGE_CYCLE_CATEGORY_LIST.map((item) => { + if (item.orderType === 'HOME_LIFT') { + return { + ...item, + value: this.formatCycleValue(wholeCategoryList[item.key]) + } + } + if (item.key === 'VL2.5') { + return { + ...item, + value: this.formatCycleValue(renovationAverageCycle) + } + } + return { + ...item, + value: this.formatCycleValue(machiningAverageCycle) + } + }) + }, + buildWholeLiftAverageCycleMap() { + const sumMap = {} + const countMap = {} + AVERAGE_CYCLE_CATEGORY_LIST + .filter(item => item.orderType === 'HOME_LIFT') + .forEach(item => { + sumMap[item.key] = 0 + countMap[item.key] = 0 + }) + this.wholeList.forEach(item => { + if (!item || item.status !== '已完成') return + const categoryKey = this.resolveWholeLiftCategoryKey(item) + if (!categoryKey || !Object.prototype.hasOwnProperty.call(sumMap, categoryKey)) return + const cycleDays = this.resolveCycleDays(item) + if (cycleDays <= 0) return + sumMap[categoryKey] += cycleDays + countMap[categoryKey] += 1 + }) + const avgMap = {} + Object.keys(sumMap).forEach((key) => { + avgMap[key] = countMap[key] > 0 ? sumMap[key] / countMap[key] : 0 + }) + return avgMap + }, + resolveWholeLiftCategoryKey(item) { + const identity = this.normalizeModelIdentity( + item && (item.modelNo || item.projectNo || item.taskNo || item.orderNo) + ) + if (!identity) { + return '' + } + if (identity.indexOf('VL3.0') === 0 || identity.indexOf('VL30') === 0) { + return 'VL3.0' + } + if (identity.indexOf('VC2.0') === 0 || identity.indexOf('VC20') === 0) { + return 'VC2.0' + } + if (identity.indexOf('Y18 2.0') === 0 || identity.indexOf('Y182.0') === 0 || identity.indexOf('Y1820') === 0) { + return 'Y18 2.0' + } + if (identity.indexOf('Y18') === 0) { + return 'Y18' + } + if (identity.indexOf('C') === 0) { + return 'VC' + } + if (/^V\d+/.test(identity) || identity.indexOf('V') === 0) { + return 'VW' + } + return '' + }, + normalizeModelIdentity(identityValue) { + return String(identityValue || '') + .toUpperCase() + .replace(/[((].*?[))]/g, '') + .replace(/[-_/]/g, ' ') + .replace(/\s+/g, ' ') + .trim() + }, + calcAverageCycleByList(list) { + let sum = 0 + let count = 0 + ;(list || []).forEach(item => { + if (!item || item.status !== '已完成') return + const cycleDays = this.resolveCycleDays(item) + if (cycleDays <= 0) return + sum += cycleDays + count += 1 + }) + return count > 0 ? (sum / count) : 0 + }, + resolveCycleDays(item) { + if (!item) return 0 + const finishDate = this.toDayjs(item.finishDate || item.planDeliveryDate || item.planFinishDate) + const startDate = this.toDayjs(item.createTime || item.planFinishDate || item.planDeliveryDate) + if (!finishDate || !startDate) return 0 + const diffDays = finishDate.diff(startDate, 'day', true) + return diffDays > 0 ? diffDays : 0 + }, + formatCycleValue(value) { + const numericValue = Number(value || 0) + if (!Number.isFinite(numericValue) || numericValue <= 0) return 0 + return Math.ceil(numericValue) + }, + formatCycleLabel(value) { + const numericValue = Number(value || 0) + if (!Number.isFinite(numericValue)) return '0' + return String(Math.ceil(numericValue)) }, updateTime() { const now = new Date()