251 lines
5.8 KiB
Vue
251 lines
5.8 KiB
Vue
<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: 191px;
|
||
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 "./dataTrendBarFuel.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>
|