310 lines
7.0 KiB
Vue
310 lines
7.0 KiB
Vue
<template>
|
||
<div class="coreItem">
|
||
<div class="item" :class="`item${index + 1}`" @click="handleItemClick(index)" v-for="(item, index) in itemList"
|
||
:key="index">
|
||
<div class="unit">{{ item.unit }}</div>
|
||
<div class="item-content">
|
||
<div class="content-wrapper">
|
||
<div class="left">
|
||
<div class="number">{{ item.target }}</div>
|
||
<div class="title">目标值</div>
|
||
</div>
|
||
<div class="line"></div>
|
||
<div class="right">
|
||
<!-- 实际值颜色动态绑定 -->
|
||
<div class="number" :style="{ color: getColor(index) }">
|
||
{{ item.actual }}
|
||
</div>
|
||
<div class="title">实际值</div>
|
||
</div>
|
||
</div>
|
||
<div class="progress-group">
|
||
<div class="progress-container">
|
||
<!-- 进度条样式动态绑定 -->
|
||
<div class="progress-bar" :style="{
|
||
width: `${item.progress}%`,
|
||
background: getColor(index)
|
||
}"></div>
|
||
</div>
|
||
<!-- 百分比颜色动态绑定 -->
|
||
<div class="progress-percent" :style="{ color: getColor(index) }">
|
||
{{ item.progress }}%
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "Container",
|
||
components: {},
|
||
// 接收父组件传递过来的原始 itemList 对象
|
||
props: ['rawItemList','dateData'],
|
||
data() {
|
||
return {
|
||
// 组件内部用于渲染的数组
|
||
itemList: [],
|
||
activeIndex: -1
|
||
};
|
||
},
|
||
// 监听 props 中的 rawItemList 变化
|
||
watch: {
|
||
rawItemList: {
|
||
handler(newVal) {
|
||
if (newVal) {
|
||
this.itemList = this.transformData(newVal);
|
||
}
|
||
},
|
||
immediate: true, // 组件初始化时立即执行一次
|
||
deep: true // 深度监听对象内部变化
|
||
}
|
||
},
|
||
methods: {
|
||
/**
|
||
* 核心转换函数:将对象转换为组件需要的数组格式
|
||
* @param {Object} rawData - 父组件传递的原始数据对象
|
||
* @returns {Array} - 转换后的数组
|
||
*/
|
||
transformData(rawData) {
|
||
// 定义一个映射关系,将后端字段名与前端显示信息关联起来
|
||
const dataMap = [
|
||
{
|
||
key: 'processCost',
|
||
unit: '制造成本·元/㎡',
|
||
route: '/productionCostAnalysis/productionCostAnalysis'
|
||
},
|
||
{
|
||
key: 'rawCost',
|
||
unit: '原片成本·元/㎡',
|
||
route: '/productionCostAnalysis/originalSheetCost'
|
||
},
|
||
{
|
||
key: 'processCost',
|
||
unit: '加工成本·元/㎡',
|
||
route: '/productionCostAnalysis/processingCostAnalysis'
|
||
},
|
||
{
|
||
key: 'rawYield',
|
||
unit: '原片成品率·%',
|
||
route: '/rawSheetYield/rawSheetYield' // 假设这个没有路由
|
||
},
|
||
{
|
||
key: 'ioYield',
|
||
unit: '投入产出率·%',
|
||
route: '/inputOutputRatio/inputOutputRatio' // 假设这个没有路由
|
||
}
|
||
];
|
||
|
||
// 使用 map 方法将 dataMap 数组转换为组件需要的 itemList 数组
|
||
return dataMap.map(itemInfo => {
|
||
const rawItem = rawData[itemInfo.key] || {};
|
||
// 计算进度百分比,确保不小于0
|
||
const progress = Math.max(0, Math.round((rawItem.rate || 0)));
|
||
|
||
return {
|
||
unit: itemInfo.unit,
|
||
route: itemInfo.route,
|
||
target: rawItem.target || 0,
|
||
actual: rawItem.real || 0,
|
||
progress: progress
|
||
};
|
||
});
|
||
},
|
||
|
||
handleItemClick(index) {
|
||
const currentItem = this.itemList[index];
|
||
console.log(`点击了第${index + 1}个item:`, currentItem.unit);
|
||
this.$emit('item-click', { index, ...currentItem });
|
||
this.activeIndex = index;
|
||
if (currentItem.route) {
|
||
this.$router.push({
|
||
path: currentItem.route,
|
||
query: {
|
||
dateData: this.dateData
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
// 判断颜色的方法
|
||
getColor(index) {
|
||
const { actual, target, progress } = this.itemList[index];
|
||
|
||
// 新增条件:如果实际值、目标值和进度都为0,则显示绿色
|
||
if (actual === 0 && target === 0 && progress === 0) {
|
||
return "rgba(98, 213, 180, 1)"; // 绿色
|
||
}
|
||
|
||
// 原有的通用判断逻辑
|
||
return progress >= 100
|
||
? "rgba(98, 213, 180, 1)" // 绿色
|
||
: "rgba(249, 164, 74, 1)"; // 橙色
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
/* (你的样式代码保持不变) */
|
||
.coreItem {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.coreItem> :nth-child(1) {
|
||
grid-area: item1;
|
||
|
||
&:hover {
|
||
box-shadow: 0px 4px 12px 2px #B5CDE5;
|
||
}
|
||
}
|
||
|
||
.coreItem> :nth-child(2) {
|
||
grid-area: item2;
|
||
|
||
&:hover {
|
||
box-shadow: 0px 4px 12px 2px #B5CDE5;
|
||
}
|
||
}
|
||
|
||
.coreItem> :nth-child(3) {
|
||
grid-area: item3;
|
||
|
||
&:hover {
|
||
box-shadow: 0px 4px 12px 2px #B5CDE5;
|
||
}
|
||
}
|
||
|
||
.coreItem> :nth-child(4) {
|
||
grid-area: item4;
|
||
&:hover {
|
||
box-shadow: 0px 4px 12px 2px #B5CDE5;
|
||
}
|
||
}
|
||
|
||
.coreItem> :nth-child(5) {
|
||
grid-area: item5;
|
||
&:hover {
|
||
box-shadow: 0px 4px 12px 2px #B5CDE5;
|
||
}
|
||
}
|
||
|
||
.item {
|
||
width: 252px;
|
||
height: 110px;
|
||
background: #f9fcff;
|
||
padding: 12px;
|
||
box-sizing: border-box;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
.unit {
|
||
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;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.item-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
height: calc(100% - 26px);
|
||
}
|
||
|
||
.content-wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-around;
|
||
flex: 1;
|
||
}
|
||
|
||
.line {
|
||
width: 1px;
|
||
height: 46px;
|
||
background: linear-gradient(to bottom,
|
||
rgba(255, 0, 0, 0),
|
||
#cbcbcb);
|
||
}
|
||
|
||
.left,
|
||
.right {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 2px;
|
||
flex: 1;
|
||
}
|
||
|
||
.number {
|
||
height: 22px;
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 600;
|
||
font-size: 24px;
|
||
color: rgba(103, 103, 103, 0.79);
|
||
line-height: 22px;
|
||
text-align: center;
|
||
font-style: normal;
|
||
}
|
||
|
||
.title {
|
||
height: 14px;
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 12px;
|
||
color: #868687;
|
||
line-height: 14px;
|
||
text-align: center;
|
||
font-style: normal;
|
||
}
|
||
|
||
.progress-group {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.progress-container {
|
||
width: 190px;
|
||
height: 10px;
|
||
background: #ECEFF7;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.progress-bar {
|
||
height: 100%;
|
||
border-radius: 8px;
|
||
transition: width 0.3s ease;
|
||
}
|
||
|
||
.progress-percent {
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 12px;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
|
||
.item1,
|
||
.item2,
|
||
.item3 {
|
||
width: 166px;
|
||
}
|
||
</style>
|