Files
yudao-dev/src/views/home/components/financeCostsBottomBar.vue
2026-03-31 15:13:13 +08:00

282 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="coreBar">
<div class="barTop">
<div class="barTop-left" style="display: flex;">
<div class="title">财务指标趋势</div>
<div class="legend">
<span class="legend-item target">预算</span>
<span class="legend-item real">实际</span>
</div>
</div>
<div class="button-group">
<div style="width: 59px;" class="item-button" :class="{ active: activeButton === 0 }" @click="activeButton = 0">
营业收入
</div>
<div class="button-line lineOne" v-if="activeButton !== 0 && activeButton !== 1"></div>
<div style="width: 75px;" class="item-button" :class="{ active: activeButton === 1 }" @click="activeButton = 1">
经营性利润
</div>
<div class="button-line lineTwo" v-if="activeButton !== 1 && activeButton !== 2"></div>
<div class="item-button" :class="{ active: activeButton === 2 }" @click="activeButton = 2">
利润总额
</div>
<div class="button-line lineThree" v-if="activeButton !== 2 && activeButton !== 3"></div>
<div class="item-button" :class="{ active: activeButton === 3 }" @click="activeButton = 3">
毛利率
</div>
<div class="button-line lineFour" v-if="activeButton !== 3 && activeButton !== 4"></div>
<div class="item-button" :class="{ active: activeButton === 4 }" @click="activeButton = 4">
应收账款
</div>
<div class="button-line lineFive" v-if="activeButton !== 4 && activeButton !== 5"></div>
<div class="item-button" :class="{ active: activeButton === 5 }" @click="activeButton = 5">
存货
</div>
</div>
</div>
<div class="lineBottom" style="height: 184px; width: 100%">
<!-- 传递当前选中的 series 数据和 xAxis 数据给子组件 -->
<coreLineChart style="height: 184px; width: 680px" :chart-series="currentSeries" :x-axis-data="xAxisData"
:dateData="dateData" />
</div>
</div>
</template>
<script>
import coreLineChart from './coresBar.vue';
import * as echarts from 'echarts';
export default {
name: "Container",
components: { coreLineChart },
props: {
line: { // 接收父组件传递的 line 数据
type: Object,
default: () => ({})
},
dateData: { // 接收父组件传递的 line 数据
type: Object,
default: () => ({})
},
},
data() {
return {
activeButton: 0, // 初始激活第一个按钮索引0
// 定义按钮与 line 数据中 key 的映射关系
buttonToDataKey: [
{name:'营业收入',unit:'万元'},
{name:'经营性利润',unit:'万元'},
{name:'利润总额',unit:'万元'},
{name:'毛利率',unit:'%'},
{name:'应收账款',unit:'万元'},
{name:'存货',unit:'万元'}
]
};
},
computed: {
// 根据当前激活的按钮,动态生成对应的 series 数据
currentSeries() {
const dataKey = this.buttonToDataKey[this.activeButton].name;
const chartData = this.line[dataKey];
if (!chartData) {
return {};
}
// 提取目标和实际数据的值
const targetDataValues = Object.values(chartData.target || {});
const realDataValues = Object.values(chartData.real || {});
let obj = {
unit: this.buttonToDataKey[this.activeButton].unit,
series:[
{
name: '预算',
type: 'line',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
itemStyle: { color: 'rgba(91, 230, 190, 1)', borderColor: 'rgba(91, 230, 190, 1)', borderWidth: 2 },
areaStyle: {
opacity: 0.3,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(91, 230, 190, 0.4)' },
{ offset: 1, color: 'rgba(91, 230, 190, 0)' },
]),
},
data: targetDataValues
},
{
name: '实际',
type: 'line',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
itemStyle: { color: 'rgba(255, 132, 0, 1)', borderColor: 'rgba(255, 132, 0, 1)', borderWidth: 2 },
areaStyle: {
opacity: 0.3,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(255, 132, 0, 0.4)' },
{ offset: 1, color: 'rgba(255, 132, 0, 0)' },
]),
},
data: realDataValues
}
]}
return obj;
},
// 提取 x 轴数据(日期)
xAxisData() {
const dataKey = this.buttonToDataKey[this.activeButton].name;
const chartData = this.line[dataKey];
// 使用 'target' 的键作为 x 轴,如果 'target' 不存在,则使用 'real' 的键
if (chartData && chartData.target) {
return Object.keys(chartData.target);
} else if (chartData && chartData.real) {
return Object.keys(chartData.real);
}
return [];
}
},
methods: {}
};
</script>
<style scoped lang="scss">
/* 原有样式保持不变 */
.coreBar {
display: flex;
flex-direction: column;
padding: 12px;
.barTop {
display: flex;
gap: 8px;
justify-content: space-between;
.title {
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;
}
.legend {
display: flex;
gap: 24px;
margin-left: 30px;
.legend-item {
position: relative;
font-family: PingFangSC, PingFang SC;
font-size: 14px;
color: rgba(0, 0, 0, 0.8);
&::before {
content: "";
position: absolute;
left: -13px;
top: 30%;
width: 6px;
height: 6px;
border-radius: 50%;
}
&::after {
content: "";
position: absolute;
left: -16px;
top: 38%;
width: 12px;
height: 2px;
}
}
.target::before,
.target::after {
background-color: rgba(91, 230, 190, 1);
}
.real::before,
.real::after {
background-color: rgba(255, 132, 0, 1);
}
}
.button-group {
display: flex;
position: relative;
gap: 2px;
width: 350px;
align-items: center;
height: 24px;
background: #ecf4fe;
border-radius: 12px;
.button-line {
position: absolute;
width: 1px;
height: 14px;
border: 1px solid rgba(11, 88, 255, 0.25);
}
.lineOne {
top: 6px;
left: 59px;
}
.lineTwo {
top: 6px;
left: 131px;
}
.lineThree {
top: 6px;
left: 190px;
}
.lineFour {
top: 6px;
left: 238px;
}
.lineFive {
top: 6px;
left: 302px;
}
.item-button {
cursor: pointer;
width: 54px;
height: 24px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #0b58ff;
line-height: 24px;
text-align: center;
font-style: normal;
}
.item-button.active {
width: 54px;
height: 24px;
background: #3071ff;
border-radius: 12px;
color: #ffffff;
font-weight: 500;
}
}
}
}
</style>