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 @@
@@ -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()