Files
l2-g30/src/views/l2/track/components/FurCurrent.vue
砂糖 a96c3ae8a3 feat(跟踪): 添加炉火实时参数组件并优化界面
refactor(登录): 调整登录页logo布局样式
fix(钢种管理): 为详情面板添加加载状态
style(发送历史): 调整表格列宽配置
2026-01-03 11:16:36 +08:00

155 lines
4.3 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="app-container">
<h3>炉火实时参数</h3>
<!-- flex布局容器开启自动换行 -->
<div class="params-list">
<!-- 遍历驱动数据的所有键值对 -->
<div
v-for="[key, value] in Object.entries(driveData)"
:key="key"
:class="['param-item', { blink: changedKeys.includes(key) }]"
>
<!-- 上方label -->
<span class="param-label">{{ formatLabel(key) }}</span>
<!-- 下方value -->
<span class="param-value">{{ formatValue(value) }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'FurCurrent',
props: {
driveData: {
type: Object,
default: () => ({})
}
},
data() {
return {
prevDriveData: {}, // 存储上一次的驱动数据,用于对比变化
changedKeys: [] // 存储当前变化的属性名,用于控制闪烁样式
}
},
watch: {
driveData: {
handler(newVal) {
if (Object.keys(this.prevDriveData).length === 0) {
// 首次加载数据,仅缓存数据,不触发闪烁
this.prevDriveData = JSON.parse(JSON.stringify(newVal));
return;
}
// 对比新值和旧值,找出变化的属性名
const changedKeys = [];
Object.entries(newVal).forEach(([key, value]) => {
// 排除首次不存在的属性,仅对比已有属性的变化
if (this.prevDriveData.hasOwnProperty(key)) {
// 由于是数字类型,直接对比值是否不同
if (this.prevDriveData[key] !== value) {
changedKeys.push(key);
}
}
});
if (changedKeys.length > 0) {
this.changedKeys = changedKeys; // 设置变化的属性,触发闪烁
// 1秒后清空变化的属性移除闪烁样式
setTimeout(() => {
this.changedKeys = [];
}, 1000);
}
// 更新缓存的旧数据
this.prevDriveData = JSON.parse(JSON.stringify(newVal));
console.log('driveData updated:', newVal, 'changed keys:', changedKeys);
},
deep: true
}
},
methods: {
// 格式化标签名(将驼峰命名转为中文式分段,提升可读性)
formatLabel(key) {
if (!key) return '';
// 驼峰命名转空格分隔
const result = key.replace(/([A-Z])/g, ' $1');
// 首字母大写
return result.charAt(0).toUpperCase() + result.slice(1);
},
// 格式化值数字类型保留4位小数提升展示美观度
formatValue(value) {
if (typeof value === 'number') {
return value.toFixed(4);
}
return value;
}
}
}
</script>
<style scoped>
.app-container {
border-radius: 8px;
min-height: 100vh;
}
/* flex布局容器 - 开启换行 */
.params-list {
display: flex;
flex-wrap: wrap; /* flex自动换行核心属性 */
gap: 16px; /* 项目之间的间距(水平+垂直) */
margin-top: 20px;
}
/* 固定宽度的参数项 - 内部上下布局 */
.param-item {
width: 200px; /* 固定宽度,可根据需求调整 */
padding: 12px 16px;
background-color: #ffffff;
border: 1px solid #e6e6e6;
border-radius: 6px;
transition: all 0.3s ease;
display: flex; /* 内部flex垂直布局 */
flex-direction: column; /* 垂直排列label在上value在下 */
align-items: flex-start; /* 左对齐可改为center居中 */
gap: 8px; /* label和value之间的垂直间距 */
}
.param-label {
font-weight: 500;
color: #333333;
font-size: 14px;
word-wrap: break-word; /* 超长label自动换行 */
}
.param-value {
color: #666666;
font-family: 'Courier New', monospace; /* 等宽字体,数字对齐更美观 */
font-size: 15px;
}
/* 闪烁动画定义 */
@keyframes borderBlink {
0% {
border-color: #4cd964; /* 初始绿色 */
box-shadow: 0 0 0 0 rgba(76, 217, 100, 0.2);
}
50% {
border-color: #28a745; /* 深绿色 */
box-shadow: 0 0 8px 2px rgba(76, 217, 100, 0.5);
}
100% {
border-color: #4cd964; /* 恢复初始绿色 */
box-shadow: 0 0 0 0 rgba(76, 217, 100, 0.2);
}
}
/* 闪烁样式 */
.blink {
border: 2px solid #4cd964; /* 绿色边框 */
animation: borderBlink 1s ease-in-out; /* 执行闪烁动画 */
}
</style>