修改G30二级内容

This commit is contained in:
2025-12-26 17:08:15 +08:00
parent d15660c731
commit 17e733333c
46 changed files with 4171 additions and 1976 deletions

View File

@@ -6,218 +6,256 @@
:rules="formRules"
>
<el-row :gutter="20">
<!-- 成品卷 -->
<!-- Finished Coil / 成品卷 -->
<el-col :span="8">
<el-form-item label="成品卷" prop="exitMatId">
<el-form-item label="Finished Coil" prop="exitMatId">
<!-- 成品卷 -->
<el-input v-model="formData.exitMatId"></el-input>
</el-form-item>
</el-col>
<!-- 来料卷 -->
<!-- Entry Coil / 来料卷 -->
<el-col :span="8">
<el-form-item label="来料卷" prop="entryMatId">
<el-form-item label="Entry Coil" prop="entryMatId">
<!-- 来料卷 -->
<el-input v-model="formData.entryMatId"></el-input>
</el-form-item>
</el-col>
<!-- 分切数 -->
<!-- Split Count / 分切数 -->
<el-col :span="8">
<el-form-item label="分切数" prop="subId">
<el-form-item label="Split Count" prop="subId">
<!-- 分切数 -->
<el-input-number v-model="formData.subId" :min="0" :step="1" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 开始位置 -->
<!-- Start Position / 开始位置 -->
<el-col :span="8">
<el-form-item label="开始位置" prop="startPosition">
<el-form-item label="Start Position" prop="startPosition">
<!-- 开始位置 -->
<el-input-number v-model="formData.startPosition" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 结束位置 -->
<!-- End Position / 结束位置 -->
<el-col :span="8">
<el-form-item label="结束位置" prop="endPosition">
<el-form-item label="End Position" prop="endPosition">
<!-- 结束位置 -->
<el-input-number v-model="formData.endPosition" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 计划ID -->
<!-- Plan ID / 计划ID -->
<el-col :span="8">
<el-form-item label="计划ID" prop="planId">
<el-form-item label="Plan ID" prop="planId">
<!-- 计划ID -->
<el-input-number v-model="formData.planId" :step="1" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 计划号 -->
<!-- Plan No / 计划号 -->
<el-col :span="8">
<el-form-item label="计划号" prop="planNo">
<el-form-item label="Plan No" prop="planNo">
<!-- 计划号 -->
<el-input v-model="formData.planNo"></el-input>
</el-form-item>
</el-col>
<!-- 产品类型 -->
<!-- Product Type / 产品类型 -->
<el-col :span="8">
<el-form-item label="产品类型" prop="prodCode">
<el-form-item label="Product Type" prop="prodCode">
<!-- 产品类型 -->
<el-input v-model="formData.prodCode"></el-input>
</el-form-item>
</el-col>
<!-- 班号 -->
<!-- Shift / 班号 -->
<el-col :span="8">
<el-form-item label="班号" prop="groupNo">
<el-form-item label="Shift" prop="groupNo">
<!-- 班号 -->
<el-input v-model="formData.groupNo"></el-input>
</el-form-item>
</el-col>
<!-- 组号 -->
<!-- Group / 组号 -->
<el-col :span="8">
<el-form-item label="组号" prop="shiftNo">
<el-form-item label="Group" prop="shiftNo">
<!-- 组号 -->
<el-input v-model="formData.shiftNo"></el-input>
</el-form-item>
</el-col>
<!-- 状态 -->
<!-- Status / 状态 -->
<el-col :span="8">
<el-form-item label="状态" prop="status">
<el-form-item label="Status" prop="status">
<!-- 状态 -->
<el-input v-model="formData.status"></el-input>
</el-form-item>
</el-col>
<!-- 钢种 -->
<!-- Steel Grade / 钢种 -->
<el-col :span="8">
<el-form-item label="钢种" prop="steelGrade">
<el-form-item label="Steel Grade" prop="steelGrade">
<!-- 钢种 -->
<el-input v-model="formData.steelGrade"></el-input>
</el-form-item>
</el-col>
<!-- 来料厚度 -->
<!-- Entry Thickness / 来料厚度 -->
<el-col :span="8">
<el-form-item label="来料厚度" prop="entryThick">
<el-form-item label="Entry Thickness" prop="entryThick">
<!-- 来料厚度 -->
<el-input-number v-model="formData.entryThick" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 来料宽度 -->
<!-- Entry Width / 来料宽度 -->
<el-col :span="8">
<el-form-item label="来料宽度" prop="entryWidth">
<el-form-item label="Entry Width" prop="entryWidth">
<!-- 来料宽度 -->
<el-input-number v-model="formData.entryWidth" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 来料长度 -->
<!-- Entry Length / 来料长度 -->
<el-col :span="8">
<el-form-item label="来料长度" prop="entryLength">
<el-form-item label="Entry Length" prop="entryLength">
<!-- 来料长度 -->
<el-input-number v-model="formData.entryLength" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 来料重量 -->
<!-- Entry Weight / 来料重量 -->
<el-col :span="8">
<el-form-item label="来料重量" prop="entryWeight">
<el-form-item label="Entry Weight" prop="entryWeight">
<!-- 来料重量 -->
<el-input-number v-model="formData.entryWeight" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 上表面镀锌 -->
<!-- Top Surface Coating / 上表面镀锌 -->
<el-col :span="8">
<el-form-item label="上表面镀锌" prop="weightTop">
<el-form-item label="Top Surface Coating" prop="weightTop">
<!-- 上表面镀锌 -->
<el-input-number v-model="formData.weightTop" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 下表面镀锌 -->
<!-- Bottom Surface Coating / 下表面镀锌 -->
<el-col :span="8">
<el-form-item label="下表面镀锌" prop="weightBottom">
<el-form-item label="Bottom Surface Coating" prop="weightBottom">
<!-- 下表面镀锌 -->
<el-input-number v-model="formData.weightBottom" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 成品长度 -->
<!-- Exit Length / 成品长度 -->
<el-col :span="8">
<el-form-item label="成品长度" prop="exitLength">
<el-form-item label="Exit Length" prop="exitLength">
<!-- 成品长度 -->
<el-input-number v-model="formData.exitLength" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 成品带涂料重量 -->
<!-- Exit Net Weight (with coating) / 成品带涂料重量 -->
<el-col :span="8">
<el-form-item label="成品带涂料重量" prop="exitNetWeight">
<el-form-item label="Exit Net Weight (with coating)" prop="exitNetWeight">
<!-- 成品带涂料重量 -->
<el-input-number v-model="formData.exitNetWeight" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 理论重量 -->
<!-- Theory Weight / 理论重量 -->
<el-col :span="8">
<el-form-item label="理论重量" prop="theoryWeight">
<el-form-item label="Theory Weight" prop="theoryWeight">
<!-- 理论重量 -->
<el-input-number v-model="formData.theoryWeight" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 实际重量 -->
<!-- Actual Weight / 实际重量 -->
<el-col :span="8">
<el-form-item label="实际重量" prop="actualWeight">
<el-form-item label="Actual Weight" prop="actualWeight">
<!-- 实际重量 -->
<el-input-number v-model="formData.actualWeight" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 成品外径 -->
<!-- Exit Outer Diameter / 成品外径 -->
<el-col :span="8">
<el-form-item label="成品外径" prop="exitOuterDiameter">
<el-form-item label="Exit Outer Diameter" prop="exitOuterDiameter">
<!-- 成品外径 -->
<el-input-number v-model="formData.exitOuterDiameter" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 成品厚度 -->
<!-- Exit Thickness / 成品厚度 -->
<el-col :span="8">
<el-form-item label="成品厚度" prop="exitThickness">
<el-form-item label="Exit Thickness" prop="exitThickness">
<!-- 成品厚度 -->
<el-input-number v-model="formData.exitThickness" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 成品宽度 -->
<!-- Exit Width / 成品宽度 -->
<el-col :span="8">
<el-form-item label="成品宽度" prop="exitWidth">
<el-form-item label="Exit Width" prop="exitWidth">
<!-- 成品宽度 -->
<el-input-number v-model="formData.exitWidth" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- 客户 -->
<!-- Customer / 客户 -->
<el-col :span="8">
<el-form-item label="客户" prop="customer">
<el-form-item label="Customer" prop="customer">
<!-- 客户 -->
<el-input v-model="formData.customer"></el-input>
</el-form-item>
</el-col>
<!-- 上线时间 -->
<!-- Online Time / 上线时间 -->
<el-col :span="8">
<el-form-item label="上线时间" prop="onlineTime">
<el-form-item label="Online Time" prop="onlineTime">
<!-- 上线时间 -->
<el-date-picker v-model="formData.onlineTime" type="datetime" value-format="yyyy-MM-ddTHH:mm:ss" />
</el-form-item>
</el-col>
<!-- 开始时间 -->
<!-- Start Time / 开始时间 -->
<el-col :span="8">
<el-form-item label="开始时间" prop="startTime">
<el-form-item label="Start Time" prop="startTime">
<!-- 开始时间 -->
<el-date-picker v-model="formData.startTime" type="datetime" value-format="yyyy-MM-ddTHH:mm:ss" />
</el-form-item>
</el-col>
<!-- 结束时间 -->
<!-- End Time / 结束时间 -->
<el-col :span="8">
<el-form-item label="结束时间" prop="endTime">
<el-form-item label="End Time" prop="endTime">
<!-- 结束时间 -->
<el-date-picker v-model="formData.endTime" type="datetime" value-format="yyyy-MM-ddTHH:mm:ss" />
</el-form-item>
</el-col>
<!-- 机组号 -->
<!-- Unit Code / 机组号 -->
<el-col :span="8">
<el-form-item label="机组号" prop="unitCode">
<el-form-item label="Unit Code" prop="unitCode">
<!-- 机组号 -->
<el-input v-model="formData.unitCode"></el-input>
</el-form-item>
</el-col>
<!-- 工序号 -->
<!-- Process Code / 工序号 -->
<el-col :span="8">
<el-form-item label="工序号" prop="processCode">
<el-form-item label="Process Code" prop="processCode">
<!-- 工序号 -->
<el-input v-model="formData.processCode"></el-input>
</el-form-item>
</el-col>
<!-- 是否尾卷 -->
<!-- Is Last Coil / 是否尾卷 -->
<el-col :span="8">
<el-form-item label="是否尾卷" prop="lastFlag">
<el-form-item label="Is Last Coil" prop="lastFlag">
<!-- 是否尾卷 -->
<el-switch v-model="formData.lastFlag"></el-switch>
</el-form-item>
</el-col>
<!-- 是否分卷 -->
<!-- Is Split Coil / 是否分卷 -->
<el-col :span="8">
<el-form-item label="是否分卷" prop="separateFlag">
<el-form-item label="Is Split Coil" prop="separateFlag">
<!-- 是否分卷 -->
<el-switch v-model="formData.separateFlag"></el-switch>
</el-form-item>
</el-col>
<!-- 计划来源 -->
<!-- Plan Origin / 计划来源 -->
<el-col :span="8">
<el-form-item label="计划来源" prop="planOrigin">
<el-select v-model="formData.planOrigin" placeholder="请选择计划来源">
<el-option label="L3计划" value="L3"></el-option>
<el-option label="人工" value="MANUAL"></el-option>
<el-form-item label="Plan Origin" prop="planOrigin">
<!-- 计划来源 -->
<el-select v-model="formData.planOrigin" placeholder="Please select plan origin">
<!-- 请选择计划来源 -->
<el-option label="L3 Plan" value="L3"></el-option>
<!-- L3计划 -->
<el-option label="Manual" value="MANUAL"></el-option>
<!-- 人工 -->
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 保存按钮 -->
<!-- Save button / 保存按钮 -->
<div class="dialog-footer">
<el-button type="primary" @click="handleSave" :loading="saveLoading">保存</el-button>
<el-button type="primary" @click="handleSave" :loading="saveLoading">Save</el-button>
<!-- 保存 -->
</div>
</el-form>
</template>
@@ -226,18 +264,18 @@
export default {
name: 'PdoDataCorrection',
props: {
// 接收父组件传递的详情数据
// Receive detail data from parent component / 接收父组件传递的详情数据
detail: {
type: Object,
required: true,
default: () => ({})
},
// 保存回调函数(父组件处理实际保存逻辑)
// Save callback function (parent component handles actual save logic) / 保存回调函数(父组件处理实际保存逻辑)
saveCallback: {
type: Function,
required: true
},
// 保存按钮loading状态由父组件控制
// Save button loading state (controlled by parent component) / 保存按钮loading状态由父组件控制
saveLoading: {
type: Boolean,
required: true,
@@ -246,33 +284,33 @@ export default {
},
data() {
return {
// 内部表单数据拷贝父组件传递的detail避免直接修改父组件数据
// Internal form data (copy parent component's detail, avoid directly modifying parent data) / 内部表单数据拷贝父组件传递的detail避免直接修改父组件数据
formData: {},
// 表单验证规则
// Form validation rules / 表单验证规则
formRules: {
exitMatId: [{ required: true, message: '请输入成品卷号', trigger: 'blur' }],
entryMatId: [{ required: true, message: '请输入来料卷号', trigger: 'blur' }],
planNo: [{ required: true, message: '请输入计划号', trigger: 'blur' }],
steelGrade: [{ required: true, message: '请输入钢种', trigger: 'blur' }]
// 可根据实际需求补充其他字段验证规则
exitMatId: [{ required: true, message: 'Please enter finished coil ID', trigger: 'blur' }], // 请输入成品卷号
entryMatId: [{ required: true, message: 'Please enter entry coil ID', trigger: 'blur' }], // 请输入来料卷号
planNo: [{ required: true, message: 'Please enter plan number', trigger: 'blur' }], // 请输入计划号
steelGrade: [{ required: true, message: 'Please enter steel grade', trigger: 'blur' }] // 请输入钢种
// Can add other field validation rules as needed / 可根据实际需求补充其他字段验证规则
}
}
},
watch: {
// 监听detail变化深拷贝更新内部formData
// Watch detail changes, deep copy to update internal formData / 监听detail变化深拷贝更新内部formData
detail: {
handler(newVal) {
// 深拷贝避免引用类型数据相互影响
// Deep copy to avoid reference type data interference / 深拷贝避免引用类型数据相互影响
this.formData = JSON.parse(JSON.stringify(newVal))
// 初始化数值类型字段防止null/undefined导致输入框异常
// Initialize numeric type fields (prevent null/undefined causing input box exceptions) / 初始化数值类型字段防止null/undefined导致输入框异常
this.initNumberFields()
},
immediate: true, // 初始渲染时立即执行
deep: true // 深度监听对象内部变化
immediate: true, // Execute immediately on initial render / 初始渲染时立即执行
deep: true // Deep watch object internal changes / 深度监听对象内部变化
}
},
methods: {
// 初始化数值类型字段确保默认值为0而非null/undefined
// Initialize numeric type fields (ensure default value is 0 instead of null/undefined) / 初始化数值类型字段确保默认值为0而非null/undefined
initNumberFields() {
const numberFields = [
'subId', 'startPosition', 'endPosition', 'planId', 'entryThick',
@@ -285,15 +323,15 @@ export default {
this.formData[field] = 0
}
})
// 初始化布尔类型字段
// Initialize boolean type fields / 初始化布尔类型字段
this.formData.lastFlag = this.formData.lastFlag ?? false
this.formData.separateFlag = this.formData.separateFlag ?? false
},
// 处理保存逻辑(先验证表单,通过后触发父组件回调)
// Handle save logic (validate form first, then trigger parent component callback) / 处理保存逻辑(先验证表单,通过后触发父组件回调)
handleSave() {
this.$refs.correctionForm.validate(valid => {
if (valid) {
// 触发父组件保存回调,传递内部修改后的表单数据
// Trigger parent component save callback, pass internally modified form data / 触发父组件保存回调,传递内部修改后的表单数据
this.saveCallback(this.formData)
}
})

View File

@@ -1,68 +1,85 @@
<template>
<div class="label-print-container">
<!-- 预览区域与打印内容一致且可编辑 -->
<!-- Preview area (consistent with print content and editable) / 预览区域与打印内容一致且可编辑 -->
<div class="label-preview" v-if="Object.keys(editableData).length">
<!-- 给打印区域添加一个唯一ID -->
<!-- Add a unique ID to the print area / 给打印区域添加一个唯一ID -->
<div id="printContent" class="label-content">
<!-- 公司名称 -->
<!-- Company name / 公司名称 -->
<div class="company-name">
{{ editableData.companyName }}
</div>
<!-- 内容区域使用Flexbox布局 -->
<!-- Content area: Use Flexbox layout / 内容区域使用Flexbox布局 -->
<div class="content-grid">
<div class="grid-item label">钢卷号</div>
<div class="grid-item label">Coil ID</div>
<!-- 钢卷号 -->
<div class="grid-item value">
<input v-model="editableData.exitMatId" :border="false" class="editable-input"
placeholder="钢卷号"></input>
placeholder="Coil ID"></input>
<!-- 钢卷号 -->
</div>
<div class="grid-item label">热卷号</div>
<div class="grid-item label">Hot Coil ID</div>
<!-- 热卷号 -->
<div class="grid-item value">
<input v-model="editableData.entryMatId" :border="false" class="editable-input"
placeholder="热卷号"></input>
placeholder="Hot Coil ID"></input>
<!-- 热卷号 -->
</div>
<div class="grid-item label">规格</div>
<div class="grid-item label">Specification</div>
<!-- 规格 -->
<div class="grid-item value">
<input v-model="editableData.spec" :border="false" class="editable-input" placeholder="规格"></input>
<input v-model="editableData.spec" :border="false" class="editable-input" placeholder="Specification"></input>
<!-- 规格 -->
</div>
<div class="grid-item label">材质</div>
<div class="grid-item label">Material</div>
<!-- 材质 -->
<div class="grid-item value">
<input v-model="editableData.steelGrade" :border="false" class="editable-input"
placeholder="材质"></input>
placeholder="Material"></input>
<!-- 材质 -->
</div>
<div class="grid-item label">净重</div>
<div class="grid-item label">Net Weight</div>
<!-- 净重 -->
<div class="grid-item value">
<input v-model="editableData.actualWeight" :border="false" class="editable-input"
placeholder="净重"></input>
placeholder="Net Weight"></input>
<!-- 净重 -->
</div>
<div class="grid-item label">生产班组</div>
<div class="grid-item label">Production Shift</div>
<!-- 生产班组 -->
<div class="grid-item value">
<input v-model="editableData.groupNo" :border="false" class="editable-input"
placeholder="生产班组"></input>
placeholder="Production Shift"></input>
<!-- 生产班组 -->
</div>
<div class="grid-item label">产品名称</div>
<div class="grid-item label">Product Name</div>
<!-- 产品名称 -->
<div class="grid-item value">
<input v-model="editableData.prodCode" :border="false" class="editable-input"
placeholder="产品名称"></input>
placeholder="Product Name"></input>
<!-- 产品名称 -->
</div>
<div class="grid-item label">生产日期</div>
<div class="grid-item label">Production Date</div>
<!-- 生产日期 -->
<div class="grid-item value">
<input v-model="editableData.productionDate" :border="false" class="editable-input"
placeholder="生产日期"></input>
placeholder="Production Date"></input>
<!-- 生产日期 -->
</div>
</div>
</div>
</div>
<!-- 打印按钮 -->
<!-- Print button / 打印按钮 -->
<div class="print-btn-container">
<el-button type="primary" @click="handlePrint" icon="el-icon-printer"
:disabled="!Object.keys(editableData).length">
打印标签
Print Label
</el-button>
<!-- 打印标签 -->
</div>
</div>
</template>
@@ -82,12 +99,12 @@ export default {
},
data() {
return {
// 可编辑的数据对象
// Editable data object / 可编辑的数据对象
editableData: {}
};
},
watch: {
// 监听detail变化初始化可编辑数据
// Watch detail changes, initialize editable data / 监听detail变化初始化可编辑数据
detail: {
handler(newVal) {
if (newVal) {
@@ -99,24 +116,24 @@ export default {
}
},
methods: {
// 初始化可编辑数据
// Initialize editable data / 初始化可编辑数据
initEditableData(detail) {
const {
exitMatId, entryMatId, exitThickness, exitWidth,
actualWeight, steelGrade, groupNo, prodCode
} = detail;
// 格式化规格
// Format specification / 格式化规格
const spec = exitThickness && exitWidth
? `${exitThickness}*${exitWidth}`
: '';
// 格式化生产日期
// Format production date / 格式化生产日期
const productionDate = dayjs().format('M月D日');
// 初始化可编辑数据
// Initialize editable data / 初始化可编辑数据
this.editableData = {
companyName: '嘉祥科伦普重工有限公司',
companyName: '嘉祥科伦普重工有限公司', // Company name (keep Chinese as it's a company name)
exitMatId: exitMatId || '',
entryMatId: entryMatId || '',
spec: spec || '',
@@ -128,9 +145,9 @@ export default {
};
},
// 处理打印逻辑
// Handle print logic / 处理打印逻辑
handlePrint() {
// 定义打印样式,确保打印效果与预览一致
// Define print styles to ensure print effect matches preview / 定义打印样式,确保打印效果与预览一致
const printStyle = `
.label-content {
width: 200mm;
@@ -176,18 +193,18 @@ export default {
}
`;
// 调用printJS进行打印
// Call printJS to print / 调用printJS进行打印
printJS({
printable: 'printContent', // 要打印的元素ID
printable: 'printContent', // Element ID to print / 要打印的元素ID
type: 'html',
header: null, // 不显示默认页眉
footer: null, // 不显示默认页脚
// style: printStyle, // 应用打印样式
scanStyles: true, // 不扫描页面现有样式
targetStyles: ['*'], // 允许所有目标样式
documentTitle: '标签打印', // 打印文档标题
header: null, // Don't show default header / 不显示默认页眉
footer: null, // Don't show default footer / 不显示默认页脚
// style: printStyle, // Apply print styles / 应用打印样式
scanStyles: true, // Don't scan existing page styles / 不扫描页面现有样式
targetStyles: ['*'], // Allow all target styles / 允许所有目标样式
documentTitle: 'Label Print', // Print document title / 打印文档标题
onPrintDialogClose: () => {
console.log('打印对话框已关闭');
console.log('Print dialog closed'); // 打印对话框已关闭
}
});
}

View File

@@ -6,14 +6,14 @@
:style="{ width: '100%' }"
size="mini"
>
<!-- 循环渲染汇总项从计算属性获取数据 -->
<!-- Loop render summary items, get data from computed property / 循环渲染汇总项从计算属性获取数据 -->
<el-descriptions-item
v-for="(item, index) in summaryResult"
:key="index"
:label="item.label"
label-class="summary-label"
>
<!-- 根据类型格式化显示重量/百分比/数量 -->
<!-- Format display based on type (weight/percentage/count) / 根据类型格式化显示重量/百分比/数量 -->
<span :class="item.type === 'rate' ? 'summary-rate' : ''">
{{ item.value }}
{{ item.unit }}
@@ -26,44 +26,44 @@
export default {
name: 'PdoSummary',
props: {
// 接收表格原始数据(父组件传递)
// Receive table raw data (passed from parent component) / 接收表格原始数据(父组件传递)
tableData: {
type: Array,
required: true,
default: () => [] // 默认空数组,避免无数据时报错
default: () => [] // Default empty array to avoid errors when no data / 默认空数组,避免无数据时报错
}
},
computed: {
// 核心根据tableData计算汇总结果
// Core: Calculate summary result based on tableData / 核心根据tableData计算汇总结果
summaryResult() {
// 1. 基础数值汇总处理字符串转数字避免NaN
// 1. Basic numerical summary (handle string to number conversion, avoid NaN) / 基础数值汇总处理字符串转数字避免NaN
const totalEntryWeight = this.tableData.reduce((sum, item) => {
return sum + (Number(item.entryWeight) || 0)
}, 0) // 原料总重(来料重量求和)
}, 0) // Total entry weight (sum of entry weights) / 原料总重(来料重量求和)
const totalExitWeight = this.tableData.reduce((sum, item) => {
return sum + (Number(item.exitNetWeight) || 0)
}, 0) // 产品总重(成品带涂料重量求和)
}, 0) // Total exit weight (sum of finished product weights with coating) / 产品总重(成品带涂料重量求和)
const totalZincRemoved = totalEntryWeight - totalExitWeight // 去锌总理重(原料总重 - 产品总重)
const totalZincRemoved = totalEntryWeight - totalExitWeight // Total zinc removed weight (entry weight - exit weight) / 去锌总理重(原料总重 - 产品总重)
// 2. 成材率计算避免除数为0
// 2. Yield rate calculation (avoid division by zero) / 成材率计算避免除数为0
const yieldRate = totalEntryWeight > 0
? ((totalExitWeight / totalEntryWeight) * 100).toFixed(2)
: '0.00'
// 3. 卷数统计(原料/成品卷数默认按表格行数可根据实际业务调整如去重entryMatId
const totalEntryCoils = this.tableData.length // 原料总卷数
const totalExitCoils = this.tableData.length // 成品总卷数
// 3. Coil count statistics (entry/finished coil count defaults to table row count, can be adjusted based on actual business, e.g., deduplicate entryMatId) / 卷数统计(原料/成品卷数默认按表格行数可根据实际业务调整如去重entryMatId
const totalEntryCoils = this.tableData.length // Total entry coils / 原料总卷数
const totalExitCoils = this.tableData.length // Total exit coils / 成品总卷数
// 4. 返回格式化后的汇总项
// 4. Return formatted summary items / 返回格式化后的汇总项
return [
{ label: '原料总重', value: totalEntryWeight.toFixed(1), unit: 't', type: 'weight' },
{ label: '去锌总理重', value: totalZincRemoved.toFixed(1), unit: 't', type: 'weight' },
{ label: '产品总重', value: totalExitWeight.toFixed(1), unit: 't', type: 'weight' },
{ label: '成材率', value: yieldRate, unit: '%', type: 'rate' },
{ label: '原料总卷数', value: totalEntryCoils, unit: '', type: 'count' },
{ label: '成品总卷数', value: totalExitCoils, unit: '', type: 'count' }
{ label: 'Total Entry Weight', value: totalEntryWeight.toFixed(1), unit: 't', type: 'weight' }, // 原料总重
{ label: 'Total Zinc Removed', value: totalZincRemoved.toFixed(1), unit: 't', type: 'weight' }, // 去锌总理重
{ label: 'Total Exit Weight', value: totalExitWeight.toFixed(1), unit: 't', type: 'weight' }, // 产品总重
{ label: 'Yield Rate', value: yieldRate, unit: '%', type: 'rate' }, // 成材率
{ label: 'Total Entry Coils', value: totalEntryCoils, unit: 'coils', type: 'count' }, // 原料总卷数
{ label: 'Total Exit Coils', value: totalExitCoils, unit: 'coils', type: 'count' } // 成品总卷数
]
}
}

View File

@@ -0,0 +1,636 @@
<template>
<div class="quality-certificate-container">
<div id="qualityCertificateContent" class="certificate-content">
<!-- Header / 头部 -->
<div class="certificate-header">
<div class="header-top">
<div class="company-logo">
<!-- Company logo placeholder / 公司Logo占位 -->
</div>
<div class="header-title">
<h1>Product Quality Certificate</h1>
<!-- 产品质量证明书 -->
<div class="document-number">Document No.: {{ certificateData.documentNo || '-' }}</div>
<!-- 文档编号 -->
</div>
<div class="qr-code-placeholder">
<!-- QR code placeholder / 二维码占位 -->
</div>
</div>
<div class="header-info">
<div class="info-row">
<div class="info-item">
<span class="info-label">Licence No.:</span>
<!-- 许可证号 -->
<span class="info-value">{{ certificateData.licenceNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Purchaser:</span>
<!-- 订货单位 -->
<span class="info-value">{{ certificateData.purchaser || '-' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">Customer:</span>
<!-- 收货单位 -->
<span class="info-value">{{ certificateData.customer || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Contract No.:</span>
<!-- 合同编号 -->
<span class="info-value">{{ certificateData.contractNo || '-' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">Trade Mark:</span>
<!-- 品种名称 -->
<span class="info-value">{{ certificateData.tradeMark || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Technique Standard:</span>
<!-- 技术条件 -->
<span class="info-value">{{ certificateData.techniqueStandard || '-' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">Odd No.:</span>
<!-- 结齐单号 -->
<span class="info-value">{{ certificateData.oddNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Delivery Condition:</span>
<!-- 交货状态 -->
<span class="info-value">{{ certificateData.deliveryCondition || '-' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">Certificate No.:</span>
<!-- 证明书号 -->
<span class="info-value">{{ certificateData.certificateNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Destination:</span>
<!-- 到站 -->
<span class="info-value">{{ certificateData.destination || '-' }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">Wagon No.:</span>
<!-- 车号 -->
<span class="info-value">{{ certificateData.wagonNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Delivery Date:</span>
<!-- 发货日期 -->
<span class="info-value">{{ certificateData.deliveryDate || '-' }}</span>
</div>
</div>
</div>
</div>
<!-- Main data table / 主数据表格 -->
<div class="certificate-table">
<table class="data-table">
<thead>
<tr>
<th rowspan="2" style="width: 3%;">No.</th>
<!-- 序号 -->
<th rowspan="2" style="width: 8%;">Coil No.</th>
<!-- 钢卷号 -->
<th rowspan="2" style="width: 7%;">Heat No.</th>
<!-- 熔炼号 -->
<th colspan="3" style="width: 9%;">Size</th>
<!-- 规格 -->
<th rowspan="2" style="width: 5%;">Weight (t)</th>
<!-- 重量 -->
<th colspan="5" style="width: 12%;">Chemical Composition (%)</th>
<!-- 化学成分 -->
<th colspan="5" style="width: 15%;">Tension Test</th>
<!-- 拉伸试验 -->
<th colspan="2" style="width: 8%;">Zinc-coating & Cold Bend</th>
<!-- 锌层冷弯 -->
<th colspan="2" style="width: 8%;">Hardness</th>
<!-- 硬度 -->
<th rowspan="2" style="width: 6%;">Coating Weight (g/)</th>
<!-- 镀层重量 -->
<th rowspan="2" style="width: 6%;">Surface Quality</th>
<!-- 表面组别 -->
<th rowspan="2" style="width: 6%;">Flatness</th>
<!-- 不平度 -->
</tr>
<tr>
<th style="width: 3%;">Thickness (mm)</th>
<!-- -->
<th style="width: 3%;">Width (mm)</th>
<!-- -->
<th style="width: 3%;">Length (m)</th>
<!-- -->
<th style="width: 2.4%;">C</th>
<th style="width: 2.4%;">Si</th>
<th style="width: 2.4%;">Mn</th>
<th style="width: 2.4%;">P</th>
<th style="width: 2.4%;">S</th>
<th style="width: 3%;">Yield (MPa)</th>
<!-- 屈服 -->
<th style="width: 3%;">Tensile (MPa)</th>
<!-- 抗拉 -->
<th style="width: 3%;">Elongation (%)</th>
<!-- 伸长 -->
<th style="width: 3%;">n Value</th>
<!-- n值 -->
<th style="width: 3%;">r Value</th>
<!-- r值 -->
<th style="width: 4%;">Types</th>
<!-- 类型 -->
<th style="width: 4%;">Value</th>
<!-- -->
<th style="width: 4%;">Types</th>
<!-- 类型 -->
<th style="width: 4%;">Value</th>
<!-- -->
</tr>
</thead>
<tbody>
<tr v-for="(coil, index) in certificateData.coils" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ coil.coilNo || '-' }}</td>
<td>{{ coil.heatNo || '-' }}</td>
<td>{{ formatNumber(coil.thickness) }}</td>
<td>{{ formatNumber(coil.width) }}</td>
<td>{{ formatNumber(coil.length) }}</td>
<td>{{ formatNumber(coil.weight) }}</td>
<td>{{ formatNumber(coil.c) }}</td>
<td>{{ formatNumber(coil.si) }}</td>
<td>{{ formatNumber(coil.mn) }}</td>
<td>{{ formatNumber(coil.p) }}</td>
<td>{{ formatNumber(coil.s) }}</td>
<td>{{ formatNumber(coil.yield) }}</td>
<td>{{ formatNumber(coil.tensile) }}</td>
<td>{{ formatNumber(coil.elongation) }}</td>
<td>{{ formatNumber(coil.nValue) }}</td>
<td>{{ formatNumber(coil.rValue) }}</td>
<td>{{ coil.zincCoatingType || '-' }}</td>
<td>{{ coil.zincCoatingValue || '-' }}</td>
<td>{{ coil.hardnessType || '-' }}</td>
<td>{{ coil.hardnessValue || '-' }}</td>
<td>{{ formatNumber(coil.coatingWeight) }}</td>
<td>{{ coil.surfaceQuality || '-' }}</td>
<td>{{ coil.flatness || '-' }}</td>
</tr>
</tbody>
</table>
</div>
<!-- Footer information / 底部信息 -->
<div class="certificate-footer">
<div class="footer-row">
<div class="footer-item">
<span class="footer-label">Steel Grade:</span>
<!-- 牌号 -->
<span class="footer-value">{{ certificateData.steelGrade || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Surface Structure:</span>
<!-- 表面结构 -->
<span class="footer-value">{{ certificateData.surfaceStructure || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Edge:</span>
<!-- 边缘状态 -->
<span class="footer-value">{{ certificateData.edge || '-' }}</span>
</div>
</div>
<div class="footer-row">
<div class="footer-item">
<span class="footer-label">Coat Type:</span>
<!-- 镀层种类 -->
<span class="footer-value">{{ certificateData.coatType || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Size Precision:</span>
<!-- 尺寸精度 -->
<span class="footer-value">{{ certificateData.sizePrecision || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Surface Treatment:</span>
<!-- 表面处理 -->
<span class="footer-value">{{ certificateData.surfaceTreatment || '-' }}</span>
</div>
</div>
<div class="footer-row">
<div class="footer-item">
<span class="footer-label">Total Number:</span>
<!-- 总卷() -->
<span class="footer-value">{{ certificateData.totalNumber || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Note:</span>
<!-- 注释 -->
<span class="footer-value">{{ certificateData.note || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Total Weight (t):</span>
<!-- 总重量 -->
<span class="footer-value">{{ certificateData.totalWeight || '-' }}</span>
</div>
</div>
</div>
<!-- Remarks / 备注 -->
<div class="certificate-remarks">
<div class="remarks-title">Remarks:</div>
<!-- 备注 -->
<div class="remarks-content">
<p>1. It is certified herein that the products have been produced and tested according to above standards and the products are all qualified.</p>
<!-- 本产品已按上述标准生产和检验,其结果符合要求,特此证明 -->
<p>2. The original quality certificate is the basis for acceptance, copies are for reference only and not to be used as acceptance vouchers.</p>
<!-- 质量证明书原件是验收依据,复印件仅供参考,不作为验收凭证 -->
</div>
</div>
</div>
<!-- Print button / 打印按钮 -->
<div class="print-btn-container">
<el-button type="primary" @click="handlePrint" icon="el-icon-printer">
Print Certificate
<!-- 打印质保书 -->
</el-button>
</div>
</div>
</template>
<script>
import printJS from 'print-js';
import dayjs from 'dayjs';
export default {
name: 'QualityCertificate',
props: {
// Single coil detail / 单卷详情
detail: {
type: Object,
required: true,
default: () => ({})
}
},
data() {
return {
certificateData: {}
};
},
watch: {
// Only watch single coil detail / 仅监听单卷详情
detail: {
handler(newVal) {
if (newVal) {
this.initCertificateData(newVal);
}
},
immediate: true,
deep: true
}
},
methods: {
// Initialize certificate data for single coil / 初始化单卷质保书数据
initCertificateData(detail) {
const coils = [detail]; // 单卷:永远只有一个卷
this.certificateData = {
documentNo: detail.documentNo || `QG/GFJL(Y) 164-2004`,
licenceNo: detail.licenceNo || '',
purchaser: detail.purchaser || '',
customer: detail.customer || '',
contractNo: detail.contractNo || detail.planNo || '',
tradeMark: detail.tradeMark || detail.prodCode || '',
techniqueStandard: detail.techniqueStandard || '',
oddNo: detail.oddNo || '',
deliveryCondition: detail.deliveryCondition || detail.prodCode || '',
certificateNo: detail.certificateNo || detail.exitMatId || '',
destination: detail.destination || '',
wagonNo: detail.wagonNo || '',
deliveryDate: detail.deliveryDate || dayjs().format('YYYY-MM-DD'),
steelGrade: detail.steelGrade || '',
surfaceStructure: detail.surfaceStructure || 'Smooth',
edge: detail.edge || 'Untrimmed',
coatType: detail.coatType || '',
sizePrecision: detail.sizePrecision || 'Normal',
surfaceTreatment: detail.surfaceTreatment || '',
totalNumber: 1, // 单卷固定为1
note: detail.note || '',
totalWeight: this.calculateTotalWeight(coils),
coils: this.formatCoilsData(coils)
};
},
// Format coils data / 格式化卷数据
formatCoilsData(coils) {
return coils.map(coil => ({
coilNo: coil.exitMatId || coil.coilid || '-',
heatNo: coil.heatNo || coil.heatNo || '-',
thickness: coil.exitThickness || coil.entryThick || '-',
width: coil.exitWidth || coil.entryWidth || '-',
length: coil.exitLength || coil.entryLength || '-',
weight: coil.exitNetWeight || coil.actualWeight || coil.entryWeight || '-',
c: coil.c || coil.chemicalC || '-',
si: coil.si || coil.chemicalSi || '-',
mn: coil.mn || coil.chemicalMn || '-',
p: coil.p || coil.chemicalP || '-',
s: coil.s || coil.chemicalS || '-',
yield: coil.yield || coil.yieldStrength || '-',
tensile: coil.tensile || coil.tensileStrength || '-',
elongation: coil.elongation || coil.elongationPercent || '-',
nValue: coil.nValue || '-',
rValue: coil.rValue || '-',
zincCoatingType: coil.zincCoatingType || '-',
zincCoatingValue: coil.zincCoatingValue || (coil.weightTop && coil.weightBottom ? 'Qualified' : '-'),
hardnessType: coil.hardnessType || '-',
hardnessValue: coil.hardnessValue || '-',
coatingWeight: coil.coatingWeight || coil.weightTop || '-',
surfaceQuality: coil.surfaceQuality || coil.surfaceGroup || 'Premium',
flatness: coil.flatness || 'Premium'
}));
},
// Calculate total weight / 计算总重量
calculateTotalWeight(coils) {
const total = coils.reduce((sum, coil) => {
const weight = parseFloat(coil.exitNetWeight || coil.actualWeight || coil.entryWeight || 0);
return sum + (isNaN(weight) ? 0 : weight);
}, 0);
return total > 0 ? total.toFixed(2) : '-';
},
// Format number / 格式化数字
formatNumber(value) {
if (value === null || value === undefined || value === '' || value === '-') {
return '-';
}
const num = parseFloat(value);
if (isNaN(num)) {
return value;
}
// Keep 2 decimal places for most numbers, but show more precision for small values / 大多数数字保留2位小数但小数值显示更多精度
if (Math.abs(num) < 1) {
return num.toFixed(3);
}
return num.toFixed(2);
},
// Handle print / 处理打印
handlePrint() {
const printStyle = `
@page {
size: A4 landscape;
margin: 10mm;
}
.certificate-content {
width: 100%;
font-family: Arial, sans-serif;
}
`;
printJS({
printable: 'qualityCertificateContent',
type: 'html',
header: null,
footer: null,
style: printStyle,
scanStyles: true,
targetStyles: ['*'],
documentTitle: 'Quality Certificate',
onPrintDialogClose: () => {
console.log('Print dialog closed');
}
});
}
}
};
</script>
<style scoped>
.quality-certificate-container {
padding: 20px;
background: #fff;
}
.certificate-content {
width: 100%;
font-family: Arial, sans-serif;
font-size: 12px;
color: #000;
}
/* Header styles / 头部样式 */
.certificate-header {
margin-bottom: 20px;
}
.header-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #000;
}
.company-logo {
width: 80px;
height: 80px;
border: 1px solid #ccc;
background: #f5f5f5;
}
.header-title {
flex: 1;
text-align: center;
}
.header-title h1 {
font-size: 20px;
font-weight: bold;
margin: 0 0 5px 0;
}
.document-number {
font-size: 11px;
color: #666;
}
.qr-code-placeholder {
width: 60px;
height: 60px;
border: 1px solid #ccc;
background: #f5f5f5;
}
.header-info {
display: flex;
flex-direction: column;
gap: 8px;
}
.info-row {
display: flex;
gap: 30px;
}
.info-item {
flex: 1;
display: flex;
align-items: center;
}
.info-label {
font-weight: bold;
min-width: 120px;
margin-right: 8px;
}
.info-value {
flex: 1;
}
/* Table styles / 表格样式 */
.certificate-table {
margin: 20px 0;
overflow-x: auto;
}
.data-table {
width: 100%;
border-collapse: collapse;
font-size: 10px;
border: 2px solid #000;
table-layout: fixed;
}
.data-table th,
.data-table td {
border: 1px solid #000;
padding: 6px 4px;
text-align: center;
vertical-align: middle;
word-wrap: break-word;
font-size: 10px;
}
.data-table th {
background: #f0f0f0;
font-weight: bold;
font-size: 9px;
}
.data-table tbody tr:nth-child(even) {
background: #fafafa;
}
.data-table tbody tr:hover {
background: #f0f0f0;
}
/* Footer styles / 底部样式 */
.certificate-footer {
margin: 20px 0;
padding: 10px 0;
border-top: 1px solid #000;
}
.footer-row {
display: flex;
gap: 30px;
margin-bottom: 8px;
}
.footer-item {
flex: 1;
display: flex;
align-items: center;
}
.footer-label {
font-weight: bold;
min-width: 120px;
margin-right: 8px;
}
.footer-value {
flex: 1;
}
/* Remarks styles / 备注样式 */
.certificate-remarks {
margin-top: 20px;
padding-top: 10px;
border-top: 1px solid #000;
}
.remarks-title {
font-weight: bold;
margin-bottom: 8px;
}
.remarks-content p {
margin: 5px 0;
line-height: 1.6;
}
/* Print button / 打印按钮 */
.print-btn-container {
text-align: center;
margin-top: 20px;
}
/* Print styles / 打印样式 */
@media print {
.print-btn-container {
display: none;
}
.quality-certificate-container {
padding: 0;
background: #fff;
}
.certificate-content {
font-size: 10px;
page-break-inside: avoid;
}
.certificate-header {
page-break-after: avoid;
}
.certificate-table {
page-break-inside: auto;
}
.data-table {
font-size: 8px;
}
.data-table th,
.data-table td {
padding: 3px 2px;
}
.data-table tbody tr {
page-break-inside: avoid;
}
.certificate-footer {
page-break-before: avoid;
}
.certificate-remarks {
page-break-inside: avoid;
}
}
</style>

View File

@@ -1,12 +1,12 @@
<template>
<div class="monitoring-container">
<div class="chart-wrapper" v-loading="loading">
<!-- 参数选择下拉框 -->
<!-- Parameter selection dropdown / 参数选择下拉框 -->
<el-select v-model="paramField" class="param-select" @change="handleParamChange" size="mini">
<el-option v-for="item in paramFields" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
<!-- 图表容器 -->
<!-- Chart container / 图表容器 -->
<div ref="chart" class="chart-content"></div>
</div>
</div>
@@ -26,53 +26,53 @@ export default {
},
data() {
return {
// 参数列表来源于 DeviceEnum 定义的监测字段
// Parameter list from monitoring fields defined in DeviceEnum / 参数列表来源于 DeviceEnum 定义的监测字段
paramFields: [
{ label: '带钢速度', value: 'stripSpeed' },
{ label: '开卷张力1#', value: 'tensionPorBr1' },
{ label: '开卷张力2#', value: 'tensionPorBr2' },
{ label: '清洗电压', value: 'cleaningVoltage' },
{ label: '清洗电流', value: 'cleaningCurrent' },
{ label: '碱液浓度', value: 'alkaliConcentration' },
{ label: '碱液温度', value: 'alkaliTemperature' },
{ label: 'PH炉出口温度', value: 'phfExitStripTemp' },
{ label: '加热段出口温度', value: 'rtfExitStripTemp' },
{ label: '冷却段出口温度', value: 'jcsExitStripTemp' },
{ label: '均衡段出口温度', value: 'scsExitStripTemp' },
{ label: '锌锅温度', value: 'potTemperature' },
{ label: '锌锅功率', value: 'zincPotPower' },
{ label: '燃气消耗', value: 'gasConsumption' },
{ label: '冷却塔温度', value: 'coolingTowerStripTemp' },
{ label: '光整机张力', value: 'tensionBr5Tm' },
{ label: 'TM出口速度', value: 'stripSpeedTmExit' },
{ label: '拉矫延伸率', value: 'tlElongation' },
{ label: '拉矫张力', value: 'tensionTlBr7' }
{ label: 'Strip Speed', value: 'stripSpeed' }, // 带钢速度
{ label: 'Pay-off Tension 1#', value: 'tensionPorBr1' }, // 开卷张力1#
{ label: 'Pay-off Tension 2#', value: 'tensionPorBr2' }, // 开卷张力2#
{ label: 'Cleaning Voltage', value: 'cleaningVoltage' }, // 清洗电压
{ label: 'Cleaning Current', value: 'cleaningCurrent' }, // 清洗电流
{ label: 'Alkali Concentration', value: 'alkaliConcentration' }, // 碱液浓度
{ label: 'Alkali Temperature', value: 'alkaliTemperature' }, // 碱液温度
{ label: 'PH Furnace Exit Temp', value: 'phfExitStripTemp' }, // PH炉出口温度
{ label: 'Heating Section Exit Temp', value: 'rtfExitStripTemp' }, // 加热段出口温度
{ label: 'Cooling Section Exit Temp', value: 'jcsExitStripTemp' }, // 冷却段出口温度
{ label: 'Equilibrium Section Exit Temp', value: 'scsExitStripTemp' }, // 均衡段出口温度
{ label: 'Pot Temperature', value: 'potTemperature' }, // 锌锅温度
{ label: 'Zinc Pot Power', value: 'zincPotPower' }, // 锌锅功率
{ label: 'Gas Consumption', value: 'gasConsumption' }, // 燃气消耗
{ label: 'Cooling Tower Temp', value: 'coolingTowerStripTemp' }, // 冷却塔温度
{ label: 'TM Tension', value: 'tensionBr5Tm' }, // 光整机张力
{ label: 'TM Exit Speed', value: 'stripSpeedTmExit' }, // TM出口速度
{ label: 'TL Elongation', value: 'tlElongation' }, // 拉矫延伸率
{ label: 'TL Tension', value: 'tensionTlBr7' } // 拉矫张力
],
paramField: 'stripSpeed',
treeProps: {
children: 'children',
label: 'label'
},
currentParam: null, // 当前选中的参数
chart: null, // 图表实例
chartData: [], // 图表数据
timeStamps: [], // 时间戳
originalTimeStamps: [], // 原始时间戳(用于采样)
originalChartData: [], // 原始图表数据(用于采样)
timeRange: '1', // 时间范围(分钟)
socket: null, // 模拟socket
currentParam: null, // Currently selected parameter / 当前选中的参数
chart: null, // Chart instance / 图表实例
chartData: [], // Chart data / 图表数据
timeStamps: [], // Timestamps / 时间戳
originalTimeStamps: [], // Original timestamps (for sampling) / 原始时间戳(用于采样)
originalChartData: [], // Original chart data (for sampling) / 原始图表数据(用于采样)
timeRange: '1', // Time range (minutes) / 时间范围(分钟)
socket: null, // Simulated socket / 模拟socket
latestValue: 0,
maxValue: 0,
minValue: 0,
avgValue: 0,
loading: false,
maxXAxisLabels: 40 // X轴最多显示的标签数量
maxXAxisLabels: 40 // Maximum number of labels displayed on X-axis / X轴最多显示的标签数量
}
},
watch: {
enCoilID: {
handler(newVal) {
console.log('enCoilID 变化:', newVal);
console.log('enCoilID changed:', newVal); // enCoilID 变化
if (newVal) {
this.fetchChartData();
} else {
@@ -83,26 +83,26 @@ export default {
},
},
mounted() {
// 初始化图表
// Initialize chart / 初始化图表
this.initChart();
},
beforeDestroy() {
// 销毁图表实例和事件监听
// Dispose chart instance and event listeners / 销毁图表实例和事件监听
if (this.chart) {
this.chart.dispose();
}
window.removeEventListener('resize', this.handleResize);
},
methods: {
// 初始化图表
// Initialize chart / 初始化图表
initChart() {
this.$nextTick(() => {
if (this.$refs.chart) {
this.chart = echarts.init(this.$refs.chart);
// 监听窗口大小变化,调整图表尺寸
// Listen to window resize, adjust chart size / 监听窗口大小变化,调整图表尺寸
window.addEventListener('resize', this.handleResize);
// 初始显示
// Initial display / 初始显示
if (this.enCoilID) {
this.fetchChartData();
} else {
@@ -112,14 +112,14 @@ export default {
});
},
// 处理窗口大小变化
// Handle window resize / 处理窗口大小变化
handleResize() {
if (this.chart) {
this.chart.resize();
}
},
// 获取图表数据
// Get chart data / 获取图表数据
fetchChartData() {
if (!this.enCoilID || !this.paramField) {
this.drawNoDataChart();
@@ -129,43 +129,43 @@ export default {
enCoilID: this.enCoilID,
paramField: this.paramField
}).then(res => {
// 假设res.data格式为[{ segNo: '时间戳', value: '数值' }]
// Assume res.data format is [{ segNo: 'timestamp', value: 'value' }] / 假设res.data格式为[{ segNo: '时间戳', value: '数值' }]
if (res.data && res.data.length) {
this.processChartData(res.data);
this.drawLineChart();
console.log('有数据,绘制折线图')
console.log('Data available, drawing line chart') // 有数据,绘制折线图
} else {
this.drawNoDataChart();
console.log('无数据,清空折线图')
console.log('No data, clearing line chart') // 无数据,清空折线图
}
}).catch(err => {
console.error('获取数据失败:', err);
console.error('Failed to fetch data:', err); // 获取数据失败
this.drawErrorChart();
}).finally(_ => {
this.loading = false;
});
},
// 处理图表数据
// Process chart data / 处理图表数据
processChartData(rawData) {
// 排序数据按segNo假设是时间戳或序号
// Sort data (by segNo, assume it's timestamp or sequence number) / 排序数据按segNo假设是时间戳或序号
rawData.sort((a, b) => a.segNo - b.segNo);
// 保存原始数据
// Save original data / 保存原始数据
this.originalTimeStamps = rawData.map(item => item.segNo);
this.originalChartData = rawData.map(item => parseFloat(item.value));
// 根据数据量决定是否采样
// Decide whether to sample based on data volume / 根据数据量决定是否采样
// if (rawData.length > this.maxXAxisLabels) {
// // 数据采样 - 均匀采样
// // Data sampling - uniform sampling / 数据采样 - 均匀采样
// this.sampleData(rawData);
// } else {
// 数据量适中,直接使用全部数据
// Data volume is moderate, use all data directly / 数据量适中,直接使用全部数据
this.timeStamps = this.originalTimeStamps;
this.chartData = this.originalChartData;
// }
// 计算统计值(基于原始数据)
// Calculate statistics (based on original data) / 计算统计值(基于原始数据)
if (this.originalChartData.length) {
this.latestValue = this.originalChartData[this.originalChartData.length - 1];
this.maxValue = Math.max(...this.originalChartData);
@@ -174,33 +174,33 @@ export default {
}
},
// 数据采样方法
// Data sampling method / 数据采样方法
sampleData(rawData) {
const total = rawData.length;
const sampleInterval = Math.ceil(total / this.maxXAxisLabels);
// 初始化采样数组
// Initialize sampling array / 初始化采样数组
this.timeStamps = [];
this.chartData = [];
// 均匀采样
// Uniform sampling / 均匀采样
for (let i = 0; i < total; i += sampleInterval) {
this.timeStamps.push(rawData[i].segNo);
this.chartData.push(parseFloat(rawData[i].value));
}
// 确保最后一个数据点被包含
// Ensure the last data point is included / 确保最后一个数据点被包含
if (this.timeStamps[this.timeStamps.length - 1] !== rawData[total - 1].segNo) {
this.timeStamps.push(rawData[total - 1].segNo);
this.chartData.push(parseFloat(rawData[total - 1].value));
}
},
// 绘制折线图
// Draw line chart / 绘制折线图
drawLineChart() {
if (!this.chart) return;
// 清理旧图层,避免暂无数据残留
// Clear old layers to avoid "No data" residue / 清理旧图层,避免"暂无数据"残留
this.chart.clear();
const option = {
@@ -220,16 +220,19 @@ export default {
formatter: (params) => {
const param = params[0];
return `
序号: ${param.name}<br>
值: ${param.value.toFixed(2)}<br>
单位: ${this.getParamUnit()}
Sequence: ${param.name}<br>
<!-- 序号 -->
Value: ${param.value.toFixed(2)}<br>
<!-- 值 -->
Unit: ${this.getParamUnit()}
<!-- 单位 -->
`;
}
},
grid: {
left: '3%',
right: '4%',
bottom: '10%', // 增加底部空间,防止标签被截断
bottom: '10%', // Increase bottom space to prevent label truncation / 增加底部空间,防止标签被截断
top: '15%',
containLabel: true
},
@@ -308,8 +311,8 @@ export default {
},
markPoint: {
data: [
{ type: 'max', name: '最大值' },
{ type: 'min', name: '最小值' }
{ type: 'max', name: 'Max' }, // 最大值
{ type: 'min', name: 'Min' } // 最小值
],
itemStyle: {
color: '#999'
@@ -320,7 +323,7 @@ export default {
},
markLine: {
data: [
{ type: 'average', name: '平均值' }
{ type: 'average', name: 'Average' } // 平均值
],
lineStyle: {
color: '#999',
@@ -337,7 +340,7 @@ export default {
this.chart.setOption(option, true);
},
// 绘制空图表(未选择实绩)
// Draw empty chart (no performance selected) / 绘制空图表(未选择实绩)
drawEmptyChart() {
if (!this.chart) return;
@@ -349,7 +352,7 @@ export default {
left: 'center',
top: 'center',
style: {
text: '请选择实绩',
text: 'Please select performance', // 请选择实绩
fontSize: 16,
fontWeight: 'bold',
fill: '#999'
@@ -370,11 +373,11 @@ export default {
this.chart.setOption(option);
},
// 绘制无数据图表
// Draw no data chart / 绘制无数据图表
drawNoDataChart() {
if (!this.chart) return;
// 先清除原有图表内容
// Clear original chart content first / 先清除原有图表内容
this.chart.clear();
const option = {
@@ -385,7 +388,7 @@ export default {
left: 'center',
top: 'center',
style: {
text: '暂无数据',
text: 'No data', // 暂无数据
fontSize: 16,
fontWeight: 'bold',
fill: '#999'
@@ -406,7 +409,7 @@ export default {
this.chart.setOption(option);
},
// 绘制错误图表
// Draw error chart / 绘制错误图表
drawErrorChart() {
if (!this.chart) return;
@@ -418,7 +421,7 @@ export default {
left: 'center',
top: 'center',
style: {
text: '数据加载失败',
text: 'Data loading failed', // 数据加载失败
fontSize: 16,
fontWeight: 'bold',
fill: '#f56c6c'
@@ -439,29 +442,29 @@ export default {
this.chart.setOption(option);
},
// 处理参数变更
// Handle parameter change / 处理参数变更
handleParamChange() {
// 清空现有数据
// Clear existing data / 清空现有数据
this.chartData = [];
this.timeStamps = [];
this.originalTimeStamps = [];
this.originalChartData = [];
// 重新获取数据
// Re-fetch data / 重新获取数据
if (this.enCoilID) {
this.fetchChartData();
}
},
// 获取参数标签
// Get parameter label / 获取参数标签
getParamLabel() {
const param = this.paramFields.find(item => item.value === this.paramField);
return param ? param.label : this.paramField;
},
// 获取参数单位
// Get parameter unit / 获取参数单位
getParamUnit() {
// 根据不同参数返回不同单位
// Return different units based on different parameters / 根据不同参数返回不同单位
switch (this.paramField) {
case 'stripSpeed':
return 'm/s';