营业收入-全成本分析页面修改

This commit is contained in:
2026-04-03 09:10:04 +08:00
parent f0ac88af3d
commit 9d91188b98
85 changed files with 1228 additions and 619 deletions

View File

@@ -10,11 +10,11 @@ VUE_APP_TITLE = 洛玻集团驾驶舱
# VUE_APP_BASE_API = 'http://172.16.33.83:7070' # 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://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' # VUE_APP_BASE_API = 'http://172.16.19.131:7070'

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -64,7 +64,15 @@ export default {
activeButton: 0, activeButton: 0,
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '全成本', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据 selectedProfit: '全成本', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据
profitOptions: ['全成本', '制造成本', '管理费用', '财务费用', '运费', '销售费用'] profitOptions:[
{name:'全成本',unit:'元/㎡'},
{name:'制造成本',unit:'元/㎡'},
{name:'管理费用',unit:'万元'},
{name:'财务费用',unit:'万元'},
{name:'运费',unit:'元/㎡'},
{name:'销售费用',unit:'万元'},
],
unit:'元/㎡'
}; };
}, },
computed: { computed: {
@@ -128,6 +136,7 @@ export default {
// 销量场景数据(保留原有结构,替换数据来源) // 销量场景数据(保留原有结构,替换数据来源)
const salesData = { const salesData = {
allPlaceNames: months, // 优先用基地名称,无则用月份 allPlaceNames: months, // 优先用基地名称,无则用月份
unit: this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -296,7 +305,8 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.unit = item.unit;
this.isDropdownShow = false; this.isDropdownShow = false;
}, },
// 复用达标状态判断方法 // 复用达标状态判断方法

View File

@@ -123,6 +123,7 @@ export default {
const data = this.currentDataSource; const data = this.currentDataSource;
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:'元/㎡',
series: [ series: [
// 完成率(折线图) // 完成率(折线图)
{ {

View File

@@ -122,7 +122,7 @@ export default {
return; // 实例未初始化则返回 return; // 实例未初始化则返回
} }
const { allPlaceNames, series } = this.chartData || {}; const { allPlaceNames,unit, series } = this.chartData || {};
const xData = allPlaceNames || []; const xData = allPlaceNames || [];
const chartSeries = series || []; const chartSeries = series || [];
@@ -169,7 +169,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '元/m2', name: unit,
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -70,16 +70,17 @@ export default {
real: 0, real: 0,
target: 0, target: 0,
thb: 0 thb: 0
} },
currentTab: 'month',
} }
}, },
computed: { computed: {
indicatorDefs() { indicatorDefs() {
return [ return [
{ key: 'productionCost', name: '制造成本', unit: '元/㎡', route:'/productionCostAnalysis/productionCostAnalysisBase'}, { key: 'productionCost', name: '制造成本', unit: '元/㎡', route:'/productionCostAnalysis/productionCostAnalysisBase'},
{ key: 'financialCost', name: '财务费用', unit: '元/㎡',route:'/expenseAnalysis/expenseAnalysisBase' }, { key: 'financialCost', name: '财务费用', unit: '元',route:'/expenseAnalysis/expenseAnalysisBase' },
{ key: 'saleCost', name: '销售费用', unit: '元/㎡',route:'/expenseAnalysis/expenseAnalysisBase'}, { key: 'saleCost', name: '销售费用', unit: '元',route:'/expenseAnalysis/expenseAnalysisBase'},
{ key: 'manageCost', name: '管理费用', unit: '元/㎡',route:'/expenseAnalysis/expenseAnalysisBase' }, { key: 'manageCost', name: '管理费用', unit: '元',route:'/expenseAnalysis/expenseAnalysisBase' },
{ key: 'freight', name: '运费', unit: '元/㎡',route:null }, { key: 'freight', name: '运费', unit: '元/㎡',route:null },
] ]
}, },
@@ -109,7 +110,7 @@ export default {
}) })
}, },
sortedIndicators() { sortedIndicators() {
const unitOrder = ['元/㎡'] const unitOrder = ['元/㎡','万元']
const unitRank = (u) => { const unitRank = (u) => {
const idx = unitOrder.indexOf(u) const idx = unitOrder.indexOf(u)
return idx === -1 ? 999 : idx return idx === -1 ? 999 : idx
@@ -128,7 +129,11 @@ export default {
// 监听 relatedData 变化(异步加载场景),同步更新月度数据 // 监听 relatedData 变化(异步加载场景),同步更新月度数据
relatedData: { relatedData: {
handler(newVal) { handler(newVal) {
if(this.currentTab === 'month') {
this.relatedDetailData = newVal.relatedMon || {}; this.relatedDetailData = newVal.relatedMon || {};
}else{
this.relatedDetailData = newVal.relatedTotal || {};
}
}, },
immediate: true, immediate: true,
deep: true deep: true
@@ -167,6 +172,7 @@ export default {
}, },
handleChange(value) { handleChange(value) {
console.log('value', value, this.relatedData); console.log('value', value, this.relatedData);
this.currentTab = value;
if (value === 'month') { if (value === 'month') {
this.relatedDetailData = this.relatedData.relatedMon || {}; this.relatedDetailData = this.relatedData.relatedMon || {};
} else { } else {

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -63,10 +63,11 @@ export default {
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '毛利率', // 选中的名称初始为null selectedProfit: '毛利率', // 选中的名称初始为null
profitOptions: [ profitOptions: [
'毛利率', {name:'毛利率',unit:'%'},
'营业收入', {name:'营业收入',unit:'万元'},
'全成本', {name:'全成本',unit:'元/㎡'}
] ],
unit:'%'
}; };
}, },
computed: { computed: {
@@ -91,6 +92,7 @@ export default {
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit: this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -251,9 +253,10 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.unit = item.unit;
this.isDropdownShow = false; this.isDropdownShow = false;
this.$emit("changeItem", item); this.$emit("changeItem", item.name);
} }
}, },
}; };

View File

@@ -123,6 +123,7 @@ export default {
const data = this.currentDataSource; const data = this.currentDataSource;
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:'%',
series: [ series: [
// 完成率(折线图) // 完成率(折线图)
{ {

View File

@@ -133,7 +133,7 @@ export default {
return; // 实例未初始化则返回 return; // 实例未初始化则返回
} }
const { allPlaceNames, series } = this.chartData || {}; const { allPlaceNames, unit, series } = this.chartData || {};
const xData = allPlaceNames || []; const xData = allPlaceNames || [];
const chartSeries = series || []; const chartSeries = series || [];
@@ -180,7 +180,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '%', name: unit,
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -61,12 +61,13 @@ export default {
return { return {
activeButton: 0, activeButton: 0,
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '加工成品率', // 选中的名称初始为null selectedProfit: '投入产出率', // 选中的名称初始为null
profitOptions: [ profitOptions: [
'加工成品率', {name:'投入产出率',unit:'%'},
'领用量', {name:'加工产量',unit:'㎡'},
'加工产量', {name:'领用量',unit:'㎡'}
] ],
unit:'%'
}; };
}, },
computed: { computed: {
@@ -90,6 +91,7 @@ export default {
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit: this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -251,9 +253,10 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.unit = item.unit;
this.isDropdownShow = false; this.isDropdownShow = false;
this.$emit("changeItem", item); this.$emit("changeItem", item.name);
} }
}, },
}; };

View File

@@ -11,7 +11,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -57,8 +57,8 @@ export default {
computed: { computed: {
indicatorDefs() { indicatorDefs() {
return [ return [
{ key: 'useData', name: '领用量', unit: '㎡'}, { key: 'useData', name: '领用量', unit: '㎡'},
{ key: 'processData', name: '加工产量', unit: '㎡'}, { key: 'processData', name: '加工产量', unit: '㎡'},
] ]
}, },
indicators() { indicators() {

View File

@@ -123,6 +123,7 @@ export default {
const data = this.currentDataSource; const data = this.currentDataSource;
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:'%',
series: [ series: [
// 完成率(折线图) // 完成率(折线图)
{ {

View File

@@ -122,7 +122,7 @@ export default {
return; // 实例未初始化则返回 return; // 实例未初始化则返回
} }
const { allPlaceNames, series } = this.chartData || {}; const { allPlaceNames, unit, series } = this.chartData || {};
const xData = allPlaceNames || []; const xData = allPlaceNames || [];
const chartSeries = series || []; const chartSeries = series || [];
@@ -169,7 +169,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '%', name: unit,
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -11,7 +11,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -57,8 +57,8 @@ export default {
computed: { computed: {
indicatorDefs() { indicatorDefs() {
return [ return [
{ key: 'useData', name: '领用量', unit: '㎡'}, { key: 'useData', name: '领用量', unit: '㎡'},
{ key: 'processData', name: '加工产量', unit: '㎡'}, { key: 'processData', name: '加工产量', unit: '㎡'},
] ]
}, },
indicators() { indicators() {

View File

@@ -48,7 +48,7 @@
gap: 12px; gap: 12px;
grid-template-columns: 1624px; grid-template-columns: 1624px;
"> ">
<dataTrend :trendData="trend" :title="'数据趋势'" /> <dataTrend :trendData="trendData" :title="'数据趋势'" />
</div> </div>
</div> </div>
</div> </div>
@@ -110,8 +110,7 @@ export default {
relatedMon: {}, relatedMon: {},
relatedTotal: {}, relatedTotal: {},
totalData: {}, totalData: {},
trendData: [], trendData: {},
trend: [],
paramList: ['单价', '运费'], paramList: ['单价', '运费'],
}; };
}, },
@@ -209,17 +208,7 @@ export default {
this.totalData = res.data.totalData this.totalData = res.data.totalData
this.relatedMon = res.data.relatedMon this.relatedMon = res.data.relatedMon
this.relatedTotal = res.data.relatedTotal this.relatedTotal = res.data.relatedTotal
this.trend = res.data.trend this.trendData = 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,
// }
}); });
}, },

View File

@@ -5,35 +5,20 @@
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;"> <div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
<!-- 新增topItem 专属包裹容器统一控制样式和布局 --> <!-- 新增topItem 专属包裹容器统一控制样式和布局 -->
<div class="topItem-container" style="display: flex; gap: 8px;"> <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"> <div class="title">
单价· {{ item.name }}·{{ item.unit }}
</div> </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;'>{{relatedMon.单价.completeRate}}%</span></span> <span>完成率:<span style='color: #0B58FF;'>{{item.detailData.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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.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> </div>
<operatingSingleBar :detailData="item.detailData"></operatingSingleBar>
</div> </div>
</div> </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: { watch: {
relatedMon: { relatedMon: {
handler(newValue) { handler(newValue) {

View File

@@ -168,7 +168,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '元', name: '元/㎡',
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -112,7 +112,7 @@ export default {
// 左侧Y轴营业收入、成本单位万元 // 左侧Y轴营业收入、成本单位万元
{ {
type: 'value', type: 'value',
name: '元', name: '元/㎡',
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -5,35 +5,20 @@
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;"> <div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
<!-- 新增topItem 专属包裹容器统一控制样式和布局 --> <!-- 新增topItem 专属包裹容器统一控制样式和布局 -->
<div class="topItem-container" style="display: flex; gap: 8px;"> <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"> <div class="title">
单价· {{ item.name }}·{{ item.unit }}
</div> </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;'>{{relatedTotal.单价.completeRate}}%</span></span> <span>完成率:<span style='color: #0B58FF;'>{{item.detailData.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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.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> </div>
<operatingSingleBar :detailData="item.detailData"></operatingSingleBar>
</div> </div>
</div> </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: { watch: {
relatedTotal: { relatedTotal: {
handler(newValue) { handler(newValue) {

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -63,16 +63,14 @@ export default {
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '营业收入', // 选中的名称初始为null selectedProfit: '营业收入', // 选中的名称初始为null
profitOptions: [ profitOptions: [
'营业收入', {name:'营业收入',unit:'万元'},
'单价', {name:'单价',unit:'元/㎡'},
'销量', {name:'销量',unit:'万㎡'},
] ],
unit:'万元'
}; };
}, },
computed: { computed: {
// profitOptions() {
// return this.categoryData.map(item => item.name) || [];
// },
currentDataSource() { currentDataSource() {
console.log('yyyy', this.chartData); console.log('yyyy', this.chartData);
@@ -90,6 +88,7 @@ export default {
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit: this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -251,9 +250,10 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.unit = item.unit;
this.isDropdownShow = false; this.isDropdownShow = false;
this.$emit("changeItem", item); this.$emit("changeItem", item.name);
} }
}, },
}; };

View File

@@ -123,6 +123,7 @@ export default {
const data = this.currentDataSource; const data = this.currentDataSource;
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:'万元',
series: [ series: [
// 完成率(折线图) // 完成率(折线图)
{ {

View File

@@ -122,7 +122,7 @@ export default {
return; // 实例未初始化则返回 return; // 实例未初始化则返回
} }
const { allPlaceNames, series } = this.chartData || {}; const { allPlaceNames, unit, series } = this.chartData || {};
const xData = allPlaceNames || []; const xData = allPlaceNames || [];
const chartSeries = series || []; const chartSeries = series || [];
@@ -169,13 +169,12 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '万元', name: unit,
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,
align: 'right' align: 'right'
}, },
min:1000,
splitNumber: 4, splitNumber: 4,
axisTick: { show: false }, axisTick: { show: false },
axisLabel: { axisLabel: {

View File

@@ -68,7 +68,6 @@ import screenfull from "screenfull";
import changeBase from "../components/changeBase.vue"; import changeBase from "../components/changeBase.vue";
import monthlyOverview from "../operatingProfitComponents/monthlyOverview.vue"; import monthlyOverview from "../operatingProfitComponents/monthlyOverview.vue";
import totalOverview from "../operatingProfitComponents/totalOverview.vue"; import totalOverview from "../operatingProfitComponents/totalOverview.vue";
// import totalOverview from "../operatingComponents/totalOverview.vue";
import relatedIndicatorsAnalysis from "../operatingProfitComponents/relatedIndicatorsAnalysis.vue"; import relatedIndicatorsAnalysis from "../operatingProfitComponents/relatedIndicatorsAnalysis.vue";
import dataTrend from "../operatingProfitComponents/dataTrend.vue"; import dataTrend from "../operatingProfitComponents/dataTrend.vue";
import { mapState } from "vuex"; import { mapState } from "vuex";

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -62,20 +62,18 @@ export default {
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '经营性利润', // 选中的名称初始为null selectedProfit: '经营性利润', // 选中的名称初始为null
profitOptions: [ profitOptions: [
'经营性利润', {name:'经营性利润',unit:'万元'},
'销量', {name:'销量',unit:'万㎡'},
'单价', {name:'单价',unit:'元/㎡'},
'制造成本', {name:'制造成本',unit:'元/㎡'},
'管理费用', {name:'管理费用',unit:'万元'},
'销售费用', {name:'销售费用',unit:'万元'},
'财务费用', {name:'财务费用',unit:'万元'},
] ],
unit:'万元'
}; };
}, },
computed: { computed: {
// profitOptions() {
// return this.categoryData.map(item => item.name) || [];
// },
currentDataSource() { currentDataSource() {
return this.chartData return this.chartData
}, },
@@ -91,6 +89,7 @@ export default {
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit: this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -249,9 +248,10 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.unit = item.unit;
this.isDropdownShow = false; this.isDropdownShow = false;
this.$emit('handleGetItemData',item) this.$emit('handleGetItemData',item.name)
} }
}, },
}; };

View File

@@ -123,6 +123,7 @@ export default {
const data = this.currentDataSource; const data = this.currentDataSource;
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:'万元',
series: [ series: [
// 完成率(折线图) // 完成率(折线图)
{ {

View File

@@ -123,7 +123,7 @@ export default {
return; // 实例未初始化则返回 return; // 实例未初始化则返回
} }
const { allPlaceNames, series } = this.chartData || {}; const { allPlaceNames, unit, series } = this.chartData || {};
const xData = allPlaceNames || []; const xData = allPlaceNames || [];
const chartSeries = series || []; const chartSeries = series || [];
@@ -170,7 +170,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '万元', name: unit,
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -9,7 +9,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>
@@ -55,7 +55,8 @@ export default {
return { return {
chart: null, chart: null,
// 核心:当前激活的数据集(月度/累计),默认初始化月度数据 // 核心:当前激活的数据集(月度/累计),默认初始化月度数据
activeData: this.relatedData.relatedMon || [] activeData: this.relatedData.relatedMon || [],
currentTab: 'month'
} }
}, },
computed: { computed: {
@@ -102,7 +103,12 @@ export default {
// 可选:监听 relatedData 初始变化(若父组件异步传递数据,确保 activeData 同步更新) // 可选:监听 relatedData 初始变化(若父组件异步传递数据,确保 activeData 同步更新)
relatedData: { relatedData: {
handler(newVal) { handler(newVal) {
if (this.currentTab === 'month') {
this.activeData = newVal.relatedMon || []; this.activeData = newVal.relatedMon || [];
}else{
this.activeData = newVal.relatedTotal || [];
}
}, },
immediate: true, immediate: true,
deep: true deep: true
@@ -127,6 +133,7 @@ export default {
*/ */
handleChange(value) { handleChange(value) {
console.log('Tab 切换值:', value); console.log('Tab 切换值:', value);
this.currentTab = value;
// 根据 Tab 值更新当前激活的数据集 // 根据 Tab 值更新当前激活的数据集
if (value === 'month') { if (value === 'month') {
// 切换为月度数据 // 切换为月度数据

View File

@@ -68,7 +68,7 @@ export default {
*/ */
factoryData() { // 整合原始数据 + 计算flag factoryData() { // 整合原始数据 + 计算flag
return { return {
completeRate: Number(this.totalData.proportion), completeRate: this.totalData.proportion ? Number(this.totalData.proportion) : 0,
diff: this.totalData.diffValue, diff: this.totalData.diffValue,
real: this.totalData.value, real: this.totalData.value,
target: this.totalData.targetValue, target: this.totalData.targetValue,

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -63,7 +63,8 @@ export default {
real: 0, real: 0,
target: 0, target: 0,
thb: 0 thb: 0
} },
currentTab:'month',
} }
}, },
computed: { computed: {
@@ -121,7 +122,11 @@ export default {
// 监听 relatedData 变化(异步加载场景),同步更新月度数据 // 监听 relatedData 变化(异步加载场景),同步更新月度数据
relatedData: { relatedData: {
handler(newVal) { handler(newVal) {
if (this.currentTab === 'month') {
this.relatedDetailData = newVal.relatedMon || {}; this.relatedDetailData = newVal.relatedMon || {};
}else{
this.relatedDetailData = newVal.relatedTotal || {};
}
}, },
immediate: true, immediate: true,
deep: true deep: true
@@ -156,6 +161,7 @@ export default {
}, },
handleChange(value) { handleChange(value) {
console.log('value', value, this.relatedData); console.log('value', value, this.relatedData);
this.currentTab = value;
if (value === 'month') { if (value === 'month') {
this.relatedDetailData = this.relatedData.relatedMon || {}; this.relatedDetailData = this.relatedData.relatedMon || {};
} else { } else {

View File

@@ -60,7 +60,7 @@ import monthlyOverview from "../productionCostAnalysisComponents/monthlyOverview
import totalOverview from "../productionCostAnalysisComponents/totalOverview.vue"; import totalOverview from "../productionCostAnalysisComponents/totalOverview.vue";
// import totalOverview from "../operatingComponents/totalOverview.vue"; // import totalOverview from "../operatingComponents/totalOverview.vue";
// import monthlyRelatedMetrics from "../procurementGainAnalysisComponents/monthlyRelatedMetrics.vue"; // import monthlyRelatedMetrics from "../procurementGainAnalysisComponents/monthlyRelatedMetrics.vue";
import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingLabor.vue"; import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingLabor2.vue";
import { mapState } from "vuex"; import { mapState } from "vuex";
import { getSingleMaterialCostAnalysis } from '@/api/cockpit' import { getSingleMaterialCostAnalysis } from '@/api/cockpit'
// import PSDO from "./components/PSDO.vue"; // import PSDO from "./components/PSDO.vue";

View File

@@ -60,7 +60,7 @@ import screenfull from "screenfull";
import changeBase from "../components/changeBase.vue"; import changeBase from "../components/changeBase.vue";
import monthlyOverview from "../productionCostAnalysisComponents/monthlyOverview.vue"; import monthlyOverview from "../productionCostAnalysisComponents/monthlyOverview.vue";
import totalOverview from "../productionCostAnalysisComponents/totalOverview.vue"; import totalOverview from "../productionCostAnalysisComponents/totalOverview.vue";
import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingLabor.vue"; import dataTrend from "../productionCostAnalysisComponents/dataTrendProcessingLabor2.vue";
import { mapState } from "vuex"; import { mapState } from "vuex";
import { getSingleMaterialCostAnalysis } from '@/api/cockpit' import { getSingleMaterialCostAnalysis } from '@/api/cockpit'
// import PSDO from "./components/PSDO.vue"; // import PSDO from "./components/PSDO.vue";

View File

@@ -1,15 +1,30 @@
<template> <template>
<div class="cockpitContainer" :class="['cockpitContainer__' + size]"> <div class="cockpitContainer" :class="['cockpitContainer__' + size]">
<div class="content-top" :class="['content-top__' + topSize]"> <div class="container-top" ref="containerTop">
<!-- 使用 flex 容器包裹图标和文字实现垂直居中 --> <!-- 左侧标题 -->
<div class="title-wrapper"> <div class="content-top-left title-wrapper" @click="handleLeftClick"
<svg-icon class="title-icon" :icon-class="icon" /> :style="{ opacity: isLeftTransparent ? 1 : 0.3 }" ref="leftTitleWrapper">
<span class="title-text"> <svg-icon class="title-icon" style="font-size: 32px; margin-left: 16px" :icon-class="icon" />
{{ name }} <span class="title-text" ref="leftTitleText">{{ name }}</span>
</span> <span class="change-text left-change-text" v-if="!isLeftTransparent" ref="leftChangeText">点击切换</span>
<svg-icon icon-class="turn-data" style='font-size: 40px;margin-left: 60px;' @click='switchData'/>
</div> </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点击切换状态动态绑定样式 --> <!-- 月度Tab点击切换状态动态绑定样式 -->
<div class="tab-item" :class="{ active: activeTab === 'month' }" @click="handleTabClick('month')"> <div class="tab-item" :class="{ active: activeTab === 'month' }" @click="handleTabClick('month')">
月度 月度
@@ -19,11 +34,9 @@
累计 累计
</div> </div>
</div> </div>
</div>
<div class="cockpitContainer-body"> <div class="container-body">
<slot> <slot></slot>
<div class="test-body">something test....</div>
</slot>
</div> </div>
</div> </div>
</template> </template>
@@ -32,16 +45,59 @@
export default { export default {
name: 'Container', name: 'Container',
components: {}, components: {},
// eslint-disable-next-line vue/require-prop-types props: {
props: ['size', 'icon', 'topSize', 'isShowTab'], 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() { data() {
return { return {
activeTab: 'month', // 初始化激活的Tab支持父组件传默认值 isLeftTransparent: true,
name:'指标分析', isRightTransparent: false,
activeTab: 'month', // 初始化激活的Tab支持父组件传默认值
}; };
}, },
computed: {}, mounted() {
// 初始化定位
// this.positionChangeText();
// // 监听窗口大小变化,重新定位
// window.addEventListener('resize', this.positionChangeText);
},
// updated() {
// // 数据更新后重新定位(如标题文字变化)
// this.positionChangeText();
// },
beforeDestroy() {
// 移除监听
// window.removeEventListener('resize', this.positionChangeText);
},
methods: { 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) { handleTabClick(tabType) {
this.activeTab = tabType; this.activeTab = tabType;
// 向父组件派发Tab切换事件传递当前选中的Tab类型 // 向父组件派发Tab切换事件传递当前选中的Tab类型
@@ -49,48 +105,72 @@ export default {
// 可选:同时传递更详细的信息(如标签名) // 可选:同时传递更详细的信息(如标签名)
// this.$emit('tabChange', { type: tabType, name: tabType === 'month' ? '月度' : '累计' }); // this.$emit('tabChange', { type: tabType, name: tabType === 'month' ? '月度' : '累计' });
}, },
switchData() { /**
console.log('aaa') * 动态定位切换文字:紧跟标题文本后方
if (this.name === '数据趋势') { */
this.name = '指标分析'; positionChangeText() {
} else { // 1. 处理左侧切换文字
this.name = '数据趋势'; 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> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.cockpitContainer { .cockpitContainer {
display: inline-block; display: inline-block;
// width: 100%;
// height: 100%;
padding: 6px; padding: 6px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative; position: relative;
.content-top { .container-top {
position: relative;
height: 60px; 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 { .title-wrapper {
display: flex; display: flex;
align-items: center; align-items: center;
margin-left: 10px;
/* 垂直居中关键属性 */
height: 100%; height: 100%;
/* 继承父容器高度,确保垂直居中范围 */ gap: 8px; // 图标、标题间距
} }
.title-icon { .title-icon {
font-size: 30px; font-size: 30px;
margin-right: 12px; margin-left: 10px;
margin-top: 4px; flex-shrink: 0; // 防止图标被压缩
/* 图标和文字之间的间距 */
flex-shrink: 0;
/* 防止图标被压缩 */
} }
.title-text { .title-text {
@@ -101,62 +181,80 @@ export default {
letter-spacing: 3px; letter-spacing: 3px;
text-align: left; text-align: left;
font-style: normal; font-style: normal;
// 移除固定行高,避免影响垂直对齐 flex-shrink: 0; // 防止标题文字被压缩
// line-height: 60px;
} }
// width: 547px; /* 左侧标题 - 左上角折现边框 */
// background: url(../../../assets/img/contentTopBasic.png) no-repeat; .content-top-left::before {
// background-size: 100% 100%; content: "";
// background-position: 0 0; position: absolute;
&__basic { top: 0;
// width: 547px; left: 0;
background: url(../../../assets/img/contentTopBasic.png) no-repeat; width: 100%;
background-size: 100% 100%; height: 100%;
background-position: 0 0; 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; .content-top-left::after {
background-size: 100% 100%; content: "";
background-position: 0 0; 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 { .content-top-right {
background: url(../../../assets/img/topTitleLargeBg.png) no-repeat; width: 1300px;
background-size: 100% 100%; height: 60px;
background-position: 0 0; 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; .content-top-right::before {
background-size: 100% 100%; content: "";
background-position: 0 0; 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; .content-top-right::after {
background-size: 100% 100%; content: "";
background-position: 0 0; position: absolute;
} top: 0;
left: 0;
&__rawTopTitleLarge { width: 30px;
background: url(../../../assets/img/rawTopTitleLarge.png) no-repeat; height: 30px;
background-size: 100% 100%; background: #E1f0fd;
background-position: 0 0; border-top: 1px solid rgba(92, 140, 255, 1);
} border-left: 1px solid rgba(92, 140, 255, 1);
transform: rotate(135deg) translate(-50%, -50%);
&__calendarTitleBg { transform-origin: top left;
background: url(../../../assets/img/calendarTitleBg.png) no-repeat; z-index: 12;
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;
}
} }
&__topBasic { &__topBasic {
@@ -171,163 +269,50 @@ export default {
background-position: 0 0; 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 { &__opLargeBg {
background: url(../../../assets/img/opLargeBg.png) no-repeat; background: url(../../../assets/img/opLargeBg.png) no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
background-position: 0 0; 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 { .container-body {
flex: 1; 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 { .tab-group {
display: inline-flex; display: inline-flex;
position: absolute; position: absolute;

View File

@@ -1,6 +1,6 @@
<template> <template>
<div style="flex: 1"> <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 v-show='showRelated' style="padding: 14px 16px; width: 100%; gap: 16px">
<div style="display: flex; gap: 8px;overflow: auto"> <div style="display: flex; gap: 8px;overflow: auto">
<div <div
@@ -11,7 +11,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>
@@ -28,7 +28,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

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

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -9,7 +9,7 @@
<div class="title"> <div class="title">
·万元 ·万元
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:dianData.completed>0?'#30B590':'#FF9423'}" >{{dianData.diffValue}}</span></span>
</div> </div>
@@ -21,7 +21,7 @@
<div class="title"> <div class="title">
·/ ·/
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:shuiData.completed>0?'#30B590':'#FF9423'}" >{{shuiData.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -10,7 +10,7 @@
<div class="title"> <div class="title">
采购单价·/ 采购单价·/
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:unitPriceData.completed>0?'#30B590':'#FF9423'}" >{{unitPriceData.diffValue}}</span></span>
</div> </div>
@@ -22,7 +22,7 @@
<div class="title"> <div class="title">
产量· 产量·
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:productData.completed>0?'#30B590':'#FF9423'}" >{{productData.diffValue}}</span></span>
</div> </div>
@@ -34,7 +34,7 @@
<div class="title"> <div class="title">
单耗·/ 单耗·/
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:unitHaoData.completed>0?'#30B590':'#FF9423'}" >{{unitHaoData.diffValue}}</span></span>
</div> </div>
@@ -46,7 +46,7 @@
<div class="title"> <div class="title">
消耗量· 消耗量·
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:haoNumData.completed>0?'#30B590':'#FF9423'}" >{{haoNumData.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -9,7 +9,7 @@
<div class="title"> <div class="title">
·万元 ·万元
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:dianData.completed>0?'#30B590':'#FF9423'}" >{{dianData.diffValue}}</span></span>
</div> </div>
@@ -21,7 +21,7 @@
<div class="title"> <div class="title">
·/ ·/
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:shuiData.completed>0?'#30B590':'#FF9423'}" >{{shuiData.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>

View File

@@ -35,10 +35,10 @@
<div class="left-three" style=" <div class="left-three" style="
display: grid; display: grid;
gap: 12px; gap: 12px;
grid-template-columns: 804px 804px; grid-template-columns: 1624px;
"> ">
<monthlyRelatedMetrics :monthAnalysis="monthAnalysis" :title="'月度·相关指标分析'" /> <relatedIndicatorsAnalysis :dateData="dateData" :factory="factory" :relatedData="relatedData"
<yearRelatedMetrics :ytdAnalysis="ytdAnalysis" :title="'累计·相关指标分析'" /> :title="'相关指标分析'" />
</div> </div>
</div> </div>
@@ -69,9 +69,7 @@ import screenfull from "screenfull";
import changeBase from "../components/changeBase.vue"; import changeBase from "../components/changeBase.vue";
import monthlyOverview from "../rawSheetYieldComponents/monthlyOverview.vue"; import monthlyOverview from "../rawSheetYieldComponents/monthlyOverview.vue";
import totalOverview from "../rawSheetYieldComponents/totalOverview.vue"; import totalOverview from "../rawSheetYieldComponents/totalOverview.vue";
// import totalOverview from "../operatingComponents/totalOverview.vue"; import relatedIndicatorsAnalysis from "../rawSheetYieldComponents/relatedIndicatorsAnalysis.vue";
import monthlyRelatedMetrics from "../rawSheetYieldComponents/monthlyRelatedMetrics.vue";
import yearRelatedMetrics from "../rawSheetYieldComponents/yearRelatedMetrics.vue";
import dataTrend from "../rawSheetYieldComponents/dataTrend.vue"; import dataTrend from "../rawSheetYieldComponents/dataTrend.vue";
import profitLineChart from "../costComponents/profitLineChart.vue"; import profitLineChart from "../costComponents/profitLineChart.vue";
@@ -95,8 +93,7 @@ export default {
monthlyOverview, monthlyOverview,
Sidebar, Sidebar,
totalOverview, totalOverview,
monthlyRelatedMetrics, relatedIndicatorsAnalysis,
yearRelatedMetrics,
dataTrend dataTrend
// psiLineChart // psiLineChart
}, },
@@ -112,8 +109,7 @@ export default {
index: '原片成品率', index: '原片成品率',
monthData: undefined, monthData: undefined,
ytdData: undefined, ytdData: undefined,
monthAnalysis: [], relatedData: {},
ytdAnalysis: [],
trend: [], trend: [],
// trendData: [], // trendData: [],
// parentItemList: [ // parentItemList: [
@@ -213,11 +209,11 @@ export default {
getSheetYieldFactoryData(requestParams).then((res) => { getSheetYieldFactoryData(requestParams).then((res) => {
this.monthData = res.data.month this.monthData = res.data.month
this.ytdData = res.data.ytd this.ytdData = res.data.ytd
this.monthAnalysis = res.data.monthAnalysis
this.ytdAnalysis = res.data.ytdAnalysis
this.trend = res.data.trend this.trend = res.data.trend
this.relatedData = {
// this.monthData = res.data.month relatedMon:res.data.monthAnalysis,
relatedTotal:res.data.ytdAnalysis
}
}); });
}, },

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -63,16 +63,19 @@ export default {
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '原片成品率', // 选中的名称初始为null selectedProfit: '原片成品率', // 选中的名称初始为null
profitOptions: [ profitOptions: [
'原片成品率', {name:'原片成品率',unit:'%'},
'原片产量', {name:'拉引量',unit:'吨'},
'拉引量', {name:'边损',unit:'㎡'},
] {name:'设备损失',unit:'㎡'},
{name:'换机损失',unit:'㎡'},
{name:'切割损失',unit:'㎡'},
{name:'退火损失',unit:'㎡'},
{name:'原片产量',unit:'㎡'}
],
unit:'%'
}; };
}, },
computed: { computed: {
// profitOptions() {
// return this.categoryData.map(item => item.name) || [];
// },
currentDataSource() { currentDataSource() {
console.log('yyyy', this.chartData); console.log('yyyy', this.chartData);
@@ -90,6 +93,7 @@ export default {
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -251,9 +255,10 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.unit = item.unit;
this.isDropdownShow = false; this.isDropdownShow = false;
this.$emit("changeItem", item); this.$emit("changeItem", item.name);
} }
}, },
}; };

View File

@@ -11,7 +11,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>

View File

@@ -123,6 +123,7 @@ export default {
const data = this.currentDataSource; const data = this.currentDataSource;
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:'%',
series: [ series: [
// 完成率(折线图) // 完成率(折线图)
{ {

View File

@@ -119,7 +119,7 @@ export default {
return; // 实例未初始化则返回 return; // 实例未初始化则返回
} }
const { allPlaceNames, series } = this.chartData || {}; const { allPlaceNames, unit, series } = this.chartData || {};
const xData = allPlaceNames || []; const xData = allPlaceNames || [];
const chartSeries = series || []; const chartSeries = series || [];
@@ -166,7 +166,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '%', name: unit,
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -6,7 +6,6 @@
<script> <script>
import operatingLineBarSaleSingle from './operatingLineBarSaleSingle.vue'; import operatingLineBarSaleSingle from './operatingLineBarSaleSingle.vue';
import * as echarts from 'echarts';
export default { export default {
name: "Container", name: "Container",
@@ -23,6 +22,7 @@ export default {
chartD() { chartD() {
// 背景图片路径(若不需要可注释) // 背景图片路径(若不需要可注释)
// const bgImageUrl = require('@/assets/img/labelBg.png'); // const bgImageUrl = require('@/assets/img/labelBg.png');
console.log('detailData++++++++++++++++++++++', this.detailData);
const rate = this.detailData?.rate || 0 const rate = this.detailData?.rate || 0
const diff = this.detailData?.diff || 0 const diff = this.detailData?.diff || 0
console.log('diff', diff); console.log('diff', diff);

View File

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

View File

@@ -11,7 +11,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -63,8 +63,18 @@ export default {
return { return {
activeButton: 0, activeButton: 0,
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '净价', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据 selectedProfit: '销量',
profitOptions: ['净价', '单价', '产销率','双镀销量','双镀占比','溢价产品销量','溢价产品毛利'] profitOptions:[
{name:'销量',unit:'万㎡'},
{name:'净价',unit:'元/㎡'},
{name:'单价',unit:'元/㎡'},
{name:'产销率',unit:'%'},
{name:'双镀销量',unit:'万㎡'},
{name:'双镀占比',unit:'%'},
{name:'溢价产品销量',unit:'万㎡'},
{name:'溢价产品毛利',unit:'元'},
],
unit:'万㎡'
}; };
}, },
computed: { computed: {
@@ -126,6 +136,7 @@ export default {
// 销量场景数据(保留原有结构,替换数据来源) // 销量场景数据(保留原有结构,替换数据来源)
const salesData = { const salesData = {
allPlaceNames: months, // 优先用基地名称,无则用月份 allPlaceNames: months, // 优先用基地名称,无则用月份
unit: this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -286,8 +297,9 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.isDropdownShow = false; this.isDropdownShow = false;
this.unit = item.unit;
}, },
// 复用达标状态判断方法 // 复用达标状态判断方法
getRateFlag(rate, real, target) { getRateFlag(rate, real, target) {

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -63,8 +63,14 @@ export default {
return { return {
activeButton: 0, activeButton: 0,
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '双镀成本', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据 selectedProfit: '双镀销量',
profitOptions: ['双镀成本', '双镀均价', '双镀毛利'] profitOptions:[
{name:'双镀销量',unit:'万㎡'},
{name:'双镀成本',unit:'元/㎡'},
{name:'双镀均价',unit:'元/㎡'},
{name:'双镀毛利',unit:'元'},
],
unit:'万㎡'
}; };
}, },
computed: { computed: {
@@ -128,6 +134,7 @@ export default {
// 销量场景数据(保留原有结构,替换数据来源) // 销量场景数据(保留原有结构,替换数据来源)
const salesData = { const salesData = {
allPlaceNames: months, // 优先用基地名称,无则用月份 allPlaceNames: months, // 优先用基地名称,无则用月份
unit: this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -286,8 +293,9 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.isDropdownShow = false; this.isDropdownShow = false;
this.unit = item.unit;
}, },
// 复用达标状态判断方法 // 复用达标状态判断方法
getRateFlag(rate) { getRateFlag(rate) {

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -63,8 +63,13 @@ export default {
return { return {
activeButton: 0, activeButton: 0,
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '产量(深加工)', // 关键修改:默认赋值为「净价」,初始化即展示该类目数据 selectedProfit: '产销率',
profitOptions: ['产量(深加工)', '销量'] profitOptions:[
{name:'产销率',unit:'%'},
{name:'销量',unit:'万㎡'},
{name:'产量(深加工)',unit:'㎡'},
],
unit:'%',
}; };
}, },
computed: { computed: {
@@ -128,6 +133,7 @@ export default {
// 销量场景数据(保留原有结构,替换数据来源) // 销量场景数据(保留原有结构,替换数据来源)
const salesData = { const salesData = {
allPlaceNames: months, // 优先用基地名称,无则用月份 allPlaceNames: months, // 优先用基地名称,无则用月份
unit: this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -286,8 +292,9 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.isDropdownShow = false; this.isDropdownShow = false;
this.unit = item.unit;
}, },
// 复用达标状态判断方法 // 复用达标状态判断方法
getRateFlag(rate) { getRateFlag(rate) {

View File

@@ -11,7 +11,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -61,7 +61,7 @@ export default {
computed: { computed: {
indicatorDefs() { indicatorDefs() {
return [ return [
{ key: 'production', name: '产量', unit: '㎡'}, { key: 'production', name: '产量', unit: '㎡'},
{ key: 'financialCost', name: '销量', unit: '万㎡'}, { key: 'financialCost', name: '销量', unit: '万㎡'},
] ]
}, },

View File

@@ -11,7 +11,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -63,7 +63,7 @@ export default {
return [ return [
{ key: 'financialCost', name: '双镀成本', unit: '元/㎡'}, { key: 'financialCost', name: '双镀成本', unit: '元/㎡'},
{ key: 'financialPrice', name: '双镀均价', unit: '元/㎡'}, { key: 'financialPrice', name: '双镀均价', unit: '元/㎡'},
{ key: 'financialProfit', name: '双镀毛利', unit: '元'}, { key: 'financialProfit', name: '双镀毛利', unit: '元'},
] ]
}, },
indicators() { indicators() {

View File

@@ -123,6 +123,7 @@ export default {
const data = this.currentDataSource; const data = this.currentDataSource;
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:'万㎡',
series: [ series: [
// 完成率(折线图) // 完成率(折线图)
{ {

View File

@@ -122,7 +122,7 @@ export default {
return; // 实例未初始化则返回 return; // 实例未初始化则返回
} }
const { allPlaceNames, series } = this.chartData || {}; const { allPlaceNames, unit, series } = this.chartData || {};
const xData = allPlaceNames || []; const xData = allPlaceNames || [];
const chartSeries = series || []; const chartSeries = series || [];
@@ -169,7 +169,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '万m2', name: unit,
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -69,13 +69,13 @@ export default {
computed: { computed: {
indicatorDefs() { indicatorDefs() {
return [ return [
{ key: 'netPrice', name: '净价', unit: '㎡', route:'/netPriceAnalysis/netPriceAnalysisBase'}, { key: 'netPrice', name: '净价', unit: '元/㎡', route:'/netPriceAnalysis/netPriceAnalysisBase'},
{ key: 'unitPrice', name: '单价', unit: '元/㎡',route:'/unitPriceAnalysis/unitPriceAnalysisBase' }, { key: 'unitPrice', name: '单价', unit: '元/㎡',route:'/unitPriceAnalysis/unitPriceAnalysisBase' },
{ key: 'productionSales', name: '产销率', unit: '%',route:'/salesVolumeAnalysis/productionSalesBase'}, { key: 'productionSales', name: '产销率', unit: '%',route:'/salesVolumeAnalysis/productionSalesBase'},
{ key: 'manageCost', name: '双镀销量', unit: '万㎡',route:'/salesVolumeAnalysis/doublePlatedBase' }, { key: 'manageCost', name: '双镀销量', unit: '万㎡',route:'/salesVolumeAnalysis/doublePlatedBase' },
{ key: 'freight', name: '双镀占比', unit: '%',route:'/salesVolumeAnalysis/doublePlatedBase' }, { key: 'freight', name: '双镀占比', unit: '%',route:'/salesVolumeAnalysis/doublePlatedBase' },
{ key: 'manageCost', name: '溢价产品销量', unit: '万㎡',route:null }, { key: 'manageCost', name: '溢价产品销量', unit: '万㎡',route:null },
{ key: 'premiumProducts', name: '溢价产品毛利', unit: '元',route:null }, { key: 'premiumProducts', name: '溢价产品毛利', unit: '元',route:null },
] ]
}, },
indicators() { indicators() {
@@ -104,7 +104,7 @@ export default {
}) })
}, },
sortedIndicators() { sortedIndicators() {
const unitOrder = ['万㎡', '元/㎡', '%','万元'] const unitOrder = ['万㎡', '元/㎡', '%','万元','元']
const unitRank = (u) => { const unitRank = (u) => {
const idx = unitOrder.indexOf(u) const idx = unitOrder.indexOf(u)
return idx === -1 ? 999 : idx return idx === -1 ? 999 : idx

View File

@@ -11,7 +11,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -25,7 +25,6 @@
<script> <script>
import Container from './container.vue' import Container from './container.vue'
import operatingSingleBar from './operatingSingleBar.vue' import operatingSingleBar from './operatingSingleBar.vue'
import verticalBarChart from './verticalBarChart.vue'
// import * as echarts from 'echarts' // import * as echarts from 'echarts'
// import rawItem from './raw-Item.vue' // import rawItem from './raw-Item.vue'
@@ -62,7 +61,7 @@ export default {
computed: { computed: {
indicatorDefs() { indicatorDefs() {
return [ return [
{ key: 'production', name: '产量', unit: '㎡'}, { key: 'production', name: '产量', unit: '㎡'},
{ key: 'financialCost', name: '销量', unit: '万㎡'}, { key: 'financialCost', name: '销量', unit: '万㎡'},
] ]
}, },

View File

@@ -12,7 +12,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.diff}}</span></span>
</div> </div>
@@ -66,7 +66,7 @@ export default {
return [ return [
{ key: 'financialCost', name: '双镀成本', unit: '元/㎡'}, { key: 'financialCost', name: '双镀成本', unit: '元/㎡'},
{ key: 'financialPrice', name: '双镀均价', unit: '元/㎡'}, { key: 'financialPrice', name: '双镀均价', unit: '元/㎡'},
{ key: 'financialProfit', name: '双镀毛利', unit: '元'}, { key: 'financialProfit', name: '双镀毛利', unit: '元'},
] ]
}, },
indicators() { indicators() {

View File

@@ -107,7 +107,7 @@ export default {
monData: {}, monData: {},
totalData: {}, totalData: {},
trend: [], trend: [],
relatedData: [], relatedData: {},
trendName: '利润总额', trendName: '利润总额',
// cusProData: {}, // cusProData: {},
}; };

View File

@@ -35,7 +35,7 @@
<div class="dropdown-options" v-if="isDropdownShow"> <div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index" <div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)"> @click.stop="selectProfit(item)">
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
</div> </div>
@@ -62,15 +62,16 @@ export default {
isDropdownShow: false, isDropdownShow: false,
selectedProfit: '利润总额', // 选中的名称初始为null selectedProfit: '利润总额', // 选中的名称初始为null
profitOptions: [ profitOptions: [
'利润总额', {name:'利润总额',unit:'万元'},
'销量', {name:'销量',unit:'万㎡'},
'单价', {name:'单价',unit:'元/㎡'},
'制造成本', {name:'制造成本',unit:'元/㎡'},
'管理费用', {name:'管理费用',unit:'万元'},
'销售费用', {name:'销售费用',unit:'万元'},
'财务费用', {name:'财务费用',unit:'万元'},
'非经营性利润', {name:'非经营性利润',unit:'万元'}
] ],
unit:'万元'
}; };
}, },
computed: { computed: {
@@ -92,6 +93,7 @@ export default {
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:this.unit,
series: [ series: [
// 1. 完成率(折线图) // 1. 完成率(折线图)
{ {
@@ -250,9 +252,10 @@ export default {
}, },
methods: { methods: {
selectProfit(item) { selectProfit(item) {
this.selectedProfit = item; this.selectedProfit = item.name;
this.unit = item.unit;
this.isDropdownShow = false; this.isDropdownShow = false;
this.$emit('handleGetItemData', item) this.$emit('handleGetItemData', item.name)
} }
}, },
}; };

View File

@@ -123,6 +123,7 @@ export default {
const data = this.currentDataSource; const data = this.currentDataSource;
const salesData = { const salesData = {
allPlaceNames: this.locations, allPlaceNames: this.locations,
unit:'万元',
series: [ series: [
// 完成率(折线图) // 完成率(折线图)
{ {

View File

@@ -119,7 +119,7 @@ export default {
return; // 实例未初始化则返回 return; // 实例未初始化则返回
} }
const { allPlaceNames, series } = this.chartData || {}; const { allPlaceNames, unit, series } = this.chartData || {};
const xData = allPlaceNames || []; const xData = allPlaceNames || [];
const chartSeries = series || []; const chartSeries = series || [];
@@ -166,7 +166,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '万元', name: unit,
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -13,7 +13,7 @@
<div class="title"> <div class="title">
{{ item.name }}·{{ item.unit }} {{ item.name }}·{{ item.unit }}
</div> </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>完成率:<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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.data.completed>0?'#30B590':'#FF9423'}" >{{item.data.diffValue}}</span></span>
</div> </div>
@@ -61,7 +61,8 @@ export default {
return { return {
chart: null, chart: null,
// 核心:当前激活的数据集(月度/累计),默认初始化月度数据 // 核心:当前激活的数据集(月度/累计),默认初始化月度数据
activeData: this.relatedData.relatedMon || [] activeData: this.relatedData.relatedMon || [],
currentTab: 'month'
} }
}, },
computed: { computed: {
@@ -109,7 +110,12 @@ export default {
// 可选:监听 relatedData 初始变化(若父组件异步传递数据,确保 activeData 同步更新) // 可选:监听 relatedData 初始变化(若父组件异步传递数据,确保 activeData 同步更新)
relatedData: { relatedData: {
handler(newVal) { handler(newVal) {
if (this.currentTab === 'month') {
this.activeData = newVal.relatedMon || []; this.activeData = newVal.relatedMon || [];
}else{
this.activeData = newVal.relatedTotal || [];
}
}, },
immediate: true, immediate: true,
deep: true deep: true
@@ -134,6 +140,7 @@ export default {
*/ */
handleChange(value) { handleChange(value) {
console.log('Tab 切换值:', value); console.log('Tab 切换值:', value);
this.currentTab = value;
// 根据 Tab 值更新当前激活的数据集 // 根据 Tab 值更新当前激活的数据集
if (value === 'month') { if (value === 'month') {
// 切换为月度数据 // 切换为月度数据

View File

@@ -3,54 +3,20 @@
<Container :name="title" icon="cockpitItemIcon" size="operatingRevenueBg" topSize="middle"> <Container :name="title" icon="cockpitItemIcon" size="operatingRevenueBg" topSize="middle">
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;"> <div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
<div class="topItem-container" style="display: flex; gap: 8px;"> <div class="topItem-container" style="display: flex; gap: 8px;">
<!-- 销量图表传递销量数据 + 完成率flag --> <div
<div class="dashboard left" @click="handleDashboardClick('/salesVolumeAnalysis/salesVolumeAnalysisBase')"> v-for="item in sortedIndicators"
:key="item.key"
class="dashboard"
@click="item.route && handleDashboardClick(item.route)"
>
<div class="title"> <div class="title">
销量· {{ item.name }}·{{ item.unit }}
</div> </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;'>{{relatedMon.销量.completeRate}}%</span></span> <span>完成率:<span style='color: #0B58FF;'>{{item.detailData.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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.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> </div>
<operatingSingleBar :detailData="item.detailData"></operatingSingleBar>
</div> </div>
</div> </div>
</div> </div>
@@ -69,7 +35,7 @@ export default {
type: Object, type: Object,
default: () => ({ 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 },
销量: { 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: { watch: {
relatedMon: { relatedMon: {
handler(newValue) { handler(newValue) {

View File

@@ -168,7 +168,7 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '元', name: '元/㎡',
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -112,7 +112,7 @@ export default {
// 左侧Y轴营业收入、成本单位万元 // 左侧Y轴营业收入、成本单位万元
{ {
type: 'value', type: 'value',
name: '元', name: '元/㎡',
nameTextStyle: { nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)', color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12, fontSize: 12,

View File

@@ -66,27 +66,11 @@ export default {
const option = { const option = {
tooltip: { tooltip: {
trigger: 'axis', 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: { grid: {
top: 25, top: 25,
bottom: 25, bottom: 25,
right: 0, right: 5,
left: 2, left: 2,
containLabel: true containLabel: true
}, },

View File

@@ -6,7 +6,6 @@
<script> <script>
import operatingLineBarSaleSingle from './operatingLineBarSaleSingle.vue'; import operatingLineBarSaleSingle from './operatingLineBarSaleSingle.vue';
import * as echarts from 'echarts';
export default { export default {
name: "Container", name: "Container",

View File

@@ -8,7 +8,6 @@
<script> <script>
import operatingLineBar from './operatingLineBarSaleGroup.vue'; import operatingLineBar from './operatingLineBarSaleGroup.vue';
import * as echarts from 'echarts';
export default { export default {
name: "Container", name: "Container",

View File

@@ -3,53 +3,20 @@
<Container :name="title" icon="cockpitItemIcon" size="operatingRevenueBg" topSize="middle"> <Container :name="title" icon="cockpitItemIcon" size="operatingRevenueBg" topSize="middle">
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;"> <div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
<div class="topItem-container" style="display: flex; gap: 8px;"> <div class="topItem-container" style="display: flex; gap: 8px;">
<!-- 销量图表传递销量数据 + 完成率flag --> <div
<div class="dashboard left" @click="handleDashboardClick('/salesVolumeAnalysis/salesVolumeAnalysisBase')"> v-for="item in sortedIndicators"
:key="item.key"
class="dashboard"
@click="item.route && handleDashboardClick(item.route)"
>
<div class="title"> <div class="title">
销量· {{ item.name }}·{{ item.unit }}
</div> </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;'>{{relatedTotal.销量.completeRate}}%</span></span> <span>完成率:<span style='color: #0B58FF;'>{{item.detailData.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> <span style='display: inline-block;margin-left: 10px;'>差值:<span :style="{color:item.detailData.flag>0?'#30B590':'#FF9423'}" >{{item.detailData.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> </div>
<operatingSingleBar :detailData="item.detailData"></operatingSingleBar>
</div> </div>
</div> </div>
</div> </div>
@@ -69,7 +36,7 @@ export default {
type: Object, type: Object,
default: () => ({ 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 },
销量: { 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: { watch: {
relatedTotal: { relatedTotal: {
handler(newValue) { handler(newValue) {