diff --git a/src/api/cockpit.js b/src/api/cockpit.js index fa468c9a..a955e6b8 100644 --- a/src/api/cockpit.js +++ b/src/api/cockpit.js @@ -60,3 +60,11 @@ export function getSalesRevenueData(data) { }); } +export function getOperateCockpit(data) { + return request({ + url: "/lb/operate-cockpit/get", + method: "post", + data: data, + }); +} + diff --git a/src/assets/icons/svg/orderReturn.svg b/src/assets/icons/svg/orderReturn.svg new file mode 100644 index 00000000..8a7c6e12 --- /dev/null +++ b/src/assets/icons/svg/orderReturn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/views/home/components/CostsBottomBar.vue b/src/views/home/components/CostsBottomBar.vue index faf81045..1cc3e3b7 100644 --- a/src/views/home/components/CostsBottomBar.vue +++ b/src/views/home/components/CostsBottomBar.vue @@ -10,10 +10,10 @@ -
- - +
+ +
@@ -25,80 +25,97 @@ import * as echarts from 'echarts'; export default { name: "Container", components: { coreLineChart }, - props: ["name", "size", "icon"], + props: { + line: { // 接收父组件传递的 cost 数据对象 + type: Object, + default: () => ({}) + }, + dateData: { + type: Object, + default: () => ({}) + } + }, data() { return { - activeButton: undefined, - itemList: [ - { unit: "单价·元/m²", targetValue: 16, currentValue: 14.5, progress: 90 }, - { unit: "净价·元/m²", targetValue: 16, currentValue: 15.2, progress: 85 }, - { unit: "销量·万m²", targetValue: 20, currentValue: 16, progress: 80 }, - { unit: "双镀面板·万m²", targetValue: 15, currentValue: 13.8, progress: 92 }, - ], - // 定义要传递的 series 数据(对应图例的三个费用类型) - chartSeries: [ - { + // 图表样式配置项,可以抽离出来方便管理 + chartConfig: { + manageCost: { name: '管理费用', - type: 'line', - stack: 'Total', - symbol: 'circle', - lineStyle: { color: 'rgba(11, 88, 255, .5)' }, - itemStyle: { - color: 'rgba(11, 88, 255, .5)', - borderColor: 'rgba(11, 88, 255, 1)', - borderWidth: 1 - }, - areaStyle: { - opacity: 0.5, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(11, 88, 255, .4)' }, - { offset: 1, color: 'rgba(18, 255, 245, 0)' }, - ]), - }, - data: [140, 232, 101, 264, 90, 340] // 与 xAxis 数据长度一致(6个月份) + lineColor: 'rgba(11, 88, 255, .5)', + itemColor: 'rgba(11, 88, 255, .5)', + borderColor: 'rgba(11, 88, 255, 1)', + areaGradient: [ + { offset: 0, color: 'rgba(11, 88, 255, .4)' }, + { offset: 1, color: 'rgba(18, 255, 245, 0)' }, + ] }, - { + saleCost: { name: '销售费用', - type: 'line', - stack: 'Total', - symbol: 'circle', - lineStyle: { color: 'rgba(54, 181, 138, .5)' }, - itemStyle: { - color: 'rgba(54, 181, 138, .5)', - borderColor: 'rgba(54, 181, 138, 1)', - borderWidth: 1 - }, - areaStyle: { - opacity: 0.5, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(54, 181, 138, .4)' }, - { offset: 1, color: 'rgba(18, 255, 245, 0)' }, - ]), - }, - data: [120, 282, 111, 234, 220, 340] + lineColor: 'rgba(54, 181, 138, .5)', + itemColor: 'rgba(54, 181, 138, .5)', + borderColor: 'rgba(54, 181, 138, 1)', + areaGradient: [ + { offset: 0, color: 'rgba(54, 181, 138, .4)' }, + { offset: 1, color: 'rgba(18, 255, 245, 0)' }, + ] }, - { + financeCost: { name: '财务费用', + lineColor: 'rgba(255, 132, 0, .5)', + itemColor: 'rgba(255, 132, 0, .5)', + borderColor: 'rgba(255, 132, 0, 1)', + areaGradient: [ + { offset: 0, color: 'rgba(255, 132, 0, .4)' }, + { offset: 1, color: 'rgba(18, 255, 245, 0)' }, + ] + } + } + }; + }, + computed: { + // 动态生成 X 轴数据 + xAxisData() { + // 从 cost.line 中获取任意一个有数据的键的 keys 作为 X 轴 + const lineData = this.line || {}; + const firstKey = Object.keys(lineData)[0]; + return firstKey ? Object.keys(lineData[firstKey]) : []; + }, + // 动态生成 series 数据 + chartSeries() { + const lineData = this.line || {}; + const xAxisKeys = this.xAxisData; + + // 如果没有 X 轴数据,则返回空数组 + if (xAxisKeys.length === 0) { + return []; + } + + // 遍历配置项,生成 series + return Object.keys(this.chartConfig).map(key => { + const config = this.chartConfig[key]; + // 确保数据顺序和 X 轴一致 + const dataValues = xAxisKeys.map(date => lineData[key] ? lineData[key][date] : 0); + + return { + name: config.name, type: 'line', stack: 'Total', symbol: 'circle', - lineStyle: { color: 'rgba(255, 132, 0, .5)' }, + symbolSize: 6, + lineStyle: { color: config.lineColor }, itemStyle: { - color: 'rgba(255, 132, 0, .5)', - borderColor: 'rgba(255, 132, 0, 1)', + color: config.itemColor, + borderColor: config.borderColor, borderWidth: 1 }, areaStyle: { opacity: 0.5, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(255, 132, 0, .4)' }, - { offset: 1, color: 'rgba(18, 255, 245, 0)' }, - ]), + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, config.areaGradient), }, - data: [90, 150, 180, 120, 250, 280] - } - ] - }; + data: dataValues + }; + }); + } }, methods: {} }; diff --git a/src/views/home/components/Header.vue b/src/views/home/components/Header.vue index 230e1805..ee23fd44 100644 --- a/src/views/home/components/Header.vue +++ b/src/views/home/components/Header.vue @@ -40,6 +40,7 @@ @@ -83,7 +89,7 @@ export default { position: absolute; top: 0; left: 0; - width: 100%; + width: 50%; height: 100%; border: 1px solid; border-image: linear-gradient(277deg, rgba(255, 255, 255, 0), rgba(92, 140, 255, 1)) 1 1; diff --git a/src/views/home/components/core-bottom-leftItem.vue b/src/views/home/components/core-bottom-leftItem.vue index af30d575..2b1c3764 100644 --- a/src/views/home/components/core-bottom-leftItem.vue +++ b/src/views/home/components/core-bottom-leftItem.vue @@ -42,40 +42,48 @@ export default { name: "Container", components: {}, - props: ["name", "size", "icon"], + props: ["purchase"], data() { return { - progress: 90, - itemList: [ - { - unit: "本月增效额·万元", - targetValue: 16, - currentValue: 14.5, - progress: 90 - }, - { - unit: "累计增效额·万元", - targetValue: 16, - currentValue: 15.2, - progress: 85 - }, - // { - // unit: "销量·万㎡", - // targetValue: 20, - // currentValue: 16, - // progress: 80 - // }, - // { - // unit: "双镀面板·万㎡", - // targetValue: 15, - // currentValue: 13.8, - // progress: 92 - // } - ] + itemList: [] }; }, - computed: {}, + watch: { + purchase: { + handler(newVal) { + if (newVal) { + this.itemList = this.transformData(newVal); + } + }, + immediate: true, + deep: true + } + }, methods: { + transformData(rawData) { + const dataMap = [ + { + key: 'increase', + unit: '本月增效额·万元' + }, + { + key: 'totalIncrease', + unit: '累计增效额·万元' + } + ]; + + return dataMap.map(itemInfo => { + const rawItem = rawData[itemInfo.key] || {}; + const progress = Math.max(0, Math.round((rawItem.rate || 0))); + + return { + unit: itemInfo.unit, + targetValue: rawItem.target || 0, + currentValue: rawItem.real || 0, + progress: progress + }; + }); + }, getTargetColor(currentValue, targetValue) { return currentValue >= targetValue ? "rgba(98, 213, 180, 1)" diff --git a/src/views/home/components/coreBottomBar.vue b/src/views/home/components/coreBottomBar.vue index 69aa69ef..37bdc46a 100644 --- a/src/views/home/components/coreBottomBar.vue +++ b/src/views/home/components/coreBottomBar.vue @@ -29,8 +29,8 @@
- +
@@ -42,204 +42,102 @@ import * as echarts from 'echarts'; export default { name: "Container", components: { coreLineChart }, - props: ["name", "size", "icon"], + props: { + line: { // 接收父组件传递的 sale 数据对象 + type: Object, + default: () => ({}) + }, + dateData: { // 接收父组件传递的 sale 数据对象 + type: Object, + default: () => ({}) + } + }, data() { return { activeButton: 0, - itemList: [ - { unit: "单价·元/m²", targetValue: 16, currentValue: 14.5, progress: 90 }, - { unit: "净价·元/m²", targetValue: 16, currentValue: 15.2, progress: 85 }, - { unit: "销量·万m²", targetValue: 20, currentValue: 16, progress: 80 }, - { unit: "双镀面板·万m²", targetValue: 15, currentValue: 13.8, progress: 92 }, - ], - // 4个按钮对应的 series 数据(目标+实际两条线) - seriesMap: [ - // 0: 单价(元/m²) - [ - { - name: '目标', - type: 'line', - stack: 'Total', - symbol: 'circle', - symbolSize: 6, - lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 }, - itemStyle: { - color: 'rgba(91, 230, 190, 1)', - borderColor: 2 - }, - areaStyle: { - opacity: 0.3, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(91, 230, 190, 0.4)' }, - { offset: 1, color: 'rgba(91, 230, 190, 0)' }, - ]), - }, - data: [16, 16.2, 15.8, 16.1, 15.9, 16] // 6-11月目标数据 - }, - { - name: '实际', - type: 'line', - stack: 'Total', - symbol: 'circle', - symbolSize: 6, - lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 }, - itemStyle: { - color: 'rgba(255, 132, 0, 1)', - borderColor: 'rgba(255, 132, 0, 1)', - borderWidth: 2, - }, - areaStyle: { - opacity: 0.3, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(255, 132, 0, 0.4)' }, - { offset: 1, color: 'rgba(255, 132, 0, 0)' }, - ]), - }, - data: [14.5, 14.8, 15.2, 14.6, 15, 14.7] // 6-11月实际数据 - } - ], - // 1: 净价(元/m²) - [ - { - name: '目标', - type: 'line', - stack: 'Total', - symbol: 'circle', - symbolSize: 6, - lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 }, - itemStyle: { - color: 'rgba(91, 230, 190, 1)', - - borderWidth: 2 - }, - areaStyle: { - opacity: 0.3, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(91, 230, 190, 0.4)' }, - { offset: 1, color: 'rgba(91, 230, 190, 0)' }, - ]), - }, - data: [16, 16.1, 15.9, 16.2, 16, 16.1] - }, - { - name: '实际', - type: 'line', - stack: 'Total', - symbol: 'circle', - symbolSize: 6, - lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 }, - itemStyle: { - color: 'rgba(255, 132, 0, 1)', - // - borderWidth: 2 - }, - areaStyle: { - opacity: 0.3, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(255, 132, 0, 0.4)' }, - { offset: 1, color: 'rgba(255, 132, 0, 0)' }, - ]), - }, - data: [15.2, 15.5, 15.3, 15.6, 15.4, 15.5] - } - ], - // 2: 销量(万m²) - [ - { - name: '目标', - type: 'line', - stack: 'Total', - symbol: 'circle', - symbolSize: 6, - lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 }, - itemStyle: { - color: 'rgba(91, 230, 190, 1)', - - borderWidth: 2 - }, - areaStyle: { - opacity: 0.3, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(91, 230, 190, 0.4)' }, - { offset: 1, color: 'rgba(91, 230, 190, 0)' }, - ]), - }, - data: [20, 20.5, 19.8, 21, 20.2, 20.8] - }, - { - name: '实际', - type: 'line', - stack: 'Total', - symbol: 'circle', - symbolSize: 6, - lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 }, - itemStyle: { - color: 'rgba(255, 132, 0, 1)', - - borderWidth: 2 - }, - areaStyle: { - opacity: 0.3, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(255, 132, 0, 0.4)' }, - { offset: 1, color: 'rgba(255, 132, 0, 0)' }, - ]), - }, - data: [16, 16.8, 17.2, 16.5, 17, 17.5] - } - ], - // 3: 双镀产品(万m²) - [ - { - name: '目标', - type: 'line', - stack: 'Total', - symbol: 'circle', - symbolSize: 6, - lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 }, - itemStyle: { - color: 'rgba(91, 230, 190, 1)', - - borderWidth: 2 - }, - areaStyle: { - opacity: 0.3, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(91, 230, 190, 0.4)' }, - { offset: 1, color: 'rgba(91, 230, 190, 0)' }, - ]), - }, - data: [15, 15.2, 14.8, 15.5, 15.1, 15.3] - }, - { - name: '实际', - type: 'line', - stack: 'Total', - symbol: 'circle', - symbolSize: 6, - lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 }, - itemStyle: { - color: 'rgba(255, 132, 0, 1)', - - borderWidth: 2 - }, - areaStyle: { - opacity: 0.3, - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'rgba(255, 132, 0, 0.4)' }, - { offset: 1, color: 'rgba(255, 132, 0, 0)' }, - ]), - }, - data: [13.8, 14.2, 14, 14.5, 14.3, 14.6] - } - ] + // 定义按钮与 line 数据中 key 的映射关系 + buttonToDataKey: [ + '单价', + '净价', + '销量', + '双镀面板' // 注意:数据中的 key 是“双镀面板”,按钮显示的是“双镀产品” ] }; }, computed: { + // 动态生成 X 轴数据 + xAxisData() { + const lineData = this.line || {}; + // 获取当前激活按钮对应的数据 + const currentDataKey = this.buttonToDataKey[this.activeButton]; + const currentIndicatorData = lineData[currentDataKey]; + + // 使用 'target' 的键作为 x 轴,如果 'target' 不存在,则使用 'real' 的键 + if (currentIndicatorData && currentIndicatorData.target) { + return Object.keys(currentIndicatorData.target); + } else if (currentIndicatorData && currentIndicatorData.real) { + return Object.keys(currentIndicatorData.real); + } + return []; + }, // 根据激活按钮动态返回对应 series 数据 currentSeries() { - return this.seriesMap[this.activeButton] || []; + const lineData = this.line || {}; + const currentDataKey = this.buttonToDataKey[this.activeButton]; + const chartData = lineData[currentDataKey]; + + if (!chartData) { + return []; + } + + // 提取目标和实际数据的值,并确保顺序与 X 轴一致 + const xAxisKeys = this.xAxisData; + const targetDataValues = xAxisKeys.map(date => chartData.target ? chartData.target[date] : 0); + const realDataValues = xAxisKeys.map(date => chartData.real ? chartData.real[date] : 0); + + return [ + { + name: '目标', + type: 'line', + stack: 'Total', + symbol: 'circle', + symbolSize: 6, + lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 }, + itemStyle: { + color: 'rgba(91, 230, 190, 1)', + borderColor: 2 + }, + areaStyle: { + opacity: 0.3, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: 'rgba(91, 230, 190, 0.4)' }, + { offset: 1, color: 'rgba(91, 230, 190, 0)' }, + ]), + }, + data: targetDataValues + }, + { + name: '实际', + type: 'line', + stack: 'Total', + symbol: 'circle', + symbolSize: 6, + lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 }, + itemStyle: { + color: 'rgba(255, 132, 0, 1)', + borderColor: 'rgba(255, 132, 0, 1)', + borderWidth: 2, + }, + areaStyle: { + opacity: 0.3, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: 'rgba(255, 132, 0, 0.4)' }, + { offset: 1, color: 'rgba(255, 132, 0, 0)' }, + ]), + }, + data: realDataValues + } + ]; } } }; diff --git a/src/views/home/components/coreBottomLeft.vue b/src/views/home/components/coreBottomLeft.vue index 472c0119..0eb961a4 100644 --- a/src/views/home/components/coreBottomLeft.vue +++ b/src/views/home/components/coreBottomLeft.vue @@ -3,7 +3,7 @@
- +
[] // 默认空数组,避免报错 + purchase: { // 接收父组件传递的设备数据数组 + type: Object, + default: () => {} // 默认空数组,避免报错 }, - productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留) + inventory: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留) type: Object, default: () => ({}) } @@ -37,12 +37,12 @@ export default { data() { return { maintenanceTasks: [ - { id: 1, eqName: '纯碱', taskName: '1313,252', }, - { id: 2, eqName: '硅砂', taskName: '14,252', }, - { id: 2, eqName: '白云石', taskName: '23,252', }, - { id: 2, eqName: '石灰石', taskName: '34,421', }, - { id: 2, eqName: '氧化铝', taskName: '1,251.34', }, - { id: 2, eqName: '氢氧化铝', taskName: '14,252', }, + { id: 1, name: '纯碱', number: '1313,252', }, + { id: 2, name: '硅砂', number: '14,252', }, + { id: 2, name: '白云石', number: '23,252', }, + { id: 2, name: '石灰石', number: '34,421', }, + { id: 2, name: '氧化铝', number: '1,251.34', }, + { id: 2, name: '氢氧化铝', number: '14,252', }, // { id: 2, eqName: '螺杆挤出', taskName: '例行维护', }, // { id: 2, eqName: '螺杆挤出', taskName: '例行维护', }, @@ -53,22 +53,26 @@ export default { ], tableProps: [ // { prop: 'id', label: '序号', width: 50, align: 'center' }, - { prop: 'eqName', label: '物料', align: 'left' }, - { prop: 'taskName', label: '库存/吨', align: 'left' }, + { prop: 'name', label: '物料', align: 'left' }, + { prop: 'number', label: '库存/吨', align: 'left' }, ] } }, watch: { - productionOverviewVo: { - handler(newValue, oldValue) { - this.updateChart() + inventory: { + handler(newInventoryData) { + // 当 inventory 数据变化时,执行转换函数 + this.maintenanceTasks = this.transformInventoryData(newInventoryData); }, - deep: true // 若对象内属性变化需触发,需加 deep: true + immediate: true, // 组件初始化时立即执行一次 + deep: true // 深度监听对象内部属性的变化 } }, mounted() { - // 初始化图表(若需展示图表,需在模板中添加对应 DOM) - // this.$nextTick(() => this.updateChart()) + // 组件挂载时,如果有初始 inventory 数据,也执行一次转换 + if (this.inventory) { + this.maintenanceTasks = this.transformInventoryData(this.inventory); + } }, beforeDestroy() { // 销毁图表,避免内存泄漏 @@ -78,115 +82,25 @@ export default { } }, methods: { - updateChart() { - // 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM,需在模板中补充,否则会报错 - // 示例:在 Container 内添加
- if (!document.getElementById('productionStatusChart')) return - - if (this.chart) this.chart.dispose() - this.chart = echarts.init(document.getElementById('productionStatusChart')) - - const data = [ - this.productionOverviewVo.input || 0, - this.productionOverviewVo.output || 0, - this.productionOverviewVo.ng || 0, - this.productionOverviewVo.lowValue || 0, - this.productionOverviewVo.scrap || 0, - this.productionOverviewVo.inProcess || 0, - this.productionOverviewVo.engineer || 0 - ] - - const option = { - type: 'bar', - grid: { left: 51, right: 40, top: 50, bottom: 45 }, - tooltip: { - trigger: 'axis', - axisPointer: { type: 'shadow' }, - className: 'production-status-chart-tooltip' - }, - xAxis: { - type: 'category', - offset: 8, - data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'], - axisTick: { show: false }, - axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } }, - axisLabel: { - color: 'rgba(255,255,255,0.7)', - fontSize: 12, - interval: 0, - width: 38, - overflow: 'break' - } - }, - yAxis: { - type: 'value', - name: '单位/片', - nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' }, - min: () => 0, - max: (value) => Math.ceil(value.max), - scale: true, - axisTick: { show: false }, - axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 }, - splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } }, - axisLine: { show: true, lineStyle: { color: '#00E8FF' } } - }, - series: [ - { - type: 'pictorialBar', - label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 }, - symbolSize: [20, 8], - symbolOffset: [0, 5], - z: 20, - itemStyle: { - borderColor: '#3588C7', - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'RGBA(22, 89, 98, 1)' }, - { offset: 1, color: '#3588C7' } - ]) - }, - data: data - }, - { - type: 'bar', - barWidth: 20, - itemStyle: { - borderWidth: 1, - borderColor: '#3588C7', - opacity: 0.8, - color: { - x: 0, y: 0, x2: 0, y2: 1, - type: 'linear', - global: false, - colorStops: [ - { offset: 0, color: 'rgba(73,178,255,0)' }, - { offset: 0.5, color: 'rgba(0, 232, 255, .5)' }, - { offset: 1, color: 'rgba(0, 232, 255, 1)' } - ] - } - }, - tooltip: { show: false }, - data: data - }, - { - type: 'pictorialBar', - symbolSize: [20, 8], - symbolOffset: [0, -4], - z: 12, - symbolPosition: 'end', - itemStyle: { - borderColor: 'rgba(0, 232, 255, 1)', - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'RGBA(22, 89, 98, 1)' }, - { offset: 1, color: '#3588C7' } - ]) - }, - tooltip: { show: false }, - data: data - } - ] + /** + * 核心转换函数:将 inventory 对象转换为 maintenanceTasks 数组 + * @param {Object} inventoryData - 格式如: { "纯碱": 0, "硅砂": 0, ... } + * @returns {Array} - 格式如: [ { id: 1, name: '纯碱', number: '0' }, ... ] + */ + transformInventoryData(inventoryData) { + // 检查输入是否为有效的非空对象 + if (!inventoryData || typeof inventoryData !== 'object' || Object.keys(inventoryData).length === 0) { + return []; // 如果无效,返回空数组 } - this.chart.setOption(option) + // 使用 Object.entries() 和 map() 进行转换 + return Object.entries(inventoryData).map(([name, value], index) => { + return { + id: index + 1, // id 从 1 开始自增 + name: name, // 物料名称 + number: String(value) // 将数值转换为字符串,以匹配 "number" 字段 + }; + }); } } } diff --git a/src/views/home/components/coreSalesKPIs.vue b/src/views/home/components/coreSalesKPIs.vue index ab0ca570..466e6621 100644 --- a/src/views/home/components/coreSalesKPIs.vue +++ b/src/views/home/components/coreSalesKPIs.vue @@ -5,12 +5,12 @@
- +
- +
@@ -28,11 +28,11 @@ export default { components: { Container, topItem, coreBottomBar }, // mixins: [resize], props: { - leftEqInfoData: { // 接收父组件传递的设备数据数组 - type: Array, - default: () => [] // 默认空数组,避免报错 + sale: { // 接收父组件传递的设备数据数组 + type: Object, + default: () => ({}) }, - productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留) + dateData: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留) type: Object, default: () => ({}) } @@ -43,135 +43,12 @@ export default { } }, watch: { - productionOverviewVo: { - handler(newValue, oldValue) { - this.updateChart() - }, - deep: true // 若对象内属性变化需触发,需加 deep: true - } }, mounted() { // 初始化图表(若需展示图表,需在模板中添加对应 DOM) // this.$nextTick(() => this.updateChart()) }, - beforeDestroy() { - // 销毁图表,避免内存泄漏 - if (this.chart) { - this.chart.dispose() - this.chart = null - } - }, methods: { - updateChart() { - // 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM,需在模板中补充,否则会报错 - // 示例:在 Container 内添加
- if (!document.getElementById('productionStatusChart')) return - - if (this.chart) this.chart.dispose() - this.chart = echarts.init(document.getElementById('productionStatusChart')) - - const data = [ - this.productionOverviewVo.input || 0, - this.productionOverviewVo.output || 0, - this.productionOverviewVo.ng || 0, - this.productionOverviewVo.lowValue || 0, - this.productionOverviewVo.scrap || 0, - this.productionOverviewVo.inProcess || 0, - this.productionOverviewVo.engineer || 0 - ] - - const option = { - type: 'bar', - grid: { left: 51, right: 40, top: 50, bottom: 45 }, - tooltip: { - trigger: 'axis', - axisPointer: { type: 'shadow' }, - className: 'production-status-chart-tooltip' - }, - xAxis: { - type: 'category', - offset: 8, - data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'], - axisTick: { show: false }, - axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } }, - axisLabel: { - color: 'rgba(255,255,255,0.7)', - fontSize: 12, - interval: 0, - width: 38, - overflow: 'break' - } - }, - yAxis: { - type: 'value', - name: '单位/片', - nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' }, - min: () => 0, - max: (value) => Math.ceil(value.max), - scale: true, - axisTick: { show: false }, - axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 }, - splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } }, - axisLine: { show: true, lineStyle: { color: '#00E8FF' } } - }, - series: [ - { - type: 'pictorialBar', - label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 }, - symbolSize: [20, 8], - symbolOffset: [0, 5], - z: 20, - itemStyle: { - borderColor: '#3588C7', - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'RGBA(22, 89, 98, 1)' }, - { offset: 1, color: '#3588C7' } - ]) - }, - data: data - }, - { - type: 'bar', - barWidth: 20, - itemStyle: { - borderWidth: 1, - borderColor: '#3588C7', - opacity: 0.8, - color: { - x: 0, y: 0, x2: 0, y2: 1, - type: 'linear', - global: false, - colorStops: [ - { offset: 0, color: 'rgba(73,178,255,0)' }, - { offset: 0.5, color: 'rgba(0, 232, 255, .5)' }, - { offset: 1, color: 'rgba(0, 232, 255, 1)' } - ] - } - }, - tooltip: { show: false }, - data: data - }, - { - type: 'pictorialBar', - symbolSize: [20, 8], - symbolOffset: [0, -4], - z: 12, - symbolPosition: 'end', - itemStyle: { - borderColor: 'rgba(0, 232, 255, 1)', - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { offset: 0, color: 'RGBA(22, 89, 98, 1)' }, - { offset: 1, color: '#3588C7' } - ]) - }, - tooltip: { show: false }, - data: data - } - ] - } - - this.chart.setOption(option) - } } } diff --git a/src/views/home/components/coresBar.vue b/src/views/home/components/coresBar.vue index 96fc0123..4fb63f4e 100644 --- a/src/views/home/components/coresBar.vue +++ b/src/views/home/components/coresBar.vue @@ -12,9 +12,16 @@ export default { props: { chartSeries: { type: Array, - required: true, default: () => [] // 默认空数组,避免报错 - } + }, + xAxisData: { + type: Array, + default: () => [] // 默认空数组,避免报错 + }, + dateData: { + type: Object, + default: () => {} // 默认空数组,避免报错 + }, }, data() { return { @@ -61,6 +68,7 @@ export default { // 单独提取更新图表的方法,方便复用 updateChart() { if (!this.myChart) return; + console.log('this.chartSeries', this.chartSeries,this.xAxisData); const option = { tooltip: { @@ -85,10 +93,28 @@ export default { color: 'rgba(0, 0, 0, 0.45)', fontSize: 12, interval: 0, - width: 38, - overflow: 'break' + // width: 38, + overflow: 'break', + formatter: (value) => { + const dateParts = value.split('-'); // ["2025", "07", "01"] + if (dateParts.length < 2) return value; // 处理异常格式 + + switch (this.dateData.mode) { + case 1: // 日模式,显示“月-日” + // 确保有日的部分 + return dateParts.length >= 3 + ? `${dateParts[1]}月${dateParts[2]}日` + : `${dateParts[1]}月`; // fallback + case 2: // 月模式,显示“月” + return `${dateParts[1]}月`; + case 3: // 年模式,显示“年” + return `${dateParts[0]}年`; + default: // 默认月模式 + return `${dateParts[1]}月`; + } + } }, - data: ['6月', '7月', '8月', '9月', '10月', '11月'] + data: this.xAxisData } ], yAxis: { diff --git a/src/views/home/components/cost-Item.vue b/src/views/home/components/cost-Item.vue index 5fffdd9f..95d74810 100644 --- a/src/views/home/components/cost-Item.vue +++ b/src/views/home/components/cost-Item.vue @@ -2,7 +2,7 @@
-
{{ item.unit }}
+
{{ item.name }}
@@ -24,7 +24,7 @@
- {{ get环比额(item.currentValue, item.targetValue) }} + {{ item.hbe }}
环比额
@@ -37,46 +37,75 @@ export default { name: "Container", components: {}, - props: ["name", "size", "icon"], + props: { + cost: { // 接收父组件传递的 cost 数据对象 + type: Object, + default: () => ({}) + } + }, data() { return { - itemList: [ - { - unit: "管理费用·万元", - targetValue: 16, // 上月值 - currentValue: 14.5, // 本月值(小于上月,应显示橙色) - }, - { - unit: "销售费用·万元", - targetValue: 16, - currentValue: 17, // 大于上月,应显示绿色 - }, - { - unit: "财务费用·万元", - targetValue: 16, - currentValue: 16, // 等于上月,应显示绿色 - }, - ] + itemList: [] // 初始化为空数组,等待数据加载 }; }, + watch: { + // 监听 cost 数据变化,实时更新 itemList + cost: { + handler(newVal) { + if (newVal) { + this.itemList = this.transformData(newVal); + } + }, + immediate: true, // 组件初始化时立即执行一次 + deep: true // 深度监听对象内部属性变化 + } + }, methods: { + /** + * 核心转换函数:将 cost 对象转换为 itemList 数组 + * @param {Object} rawData - 原始的 cost 数据对象 + * @returns {Array} - 转换后的 itemList 数组 + */ + transformData(rawData) { + // 定义费用类型映射关系(键名、显示名称、单位) + const costMapping = [ + { key: 'manageCost', name: '管理费用·万元' }, + { key: 'saleCost', name: '销售费用·万元' }, + { key: 'financeCost', name: '财务费用·万元' } + ]; + + // 遍历映射关系,转换数据 + return costMapping.map(mappingItem => { + // 获取对应费用类型的数据,若不存在则使用默认值 + const costData = rawData[mappingItem.key] || { last: 0, this: 0, hbe: 0 }; + + return { + name: mappingItem.name, + targetValue: costData.last, // 上月值 + currentValue: costData.this // 本月值 + }; + }); + }, + // 颜色判断:本月 >= 上月 绿色,否则 橙色 getColor(current, target) { return current >= target - ? "rgba(98, 213, 180, 1)" - : "rgba(249, 164, 74, 1)"; + ? "rgba(98, 213, 180, 1)" // 绿色:增长或持平 + : "rgba(249, 164, 74, 1)"; // 橙色:下降 }, + // 计算环比额(本月 - 上月),保留一位小数 - get环比额(current, target) { - const diff = current - target; - // 正数加"+"号,负数和零保持原样 - return diff > 0 ? `${diff.toFixed(1)}` : diff.toFixed(1); - } + // getData(current, target) { + // const diff = current - target; + // // 正数加"+"号,负数和零保持原样 + // return diff > 0 ? `+${diff.toFixed(1)}` : diff.toFixed(1); + // } }, }; diff --git a/src/views/home/components/order-bottom-leftItem.vue b/src/views/home/components/order-bottom-leftItem.vue index ca6253ed..3dc1e4b4 100644 --- a/src/views/home/components/order-bottom-leftItem.vue +++ b/src/views/home/components/order-bottom-leftItem.vue @@ -71,7 +71,7 @@
+ :style="{ marginTop: cityIdx > 0 ? '2px' : '0' }" @click="getTableData(city.num)" style="cursor: pointer;">
{{ city.name }}
@@ -102,72 +102,145 @@ export default { name: "Container", components: {}, - props: ["name", "size", "icon"], + props: ["orderOutput"], data() { return { progress: 90, // 进度值基础参数 itemList: [ + // { + // unit: "总进度", + // targetValue: 16, + // currentValue: 14.5, + // progress: 90, + // cities: [] // 总进度无需城市数据,留空 + // }, + // { + // unit: "一组", + // targetValue: 16, + // currentValue: 17, + // progress: 106, + // cities: [ + // { name: "桐城", completed: 12, total: 13, progress: 92 }, + // { name: "自贡", completed: 15, total: 16, progress: 93 } // 新增城市示例 + // ] + // }, + // { + // unit: "二组", + // targetValue: 16, + // currentValue: 16, + // progress: 100, + // cities: [ + // { name: "蚌埠", completed: 10, total: 12, progress: 83 }, + // { name: "合肥", completed: 8, total: 10, progress: 80 } + // ] + // }, + // // 其他组同理,按需添加 cities 数据 + // { + // unit: "三组", + // targetValue: 16, + // currentValue: 15.2, + // progress: 85, + // cities: [{ name: "宜兴", completed: 9, total: 11, progress: 81 }] + // }, + // { + // unit: "四组", + // targetValue: 16, + // currentValue: 18, + // progress: 112, + // cities: [ + // { name: "漳州", completed: 14, total: 15, progress: 93 }, + // { name: "洛阳", completed: 12, total: 14, progress: 85 } + // ] + // }, + // { + // unit: "五组", + // targetValue: 16, + // currentValue: 14, + // progress: 80, + // cities: [{ name: "桐城", completed: 7, total: 9, progress: 77 }] + // } + ] + }; + }, + watch: { + orderOutput: { + handler(newValue, oldValue) { + this.getItemData(newValue) + }, + deep: true // 若对象内属性变化需触发,需加 deep: true + } + }, + methods: { + getItemData(data) { + this.itemList = [ { unit: "总进度", - targetValue: 16, - currentValue: 14.5, - progress: 90, + targetValue: data.totalProgress.target, + currentValue: data.totalProgress.real, + progress: data.totalProgress.rate, cities: [] // 总进度无需城市数据,留空 }, { unit: "一组", - targetValue: 16, - currentValue: 17, - progress: 106, + targetValue: data.group1.target, + currentValue: data.group1.real, + progress: data.group1.rate, cities: [ - { name: "桐城", completed: 12, total: 13, progress: 92 }, - { name: "自贡", completed: 15, total: 16, progress: 93 } // 新增城市示例 + { name: "桐城", completed: data[2].real, total: data[2].target, progress: data[2].rate,num:2 }, + { name: "自贡", completed: data[3].real, total: data[3].target, progress: data[3].rate, num: 3 } // 新增城市示例 ] }, { unit: "二组", - targetValue: 16, - currentValue: 16, - progress: 100, + targetValue: data.group2.target, + currentValue: data.group2.real, + progress: data.group2.rate, cities: [ - { name: "蚌埠", completed: 10, total: 12, progress: 83 }, - { name: "合肥", completed: 8, total: 10, progress: 80 } + { name: "蚌埠", completed: data[4].real, total: data[4].target, progress: data[4].rate, num: 4 }, + { name: "合肥", completed: data[5].real, total: data[5].target, progress: data[5].rate, num: 5 } ] }, // 其他组同理,按需添加 cities 数据 { unit: "三组", - targetValue: 16, - currentValue: 15.2, - progress: 85, - cities: [{ name: "宜兴", completed: 9, total: 11, progress: 81 }] + targetValue: data.group3.target, + currentValue: data.group3.real, + progress: data.group3.rate, + cities: [{ name: "江苏凯盛", completed: data[6].real, total: data[6].target, progress: data[6].rate, num: 6 }, + { name: "宜兴", completed: data[7].real, total: data[7].target, progress: data[7].rate, num: 7 } + ] }, { unit: "四组", - targetValue: 16, - currentValue: 18, - progress: 112, + targetValue: data.group4.target, + currentValue: data.group4.real, + progress: data.group4.rate, cities: [ - { name: "漳州", completed: 14, total: 15, progress: 93 }, - { name: "洛阳", completed: 12, total: 14, progress: 85 } + { name: "漳州", completed: data[8].real, total: data[8].target, progress: data[8].rate, num: 8 }, + { name: "洛阳", completed: data[9].real, total: data[9].target, progress: data[9].rate, num: 9 } ] }, { unit: "五组", - targetValue: 16, - currentValue: 14, - progress: 80, - cities: [{ name: "桐城", completed: 7, total: 9, progress: 77 }] + targetValue: data.group5.target, + currentValue: data.group5.real, + progress: data.group5.rate, + cities: [{ name: "秦皇岛", completed: data[10].real, total: data[10].target, progress: data[10].rate, num: 10 }, + // { name: "秦皇岛", completed: 7, total: 9, progress: 77 } + ] } ] - }; - }, - methods: { + }, // 颜色判断核心方法:实际值≥目标值返回绿色,否则返回橙色 getColor(currentValue, targetValue) { return currentValue >= targetValue ? "rgba(98, 213, 180, 1)" : "rgba(249, 164, 74, 1)"; + }, + getTableData(data) { + console.log(data, 'data'); + this.$emit('handleShowTable',data) + } } }; @@ -466,15 +539,16 @@ export default { } /* 右上角折现边框(主边框) */ -.groupData::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - clip-path: polygon(0 0, calc(100% - 20px) 0, 100% 20px, 100% 100%, 0 100%); -} +// .groupData::before { +// content: ""; +// position: absolute; +// top: 0; +// left: 0; +// width: 100%; +// height: 100%; +// background-color: #000000; +// clip-path: polygon(0 0, calc(100% - 20px) 0, 100% 20px, 100% 100%, 0 100%); +// } /* 右上角折现细节 */ .groupData::after { diff --git a/src/views/home/components/orderColor.vue b/src/views/home/components/orderColor.vue new file mode 100644 index 00000000..0d59ba1b --- /dev/null +++ b/src/views/home/components/orderColor.vue @@ -0,0 +1,38 @@ + + + + + + diff --git a/src/views/home/components/orderProgress.vue b/src/views/home/components/orderProgress.vue index 0d596ae6..f0536c20 100644 --- a/src/views/home/components/orderProgress.vue +++ b/src/views/home/components/orderProgress.vue @@ -1,9 +1,12 @@