修改
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div style="">
|
||||
<Container name="利润主要影响因素" icon="cockpitItemIcon" size="profitMiddleBasic" topSize="KFAPTopTitle">
|
||||
<Container name="利润主要影响因素·万元" icon="cockpitItemIcon" size="profitMiddleBasic" topSize="KFAPTopTitle">
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex;width: 100%;">
|
||||
<div class="left" style="width: 382px;">
|
||||
<top-item :itemList="targetItemList" />
|
||||
|
||||
@@ -109,8 +109,8 @@ export default {
|
||||
lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 },
|
||||
itemStyle: {
|
||||
color: 'rgba(91, 230, 190, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -130,8 +130,8 @@ export default {
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 },
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 132, 0, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
//
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -154,8 +154,8 @@ export default {
|
||||
lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 },
|
||||
itemStyle: {
|
||||
color: 'rgba(91, 230, 190, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -175,8 +175,8 @@ export default {
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 },
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 132, 0, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -199,8 +199,8 @@ export default {
|
||||
lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 },
|
||||
itemStyle: {
|
||||
color: 'rgba(91, 230, 190, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -220,8 +220,8 @@ export default {
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 },
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 132, 0, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
|
||||
@@ -63,6 +63,7 @@ export default {
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
|
||||
itemStyle: {
|
||||
color: 'rgba(91, 230, 190, 1)',
|
||||
@@ -83,6 +84,7 @@ export default {
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 132, 0, 1)',
|
||||
@@ -106,11 +108,12 @@ export default {
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
|
||||
itemStyle: {
|
||||
color: 'rgba(91, 230, 190, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -126,11 +129,12 @@ export default {
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 132, 0, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -149,11 +153,12 @@ export default {
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
|
||||
itemStyle: {
|
||||
color: 'rgba(91, 230, 190, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -169,11 +174,12 @@ export default {
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 132, 0, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -192,11 +198,12 @@ export default {
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
|
||||
itemStyle: {
|
||||
color: 'rgba(91, 230, 190, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
@@ -212,11 +219,12 @@ export default {
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
|
||||
itemStyle: {
|
||||
color: 'rgba(255, 132, 0, 1)',
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1
|
||||
|
||||
borderWidth: 2
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
|
||||
@@ -50,12 +50,15 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
maintenanceTasks: [
|
||||
{ id: 1, eqName: '研发经费入强度/%', taskName: '例行维护', monthlyActual: '85%', accumulated: '78%', status: 'done' }, // 已完成-绿色
|
||||
{ id: 2, eqName: '存货/亿元', taskName: '例行维护', monthlyActual: '60%', accumulated: '65%', status: 'pending' }, // 未完成-橙色
|
||||
{ id: 3, eqName: '三年以上应收款/亿元', taskName: '故障排查', monthlyActual: '100%', accumulated: '92%', status: 'done' },
|
||||
{ id: 4, eqName: '非经营性资产处置到账金额/万元', taskName: '部件更换', monthlyActual: '45%', accumulated: '50%', status: 'pending' },
|
||||
{ id: 4, eqName: '研发经费投入/万元', taskName: '部件更换', monthlyActual: '45%', accumulated: '50%', status: 'pending' },
|
||||
{ id: 4, eqName: '经营性现金流/万元', taskName: '部件更换', monthlyActual: '45%', accumulated: '50%', status: 'pending' },
|
||||
{
|
||||
id: 1, eqName: '应收账款(亿元)', taskName: '10', monthlyActual: '12.45', accumulated: '12.45', status: 'done' }, // 已完成-绿色
|
||||
|
||||
{ id: 2, eqName: '存货/亿元', taskName: '0.57', monthlyActual: '0.72', accumulated: '0.72', status: 'pending' }, // 未完成-橙色
|
||||
{ id: 3, eqName: '三年以上应收款/亿元', taskName: '0.57', monthlyActual: '0.72', accumulated: '0.72', status: 'done' },
|
||||
{ id: 4, eqName: '非经营性资产处置到账金额/万元', taskName: '11000', monthlyActual: '0', accumulated: '0', status: 'pending' },
|
||||
{ id: 1, eqName: '研发经费入强度/%', taskName: '3.07', monthlyActual: '2.37', accumulated: '3.14', status: 'done' }, // 已完成-绿色
|
||||
{ id: 4, eqName: '研发经费投入/万元', taskName: '19500', monthlyActual: '1084', accumulated: '2797', status: 'pending' },
|
||||
{ id: 4, eqName: '经营性现金流/万元', taskName: '2898', monthlyActual: '13472', accumulated: '-30490', status: 'pending' },
|
||||
|
||||
// { id: 2, eqName: '螺杆挤出', taskName: '例行维护', },
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="lineBottom" style="height: 100%; width: 100%">
|
||||
<operatingLineBar :chartData="chartData" style="height: 99%; width: 100%" />
|
||||
<operatingLineBar :chartData="chartD" style="height: 99%; width: 100%" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -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. 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -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)',
|
||||
|
||||
@@ -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)',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
<Container name="趋势图" icon="cockpitItemIcon" size="operatingLarge" topSize="large">
|
||||
<!-- 1. 移除 .kpi-content 的固定高度,改为自适应 -->
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex;width: 100%;">
|
||||
<div class="bottom"
|
||||
style="height: 380px; display: flex; width: 100%;background-color: rgba(249, 252, 255, 1);">
|
||||
<div class="bottom" style="height: 380px; display: flex; width: 100%;background-color: rgba(249, 252, 255, 1);">
|
||||
<!-- <top-item /> -->
|
||||
<coreBottomBar />
|
||||
<coreBottomBar :chartData="chartData" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -15,157 +14,124 @@
|
||||
</template>
|
||||
<script>
|
||||
import Container from './container.vue'
|
||||
// import * as echarts from 'echarts'
|
||||
import coreBottomBar from './operatingBar.vue'
|
||||
|
||||
export default {
|
||||
name: 'ProductionStatus',
|
||||
components: { Container, coreBottomBar },
|
||||
// mixins: [resize],
|
||||
props: {
|
||||
leftEqInfoData: { // 接收父组件传递的设备数据数组
|
||||
type: Array,
|
||||
default: () => [] // 默认空数组,避免报错
|
||||
salesTrendMap: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
|
||||
grossMarginTrendMap: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null
|
||||
chartData: null // 初始化 chartData 为 null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
productionOverviewVo: {
|
||||
handler(newValue, oldValue) {
|
||||
this.updateChart()
|
||||
grossMarginTrendMap: {
|
||||
handler() {
|
||||
this.processChartData();
|
||||
},
|
||||
deep: true // 若对象内属性变化需触发,需加 deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 初始化图表(若需展示图表,需在模板中添加对应 DOM)
|
||||
// this.$nextTick(() => this.updateChart())
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 销毁图表,避免内存泄漏
|
||||
if (this.chart) {
|
||||
this.chart.dispose()
|
||||
this.chart = null
|
||||
immediate: true,
|
||||
deep: true
|
||||
},
|
||||
salesTrendMap: {
|
||||
handler() {
|
||||
this.processChartData();
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateChart() {
|
||||
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM,需在模板中补充,否则会报错
|
||||
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
|
||||
if (!document.getElementById('productionStatusChart')) return
|
||||
/**
|
||||
* 核心处理函数:在所有数据都准备好后,才组装 chartData
|
||||
*/
|
||||
processChartData() {
|
||||
// 关键改动:增加数据有效性检查
|
||||
// 检查 salesTrendMap 是否有实际数据(不只是空对象)
|
||||
const isSalesDataReady = Object.keys(this.salesTrendMap).length > 0;
|
||||
// 检查 grossMarginTrendMap 是否有实际数据
|
||||
const isGrossMarginDataReady = Object.keys(this.grossMarginTrendMap).length > 0;
|
||||
|
||||
if (this.chart) this.chart.dispose()
|
||||
this.chart = echarts.init(document.getElementById('productionStatusChart'))
|
||||
// 如果任一数据未准备好,则不更新 chartData,或传递一个加载中的状态
|
||||
// 你可以根据业务需求调整这里的逻辑,比如:
|
||||
// 1. 等待两者都准备好
|
||||
// 2. 只要有一个准备好了就更新,但确保另一个有合理的默认值
|
||||
|
||||
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
|
||||
]
|
||||
// --- 方案一:等待两者都准备好 ---
|
||||
// if (!isSalesDataReady || !isGrossMarginDataReady) {
|
||||
// console.log('数据尚未全部准备好,暂不更新图表');
|
||||
// this.chartData = {
|
||||
// grossMarginLocations: [],
|
||||
// salesLocations: [],
|
||||
// grossMargin: { rates: [], reals: [], targets: [], flags: [] },
|
||||
// sales: { rates: [], reals: [], targets: [], flags: [] },
|
||||
// };
|
||||
// return;
|
||||
// }
|
||||
|
||||
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
|
||||
}
|
||||
]
|
||||
}
|
||||
// --- 方案二 (推荐):有什么数据就显示什么,没有的就显示空 ---
|
||||
// 这种方式更友好,用户可以先看到部分数据
|
||||
const grossMarginLocations = isGrossMarginDataReady ? Object.keys(this.grossMarginTrendMap) : [];
|
||||
const salesLocations = isSalesDataReady ? Object.keys(this.salesTrendMap) : [];
|
||||
|
||||
this.chart.setOption(option)
|
||||
const processedGrossMarginData = isGrossMarginDataReady
|
||||
? this.processSingleDataset(grossMarginLocations, this.grossMarginTrendMap)
|
||||
: { rates: [], reals: [], targets: [], flags: [] };
|
||||
|
||||
const processedSalesData = isSalesDataReady
|
||||
? this.processSingleDataset(salesLocations, this.salesTrendMap)
|
||||
: { rates: [], reals: [], targets: [], flags: [] };
|
||||
|
||||
// 3. 组装最终的 chartData 对象
|
||||
this.chartData = {
|
||||
grossMarginLocations: grossMarginLocations,
|
||||
salesLocations: salesLocations,
|
||||
grossMargin: processedGrossMarginData,
|
||||
sales: processedSalesData
|
||||
};
|
||||
|
||||
console.log('chartData 已更新:', this.chartData);
|
||||
},
|
||||
|
||||
/**
|
||||
* 通用数据处理函数(纯函数)
|
||||
* @param {Array} locations - 某个指标的地点数组
|
||||
* @param {Object} dataMap - 该指标的原始数据映射
|
||||
* @returns {Object} - 格式化后的数据对象
|
||||
*/
|
||||
processSingleDataset(locations, dataMap) {
|
||||
const rates = [];
|
||||
const reals = [];
|
||||
const targets = [];
|
||||
const flags = [];
|
||||
|
||||
locations.forEach(location => {
|
||||
const data = dataMap[location] || {};
|
||||
// 优化:处理 data.rate 为 null/undefined 的情况
|
||||
const rate = data.rate !== null && data.rate !== undefined ? Math.round(data.rate * 100) : 0;
|
||||
|
||||
rates.push(rate);
|
||||
reals.push(data.real ?? 0); // 使用空值合并运算符
|
||||
targets.push(data.target ?? 0);
|
||||
|
||||
// 优化:更清晰的逻辑
|
||||
if (data.target === 0) {
|
||||
flags.push(1); // 如果目标为0,默认达标
|
||||
} else {
|
||||
flags.push(rate >= 100 ? 1 : 0);
|
||||
}
|
||||
});
|
||||
|
||||
return { rates, reals, targets, flags };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="kpi-content" style="padding: 14px 14px; display: flex;flex-direction: column; width: 100%;">
|
||||
<!-- 2. .top 保持 flex,无需固定高度,自动跟随子元素拉伸 -->
|
||||
<div class="top" style="display: flex; width: 100%;">
|
||||
<top-item :height="367" :itemList="parentItemList" />
|
||||
<top-item v-if="saleData" :height="367" :itemList="formattedParentItemList" />
|
||||
</div>
|
||||
<div class="bottom"
|
||||
style="display: flex; width: 100%;margin-top: 8px;background-color: rgba(249, 252, 255, 1);">
|
||||
@@ -27,14 +27,10 @@ export default {
|
||||
components: { Container, topItem },
|
||||
// mixins: [resize],
|
||||
props: {
|
||||
leftEqInfoData: { // 接收父组件传递的设备数据数组
|
||||
type: Array,
|
||||
default: () => [] // 默认空数组,避免报错
|
||||
},
|
||||
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
|
||||
saleData: { // 接收父组件传递的设备数据数组
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
default: () => {} // 默认空数组,避免报错
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -42,57 +38,57 @@ export default {
|
||||
parentItemList: [
|
||||
{
|
||||
name: "利润总额",
|
||||
targetValue: 50,
|
||||
value: 58,
|
||||
proportion: 116,
|
||||
targetValue: 0,
|
||||
value: 0,
|
||||
proportion: 0,
|
||||
route: 'profitAnalysis',
|
||||
completed: 1 // 实际超目标,达标
|
||||
},
|
||||
{
|
||||
name: "毛利率",
|
||||
targetValue: 30,
|
||||
value: 28.5,
|
||||
proportion: 95,
|
||||
targetValue: 0,
|
||||
value: 0,
|
||||
proportion: 0,
|
||||
route: 'profitAnalysis',
|
||||
completed: 0 // 未达30%目标,不达标
|
||||
completed: 1 // 未达30%目标,不达标
|
||||
},
|
||||
{
|
||||
name: "单价",
|
||||
targetValue: 12,
|
||||
value: 12.5,
|
||||
proportion: 104.2,
|
||||
targetValue: 0,
|
||||
value: 0,
|
||||
proportion: 0,
|
||||
route: 'cost/cost',
|
||||
completed: 1 // 单价达标
|
||||
},
|
||||
{
|
||||
name: "净价",
|
||||
targetValue: 9,
|
||||
value: 8.8,
|
||||
proportion: 97.8,
|
||||
targetValue: 0,
|
||||
value: 0,
|
||||
proportion: 0,
|
||||
route: 'cost/cost',
|
||||
completed: 0 // 未达目标,不达标
|
||||
completed: 1 // 未达目标,不达标
|
||||
},
|
||||
{
|
||||
name: "销量",
|
||||
targetValue: 100,
|
||||
value: 120,
|
||||
proportion: 120,
|
||||
targetValue: 0,
|
||||
value: 0,
|
||||
proportion: 0,
|
||||
route: 'profitAnalysis',
|
||||
completed: 1 // 销量超额达标
|
||||
},
|
||||
{
|
||||
name: "双镀面板",
|
||||
targetValue: 30,
|
||||
value: 29,
|
||||
proportion: 96.7,
|
||||
targetValue: 0,
|
||||
value: 0,
|
||||
proportion: 0,
|
||||
route: 'profitAnalysis',
|
||||
completed: 0 // 略低目标,不达标
|
||||
completed: 1 // 略低目标,不达标
|
||||
},
|
||||
{
|
||||
name: "溢价产品销量",
|
||||
targetValue: 15,
|
||||
value: 18,
|
||||
proportion: 120,
|
||||
targetValue: 0,
|
||||
value: 0,
|
||||
proportion: 0,
|
||||
route: 'profitAnalysis',
|
||||
completed: 1 // 超额达标
|
||||
}
|
||||
@@ -100,135 +96,59 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
productionOverviewVo: {
|
||||
handler(newValue, oldValue) {
|
||||
this.updateChart()
|
||||
},
|
||||
deep: true // 若对象内属性变化需触发,需加 deep: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
formattedParentItemList() {
|
||||
// --- 新增判断 ---
|
||||
// 如果 saleData 不存在、为 null,或者是不包含任何属性的空对象,则返回原始的 parentItemList
|
||||
if (!this.saleData || Object.keys(this.saleData).length === 0) {
|
||||
return this.parentItemList;
|
||||
}
|
||||
// --- 判断结束 ---
|
||||
|
||||
// 定义一个名称到键的映射表,方便查找
|
||||
const nameToKeyMap = {
|
||||
"利润总额": "totalProfit",
|
||||
"毛利率": "grossMargin",
|
||||
"单价": "unitPrice",
|
||||
"净价": "netPrice",
|
||||
"销量": "sales",
|
||||
"双镀面板": "panel",
|
||||
"溢价产品销量": "premiumProduct"
|
||||
};
|
||||
|
||||
// 遍历原始的 parentItemList
|
||||
return this.parentItemList.map(item => {
|
||||
// 根据当前 item 的 name 找到 SaleData 中对应的键
|
||||
const key = nameToKeyMap[item.name];
|
||||
|
||||
// 如果找到了对应的键,并且 saleItem 存在,就从 SaleData 中获取数据
|
||||
if (key && this.saleData[key]) {
|
||||
const saleItem = this.saleData[key];
|
||||
return {
|
||||
...item,
|
||||
value: saleItem.real,
|
||||
targetValue: saleItem.target,
|
||||
// proportion: saleItem.rate !== null && saleItem.rate !== undefined
|
||||
// ? Math.round(saleItem.rate * 100)
|
||||
// : 0,
|
||||
// 直接使用处理好的 rate
|
||||
proportion: saleItem.rate,
|
||||
// 根据完成率判断是否达标 (假设 >=100% 为达标)
|
||||
completed: saleItem.rate >= 1 ? 1 : 0,
|
||||
};
|
||||
}
|
||||
|
||||
// 如果没有找到对应的数据,则返回原始 item
|
||||
return item;
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 初始化图表(若需展示图表,需在模板中添加对应 DOM)
|
||||
// this.$nextTick(() => this.updateChart())
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 销毁图表,避免内存泄漏
|
||||
if (this.chart) {
|
||||
this.chart.dispose()
|
||||
this.chart = null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateChart() {
|
||||
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM,需在模板中补充,否则会报错
|
||||
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -391,14 +311,4 @@ export default {
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* 全局 tooltip 样式(不使用 scoped,确保生效) */
|
||||
.production-status-chart-tooltip {
|
||||
background: #0a2b4f77 !important;
|
||||
border: none !important;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.production-status-chart-tooltip * {
|
||||
color: #fff !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -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)' }
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px 8px 16px; display: flex;flex-direction: column; width: 100%;">
|
||||
<!-- 2. .top 保持 flex,无需固定高度,自动跟随子元素拉伸 -->
|
||||
<div class="top" style="display: flex; width: 100%;">
|
||||
<top-item :itemList="parentItemList" />
|
||||
<top-item :itemList="formattedPremiumProductList" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-content" style="display: flex;flex-direction: column; width: 100%;">
|
||||
@@ -28,10 +28,10 @@
|
||||
</div>
|
||||
<div class="pie" style="display: flex;gap: 8px;margin-top: 68px;padding: 0 16px;">
|
||||
<div class="month-pie" style="height: 212px;width: 382px;background: #F9FCFF;">
|
||||
<pieChart :chartRef=" 'monthChart' " />
|
||||
<pieChart :pieData="monthPieData" :chartRef=" 'monthChart' " />
|
||||
</div>
|
||||
<div class="-pie" style="height: 212px;width: 382px;background: #F9FCFF;">
|
||||
<pieChartTwo :chartRef="'yearChart'" />
|
||||
<pieChartTwo :pieData="yearPieData" :chartRef="'yearChart'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
|
||||
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 {
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* 全局 tooltip 样式(不使用 scoped,确保生效) */
|
||||
.production-status-chart-tooltip {
|
||||
background: #0a2b4f77 !important;
|
||||
border: none !important;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.production-status-chart-tooltip * {
|
||||
color: #fff !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container name="利润数据总览" icon="cockpitItemIcon" size="profitTopBasic" topSize="middle">
|
||||
<Container name="利润数据总览·万元" icon="cockpitItemIcon" size="profitTopBasic" topSize="middle">
|
||||
<!-- 1. 移除 .kpi-content 的固定高度,改为自适应 -->
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex;flex-direction: column; width: 100%;">
|
||||
<!-- 2. .top 保持 flex,无需固定高度,自动跟随子元素拉伸 -->
|
||||
|
||||
@@ -151,9 +151,8 @@ export default {
|
||||
fontSize: 12,
|
||||
align: 'right'
|
||||
},
|
||||
min: 0,
|
||||
max: (value) => value.max > 0 ? Math.ceil(value.max * 1.1) : 10,
|
||||
scale: false,
|
||||
scale: true,
|
||||
splitNumber: 4,
|
||||
axisTick: { show: false },
|
||||
axisLabel: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
@@ -162,7 +161,6 @@ export default {
|
||||
},
|
||||
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
|
||||
splitNumber: 4
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
@@ -171,8 +169,8 @@ export default {
|
||||
fontSize: 12,
|
||||
align: 'left'
|
||||
},
|
||||
min: 0,
|
||||
max: 100,
|
||||
// min: 0,
|
||||
// max: 100,
|
||||
axisTick: { show: false },
|
||||
axisLabel: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container name="产销数据总览" icon="cockpitItemIcon" size="profitTopBasic" topSize="middle">
|
||||
<Container name="产销数据总览·万㎡" icon="cockpitItemIcon" size="profitTopBasic" topSize="middle">
|
||||
<!-- 1. 移除 .kpi-content 的固定高度,改为自适应 -->
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex;flex-direction: column; width: 100%;">
|
||||
<!-- 2. .top 保持 flex,无需固定高度,自动跟随子元素拉伸 -->
|
||||
|
||||
Reference in New Issue
Block a user