feat: 添加PDF和图片生成库并优化打印功能

refactor(FurCurrent): 重构参数显示逻辑,优化闪烁效果
style(FurnaceHistoryPanel): 调整表格列宽和溢出处理
feat(LabelPrint): 使用dom-to-image提升打印质量
feat(QualityCertificate): 添加生产过程曲线图表
feat: 新增ParamEcharts组件用于统一图表渲染
refactor(line): 使用ParamEcharts重构监控图表组件
This commit is contained in:
砂糖
2026-01-03 13:37:27 +08:00
parent a96c3ae8a3
commit 98678cc043
7 changed files with 685 additions and 580 deletions

View File

@@ -1,14 +1,13 @@
<template>
<!-- 炉火参数表单 -->
<div class="app-container">
<h3>炉火实时参数</h3>
<!-- flex布局容器开启自动换行 -->
<div class="params-list">
<!-- 遍历驱动数据的所有键值对 -->
<!-- 遍历筛选后的驱动数据键值对 -->
<div
v-for="[key, value] in Object.entries(driveData)"
v-for="[key, value] in filteredDriveData"
:key="key"
:class="['param-item', { blink: changedKeys.includes(key) }]"
:class="['param-item', { blink: blinkKeyMap[key] }]"
>
<!-- 上方label -->
<span class="param-label">{{ formatLabel(key) }}</span>
@@ -31,7 +30,20 @@ export default {
data() {
return {
prevDriveData: {}, // 存储上一次的驱动数据,用于对比变化
changedKeys: [] // 存储当前变化的属性名,用于控制闪烁样式
blinkKeyMap: {}, // 每个key独立的闪烁状态对象形式{ key1: true, key2: false }
timerMap: {} // 每个key独立的定时器缓存用于清除旧定时器
}
},
// 筛选包含Actual不区分大小写的键值对
computed: {
filteredDriveData() {
// 校验
if (!this.driveData || typeof this.driveData !== 'object') {
return [];
}
return Object.entries(this.driveData).filter(([key]) => {
return key.toLowerCase().includes('actual');
});
}
},
watch: {
@@ -44,33 +56,39 @@ export default {
}
// 对比新值和旧值,找出变化的属性名
const changedKeys = [];
Object.entries(newVal).forEach(([key, value]) => {
// 排除首次不存在的属性,仅对比已有属性的变化
if (this.prevDriveData.hasOwnProperty(key)) {
// 由于是数字类型,直接对比值是否不同
// 仅对比已有属性的变化且仅处理筛选后的key包含Actual
if (this.prevDriveData.hasOwnProperty(key) && key.toLowerCase().includes('actual')) {
if (this.prevDriveData[key] !== value) {
changedKeys.push(key);
this.triggerBlink(key); // 为每个变化的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: {
// 单独触发某个key的闪烁核心优化独立控制
triggerBlink(key) {
// 清除该key的旧定时器避免1秒内多次更新导致定时器叠加
if (this.timerMap[key]) {
clearTimeout(this.timerMap[key]);
}
// 设置当前key为闪烁状态触发动画
this.$set(this.blinkKeyMap, key, true);
// 单独为该key设置定时器到期后关闭闪烁状态
this.timerMap[key] = setTimeout(() => {
this.$set(this.blinkKeyMap, key, false);
// 定时器执行后清除缓存的定时器ID
delete this.timerMap[key];
}, 500); // 闪烁时长可自定义1秒
},
// 格式化标签名(将驼峰命名转为中文式分段,提升可读性)
formatLabel(key) {
if (!key) return '';
@@ -86,6 +104,12 @@ export default {
}
return value;
}
},
// 组件销毁时清除所有定时器,避免内存泄漏
beforeUnmount() {
Object.values(this.timerMap).forEach(timer => {
clearTimeout(timer);
});
}
}
</script>
@@ -109,7 +133,7 @@ export default {
width: 200px; /* 固定宽度,可根据需求调整 */
padding: 12px 16px;
background-color: #ffffff;
border: 1px solid #e6e6e6;
border: 2px solid #e6e6e6;
border-radius: 6px;
transition: all 0.3s ease;
display: flex; /* 内部flex垂直布局 */
@@ -131,7 +155,7 @@ export default {
font-size: 15px;
}
/* 闪烁动画定义 */
/* 闪烁动画定义(保留原有动画效果,优化触发逻辑) */
@keyframes borderBlink {
0% {
border-color: #4cd964; /* 初始绿色 */
@@ -147,9 +171,9 @@ export default {
}
}
/* 闪烁样式 */
/* 闪烁样式每次blink类添加时动画重新触发 */
.blink {
border: 2px solid #4cd964; /* 绿色边框 */
animation: borderBlink 1s ease-in-out; /* 执行闪烁动画 */
animation: borderBlink 0.5s ease-in-out 1; /* 强制执行1次动画避免叠加 */
}
</style>