营业收入-全成本分析页面修改
This commit is contained in:
4
.env.dev
4
.env.dev
@@ -10,11 +10,11 @@ VUE_APP_TITLE = 洛玻集团驾驶舱
|
||||
# VUE_APP_BASE_API = 'http://172.16.33.83:7070'
|
||||
|
||||
# 杨姗姗
|
||||
# VUE_APP_BASE_API = 'http://172.16.20.218:7070'
|
||||
VUE_APP_BASE_API = 'http://172.16.20.218:7070'
|
||||
# 小田
|
||||
# VUE_APP_BASE_API = 'http://172.16.19.232:7070'
|
||||
# 测试
|
||||
VUE_APP_BASE_API = 'http://192.168.0.35:8080'
|
||||
# VUE_APP_BASE_API = 'http://192.168.0.35:8080'
|
||||
# 闫阳
|
||||
# VUE_APP_BASE_API = 'http://172.16.19.131:7070'
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.rate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.rate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -64,7 +64,15 @@ export default {
|
||||
activeButton: 0,
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '全成本', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据
|
||||
profitOptions: ['全成本', '制造成本', '管理费用', '财务费用', '运费', '销售费用']
|
||||
profitOptions:[
|
||||
{name:'全成本',unit:'元/㎡'},
|
||||
{name:'制造成本',unit:'元/㎡'},
|
||||
{name:'管理费用',unit:'万元'},
|
||||
{name:'财务费用',unit:'万元'},
|
||||
{name:'运费',unit:'元/㎡'},
|
||||
{name:'销售费用',unit:'万元'},
|
||||
],
|
||||
unit:'元/㎡'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -128,6 +136,7 @@ export default {
|
||||
// 销量场景数据(保留原有结构,替换数据来源)
|
||||
const salesData = {
|
||||
allPlaceNames: months, // 优先用基地名称,无则用月份
|
||||
unit: this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -296,7 +305,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.unit = item.unit;
|
||||
this.isDropdownShow = false;
|
||||
},
|
||||
// 复用达标状态判断方法
|
||||
|
||||
@@ -123,6 +123,7 @@ export default {
|
||||
const data = this.currentDataSource;
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:'元/㎡',
|
||||
series: [
|
||||
// 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -122,7 +122,7 @@ export default {
|
||||
return; // 实例未初始化则返回
|
||||
}
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
const { allPlaceNames,unit, series } = this.chartData || {};
|
||||
const xData = allPlaceNames || [];
|
||||
const chartSeries = series || [];
|
||||
|
||||
@@ -169,7 +169,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '元/m2',
|
||||
name: unit,
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -70,16 +70,17 @@ export default {
|
||||
real: 0,
|
||||
target: 0,
|
||||
thb: 0
|
||||
}
|
||||
},
|
||||
currentTab: 'month',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'productionCost', name: '制造成本', unit: '元/㎡', route:'/productionCostAnalysis/productionCostAnalysisBase'},
|
||||
{ key: 'financialCost', name: '财务费用', unit: '元/㎡',route:'/expenseAnalysis/expenseAnalysisBase' },
|
||||
{ key: 'saleCost', name: '销售费用', unit: '元/㎡',route:'/expenseAnalysis/expenseAnalysisBase'},
|
||||
{ key: 'manageCost', name: '管理费用', unit: '元/㎡',route:'/expenseAnalysis/expenseAnalysisBase' },
|
||||
{ key: 'financialCost', name: '财务费用', unit: '万元',route:'/expenseAnalysis/expenseAnalysisBase' },
|
||||
{ key: 'saleCost', name: '销售费用', unit: '万元',route:'/expenseAnalysis/expenseAnalysisBase'},
|
||||
{ key: 'manageCost', name: '管理费用', unit: '万元',route:'/expenseAnalysis/expenseAnalysisBase' },
|
||||
{ key: 'freight', name: '运费', unit: '元/㎡',route:null },
|
||||
]
|
||||
},
|
||||
@@ -109,7 +110,7 @@ export default {
|
||||
})
|
||||
},
|
||||
sortedIndicators() {
|
||||
const unitOrder = ['元/㎡']
|
||||
const unitOrder = ['元/㎡','万元']
|
||||
const unitRank = (u) => {
|
||||
const idx = unitOrder.indexOf(u)
|
||||
return idx === -1 ? 999 : idx
|
||||
@@ -128,7 +129,11 @@ export default {
|
||||
// 监听 relatedData 变化(异步加载场景),同步更新月度数据
|
||||
relatedData: {
|
||||
handler(newVal) {
|
||||
if(this.currentTab === 'month') {
|
||||
this.relatedDetailData = newVal.relatedMon || {};
|
||||
}else{
|
||||
this.relatedDetailData = newVal.relatedTotal || {};
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
@@ -167,6 +172,7 @@ export default {
|
||||
},
|
||||
handleChange(value) {
|
||||
console.log('value', value, this.relatedData);
|
||||
this.currentTab = value;
|
||||
if (value === 'month') {
|
||||
this.relatedDetailData = this.relatedData.relatedMon || {};
|
||||
} else {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,10 +63,11 @@ export default {
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '毛利率', // 选中的名称,初始为null
|
||||
profitOptions: [
|
||||
'毛利率',
|
||||
'营业收入',
|
||||
'全成本',
|
||||
]
|
||||
{name:'毛利率',unit:'%'},
|
||||
{name:'营业收入',unit:'万元'},
|
||||
{name:'全成本',unit:'元/㎡'}
|
||||
],
|
||||
unit:'%'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -91,6 +92,7 @@ export default {
|
||||
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit: this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -251,9 +253,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.unit = item.unit;
|
||||
this.isDropdownShow = false;
|
||||
this.$emit("changeItem", item);
|
||||
this.$emit("changeItem", item.name);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -123,6 +123,7 @@ export default {
|
||||
const data = this.currentDataSource;
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:'%',
|
||||
series: [
|
||||
// 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -133,7 +133,7 @@ export default {
|
||||
return; // 实例未初始化则返回
|
||||
}
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
const { allPlaceNames, unit, series } = this.chartData || {};
|
||||
const xData = allPlaceNames || [];
|
||||
const chartSeries = series || [];
|
||||
|
||||
@@ -180,7 +180,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '%',
|
||||
name: unit,
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,12 +61,13 @@ export default {
|
||||
return {
|
||||
activeButton: 0,
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '加工成品率', // 选中的名称,初始为null
|
||||
selectedProfit: '投入产出率', // 选中的名称,初始为null
|
||||
profitOptions: [
|
||||
'加工成品率',
|
||||
'领用量',
|
||||
'加工产量',
|
||||
]
|
||||
{name:'投入产出率',unit:'%'},
|
||||
{name:'加工产量',unit:'㎡'},
|
||||
{name:'领用量',unit:'㎡'}
|
||||
],
|
||||
unit:'%'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -90,6 +91,7 @@ export default {
|
||||
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit: this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -251,9 +253,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.unit = item.unit;
|
||||
this.isDropdownShow = false;
|
||||
this.$emit("changeItem", item);
|
||||
this.$emit("changeItem", item.name);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.rate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -57,8 +57,8 @@ export default {
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'useData', name: '领用量', unit: '万㎡'},
|
||||
{ key: 'processData', name: '加工产量', unit: '万㎡'},
|
||||
{ key: 'useData', name: '领用量', unit: '㎡'},
|
||||
{ key: 'processData', name: '加工产量', unit: '㎡'},
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
|
||||
@@ -123,6 +123,7 @@ export default {
|
||||
const data = this.currentDataSource;
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:'%',
|
||||
series: [
|
||||
// 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -122,7 +122,7 @@ export default {
|
||||
return; // 实例未初始化则返回
|
||||
}
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
const { allPlaceNames, unit, series } = this.chartData || {};
|
||||
const xData = allPlaceNames || [];
|
||||
const chartSeries = series || [];
|
||||
|
||||
@@ -169,7 +169,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '%',
|
||||
name: unit,
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.rate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -57,8 +57,8 @@ export default {
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'useData', name: '领用量', unit: '万㎡'},
|
||||
{ key: 'processData', name: '加工产量', unit: '万㎡'},
|
||||
{ key: 'useData', name: '领用量', unit: '㎡'},
|
||||
{ key: 'processData', name: '加工产量', unit: '㎡'},
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
gap: 12px;
|
||||
grid-template-columns: 1624px;
|
||||
">
|
||||
<dataTrend :trendData="trend" :title="'数据趋势'" />
|
||||
<dataTrend :trendData="trendData" :title="'数据趋势'" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,8 +110,7 @@ export default {
|
||||
relatedMon: {},
|
||||
relatedTotal: {},
|
||||
totalData: {},
|
||||
trendData: [],
|
||||
trend: [],
|
||||
trendData: {},
|
||||
paramList: ['单价', '运费'],
|
||||
};
|
||||
},
|
||||
@@ -209,17 +208,7 @@ export default {
|
||||
this.totalData = res.data.totalData
|
||||
this.relatedMon = res.data.relatedMon
|
||||
this.relatedTotal = res.data.relatedTotal
|
||||
this.trend = res.data.trend
|
||||
// this.cusProData = {
|
||||
// customerPriceMon: res.data.customerPriceMon,
|
||||
// customerPriceTotal: res.data.customerPriceTotal,
|
||||
// customerSaleMon: res.data.customerSaleMon,
|
||||
// customerSaleTotal: res.data.customerSaleTotal,
|
||||
// productMonSale: res.data.productMonSale,
|
||||
// productPriceMon: res.data.productPriceMon,
|
||||
// productPriceTotal: res.data.productPriceTotal,
|
||||
// productTotalSale: res.data.productTotalSale,
|
||||
// }
|
||||
this.trendData = res.data.trend
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
@@ -5,35 +5,20 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<!-- 新增:topItem 专属包裹容器,统一控制样式和布局 -->
|
||||
<div class="topItem-container" style="display: flex; gap: 8px;">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/unitPriceAnalysis/unitPriceAnalysisBase')">
|
||||
<div
|
||||
v-for="item in sortedIndicators"
|
||||
:key="item.key"
|
||||
class="dashboard"
|
||||
@click="item.route && handleDashboardClick(item.route)"
|
||||
>
|
||||
<div class="title">
|
||||
单价·万㎡
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedMon.单价.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedMon.单价 || defaultData).completeRate, (relatedMon.单价 || defaultData).real, (relatedMon.单价 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedMon.单价.diff}}</span></span>
|
||||
</div>
|
||||
<div class="line">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedMon.单价 || defaultData),
|
||||
flag: getRateFlag((relatedMon.单价 || defaultData).completeRate, (relatedMon.单价 || defaultData).real, (relatedMon.单价 || defaultData).target)
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard right">
|
||||
<div class="title">
|
||||
运费·万元
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedMon.运费.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedMon.运费 || defaultData).completeRate, (relatedMon.运费 || defaultData).real, (relatedMon.运费 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedMon.运费.diff}}</span></span>
|
||||
</div>
|
||||
<div class="line">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedMon.运费 || defaultData),
|
||||
flag: getRateFlag((relatedMon.运费 || defaultData).completeRate, (relatedMon.运费 || defaultData).real, (relatedMon.运费 || defaultData).target)
|
||||
}" />
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
<operatingSingleBar :detailData="item.detailData"></operatingSingleBar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,6 +69,54 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'djData', name: '单价', unit: '元/㎡', route:'/unitPriceAnalysis/unitPriceAnalysisBase'},
|
||||
{ key: 'yfData', name: '运费', unit: '元/㎡',route:null}
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
let _this = this
|
||||
const fallback = { target: 0, real: 0, completeRate: 0, diff: 0, flag: 0 }
|
||||
const list = Object.entries(_this.relatedMon).map(([title, data]) => {
|
||||
return {
|
||||
title: title,
|
||||
target: data.target,
|
||||
real: data.real,
|
||||
completeRate: data.completeRate,
|
||||
diff: data.diff
|
||||
};
|
||||
});
|
||||
return _this.indicatorDefs.map(def => {
|
||||
const data = list.find(item => item && item.title === def.name) || fallback
|
||||
const detailData = {
|
||||
...data,
|
||||
flag: _this.getRateFlag((data || _this.defaultData).completeRate, (data || _this.defaultData).real, (data || _this.defaultData).target),
|
||||
}
|
||||
return {
|
||||
...def,
|
||||
detailData,
|
||||
sortValue: Number((data && data.real) ?? 0)
|
||||
}
|
||||
})
|
||||
},
|
||||
sortedIndicators() {
|
||||
const unitOrder = ['万㎡','元/㎡']
|
||||
const unitRank = (u) => {
|
||||
const idx = unitOrder.indexOf(u)
|
||||
return idx === -1 ? 999 : idx
|
||||
}
|
||||
|
||||
return this.indicators.slice().sort((a, b) => {
|
||||
const ur = unitRank(a.unit) - unitRank(b.unit)
|
||||
if (ur !== 0) return ur
|
||||
const vr = (b.sortValue ?? -Infinity) - (a.sortValue ?? -Infinity)
|
||||
if (vr !== 0) return vr
|
||||
return String(a.key).localeCompare(String(b.key))
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
relatedMon: {
|
||||
handler(newValue) {
|
||||
|
||||
@@ -168,7 +168,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '元',
|
||||
name: '元/㎡',
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -112,7 +112,7 @@ export default {
|
||||
// 左侧Y轴:营业收入、成本(单位万元)
|
||||
{
|
||||
type: 'value',
|
||||
name: '元',
|
||||
name: '元/㎡',
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -5,35 +5,20 @@
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<!-- 新增:topItem 专属包裹容器,统一控制样式和布局 -->
|
||||
<div class="topItem-container" style="display: flex; gap: 8px;">
|
||||
<div class="dashboard left" @click="handleDashboardClick('/unitPriceAnalysis/unitPriceAnalysisBase')">
|
||||
<div
|
||||
v-for="item in sortedIndicators"
|
||||
:key="item.key"
|
||||
class="dashboard"
|
||||
@click="item.route && handleDashboardClick(item.route)"
|
||||
>
|
||||
<div class="title">
|
||||
单价·万㎡
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedTotal.单价.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedTotal.单价 || defaultData).completeRate, (relatedTotal.单价 || defaultData).real, (relatedTotal.单价 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedTotal.单价.diff}}</span></span>
|
||||
</div>
|
||||
<div class="line">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedTotal.单价 || defaultData),
|
||||
flag: getRateFlag((relatedTotal.单价 || defaultData).completeRate, (relatedTotal.单价 || defaultData).real, (relatedTotal.单价 || defaultData).target)
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard right">
|
||||
<div class="title">
|
||||
运费·万元
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedTotal.运费.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedTotal.运费 || defaultData).completeRate, (relatedTotal.运费 || defaultData).real, (relatedTotal.运费 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedTotal.运费.diff}}</span></span>
|
||||
</div>
|
||||
<div class="line">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedTotal.运费 || defaultData),
|
||||
flag: getRateFlag((relatedTotal.运费 || defaultData).completeRate, (relatedTotal.运费 || defaultData).real, (relatedTotal.运费 || defaultData).target)
|
||||
}" />
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
<operatingSingleBar :detailData="item.detailData"></operatingSingleBar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,6 +69,54 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'djData', name: '单价', unit: '元/㎡', route:'/unitPriceAnalysis/unitPriceAnalysisBase'},
|
||||
{ key: 'yfData', name: '运费', unit: '元/㎡',route:null}
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
let _this = this
|
||||
const fallback = { target: 0, real: 0, completeRate: 0, diff: 0, flag: 0 }
|
||||
const list = Object.entries(_this.relatedTotal).map(([title, data]) => {
|
||||
return {
|
||||
title: title,
|
||||
target: data.target,
|
||||
real: data.real,
|
||||
completeRate: data.completeRate,
|
||||
diff: data.diff
|
||||
};
|
||||
});
|
||||
return _this.indicatorDefs.map(def => {
|
||||
const data = list.find(item => item && item.title === def.name) || fallback
|
||||
const detailData = {
|
||||
...data,
|
||||
flag: _this.getRateFlag((data || _this.defaultData).completeRate, (data || _this.defaultData).real, (data || _this.defaultData).target),
|
||||
}
|
||||
return {
|
||||
...def,
|
||||
detailData,
|
||||
sortValue: Number((data && data.real) ?? 0)
|
||||
}
|
||||
})
|
||||
},
|
||||
sortedIndicators() {
|
||||
const unitOrder = ['万㎡','元/㎡']
|
||||
const unitRank = (u) => {
|
||||
const idx = unitOrder.indexOf(u)
|
||||
return idx === -1 ? 999 : idx
|
||||
}
|
||||
|
||||
return this.indicators.slice().sort((a, b) => {
|
||||
const ur = unitRank(a.unit) - unitRank(b.unit)
|
||||
if (ur !== 0) return ur
|
||||
const vr = (b.sortValue ?? -Infinity) - (a.sortValue ?? -Infinity)
|
||||
if (vr !== 0) return vr
|
||||
return String(a.key).localeCompare(String(b.key))
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
relatedTotal: {
|
||||
handler(newValue) {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,16 +63,14 @@ export default {
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '营业收入', // 选中的名称,初始为null
|
||||
profitOptions: [
|
||||
'营业收入',
|
||||
'单价',
|
||||
'销量',
|
||||
]
|
||||
{name:'营业收入',unit:'万元'},
|
||||
{name:'单价',unit:'元/㎡'},
|
||||
{name:'销量',unit:'万㎡'},
|
||||
],
|
||||
unit:'万元'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// profitOptions() {
|
||||
// return this.categoryData.map(item => item.name) || [];
|
||||
// },
|
||||
currentDataSource() {
|
||||
console.log('yyyy', this.chartData);
|
||||
|
||||
@@ -90,6 +88,7 @@ export default {
|
||||
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit: this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -251,9 +250,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.unit = item.unit;
|
||||
this.isDropdownShow = false;
|
||||
this.$emit("changeItem", item);
|
||||
this.$emit("changeItem", item.name);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -123,6 +123,7 @@ export default {
|
||||
const data = this.currentDataSource;
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:'万元',
|
||||
series: [
|
||||
// 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -122,7 +122,7 @@ export default {
|
||||
return; // 实例未初始化则返回
|
||||
}
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
const { allPlaceNames, unit, series } = this.chartData || {};
|
||||
const xData = allPlaceNames || [];
|
||||
const chartSeries = series || [];
|
||||
|
||||
@@ -169,13 +169,12 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '万元',
|
||||
name: unit,
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
align: 'right'
|
||||
},
|
||||
min:1000,
|
||||
splitNumber: 4,
|
||||
axisTick: { show: false },
|
||||
axisLabel: {
|
||||
|
||||
@@ -68,7 +68,6 @@ import screenfull from "screenfull";
|
||||
import changeBase from "../components/changeBase.vue";
|
||||
import monthlyOverview from "../operatingProfitComponents/monthlyOverview.vue";
|
||||
import totalOverview from "../operatingProfitComponents/totalOverview.vue";
|
||||
// import totalOverview from "../operatingComponents/totalOverview.vue";
|
||||
import relatedIndicatorsAnalysis from "../operatingProfitComponents/relatedIndicatorsAnalysis.vue";
|
||||
import dataTrend from "../operatingProfitComponents/dataTrend.vue";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,20 +62,18 @@ export default {
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '经营性利润', // 选中的名称,初始为null
|
||||
profitOptions: [
|
||||
'经营性利润',
|
||||
'销量',
|
||||
'单价',
|
||||
'制造成本',
|
||||
'管理费用',
|
||||
'销售费用',
|
||||
'财务费用',
|
||||
]
|
||||
{name:'经营性利润',unit:'万元'},
|
||||
{name:'销量',unit:'万㎡'},
|
||||
{name:'单价',unit:'元/㎡'},
|
||||
{name:'制造成本',unit:'元/㎡'},
|
||||
{name:'管理费用',unit:'万元'},
|
||||
{name:'销售费用',unit:'万元'},
|
||||
{name:'财务费用',unit:'万元'},
|
||||
],
|
||||
unit:'万元'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// profitOptions() {
|
||||
// return this.categoryData.map(item => item.name) || [];
|
||||
// },
|
||||
currentDataSource() {
|
||||
return this.chartData
|
||||
},
|
||||
@@ -91,6 +89,7 @@ export default {
|
||||
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit: this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -249,9 +248,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.unit = item.unit;
|
||||
this.isDropdownShow = false;
|
||||
this.$emit('handleGetItemData',item)
|
||||
this.$emit('handleGetItemData',item.name)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -123,6 +123,7 @@ export default {
|
||||
const data = this.currentDataSource;
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:'万元',
|
||||
series: [
|
||||
// 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -123,7 +123,7 @@ export default {
|
||||
return; // 实例未初始化则返回
|
||||
}
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
const { allPlaceNames, unit, series } = this.chartData || {};
|
||||
const xData = allPlaceNames || [];
|
||||
const chartSeries = series || [];
|
||||
|
||||
@@ -170,7 +170,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '万元',
|
||||
name: unit,
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
@@ -55,7 +55,8 @@ export default {
|
||||
return {
|
||||
chart: null,
|
||||
// 核心:当前激活的数据集(月度/累计),默认初始化月度数据
|
||||
activeData: this.relatedData.relatedMon || []
|
||||
activeData: this.relatedData.relatedMon || [],
|
||||
currentTab: 'month'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -102,7 +103,12 @@ export default {
|
||||
// 可选:监听 relatedData 初始变化(若父组件异步传递数据,确保 activeData 同步更新)
|
||||
relatedData: {
|
||||
handler(newVal) {
|
||||
if (this.currentTab === 'month') {
|
||||
this.activeData = newVal.relatedMon || [];
|
||||
}else{
|
||||
this.activeData = newVal.relatedTotal || [];
|
||||
}
|
||||
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
@@ -127,6 +133,7 @@ export default {
|
||||
*/
|
||||
handleChange(value) {
|
||||
console.log('Tab 切换值:', value);
|
||||
this.currentTab = value;
|
||||
// 根据 Tab 值更新当前激活的数据集
|
||||
if (value === 'month') {
|
||||
// 切换为月度数据
|
||||
|
||||
@@ -68,7 +68,7 @@ export default {
|
||||
*/
|
||||
factoryData() { // 整合原始数据 + 计算flag
|
||||
return {
|
||||
completeRate: Number(this.totalData.proportion),
|
||||
completeRate: this.totalData.proportion ? Number(this.totalData.proportion) : 0,
|
||||
diff: this.totalData.diffValue,
|
||||
real: this.totalData.value,
|
||||
target: this.totalData.targetValue,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -63,7 +63,8 @@ export default {
|
||||
real: 0,
|
||||
target: 0,
|
||||
thb: 0
|
||||
}
|
||||
},
|
||||
currentTab:'month',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -121,7 +122,11 @@ export default {
|
||||
// 监听 relatedData 变化(异步加载场景),同步更新月度数据
|
||||
relatedData: {
|
||||
handler(newVal) {
|
||||
if (this.currentTab === 'month') {
|
||||
this.relatedDetailData = newVal.relatedMon || {};
|
||||
}else{
|
||||
this.relatedDetailData = newVal.relatedTotal || {};
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
@@ -156,6 +161,7 @@ export default {
|
||||
},
|
||||
handleChange(value) {
|
||||
console.log('value', value, this.relatedData);
|
||||
this.currentTab = value;
|
||||
if (value === 'month') {
|
||||
this.relatedDetailData = this.relatedData.relatedMon || {};
|
||||
} else {
|
||||
|
||||
@@ -60,7 +60,7 @@ import monthlyOverview from "../productionCostAnalysisComponents/monthlyOverview
|
||||
import totalOverview from "../productionCostAnalysisComponents/totalOverview.vue";
|
||||
// import totalOverview from "../operatingComponents/totalOverview.vue";
|
||||
// import monthlyRelatedMetrics from "../procurementGainAnalysisComponents/monthlyRelatedMetrics.vue";
|
||||
import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingLabor.vue";
|
||||
import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingLabor2.vue";
|
||||
import { mapState } from "vuex";
|
||||
import { getSingleMaterialCostAnalysis } from '@/api/cockpit'
|
||||
// import PSDO from "./components/PSDO.vue";
|
||||
|
||||
@@ -60,7 +60,7 @@ import screenfull from "screenfull";
|
||||
import changeBase from "../components/changeBase.vue";
|
||||
import monthlyOverview from "../productionCostAnalysisComponents/monthlyOverview.vue";
|
||||
import totalOverview from "../productionCostAnalysisComponents/totalOverview.vue";
|
||||
import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingLabor.vue";
|
||||
import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingLabor2.vue";
|
||||
import { mapState } from "vuex";
|
||||
import { getSingleMaterialCostAnalysis } from '@/api/cockpit'
|
||||
// import PSDO from "./components/PSDO.vue";
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
<template>
|
||||
<div class="cockpitContainer" :class="['cockpitContainer__' + size]">
|
||||
<div class="content-top" :class="['content-top__' + topSize]">
|
||||
<!-- 使用 flex 容器包裹图标和文字,实现垂直居中 -->
|
||||
<div class="title-wrapper">
|
||||
<svg-icon class="title-icon" :icon-class="icon" />
|
||||
<span class="title-text">
|
||||
{{ name }}
|
||||
</span>
|
||||
<svg-icon icon-class="turn-data" style='font-size: 40px;margin-left: 60px;' @click='switchData'/>
|
||||
<div class="container-top" ref="containerTop">
|
||||
<!-- 左侧标题 -->
|
||||
<div class="content-top-left title-wrapper" @click="handleLeftClick"
|
||||
:style="{ opacity: isLeftTransparent ? 1 : 0.3 }" ref="leftTitleWrapper">
|
||||
<svg-icon class="title-icon" style="font-size: 32px; margin-left: 16px" :icon-class="icon" />
|
||||
<span class="title-text" ref="leftTitleText">{{ name }}</span>
|
||||
<span class="change-text left-change-text" v-if="!isLeftTransparent" ref="leftChangeText">点击切换</span>
|
||||
</div>
|
||||
<div v-show="this.name === '指标分析'" class="tab-group">
|
||||
|
||||
<!-- 右侧标题 -->
|
||||
<div class="content-top-right title-wrapper" v-if="nameTwo" @click="handleRightClick"
|
||||
:style="{ opacity: isRightTransparent ? 1 : 0.3 }" ref="rightTitleWrapper">
|
||||
<svg-icon class="title-icon" style="font-size: 32px; margin-left: 16px" :icon-class="iconTwo || icon" />
|
||||
<span class="title-text" ref="rightTitleText">{{ nameTwo }}</span>
|
||||
<span class="change-text right-change-text" v-if="!isRightTransparent" ref="rightChangeText">点击切换</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 左侧切换文字:动态定位 -->
|
||||
|
||||
<!-- 右侧切换文字:动态定位 -->
|
||||
|
||||
|
||||
<!-- Tab组:动态样式 + 点击事件 -->
|
||||
<div class="tab-group" v-if="isLeftTransparent">
|
||||
<!-- 月度Tab:点击切换状态,动态绑定样式 -->
|
||||
<div class="tab-item" :class="{ active: activeTab === 'month' }" @click="handleTabClick('month')">
|
||||
月度
|
||||
@@ -19,11 +34,9 @@
|
||||
累计
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cockpitContainer-body">
|
||||
<slot>
|
||||
<div class="test-body">something test....</div>
|
||||
</slot>
|
||||
|
||||
<div class="container-body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -32,16 +45,59 @@
|
||||
export default {
|
||||
name: 'Container',
|
||||
components: {},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['size', 'icon', 'topSize', 'isShowTab'],
|
||||
props: {
|
||||
name: { type: String, required: true },
|
||||
nameTwo: { type: String, required: false },
|
||||
size: { type: String, default: 'default' },
|
||||
icon: { type: String, default: '' },
|
||||
iconTwo: { type: String, default: '' },
|
||||
// 可选:父组件传入默认激活的Tab类型
|
||||
defaultTab: {
|
||||
type: String,
|
||||
default: 'month', // 默认激活月度
|
||||
validator: (val) => ['month', 'total'].includes(val)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'month', // 初始化激活的Tab(支持父组件传默认值)
|
||||
name:'指标分析',
|
||||
isLeftTransparent: true,
|
||||
isRightTransparent: false,
|
||||
activeTab: 'month', // 初始化激活的Tab(支持父组件传默认值
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
// 初始化定位
|
||||
// this.positionChangeText();
|
||||
// // 监听窗口大小变化,重新定位
|
||||
// window.addEventListener('resize', this.positionChangeText);
|
||||
},
|
||||
// updated() {
|
||||
// // 数据更新后重新定位(如标题文字变化)
|
||||
// this.positionChangeText();
|
||||
// },
|
||||
beforeDestroy() {
|
||||
// 移除监听
|
||||
// window.removeEventListener('resize', this.positionChangeText);
|
||||
},
|
||||
methods: {
|
||||
handleLeftClick() {
|
||||
this.isLeftTransparent = true;
|
||||
this.isRightTransparent = false;
|
||||
this.$emit('switchTab', '指标分析');
|
||||
// 切换后重新定位
|
||||
// this.$nextTick(() => this.positionChangeText());
|
||||
},
|
||||
handleRightClick() {
|
||||
this.isLeftTransparent = false;
|
||||
this.isRightTransparent = true;
|
||||
this.$emit('switchTab', '数据趋势');
|
||||
// 切换后重新定位
|
||||
// this.$nextTick(() => this.positionChangeText());
|
||||
},
|
||||
/**
|
||||
* Tab点击事件:切换状态 + 向父组件传值
|
||||
* @param {String} tabType - month(月度)/ total(累计)
|
||||
*/
|
||||
handleTabClick(tabType) {
|
||||
this.activeTab = tabType;
|
||||
// 向父组件派发Tab切换事件,传递当前选中的Tab类型
|
||||
@@ -49,48 +105,72 @@ export default {
|
||||
// 可选:同时传递更详细的信息(如标签名)
|
||||
// this.$emit('tabChange', { type: tabType, name: tabType === 'month' ? '月度' : '累计' });
|
||||
},
|
||||
switchData() {
|
||||
console.log('aaa')
|
||||
if (this.name === '数据趋势') {
|
||||
this.name = '指标分析';
|
||||
} else {
|
||||
this.name = '数据趋势';
|
||||
/**
|
||||
* 动态定位切换文字:紧跟标题文本后方
|
||||
*/
|
||||
positionChangeText() {
|
||||
// 1. 处理左侧切换文字
|
||||
const leftTitleText = this.$refs.leftTitleText;
|
||||
const leftChangeText = this.$refs.leftChangeText;
|
||||
if (leftTitleText && leftChangeText) {
|
||||
const { top, left, height } = leftTitleText.getBoundingClientRect();
|
||||
const containerTop = this.$refs.containerTop.getBoundingClientRect().top;
|
||||
// 计算相对于容器的位置
|
||||
leftChangeText.style.top = `${top - containerTop + (height - 17) / 2}px`; // 垂直居中
|
||||
leftChangeText.style.left = `${left - this.$refs.containerTop.getBoundingClientRect().left + leftTitleText.offsetWidth + 8}px`; // 标题右侧8px间距
|
||||
}
|
||||
|
||||
// 2. 处理右侧切换文字
|
||||
const rightTitleText = this.$refs.rightTitleText;
|
||||
const rightChangeText = this.$refs.rightChangeText;
|
||||
if (rightTitleText && rightChangeText) {
|
||||
const { top, left, height } = rightTitleText.getBoundingClientRect();
|
||||
const containerTop = this.$refs.containerTop.getBoundingClientRect().top;
|
||||
// 计算相对于容器的位置
|
||||
rightChangeText.style.top = `${top - containerTop + (height - 17) / 2}px`; // 垂直居中
|
||||
rightChangeText.style.left = `${left - this.$refs.containerTop.getBoundingClientRect().left + rightTitleText.offsetWidth + 8}px`; // 标题右侧8px间距
|
||||
}
|
||||
}
|
||||
this.$emit('dataChange', this.name);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.cockpitContainer {
|
||||
display: inline-block;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
padding: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
.content-top {
|
||||
.container-top {
|
||||
position: relative;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-top-left {
|
||||
width: 320px;
|
||||
height: 60px;
|
||||
background: #FFFFFF;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
z-index: 1;
|
||||
transition: opacity 0.3s ease; // 透明度过渡动画
|
||||
}
|
||||
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
/* 垂直居中关键属性 */
|
||||
height: 100%;
|
||||
/* 继承父容器高度,确保垂直居中范围 */
|
||||
gap: 8px; // 图标、标题间距
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
font-size: 30px;
|
||||
margin-right: 12px;
|
||||
margin-top: 4px;
|
||||
/* 图标和文字之间的间距 */
|
||||
flex-shrink: 0;
|
||||
/* 防止图标被压缩 */
|
||||
margin-left: 10px;
|
||||
flex-shrink: 0; // 防止图标被压缩
|
||||
}
|
||||
|
||||
.title-text {
|
||||
@@ -101,62 +181,80 @@ export default {
|
||||
letter-spacing: 3px;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
// 移除固定行高,避免影响垂直对齐
|
||||
// line-height: 60px;
|
||||
flex-shrink: 0; // 防止标题文字被压缩
|
||||
}
|
||||
|
||||
// width: 547px;
|
||||
// background: url(../../../assets/img/contentTopBasic.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
&__basic {
|
||||
// width: 547px;
|
||||
background: url(../../../assets/img/contentTopBasic.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
/* 左侧标题 - 左上角折现边框 */
|
||||
.content-top-left::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(277deg, rgba(255, 255, 255, 0), rgba(92, 140, 255, 1)) 1 1;
|
||||
clip-path: polygon(20px 0, 100% 0, 100% 100%, 0 100%, 0 20px);
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
&__middle {
|
||||
background: url(../../../assets/img/topTileMiddle.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
/* 左侧标题 - 左上角折现细节 */
|
||||
.content-top-left::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: #E1f0fd;
|
||||
border-top: 1px solid rgba(92, 140, 255, 1);
|
||||
border-left: 1px solid rgba(92, 140, 255, 1);
|
||||
transform: rotate(135deg) translate(-50%, -50%);
|
||||
transform-origin: top left;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
&__large {
|
||||
background: url(../../../assets/img/topTitleLargeBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
.content-top-right {
|
||||
width: 1300px;
|
||||
height: 60px;
|
||||
background:#FFFFFF;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0px;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s ease; // 透明度过渡动画
|
||||
}
|
||||
|
||||
&__KFAPTopTitle {
|
||||
background: url(../../../assets/img/KFAPTopTitle.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
/* 右侧标题 - 左上角折现边框 */
|
||||
.content-top-right::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(277deg, rgba(253, 255, 255, 0), rgba(92, 140, 255, 1)) 1 1;
|
||||
clip-path: polygon(20px 0, 100% 0, 100% 100%, 0 100%, 0 20px);
|
||||
z-index: 12;
|
||||
}
|
||||
|
||||
&__psiTopTitleBasic {
|
||||
background: url(../../../assets/img/psiTopTitleBasic.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__rawTopTitleLarge {
|
||||
background: url(../../../assets/img/rawTopTitleLarge.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__calendarTitleBg {
|
||||
background: url(../../../assets/img/calendarTitleBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__indicatorDetailsTitleBg {
|
||||
background: url(../../../assets/img/indicatorDetailsTitleBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
/* 右侧标题 - 左上角折现细节 */
|
||||
.content-top-right::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: #E1f0fd;
|
||||
border-top: 1px solid rgba(92, 140, 255, 1);
|
||||
border-left: 1px solid rgba(92, 140, 255, 1);
|
||||
transform: rotate(135deg) translate(-50%, -50%);
|
||||
transform-origin: top left;
|
||||
z-index: 12;
|
||||
}
|
||||
|
||||
&__topBasic {
|
||||
@@ -171,163 +269,50 @@ export default {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__operatingBasic {
|
||||
background: url(../../../assets/img/operating-basic.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__operatingLarge {
|
||||
background: url(../../../assets/img/operating-large.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__profitTopBasic {
|
||||
background: url(../../../assets/img/profitTopBasic.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__profitMiddleBasic {
|
||||
background: url(../../../assets/img/profitMiddleBasic.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__psiBasicBg {
|
||||
background: url(../../../assets/img/psiBasicBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__psiMiddleBg {
|
||||
background: url(../../../assets/img/psiMiddleBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__costBasicBg {
|
||||
background: url(../../../assets/img/costBasicBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__rawTopBg {
|
||||
background: url(../../../assets/img/rawTopBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__opLargeBg {
|
||||
background: url(../../../assets/img/opLargeBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__calendarBg {
|
||||
background: url(../../../assets/img/calendarBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
&__indicatorDetailsBg {
|
||||
background: url(../../../assets/img/indicatorDetailsBg.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
// &__left {
|
||||
// background: url(../../../../../../../assets/img/left.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__energyConsumption {
|
||||
// background: url(../../../../../../../assets/img/energyConsumption.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__left2 {
|
||||
// background: url(../../assets/left_2.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__left3 {
|
||||
// background: url(../../assets/left_3.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__mid2 {
|
||||
// background: url(../../assets/mid_2.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__mid3 {
|
||||
// background: url(../../assets/mid_3.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__right1 {
|
||||
// background: url(../../assets/right_1.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__right2 {
|
||||
// background: url(../../assets/right_2.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__right3 {
|
||||
// background: url(../../assets/right_3.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__weekRight2 {
|
||||
// background: url(../../assets/week_right_2.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__weekMidTop {
|
||||
// background: url(../../assets/week-mid-top.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
// &__weekMidMid {
|
||||
// background: url(../../assets/week-mid-mid.png) no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
// background-position: 0 0;
|
||||
// }
|
||||
|
||||
&::after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
// background: inherit;
|
||||
/* 设置模糊,不用 filter */
|
||||
backdrop-filter: blur(5px);
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
|
||||
.container-body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.test-body {
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
// 点击切换文字基础样式
|
||||
.change-text {
|
||||
position: absolute; // 绝对定位,脱离父容器透明度
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: #0B58FF !important; // 强制颜色,不受透明度影响
|
||||
line-height: 17px;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
z-index: 999; // 最高层级,防止被遮挡
|
||||
opacity: 1 !important; // 强制不透明
|
||||
margin-top: 2px; // 微调垂直对齐
|
||||
pointer-events: none; // 不影响标题点击事件
|
||||
}
|
||||
|
||||
// 左侧切换文字(可选:单独样式调整)
|
||||
.left-change-text {
|
||||
left: 70%;
|
||||
/* 若需要可添加单独样式 */
|
||||
}
|
||||
|
||||
// 右侧切换文字(可选:单独样式调整)
|
||||
.right-change-text {
|
||||
left: 18%;
|
||||
/* 若需要可添加单独样式 */
|
||||
}
|
||||
|
||||
.tab-group {
|
||||
display: inline-flex;
|
||||
position: absolute;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container :isShowTab="true" icon="cockpitItemIcon" size="opLargeBg" topSize="large" @tabChange="handleChange" @dataChange='dataChange'>
|
||||
<Container name="指标分析" nameTwo="数据趋势" icon="cockpitItemIcon" size="opLargeBg" @tabChange="handleChange" @switchTab='dataChange'>
|
||||
<div v-show='showRelated' style="padding: 14px 16px; width: 100%; gap: 16px">
|
||||
<div style="display: flex; gap: 8px;overflow: auto">
|
||||
<div
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container name="数据趋势" icon="cockpitItemIcon" size="opLargeBg" topSize="large">
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%; gap: 16px">
|
||||
<div class="right" style="
|
||||
height: 491px;
|
||||
display: flex;
|
||||
width: 1595px;
|
||||
background-color: rgba(249, 252, 255, 1);
|
||||
">
|
||||
<!-- 直接使用计算属性 chartData,无需手动更新 -->
|
||||
<dataTrendBar @handleGetItemData="getData" :chartData="chartData" />
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Container from "../components/container.vue";
|
||||
import dataTrendBar from "./dataTrendBarProcessingLabor.vue";
|
||||
export default {
|
||||
name: "ProductionStatus",
|
||||
components: { Container, dataTrendBar },
|
||||
props: {
|
||||
trendData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 移除:原 chartData 定义,改为计算属性
|
||||
};
|
||||
},
|
||||
// 移除:原 watch 监听配置,计算属性自动响应 trendData 变化
|
||||
computed: {
|
||||
/**
|
||||
* chartData 计算属性:自动响应 trendData 变化,格式化并提取各字段数组
|
||||
* @returns {Object} 包含6个独立数组的格式化数据
|
||||
*/
|
||||
chartData() {
|
||||
// 初始化6个独立数组
|
||||
const timeArr = []; // 格式化后的年月数组
|
||||
const valueArr = []; // 实际值数组
|
||||
const diffValueArr = []; // 差异值数组
|
||||
const targetValueArr = []; // 预算值数组
|
||||
const proportionArr = []; // 占比数组
|
||||
const completedArr = []; // 完成率数组
|
||||
|
||||
// 遍历传入的 trendData 数组(响应式依赖,变化时自动重算)
|
||||
this.trendData.forEach((item) => {
|
||||
// 1. 格式化时间并推入时间数组
|
||||
const yearMonth = this.formatTimeToYearMonth(item.time);
|
||||
timeArr.push(yearMonth);
|
||||
|
||||
// 2. 提取其他字段,兜底为0(防止null/undefined影响图表渲染)
|
||||
valueArr.push(item.value ?? 0);
|
||||
diffValueArr.push(item.diffValue ?? 0);
|
||||
targetValueArr.push(item.targetValue ?? 0);
|
||||
proportionArr.push(item.proportion ?? 0);
|
||||
completedArr.push(item.completed ?? 0);
|
||||
});
|
||||
|
||||
// 组装并返回格式化后的数据(结构与原一致)
|
||||
return {
|
||||
time: timeArr,
|
||||
value: valueArr,
|
||||
diffValue: diffValueArr,
|
||||
targetValue: targetValueArr,
|
||||
proportion: proportionArr,
|
||||
completed: completedArr,
|
||||
rawData: this.trendData, // 透传原始数据,方便子组件使用
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 格式化时间戳为年月格式(YYYY-MM)
|
||||
* @param {Number} timestamp 13位毫秒级时间戳
|
||||
* @returns {String} 格式化后的年月字符串(如:2025-10)
|
||||
*/
|
||||
formatTimeToYearMonth(timestamp) {
|
||||
if (!timestamp || isNaN(timestamp)) {
|
||||
return ""; // 容错:非有效时间戳返回空字符串
|
||||
}
|
||||
const date = new Date(timestamp);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0"); // 月份从0开始,补0至2位
|
||||
return `${year}-${month}`;
|
||||
},
|
||||
getData(value) {
|
||||
this.$emit('getData', value)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/* 原有样式保持不变 */
|
||||
.scroll-container {
|
||||
max-height: 210px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 10px 0;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
.proBarInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 8px 27px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.proBarInfoEqInfo {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.slot {
|
||||
width: 21px;
|
||||
height: 23px;
|
||||
background: rgba(0, 106, 205, 0.22);
|
||||
backdrop-filter: blur(1.5px);
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #68b5ff;
|
||||
line-height: 23px;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.eq-name {
|
||||
margin-left: 8px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #ffffff;
|
||||
line-height: 18px;
|
||||
letter-spacing: 1px;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.eqStatus {
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #ffffff;
|
||||
line-height: 18px;
|
||||
text-align: right;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.splitLine {
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
border: 1px solid #adadad;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.yield {
|
||||
height: 18px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #00ffff;
|
||||
line-height: 18px;
|
||||
text-align: right;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.proBarInfoEqInfoLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.proBarInfoEqInfoRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.proBarWrapper {
|
||||
position: relative;
|
||||
height: 10px;
|
||||
margin-top: 6px;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.proBarLine {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(65deg, rgba(82, 82, 82, 0) 0%, #acacac 100%);
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.proBarLineTop {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
background: linear-gradient(65deg,
|
||||
rgba(53, 223, 247, 0) 0%,
|
||||
rgba(54, 220, 246, 0.92) 92%,
|
||||
#36f6e5 100%,
|
||||
#37acf5 100%);
|
||||
border-radius: 5px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.chartImgBottom {
|
||||
position: absolute;
|
||||
bottom: 45px;
|
||||
left: 58px;
|
||||
}
|
||||
|
||||
.line {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 57px;
|
||||
bottom: 42px;
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background-color: #00e8ff;
|
||||
}
|
||||
</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>
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="title">
|
||||
电·万元
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{dianData.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:dianData.completed>0?'#30B590':'#FF9423'}" >{{dianData.diffValue}}</span></span>
|
||||
</div>
|
||||
@@ -21,7 +21,7 @@
|
||||
<div class="title">
|
||||
水·元/㎡
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{shuiData.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:shuiData.completed>0?'#30B590':'#FF9423'}" >{{shuiData.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="title">
|
||||
采购单价·元/度
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{unitPriceData.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:unitPriceData.completed>0?'#30B590':'#FF9423'}" >{{unitPriceData.diffValue}}</span></span>
|
||||
</div>
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class="title">
|
||||
产量·吨
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{productData.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:productData.completed>0?'#30B590':'#FF9423'}" >{{productData.diffValue}}</span></span>
|
||||
</div>
|
||||
@@ -34,7 +34,7 @@
|
||||
<div class="title">
|
||||
单耗·度/吨
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{unitHaoData.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:unitHaoData.completed>0?'#30B590':'#FF9423'}" >{{unitHaoData.diffValue}}</span></span>
|
||||
</div>
|
||||
@@ -46,7 +46,7 @@
|
||||
<div class="title">
|
||||
消耗量·度
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{haoNumData.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:haoNumData.completed>0?'#30B590':'#FF9423'}" >{{haoNumData.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="title">
|
||||
电·万元
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{dianData.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:dianData.completed>0?'#30B590':'#FF9423'}" >{{dianData.diffValue}}</span></span>
|
||||
</div>
|
||||
@@ -21,7 +21,7 @@
|
||||
<div class="title">
|
||||
水·元/㎡
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{shuiData.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:shuiData.completed>0?'#30B590':'#FF9423'}" >{{shuiData.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -35,10 +35,10 @@
|
||||
<div class="left-three" style="
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns: 804px 804px;
|
||||
grid-template-columns: 1624px;
|
||||
">
|
||||
<monthlyRelatedMetrics :monthAnalysis="monthAnalysis" :title="'月度·相关指标分析'" />
|
||||
<yearRelatedMetrics :ytdAnalysis="ytdAnalysis" :title="'累计·相关指标分析'" />
|
||||
<relatedIndicatorsAnalysis :dateData="dateData" :factory="factory" :relatedData="relatedData"
|
||||
:title="'相关指标分析'" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,9 +69,7 @@ import screenfull from "screenfull";
|
||||
import changeBase from "../components/changeBase.vue";
|
||||
import monthlyOverview from "../rawSheetYieldComponents/monthlyOverview.vue";
|
||||
import totalOverview from "../rawSheetYieldComponents/totalOverview.vue";
|
||||
// import totalOverview from "../operatingComponents/totalOverview.vue";
|
||||
import monthlyRelatedMetrics from "../rawSheetYieldComponents/monthlyRelatedMetrics.vue";
|
||||
import yearRelatedMetrics from "../rawSheetYieldComponents/yearRelatedMetrics.vue";
|
||||
import relatedIndicatorsAnalysis from "../rawSheetYieldComponents/relatedIndicatorsAnalysis.vue";
|
||||
import dataTrend from "../rawSheetYieldComponents/dataTrend.vue";
|
||||
|
||||
import profitLineChart from "../costComponents/profitLineChart.vue";
|
||||
@@ -95,8 +93,7 @@ export default {
|
||||
monthlyOverview,
|
||||
Sidebar,
|
||||
totalOverview,
|
||||
monthlyRelatedMetrics,
|
||||
yearRelatedMetrics,
|
||||
relatedIndicatorsAnalysis,
|
||||
dataTrend
|
||||
// psiLineChart
|
||||
},
|
||||
@@ -112,8 +109,7 @@ export default {
|
||||
index: '原片成品率',
|
||||
monthData: undefined,
|
||||
ytdData: undefined,
|
||||
monthAnalysis: [],
|
||||
ytdAnalysis: [],
|
||||
relatedData: {},
|
||||
trend: [],
|
||||
// trendData: [],
|
||||
// parentItemList: [
|
||||
@@ -213,11 +209,11 @@ export default {
|
||||
getSheetYieldFactoryData(requestParams).then((res) => {
|
||||
this.monthData = res.data.month
|
||||
this.ytdData = res.data.ytd
|
||||
this.monthAnalysis = res.data.monthAnalysis
|
||||
this.ytdAnalysis = res.data.ytdAnalysis
|
||||
this.trend = res.data.trend
|
||||
|
||||
// this.monthData = res.data.month
|
||||
this.relatedData = {
|
||||
relatedMon:res.data.monthAnalysis,
|
||||
relatedTotal:res.data.ytdAnalysis
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,16 +63,19 @@ export default {
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '原片成品率', // 选中的名称,初始为null
|
||||
profitOptions: [
|
||||
'原片成品率',
|
||||
'原片产量',
|
||||
'拉引量',
|
||||
]
|
||||
{name:'原片成品率',unit:'%'},
|
||||
{name:'拉引量',unit:'吨'},
|
||||
{name:'边损',unit:'㎡'},
|
||||
{name:'设备损失',unit:'㎡'},
|
||||
{name:'换机损失',unit:'㎡'},
|
||||
{name:'切割损失',unit:'㎡'},
|
||||
{name:'退火损失',unit:'㎡'},
|
||||
{name:'原片产量',unit:'㎡'}
|
||||
],
|
||||
unit:'%'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// profitOptions() {
|
||||
// return this.categoryData.map(item => item.name) || [];
|
||||
// },
|
||||
currentDataSource() {
|
||||
console.log('yyyy', this.chartData);
|
||||
|
||||
@@ -90,6 +93,7 @@ export default {
|
||||
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -251,9 +255,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.unit = item.unit;
|
||||
this.isDropdownShow = false;
|
||||
this.$emit("changeItem", item);
|
||||
this.$emit("changeItem", item.name);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.rate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -123,6 +123,7 @@ export default {
|
||||
const data = this.currentDataSource;
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:'%',
|
||||
series: [
|
||||
// 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -119,7 +119,7 @@ export default {
|
||||
return; // 实例未初始化则返回
|
||||
}
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
const { allPlaceNames, unit, series } = this.chartData || {};
|
||||
const xData = allPlaceNames || [];
|
||||
const chartSeries = series || [];
|
||||
|
||||
@@ -166,7 +166,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '%',
|
||||
name: unit,
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
<script>
|
||||
import operatingLineBarSaleSingle from './operatingLineBarSaleSingle.vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
export default {
|
||||
name: "Container",
|
||||
@@ -23,6 +22,7 @@ export default {
|
||||
chartD() {
|
||||
// 背景图片路径(若不需要可注释)
|
||||
// const bgImageUrl = require('@/assets/img/labelBg.png');
|
||||
console.log('detailData++++++++++++++++++++++', this.detailData);
|
||||
const rate = this.detailData?.rate || 0
|
||||
const diff = this.detailData?.diff || 0
|
||||
console.log('diff', diff);
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<div style="flex: 1">
|
||||
<Container :isShowTab="true" :name="title" icon="cockpitItemIcon" size="opLargeBg" topSize="large"
|
||||
@tabChange="handleChange">
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<div class="topItem-container" style="display: flex; gap: 8px">
|
||||
<div
|
||||
v-for="item in sortedIndicators"
|
||||
:key="item.key"
|
||||
class="dashboard"
|
||||
>
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.rate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.rate>0?'#30B590':'#FF9423'}" >{{item.data.diff}}</span></span>
|
||||
</div>
|
||||
<operatingSingleBar :detailData="item.data"></operatingSingleBar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Container from '../components/container.vue'
|
||||
import operatingSingleBar from './operatingSingleBar.vue'
|
||||
|
||||
// import * as echarts from 'echarts'
|
||||
// import rawItem from './raw-Item.vue'
|
||||
|
||||
export default {
|
||||
name: 'ProductionStatus',
|
||||
components: { Container, operatingSingleBar },
|
||||
props: {
|
||||
// 接收父组件传递的 月度+累计 组合数据
|
||||
relatedData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
relatedMon: [], // 月度数据(数组格式,存储销量/单价等数据)
|
||||
relatedTotal: [] // 累计数据(数组格式,存储销量/单价等数据)
|
||||
})
|
||||
},
|
||||
dateData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
factory: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
// 可选:动态标题
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
// 核心:当前激活的数据集(月度/累计),默认初始化月度数据
|
||||
activeData: this.relatedData.relatedMon || [],
|
||||
currentTab: 'month'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'yieldData', name: '原片产量', unit: '㎡'},
|
||||
{ key: 'pullData', name: '拉引量', unit: '吨'},
|
||||
{ key: 'eqData', name: '设备损失', unit: '㎡'},
|
||||
{ key: 'bianData', name: '边损', unit: '㎡'},
|
||||
{ key: 'huanData', name: '换机损失', unit: '㎡'},
|
||||
{ key: 'tuihuoData', name: '退火损失', unit: '㎡'},
|
||||
{ key: 'qiegeData', name: '切割损失', unit: '㎡'}
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
const fallback = { budget: 0, rate: 0, real:0, diff: 0 }
|
||||
const list = (Array.isArray(this.activeData) ? this.activeData : [])
|
||||
|
||||
return this.indicatorDefs.map(def => {
|
||||
const data = list.find(item => item && item.title === def.name) || fallback
|
||||
return {
|
||||
...def,
|
||||
data,
|
||||
sortValue: Number((data && data.real) ?? 0)
|
||||
}
|
||||
})
|
||||
},
|
||||
sortedIndicators() {
|
||||
const unitOrder = ['吨', '㎡']
|
||||
const unitRank = (u) => {
|
||||
const idx = unitOrder.indexOf(u)
|
||||
return idx === -1 ? 999 : idx
|
||||
}
|
||||
|
||||
return this.indicators.slice().sort((a, b) => {
|
||||
const ur = unitRank(a.unit) - unitRank(b.unit)
|
||||
if (ur !== 0) return ur
|
||||
const vr = (b.sortValue ?? -Infinity) - (a.sortValue ?? -Infinity)
|
||||
if (vr !== 0) return vr
|
||||
return String(a.key).localeCompare(String(b.key))
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 可选:监听 relatedData 初始变化(若父组件异步传递数据,确保 activeData 同步更新)
|
||||
relatedData: {
|
||||
handler(newVal) {
|
||||
if(this.currentTab === 'month') {
|
||||
this.activeData = newVal.relatedMon || [];
|
||||
}else{
|
||||
this.activeData = newVal.relatedTotal || [];
|
||||
}
|
||||
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log('组件挂载时的激活数据:', this.activeData);
|
||||
},
|
||||
methods: {
|
||||
handleDashboardClick(path) {
|
||||
this.$router.push({
|
||||
path: path,
|
||||
query: {
|
||||
factory: this.$route.query.factory ? this.$route.query.factory : this.factory,
|
||||
dateData: this.dateData
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* Tab 切换处理函数
|
||||
* @param {String} value 切换值('month' = 月度,'total' = 累计,可根据实际Tab值调整)
|
||||
*/
|
||||
handleChange(value) {
|
||||
console.log('Tab 切换值:', value);
|
||||
this.currentTab = value;
|
||||
// 根据 Tab 值更新当前激活的数据集
|
||||
if (value === 'month') {
|
||||
// 切换为月度数据
|
||||
this.activeData = this.relatedData.relatedMon || [];
|
||||
} else {
|
||||
// 切换为累计数据(非 month 均视为累计,可根据实际需求调整判断条件)
|
||||
this.activeData = this.relatedData.relatedTotal || [];
|
||||
}
|
||||
console.log('当前激活数据集:', this.activeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
/* 3. 核心:滚动容器样式(固定高度+溢出滚动+隐藏滚动条) */
|
||||
.scroll-container {
|
||||
/* 1. 固定容器高度:根据页面布局调整(示例300px,超出则滚动) */
|
||||
max-height: 210px;
|
||||
/* 2. 溢出滚动:内容超出高度时显示滚动功能 */
|
||||
overflow-y: auto;
|
||||
/* 3. 隐藏横向滚动条(防止设备名过长导致横向滚动) */
|
||||
overflow-x: hidden;
|
||||
/* 4. 内边距:与标题栏和容器边缘对齐 */
|
||||
padding: 10px 0;
|
||||
|
||||
/* 5. 隐藏滚动条(兼容主流浏览器) */
|
||||
/* Chrome/Safari */
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
scrollbar-width: none;
|
||||
/* IE/Edge */
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
width: 220px;
|
||||
height: 205px;
|
||||
background: #F9FCFF;
|
||||
padding: 16px 0 0 10px;
|
||||
|
||||
.title {
|
||||
// width: 190px;
|
||||
height: 18px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
color: #000000;
|
||||
line-height: 18px;
|
||||
letter-spacing: 1px;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
.number {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
// width: 190px;
|
||||
height: 32px;
|
||||
font-family: YouSheBiaoTiHei;
|
||||
font-size: 32px;
|
||||
color: #0B58FF;
|
||||
line-height: 32px;
|
||||
letter-spacing: 2px;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mom {
|
||||
width: 120px;
|
||||
height: 18px;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
color: #000000;
|
||||
line-height: 18px;
|
||||
letter-spacing: 1px;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.rate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,8 +63,18 @@ export default {
|
||||
return {
|
||||
activeButton: 0,
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '净价', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据
|
||||
profitOptions: ['净价', '单价', '产销率','双镀销量','双镀占比','溢价产品销量','溢价产品毛利']
|
||||
selectedProfit: '销量',
|
||||
profitOptions:[
|
||||
{name:'销量',unit:'万㎡'},
|
||||
{name:'净价',unit:'元/㎡'},
|
||||
{name:'单价',unit:'元/㎡'},
|
||||
{name:'产销率',unit:'%'},
|
||||
{name:'双镀销量',unit:'万㎡'},
|
||||
{name:'双镀占比',unit:'%'},
|
||||
{name:'溢价产品销量',unit:'万㎡'},
|
||||
{name:'溢价产品毛利',unit:'元'},
|
||||
],
|
||||
unit:'万㎡'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -126,6 +136,7 @@ export default {
|
||||
// 销量场景数据(保留原有结构,替换数据来源)
|
||||
const salesData = {
|
||||
allPlaceNames: months, // 优先用基地名称,无则用月份
|
||||
unit: this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -286,8 +297,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.isDropdownShow = false;
|
||||
this.unit = item.unit;
|
||||
},
|
||||
// 复用达标状态判断方法
|
||||
getRateFlag(rate, real, target) {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,8 +63,14 @@ export default {
|
||||
return {
|
||||
activeButton: 0,
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '双镀成本', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据
|
||||
profitOptions: ['双镀成本', '双镀均价', '双镀毛利']
|
||||
selectedProfit: '双镀销量',
|
||||
profitOptions:[
|
||||
{name:'双镀销量',unit:'万㎡'},
|
||||
{name:'双镀成本',unit:'元/㎡'},
|
||||
{name:'双镀均价',unit:'元/㎡'},
|
||||
{name:'双镀毛利',unit:'元'},
|
||||
],
|
||||
unit:'万㎡'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -128,6 +134,7 @@ export default {
|
||||
// 销量场景数据(保留原有结构,替换数据来源)
|
||||
const salesData = {
|
||||
allPlaceNames: months, // 优先用基地名称,无则用月份
|
||||
unit: this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -286,8 +293,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.isDropdownShow = false;
|
||||
this.unit = item.unit;
|
||||
},
|
||||
// 复用达标状态判断方法
|
||||
getRateFlag(rate) {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,8 +63,13 @@ export default {
|
||||
return {
|
||||
activeButton: 0,
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '产量(深加工)', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据
|
||||
profitOptions: ['产量(深加工)', '销量']
|
||||
selectedProfit: '产销率',
|
||||
profitOptions:[
|
||||
{name:'产销率',unit:'%'},
|
||||
{name:'销量',unit:'万㎡'},
|
||||
{name:'产量(深加工)',unit:'㎡'},
|
||||
],
|
||||
unit:'%',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -128,6 +133,7 @@ export default {
|
||||
// 销量场景数据(保留原有结构,替换数据来源)
|
||||
const salesData = {
|
||||
allPlaceNames: months, // 优先用基地名称,无则用月份
|
||||
unit: this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -286,8 +292,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.isDropdownShow = false;
|
||||
this.unit = item.unit;
|
||||
},
|
||||
// 复用达标状态判断方法
|
||||
getRateFlag(rate) {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -61,7 +61,7 @@ export default {
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'production', name: '产量', unit: '万㎡'},
|
||||
{ key: 'production', name: '产量', unit: '㎡'},
|
||||
{ key: 'financialCost', name: '销量', unit: '万㎡'},
|
||||
]
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -63,7 +63,7 @@ export default {
|
||||
return [
|
||||
{ key: 'financialCost', name: '双镀成本', unit: '元/㎡'},
|
||||
{ key: 'financialPrice', name: '双镀均价', unit: '元/㎡'},
|
||||
{ key: 'financialProfit', name: '双镀毛利', unit: '万元'},
|
||||
{ key: 'financialProfit', name: '双镀毛利', unit: '元'},
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
|
||||
@@ -123,6 +123,7 @@ export default {
|
||||
const data = this.currentDataSource;
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:'万㎡',
|
||||
series: [
|
||||
// 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -122,7 +122,7 @@ export default {
|
||||
return; // 实例未初始化则返回
|
||||
}
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
const { allPlaceNames, unit, series } = this.chartData || {};
|
||||
const xData = allPlaceNames || [];
|
||||
const chartSeries = series || [];
|
||||
|
||||
@@ -169,7 +169,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '万m2',
|
||||
name: unit,
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -69,13 +69,13 @@ export default {
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'netPrice', name: '净价', unit: '万㎡', route:'/netPriceAnalysis/netPriceAnalysisBase'},
|
||||
{ key: 'netPrice', name: '净价', unit: '元/㎡', route:'/netPriceAnalysis/netPriceAnalysisBase'},
|
||||
{ key: 'unitPrice', name: '单价', unit: '元/㎡',route:'/unitPriceAnalysis/unitPriceAnalysisBase' },
|
||||
{ key: 'productionSales', name: '产销率', unit: '%',route:'/salesVolumeAnalysis/productionSalesBase'},
|
||||
{ key: 'manageCost', name: '双镀销量', unit: '万㎡',route:'/salesVolumeAnalysis/doublePlatedBase' },
|
||||
{ key: 'freight', name: '双镀占比', unit: '%',route:'/salesVolumeAnalysis/doublePlatedBase' },
|
||||
{ key: 'manageCost', name: '溢价产品销量', unit: '万㎡',route:null },
|
||||
{ key: 'premiumProducts', name: '溢价产品毛利', unit: '万元',route:null },
|
||||
{ key: 'premiumProducts', name: '溢价产品毛利', unit: '元',route:null },
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
@@ -104,7 +104,7 @@ export default {
|
||||
})
|
||||
},
|
||||
sortedIndicators() {
|
||||
const unitOrder = ['万㎡', '元/㎡', '%','万元']
|
||||
const unitOrder = ['万㎡', '元/㎡', '%','万元','元']
|
||||
const unitRank = (u) => {
|
||||
const idx = unitOrder.indexOf(u)
|
||||
return idx === -1 ? 999 : idx
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -25,7 +25,6 @@
|
||||
<script>
|
||||
import Container from './container.vue'
|
||||
import operatingSingleBar from './operatingSingleBar.vue'
|
||||
import verticalBarChart from './verticalBarChart.vue'
|
||||
|
||||
// import * as echarts from 'echarts'
|
||||
// import rawItem from './raw-Item.vue'
|
||||
@@ -62,7 +61,7 @@ export default {
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'production', name: '产量', unit: '万㎡'},
|
||||
{ key: 'production', name: '产量', unit: '㎡'},
|
||||
{ key: 'financialCost', name: '销量', unit: '万㎡'},
|
||||
]
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
@@ -66,7 +66,7 @@ export default {
|
||||
return [
|
||||
{ key: 'financialCost', name: '双镀成本', unit: '元/㎡'},
|
||||
{ key: 'financialPrice', name: '双镀均价', unit: '元/㎡'},
|
||||
{ key: 'financialProfit', name: '双镀毛利', unit: '万元'},
|
||||
{ key: 'financialProfit', name: '双镀毛利', unit: '元'},
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
|
||||
@@ -107,7 +107,7 @@ export default {
|
||||
monData: {},
|
||||
totalData: {},
|
||||
trend: [],
|
||||
relatedData: [],
|
||||
relatedData: {},
|
||||
trendName: '利润总额',
|
||||
// cusProData: {},
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="dropdown-options" v-if="isDropdownShow">
|
||||
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
|
||||
@click.stop="selectProfit(item)">
|
||||
{{ item }}
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,15 +62,16 @@ export default {
|
||||
isDropdownShow: false,
|
||||
selectedProfit: '利润总额', // 选中的名称,初始为null
|
||||
profitOptions: [
|
||||
'利润总额',
|
||||
'销量',
|
||||
'单价',
|
||||
'制造成本',
|
||||
'管理费用',
|
||||
'销售费用',
|
||||
'财务费用',
|
||||
'非经营性利润',
|
||||
]
|
||||
{name:'利润总额',unit:'万元'},
|
||||
{name:'销量',unit:'万㎡'},
|
||||
{name:'单价',unit:'元/㎡'},
|
||||
{name:'制造成本',unit:'元/㎡'},
|
||||
{name:'管理费用',unit:'万元'},
|
||||
{name:'销售费用',unit:'万元'},
|
||||
{name:'财务费用',unit:'万元'},
|
||||
{name:'非经营性利润',unit:'万元'}
|
||||
],
|
||||
unit:'万元'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -92,6 +93,7 @@ export default {
|
||||
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:this.unit,
|
||||
series: [
|
||||
// 1. 完成率(折线图)
|
||||
{
|
||||
@@ -250,9 +252,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectProfit(item) {
|
||||
this.selectedProfit = item;
|
||||
this.selectedProfit = item.name;
|
||||
this.unit = item.unit;
|
||||
this.isDropdownShow = false;
|
||||
this.$emit('handleGetItemData', item)
|
||||
this.$emit('handleGetItemData', item.name)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -123,6 +123,7 @@ export default {
|
||||
const data = this.currentDataSource;
|
||||
const salesData = {
|
||||
allPlaceNames: this.locations,
|
||||
unit:'万元',
|
||||
series: [
|
||||
// 完成率(折线图)
|
||||
{
|
||||
|
||||
@@ -119,7 +119,7 @@ export default {
|
||||
return; // 实例未初始化则返回
|
||||
}
|
||||
|
||||
const { allPlaceNames, series } = this.chartData || {};
|
||||
const { allPlaceNames, unit, series } = this.chartData || {};
|
||||
const xData = allPlaceNames || [];
|
||||
const chartSeries = series || [];
|
||||
|
||||
@@ -166,7 +166,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '万元',
|
||||
name: unit,
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="title">
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.data.proportion}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
|
||||
</div>
|
||||
@@ -61,7 +61,8 @@ export default {
|
||||
return {
|
||||
chart: null,
|
||||
// 核心:当前激活的数据集(月度/累计),默认初始化月度数据
|
||||
activeData: this.relatedData.relatedMon || []
|
||||
activeData: this.relatedData.relatedMon || [],
|
||||
currentTab: 'month'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -109,7 +110,12 @@ export default {
|
||||
// 可选:监听 relatedData 初始变化(若父组件异步传递数据,确保 activeData 同步更新)
|
||||
relatedData: {
|
||||
handler(newVal) {
|
||||
if (this.currentTab === 'month') {
|
||||
this.activeData = newVal.relatedMon || [];
|
||||
}else{
|
||||
this.activeData = newVal.relatedTotal || [];
|
||||
}
|
||||
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
@@ -134,6 +140,7 @@ export default {
|
||||
*/
|
||||
handleChange(value) {
|
||||
console.log('Tab 切换值:', value);
|
||||
this.currentTab = value;
|
||||
// 根据 Tab 值更新当前激活的数据集
|
||||
if (value === 'month') {
|
||||
// 切换为月度数据
|
||||
|
||||
@@ -3,54 +3,20 @@
|
||||
<Container :name="title" icon="cockpitItemIcon" size="operatingRevenueBg" topSize="middle">
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<div class="topItem-container" style="display: flex; gap: 8px;">
|
||||
<!-- 销量图表:传递销量数据 + 完成率flag -->
|
||||
<div class="dashboard left" @click="handleDashboardClick('/salesVolumeAnalysis/salesVolumeAnalysisBase')">
|
||||
<div
|
||||
v-for="item in sortedIndicators"
|
||||
:key="item.key"
|
||||
class="dashboard"
|
||||
@click="item.route && handleDashboardClick(item.route)"
|
||||
>
|
||||
<div class="title">
|
||||
销量·万㎡
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedMon.销量.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedMon.销量 || defaultData).completeRate, (relatedMon.销量 || defaultData).real, (relatedMon.销量 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedMon.销量.diff}}</span></span>
|
||||
</div>
|
||||
<div class="chart-wrap">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedMon.销量 || defaultData),
|
||||
flag: getRateFlag((relatedMon.销量 || defaultData).completeRate, (relatedMon.销量 || defaultData).real, (relatedMon.销量 || defaultData).target,)
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 成本图表:传递全成本数据 + 完成率flag -->
|
||||
<div class="dashboard right" @click="handleDashboardClick('/fullCostAnalysis/fullCostAnalysisBase')">
|
||||
<div class="title">
|
||||
成本·元/㎡
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedMon.全成本.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedMon.全成本 || defaultData).completeRate, (relatedMon.全成本 || defaultData).real, (relatedMon.全成本 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedMon.全成本.diff}}</span></span>
|
||||
</div>
|
||||
<div class="chart-wrap">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedMon.全成本 || defaultData),
|
||||
flag: getRateFlag((relatedMon.全成本 || defaultData).completeRate, (relatedMon.全成本 || defaultData).real, (relatedMon.全成本 || defaultData).target)
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 运费图表:传递单价数据 + 完成率flag -->
|
||||
<div class="dashboard right">
|
||||
<div class="title">
|
||||
运费·万元
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedMon.运费.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedMon.运费 || defaultData).completeRate, (relatedMon.运费 || defaultData).real, (relatedMon.运费 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedMon.运费.diff}}</span></span>
|
||||
</div>
|
||||
<div class="chart-wrap">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedMon.运费 || defaultData),
|
||||
flag: getRateFlag((relatedMon.运费 || defaultData).completeRate, (relatedMon.运费 || defaultData).real, (relatedMon.运费 || defaultData).target)
|
||||
}" />
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
<operatingSingleBar :detailData="item.detailData"></operatingSingleBar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,7 +35,7 @@ export default {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
运费: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 },
|
||||
成本: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 },
|
||||
全成本: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 },
|
||||
销量: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 }
|
||||
})
|
||||
},
|
||||
@@ -99,6 +65,55 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'saleData', name: '销量', unit: '万㎡', route:'/salesVolumeAnalysis/salesVolumeAnalysisBase'},
|
||||
{ key: 'cbData', name: '全成本', unit: '元/㎡',route:'/fullCostAnalysis/fullCostAnalysisBase'},
|
||||
{ key: 'yfData', name: '运费', unit: '元/㎡',route:null}
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
let _this = this
|
||||
const fallback = { target: 0, real: 0, completeRate: 0, diff: 0, flag: 0 }
|
||||
const list = Object.entries(_this.relatedMon).map(([title, data]) => {
|
||||
return {
|
||||
title: title,
|
||||
target: data.target,
|
||||
real: data.real,
|
||||
completeRate: data.completeRate,
|
||||
diff: data.diff
|
||||
};
|
||||
});
|
||||
return _this.indicatorDefs.map(def => {
|
||||
const data = list.find(item => item && item.title === def.name) || fallback
|
||||
const detailData = {
|
||||
...data,
|
||||
flag: _this.getRateFlag((data || _this.defaultData).completeRate, (data || _this.defaultData).real, (data || _this.defaultData).target),
|
||||
}
|
||||
return {
|
||||
...def,
|
||||
detailData,
|
||||
sortValue: Number((data && data.real) ?? 0)
|
||||
}
|
||||
})
|
||||
},
|
||||
sortedIndicators() {
|
||||
const unitOrder = ['万㎡','元/㎡']
|
||||
const unitRank = (u) => {
|
||||
const idx = unitOrder.indexOf(u)
|
||||
return idx === -1 ? 999 : idx
|
||||
}
|
||||
|
||||
return this.indicators.slice().sort((a, b) => {
|
||||
const ur = unitRank(a.unit) - unitRank(b.unit)
|
||||
if (ur !== 0) return ur
|
||||
const vr = (b.sortValue ?? -Infinity) - (a.sortValue ?? -Infinity)
|
||||
if (vr !== 0) return vr
|
||||
return String(a.key).localeCompare(String(b.key))
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
relatedMon: {
|
||||
handler(newValue) {
|
||||
|
||||
@@ -168,7 +168,7 @@ export default {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '元',
|
||||
name: '元/㎡',
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -112,7 +112,7 @@ export default {
|
||||
// 左侧Y轴:营业收入、成本(单位万元)
|
||||
{
|
||||
type: 'value',
|
||||
name: '元',
|
||||
name: '元/㎡',
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
fontSize: 12,
|
||||
|
||||
@@ -66,27 +66,11 @@ export default {
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
// axisPointer: {
|
||||
// type: 'cross',
|
||||
// label: {
|
||||
// backgroundColor: '#6a7985'
|
||||
// }
|
||||
// },
|
||||
// formatter: (params) => {
|
||||
// let html = `${params[0].axisValue}<br/>`;
|
||||
// params.forEach(item => {
|
||||
// const unit = item.seriesName === '完成率' ? '%' : (
|
||||
// ['产量', '销量'].includes(this.$parent.selectedProfit) ? '片' : '万元'
|
||||
// );
|
||||
// html += `${item.marker} ${item.seriesName}: ${item.value}${unit}<br/>`;
|
||||
// });
|
||||
// return html;
|
||||
// }
|
||||
},
|
||||
grid: {
|
||||
top: 25,
|
||||
bottom: 25,
|
||||
right: 0,
|
||||
right: 5,
|
||||
left: 2,
|
||||
containLabel: true
|
||||
},
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
<script>
|
||||
import operatingLineBarSaleSingle from './operatingLineBarSaleSingle.vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
export default {
|
||||
name: "Container",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
<script>
|
||||
import operatingLineBar from './operatingLineBarSaleGroup.vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
export default {
|
||||
name: "Container",
|
||||
|
||||
@@ -3,53 +3,20 @@
|
||||
<Container :name="title" icon="cockpitItemIcon" size="operatingRevenueBg" topSize="middle">
|
||||
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
|
||||
<div class="topItem-container" style="display: flex; gap: 8px;">
|
||||
<!-- 销量图表:传递销量数据 + 完成率flag -->
|
||||
<div class="dashboard left" @click="handleDashboardClick('/salesVolumeAnalysis/salesVolumeAnalysisBase')">
|
||||
<div
|
||||
v-for="item in sortedIndicators"
|
||||
:key="item.key"
|
||||
class="dashboard"
|
||||
@click="item.route && handleDashboardClick(item.route)"
|
||||
>
|
||||
<div class="title">
|
||||
销量·万㎡
|
||||
{{ item.name }}·{{ item.unit }}
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedTotal.销量.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedTotal.销量 || defaultData).completeRate, (relatedTotal.销量 || defaultData).real, (relatedTotal.销量 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedTotal.销量.diff}}</span></span>
|
||||
</div>
|
||||
<div class="chart-wrap">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedTotal.销量 || defaultData),
|
||||
flag: getRateFlag((relatedTotal.销量 || defaultData).completeRate, (relatedTotal.销量 || defaultData).real, (relatedTotal.销量 || defaultData).target)
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 成本图表:传递全成本数据 + 完成率flag -->
|
||||
<div class="dashboard right" @click="handleDashboardClick('/fullCostAnalysis/fullCostAnalysisBase')">
|
||||
<div class="title">
|
||||
成本·元/㎡
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedTotal.全成本.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedTotal.全成本 || defaultData).completeRate, (relatedTotal.全成本 || defaultData).real, (relatedTotal.全成本 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedTotal.全成本.diff}}</span></span>
|
||||
</div>
|
||||
<div class="chart-wrap">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedTotal.全成本 || defaultData),
|
||||
flag: getRateFlag((relatedTotal.全成本 || defaultData).completeRate, (relatedTotal.全成本 || defaultData).real, (relatedTotal.全成本 || defaultData).target)
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 运费图表:传递单价数据 + 完成率flag -->
|
||||
<div class="dashboard right">
|
||||
<div class="title">
|
||||
运费·万元
|
||||
</div>
|
||||
<div style='font-size: 16px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{relatedTotal.运费.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:getRateFlag((relatedTotal.运费 || defaultData).completeRate, (relatedTotal.运费 || defaultData).real, (relatedTotal.运费 || defaultData).target,)>0?'#30B590':'#FF9423'}" >{{relatedTotal.运费.diff}}</span></span>
|
||||
</div>
|
||||
<div class="chart-wrap">
|
||||
<operatingSingleBar :detailData="{
|
||||
...(relatedTotal.运费 || defaultData),
|
||||
flag: getRateFlag((relatedTotal.运费 || defaultData).completeRate, (relatedTotal.运费 || defaultData).real, (relatedTotal.运费 || defaultData).target)
|
||||
}" />
|
||||
<div style='font-size: 14px;text-align: right;padding-right: 5px;'>
|
||||
<span>完成率:<span style='color: #0B58FF;'>{{item.detailData.completeRate}}%</span></span>
|
||||
<span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
|
||||
</div>
|
||||
<operatingSingleBar :detailData="item.detailData"></operatingSingleBar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,7 +36,7 @@ export default {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
运费: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 },
|
||||
成本: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 },
|
||||
全成本: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 },
|
||||
销量: { completeRate: 0, diff: 0, real: 0, target: 0, thb: 0 }
|
||||
})
|
||||
},
|
||||
@@ -99,6 +66,55 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
indicatorDefs() {
|
||||
return [
|
||||
{ key: 'saleData', name: '销量', unit: '万㎡', route:'/salesVolumeAnalysis/salesVolumeAnalysisBase'},
|
||||
{ key: 'cbData', name: '全成本', unit: '元/㎡',route:'/fullCostAnalysis/fullCostAnalysisBase'},
|
||||
{ key: 'yfData', name: '运费', unit: '元/㎡',route:null}
|
||||
]
|
||||
},
|
||||
indicators() {
|
||||
let _this = this
|
||||
const fallback = { target: 0, real: 0, completeRate: 0, diff: 0, flag: 0 }
|
||||
const list = Object.entries(_this.relatedTotal).map(([title, data]) => {
|
||||
return {
|
||||
title: title,
|
||||
target: data.target,
|
||||
real: data.real,
|
||||
completeRate: data.completeRate,
|
||||
diff: data.diff
|
||||
};
|
||||
});
|
||||
return _this.indicatorDefs.map(def => {
|
||||
const data = list.find(item => item && item.title === def.name) || fallback
|
||||
const detailData = {
|
||||
...data,
|
||||
flag: _this.getRateFlag((data || _this.defaultData).completeRate, (data || _this.defaultData).real, (data || _this.defaultData).target),
|
||||
}
|
||||
return {
|
||||
...def,
|
||||
detailData,
|
||||
sortValue: Number((data && data.real) ?? 0)
|
||||
}
|
||||
})
|
||||
},
|
||||
sortedIndicators() {
|
||||
const unitOrder = ['万㎡','元/㎡']
|
||||
const unitRank = (u) => {
|
||||
const idx = unitOrder.indexOf(u)
|
||||
return idx === -1 ? 999 : idx
|
||||
}
|
||||
|
||||
return this.indicators.slice().sort((a, b) => {
|
||||
const ur = unitRank(a.unit) - unitRank(b.unit)
|
||||
if (ur !== 0) return ur
|
||||
const vr = (b.sortValue ?? -Infinity) - (a.sortValue ?? -Infinity)
|
||||
if (vr !== 0) return vr
|
||||
return String(a.key).localeCompare(String(b.key))
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
relatedTotal: {
|
||||
handler(newValue) {
|
||||
|
||||
Reference in New Issue
Block a user