Files
yudao-dev/src/views/home/rawSheetYieldComponents/dataTrendBar.vue
‘937886381’ 5605eeab06 xiugai
2026-01-06 13:48:11 +08:00

467 lines
13 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">
<!-- 新增行容器包裹各基地情况和barTop -->
<div class="header-row">
<div class="barTop">
<!-- 关键新增右侧容器包裹图例和按钮组实现整体靠右 -->
<div class="right-container">
<div class="legend">
<span class="legend-item">
<span class="legend-icon line yield"></span>
完成率
</span>
<span class="legend-item">
<span class="legend-icon square target"></span>
预算
</span>
<span class="legend-item">
<span class="legend-icon square achieved"></span>
实际·达标
</span>
<span class="legend-item">
<span class="legend-icon square unachieved"></span>
实际·未达标
</span>
</div>
<div class="button-group">
<div class="item-button category-btn">
<span class="item-text">类目选择</span>
</div>
<div class="dropdown-container">
<div class="item-button profit-btn active" @click.stop="isDropdownShow = !isDropdownShow">
<span class="item-text profit-text">{{ selectedProfit || '请选择' }}</span>
<span class="dropdown-arrow" :class="{ 'rotate': isDropdownShow }"></span>
</div>
<div class="dropdown-options" v-if="isDropdownShow">
<div class="dropdown-option" v-for="(item, index) in profitOptions" :key="index"
@click.stop="selectProfit(item)">
{{ item }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="lineBottom" style="height: 100%; width: 100%">
<operatingLineBar :chartData="chartD" style="height: 99%; width: 100%" />
</div>
</div>
</template>
<script>
import operatingLineBar from './operatingLineBarSale.vue';
import * as echarts from 'echarts';
export default {
name: "Container",
components: { operatingLineBar },
props: ["chartData"],
data() {
return {
activeButton: 0,
isDropdownShow: false,
selectedProfit: null, // 选中的名称初始为null
profitOptions: [
'原片成品率',
'原片产量',
'拉引量',
]
};
},
computed: {
// profitOptions() {
// return this.categoryData.map(item => item.name) || [];
// },
currentDataSource() {
console.log('yyyy', this.chartData);
return this.chartData
},
locations() {
console.log('this.chartData', this.chartData);
return this.chartData.months
},
// 根据按钮切换生成对应的 chartData
chartD() {
const data = this.currentDataSource;
console.log(this.currentDataSource, 'currentDataSource');
const salesData = {
allPlaceNames: this.locations,
series: [
// 1. 完成率(折线图)
{
name: '完成率',
type: 'line',
yAxisIndex: 1, // 绑定右侧Y轴需在子组件启用配置
lineStyle: {
color: 'rgba(40, 138, 255, .5)',
width: 2
},
itemStyle: {
color: 'rgba(40, 138, 255, 1)',
borderColor: 'rgba(40, 138, 255, 1)',
borderWidth: 2,
radius: 4
},
areaStyle: {
opacity: 0.2,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(40, 138, 255, .9)' },
{ offset: 1, color: 'rgba(40, 138, 255, 0)' }
])
},
data: data.rates, // 完成率(%
symbol: 'circle',
symbolSize: 6
},
// 2. 目标(柱状图)
{
name: '预算',
type: 'bar',
yAxisIndex: 0, // 左侧Y轴万元
barWidth: 14,
itemStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(130, 204, 255, 1)' },
{ offset: 1, color: 'rgba(75, 157, 255, 1)' }
]
},
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: data.budgets // 目标销量(万元)
},
// 3. 实际(柱状图,含达标状态)
{
name: '实际',
type: 'bar',
yAxisIndex: 0,
barWidth: 14,
label: {
show: true,
position: 'top',
offset: [0, 0],
// 固定label尺寸68px×20px
width: 68,
height: 20,
// 关键:去掉换行,让文字在一行显示,适配小尺寸
formatter: function (params) {
const diff = data.diffs || [];
const currentDiff = diff[params.dataIndex] || 0;
return `{rate|${currentDiff}}{text|差值}`;
},
backgroundColor: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(205, 215, 224, 0.6)' }, // 顶部0px位置阴影最强
// { offset: 0.1, color: 'rgba(205, 215, 224, 0.4)' }, // 1px位置阴影减弱对应1px
// { offset: 0.15, color: 'rgba(205, 215, 224, 0.6)' }, // 3px位置阴影几乎消失对应3px扩散
{ offset: 0.2, color: '#ffffff' }, // 主体白色
{ offset: 1, color: '#ffffff' }
]
},
// 外阴影0px 2px 2px 0px rgba(191,203,215,0.5)
shadowColor: 'rgba(191,203,215,0.5)',
shadowBlur: 2,
shadowOffsetX: 0,
shadowOffsetY: 2,
// 圆角4px
borderRadius: 4,
// 移除边框
borderColor: '#BFCBD577',
borderWidth: 0,
// 文字垂直居中(针对富文本)
lineHeight: 20,
rich: {
text: {
// 缩小宽度和内边距适配68px容器
width: 'auto', // 自动宽度替代固定40px
padding: [5, 10, 5, 0], // 缩小内边距
align: 'center',
color: '#464646', // 文字灰色
fontSize: 11, // 缩小字体,适配小尺寸
lineHeight: 20 // 垂直居中
},
rate: {
width: 'auto',
padding: [5, 0, 5, 10],
align: 'center',
color: '#30B590',
fontSize: 11,
lineHeight: 20
}
}
},
itemStyle: {
color: (params) => {
// 达标状态1=达标绿色0=未达标(橙色)
const safeFlag = data.flags;
const currentFlag = safeFlag[params.dataIndex] || 0;
return currentFlag === 1
? {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(174, 239, 224, 1)' },
{ offset: 1, color: 'rgba(118, 218, 190, 1)' }
]
}
: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(253, 209, 129, 1)' },
{ offset: 1, color: 'rgba(249, 164, 74, 1)' }
]
};
},
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: data.reals // 实际销量(万元)
}
]
};
// 根据按钮状态返回对应数据
return salesData;
}
},
methods: {
selectProfit(item) {
this.selectedProfit = item;
this.isDropdownShow = false;
this.$emit("changeItem", item);
}
},
};
</script>
<style scoped lang="scss">
.coreBar {
display: flex;
flex-direction: column;
width: 100%;
padding: 12px;
// 新增:头部行容器,实现一行排列
.header-row {
display: flex;
justify-content: flex-end; // 左右两端对齐
align-items: center; // 垂直居中
// width: 100%;
margin-bottom: 8px; // 与下方图表区保留间距(可根据需求调整))
}
// 各基地情况标题样式
.base-title {
font-weight: 400;
font-size: 18px;
color: #000000;
line-height: 18px;
letter-spacing: 1px;
font-style: normal;
padding: 0 0 0 16px; // 保留原有内边距
white-space: nowrap; // 防止文字换行
}
.barTop {
// 移除原有flex和justify-content由header-row控制
width: auto; // 自适应宽度
// 保留原有align-items确保内部元素垂直居中
align-items: center;
gap: 16px;
// 1. 右侧容器:包裹图例和按钮组,整体靠右
.right-container {
display: flex;
align-items: center; // 图例和按钮组垂直居中
gap: 24px; // 图例与按钮组的间距,避免贴紧
margin-right: 46px; // 右侧整体留边,与原按钮组边距一致
}
// 2. 图例:在右侧容器内横向排列
.legend {
display: flex;
gap: 16px; // 图例项之间间距,避免重叠
align-items: center;
margin: 0;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: rgba(0, 0, 0, 0.8);
text-align: left;
font-style: normal;
white-space: nowrap; // 防止图例文字换行
}
.legend-icon {
display: inline-block;
}
.legend-icon.line {
width: 12px;
height: 2px;
position: relative;
&::before {
position: absolute;
content: "";
top: -2px;
left: 3px;
width: 6px;
border-radius: 50%;
height: 6px;
background-color: rgba(40, 138, 255, 1);
}
}
.legend-icon.square {
width: 8px;
height: 8px;
}
// 图例颜色
.yield {
background: rgba(40, 138, 255, 1);
}
.target {
background: #2889FF;
}
.achieved {
background: rgba(40, 203, 151, 1);
}
.unachieved {
background: rgba(255, 132, 0, 1);
}
// 3. 按钮组:在右侧容器内,保留原有样式
.button-group {
display: flex;
position: relative;
gap: 2px;
align-items: center;
height: 24px;
background: #ecf4fe;
margin: 0;
.dropdown-container {
position: relative;
z-index: 10;
}
.item-button {
cursor: pointer;
height: 24px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
line-height: 24px;
font-style: normal;
letter-spacing: 2px;
overflow: hidden;
.item-text {
display: inline-block;
}
}
.category-btn {
width: 75px;
border-top-left-radius: 12px;
border-bottom-left-radius: 12px;
background: #ffffff;
color: #0b58ff;
text-align: center;
}
.profit-btn {
width: 123px;
border-top-right-radius: 12px;
border-bottom-right-radius: 12px;
position: relative;
padding: 0 18px 0 8px;
background: #ffffff;
color: #0b58ff;
text-align: left;
&.active {
background: #3071ff;
color: rgba(249, 252, 255, .8);
}
.profit-text {
text-align: left;
width: 100%;
}
}
.dropdown-arrow {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
width: 0;
height: 0;
border-left: 6px solid currentColor;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-right: 4px solid transparent;
transition: transform 0.2s ease;
&.rotate {
transform: rotate(90deg);
}
}
.dropdown-options {
position: absolute;
top: 100%;
right: 0;
margin-top: 2px;
width: 123px;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
.dropdown-option {
padding: 6px 12px;
font-size: 12px;
color: #333;
cursor: pointer;
text-align: left;
letter-spacing: 1px;
&:hover {
background: #f5f7fa;
color: #3071ff;
}
}
}
}
}
}
</style>