diff --git a/.env.dev b/.env.dev index c5894fc5..9bd580d3 100644 --- a/.env.dev +++ b/.env.dev @@ -5,7 +5,10 @@ ENV = 'development' VUE_APP_TITLE = 洛玻集团驾驶舱 # 芋道管理系统/开发环境 -VUE_APP_BASE_API = 'http://172.16.32.18:7070' +# VUE_APP_BASE_API = 'http://172.16.32.18:7070' +# VUE_APP_BASE_API = 'http://172.16.32.95:7070' +VUE_APP_BASE_API = 'http://172.16.33.83:7070' + # VUE_APP_BASE_API = 'http://192.168.0.35:7070' diff --git a/.env.prod b/.env.prod index 4c81e3c2..50b5e38e 100644 --- a/.env.prod +++ b/.env.prod @@ -5,11 +5,13 @@ NODE_ENV = 'production' VUE_APP_TITLE = 洛玻集团驾驶舱 # 芋道管理系统/生产环境 -VUE_APP_BASE_API = 'http://192.168.0.35:7070' +# 建议使用相对路径或通过nginx配置的域名/路径,避免写死IP和端口 +VUE_APP_BASE_API = '' # 示例:使用相对路径,由nginx转发到实际后端地址 -# 根据服务器或域名修改 -# PUBLIC_PATH = 'http://192.168.0.35:7070' -# 二级部署路径 +# 根据服务器或域名修改,使用相对路径,避免写死IP和端口 +PUBLIC_PATH = '' # 改为根路径,或根据实际二级部署路径设置(如 '/subpath/') + +# 二级部署路径(如果需要) # VUE_APP_APP_NAME ='yudao-admin' # 多租户的开关 diff --git a/dist.zip b/dist.zip new file mode 100644 index 00000000..857eee84 Binary files /dev/null and b/dist.zip differ diff --git a/src/api/cockpit.js b/src/api/cockpit.js index 39ff8fe4..fa468c9a 100644 --- a/src/api/cockpit.js +++ b/src/api/cockpit.js @@ -43,3 +43,20 @@ export function getAccountSumaryPage(data) { params: data, }); } + +export function getProfitImpactList(data) { + return request({ + url: "/lb/cost-analysis/profitImpactList", + method: "post", + data: data, + }); +} + +export function getSalesRevenueData(data) { + return request({ + url: "lb/sales-revenue/getData", + method: "post", + data: data, + }); +} + diff --git a/src/assets/img/productMiddleBg.png b/src/assets/img/productMiddleBg.png index 9b31995c..0183ac6f 100644 Binary files a/src/assets/img/productMiddleBg.png and b/src/assets/img/productMiddleBg.png differ diff --git a/src/views/home/PSIAnal.vue b/src/views/home/PSIAnal.vue index 60983b57..8bb3e841 100644 --- a/src/views/home/PSIAnal.vue +++ b/src/views/home/PSIAnal.vue @@ -143,12 +143,6 @@ export default { this.destroy(); }, mounted() { - const startTime = moment().startOf("week").format("YYYY-MM-DD"); - const endTime = moment().format("YYYY-MM-DD"); - console.log(this.date, "date"); - this.date = [startTime, endTime]; - // this.weekDay = this.weekArr[moment(this.date).format('e')] - // this.getData() const _this = this; _this.beilv = document.documentElement.clientWidth / 1920; window.onresize = () => { diff --git a/src/views/home/components/KFAP.vue b/src/views/home/components/KFAP.vue index 36ed7f84..ddb46566 100644 --- a/src/views/home/components/KFAP.vue +++ b/src/views/home/components/KFAP.vue @@ -1,6 +1,6 @@ @@ -48,18 +48,31 @@ import * as echarts from 'echarts'; export default { name: "Container", components: { operatingLineBar }, - props: ["name", "size", "icon"], + props: ["chartData"], data() { return { activeButton: 0, }; }, computed: { + currentDataSource() { + console.log('yyyy',this.chartData); + + return this.activeButton === 0 ? this.chartData.sales : this.chartData.grossMargin; + }, + locations() { + console.log('this.chartData', this.chartData); + + return this.activeButton === 0 ? this.chartData.salesLocations : this.chartData.grossMarginLocations; + }, // 根据按钮切换生成对应的 chartData - chartData() { + chartD() { // 销量场景数据 + const data = this.currentDataSource; + console.log(this.currentDataSource,'currentDataSource'); + const salesData = { - allPlaceNames: ['桐城', '合肥', '宜兴', '漳州', '自贡', '洛阳'], // x轴刻度 + allPlaceNames: this.locations, series: [ // 1. 完成率(折线图) { @@ -83,7 +96,7 @@ export default { { offset: 1, color: 'rgba(40, 138, 255, 0)' } ]) }, - data: [104, 96.7, 107.3, 97.1, 107.7, 93.8], // 完成率(%) + data: data.rates, // 完成率(%) symbol: 'circle', symbolSize: 6 }, @@ -105,7 +118,7 @@ export default { borderRadius: [4, 4, 0, 0], borderWidth: 0 }, - data: [50, 60, 55, 70, 65, 80] // 目标销量(万元) + data: data.targets // 目标销量(万元) }, // 3. 实际(柱状图,含达标状态) { @@ -116,7 +129,7 @@ export default { itemStyle: { color: (params) => { // 达标状态:1=达标(绿色),0=未达标(橙色) - const safeFlag = [1, 0, 1, 0, 1, 0]; + const safeFlag = data.flags; const currentFlag = safeFlag[params.dataIndex] || 0; return currentFlag === 1 ? { @@ -139,14 +152,13 @@ export default { borderRadius: [4, 4, 0, 0], borderWidth: 0 }, - data: [52, 58, 59, 68, 70, 75] // 实际销量(万元) + data: data.reals // 实际销量(万元) } ] }; // 毛利率场景数据 const grossProfitData = { - allPlaceNames: ['1月', '2月', '3月', '4月', '5月', '6月'], series: [ // 1. 完成率(折线图) { diff --git a/src/views/home/components/operatingBottomLineBar.vue b/src/views/home/components/operatingBottomLineBar.vue index fb01491f..6f6e5109 100644 --- a/src/views/home/components/operatingBottomLineBar.vue +++ b/src/views/home/components/operatingBottomLineBar.vue @@ -111,15 +111,16 @@ export default { // 左侧Y轴:营业收入、成本(单位万元) { type: 'value', + splitNumber: 4, name: '万元', nameTextStyle: { color: 'rgba(0, 0, 0, 0.45)', fontSize: 12, align: 'right' }, - min: 0, - max: (value) => Math.ceil((value.max || 0) * 1.1), - scale: false, + // min: 0, + // max: (value) => Math.ceil((value.max || 0) * 1.1), + scale: true, axisTick: { show: false }, axisLabel: { color: 'rgba(0, 0, 0, 0.45)', @@ -138,8 +139,10 @@ export default { fontSize: 12, align: 'left' }, - min: 0, - max: 100, + // min: 0, + // max: 100, + scale:true, + splitNumber: 4, axisTick: { show: false }, axisLabel: { color: 'rgba(0, 0, 0, 0.45)', diff --git a/src/views/home/components/operatingLineBar.vue b/src/views/home/components/operatingLineBar.vue index cefdd756..240021a3 100644 --- a/src/views/home/components/operatingLineBar.vue +++ b/src/views/home/components/operatingLineBar.vue @@ -117,9 +117,8 @@ export default { fontSize: 12, align: 'right' }, - min: 0, - max: (value) => Math.ceil((value.max || 0) * 1.1), - scale: false, + scale: true, + splitNumber: 4, axisTick: { show: false }, axisLabel: { color: 'rgba(0, 0, 0, 0.45)', diff --git a/src/views/home/components/operatingLineBarSale.vue b/src/views/home/components/operatingLineBarSale.vue index 8e0ee6e6..2d1dd5a0 100644 --- a/src/views/home/components/operatingLineBarSale.vue +++ b/src/views/home/components/operatingLineBarSale.vue @@ -16,13 +16,11 @@ export default { chartData: { type: Object, default: () => ({ - series: [], - allPlaceNames: [] }), // 校验数据格式 - validator: (value) => { - return Array.isArray(value.series) && Array.isArray(value.allPlaceNames); - } + // validator: (value) => { + // return Array.isArray(value.series) && Array.isArray(value.allPlaceNames); + // } } }, mounted() { @@ -37,7 +35,6 @@ export default { chartData: { handler() { console.log(this.chartData,'chartData'); - this.updateChart(); }, deep: true, @@ -58,6 +55,7 @@ export default { this.myChart = echarts.init(chartDom); const { allPlaceNames, series } = this.chartData || {}; + console.log('chartData', this.chartData); // 处理空数据 const xData = allPlaceNames || []; @@ -117,9 +115,8 @@ export default { fontSize: 12, align: 'right' }, - min: 0, - max: (value) => Math.ceil((value.max || 0) * 1.1), - scale: false, + scale: true, + splitNumber: 4, axisTick: { show: false }, axisLabel: { color: 'rgba(0, 0, 0, 0.45)', @@ -128,7 +125,6 @@ export default { }, splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }, axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }, - splitNumber: 4 }, // 右侧Y轴:利润占比(百分比) { @@ -148,7 +144,8 @@ export default { }, splitLine: { show: false }, axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } }, - splitNumber: 4 + // scale: true, + splitNumber: 4, } ], series: chartSeries // 直接使用父组件传递的 series diff --git a/src/views/home/components/operatingLineChart.vue b/src/views/home/components/operatingLineChart.vue index b64f17af..92546a18 100644 --- a/src/views/home/components/operatingLineChart.vue +++ b/src/views/home/components/operatingLineChart.vue @@ -3,10 +3,9 @@
-
+
- +
@@ -15,157 +14,124 @@ @@ -391,14 +311,4 @@ export default { diff --git a/src/views/home/components/pieChart.vue b/src/views/home/components/pieChart.vue index ef154d82..0145c423 100644 --- a/src/views/home/components/pieChart.vue +++ b/src/views/home/components/pieChart.vue @@ -17,21 +17,35 @@ export default { // // 验证:ref 名不能为空,确保有效 // return value.trim() !== ''; // } - } + }, + pieData: { + type: Object, + default: () => { } // 默认空数组,避免报错 + }, }, - components: {}, data() { return {}; }, computed: {}, + watch: { + // 监听 pieData 变化,只要数据变了,就更新图表 + pieData: { + handler() { + this.initData(); // 直接调用更新,无需判断 myChart 是否存在 + }, + deep: true, + immediate: true // 初始化时立即执行 + }, + }, mounted() { this.$nextTick(() => { - this.initData(); + this.initChart(); // 只负责初始化图表实例 }); }, methods: { initData() { - // 2. 动态获取 DOM:通过 props 中的 chartRef 拿到对应的 ref 元素 + console.log(this.pieData,'this.pieData.value'); + const chartDom = this.$refs[this.chartRef]; if (!chartDom) { console.error(`图表容器未找到!请确认父组件传递的 chartRef 为 "${this.chartRef}"`); @@ -94,7 +108,7 @@ export default { labelLine: { show: true, length: 0, - length2: 30, + length2: 10, lineStyle: { color: (params) => customColors[params.dataIndex] } @@ -104,7 +118,7 @@ export default { }, data: [ { - value: 1048, name: '单镀面板', + value: this.pieData?.value || 0, name: '单镀面板', label: { normal: { align: 'left', @@ -133,7 +147,9 @@ export default { } }, labelLine: { - lineStyle: { color: 'rgba(39, 96, 255, 1)' } + lineStyle: { color: 'rgba(39, 96, 255, 1)' }, + length: 10, + length2: 20, }, itemStyle: { color: 'rgba(39, 96, 255, 1)' } }, @@ -168,8 +184,8 @@ export default { }, labelLine: { length: 0, - length2: 50, - lineStyle: { color: 'rgba(40, 138, 255, 1)' } + length2: 10, + lineStyle: { color: 'rgba(40, 138, 255, 1)' }, }, itemStyle: { color: 'rgba(40, 138, 255, 1)' } }, @@ -203,7 +219,9 @@ export default { } }, labelLine: { - lineStyle: { color: 'rgba(118, 218, 190, 1)' } + lineStyle: { color: 'rgba(118, 218, 190, 1)' }, + length: 0, + length2: 10, }, itemStyle: { color: 'rgba(118, 218, 190, 1)' } }, @@ -237,7 +255,9 @@ export default { } }, labelLine: { - lineStyle: { color: 'rgba(255, 206, 106, 1)' } + lineStyle: { color: 'rgba(255, 206, 106, 1)' }, + length: 10, + length2: 10, }, itemStyle: { color: 'rgba(255, 206, 106, 1)' } } diff --git a/src/views/home/components/premProdStatus.vue b/src/views/home/components/premProdStatus.vue index e2ecf3ae..140ef480 100644 --- a/src/views/home/components/premProdStatus.vue +++ b/src/views/home/components/premProdStatus.vue @@ -5,7 +5,7 @@
- +
@@ -28,10 +28,10 @@
- +
- +
@@ -54,11 +54,11 @@ export default { components: { Container, topItem, coreBottomBar, pieChart, pieChartTwo }, // mixins: [resize], props: { - leftEqInfoData: { // 接收父组件传递的设备数据数组 - type: Array, - default: () => [] // 默认空数组,避免报错 + premiumProduct: { // 接收父组件传递的设备数据数组 + type: Object, + default: () => {} // 默认空数组,避免报错 }, - productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留) + salesProportion: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留) type: Object, default: () => ({}) } @@ -66,20 +66,22 @@ export default { data() { return { chart: null, + monthPieData: {}, + yearPieData:{}, parentItemList: [ { name: "月度", - targetValue: 80, - value: 76, - proportion: 95, + targetValue: 0, + value: 0, + proportion: 0, route: 'profitAnalysis', - completed: 0 // 未达目标值,不达标 + completed: 1 // 未达目标值,不达标 }, { name: "年度", - targetValue: 900, - value: 920, - proportion: 102.2, + targetValue: 0, + value: 0, + proportion: 0, route: 'profitAnalysis', completed: 1 // 超出目标值,达标 } @@ -87,134 +89,68 @@ export default { } }, watch: { - productionOverviewVo: { + salesProportion: { handler(newValue, oldValue) { - this.updateChart() + console.log('salesProportion',newValue); + + this.getPieData() }, deep: true // 若对象内属性变化需触发,需加 deep: true } }, + computed: { + formattedPremiumProductList() { + const premiumProductData = this.premiumProduct || {}; + + const nameToKeyMap = { + "月度": "month", + "年度": "year" + }; + + return this.parentItemList.map(item => { + const key = nameToKeyMap[item.name]; + + if (key && premiumProductData[key]) { + const periodData = premiumProductData[key]; + + let completed = 0; + + // 新增:判断三个值是否都为0 + const allZeros = periodData.real === 0 && + periodData.target === 0 && + periodData.rate === 0; + + if (allZeros) { + completed = 1; + } else if (periodData.rate !== null && periodData.rate !== undefined) { + completed = periodData.rate >= 1 ? 1 : 0; + } + + return { + ...item, + value: periodData.real, + targetValue: periodData.target, + proportion: periodData.rate !== null && periodData.rate !== undefined + ? Math.round(periodData.rate * 100) + : 0, + completed: completed, + }; + } + + return item; + }); + } + }, 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 + getPieData() { + this.monthPieData = this.salesProportion ? this.salesProportion.month : {} + this.yearPieData = this.salesProportion ? this.salesProportion.year : {} + console.log('this.monthPieData', this.monthPieData, this.yearPieData); - 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) } } } @@ -392,16 +328,3 @@ export default { } - - diff --git a/src/views/home/components/profitBar.vue b/src/views/home/components/profitBar.vue index 925380ca..d6318e02 100644 --- a/src/views/home/components/profitBar.vue +++ b/src/views/home/components/profitBar.vue @@ -118,8 +118,20 @@ export default { yAxisIndex: 0, barWidth: 18, itemStyle: { - color: '#2889FF', - borderRadius: [4, 4, 0, 0] + // 移除多余的 normal 层级,直接配置 color 渐变 + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [ + { offset: 0, color: 'rgba(130, 204, 255, 1)' }, + { offset: 1, color: 'rgba(75, 157, 255, 1)' } + ] + }, + borderRadius: [4, 4, 0, 0], + borderWidth: 0 }, data: targetData.map(item => item.targetValue) }, diff --git a/src/views/home/components/profitOverview.vue b/src/views/home/components/profitOverview.vue index 8e90ae33..87df1aa4 100644 --- a/src/views/home/components/profitOverview.vue +++ b/src/views/home/components/profitOverview.vue @@ -1,6 +1,6 @@