feat: 同步g30

This commit is contained in:
砂糖
2026-01-04 17:04:42 +08:00
parent 36e9fc47db
commit b95291265b
38 changed files with 1550 additions and 2176 deletions

View File

@@ -38,6 +38,7 @@
"core-js": "3.37.1",
"cross-env": "^10.1.0",
"dayjs": "^1.11.18",
"dom-to-image": "^2.6.0",
"echarts": "5.4.0",
"element-ui": "2.15.14",
"file-saver": "2.0.5",

View File

@@ -306,7 +306,7 @@ export default {
.contextmenu {
margin: 0;
// 右键菜单金属背景
background: #454c51;
background: #fff;
border: 1px solid #a0a6ad;
z-index: 3000;
position: absolute;

View File

@@ -1,127 +1,76 @@
<template>
<div class="log-data-page">
<el-card>
<!-- Query form / 查询表单 -->
<!-- 查询表单 -->
<el-form :inline="true" :model="queryForm" ref="queryForm" label-width="80px">
<el-form-item label="Start Time" prop="startTime">
<!-- 开始时间 -->
<!-- Select start time / 选择开始时间 -->
<el-date-picker v-model="queryForm.startTime" type="datetime" placeholder="Select start time"
<el-form-item label="开始时间" prop="startTime">
<el-date-picker v-model="queryForm.startTime" type="datetime" placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss" :clearable="true"></el-date-picker>
</el-form-item>
<el-form-item label="End Time" prop="endTime">
<!-- 结束时间 -->
<!-- Select end time / 选择结束时间 -->
<el-date-picker v-model="queryForm.endTime" type="datetime" placeholder="Select end time"
<el-form-item label="结束时间" prop="endTime">
<el-date-picker v-model="queryForm.endTime" type="datetime" placeholder="选择结束时间"
value-format="yyyy-MM-dd HH:mm:ss" :clearable="true"></el-date-picker>
</el-form-item>
<el-form-item label="Alarm Type" prop="logtype">
<!-- 报警类型 -->
<el-select v-model="queryForm.logtype" placeholder="Please select alarm type" clearable>
<!-- 请选择报警类型 -->
<el-option label="System Alarm" value="system"></el-option>
<!-- 系统报警 -->
<el-option label="Device Alarm" value="device"></el-option>
<!-- 设备报警 -->
<el-option label="Network Alarm" value="network"></el-option>
<!-- 网络报警 -->
<el-option label="Security Alarm" value="security"></el-option>
<!-- 安全报警 -->
<el-form-item label="报警类型" prop="logtype">
<el-select v-model="queryForm.logtype" placeholder="请选择报警类型" clearable>
<el-option label="系统报警" value="system"></el-option>
<el-option label="设备报警" value="device"></el-option>
<el-option label="网络报警" value="network"></el-option>
<el-option label="安全报警" value="security"></el-option>
</el-select>
</el-form-item>
<el-form-item label="Alarm Module" prop="module">
<!-- 报警模块 -->
<el-select v-model="queryForm.module" placeholder="Please select alarm module" clearable>
<!-- 请选择报警模块 -->
<el-option label="Monitor Module" value="monitor"></el-option>
<!-- 监控模块 -->
<el-option label="Admin Module" value="admin"></el-option>
<!-- 管理模块 -->
<el-option label="Analysis Module" value="analysis"></el-option>
<!-- 分析模块 -->
<el-option label="Storage Module" value="storage"></el-option>
<!-- 存储模块 -->
<el-form-item label="报警模块" prop="module">
<el-select v-model="queryForm.module" placeholder="请选择报警模块" clearable>
<el-option label="监控模块" value="monitor"></el-option>
<el-option label="管理模块" value="admin"></el-option>
<el-option label="分析模块" value="analysis"></el-option>
<el-option label="存储模块" value="storage"></el-option>
</el-select>
</el-form-item>
<el-form-item label="Alarm Content" prop="logtext">
<!-- 警报内容 -->
<el-input v-model="queryForm.logtext" placeholder="Please enter alarm content" clearable style="width: 200px;"></el-input>
<!-- 请输入警报内容 -->
<el-form-item label="报警内容" prop="logtext">
<el-input v-model="queryForm.logtext" placeholder="请输入报警内容" clearable style="width: 200px;"></el-input>
</el-form-item>
<el-form-item label="Alarm Status" prop="status">
<!-- 报警状态 -->
<el-select v-model="queryForm.status" placeholder="Please select alarm status" clearable>
<!-- 请选择报警状态 -->
<el-option label="Unhandled" value="0"></el-option>
<!-- 未处理 -->
<el-option label="Handled" value="1"></el-option>
<!-- 已处理 -->
<el-option label="Ignored" value="2"></el-option>
<!-- 已忽略 -->
<el-form-item label="报警状态" prop="status">
<el-select v-model="queryForm.status" placeholder="请选择报警状态" clearable>
<el-option label="未处理" value="0"></el-option>
<el-option label="已处理" value="1"></el-option>
<el-option label="已忽略" value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery" :loading="btnLoading">
<i class="el-icon-search"></i> Query
<i class="el-icon-search"></i> 查询
</el-button>
<!-- 查询 -->
<el-button @click="handleReset">
<i class="el-icon-refresh"></i> Reset
<i class="el-icon-refresh"></i> 重置
</el-button>
<!-- 重置 -->
</el-form-item>
</el-form>
<!-- Data table / 数据表格 -->
<!-- 数据表格 -->
<el-table v-loading="tableLoading" :data="tableData" border style="width: 100%; margin-top: 20px;"
@row-click="handleRowClick" highlight-current-row>
<el-table-column prop="seqid" label="No." width="80" align="center"></el-table-column>
<!-- 序号 -->
<el-table-column prop="timestamp" label="Occurrence Time" width="180" align="center"></el-table-column>
<!-- 发生时间 -->
<el-table-column prop="module" label="Alarm Module" align="center">
<!-- 报警模块 -->
<el-table-column prop="seqid" label="序号" width="80" align="center"></el-table-column>
<el-table-column prop="timestamp" label="发生时间" width="180" align="center"></el-table-column>
<el-table-column prop="module" label="报警模块" align="center">
<template slot-scope="scope">
<!-- <el-tag>{{ formatModule(scope.row.module) }}</el-tag> -->
<dict-tag :options="dict.type.main_log_module" :value="scope.row.module" />
</template>
</el-table-column>
<el-table-column prop="logtype" label="Alarm Type" align="center">
<!-- 报警类型 -->
<el-table-column prop="logtype" label="报警类型" align="center">
<template slot-scope="scope">
<!-- <el-tag :type="getLogTypeTagType(scope.row.logtype)">{{ formatLogType(scope.row.logtype) }}</el-tag> -->
<dict-tag :options="dict.type.main_log_type" :value="scope.row.logtype" />
</template>
</el-table-column>
<el-table-column prop="logtext" label="Alarm Content" min-width="200"></el-table-column>
<!-- 警报内容 -->
<!-- <el-table-column prop="status" label="状态" align="center">
<template slot-scope="scope">
<el-tag :type="getStatusTagType(scope.row.status)">
{{ formatStatus(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="confirmTime" label="确认时间" width="180" align="center"></el-table-column> -->
<!-- <el-table-column label="操作" width="120" align="center">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="handleViewDetail(scope.row)" icon="el-icon-view">
详情
</el-button>
<el-button size="mini" type="text" @click="handleAck(scope.row.seqid)" icon="el-icon-check">
确认
</el-button>
</template>
</el-table-column> -->
<el-table-column prop="logtext" label="报警内容" min-width="200"></el-table-column>
</el-table>
<Pagination
v-show="total>0"
:total="total"
@@ -132,46 +81,37 @@
</el-card>
<!-- Detail dialog / 详情弹窗 -->
<el-dialog title="History Record Details" :visible.sync="detailDialogVisible" width="60%" :close-on-click-modal="false">
<!-- 历史记录详情 -->
<!-- 详情弹窗 -->
<el-dialog title="历史记录详情" :visible.sync="detailDialogVisible" width="60%" :close-on-click-modal="false">
<el-descriptions column="1" border>
<el-descriptions-item label="No.">{{ currentRow.seqid }}</el-descriptions-item>
<!-- 序号 -->
<el-descriptions-item label="Occurrence Time">{{ currentRow.timestamp }}</el-descriptions-item>
<!-- 发生时间 -->
<el-descriptions-item label="Alarm Module">{{ formatModule(currentRow.module) }}</el-descriptions-item>
<!-- 报警模块 -->
<el-descriptions-item label="Alarm Type">{{ formatLogType(currentRow.logtype) }}</el-descriptions-item>
<!-- 报警类型 -->
<el-descriptions-item label="Alarm Content">{{ currentRow.logtext }}</el-descriptions-item>
<!-- 警报内容 -->
<el-descriptions-item label="Status">
<!-- 状态 -->
<el-descriptions-item label="序号">{{ currentRow.seqid }}</el-descriptions-item>
<el-descriptions-item label="发生时间">{{ currentRow.timestamp }}</el-descriptions-item>
<el-descriptions-item label="报警模块">{{ formatModule(currentRow.module) }}</el-descriptions-item>
<el-descriptions-item label="报警类型">{{ formatLogType(currentRow.logtype) }}</el-descriptions-item>
<el-descriptions-item label="报警内容">{{ currentRow.logtext }}</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag :type="getStatusTagType(currentRow.status)">
{{ formatStatus(currentRow.status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="Confirm Time">{{ currentRow.confirmTime || 'Unconfirmed' }}</el-descriptions-item>
<!-- 确认时间 / 未确认 -->
<el-descriptions-item label="确认时间">{{ currentRow.confirmTime || '未确认' }}</el-descriptions-item>
</el-descriptions>
<div slot="footer" class="dialog-footer">
<el-button @click="detailDialogVisible = false">Close</el-button>
<!-- 关闭 -->
<el-button @click="detailDialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getLogDataPage, alarmAck } from '@/api/l2/log'; // Assume API file path / 假设API文件路径
import { getLogDataPage, alarmAck } from '@/api/l2/log'; // 假设API文件路径
export default {
name: 'LogDataTable',
dicts: ['main_log_type', 'main_log_module'],
data() {
return {
// Query form data / 查询表单数据
// 查询表单数据
queryForm: {
startTime: '',
endTime: '',
@@ -182,25 +122,25 @@ export default {
pageNum: 1,
pageSize: 10
},
// Table data / 表格数据
// 表格数据
tableData: [],
// Total count / 总条数
// 总条数
total: 0,
// Loading state / 加载状态
// 加载状态
tableLoading: false,
btnLoading: false,
// Detail dialog / 详情弹窗
// 详情弹窗
detailDialogVisible: false,
// Current selected row / 当前选中行
// 当前选中行
currentRow: {}
};
},
created() {
// Query once by default when page loads / 页面加载时默认查询一次
// 页面加载时默认查询一次
this.getLogData();
},
methods: {
// Get log data / 获取日志数据
// 获取日志数据
getLogData() {
this.tableLoading = true;
getLogDataPage(this.queryForm)
@@ -213,26 +153,26 @@ export default {
.catch(error => {
this.tableLoading = false;
this.btnLoading = false;
console.error('Failed to fetch data:', error); // 获取数据失败
this.$message.error('Failed to fetch data, please retry later'); // 获取数据失败,请稍后重试
console.error('获取数据失败:', error);
this.$message.error('获取数据失败,请稍后重试');
});
},
// Handle query / 处理查询
// 处理查询
handleQuery() {
// Validate that start time cannot be later than end time / 验证开始时间不能晚于结束时间
// 验证开始时间不能晚于结束时间
if (this.queryForm.startTime && this.queryForm.endTime &&
new Date(this.queryForm.startTime) > new Date(this.queryForm.endTime)) {
this.$message.warning('Start time cannot be later than end time'); // 开始时间不能晚于结束时间
this.$message.warning('开始时间不能晚于结束时间');
return;
}
this.btnLoading = true;
this.queryForm.pageNum = 1; // Reset to first page / 重置为第一页
this.queryForm.pageNum = 1; // 重置为第一页
this.getLogData();
},
// Handle reset / 处理重置
// 处理重置
handleReset() {
this.$refs.queryForm.resetFields();
this.queryForm.pageNum = 1;
@@ -240,53 +180,53 @@ export default {
this.getLogData();
},
// Handle page size change / 处理每页条数变化
// 处理每页条数变化
handleSizeChange(val) {
this.queryForm.pageSize = val;
this.queryForm.pageNum = 1; // Reset to first page / 重置为第一页
this.queryForm.pageNum = 1; // 重置为第一页
this.getLogData();
},
// Handle page number change / 处理页码变化
// 处理页码变化
handleCurrentChange(val) {
this.queryForm.pageNum = val;
this.getLogData();
},
// Row click event / 行点击事件
// 行点击事件
handleRowClick(row) {
this.currentRow = row;
},
// View detail / 查看详情
// 查看详情
handleViewDetail(row) {
this.currentRow = { ...row };
this.detailDialogVisible = true;
},
// Format alarm module display / 格式化报警模块显示
// 格式化报警模块显示
formatModule(module) {
const moduleMap = {
'monitor': 'Monitor Module', // 监控模块
'admin': 'Admin Module', // 管理模块
'analysis': 'Analysis Module', // 分析模块
'storage': 'Storage Module' // 存储模块
'monitor': '监控模块',
'admin': '管理模块',
'analysis': '分析模块',
'storage': '存储模块'
};
return moduleMap[module] || module || 'Unknown'; // 未知
return moduleMap[module] || module || '未知';
},
// Format alarm type display / 格式化报警类型显示
// 格式化报警类型显示
formatLogType(logtype) {
const logtypeMap = {
'system': 'System Alarm', // 系统报警
'device': 'Device Alarm', // 设备报警
'network': 'Network Alarm', // 网络报警
'security': 'Security Alarm' // 安全报警
'system': '系统报警',
'device': '设备报警',
'network': '网络报警',
'security': '安全报警'
};
return logtypeMap[logtype] || logtype || 'Unknown'; // 未知
return logtypeMap[logtype] || logtype || '未知';
},
// Get alarm type tag style / 获取报警类型标签样式
// 获取报警类型标签样式
getLogTypeTagType(logtype) {
const typeMap = {
'system': 'info',
@@ -297,17 +237,17 @@ export default {
return typeMap[logtype] || 'default';
},
// Format status display / 格式化状态显示
// 格式化状态显示
formatStatus(status) {
const statusMap = {
0: 'Unhandled', // 未处理
1: 'Handled', // 已处理
2: 'Ignored' // 已忽略
0: '未处理',
1: '已处理',
2: '已忽略'
};
return statusMap[status] || 'Unknown'; // 未知
return statusMap[status] || '未知';
},
// Get status tag style / 获取状态标签样式
// 获取状态标签样式
getStatusTagType(status) {
const typeMap = {
0: 'danger',
@@ -322,7 +262,7 @@ export default {
this.loading = true;
alarmAck(seqid)
.then(response => {
this.$message.success('Acknowledge successful'); // 确认成功
this.$message.success('确认成功');
this.getLogData();
})
}
@@ -344,4 +284,4 @@ export default {
::v-deep .el-descriptions__label {
font-weight: bold !important;
}
</style>
</style>

View File

@@ -6,256 +6,218 @@
:rules="formRules"
>
<el-row :gutter="20">
<!-- Finished Coil / 成品卷 -->
<!-- 成品卷 -->
<el-col :span="8">
<el-form-item label="Finished Coil" prop="exitMatId">
<!-- 成品卷 -->
<el-form-item label="成品卷" 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="Entry Coil" prop="entryMatId">
<!-- 来料卷 -->
<el-form-item label="来料卷" 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="Split Count" prop="subId">
<!-- 分切数 -->
<el-form-item label="分切数" 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="Start Position" prop="startPosition">
<!-- 开始位置 -->
<el-form-item label="开始位置" 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="End Position" prop="endPosition">
<!-- 结束位置 -->
<el-form-item label="结束位置" prop="endPosition">
<el-input-number v-model="formData.endPosition" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<!-- Plan ID / 计划ID -->
<!-- 计划ID -->
<el-col :span="8">
<el-form-item label="Plan ID" prop="planId">
<!-- 计划ID -->
<el-form-item label="计划ID" prop="planId">
<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="Plan No" prop="planNo">
<!-- 计划号 -->
<el-form-item label="计划号" 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="Product Type" prop="prodCode">
<!-- 产品类型 -->
<el-form-item label="产品类型" prop="prodCode">
<el-input v-model="formData.prodCode"></el-input>
</el-form-item>
</el-col>
<!-- Shift / 班号 -->
<!-- 班号 -->
<el-col :span="8">
<el-form-item label="Shift" prop="groupNo">
<!-- 班号 -->
<el-form-item label="班号" prop="groupNo">
<el-input v-model="formData.groupNo"></el-input>
</el-form-item>
</el-col>
<!-- Group / 组号 -->
<!-- 组号 -->
<el-col :span="8">
<el-form-item label="Group" prop="shiftNo">
<!-- 组号 -->
<el-form-item label="组号" prop="shiftNo">
<el-input v-model="formData.shiftNo"></el-input>
</el-form-item>
</el-col>
<!-- Status / 状态 -->
<!-- 状态 -->
<el-col :span="8">
<el-form-item label="Status" prop="status">
<!-- 状态 -->
<el-form-item label="状态" 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="Steel Grade" prop="steelGrade">
<!-- 钢种 -->
<el-form-item label="钢种" 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="Entry Thickness" prop="entryThick">
<!-- 来料厚度 -->
<el-form-item label="来料厚度" 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="Entry Width" prop="entryWidth">
<!-- 来料宽度 -->
<el-form-item label="来料宽度" 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="Entry Length" prop="entryLength">
<!-- 来料长度 -->
<el-form-item label="来料长度" 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="Entry Weight" prop="entryWeight">
<!-- 来料重量 -->
<el-form-item label="来料重量" 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="Top Surface Coating" prop="weightTop">
<!-- 上表面镀锌 -->
<el-form-item label="上表面镀锌" 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="Bottom Surface Coating" prop="weightBottom">
<!-- 下表面镀锌 -->
<el-form-item label="下表面镀锌" 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="Exit Length" prop="exitLength">
<!-- 成品长度 -->
<el-form-item label="成品长度" 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="Exit Net Weight (with coating)" prop="exitNetWeight">
<!-- 成品带涂料重量 -->
<el-form-item label="成品带涂料重量" 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="Theory Weight" prop="theoryWeight">
<!-- 理论重量 -->
<el-form-item label="理论重量" 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="Actual Weight" prop="actualWeight">
<!-- 实际重量 -->
<el-form-item label="实际重量" 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="Exit Outer Diameter" prop="exitOuterDiameter">
<!-- 成品外径 -->
<el-form-item label="成品外径" 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="Exit Thickness" prop="exitThickness">
<!-- 成品厚度 -->
<el-form-item label="成品厚度" 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="Exit Width" prop="exitWidth">
<!-- 成品宽度 -->
<el-form-item label="成品宽度" 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="Customer" prop="customer">
<!-- 客户 -->
<el-form-item label="客户" 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="Online Time" prop="onlineTime">
<!-- 上线时间 -->
<el-form-item label="上线时间" 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="Start Time" prop="startTime">
<!-- 开始时间 -->
<el-form-item label="开始时间" 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="End Time" prop="endTime">
<!-- 结束时间 -->
<el-form-item label="结束时间" 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="Unit Code" prop="unitCode">
<!-- 机组号 -->
<el-form-item label="机组号" 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="Process Code" prop="processCode">
<!-- 工序号 -->
<el-form-item label="工序号" 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="Is Last Coil" prop="lastFlag">
<!-- 是否尾卷 -->
<el-form-item label="是否尾卷" 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="Is Split Coil" prop="separateFlag">
<!-- 是否分卷 -->
<el-form-item label="是否分卷" 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="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-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-select>
</el-form-item>
</el-col>
</el-row>
<!-- Save button / 保存按钮 -->
<!-- 保存按钮 -->
<div class="dialog-footer">
<el-button type="primary" @click="handleSave" :loading="saveLoading">Save</el-button>
<!-- 保存 -->
<el-button type="primary" @click="handleSave" :loading="saveLoading">保存</el-button>
</div>
</el-form>
</template>
@@ -264,18 +226,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
},
// Save button loading state (controlled by parent component) / 保存按钮loading状态由父组件控制
// 保存按钮loading状态由父组件控制
saveLoading: {
type: Boolean,
required: true,
@@ -284,33 +246,33 @@ export default {
},
data() {
return {
// Internal form data (copy parent component's detail, avoid directly modifying parent data) / 内部表单数据拷贝父组件传递的detail避免直接修改父组件数据
// 内部表单数据拷贝父组件传递的detail避免直接修改父组件数据
formData: {},
// Form validation rules / 表单验证规则
// 表单验证规则
formRules: {
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 / 可根据实际需求补充其他字段验证规则
exitMatId: [{ required: true, message: '请输入成品卷号', trigger: 'blur' }],
entryMatId: [{ required: true, message: '请输入来料卷号', trigger: 'blur' }],
planNo: [{ required: true, message: '请输入计划号', trigger: 'blur' }],
steelGrade: [{ required: true, message: '请输入钢种', trigger: 'blur' }]
// 可根据实际需求补充其他字段验证规则
}
}
},
watch: {
// Watch detail changes, deep copy to update internal formData / 监听detail变化深拷贝更新内部formData
// 监听detail变化深拷贝更新内部formData
detail: {
handler(newVal) {
// Deep copy to avoid reference type data interference / 深拷贝避免引用类型数据相互影响
// 深拷贝避免引用类型数据相互影响
this.formData = JSON.parse(JSON.stringify(newVal))
// Initialize numeric type fields (prevent null/undefined causing input box exceptions) / 初始化数值类型字段防止null/undefined导致输入框异常
// 初始化数值类型字段防止null/undefined导致输入框异常
this.initNumberFields()
},
immediate: true, // Execute immediately on initial render / 初始渲染时立即执行
deep: true // Deep watch object internal changes / 深度监听对象内部变化
immediate: true, // 初始渲染时立即执行
deep: true // 深度监听对象内部变化
}
},
methods: {
// Initialize numeric type fields (ensure default value is 0 instead of null/undefined) / 初始化数值类型字段确保默认值为0而非null/undefined
// 初始化数值类型字段确保默认值为0而非null/undefined
initNumberFields() {
const numberFields = [
'subId', 'startPosition', 'endPosition', 'planId', 'entryThick',
@@ -323,15 +285,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,79 +1,62 @@
<template>
<div class="label-print-container">
<!-- Preview area (consistent with print content and editable) / 预览区域与打印内容一致且可编辑 -->
<!-- 预览区域与打印内容一致且可编辑 -->
<div class="label-preview" v-if="Object.keys(editableData).length">
<!-- Add a unique ID to the print area / 给打印区域添加一个唯一ID -->
<!-- 给打印区域添加一个唯一ID -->
<div id="printContent" class="label-content">
<!-- Company name / 公司名称 -->
<!-- 公司名称 -->
<div class="company-name">
{{ editableData.companyName }}
</div>
<!-- Content area: Use Flexbox layout / 内容区域使用Flexbox布局 -->
<!-- 内容区域使用Flexbox布局 -->
<div class="content-grid">
<div class="grid-item label">Coil ID</div>
<!-- 钢卷号 -->
<div class="grid-item label">钢卷号</div>
<div class="grid-item value">
<input v-model="editableData.exitMatId" :border="false" class="editable-input" placeholder="Coil ID">
<!-- 钢卷号 -->
<input v-model="editableData.exitMatId" :border="false" class="editable-input" placeholder="请输入钢卷号">
</div>
<div class="grid-item label">Hot Coil ID</div>
<!-- 热卷号 -->
<div class="grid-item label">热卷号</div>
<div class="grid-item value">
<input v-model="editableData.entryMatId" :border="false" class="editable-input" placeholder="Hot Coil ID">
<!-- 热卷号 -->
<input v-model="editableData.entryMatId" :border="false" class="editable-input" placeholder="请输入热卷号">
</div>
<div class="grid-item label">Specification</div>
<!-- 规格 -->
<div class="grid-item label">规格</div>
<div class="grid-item value">
<input v-model="editableData.spec" :border="false" class="editable-input" placeholder="Specification">
<!-- 规格 -->
<input v-model="editableData.spec" :border="false" class="editable-input" placeholder="请输入规格">
</div>
<div class="grid-item label">Material</div>
<!-- 材质 -->
<div class="grid-item label">材质</div>
<div class="grid-item value">
<input v-model="editableData.steelGrade" :border="false" class="editable-input" placeholder="Material">
<!-- 材质 -->
<input v-model="editableData.steelGrade" :border="false" class="editable-input" placeholder="请输入材质">
</div>
<div class="grid-item label">Net Weight</div>
<!-- 净重 -->
<div class="grid-item label">净重</div>
<div class="grid-item value">
<input v-model="editableData.actualWeight" :border="false" class="editable-input" placeholder="Net Weight">
<!-- 净重 -->
<input v-model="editableData.actualWeight" :border="false" class="editable-input" placeholder="请输入净重">
</div>
<div class="grid-item label">Production Shift</div>
<!-- 生产班组 -->
<div class="grid-item label">生产班组</div>
<div class="grid-item value">
<input v-model="editableData.groupNo" :border="false" class="editable-input" placeholder="Production Shift">
<!-- 生产班组 -->
<input v-model="editableData.groupNo" :border="false" class="editable-input" placeholder="请输入生产班组">
</div>
<div class="grid-item label">Product Name</div>
<!-- 产品名称 -->
<div class="grid-item label">产品名称</div>
<div class="grid-item value">
<input v-model="editableData.prodCode" :border="false" class="editable-input" placeholder="Product Name">
<!-- 产品名称 -->
<input v-model="editableData.prodCode" :border="false" class="editable-input" placeholder="请输入产品名称">
</div>
<div class="grid-item label">Production Date</div>
<!-- 生产日期 -->
<div class="grid-item label">生产日期</div>
<div class="grid-item value">
<input v-model="editableData.productionDate" :border="false" class="editable-input"
placeholder="Production Date">
<!-- 生产日期 -->
placeholder="请输入生产日期">
</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>
@@ -95,12 +78,12 @@ export default {
},
data() {
return {
// Editable data object / 可编辑的数据对象
// 可编辑的数据对象
editableData: {}
};
},
watch: {
// Watch detail changes, initialize editable data / 监听detail变化初始化可编辑数据
// 监听detail变化初始化可编辑数据
detail: {
handler(newVal) {
if (newVal) {
@@ -112,24 +95,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: '嘉祥科伦普重工有限公司', // Company name (keep Chinese as it's a company name)
companyName: '嘉祥科伦普重工有限公司', // 公司名称(保持中文)
exitMatId: exitMatId || '',
entryMatId: entryMatId || '',
spec: spec || '',
@@ -160,7 +143,7 @@ export default {
height: 80mm;
object-fit: contain;
`,
documentTitle: 'Label Print'
documentTitle: '标签打印'
});
} catch (e) { /* 错误处理 */ }
}

View File

@@ -43,26 +43,26 @@ export default {
avgValue: 0
},
maxXAxisLabels: 40, // X轴最大显示标签数
paramLabelMap: { // 参数字段与标签的映射(与父组件保持一致)
stripSpeed: 'Strip Speed',
tensionPorBr1: 'Pay-off Tension 1#',
tensionPorBr2: 'Pay-off Tension 2#',
cleaningVoltage: 'Cleaning Voltage',
cleaningCurrent: 'Cleaning Current',
alkaliConcentration: 'Alkali Concentration',
alkaliTemperature: 'Alkali Temperature',
phfExitStripTemp: 'PH Furnace Exit Temp',
rtfExitStripTemp: 'Heating Section Exit Temp',
jcsExitStripTemp: 'Cooling Section Exit Temp',
scsExitStripTemp: 'Equilibrium Section Exit Temp',
potTemperature: 'Pot Temperature',
zincPotPower: 'Zinc Pot Power',
gasConsumption: 'Gas Consumption',
coolingTowerStripTemp: 'Cooling Tower Temp',
tensionBr5Tm: 'TM Tension',
stripSpeedTmExit: 'TM Exit Speed',
tlElongation: 'TL Elongation',
tensionTlBr7: 'TL Tension'
paramLabelMap: { // 参数字段与标签的映射(与父组件保持一致,替换为中文
stripSpeed: '带钢速度',
tensionPorBr1: '开卷张力1#',
tensionPorBr2: '开卷张力2#',
cleaningVoltage: '清洗电压',
cleaningCurrent: '清洗电流',
alkaliConcentration: '碱液浓度',
alkaliTemperature: '碱液温度',
phfExitStripTemp: 'PH炉出口温度',
rtfExitStripTemp: '加热段出口温度',
jcsExitStripTemp: '冷却段出口温度',
scsExitStripTemp: '均热段出口温度',
potTemperature: '锌锅温度',
zincPotPower: '锌锅功率',
gasConsumption: '燃气消耗量',
coolingTowerStripTemp: '冷却塔温度',
tensionBr5Tm: 'TM张力',
stripSpeedTmExit: 'TM出口速度',
tlElongation: 'TL延伸率',
tensionTlBr7: 'TL张力'
}
}
},
@@ -218,9 +218,9 @@ export default {
formatter: (params) => {
const paramItem = params[0]
return `
Sequence: ${paramItem.name}<br>
Value: ${paramItem.value.toFixed(2)}<br>
Unit: ${this.getParamUnit()}
序号: ${paramItem.name}<br>
数值: ${paramItem.value.toFixed(2)}<br>
单位: ${this.getParamUnit()}
`
}
},
@@ -281,12 +281,12 @@ export default {
}
},
markPoint: {
data: [{ type: 'max', name: 'Max' }, { type: 'min', name: 'Min' }],
data: [{ type: 'max', name: '最大值' }, { type: 'min', name: '最小值' }],
itemStyle: { color: '#999' },
label: { color: '#333' }
},
markLine: {
data: [{ type: 'average', name: 'Average' }],
data: [{ type: 'average', name: '平均值' }],
lineStyle: { color: '#999', type: 'dashed' },
label: { color: '#333' }
}
@@ -309,7 +309,7 @@ export default {
left: 'center',
top: 'center',
style: {
text: 'Please select performance',
text: '请选择实绩数据',
fontSize: 16,
fontWeight: 'bold',
fill: '#999'
@@ -337,7 +337,7 @@ export default {
left: 'center',
top: 'center',
style: {
text: 'No data',
text: '暂无数据',
fontSize: 16,
fontWeight: 'bold',
fill: '#999'
@@ -365,7 +365,7 @@ export default {
left: 'center',
top: 'center',
style: {
text: 'Data loading failed',
text: '数据加载失败',
fontSize: 16,
fontWeight: 'bold',
fill: '#f56c6c'
@@ -388,7 +388,7 @@ export default {
}
},
// 获取参数单位(保持原有逻辑)
// 获取参数单位(保持原有逻辑,单位为标准符号无需修改
getParamUnit() {
switch (this.paramField) {
case 'stripSpeed':

View File

@@ -58,12 +58,12 @@ export default {
// 4. Return formatted summary items / 返回格式化后的汇总项
return [
{ label: 'Total Entry Weight', value: totalEntryWeight.toFixed(1), unit: 't', type: 'weight' }, // 原料总重
{ label: '原料总重', 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' } // 成品总卷数
{ 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' } // 成品总卷数
]
}
}

View File

@@ -1,163 +1,123 @@
<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占位 -->
<!-- 公司Logo占位 -->
</div>
<div class="header-title">
<h1>Product Quality Certificate</h1>
<!-- 产品质量证明书 -->
<div class="document-number">Document No.: {{ certificateData.documentNo || '-' }}</div>
<!-- 文档编号 -->
<h1>产品质量证明书</h1>
<div class="document-number">文档编号{{ 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-label">许可证号</span>
<span class="info-value">{{ certificateData.licenceNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Purchaser:</span>
<!-- 订货单位 -->
<span class="info-label">订货单位</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-label">收货单位</span>
<span class="info-value">{{ certificateData.customer || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Contract No.:</span>
<!-- 合同编号 -->
<span class="info-label">合同编号</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-label">品种名称</span>
<span class="info-value">{{ certificateData.tradeMark || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Technique Standard:</span>
<!-- 技术条件 -->
<span class="info-label">技术条件</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-label">结齐单号</span>
<span class="info-value">{{ certificateData.oddNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Delivery Condition:</span>
<!-- 交货状态 -->
<span class="info-label">交货状态</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-label">证明书号</span>
<span class="info-value">{{ certificateData.certificateNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Destination:</span>
<!-- 到站 -->
<span class="info-label">到站</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-label">车号</span>
<span class="info-value">{{ certificateData.wagonNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">Delivery Date:</span>
<!-- 发货日期 -->
<span class="info-label">发货日期</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 style="width: 6%;">Zinc Coating Thickness</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>
<!-- 不平度 -->
<th rowspan="2" style="width: 3%;">序号</th>
<th rowspan="2" style="width: 8%;">钢卷号</th>
<th rowspan="2" style="width: 7%;">熔炼号</th>
<th colspan="3" style="width: 9%;">规格</th>
<th rowspan="2" style="width: 5%;">重量(t)</th>
<th colspan="5" style="width: 12%;">化学成分(%)</th>
<th colspan="5" style="width: 15%;">拉伸试验</th>
<th colspan="2" style="width: 8%;">锌层冷弯</th>
<th style="width: 6%;">锌层厚度</th>
<th colspan="2" style="width: 8%;">硬度</th>
<th rowspan="2" style="width: 6%;">镀层重量(g/)</th>
<th rowspan="2" style="width: 6%;">表面组别</th>
<th rowspan="2" style="width: 6%;">不平度</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: 6%;">Thickness</th>
<!-- 厚度 -->
<th style="width: 4%;">Types</th>
<!-- 类型 -->
<th style="width: 4%;">Value</th>
<!-- -->
<th style="width: 3%;">厚度(mm)</th>
<th style="width: 3%;">宽度(mm)</th>
<th style="width: 3%;">长度(m)</th>
<th style="width: 2.4%;"></th>
<th style="width: 2.4%;"></th>
<th style="width: 2.4%;"></th>
<th style="width: 2.4%;"></th>
<th style="width: 2.4%;"></th>
<th style="width: 3%;">屈服强度(MPa)</th>
<th style="width: 3%;">抗拉强度(MPa)</th>
<th style="width: 3%;">伸长率(%)</th>
<th style="width: 3%;">n值</th>
<th style="width: 3%;">r值</th>
<th style="width: 4%;">类型</th>
<th style="width: 4%;">数值</th>
<th style="width: 6%;">厚度</th>
<th style="width: 4%;">类型</th>
<th style="width: 4%;">数值</th>
</tr>
</thead>
<tbody>
@@ -193,97 +153,81 @@
</div>
<div class="certificate-charts">
<div class="charts-title">Production Process Curves</div>
<!-- 生产过程曲线标题 -->
<div class="charts-title">生产过程曲线</div>
<div class="charts-wrapper">
<!-- 带钢速度曲线stripSpeed -->
<div class="chart-item">
<div class="chart-subtitle">Strip Speed (m/s)</div>
<div class="chart-subtitle">带钢速度 (m/s)</div>
<ParamEcharts :enCoilID="getEnCoilID" paramField="stripSpeed" />
</div>
<!-- 1#放卷张力曲线tensionPorBr1 -->
<div class="chart-item">
<div class="chart-subtitle">Pay-off Tension 1# (N)</div>
<div class="chart-subtitle">开卷张力1# (N)</div>
<ParamEcharts :enCoilID="getEnCoilID" paramField="tensionPorBr1" />
</div>
</div>
</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-label">牌号</span>
<span class="footer-value">{{ certificateData.steelGrade || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Surface Structure:</span>
<!-- 表面结构 -->
<span class="footer-label">表面结构</span>
<span class="footer-value">{{ certificateData.surfaceStructure || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Edge:</span>
<!-- 边缘状态 -->
<span class="footer-label">边缘状态</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-label">镀层种类</span>
<span class="footer-value">{{ certificateData.coatType || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Size Precision:</span>
<!-- 尺寸精度 -->
<span class="footer-label">尺寸精度</span>
<span class="footer-value">{{ certificateData.sizePrecision || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Surface Treatment:</span>
<!-- 表面处理 -->
<span class="footer-label">表面处理</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-label">总卷()</span>
<span class="footer-value">{{ certificateData.totalNumber || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Note:</span>
<!-- 注释 -->
<span class="footer-label">注释</span>
<span class="footer-value">{{ certificateData.note || '-' }}</span>
</div>
<div class="footer-item">
<span class="footer-label">Total Weight (t):</span>
<!-- 总重量 -->
<span class="footer-label">总重量(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-title">备注</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>
<!-- 质量证明书原件是验收依据,复印件仅供参考,不作为验收凭证 -->
<p>1. 本产品已按上述标准生产和检验其结果符合要求特此证明</p>
<p>2. 质量证明书原件是验收依据复印件仅供参考不作为验收凭证</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>
@@ -292,9 +236,9 @@
<script>
import printJS from 'print-js';
import dayjs from 'dayjs';
// 1. 导入 dom-to-image 库
// 导入 dom-to-image 库
import domtoimage from 'dom-to-image';
// 获取生产过程曲线数据
// 获取生产过程曲线组件
import ParamEcharts from './ParamEcharts.vue'
export default {
@@ -303,7 +247,7 @@ export default {
ParamEcharts
},
props: {
// Single coil detail / 单卷详情
// 单卷详情
detail: {
type: Object,
required: true,
@@ -316,7 +260,7 @@ export default {
};
},
watch: {
// Only watch single coil detail / 仅监听单卷详情
// 仅监听单卷详情
detail: {
handler(newVal) {
if (newVal) {
@@ -334,7 +278,7 @@ export default {
}
},
methods: {
// Initialize certificate data for single coil / 初始化单卷质保书数据
// 初始化单卷质保书数据
initCertificateData(detail) {
const coils = [detail]; // 单卷:永远只有一个卷
@@ -353,10 +297,10 @@ export default {
wagonNo: detail.wagonNo || '',
deliveryDate: detail.deliveryDate || dayjs().format('YYYY-MM-DD'),
steelGrade: detail.steelGrade || '',
surfaceStructure: detail.surfaceStructure || 'Smooth',
edge: detail.edge || 'Untrimmed',
surfaceStructure: detail.surfaceStructure || '光滑',
edge: detail.edge || '未切边',
coatType: detail.coatType || '',
sizePrecision: detail.sizePrecision || 'Normal',
sizePrecision: detail.sizePrecision || '普通',
surfaceTreatment: detail.surfaceTreatment || '',
totalNumber: 1, // 单卷固定为1
note: detail.note || '',
@@ -365,7 +309,7 @@ export default {
};
},
// Format coils data / 格式化卷数据
// 格式化卷数据
formatCoilsData(coils) {
return coils.map(coil => ({
coilNo: coil.exitMatId || coil.coilid || '-',
@@ -385,17 +329,17 @@ export default {
nValue: coil.nValue || '-',
rValue: coil.rValue || '-',
zincCoatingType: coil.zincCoatingType || '-',
zincCoatingValue: coil.zincCoatingValue || (coil.weightTop && coil.weightBottom ? 'Qualified' : '-'),
zincCoatingValue: coil.zincCoatingValue || (coil.weightTop && coil.weightBottom ? '合格' : '-'),
zincCoatingThickness: coil.zincCoatingThickness || coil.zincCoatingThickness || '-', // 添加锌层厚度字段
hardnessType: coil.hardnessType || '-',
hardnessValue: coil.hardnessValue || '-',
coatingWeight: coil.coatingWeight || coil.weightTop || '-',
surfaceQuality: coil.surfaceQuality || coil.surfaceGroup || 'Premium',
flatness: coil.flatness || 'Premium'
surfaceQuality: coil.surfaceQuality || coil.surfaceGroup || '优质',
flatness: coil.flatness || '优质'
}));
},
// Calculate total weight / 计算总重量
// 计算总重量
calculateTotalWeight(coils) {
const total = coils.reduce((sum, coil) => {
const weight = parseFloat(coil.exitNetWeight || coil.actualWeight || coil.entryWeight || 0);
@@ -404,7 +348,7 @@ export default {
return total > 0 ? total.toFixed(2) : '-';
},
// Format number / 格式化数字
// 格式化数字
formatNumber(value) {
if (value === null || value === undefined || value === '' || value === '-') {
return '-';
@@ -413,14 +357,14 @@ export default {
if (isNaN(num)) {
return value;
}
// Keep 2 decimal places for most numbers, but show more precision for small values / 大多数数字保留2位小数但小数值显示更多精度
// 大多数数字保留2位小数但小数值显示更多精度
if (Math.abs(num) < 1) {
return num.toFixed(3);
}
return num.toFixed(2);
},
// 2. 重构打印方法DOM -> 高清图片 -> 打印
// 重构打印方法DOM -> 高清图片 -> 打印
async handlePrint() {
try {
// 获取打印目标DOM元素
@@ -443,7 +387,7 @@ export default {
type: 'image', // 打印类型改为image关键变更
header: null,
footer: null,
documentTitle: 'Quality Certificate',
documentTitle: '产品质量证明书',
// 配置图片打印样式适配A4横向防止变形
imageStyle: `
width: 100%;
@@ -452,7 +396,7 @@ export default {
object-fit: contain;
`,
onPrintDialogClose: () => {
console.log('Print dialog closed');
console.log('打印对话框已关闭');
}
});
} catch (error) {
@@ -478,7 +422,7 @@ export default {
color: #000;
}
/* Header styles / 头部样式 */
/* 头部样式 */
.certificate-header {
margin-bottom: 20px;
}
@@ -549,7 +493,7 @@ export default {
flex: 1;
}
/* Table styles / 表格样式 */
/* 表格样式 */
.certificate-table {
margin: 20px 0;
overflow-x: auto;
@@ -587,7 +531,7 @@ export default {
background: #f0f0f0;
}
/* Footer styles / 底部样式 */
/* 底部样式 */
.certificate-footer {
margin: 20px 0;
padding: 10px 0;
@@ -616,7 +560,7 @@ export default {
flex: 1;
}
/* Remarks styles / 备注样式 */
/* 备注样式 */
.certificate-remarks {
margin-top: 20px;
padding-top: 10px;
@@ -633,7 +577,7 @@ export default {
line-height: 1.6;
}
/* Print button / 打印按钮 */
/* 打印按钮 */
.print-btn-container {
text-align: center;
margin-top: 20px;
@@ -679,8 +623,7 @@ export default {
font-weight: 500;
}
/* Print styles / 打印样式仅隐藏按钮图片打印样式已在printJS中配置 */
/* 打印样式仅隐藏按钮图片打印样式已在printJS中配置 */
@media print {
.print-btn-container {
display: none;

View File

@@ -26,7 +26,7 @@
<!-- 无勾选时显示提示 -->
<div v-if="checkedCount === 0" class="no-param-tip">
Please place the parameter on the left to display the chart. (Max 4)
请在左侧勾选参数以显示图表最多4个
</div>
</div>
</div>
@@ -48,27 +48,27 @@ export default {
},
data() {
return {
// 参数列表
// 参数列表(汉化:冷轧行业专业术语)
paramFields: [
{ label: 'Strip Speed', value: 'stripSpeed' },
{ label: 'Pay-off Tension 1#', value: 'tensionPorBr1' },
{ label: 'Pay-off Tension 2#', value: 'tensionPorBr2' },
{ 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' },
{ 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' },
{ label: 'TL Elongation', value: 'tlElongation' },
{ label: 'TL Tension', value: 'tensionTlBr7' }
{ label: '带钢速度', value: 'stripSpeed' },
{ label: '1#开卷机张力', value: 'tensionPorBr1' },
{ label: '2#开卷机张力', value: 'tensionPorBr2' },
{ label: '清洗电压', value: 'cleaningVoltage' },
{ label: '清洗电流', value: 'cleaningCurrent' },
{ label: '碱液浓度', value: 'alkaliConcentration' },
{ label: '碱液温度', value: 'alkaliTemperature' },
{ label: '预热段出口板温', 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: '光整机出口速度', value: 'stripSpeedTmExit' },
{ label: '拉矫机延伸率', value: 'tlElongation' },
{ label: '拉矫机张力', value: 'tensionTlBr7' }
],
treeProps: {
children: 'children',
@@ -80,10 +80,10 @@ export default {
}
},
watch: {
// 监听线圈ID变化无需手动更新图表子组件已自行监听
// 监听钢卷ID变化无需手动更新图表子组件已自行监听
enCoilID: {
handler(newVal) {
console.log('enCoilID changed:', newVal);
console.log('钢卷ID发生变化:', newVal);
},
immediate: true
},
@@ -105,7 +105,7 @@ export default {
// 超过4个时取消最后一个并提示
if (checkedCount > this.maxCheckCount) {
this.$message.warning(`Please select up to ${this.maxCheckCount} parameters.`);
this.$message.warning(`最多只能选择${this.maxCheckCount}个参数`);
const lastNode = checkedNodes[checkedNodes.length - 1];
this.$refs.paramTree.setChecked(lastNode.value, false, false);
return;

View File

@@ -1,87 +1,78 @@
<template>
<div class="pdo-container">
<!-- Query form area / 查询表单区域 -->
<!-- 查询表单区域 -->
<div class="pdo-header">
<el-form :inline="true" :model="queryForm" ref="queryForm" label-width="100px" size="small">
<el-form-item label="Coil ID" prop="coilid">
<!-- 钢卷号 -->
<el-input v-model="queryForm.coilid" placeholder="Please enter coil ID"></el-input>
<!-- 请输入钢卷号 -->
<el-form-item label="钢卷号" prop="coilid">
<el-input v-model="queryForm.coilid" placeholder="请输入钢卷号"></el-input>
</el-form-item>
<el-form-item label="Start Date" prop="startDate">
<!-- 开始日期 -->
<el-date-picker v-model="queryForm.startDate" type="date" placeholder="Select start date"
<el-form-item label="开始日期" prop="startDate">
<el-date-picker v-model="queryForm.startDate" type="date" placeholder="选择开始日期"
value-format="yyyy-MM-dd" clearable></el-date-picker>
<!-- 选择开始日期 -->
</el-form-item>
<el-form-item label="End Date" prop="endDate">
<!-- 结束日期 -->
<el-date-picker v-model="queryForm.endDate" type="date" placeholder="Select end date"
<el-form-item label="结束日期" prop="endDate">
<el-date-picker v-model="queryForm.endDate" type="date" placeholder="选择结束日期"
value-format="yyyy-MM-dd" clearable></el-date-picker>
<!-- 选择结束日期 -->
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery" :loading="btnLoading" icon="el-icon-search">Query</el-button>
<!-- 查询 -->
<el-button @click="handleReset" icon="el-icon-refresh">Reset</el-button>
<!-- 重置 -->
<el-button type="success" @click="handleAdd" icon="el-icon-plus">Add Record</el-button>
<el-button type="primary" @click="handleQuery" :loading="btnLoading" icon="el-icon-search">查询</el-button>
<el-button @click="handleReset" icon="el-icon-refresh">重置</el-button>
<el-button type="success" @click="handleAdd" icon="el-icon-plus">新增记录</el-button>
<span v-if="currentRow.exitMatId" style="margin-left: 10px; border: 1px solid #d4d4d4; border-radius: 2px; padding: 5px;">
<el-button size="mini" type="text" icon="el-icon-view"
@click.stop="handlePrint(currentRow)">Print</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleEdit(currentRow)">Edit</el-button>
@click.stop="handlePrint(currentRow)">打印</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleEdit(currentRow)">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-document"
@click.stop="handleQualityCertificate(currentRow)">Quality Certificate</el-button>
@click.stop="handleQualityCertificate(currentRow)">质保书</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" :loading="currentRow.deleteLoading"
@click.stop="handleDelete(currentRow)">Delete</el-button>
@click.stop="handleDelete(currentRow)">删除</el-button>
</span>
<!-- 补录 -->
</el-form-item>
</el-form>
</div>
<!-- Card grid layout / 卡片网格布局 -->
<!-- 卡片网格布局 -->
<div v-loading="tableLoading">
<el-table :data="tableData" style="width: 100%" border stripe @row-click="handleRowClick" highlight-current-row height="300px">
<el-table-column prop="exitMatId" label="exitMat"></el-table-column>
<el-table-column prop="entryMatId" label="entryMat"></el-table-column>
<el-table-column prop="planNo" label="PlanNo"></el-table-column>
<el-table-column prop="exitMatId" label="成品卷号"></el-table-column>
<el-table-column prop="entryMatId" label="来料卷号"></el-table-column>
<el-table-column prop="planNo" label="计划单号"></el-table-column>
<el-table-column prop="status" label="Status"></el-table-column>
<el-table-column prop="steelGrade" label="SteelGrade"></el-table-column>
<el-table-column prop="prodCode" label="ProductType"></el-table-column>
<el-table-column prop="customer" label="Customer"></el-table-column>
<el-table-column prop="status" label="状态"></el-table-column>
<el-table-column prop="steelGrade" label="钢种"></el-table-column>
<el-table-column prop="prodCode" label="产品类型"></el-table-column>
<el-table-column prop="customer" label="客户"></el-table-column>
<el-table-column prop="entryThick" label="EntryThickness"></el-table-column>
<el-table-column prop="entryWidth" label="EntryWidth"></el-table-column>
<el-table-column prop="entryLength" label="EntryLength"></el-table-column>
<el-table-column prop="entryWeight" label="EntryWeight"></el-table-column>
<el-table-column prop="entryThick" label="入口厚度"></el-table-column>
<el-table-column prop="entryWidth" label="入口宽度"></el-table-column>
<el-table-column prop="entryLength" label="入口长度"></el-table-column>
<el-table-column prop="entryWeight" label="入口重量"></el-table-column>
<el-table-column prop="exitThickness" label="ExitThickness"></el-table-column>
<el-table-column prop="exitWidth" label="ExitWidth"></el-table-column>
<el-table-column prop="exitLength" label="ExitLength"></el-table-column>
<el-table-column prop="exitNetWeight" label="ExitNetWeight"></el-table-column>
<el-table-column prop="exitThickness" label="出口厚度"></el-table-column>
<el-table-column prop="exitWidth" label="出口宽度"></el-table-column>
<el-table-column prop="exitLength" label="出口长度"></el-table-column>
<el-table-column prop="exitNetWeight" label="出口净重"></el-table-column>
<!-- <el-table-column label="Operation">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-view"
@click.stop="handlePrint(scope.row)">Print</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleEdit(scope.row)">Edit</el-button>
@click.stop="handlePrint(scope.row)">打印</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleEdit(scope.row)">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-document"
@click.stop="handleQualityCertificate(scope.row)">Quality Certificate</el-button>
@click.stop="handleQualityCertificate(scope.row)">质保书</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" :loading="scope.row.deleteLoading"
@click.stop="handleDelete(scope.row)">Delete</el-button>
@click.stop="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column> -->
</el-table>
<div v-if="tableData.length === 0 && !tableLoading" class="empty-data">
<el-empty description="No data"></el-empty>
<!-- 暂无数据 -->
<el-empty description="暂无数据"></el-empty>
</div>
</div>
@@ -90,22 +81,18 @@
</div>
<!-- Statistics summary and chart area / 统计汇总和图表区域 -->
<!-- 统计汇总和图表区域 -->
<div class="statistics-container">
<div class="statistics-header">
<div class="selected-info" v-if="currentRow && currentRow.entryMatId">
<i class="el-icon-check"></i>
<span class="selected-label">Selected:</span>
<!-- 已选中 -->
<span class="selected-value">Finished Coil {{ currentRow.exitMatId }}</span>
<!-- 成品卷 -->
<span class="selected-detail" v-if="currentRow.entryMatId">(Entry Coil: {{ currentRow.entryMatId }})</span>
<!-- 来料卷 -->
<span class="selected-label">已选中</span>
<span class="selected-value">成品卷 {{ currentRow.exitMatId }}</span>
<span class="selected-detail" v-if="currentRow.entryMatId">(来料卷{{ currentRow.entryMatId }})</span>
</div>
<div class="selected-info empty" v-else>
<i class="el-icon-info"></i>
<span>Please select a card above to view details</span>
<!-- 请选择上方卡片查看详情 -->
<span>请选择上方表格行查看详情</span>
</div>
</div>
<el-row :gutter="15" class="statistics-content">
@@ -115,27 +102,22 @@
</el-row>
</div>
<!-- Edit/Add dialog: render content based on isAdd condition / 编辑/新增弹窗根据isAdd条件渲染内容 -->
<!-- 编辑/新增弹窗根据isAdd条件渲染内容 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="80%" :close-on-click-modal="false">
<!-- Add record (new): only show data correction component, no tab / 补录新增仅显示数据修正组件无tab -->
<!-- 补录新增仅显示数据修正组件无tab -->
<div v-if="isAdd">
<pdo-data-correction :detail="formData" :save-callback="handleSave"
:save-loading="saveLoading"></pdo-data-correction>
</div>
<!-- 数据修正 -->
<pdo-data-correction :detail="formData" :save-callback="handleSave"
:save-loading="saveLoading"></pdo-data-correction>
</el-dialog>
<el-dialog title="Label Print" :visible.sync="printOpen" width="600px" :close-on-click-modal="false">
<!-- 标签打印 -->
<el-dialog title="标签打印" :visible.sync="printOpen" width="600px" :close-on-click-modal="false">
<div style="display: flex; justify-content: center; align-items: center;">
<pdo-label-print :detail="formData"></pdo-label-print>
</div>
</el-dialog>
<el-dialog title="Quality Certificate" :visible.sync="certificateVisible" width="90%" :close-on-click-modal="false">
<!-- 质保书单卷 -->
<el-dialog title="质保书(单卷)" :visible.sync="certificateVisible" width="90%" :close-on-click-modal="false">
<quality-certificate :detail="formData"></quality-certificate>
</el-dialog>
</div>
@@ -144,7 +126,7 @@
<script>
import { getPdoList, addPdo, updatePdo, deletePdo } from '@/api/l2/pdo'
import LineChart from './components/line.vue'
// Import two encapsulated components / 引入封装的两个组件
// 引入封装的两个组件
import PdoDataCorrection from './components/DataCorrection.vue'
import PdoLabelPrint from './components/LabelPrint.vue'
import PdoSummary from './components/PdoSummary.vue'
@@ -155,35 +137,35 @@ export default {
dicts: ['pdo_plan_origin'],
components: {
LineChart,
PdoDataCorrection, // Register data correction component / 注册数据修正组件
PdoLabelPrint, // Register label print component / 注册标签打印组件
PdoDataCorrection, // 注册数据修正组件
PdoLabelPrint, // 注册标签打印组件
PdoSummary,
QualityCertificate // Register quality certificate component / 注册质保书组件
QualityCertificate // 注册质保书组件
},
data() {
return {
activeTab: 'basicInfo',
queryForm: { coilid: '', startDate: '', endDate: '' },
printOpen: false,
certificateVisible: false, // Quality certificate dialog visibility / 质保书对话框显示状态
certificateVisible: false, // 质保书对话框显示状态
tableData: [],
tableLoading: false,
btnLoading: false,
dialogVisible: false,
dialogTitle: 'Add Performance', // 新增实绩
// New: status flag to distinguish "Add Record (New)" and "Edit" / 新增:区分「补录(新增)」和「编辑」的状态标识
dialogTitle: '新增实绩',
// 新增:区分「补录(新增)」和「编辑」的状态标识
isAdd: false,
// Detail data passed to child component (parent component only does data transfer, does not directly modify) / 传递给子组件的详情数据(父组件仅做数据中转,不直接修改)
// 传递给子组件的详情数据(父组件仅做数据中转,不直接修改)
formData: {},
saveLoading: false,
currentRow: {},
socketType: [
{ value: 'alarm', label: 'Alarm' }, // 报警
{ value: 'track_position', label: 'Track Position' }, // 跟踪位置
{ value: 'track_measure', label: 'Track Measure' }, // 跟踪测量
{ value: 'track_signal', label: 'Track Signal' }, // 跟踪信号
{ value: 'track_matmap', label: 'Track Material ID' }, // 跟踪料号
{ value: 'calc_setup_result', label: 'Calculation Result' } // 计算结果
{ value: 'alarm', label: '报警' },
{ value: 'track_position', label: '跟踪位置' },
{ value: 'track_measure', label: '跟踪测量' },
{ value: 'track_signal', label: '跟踪信号' },
{ value: 'track_matmap', label: '跟踪料号' },
{ value: 'calc_setup_result', label: '计算结果' }
]
}
},
@@ -191,43 +173,43 @@ export default {
this.getPdoList()
},
methods: {
// Get list data (unchanged) / 获取列表数据(保持不变)
// 获取列表数据(保持不变)
getPdoList() {
this.tableLoading = true
getPdoList(this.queryForm).then(res => {
this.tableData = res.data.map(item => ({ ...item, deleteLoading: false }))
}).catch(err => {
console.error(err)
this.$message.error('Failed to fetch data') // 获取数据失败
this.$message.error('获取数据失败')
}).finally(() => {
this.tableLoading = false
this.btnLoading = false
})
},
// Query (unchanged) / 查询(保持不变)
// 查询(保持不变)
handleQuery() {
this.btnLoading = true;
this.getPdoList()
},
// Reset (unchanged) / 重置(保持不变)
// 重置(保持不变)
handleReset() {
this.$refs.queryForm.resetFields();
this.getPdoList()
},
// Row click (unchanged) / 行点击(保持不变)
// 行点击(保持不变)
handleRowClick(row) {
this.currentRow = row;
},
// Format time / 格式化时间
// 格式化时间
formatTime(time) {
if (!time) return '-';
return this.parseTime(time, '{y}-{m}-{d} {h}:{i}:{s}');
},
// Add record (new): set isAdd=true, initialize empty form / 补录新增设置isAdd=true初始化空表单
// 补录新增设置isAdd=true初始化空表单
handleAdd() {
this.isAdd = true; // Mark as "Add Record" / 标记为「补录」
this.dialogTitle = 'Add Performance'; // 新增实绩
// Initialize empty form data (passed to child component) / 初始化空表单数据(传递给子组件)
this.isAdd = true; // 标记为「补录」
this.dialogTitle = '新增实绩';
// 初始化空表单数据(传递给子组件)
this.formData = {
subId: 0,
startPosition: 0,
@@ -251,50 +233,49 @@ export default {
};
this.dialogVisible = true
},
// Edit: set isAdd=false, assign row data / 编辑设置isAdd=false赋值行数据
// 编辑设置isAdd=false赋值行数据
handleEdit(row) {
this.isAdd = false; // Mark as "Edit" / 标记为「编辑」
this.dialogTitle = 'Edit Performance'; // 编辑实绩
// Deep copy row data (avoid directly modifying table data) / 深拷贝行数据(避免直接修改表格数据)
this.isAdd = false; // 标记为「编辑」
this.dialogTitle = '编辑实绩';
// 深拷贝行数据(避免直接修改表格数据)
this.formData = JSON.parse(JSON.stringify(row));
this.dialogVisible = true
},
handlePrint(row) {
// Deep copy row data (avoid directly modifying table data) / 深拷贝行数据(避免直接修改表格数据)
// 深拷贝行数据(避免直接修改表格数据)
this.formData = JSON.parse(JSON.stringify(row));
this.printOpen = true
},
// Handle quality certificate / 处理质保书(单卷)
// 处理质保书(单卷)
handleQualityCertificate(row) {
// Deep copy row data / 深拷贝行数据
// 深拷贝行数据
this.formData = JSON.parse(JSON.stringify(row));
// 单卷质保书:只显示当前成品卷
this.certificateVisible = true;
},
// Delete (unchanged) / 删除(保持不变)
// 删除(保持不变)
handleDelete(row) {
this.$confirm(`Are you sure to delete finished coil ${row.exitMatId}?`, 'Confirm Delete', { type: 'danger' }).then(() => {
// 确定删除成品卷 / 确认删除
this.$confirm(`您确定要删除成品卷 ${row.exitMatId} 吗?`, '确认删除', { type: 'danger' }).then(() => {
row.deleteLoading = true
deletePdo(row.exitMatId, row.planId).then(res => {
if (res.code === 200) {
this.$message.success('Delete successful'); // 删除成功
this.$message.success('删除成功');
this.getPdoList()
} else this.$message.error(res.msg || 'Delete failed') // 删除失败
} else this.$message.error(res.msg || '删除失败')
}).finally(() => row.deleteLoading = false)
})
},
// Save callback (triggered by child component, handles actual API call) / 保存回调子组件触发处理实际API调用
// 保存回调子组件触发处理实际API调用
handleSave(formData) {
this.saveLoading = true
// Determine if it's add or edit based on whether id exists / 根据是否有id判断是新增还是编辑
// 根据是否有id判断是新增还是编辑
const request = formData.id ? updatePdo(formData) : addPdo(formData)
request.then(res => {
if (res.code === 200) {
this.$message.success('Save successful'); // 保存成功
this.$message.success('保存成功');
this.dialogVisible = false;
this.getPdoList() // Refresh list / 刷新列表
} else this.$message.error(res.msg || 'Save failed') // 保存失败
this.getPdoList() // 刷新列表
} else this.$message.error(res.msg || '保存失败')
}).finally(() => {
this.saveLoading = false
})
@@ -554,4 +535,4 @@ export default {
height: 100%;
padding-left: 15px;
}
</style>
</style>

View File

@@ -3,10 +3,8 @@
<div class="recommend-section steel-panel">
<div class="section-header">
<div>
<div class="section-title">Steel Grade Recommendation</div>
<!-- 钢种推荐 -->
<div class="section-subtitle">After locking steel grade, automatically retrieve typical process master data from panel library</div>
<!-- 锁定钢种后自动调取面板库中的典型工艺主数据 -->
<div class="section-title">钢种推荐</div>
<div class="section-subtitle">锁定钢种后自动调取面板库中的典型工艺主数据</div>
</div>
<el-tag v-if="steelGradeName" size="mini" effect="dark">{{ steelGradeName }}</el-tag>
</div>
@@ -21,41 +19,34 @@
>
<div class="card-header">
<div class="card-title">
{{ item.steelGradeLabel || 'Steel Grade' }}
<!-- 钢种 -->
{{ item.steelGradeLabel || '钢种' }}
</div>
<el-tag size="mini" type="info">
Thickness {{ formatNumber(item.entryThick) }} mm
<!-- 厚度 -->
厚度 {{ formatNumber(item.entryThick) }} mm
</el-tag>
</div>
<div class="card-meta">
<div>
<span class="label">Yield Point</span>
<!-- 屈服点 -->
<span class="label">屈服点</span>
<span class="value">{{ formatNumber(item.yieldPoint) }}</span>
</div>
<div>
<span class="label">Elongation</span>
<!-- 延伸率 -->
<span class="label">延伸率</span>
<span class="value">{{ formatNumber(item.spmElongation) }}</span>
</div>
</div>
<div class="card-meta">
<div>
<span class="label">Roll Force</span>
<!-- 轧制力 -->
<span class="label">轧制力</span>
<span class="value">{{ formatNumber(item.spmRollforce) }}</span>
</div>
<div>
<span class="label">Update Time</span>
<!-- 更新时间 -->
<span class="label">更新时间</span>
<span class="value">{{ formatDate(item.updateTime) }}</span>
</div>
</div>
<div class="card-footer">
<span>Click to write steel grade and primary key</span>
<!-- 点击写入钢种及主键 -->
<span>点击写入钢种及主键</span>
<i class="el-icon-top-right" />
</div>
</div>
@@ -63,20 +54,17 @@
</template>
<el-empty
v-else
description="Select steel grade to enable linked query"
description="选择钢种后即可联动查询"
:image-size="100"
/>
<!-- 选择钢种后即可联动查询 -->
</div>
</div>
<div class="recommend-section thickness-panel">
<div class="section-header">
<div>
<div class="section-title">Thickness / Yield Point Linkage</div>
<!-- 厚度 / 屈服点联动 -->
<div class="section-subtitle">After entering thickness, automatically collect corresponding yield point records from multiple panel libraries</div>
<!-- 输入厚度后自动搜集多面板库对应的屈服点档案 -->
<div class="section-title">厚度/屈服点联动</div>
<div class="section-subtitle">输入厚度后自动搜集多面板库对应的屈服点档案</div>
</div>
<el-tag v-if="entryThick" size="mini" effect="plain">{{ formatNumber(entryThick) }} mm</el-tag>
</div>
@@ -94,25 +82,21 @@
{{ formatNumber(item.entryThick) }} mm
</div>
<el-tag size="mini" type="success">
Yield Point {{ formatNumber(item.yieldPoint) }}
<!-- 屈服点 -->
屈服点 {{ formatNumber(item.yieldPoint) }}
</el-tag>
</div>
<div class="card-meta">
<div>
<span class="label">Steel Grade</span>
<!-- 钢种 -->
<span class="label">钢种</span>
<span class="value">{{ item.steelGradeLabel || '-' }}</span>
</div>
<div>
<span class="label">Data Source</span>
<!-- 数据来源 -->
<span class="label">数据来源</span>
<span class="value">{{ item.sourceLabel }}</span>
</div>
</div>
<div class="card-footer">
<span>{{ item.updateTime ? 'Recently updated ' + formatDate(item.updateTime) : 'Click to write thickness/yield point' }}</span>
<!-- 最近更新 / 点击写入厚度/屈服点 -->
<span>{{ item.updateTime ? '最近更新 ' + formatDate(item.updateTime) : '点击写入厚度/屈服点' }}</span>
<i class="el-icon-top-right" />
</div>
</div>
@@ -120,20 +104,17 @@
</template>
<el-empty
v-else
description="Fill in thickness to get recommended yield point"
description="填写厚度后可获取推荐屈服点"
:image-size="100"
/>
<!-- 填写厚度后可获取推荐屈服点 -->
</div>
</div>
<div class="recommend-section width-panel">
<div class="section-header">
<div>
<div class="section-title">Width / Bending Force Linkage</div>
<!-- 宽度 / 弯辊联动 -->
<div class="section-subtitle">Match bending force and width combination based on width & roll force</div>
<!-- 根据宽度 & 轧制力匹配弯辊力与宽度组合 -->
<div class="section-title">宽度/弯辊力联动</div>
<div class="section-subtitle">根据宽度&轧制力匹配弯辊力与宽度组合</div>
</div>
<el-tag v-if="entryWidth" size="mini" type="info">{{ formatNumber(entryWidth) }} mm</el-tag>
</div>
@@ -148,24 +129,20 @@
>
<div class="card-header">
<div class="card-title">{{ formatNumber(item.width) }} mm</div>
<el-tag size="mini" effect="plain">Roll Force {{ formatNumber(item.rollForce) }}</el-tag>
<!-- 轧制力 -->
<el-tag size="mini" effect="plain">轧制力 {{ formatNumber(item.rollForce) }}</el-tag>
</div>
<div class="card-meta">
<div>
<span class="label">Bending Force</span>
<!-- 弯辊力 -->
<span class="label">弯辊力</span>
<span class="value">{{ formatNumber(item.bendForce) }}</span>
</div>
<div>
<span class="label">Data Source</span>
<!-- 数据来源 -->
<span class="label">数据来源</span>
<span class="value">{{ item.sourceLabel }}</span>
</div>
</div>
<div class="card-footer">
<span>Click to write width / roll force</span>
<!-- 点击写入宽度 / 轧制力 -->
<span>点击写入宽度/轧制力</span>
<i class="el-icon-top-right" />
</div>
</div>
@@ -173,20 +150,17 @@
</template>
<el-empty
v-else
description="Fill in width to get recommendations"
description="填写宽度后可获取推荐数据"
:image-size="100"
/>
<!-- 填写宽度后可获取推荐 -->
</div>
</div>
<div class="recommend-section rollforce-panel">
<div class="section-header">
<div>
<div class="section-title">Roll Force Reverse Lookup</div>
<!-- 轧制力反查 -->
<div class="section-subtitle">After entering roll force, reverse lookup corresponding thickness / yield point combination</div>
<!-- 输入轧制力后反查对应厚度 / 屈服点组合 -->
<div class="section-title">轧制力反查</div>
<div class="section-subtitle">输入轧制力后反查对应厚度/屈服点组合</div>
</div>
<el-tag v-if="spmRollforce" size="mini" type="warning">{{ formatNumber(spmRollforce) }}</el-tag>
</div>
@@ -205,31 +179,26 @@
</div>
<div class="card-meta">
<div>
<span class="label">Thickness</span>
<!-- 厚度 -->
<span class="label">厚度</span>
<span class="value">{{ formatNumber(item.entryThick) }} mm</span>
</div>
<div>
<span class="label">Yield Point</span>
<!-- 屈服点 -->
<span class="label">屈服点</span>
<span class="value">{{ formatNumber(item.yieldPoint) }}</span>
</div>
</div>
<div class="card-meta">
<div>
<span class="label">Elongation</span>
<!-- 延伸率 -->
<span class="label">延伸率</span>
<span class="value">{{ formatNumber(item.spmElongation) }}</span>
</div>
<div>
<span class="label">Steel Grade</span>
<!-- 钢种 -->
<span class="label">钢种</span>
<span class="value">{{ item.steelGradeLabel || '-' }}</span>
</div>
</div>
<div class="card-footer">
<span>Click to write related fields</span>
<!-- 点击写入相关字段 -->
<span>点击写入相关字段</span>
<i class="el-icon-top-right" />
</div>
</div>
@@ -237,10 +206,9 @@
</template>
<el-empty
v-else
description="Fill in roll force to get recommendations"
description="填写轧制力后可获取推荐数据"
:image-size="100"
/>
<!-- 填写轧制力后可获取推荐 -->
</div>
</div>
</div>
@@ -393,7 +361,7 @@ export default {
this.steelRecommendations = rows.map(row => this.mapRollforceRow(row))
} catch (error) {
console.error('fetchSteelRecommendations error:', error)
this.$message?.error('Failed to get steel grade recommendation, please retry later') // 钢种推荐获取失败,请稍后重试
this.$message?.error('钢种推荐获取失败,请稍后重试')
this.steelRecommendations = []
} finally {
if (token === this.steelFetchToken) {
@@ -423,7 +391,7 @@ export default {
const records = []
if (rollforceRes.status === 'fulfilled') {
const rows = Array.isArray(rollforceRes.value.rows) ? rollforceRes.value.rows : []
records.push(...rows.map(row => this.mapRollforceRow(row, 'TM Roll Force'))) // 光整机轧制力
records.push(...rows.map(row => this.mapRollforceRow(row, '光整机轧制力')))
}
if (tensionRes.status === 'fulfilled') {
const rows = Array.isArray(tensionRes.value.rows) ? tensionRes.value.rows : []
@@ -432,7 +400,7 @@ export default {
this.thicknessRecommendations = this.uniqueRecords(records).slice(0, 8)
} catch (error) {
console.error('fetchThicknessRecommendations error:', error)
this.$message?.error('Failed to get thickness recommendation, please retry later') // 厚度推荐获取失败,请稍后重试
this.$message?.error('厚度推荐获取失败,请稍后重试')
this.thicknessRecommendations = []
} finally {
if (token === this.thicknessFetchToken) {
@@ -466,7 +434,7 @@ export default {
this.widthRecommendations = matches.slice(0, 6)
} catch (error) {
console.error('fetchWidthRecommendations error:', error)
this.$message?.error('Failed to get width recommendation, please retry later') // 宽度推荐获取失败,请稍后重试
this.$message?.error('宽度推荐获取失败,请稍后重试')
this.widthRecommendations = []
} finally {
if (token === this.widthFetchToken) {
@@ -500,7 +468,7 @@ export default {
this.rollforceFocusRecommendations = matches.slice(0, 6)
} catch (error) {
console.error('fetchRollforceFocus error:', error)
this.$message?.error('Failed to get roll force recommendation, please retry later') // 轧制力推荐获取失败,请稍后重试
this.$message?.error('轧制力推荐获取失败,请稍后重试')
this.rollforceFocusRecommendations = []
} finally {
if (token === this.rollforceFetchToken) {
@@ -508,7 +476,7 @@ export default {
}
}
},
mapRollforceRow(row, sourceLabel = 'TM Roll Force') { // 光整机轧制力
mapRollforceRow(row, sourceLabel = '光整机轧制力') {
const gradeLabel =
row.steelGradeName ||
row.steelGradeLabel ||
@@ -528,7 +496,7 @@ export default {
},
mapRollforceByValueRow(row) {
return {
...this.mapRollforceRow(row, 'Roll Force Panel'), // 轧制力面板
...this.mapRollforceRow(row, '轧制力面板'),
_id: `rollforce-focus-${row.id || createId()}`,
spmRollforce: row.value1
}
@@ -537,7 +505,7 @@ export default {
const gradeLabel = row.steelGradeName || this.getSteelGradeLabel(row.steelGrade) || row.steelGrade
return {
_id: `tension-${row.id || createId()}`,
sourceLabel: 'Full Line Tension', // 全线张力
sourceLabel: '全线张力',
steelGrade: row.steelGrade,
steelGradeLabel: gradeLabel || '',
entryThick: row.thick,
@@ -550,7 +518,7 @@ export default {
mapBendforceRow(row) {
return {
_id: `bendforce-${row.id || createId()}`,
sourceLabel: 'Bending Force Panel', // 弯辊力面板
sourceLabel: '弯辊力面板',
width: row.width,
rollForce: row.rollForce,
bendForce: row.value1,
@@ -748,5 +716,4 @@ export default {
display: flex;
flex-direction: column;
}
</style>
</style>

View File

@@ -3,19 +3,15 @@
<el-card shadow="never">
<div class="recommend-header">
<div>
<div class="title">Recommended Process Parameters</div>
<!-- 推荐工艺参数 -->
<div class="subtitle">Click to fill in the left form, one row displays more fields</div>
<!-- 点击即可填入左侧表单一行展示更多字段 -->
<div class="title">推荐工艺参数</div>
<div class="subtitle">点击即可填入左侧表单一行展示更多字段</div>
</div>
<el-button type="text" icon="el-icon-finished" :disabled="!hasRecommendation" @click="$emit('apply-all')">
Apply All
全部套用
</el-button>
<!-- 全部套用 -->
</div>
<div v-if="!hasRecommendation" class="empty-state">
<el-empty description="No recommendation data, please complete basic information first" :image-size="90" />
<!-- 暂无推荐数据先补齐基础信息 -->
<el-empty description="暂无推荐数据,先补齐基础信息" :image-size="90" />
</div>
<div v-else class="group-list">
<div class="group" v-for="group in parameterGroups" :key="group.title">
@@ -55,19 +51,23 @@ export default {
return PARAMETER_GROUPS
},
hasRecommendation() {
// 判断是否存在有效的推荐数据
return Object.values(this.recommendation || {}).some(val => this.hasValue(val))
}
},
methods: {
// 判断值是否有效非null、undefined、空字符串
hasValue(value) {
return !(value === null || value === undefined || value === '')
},
// 格式化显示值:无效值显示-,数字保留两位小数(整数除外)
formatValue(value) {
if (!this.hasValue(value)) return '-'
const num = Number(value)
if (Number.isNaN(num)) return value
return Number.isInteger(num) ? num : num.toFixed(2)
},
// 单个参数套用逻辑
handleApply(key) {
if (!this.hasValue(this.recommendation[key])) return
this.$emit('apply-one', key)
@@ -169,5 +169,4 @@ export default {
font-size: 12px;
color: #c0c4cc;
}
</style>
</style>

View File

@@ -4,13 +4,11 @@
<el-alert
type="info"
:closable="false"
title="Process Parameter Generation Hint"
<!-- 工艺参数生成提示 -->
title="工艺参数生成提示"
>
<div class="hint-text">
Please complete the following basic information first, then the system can automatically match recommended process parameters:
请先补齐以下基础信息系统才可以自动匹配推荐的工艺参数
</div>
<!-- 请先补齐以下基础信息系统才可以自动匹配推荐的工艺参数 -->
<div class="hint-tags">
<el-tag
v-for="label in missingFieldLabels"
@@ -28,106 +26,91 @@
<el-form :model="form" label-width="150px" v-loading="loading">
<el-row>
<el-col :span="8">
<el-form-item label="Pay-off Reel Tension">
<!-- 开卷机张力 -->
<el-form-item label="开卷机张力">
<el-input v-model="form.porTension" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Entry Loop Tension">
<!-- 入口活套张力 -->
<el-form-item label="入口活套张力">
<el-input v-model="form.celTension" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Cleaning Section Tension">
<!-- 清洗段张力 -->
<el-form-item label="清洗段张力">
<el-input v-model="form.cleanTension" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Furnace Zone Tension">
<!-- 炉区张力 -->
<el-form-item label="炉区张力">
<el-input v-model="form.furTension" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Cooling Tower Tension">
<!-- 冷却塔张力 -->
<el-form-item label="冷却塔张力">
<el-input v-model="form.towerTension" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TM No Tension">
<!-- 光整机不投张力 -->
<el-form-item label="光整机不投张力">
<el-input v-model="form.tmNoneTension" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TM Entry Tension">
<!-- 光整机入口张力 -->
<el-form-item label="光整机入口张力">
<el-input v-model="form.tmEntryTension" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TM Exit Tension">
<!-- 光整机出口张力 -->
<el-form-item label="光整机出口张力">
<el-input v-model="form.tmExitTension" @change="syncModal" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="TM Roll Force">
<!-- 光整机轧制力 -->
<el-form-item label="光整机轧制力">
<el-input v-model="form.tmRollforce" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TM Bending Force">
<!-- 光整机弯辊力 -->
<el-form-item label="光整机弯辊力">
<el-input v-model="form.tmBendforce" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TM Anti-crimping Roll Mesh">
<!-- 光整机防皱辊插入量 -->
<el-form-item label="光整机防皱辊插入量">
<el-input v-model="form.tmAcrMesh" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TM Anti-tremor Roll Mesh">
<!-- 光整机防颤辊插入量 -->
<el-form-item label="光整机防颤辊插入量">
<el-input v-model="form.tmBrMesh" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TL Elongation">
<!-- 拉矫机延伸率 -->
<el-form-item label="拉矫机延伸率">
<el-input v-model="form.tlElong" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TL Leveling Roll Mesh 1">
<!-- 拉矫机矫直辊插入量1 -->
<el-form-item label="拉矫机矫直辊插入量1">
<el-input v-model="form.tlLvlMesh1" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="TL Leveling Roll Mesh 2">
<!-- 拉矫机矫直辊插入量2 -->
<el-form-item label="拉矫机矫直辊插入量2">
<el-input v-model="form.tlLvlMesh2" @change="syncModal" />
</el-form-item>
</el-col>
@@ -135,22 +118,19 @@
<el-row>
<el-col :span="8">
<el-form-item label="Furnace Preheating Section Exit Strip Temp">
<!-- 炉火段预热段出口板温 -->
<el-form-item label="炉火段预热段出口板温">
<el-input v-model="form.preheatingSection" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Furnace Heating Section Exit Strip Temp">
<!-- 炉火段加热段出口板温 -->
<el-form-item label="炉火段加热段出口板温">
<el-input v-model="form.heatingSection" @change="syncModal" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Furnace Cooling Section Exit Strip Temp">
<!-- 炉火段冷却段出口板温 -->
<el-form-item label="炉火段冷却段出口板温">
<el-input v-model="form.coolingSection" @change="syncModal" />
</el-form-item>
</el-col>
@@ -161,17 +141,13 @@
<el-card class="recommend-card" shadow="never">
<div class="recommend-header">
<div>
<div class="title">Recommended Process Parameters</div>
<!-- 推荐工艺参数 -->
<div class="subtitle">Click to fill in the left form</div>
<!-- 点击即可填入左侧表单 -->
<div class="title">推荐工艺参数</div>
<div class="subtitle">点击即可填入左侧表单</div>
</div>
<el-button type="text" @click="applyAll" :disabled="!hasRecommendation">Apply All</el-button>
<!-- 全部套用 -->
<el-button type="text" @click="applyAll" :disabled="!hasRecommendation">全部套用</el-button>
</div>
<div v-if="!hasRecommendation" class="empty-recommend">
<el-empty description="No recommendation data" :image-size="100"></el-empty>
<!-- 暂无推荐数据 -->
<el-empty description="暂无推荐数据" :image-size="100"></el-empty>
</div>
<div v-else class="recommend-groups">
<div
@@ -204,12 +180,12 @@
</template>
<script>
import { getBendforce } from '@/api/business/bendforce' // TM Bending Force / 光整机弯辊力
import { getTension } from '@/api/business/tension' // Full Line Tension / 全线张力
import { getRollforce } from '@/api/business/rollforce' // TM Roll Force / 光整机轧制力
import { getTl } from '@/api/business/tl' // TL / 拉矫机
import { getMesh } from '@/api/business/mesh' // TM Mesh / 光整机插入量
import { getFur } from '@/api/business/fur' // Furnace Section / 炉火段
import { getBendforce } from '@/api/business/bendforce' // 光整机弯辊力
import { getTension } from '@/api/business/tension' // 全线张力
import { getRollforce } from '@/api/business/rollforce' // 光整机轧制力
import { getTl } from '@/api/business/tl' // 拉矫机
import { getMesh } from '@/api/business/mesh' // 光整机插入量
import { getFur } from '@/api/business/fur' // 炉火段
import { PARAMETER_GROUPS } from './setupRecommendationConfig'
const REQUIRED_FIELDS = [
@@ -222,46 +198,46 @@ const REQUIRED_FIELDS = [
]
const FIELD_LABEL_MAP = {
entryThick: 'Entry Thickness', // 入口厚度
yieldPoint: 'Yield Point', // 屈服点
steelGrade: 'Steel Grade', // 钢种
spmElongation: 'Elongation (%)', // 延伸率(%)
spmRollforce: 'SPM Roll Force', // SPM轧制力
entryWidth: 'Entry Width' // 入口宽度
entryThick: '入口厚度',
yieldPoint: '屈服点',
steelGrade: '钢种',
spmElongation: '延伸率(%)',
spmRollforce: 'SPM轧制力',
entryWidth: '入口宽度'
}
const createDefaultForm = () => ({
// Full Line Tension / 全线张力
porTension: undefined, // Pay-off Reel Tension / 开卷机张力
celTension: undefined, // Entry Loop Tension / 入口活套张力
cleanTension: undefined, // Cleaning Section Tension / 清洗段张力
furTension: undefined, // Furnace Zone Tension / 炉区张力
towerTension: undefined, // Cooling Tower Tension / 冷却塔张力
tmNoneTension: undefined, // TM No Tension / 光整机不投张力
tmEntryTension: undefined, // TM Entry Tension / 光整机入口张力
tmExitTension: undefined, // TM Exit Tension / 光整机出口张力
tlNoneTension: undefined, // TL No Tension / 拉矫机不投张力
tlExitTension: undefined, // TL Exit Tension / 拉矫机出口张力
coatTension: undefined, // Post-treatment Tension / 后处理张力
cxlTension: undefined, // Exit Loop Tension / 出口活套张力
trTension: undefined, // Take-up Reel Tension / 卷取机张力
// 全线张力
porTension: undefined, // 开卷机张力
celTension: undefined, // 入口活套张力
cleanTension: undefined, // 清洗段张力
furTension: undefined, // 炉区张力
towerTension: undefined, // 冷却塔张力
tmNoneTension: undefined, // 光整机不投张力
tmEntryTension: undefined, // 光整机入口张力
tmExitTension: undefined, // 光整机出口张力
tlNoneTension: undefined, // 拉矫机不投张力
tlExitTension: undefined, // 拉矫机出口张力
coatTension: undefined, // 后处理张力
cxlTension: undefined, // 出口活套张力
trTension: undefined, // 卷取机张力
// TM / 光整机
tmRollforce: undefined, // TM Roll Force / 光整机轧制力
tmBendforce: undefined, // TM Bending Force / 光整机弯辊力
tmAcrMesh: undefined, // TM Anti-crimping Roll Mesh / 光整机防皱辊插入量
tmBrMesh: undefined, // TM Anti-tremor Roll Mesh / 光整机防颤辊插入量
// 光整机
tmRollforce: undefined, // 光整机轧制力
tmBendforce: undefined, // 光整机弯辊力
tmAcrMesh: undefined, // 光整机防皱辊插入量
tmBrMesh: undefined, // 光整机防颤辊插入量
// TL / 拉矫机
tlElong: undefined, // TL Elongation / 拉矫机延伸率
tlLvlMesh1: undefined, // TL Leveling Roll Mesh 1 / 拉矫机矫直辊插入量1
tlLvlMesh2: undefined, // TL Leveling Roll Mesh 2 / 拉矫机矫直辊插入量2
tlAcbMesh: undefined, // TL Anti-crossbow Mesh / 拉矫机防横弓插入量
// 拉矫机
tlElong: undefined, // 拉矫机延伸率
tlLvlMesh1: undefined, // 拉矫机矫直辊插入量1
tlLvlMesh2: undefined, // 拉矫机矫直辊插入量2
tlAcbMesh: undefined, // 拉矫机防横弓插入量
// Furnace Section / 炉火段
preheatingSection: undefined, // Furnace Preheating Section Exit Strip Temp / 炉火段预热段出口板温
heatingSection: undefined, // Furnace Heating Section Exit Strip Temp / 炉火段加热段出口板温
coolingSection: undefined, // Furnace Cooling Section Exit Strip Temp / 炉火段冷却段出口板温
// 炉火段
preheatingSection: undefined, // 炉火段预热段出口板温
heatingSection: undefined, // 炉火段加热段出口板温
coolingSection: undefined, // 炉火段冷却段出口板温
})
export default {
@@ -414,7 +390,7 @@ export default {
this.recommendation.coolingSection = data.value3
}
} catch (error) {
console.error('Failed to get process parameter hint', error) // 获取工艺参数提示失败
console.error('获取工艺参数提示失败', error)
} finally {
this.loading = false
this.emitRecommendationChange()
@@ -455,7 +431,7 @@ export default {
.setup-hint {
margin-bottom: 12px;
}
q
.hint-text {
font-size: 13px;
color: #909399;

View File

@@ -1,133 +1,103 @@
<template>
<el-tabs>
<el-tab-pane label="Full Line Tension">
<!-- 全线张力 -->
<el-tab-pane label="全线张力">
<el-descriptions :column="1">
<el-descriptions-item label="Pay-off Reel Tension">
<!-- 开卷机张力 -->
<el-descriptions-item label="开卷机张力">
{{ setupForm.porTension }}
</el-descriptions-item>
<el-descriptions-item label="Entry Loop Tension">
<!-- 入口活套张力 -->
<el-descriptions-item label="入口活套张力">
{{ setupForm.celTension }}
</el-descriptions-item>
<el-descriptions-item label="Cleaning Section Tension">
<!-- 清洗段张力 -->
<el-descriptions-item label="清洗段张力">
{{ setupForm.cleanTension }}
</el-descriptions-item>
<el-descriptions-item label="Furnace Zone Tension">
<!-- 炉区张力 -->
<el-descriptions-item label="炉区张力">
{{ setupForm.furTension }}
</el-descriptions-item>
<el-descriptions-item label="Cooling Tower Tension">
<!-- 冷却塔张力 -->
<el-descriptions-item label="冷却塔张力">
{{ setupForm.towerTension }}
</el-descriptions-item>
<el-descriptions-item label="TM No Tension">
<!-- 光整机不投张力 -->
<el-descriptions-item label="光整机不投张力">
{{ setupForm.tmNoneTension }}
</el-descriptions-item>
<el-descriptions-item label="TM Entry Tension">
<!-- 光整机入口张力 -->
<el-descriptions-item label="光整机入口张力">
{{ setupForm.tmEntryTension }}
</el-descriptions-item>
<el-descriptions-item label="TM Exit Tension">
<!-- 光整机出口张力 -->
<el-descriptions-item label="光整机出口张力">
{{ setupForm.tmExitTension }}
</el-descriptions-item>
<el-descriptions-item label="TL No Tension">
<!-- 拉矫机不投张力 -->
<el-descriptions-item label="拉矫机不投张力">
{{ setupForm.tlNoneTension }}
</el-descriptions-item>
<el-descriptions-item label="TL Exit Tension">
<!-- 拉矫机出口张力 -->
<el-descriptions-item label="拉矫机出口张力">
{{ setupForm.tlExitTension }}
</el-descriptions-item>
<el-descriptions-item label="Post-treatment Tension">
<!-- 后处理张力 -->
<el-descriptions-item label="后处理张力">
{{ setupForm.coatTension }}
</el-descriptions-item>
<el-descriptions-item label="Exit Loop Tension">
<!-- 出口活套张力 -->
<el-descriptions-item label="出口活套张力">
{{ setupForm.cxlTension }}
</el-descriptions-item>
<el-descriptions-item label="Take-up Reel Tension">
<!-- 卷取机张力 -->
<el-descriptions-item label="卷取机张力">
{{ setupForm.trTension }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="TL Parameters">
<!-- 拉矫机参数 -->
<el-tab-pane label="拉矫机参数">
<el-descriptions :column="1">
<el-descriptions-item label="TL Elongation">
<!-- 拉矫机延伸率 -->
<el-descriptions-item label="拉矫机延伸率">
{{ setupForm.tlElong }}
</el-descriptions-item>
<el-descriptions-item label="TL Leveling Roll Mesh 1">
<!-- 拉矫机矫直辊插入量1 -->
<el-descriptions-item label="拉矫机矫直辊插入量1">
{{ setupForm.tlLvlMesh1 }}
</el-descriptions-item>
<el-descriptions-item label="TL Leveling Roll Mesh 2">
<!-- 拉矫机矫直辊插入量2 -->
<el-descriptions-item label="拉矫机矫直辊插入量2">
{{ setupForm.tlLvlMesh2 }}
</el-descriptions-item>
<el-descriptions-item label="TL Anti-crossbow Mesh">
<!-- 拉矫机防横弓插入量 -->
<el-descriptions-item label="拉矫机防横弓插入量">
{{ setupForm.tlAcbMesh }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="TM Bending Force">
<!-- 光整机弯辊力 -->
<el-tab-pane label="光整机弯辊力">
<el-descriptions :column="1">
<el-descriptions-item label="TM Bending Force">
<!-- 光整机弯辊力 -->
<el-descriptions-item label="光整机弯辊力">
{{ setupForm.tmBendforce }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="TM Mesh">
<!-- 光整机插入量 -->
<el-tab-pane label="光整机插入量">
<el-descriptions :column="1">
<el-descriptions-item label="TM Anti-crimping Roll Mesh">
<!-- 光整机防皱辊插入量 -->
<el-descriptions-item label="光整机防皱辊插入量">
{{ setupForm.tmAcrMesh }}
</el-descriptions-item>
<el-descriptions-item label="TM Anti-tremor Roll Mesh">
<!-- 光整机防颤辊插入量 -->
<el-descriptions-item label="光整机防颤辊插入量">
{{ setupForm.tmBrMesh }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="TM Roll Force">
<!-- 光整机轧制力 -->
<el-tab-pane label="光整机轧制力">
<el-descriptions :column="1">
<el-descriptions-item label="TM Roll Force">
<!-- 光整机轧制力 -->
<el-descriptions-item label="光整机轧制力">
{{ setupForm.tmRollforce }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="Furnace Section">
<!-- 炉火段 -->
<el-tab-pane label="炉火段">
<el-descriptions :column="1">
<el-descriptions-item label="Preheating Section Exit Strip Temp">
<!-- 预热段出口板温 -->
<el-descriptions-item label="预热段出口板温">
{{ setupForm.preheatingSection }}
</el-descriptions-item>
<el-descriptions-item label="Heating Section Exit Strip Temp">
<!-- 加热段出口板温 -->
<el-descriptions-item label="加热段出口板温">
{{ setupForm.heatingSection }}
</el-descriptions-item>
<el-descriptions-item label="Cooling Section Exit Strip Temp">
<!-- 冷却段出口板温 -->
<el-descriptions-item label="冷却段出口板温">
{{ setupForm.coolingSection }}
</el-descriptions-item>
</el-descriptions>
@@ -136,7 +106,7 @@
</template>
<script>
// Receive data, render as tabs / 接收数据渲染为tab
// 接收数据渲染为tab
export default {
props: {
setupForm: {

View File

@@ -1,18 +1,17 @@
<template>
<div class="plan-management-industrial">
<!-- Top toolbar / 顶部工具栏 -->
<!-- 顶部工具栏 -->
<div class="toolbar">
<el-button type="primary" @click="handleAdd" icon="el-icon-plus" size="small">
Add Plan
</el-button>
<!-- 新增计划 -->
<el-button @click="getList" icon="el-icon-refresh" size="small">
Refresh
新增计划
</el-button>
<!-- 刷新 -->
<el-button @click="getList" icon="el-icon-refresh" size="small">
刷新
</el-button>
</div>
<!-- Producing section / 正在生产区 -->
<!-- 正在生产区 -->
<div class="producing-section" v-if="productingPlans.length > 0">
<div class="producing-cards">
<el-card
@@ -24,9 +23,8 @@
>
<div class="card-status">
<span class="status-dot status-producing"></span>
<span class="status-text">Producing</span>
<!-- 生产中 -->
<!-- Current position / 当前位置 -->
<span class="status-text">生产中</span>
<!-- 当前位置 -->
<div class="card-position" v-if="getPlanPosition(plan)">
<i class="el-icon-location"></i>
{{ getPlanPosition(plan).positionNameCn }}
@@ -35,58 +33,50 @@
<div class="card-content">
<div class="card-main">
<div class="plan-id">{{ plan.planid }}</div>
<div class="coil-id">Coil ID: {{ plan.coilid }}</div>
<!-- 钢卷号 -->
<div class="coil-id">钢卷号{{ plan.coilid }}</div>
</div>
<div class="card-details">
<div class="detail-item">
<span class="label">Steel Grade:</span>
<!-- 钢种 -->
<span class="label">钢种</span>
<span class="value">{{ plan.steelGrade }}</span>
</div>
<div class="detail-item">
<span class="label">Thickness:</span>
<!-- 厚度 -->
<span class="label">厚度</span>
<span class="value">{{ plan.entryThick }} mm</span>
</div>
<div class="detail-item">
<span class="label">Width:</span>
<!-- 宽度 -->
<span class="label">宽度</span>
<span class="value">{{ plan.entryWidth }} mm</span>
</div>
<div class="detail-item">
<span class="label">Weight:</span>
<!-- 重量 -->
<span class="label">重量</span>
<span class="value">{{ plan.entryWeight }} t</span>
</div>
</div>
</div>
<div class="card-actions">
<el-button size="mini" type="text" @click.stop="handleUpdate(plan)" icon="el-icon-edit">
Edit
编辑
</el-button>
<!-- 编辑 -->
<el-button size="mini" type="text" @click.stop="handleDelete(plan)" icon="el-icon-delete">
Delete
删除
</el-button>
<!-- 删除 -->
</div>
</el-card>
</div>
</div>
<!-- Main content area / 主内容区 -->
<!-- 主内容区 -->
<el-row :gutter="20" class="main-content">
<!-- Left: Plan queue (tabs) / 左侧计划队列标签页 -->
<!-- 左侧计划队列标签页 -->
<el-col :span="10" class="left-panel">
<div class="queue-tabs-section">
<el-tabs v-model="queueTab">
<!-- Production queue tab / 生产队列标签页 -->
<!-- 生产队列标签页 -->
<el-tab-pane name="pending">
<span slot="label">
<i class="el-icon-s-order"></i>
Production Queue
<!-- 生产队列 -->
生产队列
<el-badge :value="pendingPlans.length" class="tab-badge" />
</span>
<div v-loading="loading" class="plan-list">
@@ -113,10 +103,9 @@
plan.status === 'READY' ? 'primary' : 'info'"
size="mini"
>
{{ plan.status === 'PRODUCING' ? 'Producing' :
plan.status === 'ONLINE' ? 'Online' :
plan.status === 'READY' ? 'Ready' : 'New' }}
<!-- 生产中 / 在机 / 就绪 / 新建 -->
{{ plan.status === 'PRODUCING' ? '生产中' :
plan.status === 'ONLINE' ? '在机' :
plan.status === 'READY' ? '就绪' : '新建' }}
</el-tag>
</div>
<div class="plan-content">
@@ -129,7 +118,7 @@
<span>{{ plan.entryThick }}×{{ plan.entryWidth }} mm</span>
<span>{{ plan.entryWeight }} t</span>
</div>
<!-- Position info (only shown for PRODUCING status) / 位置信息仅生产中状态显示 -->
<!-- 位置信息仅生产中状态显示 -->
<div class="plan-position" v-if="plan.status === 'PRODUCING' && getPlanPosition(plan)">
<i class="el-icon-location"></i>
<span>{{ getPlanPosition(plan).positionNameCn }}</span>
@@ -141,18 +130,16 @@
</div>
</div>
<div v-if="pendingPlans.length === 0" class="empty-text">
No production plans
暂无生产计划
</div>
<!-- 暂无生产计划 -->
</div>
</el-tab-pane>
<!-- History tab / 历史记录标签页 -->
<!-- 历史记录标签页 -->
<el-tab-pane name="history">
<span slot="label">
<i class="el-icon-document-checked"></i>
History
<!-- 历史记录 -->
历史记录
<el-badge :value="historyPlans.length" class="tab-badge" />
</span>
<div class="plan-list">
@@ -165,8 +152,7 @@
>
<div class="plan-status">
<span class="status-dot status-history"></span>
<el-tag type="info" size="mini">Completed</el-tag>
<!-- 已完成 -->
<el-tag type="info" size="mini">已完成</el-tag>
</div>
<div class="plan-content">
<div class="plan-main">
@@ -189,77 +175,60 @@
</div>
</div>
<div v-if="historyPlans.length === 0" class="empty-text">
No history records
暂无历史记录
</div>
<!-- 暂无历史记录 -->
</div>
</el-tab-pane>
</el-tabs>
</div>
</el-col>
<!-- Right: Plan details and tension data / 右侧计划详情和张力数据 -->
<!-- 右侧计划详情和张力数据 -->
<el-col :span="14" class="right-panel">
<div v-if="currentRow" class="detail-section">
<div class="section-header">
<i class="el-icon-data-line"></i>
<span>Plan Details & Process Parameters</span>
<!-- 计划详情与工艺参数 -->
<span>计划详情与工艺参数</span>
</div>
<!-- Unified detail card / 整合的详情卡片 -->
<!-- 整合的详情卡片 -->
<el-card class="detail-card-unified" shadow="never">
<el-tabs v-model="activeTab" type="border-card">
<!-- Basic info tab / 基础信息标签页 -->
<el-tab-pane label="Basic Info" name="basic">
<!-- 基础信息 -->
<!-- 基础信息标签页 -->
<el-tab-pane label="基础信息" name="basic">
<el-descriptions :column="3" border size="small">
<el-descriptions-item label="Plan ID">{{ currentRow.planid }}</el-descriptions-item>
<!-- 计划号 -->
<el-descriptions-item label="Coil ID">{{ currentRow.coilid }}</el-descriptions-item>
<!-- 钢卷号 -->
<el-descriptions-item label="Steel Grade">{{ currentRow.steelGrade }}</el-descriptions-item>
<!-- 钢种 -->
<el-descriptions-item label="Yield Point">{{ currentRow.yieldPoint }}</el-descriptions-item>
<!-- 屈服点 -->
<el-descriptions-item label="Weight (t)">{{ currentRow.entryWeight }}</el-descriptions-item>
<!-- 重量(t) -->
<el-descriptions-item label="Thickness (mm)">{{ currentRow.entryThick }}</el-descriptions-item>
<!-- 厚度(mm) -->
<el-descriptions-item label="Width (mm)">{{ currentRow.entryWidth }}</el-descriptions-item>
<!-- 宽度(mm) -->
<el-descriptions-item label="Length (mm)">{{ currentRow.entryLength }}</el-descriptions-item>
<!-- 长度(mm) -->
<el-descriptions-item label="Outer Diameter (mm)">{{ currentRow.entryOuterDiameter }}</el-descriptions-item>
<!-- 外径(mm) -->
<el-descriptions-item label="Elongation (%)">{{ currentRow.spmElongation }}</el-descriptions-item>
<!-- 延伸率(%) -->
<el-descriptions-item label="SPM Roll Force">{{ currentRow.spmRollforce }}</el-descriptions-item>
<!-- SPM轧制力 -->
<el-descriptions-item label="计划号">{{ currentRow.planid }}</el-descriptions-item>
<el-descriptions-item label="钢卷号">{{ currentRow.coilid }}</el-descriptions-item>
<el-descriptions-item label="钢种">{{ currentRow.steelGrade }}</el-descriptions-item>
<el-descriptions-item label="屈服点">{{ currentRow.yieldPoint }}</el-descriptions-item>
<el-descriptions-item label="重量(t)">{{ currentRow.entryWeight }}</el-descriptions-item>
<el-descriptions-item label="厚度(mm)">{{ currentRow.entryThick }}</el-descriptions-item>
<el-descriptions-item label="宽度(mm)">{{ currentRow.entryWidth }}</el-descriptions-item>
<el-descriptions-item label="长度(mm)">{{ currentRow.entryLength }}</el-descriptions-item>
<el-descriptions-item label="外径(mm)">{{ currentRow.entryOuterDiameter }}</el-descriptions-item>
<el-descriptions-item label="延伸率(%)">{{ currentRow.spmElongation }}</el-descriptions-item>
<el-descriptions-item label="SPM轧制力">{{ currentRow.spmRollforce }}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- Process parameters tab / 工艺参数标签页 -->
<el-tab-pane label="Process Parameters" name="process" v-loading="setupLoading">
<!-- 工艺参数 -->
<!-- 工艺参数标签页 -->
<el-tab-pane label="工艺参数" name="process" v-loading="setupLoading">
<setup-pane v-if="!setupLoading && setupForm" :setup-form="setupForm" />
<div v-if="!setupLoading && !setupForm" class="empty-text">
No process parameter data
暂无工艺参数数据
</div>
<!-- 暂无工艺参数数据 -->
</el-tab-pane>
</el-tabs>
</el-card>
</div>
<div v-else class="empty-section">
<i class="el-icon-info"></i>
<p>Please select a plan from the left to view details</p>
<!-- 请从左侧选择一个计划查看详情 -->
<p>请从左侧选择一个计划查看详情</p>
</div>
</el-col>
</el-row>
<!-- Edit/Add dialog / 编辑/新增弹窗 -->
<!-- 编辑/新增弹窗 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="80%" :close-on-click-modal="false"
append-to-body>
<div class="plan-dialog-body">
@@ -267,113 +236,83 @@
<el-form :model="form" ref="form" label-width="90px" :rules="rules" size="mini" class="plan-base-form">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="Plan ID" prop="planid">
<!-- 计划ID -->
<el-input v-model="form.planid" placeholder="Please enter plan ID" maxLength="32"></el-input>
<!-- 请输入计划ID -->
<el-form-item label="计划ID" prop="planid">
<el-input v-model="form.planid" placeholder="请输入计划ID" maxLength="32"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Coil ID" prop="coilid">
<!-- 钢卷号 -->
<el-input v-model="form.coilid" placeholder="Please enter coil ID" maxLength="32"></el-input>
<!-- 请输入钢卷号 -->
<el-form-item label="钢卷号" prop="coilid">
<el-input v-model="form.coilid" placeholder="请输入钢卷号" maxLength="32"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Steel Grade" prop="steelGrade">
<!-- 钢种 -->
<el-select v-model="form.steelGrade" placeholder="Please select steel grade">
<!-- 请选择钢种 -->
<el-form-item label="钢种" prop="steelGrade">
<el-select v-model="form.steelGrade" placeholder="请选择钢种">
<el-option v-for="item in steelGradeList" :key="item.gradeid" :label="item.name"
:value="item.gradeid"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Thickness (mm)" prop="entryThick">
<!-- 厚度(mm) -->
<el-input v-model="form.entryThick" placeholder="Please enter entry thickness" type="number" step="0.01" min="0"></el-input>
<!-- 请输入入口厚度 -->
<el-form-item label="厚度(mm)" prop="entryThick">
<el-input v-model="form.entryThick" placeholder="请输入入口厚度" type="number" step="0.01" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Width (mm)" prop="entryWidth">
<!-- 宽度(mm) -->
<el-input v-model="form.entryWidth" placeholder="Please enter entry width" type="number" step="1" min="0"></el-input>
<!-- 请输入入口宽度 -->
<el-form-item label="宽度(mm)" prop="entryWidth">
<el-input v-model="form.entryWidth" placeholder="请输入入口宽度" type="number" step="1" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Yield Point" prop="yieldPoint">
<!-- 屈服点 -->
<el-input v-model="form.yieldPoint" placeholder="Please enter yield point" type="number" step="0.01" min="0"></el-input>
<!-- 请输入屈服点 -->
<el-form-item label="屈服点" prop="yieldPoint">
<el-input v-model="form.yieldPoint" placeholder="请输入屈服点" type="number" step="0.01" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Zinc Coating Thickness" prop="zincCoatingThickness">
<!-- 锌层厚度 -->
<el-input v-model="form.zincCoatingThickness" placeholder="Please enter zinc coating thickness" type="number" step="0.01" min="0"></el-input>
<!-- 请输入锌层厚度 -->
<el-form-item label="锌层厚度" prop="zincCoatingThickness">
<el-input v-model="form.zincCoatingThickness" placeholder="请输入锌层厚度" type="number" step="0.01" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Weight (t)" prop="entryWeight">
<!-- 重量(t) -->
<el-input v-model="form.entryWeight" placeholder="Please enter entry weight" type="number" step="0.01" min="0"></el-input>
<!-- 请输入入口重量 -->
<el-form-item label="重量(t)" prop="entryWeight">
<el-input v-model="form.entryWeight" placeholder="请输入入口重量" type="number" step="0.01" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Length (mm)" prop="entryLength">
<!-- 长度(mm) -->
<el-input v-model="form.entryLength" placeholder="Please enter entry length" type="number" step="1" min="0"></el-input>
<!-- 请输入入口长度 -->
<el-form-item label="长度(mm)" prop="entryLength">
<el-input v-model="form.entryLength" placeholder="请输入入口长度" type="number" step="1" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Outer Diameter (mm)" prop="entryOuterDiameter">
<!-- 外径(mm) -->
<el-input v-model="form.entryOuterDiameter" placeholder="Please enter entry outer diameter" type="number" step="1"
<el-form-item label="外径(mm)" prop="entryOuterDiameter">
<el-input v-model="form.entryOuterDiameter" placeholder="请输入入口外径" type="number" step="1"
min="0"></el-input>
<!-- 请输入入口外径 -->
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Elongation (%)" prop="spmElongation">
<!-- 延伸率(%) -->
<el-input v-model="form.spmElongation" placeholder="Please enter elongation" type="number" step="0.01" min="0"></el-input>
<!-- 请输入延伸率 -->
<el-form-item label="延伸率(%)" prop="spmElongation">
<el-input v-model="form.spmElongation" placeholder="请输入延伸率" type="number" step="0.01" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Roll Force" prop="spmRollforce">
<!-- 轧制力 -->
<el-input v-model="form.spmRollforce" placeholder="Please enter SPM roll force" type="number" step="0.01"
<el-form-item label="轧制力" prop="spmRollforce">
<el-input v-model="form.spmRollforce" placeholder="请输入SPM轧制力" type="number" step="0.01"
min="0"></el-input>
<!-- 请输入SPM轧制力 -->
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Exit Target Length" prop="exitLengthTar">
<!-- 出口目标长度 -->
<el-input v-model="form.exitLengthTar" placeholder="Please enter exit target length (mm)" type="number" step="1" min="0"></el-input>
<!-- 请输入出口目标长度(mm) -->
<el-form-item label="出口目标长度" prop="exitLengthTar">
<el-input v-model="form.exitLengthTar" placeholder="请输入出口目标长度(mm)" type="number" step="1" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Exit Target Thickness" prop="exitThickTar">
<!-- 出口目标厚度 -->
<el-input v-model="form.exitThickTar" placeholder="Please enter exit target thickness (mm)" type="number" step="0.01" min="0"></el-input>
<!-- 请输入出口目标厚度(mm) -->
<el-form-item label="出口目标厚度" prop="exitThickTar">
<el-input v-model="form.exitThickTar" placeholder="请输入出口目标厚度(mm)" type="number" step="0.01" min="0"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Exit Target Width" prop="exitWidthTar">
<!-- 出口目标宽度 -->
<el-input v-model="form.exitWidthTar" placeholder="Please enter exit target width (mm)" type="number" step="1" min="0"></el-input>
<!-- 请输入出口目标宽度(mm) -->
<el-form-item label="出口目标宽度" prop="exitWidthTar">
<el-input v-model="form.exitWidthTar" placeholder="请输入出口目标宽度(mm)" type="number" step="1" min="0"></el-input>
</el-form-item>
</el-col>
</el-row>
@@ -381,10 +320,8 @@
<div class="plan-dialog-actions">
<el-checkbox v-if="!form.id" v-model="spmFlag"
label="Generate Process Parameters (Recommended: complete basic info first)"></el-checkbox>
<!-- 生成工艺参数(建议先填写完成基础信息再勾选此选项) -->
<el-divider content-position="left" v-if="spmFlag">Process Parameters</el-divider>
<!-- 工艺参数 -->
label="生成工艺参数(建议先填写完整基础信息再勾选此选项)"></el-checkbox>
<el-divider content-position="left" v-if="spmFlag">工艺参数</el-divider>
<setup-form v-if="spmFlag" ref="setupFormRef" :income="form" :steel-grade-options="steelGradeList"
:plan-history="planList" :show-recommendation-panel="false" @input="handleSetupInput"
@recommendation-change="handleProcessRecommendation" />
@@ -400,12 +337,10 @@
@apply-width="handleApplyWidth" @apply-rollforce="handleApplyRollforce" />
</div>
</div>
<!-- Dialog footer buttons / 弹窗底部按钮 -->
<!-- 弹窗底部按钮 -->
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">Cancel</el-button>
<!-- 取消 -->
<el-button type="primary" @click="submitForm" :loading="saveLoading">Save</el-button>
<!-- 保存 -->
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm" :loading="saveLoading">保存</el-button>
</div>
</el-dialog>
</div>
@@ -474,35 +409,6 @@ export default {
setupLoading: false,
matMapList: [], // 物料位置映射列表
// 查询表单参数(与后端列表接口参数对齐)
// setupForm: {
// // 全线张力
// porTension: undefined, // 开卷机张力
// celTension: undefined, // 入口活套张力
// cleanTension: undefined, // 清洗段张力
// furTension: undefined, // 炉区张力
// towerTension: undefined, // 冷却塔张力
// tmNoneTension: undefined, // 光整机不投张力
// tmEntryTension: undefined, // 光整机入口张力
// tmExitTension: undefined, // 光整机出口张力
// tlNoneTension: undefined, // 拉矫机不投张力
// tlExitTension: undefined, // 拉矫机出口张力
// coatTension: undefined, // 后处理张力
// cxlTension: undefined, // 出口活套张力
// trTension: undefined, // 卷取机张力
// // 光整机
// tmRollforce: undefined, // 光整机轧制力
// tmBendforce: undefined, // 光整机弯辊力
// tmAcrMesh: undefined, // 光整机防皱辊插入量
// tmBrMesh: undefined, // 光整机防颤辊插入量
// // 拉矫机
// tlElong: undefined, // 拉矫机延伸率
// tlLvlMesh1: undefined, // 拉矫机矫直辊插入量1
// tlLvlMesh2: undefined, // 拉矫机矫直辊插入量2
// tlAcbMesh: undefined, // 拉矫机防横弓插入量
// },
// setupForm: undefined,
queryParams: {
coilid: "",
entryThick: null,
@@ -518,9 +424,9 @@ export default {
planList: [],
loading: false,
btnLoading: false,
// Dialog state (add/edit dialog visibility + title) / 弹窗状态(新增/编辑弹窗显隐+标题)
// 弹窗状态(新增/编辑弹窗显隐+标题)
dialogVisible: false,
dialogTitle: "Add Plan", // 新增计划
dialogTitle: "新增计划",
// 表单数据(与后端新增/编辑接口参数完全对齐)
form: {
id: null, // 主键ID组件内部用提交时后端自动处理
@@ -623,31 +529,31 @@ export default {
headendGaugeLength: null, // 头端测厚长度(mm)number接口要求
tailendGaugeLength: null, // 尾端测厚长度(mm)number接口要求
},
// Form validation rules (at least include required field validation) / 表单验证规则(至少包含必填字段校验)
// 表单验证规则(至少包含必填字段校验)
rules: {
coilid: [
{ required: true, message: "Coil ID cannot be empty", trigger: "blur" }, // 钢卷号不能为空
{ max: 32, message: "Coil ID length cannot exceed 32 characters", trigger: "blur" }, // 钢卷号长度不能超过32字符
{ required: true, message: "钢卷号不能为空", trigger: "blur" },
{ max: 32, message: "钢卷号长度不能超过32个字符", trigger: "blur" },
],
// Add status required validation / 新增 status 必填校验
// 新增 status 必填校验
status: [
{ required: true, message: "Please select plan status", trigger: "change" } // 请选择计划状态
{ required: true, message: "请选择计划状态", trigger: "change" }
]
},
// Save button loading state (avoid duplicate submission) / 保存按钮加载状态(避免重复提交)
// 保存按钮加载状态(避免重复提交)
saveLoading: false,
// Current selected row data (for row click, edit echo) / 当前选中行数据(用于行点击、编辑回显)
// 当前选中行数据(用于行点击、编辑回显)
currentRow: null,
steelGradeList: [],
processRecommendation: {},
};
},
computed: {
// Plans in production - for top independent display / 正在生产的计划 - 顶部独立显示用
// 正在生产的计划 - 顶部独立显示用
productingPlans() {
return this.planList.filter(plan => plan.status === 'PRODUCING');
},
// Production queue - only includes producing and pending, sorted by priority / 生产队列 - 只包含生产中和待生产,按优先级排序
// 生产队列 - 只包含生产中和待生产,按优先级排序
pendingPlans() {
const statusPriority = {
'PRODUCING': 1,
@@ -663,16 +569,16 @@ export default {
return priorityA - priorityB;
});
},
// On pay-off reel (ONLINE) / 在开卷机上 (ONLINE)
// 在开卷机上 (ONLINE)
onlinePlans() {
return this.planList.filter(plan => plan.status === 'ONLINE');
},
// History records - only show completed plans, sorted by completion time descending / 历史记录 - 只显示已完成的计划,按完成时间倒序
// 历史记录 - 只显示已完成的计划,按完成时间倒序
historyPlans() {
return this.planList
.filter(plan => plan.status === 'PRODUCT')
.sort((a, b) => {
// Sort by end time descending (newest completed first) / 按结束时间倒序排列(最新完成的在前)
// 按结束时间倒序排列(最新完成的在前)
if (a.endDate && b.endDate) {
return new Date(b.endDate) - new Date(a.endDate);
}
@@ -684,13 +590,13 @@ export default {
}
},
created() {
// Automatically load plan list when component is created / 组件创建时自动加载计划列表
// 组件创建时自动加载计划列表
this.getList();
this.fetchSteelGradeList();
this.fetchMatMapList();
},
methods: {
parseTime, // Mount date formatting method to instance / 挂载日期格式化方法到实例
parseTime, // 挂载日期格式化方法到实例
fetchSteelGradeList() {
getSteelGradeList().then(res => {
this.steelGradeList = res.data
@@ -706,7 +612,7 @@ export default {
String(item.name) === gid ||
String(item.gradeName || '') === gid
)
// Dropdown selector uses gradeid as value, ensure backfill id to display name / 下拉选择器以 gradeid 为 value确保回填 id 以显示名称
// 下拉选择器以 gradeid 为 value确保回填 id 以显示名称
this.form.steelGrade = match ? match.gradeid : payload.steelGrade
}
if (payload.entryThick) this.form.entryThick = payload.entryThick
@@ -744,27 +650,27 @@ export default {
if (!this.$refs.setupFormRef) return
this.$refs.setupFormRef.applyAll()
},
// Get material position mapping / 获取物料位置映射
// 获取物料位置映射
fetchMatMapList() {
getTrackMatPosition().then(res => {
if (res.data && res.data.matMapList) {
this.matMapList = res.data.matMapList
console.log('Material position mapping obtained:', this.matMapList.length, 'devices') // 获取物料位置映射:, 个设备
console.log('获取物料位置映射:', this.matMapList.length, '个设备')
}
}).catch(err => {
console.error('Failed to get material position:', err) // 获取物料位置失败:
console.error('获取物料位置失败:', err)
})
},
handleSetupInput(data) {
this.setupForm = data
},
// Get current position of plan / 获取计划的当前位置
// 获取计划的当前位置
getPlanPosition(plan) {
if (!this.matMapList || this.matMapList.length === 0) {
return null
}
// Find matching position from matMapList (if multiple matches, take the one with largest posIdx/most backward as current position) / 从matMapList中查找匹配的位置若有多个匹配取posIdx最大/最靠后的为当前位置)
// 从matMapList中查找匹配的位置若有多个匹配取posIdx最大/最靠后的为当前位置)
const positions = this.matMapList.filter(item =>
(item.planId && item.planId === plan.planid) ||
(item.planId && item.planId === plan.planId) ||
@@ -779,41 +685,41 @@ export default {
return c > p ? cur : prev
})
},
// Get plan list data (supports passing cleaned query parameters) / 获取计划列表数据(支持传入清理后的查询参数)
// 获取计划列表数据(支持传入清理后的查询参数)
async getList(cleanParams) {
this.loading = true; // Enable table loading / 开启表格加载
const params = cleanParams || this.queryParams; // Prefer passed parameters (e.g., reset/query) / 优先使用传入参数(如重置/查询)
this.loading = true; // 开启表格加载
const params = cleanParams || this.queryParams; // 优先使用传入参数(如重置/查询)
try {
// If status is not specified, query required statuses in parallel then merge / 如果没有指定状态,并行查询需要的状态然后合并
// 如果没有指定状态,并行查询需要的状态然后合并
if (!params.status) {
// Only query: PRODUCING, READY, NEW, PRODUCT / 只查询:生产中、就绪、新建、已完成
// 只查询:生产中、就绪、新建、已完成
const statuses = ['PRODUCING', 'READY', 'NEW', 'PRODUCT']
const allPlans = []
// Query all statuses in parallel / 并行查询所有状态
// 并行查询所有状态
const requests = statuses.map(status =>
listPlan({ ...params, status }).catch(err => {
console.warn(`Failed to query ${status} status:`, err) // 查询状态失败
console.warn(`查询${status}状态计划失败:`, err)
return { data: [] }
})
)
const results = await Promise.all(requests)
// Merge all query results / 合并所有查询结果
// 合并所有查询结果
results.forEach(res => {
if (res.data) {
allPlans.push(...res.data)
}
})
// Deduplicate (by id) / 去重根据id
// 去重根据id
const uniquePlans = Array.from(
new Map(allPlans.map(plan => [plan.id, plan])).values()
)
// Process list data / 处理列表数据
// 处理列表数据
this.planList = uniquePlans.map((item) => {
return {
...item,
@@ -821,15 +727,15 @@ export default {
};
});
console.log('Total plans queried:', uniquePlans.length) // 查询到的总计划数:, 条
console.log('Status distribution:', { // 各状态分布:
PRODUCING: uniquePlans.filter(p => p.status === 'PRODUCING').length,
READY: uniquePlans.filter(p => p.status === 'READY').length,
NEW: uniquePlans.filter(p => p.status === 'NEW').length,
PRODUCT: uniquePlans.filter(p => p.status === 'PRODUCT').length
console.log('查询到的总计划数:', uniquePlans.length, '条')
console.log('各状态分布:', {
生产中: uniquePlans.filter(p => p.status === 'PRODUCING').length,
就绪: uniquePlans.filter(p => p.status === 'READY').length,
新建: uniquePlans.filter(p => p.status === 'NEW').length,
已完成: uniquePlans.filter(p => p.status === 'PRODUCT').length
})
} else {
// If status is specified, query directly / 如果指定了状态,直接查询
// 如果指定了状态,直接查询
const response = await listPlan(params)
this.planList = response.data.map((item) => {
return {
@@ -839,58 +745,58 @@ export default {
});
}
// Close loading state / 关闭加载状态
// 关闭加载状态
this.loading = false;
this.btnLoading = false;
} catch (error) {
// Error handling: close loading + show error / 异常处理:关闭加载+提示错误
// 异常处理:关闭加载+提示错误
this.loading = false;
this.btnLoading = false;
console.error("Failed to get plan list:", error); // 获取计划列表失败
this.$message.error("Failed to fetch data, please retry"); // 获取数据失败,请重试
console.error("获取计划列表失败:", error);
this.$message.error("获取数据失败,请重试");
}
},
// Handle query operation (validate parameters + call list API) / 处理查询操作(校验参数+调用列表接口)
// 处理查询操作(校验参数+调用列表接口)
handleQuery() {
// Deep copy query parameters (avoid modifying original data) / 深拷贝查询参数(避免修改原数据)
// 深拷贝查询参数(避免修改原数据)
const params = JSON.parse(JSON.stringify(this.queryParams));
// 1. Time range validation (start time cannot be later than end time) / 时间范围校验(开始时间不能晚于结束时间)
// 1. 时间范围校验(开始时间不能晚于结束时间)
if (params.startDate && params.endDate) {
const start = new Date(params.startDate);
const end = new Date(params.endDate);
if (start > end) {
this.$message.warning("Start time cannot be later than end time"); // 开始时间不能晚于结束时间
this.$message.warning("开始时间不能晚于结束时间");
return;
}
}
// 3. Call list API (with query parameters) / 调用列表接口(带查询参数)
// 3. 调用列表接口(带查询参数)
this.btnLoading = true;
this.getList(params);
},
// Reset query form (clear parameters + reload list) / 重置查询表单(清空参数+重新加载列表)
// 重置查询表单(清空参数+重新加载列表)
handleReset() {
// Clear form fields (depends on form ref="queryForm") / 清空表单字段依赖表单ref="queryForm"
// 清空表单字段依赖表单ref="queryForm"
if (this.$refs.queryForm) {
this.$refs.queryForm.resetFields();
}
// Reload list (no query parameters) / 重新加载列表(无查询参数)
// 重新加载列表(无查询参数)
this.getList();
},
// Table row click event (record current selected row) / 表格行点击事件(记录当前选中行)
// 表格行点击事件(记录当前选中行)
handleRowClick(row) {
this.currentRow = { ...row }; // Deep copy to avoid reference modification / 深拷贝避免引用修改
this.currentRow = { ...row }; // 深拷贝避免引用修改
this.fetchSpmParams()
},
// Add plan (reset form + open dialog) / 新增计划(重置表单+打开弹窗)
// 新增计划(重置表单+打开弹窗)
handleAdd() {
this.dialogTitle = "Add Plan"; // Set dialog title / 设置弹窗标题
// Reset form data (default values aligned with API requirements) / 重置表单数据(默认值与接口要求对齐)
this.dialogTitle = "新增计划"; // 设置弹窗标题
// 重置表单数据(默认值与接口要求对齐)
this.form = {
dummyCoilFlag: 0,
tlvFlag: 0,
@@ -901,7 +807,7 @@ export default {
seqid: null,
coilid: "",
unitCode: "",
status: "NEW", // Default status for new plan is NEW / 新增计划默认状态为 NEW
status: "NEW", // 新增计划默认状态为 新建
planid: "",
planType: "",
originCoilid: "",
@@ -994,7 +900,7 @@ export default {
};
this.spmFlag = false
// Open dialog + clear form validation state / 打开弹窗+清空表单验证状态
// 打开弹窗+清空表单验证状态
this.dialogVisible = true;
this.$nextTick(() => {
if (this.$refs.form) {
@@ -1003,26 +909,26 @@ export default {
});
},
// Edit plan (echo row data + open dialog) / 编辑计划(回显行数据+打开弹窗)
// 编辑计划(回显行数据+打开弹窗)
handleUpdate(row) {
this.dialogTitle = "Edit Plan"; // Set dialog title / 设置弹窗标题
// Deep copy row data (avoid modifying original table data) / 深拷贝行数据(避免修改原表格数据)
this.dialogTitle = "编辑计划"; // 设置弹窗标题
// 深拷贝行数据(避免修改原表格数据)
this.form = JSON.parse(JSON.stringify(row));
this.spmFlag = false
// 1. Convert ID to string (avoid precision loss) / ID转字符串避免精度丢失
// 1. ID转字符串避免精度丢失
this.form.id = this.form.id !== null && this.form.id !== undefined ? String(this.form.id) : "";
// 2. Format numeric fields (ensure number type, adapt to API requirements) / 数值字段格式化确保为number类型适配接口要求
// 2. 数值字段格式化确保为number类型适配接口要求
this.formatFormNumericFields(this.form);
// 3. Date field processing (backend returns formatted string, convert to Date object for form component) / 日期字段处理后端返回为格式化字符串转为Date对象适配表单组件
// 3. 日期字段处理后端返回为格式化字符串转为Date对象适配表单组件
const dateFields = ["startDate", "endDate", "onlineDate", "furInDate", "furOutDate"];
dateFields.forEach((field) => {
this.form[field] = this.form[field] ? new Date(this.form[field]) : null;
});
// 4. Open dialog + clear validation state / 打开弹窗+清空验证状态
// 4. 打开弹窗+清空验证状态
this.dialogVisible = true;
this.$nextTick(() => {
if (this.$refs.form) {
@@ -1031,9 +937,9 @@ export default {
});
},
// Format form numeric fields (unified conversion to number/null, adapt to API type requirements) / 格式化表单数值字段统一转为number/null适配接口类型要求
// 格式化表单数值字段统一转为number/null适配接口类型要求
formatFormNumericFields(formData) {
// All fields that need to be converted to number type (aligned with API parameters) / 所有需转为number类型的字段与接口参数对齐
// 所有需转为number类型的字段与接口参数对齐
const numericFields = [
"seqid", "dummyCoilFlag", "status", "tlvFlag", "splitNum", "headSampleNum", "tailSampleNum",
"spmFlag", "trimFlag", "chromating", "oilingFlag", "yieldPoint", "entryWeight", "entryThick",
@@ -1049,7 +955,7 @@ export default {
];
numericFields.forEach((field) => {
// Convert empty value/empty string to null, non-empty value to number / 空值/空字符串转为null非空值转为number
// 空值/空字符串转为null非空值转为number
if (formData[field] === "" || formData[field] === null || formData[field] === undefined) {
formData[field] = null;
} else {
@@ -1058,76 +964,76 @@ export default {
});
},
// Delete plan (single delete, supports batch extension) / 删除计划(单个删除,支持批量扩展)
// 删除计划(单个删除,支持批量扩展)
handleDelete(row) {
// Dialog confirmation (dangerous operation requires secondary confirmation) / 弹窗确认(危险操作二次确认)
this.$confirm(`Are you sure to delete plan with ID: ${row.id}?`, "Confirm Delete", {
// 弹窗确认(危险操作二次确认)
this.$confirm(`确定要删除ID为${row.id}的计划吗?`, "确认删除", {
type: "danger",
confirmButtonText: "Confirm", // 确认
cancelButtonText: "Cancel" // 取消
confirmButtonText: "确认",
cancelButtonText: "取消"
})
.then(() => {
row.deleteLoading = true; // Enable row delete button loading / 开启行删除按钮加载
// Call delete API (pass ID array, supports batch extension) / 调用删除接口传入ID数组支持批量扩展
row.deleteLoading = true; // 开启行删除按钮加载
// 调用删除接口传入ID数组支持批量扩展
delPlan([row.id])
.then((res) => {
row.deleteLoading = false; // Close loading / 关闭加载
this.$message.success("Delete successful"); // 删除成功
this.getList(); // Reload list / 重新加载列表
row.deleteLoading = false; // 关闭加载
this.$message.success("删除成功");
this.getList(); // 重新加载列表
})
.catch((err) => {
row.deleteLoading = false; // Close loading / 关闭加载
console.error("Failed to delete plan:", err); // 删除计划失败
this.$message.error("Delete failed, please retry"); // 删除失败,请重试
row.deleteLoading = false; // 关闭加载
console.error("删除计划失败:", err);
this.$message.error("删除失败,请重试");
});
})
},
// Save form (unified handling for add/edit) / 保存表单(新增/编辑统一处理)
// 保存表单(新增/编辑统一处理)
submitForm() {
// 1. Form validation (depends on form ref="form") / 表单验证依赖表单ref="form"
// 1. 表单验证依赖表单ref="form"
this.$refs.form.validate((valid) => {
if (!valid) return; // Validation failed, terminate / 验证不通过则终止
if (!valid) return; // 验证不通过则终止
// 2. Deep copy form data (avoid modifying original data) / 深拷贝表单数据(避免修改原数据)
// 2. 深拷贝表单数据(避免修改原数据)
const formData = JSON.parse(JSON.stringify(this.form));
// 3. Time range validation (start time cannot be later than end time) / 时间范围校验(开始时间不能晚于结束时间)
// 3. 时间范围校验(开始时间不能晚于结束时间)
if (formData.startDate && formData.endDate) {
const start = new Date(formData.startDate);
const end = new Date(formData.endDate);
if (start > end) {
this.$message.warning("Start time cannot be later than end time"); // 开始时间不能晚于结束时间
this.$message.warning("开始时间不能晚于结束时间");
return;
}
}
// 4. Format numeric fields (ensure consistent with API types) / 数值字段格式化(确保与接口类型一致)
// 4. 数值字段格式化(确保与接口类型一致)
this.formatFormNumericFields(formData);
// 8. Call add/edit API / 调用新增/编辑接口
this.saveLoading = true; // Enable save button loading / 开启保存按钮加载
// 8. 调用新增/编辑接口
this.saveLoading = true; // 开启保存按钮加载
const request = formData.id ? updatePlan(formData) : addPlan(formData);
request
.then((res) => {
this.saveLoading = false; // Close loading / 关闭加载
console.log("Server response:", res); // 服务器响应
this.saveLoading = false; // 关闭加载
console.log("服务器响应:", res);
if (res.code === 200) {
this.$message.success(formData.id ? "Update plan successful" : "Add plan successful"); // 更新计划成功 / 新增计划成功
this.dialogVisible = false; // Close dialog / 关闭弹窗
this.getList(); // Reload list / 重新加载列表
this.$message.success(formData.id ? "更新计划成功" : "新增计划成功");
this.dialogVisible = false; // 关闭弹窗
this.getList(); // 重新加载列表
} else {
this.$message.error(res.msg || (formData.id ? "Update failed" : "Add failed")); // 更新失败 / 新增失败
this.$message.error(res.msg || (formData.id ? "更新失败" : "新增失败"));
}
})
.catch((err) => {
this.saveLoading = false; // Close loading / 关闭加载
console.error(`${formData.id ? "Update" : "Add"} plan failed:`, err); // 更新/新增计划失败
this.$message.error(`${formData.id ? "Update" : "Add"} failed, please retry`); // 更新/新增失败,请重试
this.saveLoading = false; // 关闭加载
console.error(`${formData.id ? "更新" : "新增"}计划失败:`, err);
this.$message.error(`${formData.id ? "更新" : "新增"}失败,请重试`);
});
// If it's a new plan and process parameter generation is checked, generate process parameters / 如果是新增计划并且勾选了生成工艺参数,则生成工艺参数
// 如果是新增计划并且勾选了生成工艺参数,则生成工艺参数
if (!formData.id && this.spmFlag) {
this.generateSpmParams();
}
@@ -1135,7 +1041,7 @@ export default {
},
fetchSpmParams() {
console.log("Get process parameters"); // 获取工艺参数
console.log("获取工艺参数");
this.setupLoading = true
listSetup({
coilid: this.currentRow.coilid,
@@ -1156,7 +1062,7 @@ export default {
planid: this.form.planid,
...this.setupForm
}).then(res => {
this.$message.success("Process parameters created successfully"); // 工艺参数创建成功
this.$message.success("工艺参数创建成功");
})
}
},

View File

@@ -2,10 +2,10 @@
<div class="report-body">
<!-- Action row / 操作行 -->
<div class="report-actions">
<el-button type="primary" @click="exportReport" icon="el-icon-download" size="small">Export Report</el-button>
<el-button type="primary" @click="exportReport" icon="el-icon-download" size="small">导出报表</el-button>
<!-- 导出报表 -->
</div>
<h1 class="report-body-title">Overview Data</h1>
<h1 class="report-body-title">总览数据</h1>
<!-- 总览数据 -->
<div class="summary-cards" v-if="summary.length > 0">
<div v-for="(item, index) in summary" :key="index">

View File

@@ -4,43 +4,35 @@
<div class="header-title">
<i class="el-icon-document"></i>
<div class="title-text">
<span>Performance Report</span>
<!-- 实绩报表 -->
<small>Displaying data for the last month by default</small>
<!-- 默认展示近一个月数据 -->
<span>实绩报表</span>
<small>默认展示近一个月数据</small>
</div>
</div>
<el-tag size="small" effect="plain">Performance</el-tag>
<!-- 实绩 -->
<el-tag size="small" effect="plain">实绩</el-tag>
</div>
<div class="time-selector-card" v-if="!hasSelectedTime">
<div class="selector-header">
<i class="el-icon-calendar"></i>
<span>Please select query time range</span>
<!-- 请选择查询时间范围 -->
<span>请选择查询时间范围</span>
</div>
<div class="selector-content">
<el-form :inline="true" size="small">
<el-form-item label="Start Time">
<!-- 开始时间 -->
<!-- Select start time / 选择开始时间 -->
<el-form-item label="开始时间">
<el-date-picker
v-model="timeRange.startTime"
type="datetime"
placeholder="Select start time"
placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 220px;"
:clearable="false"
/>
</el-form-item>
<el-form-item label="End Time">
<!-- 结束时间 -->
<!-- Select end time / 选择结束时间 -->
<el-form-item label="结束时间">
<el-date-picker
v-model="timeRange.endTime"
type="datetime"
placeholder="Select end time"
placeholder="选择结束时间"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 220px;"
:clearable="false"
@@ -48,11 +40,9 @@
</el-form-item>
<el-form-item>
<el-button type="primary" :disabled="!canQuery" icon="el-icon-search" @click="handleTimeConfirm">
Query
查询
</el-button>
<!-- 查询 -->
<el-button icon="el-icon-refresh" @click="handleTimeReset">Reset</el-button>
<!-- 重置 -->
<el-button icon="el-icon-refresh" @click="handleTimeReset">重置</el-button>
</el-form-item>
</el-form>
</div>
@@ -61,23 +51,17 @@
<div class="report-content" v-else>
<div class="content-toolbar">
<div class="toolbar-info">
<span class="info-label">Report Type:</span>
<!-- 报表类型 -->
<span class="info-value">Performance Report</span>
<!-- 实绩报表 -->
<span class="info-label">报表类型</span>
<span class="info-value">实绩报表</span>
<span class="info-divider">|</span>
<span class="info-label">Time Range:</span>
<!-- 时间范围 -->
<span class="info-label">时间范围</span>
<span class="info-range">{{ displayTimeRange }}</span>
</div>
<el-button type="text" icon="el-icon-refresh-left" @click="handleReturn">Change Time Range</el-button>
<!-- 重新选择时间 -->
<el-button type="text" icon="el-icon-refresh-left" @click="handleReturn">重新选择时间</el-button>
</div>
<!-- 实绩报表 -->
<ReportBody
v-loading="loading"
title="Performance Report"
title="实绩报表"
:summary="reportSummary"
:dataset="reportDetail"
:columns="columns"
@@ -97,7 +81,7 @@ export default {
data() {
return {
loading: false,
hasSelectedTime: true, // Directly show report content
hasSelectedTime: true, // 直接显示报表内容
timeRange: {
startTime: '',
endTime: ''
@@ -113,12 +97,11 @@ export default {
},
displayTimeRange() {
if (!this.canQuery) return '-'
return `${this.timeRange.startTime} to ${this.timeRange.endTime}`
// 至
return `${this.timeRange.startTime} ${this.timeRange.endTime}`
},
overviewInfo() {
return {
reportLabel: 'Performance Report', // 实绩报表
reportLabel: '实绩报表',
rangeText: this.displayTimeRange
}
}
@@ -156,13 +139,13 @@ export default {
},
async handleTimeConfirm() {
if (!this.canQuery) {
this.$message.warning('Please select complete time range') // 请选择完整的时间范围
this.$message.warning('请选择完整的时间范围')
return
}
const start = new Date(this.timeRange.startTime)
const end = new Date(this.timeRange.endTime)
if (start > end) {
this.$message.warning('Start time cannot be later than end time') // 开始时间不能晚于结束时间
this.$message.warning('开始时间不能晚于结束时间')
return
}
this.hasSelectedTime = true
@@ -170,7 +153,7 @@ export default {
},
handleReturn() {
this.hasSelectedTime = false
// Do not reset time, so user can see the previous selection
// 不重置时间,保留用户上一次选择
},
async fetchReportData() {
this.loading = true
@@ -179,18 +162,18 @@ export default {
startTime: this.timeRange.startTime,
endTime: this.timeRange.endTime,
pageNum: 1,
pageSize: 1000 // Assuming we fetch all data for the report
pageSize: 1000 // 假设获取报表所有数据
}
const res = await getReportSummary(queryParams)
this.reportSummary = [
{ label: 'Finished Coil Count', value: res.coilCount }, // 成品卷数
{ label: 'Avg Exit Thickness [mm]', value: res.avgExitThickness }, // 平均出口厚度[mm]
{ label: 'Total Entry Weight [t]', value: res.totalEntryWeight }, // 原料总重[t]
{ label: 'Total Exit Length [mm]', value: res.totalExitLength }, // 总出口长度[mm]
{ label: 'Avg Exit Width [mm]', value: res.avgExitWidth }, // 平均出口宽度[mm]
{ label: 'Total Finished Weight [t]', value: res.totalActualWeight }, // 成品总重[t]
{ label: 'Total Theory Weight [t]', value: res.totalTheoryWeight }, // 总理论重量[t]
{ label: 'Yield Rate', value: (res.yieldRate * 100).toFixed(2) + '%' } // 成材率
{ label: '成品卷数', value: res.coilCount },
{ label: '平均出口厚度(mm)', value: res.avgExitThickness },
{ label: '原料总重(t)', value: res.totalEntryWeight },
{ label: '总出口长度(mm)', value: res.totalExitLength },
{ label: '平均出口宽度(mm)', value: res.avgExitWidth },
{ label: '成品总重(t)', value: res.totalActualWeight },
{ label: '总理论重量(t)', value: res.totalTheoryWeight },
{ label: '成材率', value: (res.yieldRate * 100).toFixed(2) + '%' }
]
const res2 = await getReportDetail(queryParams)
this.reportDetail = (res2 || []).map(item => ({
@@ -198,21 +181,21 @@ export default {
onlineTime: item.onlineTime ? item.onlineTime.replace('T', ' ') : ''
}))
this.columns = [
{ label: 'Exit Material ID', prop: 'exitMatId' }, // 出口物料ID
{ label: 'Entry Material ID', prop: 'entryMatId' }, // 入口物料ID
{ label: 'Group No', prop: 'groupNo' }, // 机组号
{ label: 'Shift No', prop: 'shiftNo' }, // 班次号
{ label: 'Steel Grade', prop: 'steelGrade' }, // 钢种
{ label: 'Exit Thickness (mm)', prop: 'exitThickness' }, // 出口厚度(mm)
{ label: 'Exit Width (mm)', prop: 'exitWidth' }, // 出口宽度(mm)
{ label: 'Exit Length (m)', prop: 'exitLength' }, // 出口长度(m)
{ label: 'Theory Weight (t)', prop: 'theoryWeight' }, // 理论重量(t)
{ label: 'Actual Weight (t)', prop: 'actualWeight' }, // 实际重量(t)
{ label: 'Online Time', prop: 'onlineTime' } // 上线时间
{ label: '出口物料ID', prop: 'exitMatId' },
{ label: '入口物料ID', prop: 'entryMatId' },
{ label: '机组号', prop: 'groupNo' },
{ label: '班次号', prop: 'shiftNo' },
{ label: '钢种', prop: 'steelGrade' },
{ label: '出口厚度(mm)', prop: 'exitThickness' },
{ label: '出口宽度(mm)', prop: 'exitWidth' },
{ label: '出口长度(m)', prop: 'exitLength' },
{ label: '理论重量(t)', prop: 'theoryWeight' },
{ label: '实际重量(t)', prop: 'actualWeight' },
{ label: '上线时间', prop: 'onlineTime' }
]
} catch (error) {
console.error(error)
this.$message.error('Failed to fetch report data') // 获取报表数据失败
this.$message.error('获取报表数据失败')
} finally {
this.loading = false
}
@@ -331,4 +314,4 @@ export default {
}
}
}
</style>
</style>

View File

@@ -4,39 +4,35 @@
<div class="header-title">
<i class="el-icon-document"></i>
<div class="title-text">
<span>Roll Change Report</span>
<!-- 换辊报表 -->
<small>Displaying data for the last month by default</small>
<!-- 默认展示近一个月数据 -->
<span>换辊报表</span>
<small>默认展示近一个月数据</small>
</div>
</div>
<el-tag size="small" effect="plain">Roll Change</el-tag>
<!-- 换辊 -->
<el-tag size="small" effect="plain">换辊</el-tag>
</div>
<div class="time-selector-card" v-if="!hasSelectedTime">
<div class="selector-header">
<i class="el-icon-calendar"></i>
<span>Please select query time range</span>
<!-- 请选择查询时间范围 -->
<span>请选择查询时间范围</span>
</div>
<div class="selector-content">
<el-form :inline="true" size="small">
<el-form-item label="Start Time">
<el-form-item label="开始时间">
<el-date-picker
v-model="timeRange.startTime"
type="datetime"
placeholder="Select start time"
placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 220px;"
:clearable="false"
/>
</el-form-item>
<el-form-item label="End Time">
<el-form-item label="结束时间">
<el-date-picker
v-model="timeRange.endTime"
type="datetime"
placeholder="Select end time"
placeholder="选择结束时间"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 220px;"
:clearable="false"
@@ -44,9 +40,9 @@
</el-form-item>
<el-form-item>
<el-button type="primary" :disabled="!canQuery" icon="el-icon-search" @click="handleTimeConfirm">
Query
查询
</el-button>
<el-button icon="el-icon-refresh" @click="handleTimeReset">Reset</el-button>
<el-button icon="el-icon-refresh" @click="handleTimeReset">重置</el-button>
</el-form-item>
</el-form>
</div>
@@ -55,18 +51,18 @@
<div class="report-content" v-else>
<div class="content-toolbar">
<div class="toolbar-info">
<span class="info-label">Report Type:</span>
<span class="info-value">Roll Change Report</span>
<span class="info-label">报表类型</span>
<span class="info-value">换辊报表</span>
<span class="info-divider">|</span>
<span class="info-label">Time Range:</span>
<span class="info-label">时间范围</span>
<span class="info-range">{{ displayTimeRange }}</span>
</div>
<el-button type="text" icon="el-icon-refresh-left" @click="handleReturn">Change Time Range</el-button>
<el-button type="text" icon="el-icon-refresh-left" @click="handleReturn">重新选择时间</el-button>
</div>
<ReportBody
v-loading="loading"
title="Roll Change Report"
title="换辊报表"
:summary="reportSummary"
:dataset="reportDetail"
:columns="columns"
@@ -102,11 +98,11 @@ export default {
},
displayTimeRange() {
if (!this.canQuery) return '-'
return `${this.timeRange.startTime} to ${this.timeRange.endTime}`
return `${this.timeRange.startTime} ${this.timeRange.endTime}`
},
overviewInfo() {
return {
reportLabel: 'Roll Change Report',
reportLabel: '换辊报表',
rangeText: this.displayTimeRange
}
}
@@ -143,11 +139,11 @@ export default {
},
async handleTimeConfirm() {
if (!this.canQuery) {
this.$message.warning('Please select complete time range')
this.$message.warning('请选择完整的时间范围')
return
}
if (new Date(this.timeRange.startTime) > new Date(this.timeRange.endTime)) {
this.$message.warning('Start time cannot be later than end time')
this.$message.warning('开始时间不能晚于结束时间')
return
}
this.hasSelectedTime = true
@@ -170,26 +166,26 @@ export default {
...item
}))
this.columns = [
{ label: 'Change ID', prop: 'changeid' },
{ label: 'Roll ID', prop: 'rollid' },
{ label: 'Type', prop: 'type' },
{ label: 'Position', prop: 'position' },
{ label: 'Diameter', prop: 'diameter' },
{ label: 'Roughness', prop: 'rough' },
{ label: 'Crown', prop: 'crown' },
{ label: 'Rolled Length', prop: 'rolledLength' },
{ label: 'Rolled Weight', prop: 'rolledWeight' },
{ label: 'Rolled Count', prop: 'rolledCount' },
{ label: 'Install Time', prop: 'instalTime' },
{ label: 'Uninstall Time', prop: 'deinstalTime' }
{ label: '换辊ID', prop: 'changeid' },
{ label: '轧辊号', prop: 'rollid' },
{ label: '轧辊类型', prop: 'type' },
{ label: '安装位置', prop: 'position' },
{ label: '直径', prop: 'diameter' },
{ label: '粗糙度', prop: 'rough' },
{ label: '凸度', prop: 'crown' },
{ label: '轧制长度', prop: 'rolledLength' },
{ label: '轧制重量', prop: 'rolledWeight' },
{ label: '轧制数量', prop: 'rolledCount' },
{ label: '装机时间', prop: 'instalTime' },
{ label: '卸机时间', prop: 'deinstalTime' }
]
this.reportSummary = [
{ label: 'Data Count', value: this.reportDetail.length },
{ label: 'Time Range', value: this.displayTimeRange }
{ label: '数据条数', value: this.reportDetail.length },
{ label: '时间范围', value: this.displayTimeRange }
]
} catch (error) {
console.error(error)
this.$message.error('Failed to fetch report data')
this.$message.error('获取报表数据失败')
} finally {
this.loading = false
}
@@ -308,4 +304,4 @@ export default {
}
}
}
</style>
</style>

View File

@@ -4,38 +4,35 @@
<div class="header-title">
<i class="el-icon-document"></i>
<div class="title-text">
<span>Stoppage Report</span>
<!-- 停机报表 -->
<small>Displaying data for the last month by default</small>
<!-- 默认展示近一个月数据 -->
<span>停机报表</span>
<small>默认展示近一个月数据</small>
</div>
</div>
<el-tag size="small" effect="plain">Stoppage</el-tag>
<!-- 停机 -->
<el-tag size="small" effect="plain">停机</el-tag>
</div>
<div class="time-selector-card" v-if="!hasSelectedTime">
<div class="selector-header">
<i class="el-icon-calendar"></i>
<span>Please select query date range</span>
<span>请选择查询日期范围</span>
</div>
<div class="selector-content">
<el-form :inline="true" size="small">
<el-form-item label="Start Date">
<el-form-item label="开始日期">
<el-date-picker
v-model="timeRange.startTime"
type="date"
placeholder="Select start date"
placeholder="选择开始日期"
value-format="yyyy-MM-dd"
style="width: 200px;"
:clearable="false"
/>
</el-form-item>
<el-form-item label="End Date">
<el-form-item label="结束日期">
<el-date-picker
v-model="timeRange.endTime"
type="date"
placeholder="Select end date"
placeholder="选择结束日期"
value-format="yyyy-MM-dd"
style="width: 200px;"
:clearable="false"
@@ -43,9 +40,9 @@
</el-form-item>
<el-form-item>
<el-button type="primary" :disabled="!canQuery" icon="el-icon-search" @click="handleTimeConfirm">
Query
查询
</el-button>
<el-button icon="el-icon-refresh" @click="handleTimeReset">Reset</el-button>
<el-button icon="el-icon-refresh" @click="handleTimeReset">重置</el-button>
</el-form-item>
</el-form>
</div>
@@ -54,18 +51,18 @@
<div class="report-content" v-else>
<div class="content-toolbar">
<div class="toolbar-info">
<span class="info-label">Report Type:</span>
<span class="info-value">Stoppage Report</span>
<span class="info-label">报表类型</span>
<span class="info-value">停机报表</span>
<span class="info-divider">|</span>
<span class="info-label">Time Range:</span>
<span class="info-label">时间范围</span>
<span class="info-range">{{ displayTimeRange }}</span>
</div>
<el-button type="text" icon="el-icon-refresh-left" @click="handleReturn">Change Date Range</el-button>
<el-button type="text" icon="el-icon-refresh-left" @click="handleReturn">重新选择日期</el-button>
</div>
<ReportBody
v-loading="loading"
title="Stoppage Report"
title="停机报表"
:summary="reportSummary"
:dataset="reportDetail"
:columns="columns"
@@ -93,14 +90,14 @@ export default {
reportSummary: [],
reportDetail: [],
columns: [
{ label: 'Coil ID', prop: 'coilid' },
{ label: 'Shift', prop: 'shift' },
{ label: 'Group', prop: 'area' },
{ label: 'Start Time', prop: 'startDate' },
{ label: 'End Time', prop: 'endDate' },
{ label: 'Duration [min]', prop: 'duration' },
{ label: 'Stoppage Type', prop: 'unit' },
{ label: 'Remark', prop: 'remark' }
{ label: '钢卷号', prop: 'coilid' },
{ label: '班次', prop: 'shift' },
{ label: '区域', prop: 'area' },
{ label: '开始时间', prop: 'startDate' },
{ label: '结束时间', prop: 'endDate' },
{ label: '停机时长(分钟)', prop: 'duration' },
{ label: '停机类型', prop: 'unit' },
{ label: '备注', prop: 'remark' }
]
}
},
@@ -110,11 +107,11 @@ export default {
},
displayTimeRange() {
if (!this.canQuery) return '-'
return `${this.timeRange.startTime} to ${this.timeRange.endTime}`
return `${this.timeRange.startTime} ${this.timeRange.endTime}`
},
overviewInfo() {
return {
reportLabel: 'Stoppage Report',
reportLabel: '停机报表',
rangeText: this.displayTimeRange
}
}
@@ -148,11 +145,11 @@ export default {
},
async handleTimeConfirm() {
if (!this.canQuery) {
this.$message.warning('Please select complete date range')
this.$message.warning('请选择完整的日期范围')
return
}
if (new Date(this.timeRange.startTime) > new Date(this.timeRange.endTime)) {
this.$message.warning('Start date cannot be later than end date')
this.$message.warning('开始日期不能晚于结束日期')
return
}
this.hasSelectedTime = true
@@ -175,14 +172,14 @@ export default {
const res2 = await getStoppageSummary(queryParams)
this.reportSummary = [
{ label: 'Statistics Range', value: this.displayTimeRange },
{ label: 'Stoppage Count', value: res2.data?.[0] || 0 },
{ label: 'Stoppage Duration [hours]', value: res2.data?.[1] || 0 },
{ label: 'Operation Rate', value: (res2.data?.[2] || 0) + ' %' }
{ label: '统计范围', value: this.displayTimeRange },
{ label: '停机次数', value: res2.data?.[0] || 0 },
{ label: '停机总时长(小时)', value: res2.data?.[1] || 0 },
{ label: '作业率', value: (res2.data?.[2] || 0) + ' %' }
]
} catch (error) {
console.error(error)
this.$message.error('Failed to fetch report data')
this.$message.error('获取报表数据失败')
} finally {
this.loading = false
}
@@ -301,4 +298,4 @@ export default {
}
}
}
</style>
</style>

View File

@@ -2,47 +2,43 @@
<div class="filter-container">
<div class="filter-panel">
<div class="panel-header">
<h4>History Search</h4>
<!-- 历史检索 -->
<h4>历史检索</h4>
</div>
<div class="filter-item">
<div class="filter-label"> By Time</div>
<!-- 按时间 -->
<div class="filter-label"> 按时间</div>
<div class="filter-content time-range">
<div class="time-label">Start Time:</div>
<!-- 开始时间 -->
<!-- Select Date / 选择日期 -->
<div class="time-label">开始时间</div>
<!-- 选择日期 -->
<el-date-picker
v-model="startDate"
type="date"
placeholder="Select Date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 140px"
></el-date-picker>
<!-- Select Time / 选择时间 -->
<!-- 选择时间 -->
<el-time-picker
v-model="startTime"
format="HH:mm"
placeholder="Select Time"
placeholder="选择时间"
value-format="HH:mm"
style="width: 140px; margin-left: 5px"
></el-time-picker>
<div class="time-label" style="margin-top: 10px">End Time:</div>
<!-- 结束时间 -->
<!-- Select Date / 选择日期 -->
<div class="time-label" style="margin-top: 10px">结束时间</div>
<!-- 选择日期 -->
<el-date-picker
v-model="endDate"
type="date"
placeholder="Select Date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 140px"
></el-date-picker>
<!-- Select Time / 选择时间 -->
<!-- 选择时间 -->
<el-time-picker
v-model="endTime"
format="HH:mm"
placeholder="Select Time"
placeholder="选择时间"
value-format="HH:mm"
style="width: 140px; margin-left: 5px"
></el-time-picker>
@@ -50,13 +46,10 @@
</div>
<div class="filter-item">
<div class="filter-label"> By Change ID</div>
<!-- 按换辊号 -->
<div class="filter-label"> 按换辊号</div>
<div class="filter-content">
<div class="input-label">Change ID:</div>
<!-- 换辊号 -->
<!-- Please select / 请选择 -->
<el-select filterable v-model="queryParams.changeId" placeholder="Please select" clearable style="width: 240px">
<div class="input-label">换辊号</div>
<el-select filterable v-model="queryParams.changeId" placeholder="请选择" clearable style="width: 240px">
<el-option
v-for="item in changeIdOptions"
:key="item"
@@ -68,13 +61,10 @@
</div>
<div class="filter-item">
<div class="filter-label"> By Roll ID</div>
<!-- 按轧辊号 -->
<div class="filter-label"> 按轧辊号</div>
<div class="filter-content">
<div class="input-label">Roll ID:</div>
<!-- 轧辊号 -->
<!-- Please select / 请选择 -->
<el-select filterable v-model="queryParams.rollId" placeholder="Please select" clearable style="width: 240px">
<div class="input-label">轧辊号</div>
<el-select filterable v-model="queryParams.rollId" placeholder="请选择" clearable style="width: 240px">
<el-option
v-for="item in rollIdOptions"
:key="item"
@@ -86,10 +76,8 @@
</div>
<div class="filter-buttons">
<el-button type="primary" @click="handleSearch">Query</el-button>
<!-- 查询 -->
<el-button @click="resetQuery">Reset</el-button>
<!-- 重置 -->
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</div>
</div>
</div>
@@ -102,7 +90,7 @@ export default {
name: 'RollerFilter',
data() {
return {
// Query parameters / 查询参数
// 查询参数
queryParams: {
changeId: '',
rollId: ''
@@ -111,47 +99,47 @@ export default {
startTime: '',
endDate: '',
endTime: '',
// Change ID options / 换辊号选项
// 换辊号选项
changeIdOptions: [],
// Roll ID options / 轧辊号选项
// 轧辊号选项
rollIdOptions: []
}
},
created() {
// Get change ID and roll ID lists / 获取换辊号和轧辊号列表
// 获取换辊号和轧辊号列表
this.getChangeIdOptions()
this.getRollIdOptions()
this.setDefaultTimeRange()
},
methods: {
// Get change ID list / 获取换辊号列表
// 获取换辊号列表
getChangeIdOptions() {
getChangeIdList().then(res => {
console.log('Change ID list response:', res) // 换辊号列表响应
console.log('换辊号列表响应:', res)
if (res.code === 200 && res.data) {
this.changeIdOptions = res.data
} else {
this.$message.error(res.msg || 'Failed to fetch change ID list') // 获取换辊号列表失败
this.$message.error(res.msg || '获取换辊号列表失败')
}
}).catch(error => {
console.error('Failed to fetch change ID list', error) // 获取换辊号列表失败
this.$message.error('Failed to fetch change ID list: ' + (error.message || 'Unknown error')) // 获取换辊号列表失败:未知错误
console.error('获取换辊号列表失败', error)
this.$message.error('获取换辊号列表失败:' + (error.message || '未知错误'))
})
},
// Get roll ID list / 获取轧辊号列表
// 获取轧辊号列表
getRollIdOptions() {
getRollIdList().then(res => {
console.log('Roll ID list response:', res) // 轧辊号列表响应
console.log('轧辊号列表响应:', res)
if (res.code === 200 && res.data) {
this.rollIdOptions = res.data
} else {
this.$message.error(res.msg || 'Failed to fetch roll ID list') // 获取轧辊号列表失败
this.$message.error(res.msg || '获取轧辊号列表失败')
}
}).catch(error => {
console.error('Failed to fetch roll ID list', error) // 获取轧辊号列表失败
this.$message.error('Failed to fetch roll ID list: ' + (error.message || 'Unknown error')) // 获取轧辊号列表失败:未知错误
console.error('获取轧辊号列表失败', error)
this.$message.error('获取轧辊号列表失败:' + (error.message || '未知错误'))
})
},
@@ -177,24 +165,24 @@ export default {
this.endTime = this.formatTime(now)
},
// Handle search button click / 处理搜索按钮点击
// 处理搜索按钮点击
handleSearch() {
this.setEndToNow()
// Build search parameters / 构建搜索参数
// 构建搜索参数
const params = {
startTime: `${this.startDate} ${this.startTime}:00`,
endTime: `${this.endDate} ${this.endTime}:00`,
changeId: this.queryParams.changeId || '',
rollid: this.queryParams.rollId || '' // Note: use rollid instead of rollId to match API parameter / 注意这里使用rollid而不是rollId与API参数保持一致
rollid: this.queryParams.rollId || '' // 注意这里使用rollid而不是rollId与API参数保持一致
}
console.log('Search parameters:', params) // 搜索参数
console.log('搜索参数:', params)
// Emit search event to parent component / 触发父组件的搜索事件
// 触发父组件的搜索事件
this.$emit('filter', params)
},
// Reset query conditions / 重置查询条件
// 重置查询条件
resetQuery() {
this.queryParams = {
changeId: '',
@@ -202,7 +190,7 @@ export default {
}
this.setDefaultTimeRange()
// Emit reset event to parent component / 触发父组件的重置事件
// 触发父组件的重置事件
this.$emit('reset')
}
}
@@ -274,4 +262,4 @@ export default {
}
}
}
</style>
</style>

View File

@@ -1,6 +1,5 @@
<template>
<div class="history-container">
<div class="history-table" ref="historyWrapper" @mouseleave="handleTableLeave">
<el-table
:data="tableData"
@@ -12,32 +11,23 @@
@cell-mouse-enter="handleCellEnter"
@row-mouseleave="handleRowLeave"
>
<el-table-column prop="changeid" label="Change ID" align="center" show-overflow-tooltip />
<!-- 辊号 -->
<el-table-column prop="rollid" label="Roll ID" align="center" show-overflow-tooltip />
<!-- 轧辊号 -->
<el-table-column prop="standid" label="Stand ID" align="center" show-overflow-tooltip />
<!-- 机架号 -->
<el-table-column label="Position" align="center" prop="position">
<!-- 位置 -->
<el-table-column prop="changeid" label="换辊号" align="center" show-overflow-tooltip />
<el-table-column prop="rollid" label="轧辊号" align="center" show-overflow-tooltip />
<el-table-column prop="standid" label="机架号" align="center" show-overflow-tooltip />
<el-table-column label="位置" align="center" prop="position">
<template slot-scope="scope">
<dict-tag :options="dict.type.main_roll_position" :value="scope.row.position" />
</template>
</el-table-column>
<el-table-column label="Type" align="center" prop="type" >
<!-- 类型 -->
<el-table-column label="类型" align="center" prop="type" >
<template slot-scope="scope">
<dict-tag :options="dict.type.main_roll_type" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column prop="changeType" label="Change Type" align="center" show-overflow-tooltip />
<!-- 换辊类型 -->
<el-table-column prop="changeTime" label="Change Time" align="center" show-overflow-tooltip />
<!-- 换辊时间 -->
<el-table-column prop="instalTime" label="Install Time" align="center" show-overflow-tooltip />
<!-- 安装时间 -->
<el-table-column prop="deinstalTime" label="Uninstall Time" align="center" show-overflow-tooltip />
<!-- 拆卸时间 -->
<el-table-column prop="changeType" label="换辊类型" align="center" show-overflow-tooltip />
<el-table-column prop="changeTime" label="换辊时间" align="center" show-overflow-tooltip />
<el-table-column prop="instalTime" label="安装时间" align="center" show-overflow-tooltip />
<el-table-column prop="deinstalTime" label="拆卸时间" align="center" show-overflow-tooltip />
</el-table>
<transition name="el-fade-in-linear">
<div
@@ -46,8 +36,7 @@
:style="tooltipStyle"
ref="rowTooltip"
>
<div class="tooltip-title">Details</div>
<!-- 详细信息 -->
<div class="tooltip-title">详细信息</div>
<div class="tooltip-list">
<div
class="tooltip-item"
@@ -61,13 +50,13 @@
</div>
</transition>
</div>
<Pagination
v-show="pagination.total>0"
:total="pagination.total"
:page.sync="pagination.currentPage"
:limit.sync="pagination.pageSize"
@pagination="getList"
/>
<Pagination
v-show="pagination.total>0"
:total="pagination.total"
:page.sync="pagination.currentPage"
:limit.sync="pagination.pageSize"
@pagination="getList"
/>
</div>
</template>
@@ -100,26 +89,26 @@ export default {
deinstalTimeRange: []
},
detailFields: [
{ label: 'Change ID', prop: 'changeid' }, // 换辊号
{ label: 'Roll ID', prop: 'rollid' }, // 轧辊号
{ label: 'Stand ID', prop: 'standid' }, // 机架号
{ label: 'Position', prop: 'position', dict: 'main_roll_position' }, // 位置
{ label: 'Type', prop: 'type', dict: 'main_roll_type' }, // 类型
{ label: 'Change Type', prop: 'changeType' }, // 换辊类型
{ label: 'Change Time', prop: 'changeTime' }, // 换辊时间
{ label: 'Install Time', prop: 'instalTime' }, // 安装时间
{ label: 'Uninstall Time', prop: 'deinstalTime' }, // 拆卸时间
{ label: 'Diameter', prop: 'diameter' }, // 直径
{ label: 'Roughness', prop: 'rough' }, // 粗糙度
{ label: 'Crown', prop: 'crown' }, // 凸度
{ label: 'Composition', prop: 'composition' }, // 成分
{ label: 'Grind Count', prop: 'grindCount' }, // 磨削次数
{ label: 'Rolled Weight', prop: 'rolledWeight' }, // 轧制重量
{ label: 'Rolled Count', prop: 'rolledCount' }, // 轧制数量
{ label: 'Rolled Length', prop: 'rolledLength' }, // 轧制长度
{ label: 'Total Rolled Weight', prop: 'totalRolledWeight' }, // 总轧制重量
{ label: 'Total Rolled Length', prop: 'totalRolledLength' }, // 总轧制长度
{ label: 'Total Rolled Count', prop: 'totalRolledCount' } // 总轧制数量
{ label: '换辊号', prop: 'changeid' },
{ label: '轧辊号', prop: 'rollid' },
{ label: '机架号', prop: 'standid' },
{ label: '位置', prop: 'position', dict: 'main_roll_position' },
{ label: '类型', prop: 'type', dict: 'main_roll_type' },
{ label: '换辊类型', prop: 'changeType' },
{ label: '换辊时间', prop: 'changeTime' },
{ label: '安装时间', prop: 'instalTime' },
{ label: '拆卸时间', prop: 'deinstalTime' },
{ label: '直径', prop: 'diameter' },
{ label: '粗糙度', prop: 'rough' },
{ label: '凸度', prop: 'crown' },
{ label: '成分', prop: 'composition' },
{ label: '磨削次数', prop: 'grindCount' },
{ label: '轧制重量', prop: 'rolledWeight' },
{ label: '轧制数量', prop: 'rolledCount' },
{ label: '轧制长度', prop: 'rolledLength' },
{ label: '总轧制重量', prop: 'totalRolledWeight' },
{ label: '总轧制长度', prop: 'totalRolledLength' },
{ label: '总轧制数量', prop: 'totalRolledCount' }
]
}
},
@@ -133,7 +122,7 @@ export default {
watch: {
params: {
handler(newVal) {
console.log(newVal, 'params,watch');
console.log(newVal, '参数变化');
this.fetchData()
},
deep: true,
@@ -141,8 +130,8 @@ export default {
}
},
created() {
// Don't auto query on initialization, wait for filter conditions / 初始化时不自动查询,等待筛选条件
console.log('History component initialized') // 历史记录组件初始化
// 初始化时不自动查询,等待筛选条件
console.log('历史记录组件初始化')
// this.fetchData()
},
methods: {
@@ -156,7 +145,7 @@ export default {
const loading = this.$loading({
lock: true,
text: 'Loading...', // 加载中...
text: '加载中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
@@ -174,14 +163,14 @@ export default {
if (item.deinstalTime) item.deinstalTime = this.formatDate(item.deinstalTime)
})
} else {
this.$message.error(res.msg || 'Failed to fetch data') // 获取数据失败
this.$message.error(res.msg || '获取轧辊历史数据失败')
this.tableData = []
this.pagination.total = 0
}
})
.catch(error => {
console.error('Failed to fetch roll history data', error) // 获取轧辊历史数据失败
this.$message.error('Failed to fetch data: ' + (error.message || 'Unknown error')) // 获取数据失败:未知错误
console.error('获取轧辊历史数据失败', error)
this.$message.error('获取轧辊历史数据失败:' + (error.message || '未知错误'))
this.tableData = []
this.pagination.total = 0
})
@@ -190,7 +179,7 @@ export default {
})
},
// Format date / 格式化日期
// 格式化日期
formatDate(dateStr) {
if (!dateStr) return ''
@@ -208,38 +197,38 @@ export default {
return dateStr
}
},
// Query method called from parent component / 从父组件调用的查询方法
// 从父组件调用的查询方法
getList(params) {
console.log('Received search parameters from parent:', params) // 接收到父组件的搜索参数
console.log('接收到父组件的搜索参数:', params)
// this.pagination.currentPage = 1
this.fetchData()
},
// Handle search / 处理搜索
// 处理搜索
handleSearch(params) {
this.pagination.currentPage = 1
this.fetchData()
},
// Handle reset / 处理重置
// 处理重置
handleReset() {
this.pagination.currentPage = 1
this.fetchData()
},
// Handle refresh / 处理刷新
// 处理刷新
handleRefresh() {
this.fetchData()
},
// Handle export / 处理导出
// 处理导出
handleExport() {
// Export logic / 导出逻辑
this.$message.success('Export successful') // 导出成功
// 导出逻辑
this.$message.success('导出成功')
},
// Handle page number change / 处理页码变化
// 处理页码变化
handleCurrentChange(currentPage) {
this.pagination.currentPage = currentPage
this.fetchData()
},
// Handle page size change / 处理每页条数变化
// 处理每页条数变化
handleSizeChange(pageSize) {
this.pagination.pageSize = pageSize
this.fetchData()
@@ -442,4 +431,4 @@ export default {
word-break: break-all;
}
}
</style>
</style>

View File

@@ -1,9 +1,8 @@
<!-- Current online roll information, props receive online roll table data / 当前在线辊的信息props接收在线辊的表格数据 -->
<!-- 当前在线辊的信息props接收在线辊的表格数据 -->
<template>
<div class="online-roll">
<div class="panel-header">
<h4>Online Rolls</h4>
<!-- 在线辊 -->
<h4>在线轧辊</h4>
</div>
<el-table
:data="onlineData"
@@ -15,42 +14,28 @@
:show-overflow-tooltip="true"
style="width: 100%; table-layout: fixed;"
>
<el-table-column prop="rollid" label="Roll ID" show-overflow-tooltip />
<!-- 轧辊号 -->
<el-table-column label="Position" align="center" prop="position" show-overflow-tooltip>
<!-- 位置 -->
<el-table-column prop="rollid" label="轧辊号" show-overflow-tooltip />
<el-table-column label="位置" align="center" prop="position" show-overflow-tooltip>
<template slot-scope="scope">
<dict-tag :options="dict.type.main_roll_position" :value="scope.row.position" />
</template>
</el-table-column>
<el-table-column label="Type" align="center" prop="type" show-overflow-tooltip>
<!-- 类型 -->
<el-table-column label="类型" align="center" prop="type" show-overflow-tooltip>
<template slot-scope="scope">
<dict-tag :options="dict.type.main_roll_type" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column prop="diameter" label="Diameter" show-overflow-tooltip />
<!-- 直径 -->
<el-table-column prop="rough" label="Roughness"show-overflow-tooltip />
<!-- 粗糙度 -->
<el-table-column prop="crown" label="Crown" show-overflow-tooltip />
<!-- 凸度 -->
<el-table-column prop="rolledLength" label="Length" show-overflow-tooltip />
<!-- 长度 -->
<el-table-column prop="rolledWeight" label="Weight" show-overflow-tooltip />
<!-- 重量 -->
<el-table-column prop="rolledCount" label="Rolled Count" show-overflow-tooltip />
<!-- 轧制数量 -->
<el-table-column prop="instalTime" label="Install Time" show-overflow-tooltip />
<!-- 装机时间 -->
<!-- <el-table-column prop="usableLength" label="Usable Length" show-overflow-tooltip /> -->
<!-- 可用长度 -->
<!-- <el-table-column prop="leftLength" label="Remaining Length" show-overflow-tooltip /> -->
<!-- 剩余长度 -->
<!-- <el-table-column prop="usableWeight" label="Usable Weight" show-overflow-tooltip /> -->
<!-- 可用重量 -->
<!-- <el-table-column prop="leftWeight" label="Remaining Weight" show-overflow-tooltip /> -->
<!-- 剩余重量 -->
<el-table-column prop="diameter" label="直径" show-overflow-tooltip />
<el-table-column prop="rough" label="粗糙度" show-overflow-tooltip />
<el-table-column prop="crown" label="凸度" show-overflow-tooltip />
<el-table-column prop="rolledLength" label="轧制长度" show-overflow-tooltip />
<el-table-column prop="rolledWeight" label="轧制重量" show-overflow-tooltip />
<el-table-column prop="rolledCount" label="轧制数量" show-overflow-tooltip />
<el-table-column prop="instalTime" label="装机时间" show-overflow-tooltip />
<!-- <el-table-column prop="usableLength" label="可用长度" show-overflow-tooltip /> -->
<!-- <el-table-column prop="leftLength" label="剩余长度" show-overflow-tooltip /> -->
<!-- <el-table-column prop="usableWeight" label="可用重量" show-overflow-tooltip /> -->
<!-- <el-table-column prop="leftWeight" label="剩余重量" show-overflow-tooltip /> -->
</el-table>
</div>
</template>
@@ -113,7 +98,4 @@ export default {
overflow: hidden;
text-overflow: ellipsis;
}
</style>
</style>

View File

@@ -1,14 +1,11 @@
<!-- Standby roll table, props receive online roll table data, each online roll generates a change roll row, component internally handles getting all standby rolls and creating standby roll information / 准备轧辊的表格props接收在线辊表格数据每一个在线辊生成一个换辊行组件内部处理获取所有备用轧辊和创建备用轧辊的信息 -->
<!-- 准备轧辊的表格props接收在线辊表格数据每一个在线辊生成一个换辊行组件内部处理获取所有备用轧辊和创建备用轧辊的信息 -->
<template>
<div class="standby-panel" v-loading="loading">
<div class="panel-header">
<h4>Standby Rolls</h4>
<!-- 准备辊 -->
<h4>备用轧辊</h4>
<div class="header-actions">
<el-button type="primary" size="mini" icon="el-icon-box" @click="handleBackup">Backup</el-button>
<!-- 备辊 -->
<el-button type="primary" size="mini" icon="el-icon-upload2" @click="handleOnline">Online</el-button>
<!-- 上线 -->
<el-button type="primary" size="mini" icon="el-icon-box" @click="handleBackup">备辊</el-button>
<el-button type="primary" size="mini" icon="el-icon-upload2" @click="handleOnline">上线</el-button>
</div>
</div>
<el-table
@@ -20,15 +17,12 @@
:show-overflow-tooltip="true"
style="width: 100%; table-layout: fixed;"
>
<el-table-column label="Position/Type" show-overflow-tooltip>
<!-- 位置/类型 -->
<el-table-column label="位置/类型" show-overflow-tooltip>
<template #default="scope">
{{ getRollerTitle(scope.row.type, scope.row.position) }}
</template>
</el-table-column>
<el-table-column prop="rollid" label="Roll ID" show-overflow-tooltip>
<!-- 轧辊号 -->
<!-- 请选择轧辊号 -->
<el-table-column prop="rollid" label="轧辊号" show-overflow-tooltip>
<template #default="scope">
<el-select
size="mini"
@@ -37,33 +31,26 @@
allow-create
v-model="scope.row.rollid"
style="width: 100%;"
placeholder="Please select roll ID"
placeholder="请选择轧辊号"
@change="handleChange(scope.row)"
>
<el-option v-for="item in scope.row.data" :key="item.rollid" :label="item.rollid" :value="item.rollid" />
</el-select>
</template>
</el-table-column>
<el-table-column prop="diameter" label="Diameter" show-overflow-tooltip>
<!-- 直径 -->
<el-table-column prop="diameter" label="直径" show-overflow-tooltip>
<template #default="scope">
<el-input style="width: 100%;" size="mini" :disabled="!scope.row.rollid" v-model="scope.row.diameter" placeholder="Please enter diameter" />
<!-- 请输入直径 -->
<el-input style="width: 100%;" size="mini" :disabled="!scope.row.rollid" v-model="scope.row.diameter" placeholder="请输入直径" />
</template>
</el-table-column>
<el-table-column prop="rough" label="Roughness" show-overflow-tooltip>
<!-- 粗糙度 -->
<el-table-column prop="rough" label="粗糙度" show-overflow-tooltip>
<template #default="scope">
<el-input style="width: 100%;" size="mini" :disabled="!scope.row.rollid" v-model="scope.row.rough" placeholder="Please enter roughness" />
<!-- 请输入粗糙度 -->
<el-input style="width: 100%;" size="mini" :disabled="!scope.row.rollid" v-model="scope.row.rough" placeholder="请输入粗糙度" />
</template>
</el-table-column>
<el-table-column prop="crown" label="Concavity" show-overflow-tooltip>
<!-- 凹度 -->
<el-table-column prop="crown" label="凹度" show-overflow-tooltip>
<template #default="scope">
<el-input style="width: 100%;" size="mini" :disabled="!scope.row.rollid" v-model="scope.row.crown" placeholder="Please enter concavity" />
<!-- 请输入凹度 -->
<el-input style="width: 100%;" size="mini" :disabled="!scope.row.rollid" v-model="scope.row.crown" placeholder="请输入凹度" />
</template>
</el-table-column>
</el-table>
@@ -106,7 +93,7 @@ export default {
const tableData = await Promise.all(newVal.map(async item => {
const res = await getOfflineRollList(item.position, item.type)
console.log(res);
// If readyRollList contains object with same position and type, assign additional parameters like diameter / 如果readyRollList中存在position和type相同的对象则额外赋值直径等参数
// 如果readyRollList中存在position和type相同的对象则额外赋值直径等参数
const key = `${item.position.toUpperCase()}${item.type.toUpperCase()}`
const readyRoll = readyRollList[key]
const { diameter, rough, crown, rollid, ...roll } =
@@ -123,27 +110,26 @@ export default {
}))
this.tableData = tableData
this.loading = false
}
},
deep: true,
immediate: true
},
deep: true,
immediate: true
}
},
methods: {
getRollerTitle(type, position) {
const typeDict = {
WORK: 'Work Roll', // 工作辊
BACKUP: "Backup Roll", // 支撑辊
INTERMEDIATE: "Intermediate Roll", // 中间辊
WORK: '工作辊',
BACKUP: "支撑辊",
INTERMEDIATE: "中间辊",
}
const positionDict = {
TOP: "Top", // 上
BOTTOM: "Bottom", //
TOP: "",
BOTTOM: "下",
}
return positionDict[position] + ' ' + typeDict[type]
},
handleChange(row) {
// console.log(row);
// Find corresponding roll data and fill into table / 查找对应的轧辊的数据填入表格
// 查找对应的轧辊数据填入表格
const roll = row.data.find(item => item.rollid === row.rollid)
row.diameter = roll?.diameter || 0
row.rough = roll?.rough || 0
@@ -157,13 +143,13 @@ export default {
},
handleBackup() {
backupRoll(this.tableData.filter(item => item.rollid)).then(res => {
this.$message.success('Backup successful') // 备辊成功
this.$message.success('备辊成功')
this.$emit('backup')
})
},
handleOnline() {
onlineRoll(this.tableData).then(res => {
this.$message.success('Online successful') // 上线成功
this.$message.success('上线成功')
this.$emit('online')
})
}
@@ -206,5 +192,4 @@ export default {
text-align: center;
white-space: nowrap;
}
</style>
</style>

View File

@@ -1,33 +1,33 @@
<template>
<div class="fh-root">
<!-- Query -->
<!-- 查询表单 -->
<el-form :model="query" inline size="mini" class="fh-toolbar">
<el-form-item label="Device">
<el-input v-model="query.deviceName" placeholder="Device name" clearable />
<el-form-item label="设备">
<el-input v-model="query.deviceName" placeholder="请输入设备名称" clearable />
</el-form-item>
<el-form-item label="Status">
<el-select v-model="query.status" placeholder="Status" clearable style="width: 160px">
<el-option label="COMPLETED" value="COMPLETED" />
<el-option label="PARTIAL_SUCCESS" value="PARTIAL_SUCCESS" />
<el-option label="FAILED" value="FAILED" />
<el-form-item label="状态">
<el-select v-model="query.status" placeholder="请选择状态" clearable style="width: 160px">
<el-option label="执行完成" value="COMPLETED" />
<el-option label="部分成功" value="PARTIAL_SUCCESS" />
<el-option label="执行失败" value="FAILED" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">Search</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">Reset</el-button>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="list" border size="mini" height="380">
<el-table-column label="Job ID" prop="jobId" />
<el-table-column label="Device" prop="deviceName" />
<el-table-column label="Status" prop="status" />
<el-table-column label="Create Time" prop="createTime" />
<el-table-column label="Finish Time" prop="finishTime" width="170" show-overflow-tooltip />
<el-table-column label="Action">
<el-table-column label="任务ID" prop="jobId" />
<el-table-column label="设备" prop="deviceName" />
<el-table-column label="状态" prop="status" />
<el-table-column label="创建时间" prop="createTime" />
<el-table-column label="完成时间" prop="finishTime" width="170" show-overflow-tooltip />
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="apply(scope.row)">Apply</el-button>
<el-button type="text" size="mini" @click="openDetail(scope.row.jobId)">Detail</el-button>
<el-button type="text" size="mini" @click="apply(scope.row)">应用参数</el-button>
<el-button type="text" size="mini" @click="openDetail(scope.row.jobId)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
@@ -40,28 +40,28 @@
@pagination="getList"
/>
<!-- Detail dialog -->
<el-dialog title="Send Detail" :visible.sync="detailVisible" width="90%" append-to-body v-loading="detailLoading">
<!-- 详情弹窗 -->
<el-dialog title="下发任务详情" :visible.sync="detailVisible" width="90%" append-to-body v-loading="detailLoading">
<div v-if="detail">
<el-tabs type="border-card">
<el-tab-pane
v-for="(g, idx) in (detail.groups || [])"
:key="g.groupId || idx"
:label="(g.groupName || g.groupType || ('Group ' + (idx+1)))"
:label="(g.groupName || g.groupType || ('分组 ' + (idx+1)))"
>
<el-table :data="g.items || []" border size="small">
<el-table-column label="Param" prop="paramCode" width="180" />
<el-table-column label="Address" prop="address" min-width="320" />
<el-table-column label="Value" prop="valueRaw" width="160" />
<el-table-column label="Result" prop="resultStatus" width="120" />
<el-table-column label="Message" prop="resultMsg" min-width="180" />
<el-table-column label="Update Time" prop="updateTime" width="170" />
<el-table-column label="参数编码" prop="paramCode" width="180" />
<el-table-column label="地址" prop="address" min-width="320" />
<el-table-column label="原始值" prop="valueRaw" width="160" />
<el-table-column label="执行结果" prop="resultStatus" width="120" />
<el-table-column label="结果信息" prop="resultMsg" min-width="180" />
<el-table-column label="更新时间" prop="updateTime" width="170" />
</el-table>
</el-tab-pane>
</el-tabs>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="detailVisible=false">Close</el-button>
<el-button @click="detailVisible=false">关闭</el-button>
</div>
</el-dialog>
</div>
@@ -129,7 +129,7 @@ export default {
})
})
this.$emit('apply', { jobId: row.jobId, values })
this.$message.success('Values applied')
this.$message.success('参数应用成功')
}
}
}
@@ -137,5 +137,4 @@ export default {
<style scoped>
.fh-toolbar { margin-bottom: 10px; display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
</style>
</style>

View File

@@ -1,9 +1,9 @@
<template>
<div class="app-container">
<!-- Toolbar / 工具栏 -->
<!-- 工具栏 -->
<div class="toolbar">
<el-button @click="reload" icon="el-icon-refresh" size="small" :loading="loading">
Refresh
刷新
</el-button>
<el-button
v-if="lastSuccess && lastSuccess.lastSendTime"
@@ -13,11 +13,11 @@
size="small"
@click="applyLastSuccessValues"
>
Apply Last Success Values
应用上次成功参数
</el-button>
</div>
<!-- Cards / 卡片 -->
<!-- 卡片列表 -->
<div v-loading="loading" class="card-grid-container">
<el-row :gutter="20">
<el-col
@@ -31,27 +31,27 @@
<el-card class="parameter-card" shadow="hover">
<div slot="header" class="card-header">
<div class="card-header-content">
<!-- 头部信息参考 setup/panels 卡片表头多字段拼接的风格 -->
<!-- 头部信息多字段拼接展示 -->
<div class="card-title-row">
<span class="card-title">
Plan ID: {{ setup.planid || '-' }}
| Coil ID: {{ setup.coilid || '-' }}
| Steel Grade: {{ setup.steelGrade || setup.grade || '-' }}
计划ID: {{ setup.planid || '-' }}
| 钢卷号: {{ setup.coilid || '-' }}
| 钢种: {{ setup.steelGrade || setup.grade || '-' }}
</span>
</div>
<div class="card-subtitle">
<span>Entry Thickness: {{ setup.entryThick || '-' }}</span>
<span>Entry Width: {{ setup.entryWidth || '-' }}</span>
<span>Entry Weight: {{ setup.entryWeight || '-' }}</span>
<span>Entry Length: {{ setup.entryLength || '-' }}</span>
<span>入口厚度: {{ setup.entryThick || '-' }}</span>
<span>入口宽度: {{ setup.entryWidth || '-' }}</span>
<span>入口重量: {{ setup.entryWeight || '-' }}</span>
<span>入口长度: {{ setup.entryLength || '-' }}</span>
</div>
<div class="card-subtitle">
<span>TL Elongation: {{ setup.tlElong || '-' }}</span>
<span>TM Roll Force: {{ setup.tmRollforce || '-' }}</span>
<span>TM Bending Force: {{ setup.tmBendforce || '-' }}</span>
<span v-if="setup.updateTime">Updated: {{ formatTime(setup.updateTime) }}</span>
<span>拉伸机延伸率: {{ setup.tlElong || '-' }}</span>
<span>轧机轧制力: {{ setup.tmRollforce || '-' }}</span>
<span>轧机弯辊力: {{ setup.tmBendforce || '-' }}</span>
<span v-if="setup.updateTime">更新时间: {{ formatTime(setup.updateTime) }}</span>
</div>
</div>
@@ -63,7 +63,7 @@
@click="handleSend(setup)"
:loading="setup.sending"
>
Send
下发
</el-button>
</div>
</div>
@@ -92,46 +92,46 @@
</el-row>
<div v-if="setups.length === 0 && !loading" class="empty-data">
<el-empty description="No Setup History Data"></el-empty>
<el-empty description="暂无配置历史数据"></el-empty>
</div>
</div>
</div>
</template>
<script>
// Import APIs / 引入接口
// 引入接口
import { listSetup } from '@/api/business/setup'
import { createSendJob, executeSendJob } from '@/api/l2/sendJob'
import { getLastSuccess } from '@/api/l2/sendTemplate'
// Drive fields definition (English UI, Chinese comments) / 传动字段定义(文界面,中文注释
// 传动字段定义(文界面,贴合工业场景
const DRIVE_FIELDS = [
{ key: 'porTension', label: 'Pay-off Reel Tension' },
{ key: 'celTension', label: 'Entry Loop Tension' },
{ key: 'cleanTension', label: 'Cleaning Section Tension' },
{ key: 'furTension', label: 'Furnace Zone Tension' },
{ key: 'towerTension', label: 'Cooling Tower Tension' },
{ key: 'tmNoneTension', label: 'TM No Tension' },
{ key: 'tmEntryTension', label: 'TM Entry Tension' },
{ key: 'tmExitTension', label: 'TM Exit Tension' },
{ key: 'tlNoneTension', label: 'TL No Tension' },
{ key: 'tlExitTension', label: 'TL Exit Tension' },
{ key: 'coatTension', label: 'Post-treatment Tension' },
{ key: 'cxlTension', label: 'Exit Loop Tension' },
{ key: 'trTension', label: 'Take-up Reel Tension' },
{ key: 'porTension', label: '开卷机张力' },
{ key: 'celTension', label: '入口活套张力' },
{ key: 'cleanTension', label: '清洗段张力' },
{ key: 'furTension', label: '炉区张力' },
{ key: 'towerTension', label: '冷却塔张力' },
{ key: 'tmNoneTension', label: '轧机无张力' },
{ key: 'tmEntryTension', label: '轧机入口张力' },
{ key: 'tmExitTension', label: '轧机出口张力' },
{ key: 'tlNoneTension', label: '拉伸机无张力' },
{ key: 'tlExitTension', label: '拉伸机出口张力' },
{ key: 'coatTension', label: '后处理段张力' },
{ key: 'cxlTension', label: '出口活套张力' },
{ key: 'trTension', label: '卷取机张力' },
{ key: 'tlElong', label: 'TL Elongation' },
{ key: 'tlLvlMesh1', label: 'TL Leveling Roll Mesh 1' },
{ key: 'tlLvlMesh2', label: 'TL Leveling Roll Mesh 2' },
{ key: 'tlAcbMesh', label: 'TL Anti-crossbow Mesh' },
{ key: 'tlElong', label: '拉伸机延伸率' },
{ key: 'tlLvlMesh1', label: '拉伸机矫直辊间隙1' },
{ key: 'tlLvlMesh2', label: '拉伸机矫直辊间隙2' },
{ key: 'tlAcbMesh', label: '拉伸机防侧弯间隙' },
{ key: 'tmBendforce', label: 'TM Bending Force' },
{ key: 'tmAcrMesh', label: 'TM Anti-crimping Roll Mesh' },
{ key: 'tmBrMesh', label: 'TM Anti-tremor Roll Mesh' },
{ key: 'tmRollforce', label: 'TM Roll Force' }
{ key: 'tmBendforce', label: '轧机弯辊力' },
{ key: 'tmAcrMesh', label: '轧机防皱辊间隙' },
{ key: 'tmBrMesh', label: '轧机防颤辊间隙' },
{ key: 'tmRollforce', label: '轧机轧制力' }
]
// OPC address mapping / OPC点位映射
// OPC地址映射(保持原有配置,不影响功能)
const DRIVE_ADDRESS = {
porTension: 'ns=2;s=ProcessCGL.PLCLine.L2Setup.tensionPorBR1',
celTension: 'ns=2;s=ProcessCGL.PLCLine.L2Setup.tensionBR3',
@@ -164,7 +164,7 @@ export default {
return {
loading: false,
lastSuccess: null,
setups: [], // Changed from 'plans' to 'setups'
setups: [],
driveFields: DRIVE_FIELDS,
driveAddress: { ...DRIVE_ADDRESS }
}
@@ -176,22 +176,22 @@ export default {
async reload() {
this.loading = true
try {
// 1. Get last success for DRIVE
// 1. 获取传动模块上次成功下发数据
const lastRes = await getLastSuccess('DRIVE')
this.lastSuccess = lastRes && lastRes.code === 200 ? lastRes.data : null
// 2. Get setup history list (instead of plans)
const setupRes = await listSetup({ pageNum: 1, pageSize: 20 }) // Fetch latest 20 for example
// 2. 获取配置历史列表
const setupRes = await listSetup({ pageNum: 1, pageSize: 20 })
const setupList = (setupRes && setupRes.rows) || []
// 3. Map setup list to display data
// 3. 映射配置列表为展示数据
this.setups = setupList.map(s => {
const params = {}
this.driveFields.forEach(f => {
const fromSetup = s ? s[f.key] : undefined
const fromLast = this.lastSuccess?.values?.[f.key]
// Priority: current setup value > last success value > ''
// 优先级:当前配置值 > 上次成功值 > 空字符串
if (fromSetup !== undefined && fromSetup !== null && String(fromSetup) !== '') {
params[f.key] = String(fromSetup)
} else if (fromLast !== undefined && fromLast !== null) {
@@ -209,7 +209,7 @@ export default {
})
} catch (e) {
console.error(e)
this.$message.error('Load failed')
this.$message.error('加载失败')
} finally {
this.loading = false
}
@@ -217,7 +217,7 @@ export default {
applyLastSuccessValues() {
if (!this.lastSuccess || !this.lastSuccess.values) {
this.$message.info('No last success data')
this.$message.info('暂无上次成功数据')
return
}
this.setups.forEach(setup => {
@@ -228,13 +228,13 @@ export default {
}
})
})
this.$message.success('Last success values applied')
this.$message.success('上次成功参数应用完成')
},
getPlaceholder(key) {
const v = this.lastSuccess?.values?.[key]
if (v !== undefined) return `Last: ${v}`
return 'Please enter'
if (v !== undefined) return `上次值:${v}`
return '请输入参数值'
},
formatTime(t) {
@@ -244,11 +244,11 @@ export default {
handleSend(setup) {
this.$confirm(
`Confirm to send parameters for Coil [${setup.coilid || '-'}]?`,
'Warning',
`确认要下发【${setup.coilid || '-'}】钢卷的传动参数吗?`,
'提示',
{
confirmButtonText: 'Confirm',
cancelButtonText: 'Cancel',
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => this.doSend(setup)).catch(() => {})
@@ -259,24 +259,24 @@ export default {
try {
const items = this.driveFields.map(f => ({
paramCode: f.key,
address: this.driveAddress[f.key], // OPC address can be empty
address: this.driveAddress[f.key],
valueRaw: String(setup.params[f.key] || ''),
setTime: new Date()
})).filter(it => !!it.address) // Filter out items without an address
})).filter(it => !!it.address) // 过滤无OPC地址的项
if (!items.length) {
this.$message.warning('OPC addresses are not configured. Nothing to send.')
this.$message.warning('OPC地址未配置,无可下发内容')
return
}
const dto = {
deviceName: 'CGL_LINE_1',
bizKey: setup.coilid, // Use coilid as business key
bizKey: setup.coilid,
groups: [
{
groupNo: 1,
groupType: 'DRIVE',
groupName: `Drive Params for ${setup.coilid || ''}`,
groupName: `传动参数_${setup.coilid || ''}`,
items
}
]
@@ -284,15 +284,15 @@ export default {
const createRes = await createSendJob(dto)
const jobId = createRes.data
if (!jobId) throw new Error('Create send job failed')
if (!jobId) throw new Error('创建下发任务失败')
await executeSendJob(jobId)
this.$message.success('Send success')
this.$message.success('下发成功')
await this.reload()
} catch (e) {
console.error(e)
this.$message.error(e.message || 'Send failed')
this.$message.error(e.message || '下发失败')
} finally {
setup.sending = false
}
@@ -313,4 +313,4 @@ export default {
.header-right { flex-shrink: 0; margin-left: 16px; }
.last-send-time { font-size: 12px; color:#909399; margin-right:16px; }
.empty-data { margin-top: 20px; }
</style>
</style>

View File

@@ -1,16 +1,16 @@
<template>
<div class="app-container">
<!-- Toolbar / 工具栏 -->
<!-- 工具栏 -->
<div class="toolbar">
<el-button @click="reload" icon="el-icon-refresh" size="small" :loading="loading">
Refresh
刷新
</el-button>
<!-- Edit template switch / -->
<!-- 编辑模板开关 -->
<el-switch
v-model="editTemplate"
active-text="Edit Template"
inactive-text="View"
active-text="编辑模板"
inactive-text="查看模式"
style="margin: 0 12px"
/>
@@ -23,7 +23,7 @@
:loading="savingTemplate"
@click="saveTemplate"
>
Save Template
保存模板
</el-button>
<el-button
@@ -34,7 +34,7 @@
size="small"
@click="applyLastSuccessValues"
>
Apply Last Success Values
应用上次成功参数
</el-button>
<el-button
@@ -44,14 +44,14 @@
size="small"
@click="openHistory"
>
History
历史记录
</el-button>
</div>
<!-- History Floating Panel -->
<!-- 历史浮动面板 -->
<FloatingPanel
ref="historyPanel"
title="History"
title="炉火下发历史"
storageKey="FURNACE_SEND_HISTORY_PANEL"
:defaultW="980"
:defaultH="520"
@@ -61,15 +61,15 @@
<FurnaceHistoryPanel @apply="applyHistoryValues" />
</FloatingPanel>
<!-- Furnace Parameter Form / 炉火参数表单 -->
<!-- 炉火参数表单 -->
<div v-loading="loading" class="card-grid-container">
<el-card class="parameter-card" shadow="hover">
<div slot="header" class="card-header">
<span class="card-title">{{ template ? template.templateName : 'Furnace Settings' }}</span>
<span class="card-title">{{ template ? template.templateName : '炉火参数配置' }}</span>
<div class="header-right">
<span v-if="lastSuccess && lastSuccess.lastSendTime" class="last-send-time">
<i class="el-icon-time"></i>
Last Sent: {{ formatTime(lastSuccess.lastSendTime) }}
上次下发{{ formatTime(lastSuccess.lastSendTime) }}
</span>
<el-button
type="primary"
@@ -78,12 +78,12 @@
@click="handleSend"
:loading="sending"
>
Send
下发
</el-button>
</div>
</div>
<!-- Template-driven editable form / 按模板渲染可编辑表单 -->
<!-- 按模板渲染可编辑表单 -->
<el-form :model="form" label-position="top" size="mini">
<div class="group-list">
<div
@@ -93,10 +93,10 @@
>
<div class="group-header">
<span class="group-title">{{ group.groupTitle }}</span>
<span class="group-count">({{ group.items.length }} items)</span>
<span class="group-count">({{ group.items.length }} )</span>
</div>
<!-- Three inputs per row / 每行三个输入框 -->
<!-- 每行三个输入框 -->
<el-row :gutter="20">
<el-col
:span="8"
@@ -113,19 +113,19 @@
<!-- 辅助信息上次/默认值常驻不会像 placeholder 一样消失 -->
<div class="field-hint">
<span v-if="getLastValue(item) !== undefined" class="hint-item">
Last Success: <b>{{ getLastValue(item) }}</b>
上次成功<b>{{ getLastValue(item) }}</b>
</span>
<span v-if="getDefaultValue(item) !== undefined" class="hint-item">
Default: <b>{{ getDefaultValue(item) }}</b>
默认值<b>{{ getDefaultValue(item) }}</b>
</span>
<span v-if="isChangedFromLast(item)" class="hint-item changed">
Modified
已修改
</span>
</div>
<!-- Inline address editor / 编辑点位 -->
<!-- 编辑点位 -->
<div v-if="editTemplate" class="addr-inline">
<span class="addr-label">Address:</span>
<span class="addr-label">点位地址</span>
<el-input v-model="item.address" size="mini" placeholder="ns=2;s=..." />
</div>
</el-form-item>
@@ -136,7 +136,7 @@ Modified
</el-form>
<div v-if="!loading && templateItems.length === 0" class="empty-data">
<el-empty description="Template is empty or not found"></el-empty>
<el-empty description="模板为空或未找到"></el-empty>
</div>
</el-card>
</div>
@@ -144,11 +144,11 @@ Modified
</template>
<script>
// Import APIs / 引入接口
// 引入接口
import { createSendJob, executeSendJob } from '@/api/l2/sendJob'
import { getSendTemplate, getLastSuccess, updateSendTemplate, batchSaveSendTemplateItems } from '@/api/l2/sendTemplate'
// Import Components / 引入组件
// 引入组件
import FloatingPanel from '@/components/FloatingPanel.vue'
import FurnaceHistoryPanel from './components/FurnaceHistoryPanel.vue'
@@ -160,14 +160,14 @@ export default {
},
data() {
return {
loading: false, // Loading / 加载
sending: false, // Sending / 发送
savingTemplate: false, // Saving template / 保存模板中
editTemplate: false, // Edit template switch / 编辑模板开关
loading: false, // 加载
sending: false, // 下发
savingTemplate: false, // 保存模板中
editTemplate: false, // 编辑模板开关
template: null, // Template / 模板
lastSuccess: null, // Last success / 上次成功
form: {}, // Form values / 表单值
template: null, // 模板信息
lastSuccess: null, // 上次成功下发数据
form: {}, // 表单值
// 仅用于 Edit Template记录加载时的原始模板项快照用来计算差异避免全量提交
originalItemsSnapshot: []
@@ -254,7 +254,7 @@ export default {
},
getGroupTitle(groupKey) {
// 可按你们现场习惯改中文名
// 可按你们现场习惯改中文名,此处保留工业常用缩写
const map = {
NOF: 'NOF',
RTF: 'RTF',
@@ -305,7 +305,7 @@ export default {
applyLastSuccessValues() {
if (!this.lastSuccess || !this.lastSuccess.values) {
this.$message.info('No last success data')
this.$message.info('暂无上次成功数据')
return
}
this.templateItems.forEach(item => {
@@ -314,12 +314,12 @@ export default {
this.$set(this.form, item.paramCode, String(v))
}
})
this.$message.success('Last success values applied')
this.$message.success('上次成功参数应用完成')
},
getPlaceholder() {
// placeholder 只保留引导,不承载关键信息(上次/默认值放到下方提示)
return 'Please enter'
return '请输入参数值'
},
getLastValue(item) {
@@ -347,13 +347,13 @@ export default {
async saveTemplate() {
if (!this.template || !this.template.templateId) {
this.$message.error('Template not loaded')
this.$message.error('模板未加载')
return
}
this.savingTemplate = true
try {
// 1) save template main
// 1) 保存模板主信息
await updateSendTemplate({
templateId: this.template.templateId,
deviceName: this.template.deviceName,
@@ -361,7 +361,7 @@ export default {
remark: this.template.remark
})
// 2) diff items (ONLY send changed items)
// 2) 对比模板项差异(仅发送变更项,减少请求压力)
const currentAll = (this.template && Array.isArray(this.template.items))
? this.template.items.map(it => this.pickItemFields(it))
: []
@@ -373,17 +373,17 @@ export default {
const originalById = new Map(originalAll.filter(x => x.templateItemId != null).map(x => [x.templateItemId, x]))
const currentById = new Map(currentAll.filter(x => x.templateItemId != null).map(x => [x.templateItemId, x]))
// deleted: in original but not in current
// 待删除项:在原始快照中存在,当前不存在
const deleteIds = []
originalById.forEach((_, id) => {
if (!currentById.has(id)) deleteIds.push(id)
})
// upsert: new (no id) OR changed
// 待新增/更新项无ID新增 或 与原始快照不一致(更新)
const upserts = []
currentAll.forEach(it => {
if (!it.templateItemId) {
// new item
// 新增项
upserts.push(it)
return
}
@@ -398,7 +398,7 @@ export default {
})
if (!upserts.length && !deleteIds.length) {
this.$message.success('No changes')
this.$message.success('暂无变更')
this.editTemplate = false
return
}
@@ -409,21 +409,21 @@ export default {
deleteIds
})
this.$message.success('Template saved')
this.$message.success('模板保存成功')
this.editTemplate = false
await this.reload()
} catch (e) {
console.error(e)
this.$message.error(e.message || 'Save template failed')
this.$message.error(e.message || '保存模板失败')
} finally {
this.savingTemplate = false
}
},
handleSend() {
this.$confirm('Confirm to send furnace parameters?', 'Warning', {
confirmButtonText: 'Confirm',
cancelButtonText: 'Cancel',
this.$confirm('确认要下发炉火参数吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.doSend()
@@ -432,11 +432,11 @@ export default {
async doSend() {
if (!this.template) {
this.$message.error('Template not loaded')
this.$message.error('模板未加载')
return
}
if (!this.templateItems.length) {
this.$message.error('Template is empty')
this.$message.error('模板为空')
return
}
@@ -473,7 +473,7 @@ export default {
{
groupNo: 1,
groupType: 'FURNACE',
groupName: this.template.templateName || 'Furnace Settings',
groupName: this.template.templateName || '炉火参数配置',
items
}
]
@@ -481,15 +481,15 @@ export default {
const createRes = await createSendJob(dto)
const jobId = createRes.data
if (!jobId) throw new Error('Create send job failed')
if (!jobId) throw new Error('创建下发任务失败')
await executeSendJob(jobId)
this.$message.success('Send success')
this.$message.success('下发成功')
await this.reload()
} catch (e) {
console.error(e)
this.$message.error(e.message || 'Send failed')
this.$message.error(e.message || '下发失败')
} finally {
this.sending = false
}
@@ -540,4 +540,4 @@ export default {
border-color: #e6a23c;
background-color: #fdf6ec;
}
</style>
</style>

View File

@@ -5,7 +5,7 @@
<el-col :span="4" class="sidebar-col">
<div class="sidebar-wrapper">
<div class="sidebar-header">
<h3>Process Parameter Categories</h3>
<h3>工艺参数分类</h3>
<!-- 工艺参数分类 -->
</div>
<el-menu
@@ -15,27 +15,27 @@
>
<el-menu-item index="1">
<i class="el-icon-setting"></i>
<span slot="title">Full Line Tension</span>
<span slot="title">全线张力</span>
<!-- 全线张力 -->
</el-menu-item>
<el-menu-item index="2">
<i class="el-icon-setting"></i>
<span slot="title">Leveling Machine Parameters</span>
<span slot="title">拉校机参数</span>
<!-- 拉校机参数 -->
</el-menu-item>
<el-menu-item index="3">
<i class="el-icon-setting"></i>
<span slot="title">Temper Mill Bending Force</span>
<span slot="title">光整机弯辊力</span>
<!-- 光整机弯辊力 -->
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting"></i>
<span slot="title">Temper Mill Insertion</span>
<span slot="title">光整机插入量</span>
<!-- 光整机插入量 -->
</el-menu-item>
<el-menu-item index="5">
<i class="el-icon-setting"></i>
<span slot="title">Temper Mill Rolling Force</span>
<span slot="title">光整机轧制力</span>
<!-- 光整机轧制力 -->
</el-menu-item>
<!-- <el-menu-item index="6">

View File

@@ -6,14 +6,14 @@
<el-col :span="19.5">
<el-row :gutter="8" align="middle" class="filter-row">
<!-- 循环processAcceptKeys生成筛选控件 -->
<el-form inline>
<el-form inline>
<el-form-item v-for="key in processAcceptKeys" :key="key" :label="getFieldLabel(key)" class="filter-form-item" label-width="100px">
<!-- 输入框 -->
<el-input v-if="getFieldComponentType(key) === 'el-input'" v-model="queryParams[key]"
:placeholder="`Please enter ${getFieldLabel(key)}`" size="mini" clearable @keyup.enter="handleQuery" />
:placeholder="`请输入${getFieldLabel(key)}`" size="mini" clearable @keyup.enter="handleQuery" />
<!-- 下拉选择框 -->
<el-select v-else-if="getFieldComponentType(key) === 'el-select'" v-model="queryParams[key]"
:placeholder="`Please select ${getFieldLabel(key)}`" size="mini" clearable @change="handleQuery">
:placeholder="`请选择${getFieldLabel(key)}`" size="mini" clearable @change="handleQuery">
<el-option v-for="item in getFieldOptions(key)" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
@@ -26,9 +26,9 @@
<!-- 筛选操作按钮查询 + 重置 -->
<el-col :xs="24" :sm="12" :md="6" class="filter-btn-group">
<el-button type="primary" plain icon="el-icon-search" size="mini" @click="handleQuery">Query</el-button>
<el-button type="primary" plain icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
<el-button type="default" plain icon="el-icon-refresh-left" size="mini" @click="handleResetFilter"
style="margin-left: 8px;">Reset</el-button>
style="margin-left: 8px;">重置</el-button>
</el-col>
</el-row>
</el-col>
@@ -36,13 +36,13 @@
<!-- 顶部操作栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">Add</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">Export</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-refresh" size="mini" @click="handleRefresh">Refresh</el-button>
<el-button type="success" plain icon="el-icon-refresh" size="mini" @click="handleRefresh">刷新</el-button>
</el-col>
</el-row>
@@ -75,9 +75,9 @@
<!-- 卡片底部操作按钮 -->
<div class="card-footer">
<el-button size="mini" type="text" icon="el-icon-copy-document" @click="handleCopy(item)">Copy</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(item)">Edit</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(item)">Delete</el-button>
<el-button size="mini" type="text" icon="el-icon-copy-document" @click="handleCopy(item)">复制</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(item)">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(item)">删除</el-button>
</div>
</el-card>
</el-col>
@@ -102,7 +102,7 @@
<el-input v-if="getFieldComponentType(key) == 'el-input'" v-model="form[key]" placeholder="Please enter"
:disabled="isEdit" />
<el-select v-else-if="getFieldComponentType(key) == 'el-select'" v-model="form[key]"
placeholder="Please select" :disabled="isEdit">
placeholder="请选择" :disabled="isEdit">
<el-option v-for="item in getFieldOptions(key)" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<component v-else :is="getFieldComponentType(key)" v-model="form[key]"
@@ -115,7 +115,7 @@
:prop="key">
<el-input v-if="getFieldComponentType(key) == 'el-input'" v-model="form[key]" placeholder="Please enter" />
<el-select v-else-if="getFieldComponentType(key) == 'el-select'" v-model="form[key]"
placeholder="Please select">
placeholder="请选择">
<el-option v-for="item in getFieldOptions(key)" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<component v-else :is="getFieldComponentType(key)" v-model="form[key]"
@@ -250,7 +250,7 @@ export default {
/** 根据字段prop获取输入提示输入/选择) */
getFieldInputHint(prop) {
const field = this.schema.find(item => item.prop === prop);
return field?.type === 'select' ? 'select' : 'enter';
return field?.type === 'el-select' ? '请选择' : '请输入';
},
/** 根据字段prop获取下拉选项 */
@@ -284,7 +284,7 @@ export default {
const field = this.schema.find(item => item.prop === key);
if (field?.required !== false) { // 默认必填除非显式设置required: false
this.formRules[key] = [
{ required: true, message: `Please ${this.getFieldInputHint(key)} ${this.getFieldLabel(key)}`, trigger: 'blur' }
{ required: true, message: `${this.getFieldInputHint(key)} ${this.getFieldLabel(key)}`, trigger: 'blur' }
];
}
});
@@ -352,7 +352,7 @@ export default {
this.isAdd = true;
this.resetForm();
this.open = true;
this.title = `Add ${this.$options.name || 'Process Parameters'}`;
this.title = `新增工艺参数`;
},
/** 复制新增操作 */
@@ -365,7 +365,7 @@ export default {
this.form[key] = row[key] || '';
});
this.open = true;
this.title = `Copy & Add ${this.$options.name || 'Process Parameters'}`;
this.title = `复制新增工艺参数`;
},
/** 修改操作(优化异常处理和数据赋值) */
@@ -380,9 +380,9 @@ export default {
this.form[key] = data[key] !== undefined ? data[key] : '';
});
this.open = true;
this.title = `Edit ${this.$options.name || 'Process Parameters'}`;
this.title = `编辑工艺参数`;
}).catch(error => {
this.$modal.msgError('Failed to get details, please try again.');
this.$modal.msgError('获取详情失败,请稍后重试。');
console.error('获取详情失败:', error);
});
},
@@ -393,11 +393,11 @@ export default {
if (valid) {
const api = this.isAdd ? this.apis.add : this.apis.update;
api(this.form).then(() => {
this.$modal.msgSuccess(this.isAdd ? "Added successfully" : "Updated successfully");
this.$modal.msgSuccess(this.isAdd ? "新增成功" : "更新成功");
this.open = false;
this.getList();
}).catch(error => {
this.$modal.msgError(this.isAdd ? "Add failed" : "Update failed");
this.$modal.msgError(this.isAdd ? "新增失败" : "更新失败");
console.error('提交失败:', error);
});
}
@@ -406,11 +406,11 @@ export default {
/** 删除操作 */
handleDelete(row) {
this.$modal.confirm('Are you sure you want to delete this parameter?').then(() => {
this.$modal.confirm('确定删除该工艺参数吗?').then(() => {
return this.apis.del(row);
}).then(() => {
this.getList();
this.$modal.msgSuccess("Deleted successfully");
this.$modal.msgSuccess("删除成功");
}).catch(() => { });
},
@@ -419,9 +419,9 @@ export default {
try {
this.download(this.apis.export, {
...this.queryParams
}, `${this.$options.name || 'process_param'}_${new Date().getTime()}.xlsx`);
}, `工艺参数_${new Date().getTime()}.xlsx`);
} catch (error) {
this.$modal.msgWarning('Export is not configured yet. Please contact admin.');
this.$modal.msgWarning('导出功能暂未配置,请联系管理员。');
console.error('导出失败:', error);
}
}

View File

@@ -1,10 +1,6 @@
<template>
<ProcessParamCardTemplate
:apis="tensionApis"
:schema="tensionSchema"
:processAcceptKeys="processAcceptKeys"
:processReturnKeys="processReturnKeys"
/>
<ProcessParamCardTemplate :apis="tensionApis" :schema="tensionSchema" :processAcceptKeys="processAcceptKeys"
:processReturnKeys="processReturnKeys" />
</template>
<script>
@@ -28,22 +24,22 @@ export default {
// 2. 字段配置schema数组格式
tensionSchema: [
// 标识字段processAcceptKeys
{ prop: 'thick', label: 'Thickness', required: true },
{ prop: 'yieldStren', label: 'Yield Strength', required: true },
{ prop: 'thick', label: '厚度', required: true },
{ prop: 'yieldStren', label: '屈服强度', required: true },
// 业务参数processReturnKeys
{ prop: 'value1', label: 'Uncoiler tension', required: true },
{ prop: 'value2', label: 'Entry looper', required: true },
{ prop: 'value3', label: 'Cleaning section', required: true },
{ prop: 'value4', label: 'Furnace tension', required: true },
{ prop: 'value5', label: 'Cooling tower', required: true },
{ prop: 'value6', label: 'Skin-pass (off)', required: true },
{ prop: 'value7', label: 'Skin-pass entry', required: true },
{ prop: 'value8', label: 'Skin-pass exit', required: true },
{ prop: 'value9', label: 'Tension leveler (off)', required: true },
{ prop: 'value10', label: 'Tension leveler exit', required: true },
{ prop: 'value11', label: 'Post treatment', required: true },
{ prop: 'value12', label: 'Exit looper', required: true },
{ prop: 'value13', label: 'Coiler', required: true }
{ prop: 'value1', label: '开卷机张力', required: true },
{ prop: 'value2', label: '入口活套', required: true },
{ prop: 'value3', label: '清洗段', required: true },
{ prop: 'value4', label: '炉区张力', required: true },
{ prop: 'value5', label: '冷却塔', required: true },
{ prop: 'value6', label: '平整机(停机状态)', required: true },
{ prop: 'value7', label: '平整机入口', required: true },
{ prop: 'value8', label: '平整机出口', required: true },
{ prop: 'value9', label: '张力矫直机(停机状态)', required: true },
{ prop: 'value10', label: '张力矫直机出口', required: true },
{ prop: 'value11', label: '后处理段', required: true },
{ prop: 'value12', label: '出口活套', required: true },
{ prop: 'value13', label: '卷取机', required: true }
],
// 3. 工艺参数接受值编辑禁用的字段prop
processAcceptKeys: ['thick', 'yieldStren'],

View File

@@ -52,7 +52,7 @@ export default {
this.schema = [
{
prop: 'steelGrade',
label: 'Steel Grade',
label: '钢种',
required: true,
type: 'el-select',
options: steelGradeList.map(item => ({ label: item.name, value: item.gradeid })),
@@ -61,12 +61,12 @@ export default {
return grade ? grade.name : gradeId;
}
},
{ prop: 'yieldStren', label: 'Hardness', required: true },
{ prop: 'thick', label: 'Thickness', required: true },
{ prop: 'value1', label: 'Elongation', required: true },
{ prop: 'value2', label: 'Leveler roll insertion 1', required: true },
{ prop: 'value3', label: 'Leveler roll insertion 2', required: true },
{ prop: 'value4', label: 'Anti-crossbow insertion', required: true }
{ prop: 'yieldStren', label: '屈服强度', required: true },
{ prop: 'thick', label: '厚度', required: true },
{ prop: 'value1', label: '伸长率', required: true },
{ prop: 'value2', label: '一级级头插入力', required: true },
{ prop: 'value3', label: '二级级头插入力', required: true },
{ prop: 'value4', label: '反跨弓插入力', required: true }
];
}
}

View File

@@ -31,9 +31,9 @@ export default {
},
// 字段配置
schema: [
{ prop: 'width', label: 'Width', required: true },
{ prop: 'rollForce', label: 'Rolling force', required: true },
{ prop: 'value1', label: 'Bending force', required: true }
{ prop: 'width', label: '宽度', required: true },
{ prop: 'rollForce', label: '轧制力', required: true },
{ prop: 'value1', label: '弯曲力', required: true }
],
// 编辑禁用字段
processAcceptKeys: ['width', 'rollForce'],

View File

@@ -52,7 +52,7 @@ export default {
this.schema = [
{
prop: 'steelGrade',
label: 'Steel Grade',
label: '钢种',
required: true,
type: 'el-select',
options: steelGradeList.map(item => ({ label: item.name, value: item.gradeid })),
@@ -63,8 +63,8 @@ export default {
},
{ prop: 'thick', label: 'Thickness', required: true },
{ prop: 'yieldStren', label: 'Yield Strength', required: true },
{ prop: 'value1', label: 'Anti-wrinkle roll insertion', required: true },
{ prop: 'value2', label: 'Anti-chatter roll insertion', required: true }
{ prop: 'value1', label: 'wrinkles插入力', required: true },
{ prop: 'value2', label: 'chatter 插入力', required: true }
];
}
}

View File

@@ -53,7 +53,7 @@ export default {
this.schema = [
{
prop: 'steelGrade',
label: 'Steel Grade',
label: '钢种',
required: true,
type: 'el-select',
options: steelGradeList.map(item => ({ label: item.name, value: item.gradeid })),
@@ -62,10 +62,10 @@ export default {
return grade ? grade.name : gradeId;
}
},
{ prop: 'thick', label: 'Thickness', required: true },
{ prop: 'yieldStren', label: 'Yield Strength', required: true },
{ prop: 'elong', label: 'Elongation', required: true },
{ prop: 'value1', label: 'Rolling force', required: true }
{ prop: 'thick', label: '厚度', required: true },
{ prop: 'yieldStren', label: '屈服强度', required: true },
{ prop: 'elong', label: '伸长率', required: true },
{ prop: 'value1', label: '滚动力', required: true }
];
}
}

View File

@@ -1,37 +1,29 @@
<template>
<div class="pdi-container">
<!-- Card grid layout / 卡片网格布局 -->
<!-- 卡片网格布局 -->
<div v-loading="loading" class="card-grid-container">
<el-row :gutter="10">
<el-col :span="12">
<div class="pdi-header">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
label-width="68px">
<el-form-item label="Coil ID" prop="coilid">
<!-- 钢卷号 -->
<!-- Please enter coil ID / 请输入钢卷号 -->
<el-input v-model="queryParams.coilid" placeholder="Please enter coil ID" clearable
<el-form-item label="钢卷号" prop="coilid">
<el-input v-model="queryParams.coilid" placeholder="请输入钢卷号" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="Plan ID" prop="planid">
<!-- 计划号 -->
<!-- Please enter plan ID / 请输入计划号 -->
<el-input v-model="queryParams.planid" placeholder="Please enter plan ID" clearable
<el-form-item label="计划号" prop="planid">
<el-input v-model="queryParams.planid" placeholder="请输入计划号" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">Search</el-button>
<!-- 搜索 -->
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">Reset</el-button>
<!-- 重置 -->
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">Export</el-button>
<!-- 导出 -->
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
</el-form-item>
</el-form>
</div>
<div v-if="setupList.length === 0 && !loading" class="empty-data">
<el-empty description="No data"></el-empty>
<!-- 暂无数据 -->
<el-empty description="暂无数据"></el-empty>
</div>
<el-row v-else :gutter="10">
<el-col v-for="(item, index) in setupList" :key="index" :xs="24" :sm="24" :md="12" :lg="8" :xl="6"
@@ -40,15 +32,12 @@
:body-style="{ padding: '10px' }">
<div class="card-header">
<div class="card-title-row">
<span class="card-title">Coil ID: {{ item.coilid || '-' }}</span>
<!-- 钢卷号 -->
<span class="card-title">钢卷号: {{ item.coilid || '-' }}</span>
</div>
<div class="card-subtitle">Plan ID: {{ item.planid || '-' }} | Change Count: {{ item.type || '-' }}</div>
<!-- 计划ID: {{ item.planid || '-' }} | 更改次数: {{ item.type || '-' }} -->
<div class="card-subtitle">计划号: {{ item.planid || '-' }} | 更改次数: {{ item.type || '-' }}</div>
</div>
<div class="card-footer">
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(item)">Delete</el-button>
<!-- 删除 -->
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(item)">删除</el-button>
</div>
</el-card>
</el-col>
@@ -60,87 +49,71 @@
<div v-if="currentRow && currentRow.coilid" class="parameter-detail">
<div class="card-header">
<div class="card-title-row">
<span class="card-title">Coil ID: {{ currentRow.coilid || '-' }}</span>
<!-- 钢卷号 -->
<span class="card-title">钢卷号: {{ currentRow.coilid || '-' }}</span>
</div>
<div class="card-subtitle">Plan ID: {{ currentRow.planid || '-' }} | Change Count: {{ currentRow.type || '-' }}</div>
<!-- 计划ID: {{ currentRow.planid || '-' }} | 更改次数: {{ currentRow.type || '-' }} -->
<div class="card-subtitle">计划号: {{ currentRow.planid || '-' }} | 更改次数: {{ currentRow.type || '-' }}</div>
</div>
<div class="card-body">
<!-- Full line tension / 全线张力 -->
<!-- 全线张力 -->
<div class="param-group">
<div class="group-title">Full Line Tension</div>
<!-- 全线张力 -->
<div class="group-title">全线张力</div>
<div class="param-row">
<div class="param-item">
<span class="param-label">Pay-off Reel Tension:</span>
<!-- 开卷机张力 -->
<span class="param-label">开卷机张力:</span>
<span class="param-value">{{ currentRow.porTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Entry Loop Tension:</span>
<!-- 入口活套张力 -->
<span class="param-label">入口活套张力:</span>
<span class="param-value">{{ currentRow.celTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Cleaning Section Tension:</span>
<!-- 清洗段张力 -->
<span class="param-label">清洗段张力:</span>
<span class="param-value">{{ currentRow.cleanTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Furnace Zone Tension:</span>
<!-- 炉区张力 -->
<span class="param-label">炉区张力:</span>
<span class="param-value">{{ currentRow.furTension || '-' }}</span>
</div>
</div>
<div class="param-row">
<div class="param-item">
<span class="param-label">Cooling Tower Tension:</span>
<!-- 冷却塔张力 -->
<span class="param-label">冷却塔张力:</span>
<span class="param-value">{{ currentRow.towerTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">TM No-Engage Tension:</span>
<!-- 光整机不投张力 -->
<span class="param-label">光整机不投张力:</span>
<span class="param-value">{{ currentRow.tmNoneTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">TM Entry Tension:</span>
<!-- 光整机入口张力 -->
<span class="param-label">光整机入口张力:</span>
<span class="param-value">{{ currentRow.tmEntryTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">TM Exit Tension:</span>
<!-- 光整机出口张力 -->
<span class="param-label">光整机出口张力:</span>
<span class="param-value">{{ currentRow.tmExitTension || '-' }}</span>
</div>
</div>
<div class="param-row">
<div class="param-item">
<span class="param-label">TL No-Engage Tension:</span>
<!-- 拉矫机不投张力 -->
<span class="param-label">拉矫机不投张力:</span>
<span class="param-value">{{ currentRow.tlNoneTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">TL Exit Tension:</span>
<!-- 拉矫机出口张力 -->
<span class="param-label">拉矫机出口张力:</span>
<span class="param-value">{{ currentRow.tlExitTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Post-Processing Tension:</span>
<!-- 后处理张力 -->
<span class="param-label">后处理张力:</span>
<span class="param-value">{{ currentRow.coatTension || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Exit Loop Tension:</span>
<!-- 出口活套张力 -->
<span class="param-label">出口活套张力:</span>
<span class="param-value">{{ currentRow.cxlTension || '-' }}</span>
</div>
</div>
<div class="param-row">
<div class="param-item">
<span class="param-label">Take-up Reel Tension:</span>
<!-- 卷取机张力 -->
<span class="param-label">卷取机张力:</span>
<span class="param-value">{{ currentRow.trTension || '-' }}</span>
</div>
<div class="param-item"></div>
@@ -149,80 +122,66 @@
</div>
</div>
<!-- Temper mill parameters / 光整机参数 -->
<!-- 光整机参数 -->
<div class="param-group">
<div class="group-title">Temper Mill Parameters</div>
<!-- 光整机参数 -->
<div class="group-title">光整机参数</div>
<div class="param-row">
<div class="param-item">
<span class="param-label">TM Rolling Force:</span>
<!-- 光整机轧制力 -->
<span class="param-label">光整机轧制力:</span>
<span class="param-value">{{ currentRow.tmRollforce || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">TM Bending Force:</span>
<!-- 光整机弯辊力 -->
<span class="param-label">光整机弯辊力:</span>
<span class="param-value">{{ currentRow.tmBendforce || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Anti-Crimping Roll Insertion:</span>
<!-- 防皱辊插入量 -->
<span class="param-label">防皱辊插入量:</span>
<span class="param-value">{{ currentRow.tmAcrMesh || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Anti-Flutter Roll Insertion:</span>
<!-- 防颤辊插入量 -->
<span class="param-label">防颤辊插入量:</span>
<span class="param-value">{{ currentRow.tmBrMesh || '-' }}</span>
</div>
</div>
</div>
<!-- Leveling machine parameters / 拉矫机参数 -->
<!-- 拉矫机参数 -->
<div class="param-group">
<div class="group-title">Leveling Machine Parameters</div>
<!-- 拉矫机参数 -->
<div class="group-title">拉矫机参数</div>
<div class="param-row">
<div class="param-item">
<span class="param-label">TL Elongation:</span>
<!-- 拉矫机延伸率 -->
<span class="param-label">拉矫机延伸率:</span>
<span class="param-value">{{ currentRow.tlElong || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Leveling Roll Insertion 1:</span>
<!-- 矫直辊插入量1 -->
<span class="param-label">矫直辊插入量1:</span>
<span class="param-value">{{ currentRow.tlLvlMesh1 || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Leveling Roll Insertion 2:</span>
<!-- 矫直辊插入量2 -->
<span class="param-label">矫直辊插入量2:</span>
<span class="param-value">{{ currentRow.tlLvlMesh2 || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Anti-Cross-Bow Insertion:</span>
<!-- 防横弓插入量 -->
<span class="param-label">防横弓插入量:</span>
<span class="param-value">{{ currentRow.tlAcbMesh || '-' }}</span>
</div>
</div>
</div>
<!-- Furnace section / 炉火段 -->
<!-- 炉段温度 -->
<div class="param-group">
<div class="group-title">Furnace Section Temperature</div>
<!-- 炉段温度 -->
<div class="group-title">炉段温度</div>
<div class="param-row">
<div class="param-item">
<span class="param-label">Preheating Section Exit Temp:</span>
<!-- 预热段出口板温 -->
<span class="param-label">预热段出口板温:</span>
<span class="param-value">{{ currentRow.preheatingSection || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Heating Section Exit Temp:</span>
<!-- 加热段出口板温 -->
<span class="param-label">加热段出口板温:</span>
<span class="param-value">{{ currentRow.heatingSection || '-' }}</span>
</div>
<div class="param-item">
<span class="param-label">Cooling Section Exit Temp:</span>
<!-- 冷却段出口板温 -->
<span class="param-label">冷却段出口板温:</span>
<span class="param-value">{{ currentRow.coolingSection || '-' }}</span>
</div>
<div class="param-item"></div>
@@ -231,34 +190,28 @@
</div>
</div>
<el-empty v-else description="Please select a coil from the left to view process history"></el-empty>
<!-- 请在左侧选择钢卷查看工艺历史 -->
<el-empty v-else description="请在左侧选择钢卷查看工艺历史"></el-empty>
</el-col>
</el-row>
</div>
<!-- Statistics chart area: reuse PDO line chart component, based on selected coil ID / 统计图区域复用 PDO 的折线图组件基于选中的钢卷号 -->
<!-- 统计图区域复用 PDO 的折线图组件基于选中的钢卷号 -->
<div class="statistics-container">
<div class="statistics-header">
<div v-if="currentRow && currentRow.coilid" class="selected-info">
<i class="el-icon-check"></i>
<span class="selected-label">Selected:</span>
<!-- 已选中 -->
<span class="selected-value">Coil {{ currentRow.coilid }}</span>
<!-- 钢卷 -->
<span class="selected-detail" v-if="currentRow.planid">Plan ID: {{ currentRow.planid }}</span>
<!-- 计划号 -->
<span class="selected-label">已选中:</span>
<span class="selected-value">钢卷 {{ currentRow.coilid }}</span>
<span class="selected-detail" v-if="currentRow.planid">计划号: {{ currentRow.planid }}</span>
</div>
<div v-else class="selected-info empty">
<i class="el-icon-info"></i>
<span>Please select a card above to view chart</span>
<!-- 请选择上方卡片查看图表 -->
<i class="el-icon-info"></i>
<span>请选择上方卡片查看图表</span>
</div>
</div>
<div class="chart-wrapper">
<line-chart v-if="currentRow && currentRow.coilid" :enCoilID="currentRow.coilid" />
<div v-else class="chart-placeholder">Please select a coil to view process curve</div>
<!-- 请选择钢卷以查看工艺曲线 -->
<div v-else class="chart-placeholder">请选择钢卷以查看工艺曲线</div>
</div>
</div>
</div>
@@ -273,26 +226,26 @@ export default {
components: { LineChart },
data() {
return {
// Loading mask / 遮罩层
// 遮罩层
loading: true,
// Selected array / 选中数组
// 选中数组
ids: [],
currentRow: null,
// Disable single selection / 非单个禁用
// 非单个禁用
single: true,
// Disable multiple selection / 非多个禁用
// 非多个禁用
multiple: true,
// Show search conditions / 显示搜索条件
// 显示搜索条件
showSearch: true,
// Total count / 总条数
// 总条数
total: 0,
// Table data / 【请填写功能名称】表格数据
// 工艺参数配置表格数据
setupList: [],
// Dialog title / 弹出层标题
// 弹出层标题
title: "",
// Whether to show dialog / 是否显示弹出层
// 是否显示弹出层
open: false,
// Query parameters / 查询参数
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
@@ -323,18 +276,17 @@ export default {
updateTime: null,
TYPE: null
},
// Form parameters / 表单参数
// 表单参数
form: {},
// Form validation / 表单校验
rules: {
}
// 表单校验
rules: {}
};
},
created() {
this.getList();
},
methods: {
/** Query list / 查询【请填写功能名称】列表 */
/** 查询工艺参数配置列表 */
getList() {
this.loading = true;
listSetup(this.queryParams).then(response => {
@@ -343,12 +295,12 @@ export default {
this.loading = false;
});
},
// Cancel button / 取消按钮
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// Form reset / 表单重置
// 表单重置
reset() {
this.form = {
ID: null,
@@ -381,31 +333,31 @@ export default {
};
this.resetForm("form");
},
/** Search button operation / 搜索按钮操作 */
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
this.currentRow = null
},
/** Reset button operation / 重置按钮操作 */
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// Multi-select data / 多选框选中数据
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.ID)
this.single = selection.length !== 1
this.multiple = !selection.length
},
// Check if selected / 判断是否选中
// 判断是否选中
isSelected(item) {
return this.ids.includes(this.getItemKey(item))
},
getItemKey(item) {
return item.id ?? item.ID
},
// Toggle selection state / 切换选中状态
// 切换选中状态
toggleSelection(item, checked) {
const key = this.getItemKey(item)
if (checked) {
@@ -418,40 +370,40 @@ export default {
this.single = this.ids.length !== 1
this.multiple = this.ids.length === 0
},
/** Add button operation / 新增按钮操作 */
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "Add Setup"; // 添加【请填写功能名称】
this.title = "新增工艺参数配置";
},
/** Edit button operation / 修改按钮操作 */
/** 编辑按钮操作 */
handleUpdate(row) {
this.reset();
const ID = row.ID || this.ids
getSetup(ID).then(response => {
this.form = response.data;
this.open = true;
this.title = "Edit Setup"; // 修改【请填写功能名称】
this.title = "编辑工艺参数配置";
});
},
handleClick(item) {
this.currentRow = item;
console.log('Click', item) // 点击
console.log('点击', item)
// this.handleUpdate(item);
},
/** Submit button / 提交按钮 */
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.ID != null) {
updateSetup(this.form).then(response => {
this.$modal.msgSuccess("Update successful"); // 修改成功
this.$modal.msgSuccess("编辑成功");
this.open = false;
this.getList();
});
} else {
addSetup(this.form).then(response => {
this.$modal.msgSuccess("Add successful"); // 新增成功
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
@@ -459,24 +411,23 @@ export default {
}
});
},
/** Delete button operation / 删除按钮操作 */
/** 删除按钮操作 */
handleDelete(row) {
const IDs = row.id || this.ids;
this.$modal.confirm(`Confirm to delete setup record with ID "${IDs}"?`, 'Confirm Delete', {
// 是否确认删除【请填写功能名称】编号为"${IDs}"的数据项?
this.$modal.confirm(`确定要删除编号为"${IDs}"的工艺参数配置记录吗?`, '确认删除', {
type: 'warning'
}).then(function () {
return delSetup(IDs);
}).then(() => {
this.getList();
this.$modal.msgSuccess("Delete successful"); // 删除成功
this.$modal.msgSuccess("删除成功");
}).catch(() => { });
},
/** Export button operation / 导出按钮操作 */
/** 导出按钮操作 */
handleExport() {
this.download('system/setup/export', {
...this.queryParams
}, `setup_${new Date().getTime()}.xlsx`)
}, `工艺参数配置_${new Date().getTime()}.xlsx`)
}
}
};
@@ -652,7 +603,7 @@ export default {
padding: 40px 0;
}
/* Statistics chart styles, reuse PDO industrial style / 统计图样式,复用 PDO 工业风 */
/* 统计图样式,复用 PDO 工业风 */
.statistics-container {
margin-top: 16px;
background: #ffffff;
@@ -715,4 +666,4 @@ export default {
color: #909399;
font-size: 13px;
}
</style>
</style>

View File

@@ -1,10 +1,10 @@
<template>
<div class="steel-grade-management">
<!-- Overall layout: left card list + right detail panel / 整体布局左侧卡片列表 + 右侧明细面板 -->
<!-- 整体布局左侧卡片列表 + 右侧明细面板 -->
<div class="layout-container">
<!-- Left: search + card list / 左侧搜索+卡片列表 -->
<!-- 左侧搜索+卡片列表 -->
<div class="left-panel">
<!-- Top search area / 顶部搜索区域 -->
<!-- 顶部搜索区域 -->
<div class="search-container">
<el-form
:inline="true"
@@ -18,8 +18,7 @@
<el-input
size="mini"
v-model="queryForm.name"
placeholder="Please enter steel grade name"
placeholder="请输入钢种名称"
clearable
@clear="handleReset"
></el-input>
@@ -31,46 +30,42 @@
:loading="btnLoading"
icon="el-icon-search"
size="mini"
>Query</el-button>
<!-- 查询 -->
>查询</el-button>
<el-button
@click="handleReset"
icon="el-icon-refresh"
size="mini"
>Reset</el-button>
<!-- 重置 -->
>重置</el-button>
<el-button
type="success"
@click="handleAdd"
icon="el-icon-plus"
size="mini"
>Add Steel Grade</el-button>
<!-- 新增钢种 -->
>新增钢种</el-button>
</el-form-item>
</el-form>
</div>
<!-- Steel grade card list / 钢种卡片列表 -->
<!-- 钢种卡片列表 -->
<div class="card-list-container" v-loading="tableLoading">
<!-- No data tip / 无数据提示 -->
<!-- 无数据提示 -->
<div class="empty-tip" v-if="tableData.length === 0 && !tableLoading">
<el-empty description="No steel grade data"></el-empty>
<!-- 暂无钢种数据 -->
<el-empty description="暂无钢种数据"></el-empty>
</div>
<!-- Loop render compact cards / 循环渲染紧凑卡片 -->
<!-- 循环渲染紧凑卡片 -->
<div
class="steel-grade-card"
v-for="(item) in tableData"
:class="{ active: (selectedItem && selectedItem.gradeid) === item.gradeid }"
@click="handleCardClick(item)"
>
<!-- Card row 1: steel grade name # ID / 卡片第一行钢种名称 # ID -->
<!-- 卡片第一行钢种名称 # ID -->
<div class="card-row row1">
<span class="grade-name">{{ item.name }}</span>
<span class="grade-id">#{{ item.gradeid }}</span>
</div>
<!-- Card row 2: insert date + action buttons / 卡片第二行插入日期 + 操作按钮 -->
<!-- 卡片第二行插入日期 + 操作按钮 -->
<div class="card-row row2">
<span class="ins-date">{{ parseTime(item.insDate, '{y}-{m}-{d}') }}</span>
<div class="card-actions">
@@ -79,97 +74,69 @@
type="text"
@click.stop="handleEdit(item)"
icon="el-icon-edit"
>Edit</el-button>
<!-- 编辑 -->
>编辑</el-button>
<el-button
size="mini"
type="text"
@click.stop="handleDelete(item)"
:loading="item.deleteLoading"
icon="el-icon-delete"
>Delete</el-button>
<!-- 删除 -->
>删除</el-button>
</div>
</div>
</div>
</div>
</div>
<!-- Right: detail panel / 右侧明细面板 -->
<!-- 右侧明细面板 -->
<div class="right-panel" v-loading="rightLoading">
<!-- No selection tip / 未选择卡片提示 -->
<!-- 未选择卡片提示 -->
<div class="empty-detail" v-if="!selectedItem && !dialogVisible">
<el-empty description="Please select a steel grade from the left to view details"></el-empty>
<!-- 请选择左侧钢种查看详情 -->
<el-empty description="请选择左侧钢种查看详情"></el-empty>
</div>
<!-- Steel grade detail display / 钢种明细展示 -->
<!-- 钢种明细展示 -->
<div class="detail-content" v-if="selectedItem && !dialogVisible">
<div class="detail-header">
<h3>Steel Grade Details</h3>
<!-- 钢种详情 -->
<h3>钢种详情</h3>
<el-button
type="primary"
@click="handleEdit(selectedItem)"
icon="el-icon-edit"
size="mini"
>Edit</el-button>
<!-- 编辑 -->
>编辑</el-button>
</div>
<el-descriptions :column="2" border style="margin-top: 10px;">
<el-descriptions-item label="Steel Grade ID">{{ selectedItem.gradeid }}</el-descriptions-item>
<!-- 钢种ID -->
<el-descriptions-item label="Steel Grade Name">{{ selectedItem.name }}</el-descriptions-item>
<!-- 钢种名称 -->
<el-descriptions-item label="Origin">{{ selectedItem.origin }}</el-descriptions-item>
<!-- 来源 -->
<el-descriptions-item label="钢种ID">{{ selectedItem.gradeid }}</el-descriptions-item>
<el-descriptions-item label="钢种名称">{{ selectedItem.name }}</el-descriptions-item>
<el-descriptions-item label="来源">{{ selectedItem.origin }}</el-descriptions-item>
<el-descriptions-item label="Sigma0">{{ selectedItem.sigma0 }}</el-descriptions-item>
<el-descriptions-item label="First Sigma0">{{ selectedItem.firstSigma0 }}</el-descriptions-item>
<!-- 首次Sigma0 -->
<el-descriptions-item label="Initial Sigma">{{ selectedItem.initSigma }}</el-descriptions-item>
<!-- 初始Sigma -->
<el-descriptions-item label="Ro Value">{{ selectedItem.ro }}</el-descriptions-item>
<!-- Ro值 -->
<el-descriptions-item label="Class ID">{{ selectedItem.classId }}</el-descriptions-item>
<!-- 分类ID -->
<el-descriptions-item label="Parameter A">{{ selectedItem.a }}</el-descriptions-item>
<!-- 参数A -->
<el-descriptions-item label="Parameter B">{{ selectedItem.b }}</el-descriptions-item>
<!-- 参数B -->
<el-descriptions-item label="Parameter C">{{ selectedItem.c }}</el-descriptions-item>
<!-- 参数C -->
<el-descriptions-item label="Parameter D">{{ selectedItem.d }}</el-descriptions-item>
<!-- 参数D -->
<el-descriptions-item label="KC0 Parameter">{{ selectedItem.kc0 }}</el-descriptions-item>
<!-- KC0参数 -->
<el-descriptions-item label="KC1 Parameter">{{ selectedItem.kc1 }}</el-descriptions-item>
<!-- KC1参数 -->
<el-descriptions-item label="KC2 Parameter">{{ selectedItem.kc2 }}</el-descriptions-item>
<!-- KC2参数 -->
<el-descriptions-item label="KC3 Parameter">{{ selectedItem.kc3 }}</el-descriptions-item>
<!-- KC3参数 -->
<el-descriptions-item label="KC4 Parameter">{{ selectedItem.kc4 }}</el-descriptions-item>
<!-- KC4参数 -->
<el-descriptions-item label="Nu Parameter">{{ selectedItem.nu }}</el-descriptions-item>
<!-- Nu参数 -->
<el-descriptions-item label="E Parameter">{{ selectedItem.e }}</el-descriptions-item>
<!-- E参数 -->
<el-descriptions-item label="Chal Parameter">{{ selectedItem.chal }}</el-descriptions-item>
<!-- Chal参数 -->
<el-descriptions-item label="Temp0 Parameter">{{ selectedItem.temp0 }}</el-descriptions-item>
<!-- Temp0参数 -->
<el-descriptions-item label="Strength">{{ selectedItem.strength }}</el-descriptions-item>
<!-- 强度 -->
<el-descriptions-item label="Weld Code">{{ selectedItem.weldCode }}</el-descriptions-item>
<!-- 焊接代码 -->
<el-descriptions-item label="Insert Date">{{ parseTime(selectedItem.insDate) }}</el-descriptions-item>
<!-- 插入日期 -->
<el-descriptions-item label="首次Sigma0">{{ selectedItem.firstSigma0 }}</el-descriptions-item>
<el-descriptions-item label="初始Sigma">{{ selectedItem.initSigma }}</el-descriptions-item>
<el-descriptions-item label="Ro值">{{ selectedItem.ro }}</el-descriptions-item>
<el-descriptions-item label="分类ID">{{ selectedItem.classId }}</el-descriptions-item>
<el-descriptions-item label="参数A">{{ selectedItem.a }}</el-descriptions-item>
<el-descriptions-item label="参数B">{{ selectedItem.b }}</el-descriptions-item>
<el-descriptions-item label="参数C">{{ selectedItem.c }}</el-descriptions-item>
<el-descriptions-item label="参数D">{{ selectedItem.d }}</el-descriptions-item>
<el-descriptions-item label="KC0参数">{{ selectedItem.kc0 }}</el-descriptions-item>
<el-descriptions-item label="KC1参数">{{ selectedItem.kc1 }}</el-descriptions-item>
<el-descriptions-item label="KC2参数">{{ selectedItem.kc2 }}</el-descriptions-item>
<el-descriptions-item label="KC3参数">{{ selectedItem.kc3 }}</el-descriptions-item>
<el-descriptions-item label="KC4参数">{{ selectedItem.kc4 }}</el-descriptions-item>
<el-descriptions-item label="Nu参数">{{ selectedItem.nu }}</el-descriptions-item>
<el-descriptions-item label="E参数">{{ selectedItem.e }}</el-descriptions-item>
<el-descriptions-item label="Chal参数">{{ selectedItem.chal }}</el-descriptions-item>
<el-descriptions-item label="Temp0参数">{{ selectedItem.temp0 }}</el-descriptions-item>
<el-descriptions-item label="强度">{{ selectedItem.strength }}</el-descriptions-item>
<el-descriptions-item label="焊接代码">{{ selectedItem.weldCode }}</el-descriptions-item>
<el-descriptions-item label="插入日期">{{ parseTime(selectedItem.insDate) }}</el-descriptions-item>
</el-descriptions>
</div>
</div>
</div>
<!-- Edit/Add Dialog / 编辑/新增弹窗 -->
<!-- 编辑/新增弹窗 -->
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
@@ -185,21 +152,17 @@
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="Steel Grade ID" prop="gradeid">
<!-- 钢种ID -->
<el-form-item label="钢种ID" prop="gradeid">
<el-input v-model="formData.gradeid" :disabled="isEdit"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Steel Grade Name" prop="name">
<!-- 钢种名称 -->
<el-input v-model="formData.name" placeholder="Please enter steel grade name"></el-input>
<!-- 请输入钢种名称 -->
<el-form-item label="钢种名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入钢种名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Origin" prop="origin">
<!-- 来源 -->
<el-form-item label="来源" prop="origin">
<el-input-number v-model="formData.origin" :min="0" :step="1" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
@@ -209,122 +172,102 @@
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="First Sigma0" prop="firstSigma0">
<!-- 首次Sigma0 -->
<el-form-item label="首次Sigma0" prop="firstSigma0">
<el-input-number v-model="formData.firstSigma0" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Initial Sigma" prop="initSigma">
<!-- 初始Sigma -->
<el-form-item label="初始Sigma" prop="initSigma">
<el-input-number v-model="formData.initSigma" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Ro Value" prop="ro">
<!-- Ro值 -->
<el-form-item label="Ro" prop="ro">
<el-input-number v-model="formData.ro" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Class ID" prop="classId">
<!-- 分类ID -->
<el-form-item label="分类ID" prop="classId">
<el-input-number v-model="formData.classId" :min="0" :step="1" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Parameter A" prop="a">
<!-- 参数A -->
<el-form-item label="参数A" prop="a">
<el-input-number v-model="formData.a" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Parameter B" prop="b">
<!-- 参数B -->
<el-form-item label="参数B" prop="b">
<el-input-number v-model="formData.b" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Parameter C" prop="c">
<!-- 参数C -->
<el-form-item label="参数C" prop="c">
<el-input-number v-model="formData.c" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Parameter D" prop="d">
<!-- 参数D -->
<el-form-item label="参数D" prop="d">
<el-input-number v-model="formData.d" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="KC0 Parameter" prop="kc0">
<!-- KC0参数 -->
<el-form-item label="KC0参数" prop="kc0">
<el-input-number v-model="formData.kc0" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="KC1 Parameter" prop="kc1">
<!-- KC1参数 -->
<el-form-item label="KC1参数" prop="kc1">
<el-input-number v-model="formData.kc1" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="KC2 Parameter" prop="kc2">
<!-- KC2参数 -->
<el-form-item label="KC2参数" prop="kc2">
<el-input-number v-model="formData.kc2" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="KC3 Parameter" prop="kc3">
<!-- KC3参数 -->
<el-form-item label="KC3参数" prop="kc3">
<el-input-number v-model="formData.kc3" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="KC4 Parameter" prop="kc4">
<!-- KC4参数 -->
<el-form-item label="KC4参数" prop="kc4">
<el-input-number v-model="formData.kc4" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Nu Parameter" prop="nu">
<!-- Nu参数 -->
<el-form-item label="Nu参数" prop="nu">
<el-input-number v-model="formData.nu" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="E Parameter" prop="e">
<!-- E参数 -->
<el-form-item label="E参数" prop="e">
<el-input-number v-model="formData.e" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Chal Parameter" prop="chal">
<!-- Chal参数 -->
<el-form-item label="Chal参数" prop="chal">
<el-input-number v-model="formData.chal" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Temp0 Parameter" prop="temp0">
<!-- Temp0参数 -->
<el-form-item label="Temp0参数" prop="temp0">
<el-input-number v-model="formData.temp0" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Strength" prop="strength">
<!-- 强度 -->
<el-form-item label="强度" prop="strength">
<el-input-number v-model="formData.strength" :step="0.01" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Weld Code" prop="weldCode">
<!-- 焊接代码 -->
<el-form-item label="焊接代码" prop="weldCode">
<el-input-number v-model="formData.weldCode" :min="0" :step="1" style="width: 100%;"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Insert Date" prop="insDate">
<!-- 插入日期 -->
<el-form-item label="插入日期" prop="insDate">
<el-date-picker v-model="formData.insDate" type="datetime" disabled value-format="yyyy-MM-ddTHH:mm:ss" style="width: 100%;"/>
</el-form-item>
</el-col>
@@ -332,10 +275,8 @@
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible=false">Cancel</el-button>
<!-- 取消 -->
<el-button type="primary" @click="handleSave" :loading="saveLoading">Save</el-button>
<!-- 保存 -->
<el-button @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="handleSave" :loading="saveLoading">保存</el-button>
</div>
</el-dialog>
</div>
@@ -355,7 +296,7 @@ export default {
tableLoading: false,
btnLoading: false,
dialogVisible: false,
dialogTitle: 'Add Steel Grade', // 新增钢种
dialogTitle: '新增钢种',
rightLoading: false,
formData: {
gradeid: null,
@@ -385,18 +326,16 @@ export default {
},
formRules: {
gradeid: [
{ required: true, message: 'Please enter steel grade ID', trigger: 'blur' }
// 请输入钢种ID
{ required: true, message: '请输入钢种ID', trigger: 'blur' }
],
name: [
{ required: true, message: 'Please enter steel grade name', trigger: 'blur' }
// 请输入钢种名称
{ required: true, message: '请输入钢种名称', trigger: 'blur' }
]
},
saveLoading: false,
currentRow: {},
isEdit: false,
selectedItem: null // Selected steel grade item / 选中的钢种项
selectedItem: null // 选中的钢种项
}
},
created() {
@@ -406,12 +345,12 @@ export default {
getSteelGradeList() {
this.tableLoading = true
getSteelGradeList().then(res => {
// Keep complete data, add delete loading state / 保留完整数据,添加删除加载状态
// 保留完整数据,添加删除加载状态
this.tableData = res.data.map(item => ({
...item,
deleteLoading: false
}))
// Frontend search filter (only for name) / 前端搜索过滤仅针对name
// 前端搜索过滤仅针对name
if (this.queryForm.name) {
this.tableData = this.tableData.filter(item =>
item.name && item.name.includes(this.queryForm.name)
@@ -419,7 +358,7 @@ export default {
}
}).catch(err => {
console.error(err)
this.$message.error('Failed to fetch data') // 获取数据失败
this.$message.error('获取数据失败')
}).finally(() => {
this.tableLoading = false
this.btnLoading = false
@@ -433,23 +372,23 @@ export default {
this.$refs.queryForm.resetFields();
this.getSteelGradeList()
},
// Card click event: load and display details / 卡片点击事件:加载详情并展示
// 卡片点击事件:加载详情并展示
handleCardClick(item) {
// Call detail API to get complete data / 调用详情接口获取完整数据
// 调用详情接口获取完整数据
this.rightLoading = true
getSteelGradeInfo(item.gradeid).then(res => {
this.selectedItem = { ...res.data }
this.rightLoading = false
}).catch(() => {
// Fallback: use list data / 降级处理:使用列表数据
// 降级处理:使用列表数据
this.selectedItem = { ...item }
this.rightLoading = false
})
},
handleAdd() {
this.dialogTitle = 'Add Steel Grade'; // 新增钢种
this.dialogTitle = '新增钢种';
this.isEdit = false;
// Reset form / 重置表单
// 重置表单
this.formData = {
gradeid: null,
name: '',
@@ -479,13 +418,13 @@ export default {
this.dialogVisible = true
},
handleEdit(row) {
this.dialogTitle = 'Edit Steel Grade'; // 编辑钢种
this.dialogTitle = '编辑钢种';
this.isEdit = true;
// Call detail API to get complete field data / 调用详情接口获取完整字段数据
// 调用详情接口获取完整字段数据
getSteelGradeInfo(row.gradeid).then(res => {
this.formData = { ...res.data }
}).catch(() => {
// Fallback / 降级处理
// 降级处理
this.formData = {
...this.formData,
...row
@@ -494,18 +433,17 @@ export default {
this.dialogVisible = true
},
handleDelete(row) {
this.$confirm(`Confirm to delete steel grade ${row.name}?`, 'Confirm Delete', { type: 'danger' }).then(() => {
// 确定删除钢种 ${row.name}?, 确认删除
this.$confirm(`确定要删除钢种【${row.name}】吗?`, '确认删除', { type: 'danger' }).then(() => {
row.deleteLoading = true
deleteSteelGrade(row.gradeid).then(res => {
if (res.code === 200) {
this.$message.success('Delete successful'); // 删除成功
this.$message.success('删除成功');
this.getSteelGradeList()
// If deleted item is currently selected, clear selection / 若删除的是当前选中项,清空选中状态
// 若删除的是当前选中项,清空选中状态
if (this.selectedItem?.gradeid === row.gradeid) {
this.selectedItem = null
}
} else this.$message.error(res.msg || 'Delete failed') // 删除失败
} else this.$message.error(res.msg || '删除失败')
}).finally(() => {
row.deleteLoading = false
})
@@ -519,10 +457,10 @@ export default {
const request = this.isEdit ? updateSteelGrade(this.formData) : addSteelGrade(this.formData)
request.then(res => {
if (res.code === 200) {
this.$message.success('Save successful'); // 保存成功
this.$message.success('保存成功');
this.dialogVisible = false;
this.getSteelGradeList()
} else this.$message.error(res.msg || 'Save failed') // 保存失败
} else this.$message.error(res.msg || '保存失败')
}).finally(() => {
this.saveLoading = false
})

View File

@@ -1,32 +1,26 @@
<template>
<div class="stoppage-management">
<!-- Query Form Area / 查询表单区域 -->
<!-- 查询表单区域 -->
<div class="stop-header">
<el-form :inline="true" :model="queryForm" ref="queryForm" label-width="80px" size="small">
<el-form-item label="Start Date" prop="startDate">
<!-- 开始时间 -->
<el-date-picker v-model="queryForm.startDate" type="date" placeholder="Select start date" value-format="yyyy-MM-dd"
<el-form-item label="开始日期" prop="startDate">
<el-date-picker v-model="queryForm.startDate" type="date" placeholder="选择开始日期" value-format="yyyy-MM-dd"
:clearable="true"></el-date-picker>
<!-- 选择开始时间 -->
</el-form-item>
<el-form-item label="End Date" prop="endDate">
<!-- 结束时间 -->
<el-date-picker v-model="queryForm.endDate" type="date" placeholder="Select end date" value-format="yyyy-MM-dd"
<el-form-item label="结束日期" prop="endDate">
<el-date-picker v-model="queryForm.endDate" type="date" placeholder="选择结束日期" value-format="yyyy-MM-dd"
:clearable="true"></el-date-picker>
<!-- 选择结束时间 -->
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery" :loading="btnLoading" icon="el-icon-search">Query</el-button>
<!-- 查询 -->
<el-button @click="handleReset" icon="el-icon-refresh">Reset</el-button>
<!-- 重置 -->
<el-button type="primary" @click="handleQuery" :loading="btnLoading" icon="el-icon-search">查询</el-button>
<el-button @click="handleReset" icon="el-icon-refresh">重置</el-button>
</el-form-item>
</el-form>
</div>
<!-- Card Grid Layout / 卡片网格布局 -->
<!-- 卡片网格布局 -->
<div v-loading="tableLoading" class="card-grid-container">
<el-row :gutter="10">
<el-col
@@ -47,88 +41,71 @@
@click.native="handleRowClick(item)"
>
<div slot="header" class="card-header">
<div class="card-title">Stop ID: {{ item.stopid || '-' }}</div>
<!-- 停机ID -->
<div class="card-subtitle">Coil ID: {{ item.coilid || '-' }}</div>
<!-- 钢卷号 -->
<div class="card-title">停机ID: {{ item.stopid || '-' }}</div>
<div class="card-subtitle">钢卷号: {{ item.coilid || '-' }}</div>
</div>
<div class="card-body">
<div class="param-groups-row">
<!-- Basic Info / 基本信息 -->
<!-- 基本信息 -->
<div class="param-group">
<div class="group-title">Basic Info</div>
<!-- 基本信息 -->
<div class="group-title">基本信息</div>
<div class="param-list">
<div class="param-line">
<span class="param-label">Stop Type:</span>
<!-- 停机类型 -->
<span class="param-label">停机类型:</span>
<span class="param-value">{{ item.stopType || '-' }}</span>
</div>
<div class="param-line">
<span class="param-label">Shift:</span>
<!-- -->
<span class="param-label">班次:</span>
<span class="param-value">{{ item.shift || '-' }}</span>
</div>
<div class="param-line">
<span class="param-label">Crew:</span>
<!-- -->
<span class="param-label">班组:</span>
<span class="param-value">{{ item.crew || '-' }}</span>
</div>
<div class="param-line">
<span class="param-label">Area:</span>
<!-- 区域 -->
<span class="param-label">区域:</span>
<span class="param-value">{{ item.area || '-' }}</span>
</div>
</div>
</div>
<!-- Device Info / 设备信息 -->
<!-- 设备信息 -->
<div class="param-group">
<div class="group-title">Device Info</div>
<!-- 设备信息 -->
<div class="group-title">设备信息</div>
<div class="param-list">
<div class="param-line">
<span class="param-label">Device:</span>
<!-- 设备 -->
<span class="param-label">设备:</span>
<span class="param-value">{{ item.seton || '-' }}</span>
</div>
<div class="param-line">
<span class="param-label">Unit:</span>
<!-- 机组 -->
<span class="param-label">机组:</span>
<span class="param-value">{{ item.unit || '-' }}</span>
</div>
<div class="param-line">
<span class="param-label">Duration:</span>
<!-- 停机时长 -->
<span class="param-value">{{ item.duration || '-' }} min</span>
<!-- 分钟 -->
<span class="param-label">停机时长:</span>
<span class="param-value">{{ item.duration || '-' }} 分钟</span>
</div>
<div class="param-line">
<span class="param-label">Update Time:</span>
<!-- 更新时间 -->
<span class="param-label">更新时间:</span>
<span class="param-value">{{ formatTime(item.insdate) }}</span>
</div>
</div>
</div>
<!-- Time Info / 时间信息 -->
<!-- 时间信息 -->
<div class="param-group">
<div class="group-title">Time Info</div>
<!-- 时间信息 -->
<div class="group-title">时间信息</div>
<div class="param-list">
<div class="param-line">
<span class="param-label">Start Time:</span>
<!-- 开始时间 -->
<span class="param-label">开始时间:</span>
<span class="param-value">{{ formatTime(item.startDate) }}</span>
</div>
<div class="param-line">
<span class="param-label">End Time:</span>
<!-- 结束时间 -->
<span class="param-label">结束时间:</span>
<span class="param-value">{{ formatTime(item.endDate) }}</span>
</div>
<div class="param-line full-width" v-if="item.remark">
<span class="param-label">Stop Reason:</span>
<!-- 停机原因 -->
<span class="param-label">停机原因:</span>
<span class="param-value">{{ item.remark }}</span>
</div>
</div>
@@ -141,117 +118,84 @@
type="primary"
icon="el-icon-edit"
@click.stop="handleEdit(item)"
>Edit</el-button>
<!-- 编辑 -->
>编辑</el-button>
<el-button
size="mini"
type="danger"
icon="el-icon-delete"
:loading="item.deleteLoading"
@click.stop="handleDelete(item)"
>Delete</el-button>
<!-- 删除 -->
>删除</el-button>
</div>
</el-card>
</el-col>
</el-row>
<div v-if="tableData.length === 0 && !tableLoading" class="empty-data">
<el-empty description="No data"></el-empty>
<!-- 暂无数据 -->
<el-empty description="暂无数据"></el-empty>
</div>
</div>
<!-- Edit/Add Dialog / 编辑/新增弹窗 -->
<!-- 编辑/新增弹窗 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="60%" :close-on-click-modal="false">
<el-form :model="formData" ref="formData" label-width="120px" :rules="formRules">
<el-form-item label="Stop ID" prop="stopid" v-if="formData.stopid">
<!-- 停机ID -->
<el-form-item label="停机ID" prop="stopid" v-if="formData.stopid">
<el-input v-model="formData.stopid" disabled></el-input>
</el-form-item>
<el-form-item label="Coil ID" prop="coilid">
<!-- 钢卷号 -->
<el-input v-model="formData.coilid" placeholder="Please enter Coil ID"></el-input>
<!-- 请输入钢卷号 -->
<el-form-item label="钢卷号" prop="coilid">
<el-input v-model="formData.coilid" placeholder="请输入钢卷号"></el-input>
</el-form-item>
<el-form-item label="Shift" prop="shift">
<!-- -->
<el-select v-model="formData.shift" placeholder="Please select shift" clearable>
<!-- 请选择班次 -->
<el-option label="Morning Shift" value="班"></el-option>
<!-- 早班 -->
<el-option label="Afternoon Shift" value="中班"></el-option>
<!-- 中班 -->
<el-option label="Night Shift" value="晚班"></el-option>
<!-- 晚班 -->
<el-form-item label="班次" prop="shift">
<el-select v-model="formData.shift" placeholder="请选择班次" clearable>
<el-option label="早班" value="早班"></el-option>
<el-option label="中班" value="中班"></el-option>
<el-option label="晚班" value="班"></el-option>
</el-select>
</el-form-item>
<el-form-item label="Crew" prop="crew">
<!-- -->
<el-input v-model="formData.crew" placeholder="Please enter crew number"></el-input>
<!-- 请输入组号 -->
<el-form-item label="班组" prop="crew">
<el-input v-model="formData.crew" placeholder="请输入班组号"></el-input>
</el-form-item>
<el-form-item label="Area" prop="area">
<!-- 区域 -->
<el-input v-model="formData.area" placeholder="Please enter area"></el-input>
<!-- 请输入区域 -->
<el-form-item label="区域" prop="area">
<el-input v-model="formData.area" placeholder="请输入区域"></el-input>
</el-form-item>
<el-form-item label="Unit" prop="unit">
<!-- 机组 -->
<el-input v-model="formData.unit" placeholder="Please enter unit"></el-input>
<!-- 请输入机组 -->
<el-form-item label="机组" prop="unit">
<el-input v-model="formData.unit" placeholder="请输入机组"></el-input>
</el-form-item>
<el-form-item label="Device" prop="seton">
<!-- 设备 -->
<el-input v-model="formData.seton" placeholder="Please enter device"></el-input>
<!-- 请输入设备 -->
<el-form-item label="设备" prop="seton">
<el-input v-model="formData.seton" placeholder="请输入设备"></el-input>
</el-form-item>
<el-form-item label="Start Time" prop="startDate">
<!-- 开始时间 -->
<el-date-picker v-model="formData.startDate" type="datetime" placeholder="Select start time"
<el-form-item label="开始时间" prop="startDate">
<el-date-picker v-model="formData.startDate" type="datetime" placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss"></el-date-picker>
<!-- 选择开始时间 -->
</el-form-item>
<el-form-item label="End Time" prop="endDate">
<!-- 结束时间 -->
<el-date-picker v-model="formData.endDate" type="datetime" placeholder="Select end time"
<el-form-item label="结束时间" prop="endDate">
<el-date-picker v-model="formData.endDate" type="datetime" placeholder="选择结束时间"
value-format="yyyy-MM-dd HH:mm:ss"></el-date-picker>
<!-- 选择结束时间 -->
</el-form-item>
<el-form-item label="Stop Type" prop="stopType">
<!-- 停机类型 -->
<el-select v-model="formData.stopType" placeholder="Please select stop type" clearable>
<!-- 请选择停机类型 -->
<el-option label="Planned Stop" value="计划停机"></el-option>
<!-- 计划停机 -->
<el-option label="Fault Stop" value="故障停机"></el-option>
<!-- 故障停机 -->
<el-option label="Maintenance Stop" value="维护停机"></el-option>
<!-- 维护停机 -->
<el-option label="Other" value="其他"></el-option>
<!-- 其他 -->
<el-form-item label="停机类型" prop="stopType">
<el-select v-model="formData.stopType" placeholder="请选择停机类型" clearable>
<el-option label="计划停机" value="计划停机"></el-option>
<el-option label="故障停机" value="故障停机"></el-option>
<el-option label="维护停机" value="维护停机"></el-option>
<el-option label="其他" value="其他"></el-option>
</el-select>
</el-form-item>
<el-form-item label="Stop Reason" prop="remark">
<!-- 停机原因 -->
<el-input v-model="formData.remark" placeholder="Please enter stop reason" type="textarea" rows="4"></el-input>
<!-- 请输入停机原因 -->
<el-form-item label="停机原因" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入停机原因" type="textarea" rows="4"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">Cancel</el-button>
<!-- 取消 -->
<el-button type="primary" @click="handleSave" :loading="saveLoading">Save</el-button>
<!-- 保存 -->
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave" :loading="saveLoading">保存</el-button>
</div>
</el-dialog>
</div>
@@ -264,21 +208,20 @@ export default {
name: 'StoppageManagement',
data() {
return {
// Query form data / 查询表单数据
// 查询表单数据
queryForm: {
// Only keep YYYY-MM-dd format / 只保留年月日YYYY-mm-dd
// 只保留年月日YYYY-mm-dd格式
startDate: '2023-08-13',
endDate: '2025-08-20'
},
// Table data / 表格数据
// 表格数据
tableData: [],
// Loading state / 加载状态
// 加载状态
tableLoading: false,
btnLoading: false,
// Dialog state / 弹窗状态
// 弹窗状态
dialogVisible: false,
dialogTitle: 'Add Stoppage Record',
// 新增停机记录
dialogTitle: '新增停机记录',
// 表单数据
formData: {
stopid: '',
@@ -295,33 +238,30 @@ export default {
stopType: '',
remark: ''
},
// Form validation rules / 表单验证规则
// 表单验证规则
formRules: {
startDate: [
{ required: true, message: 'Please select start time', trigger: 'blur' }
// 请选择开始时间
{ required: true, message: '请选择开始时间', trigger: 'blur' }
],
endDate: [
{ required: true, message: 'Please select end time', trigger: 'blur' }
// 请选择结束时间
{ required: true, message: '请选择结束时间', trigger: 'blur' }
],
seton: [
{ required: true, message: 'Please enter device', trigger: 'blur' }
// 请输入设备
{ required: true, message: '请输入设备', trigger: 'blur' }
]
},
// Save button loading state / 保存按钮加载状态
// 保存按钮加载状态
saveLoading: false,
// Current row data / 当前操作的行数据
// 当前操作的行数据
currentRow: {}
};
},
created() {
// Query once on page load / 页面加载时默认查询一次
// 页面加载时默认查询一次
this.getStoppageList();
},
methods: {
// Get stoppage record list / 获取停机记录列表
// 获取停机记录列表
getStoppageList() {
this.tableLoading = true;
listStoppage(this.queryForm)
@@ -336,17 +276,17 @@ export default {
.catch(error => {
this.tableLoading = false;
this.btnLoading = false;
console.error('Failed to fetch data:', error); // 获取数据失败
this.$message.error('Failed to fetch data, please retry'); // 获取数据失败,请稍后重试
console.error('获取数据失败:', error);
this.$message.error('获取数据失败,请稍后重试');
});
},
// Handle query / 处理查询
// 处理查询
handleQuery() {
// Validate start time cannot be later than end time / 验证开始时间不能晚于结束时间
// 验证开始时间不能晚于结束时间
if (this.queryForm.startDate && this.queryForm.endDate &&
new Date(this.queryForm.startDate) > new Date(this.queryForm.endDate)) {
this.$message.warning('Start time cannot be later than end time'); // 开始时间不能晚于结束时间
this.$message.warning('开始时间不能晚于结束时间');
return;
}
@@ -354,30 +294,30 @@ export default {
this.getStoppageList();
},
// Handle reset / 处理重置
// 处理重置
handleReset() {
this.$refs.queryForm.resetFields();
this.getStoppageList();
},
// Row click event / 行点击事件
// 行点击事件
handleRowClick(row) {
this.currentRow = row;
},
// Format time / 格式化时间
// 格式化时间
formatTime(time) {
if (!time) return '-';
// If it's datetime format, return directly / 如果是日期时间格式,直接返回
// 如果是日期时间格式,直接返回
if (time.includes(' ')) {
return time;
}
// If it's date format, return date / 如果是日期格式,返回日期
// 如果是日期格式,返回日期
return time;
},
// Add / 新增
// 新增
handleAdd() {
this.dialogTitle = 'Add Stoppage Record'; // 新增停机记录
this.dialogTitle = '新增停机记录';
this.formData = {
stopid: '',
coilid: '',
@@ -396,22 +336,21 @@ export default {
this.dialogVisible = true;
},
// Edit / 编辑
// 编辑
handleEdit(row) {
this.dialogTitle = 'Edit Stoppage Record'; // 编辑停机记录
this.dialogTitle = '编辑停机记录';
this.formData = { ...row };
this.dialogVisible = true;
},
// Delete / 删除
// 删除
handleDelete(row) {
this.$confirm(`Confirm to delete stoppage record with ID ${row.stopid}?`, 'Confirm Delete', {
// 确定要删除ID为 ${row.stopid} 的停机记录吗?, 确认删除
confirmButtonText: 'Confirm', // 确定
cancelButtonText: 'Cancel', // 取消
this.$confirm(`确定要删除ID ${row.stopid} 的停机记录吗?`, '确认删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'danger'
}).then(() => {
// Set current row delete button to loading state / 设置当前行的删除按钮为加载状态
// 设置当前行的删除按钮为加载状态
row.deleteLoading = true;
deleteStoppage(row.stopid)
@@ -419,63 +358,63 @@ export default {
row.deleteLoading = false;
if (response.code === 200) {
this.$message.success('Delete successful'); // 删除成功
// Re-query data / 重新查询数据
this.$message.success('删除成功');
// 重新查询数据
this.getStoppageList();
} else {
this.$message.error(response.msg || 'Delete failed'); // 删除失败
this.$message.error(response.msg || '删除失败');
}
})
.catch(error => {
row.deleteLoading = false;
console.error('Delete failed:', error); // 删除失败
this.$message.error('Delete failed, please retry'); // 删除失败,请稍后重试
console.error('删除失败:', error);
this.$message.error('删除失败,请稍后重试');
});
}).catch(() => {
// User cancelled delete / 用户取消删除
this.$message.info('Delete cancelled'); // 已取消删除
// 用户取消删除
this.$message.info('已取消删除');
});
},
// Save / 保存
// 保存
handleSave() {
this.$refs.formData.validate(valid => {
if (valid) {
// Validate start time cannot be later than end time / 验证开始时间不能晚于结束时间
// 验证开始时间不能晚于结束时间
if (new Date(this.formData.startDate) > new Date(this.formData.endDate)) {
this.$message.warning('Start time cannot be later than end time'); // 开始时间不能晚于结束时间
this.$message.warning('开始时间不能晚于结束时间');
return;
}
// Calculate stoppage duration (minutes) / 计算停机时长(分钟)
// 计算停机时长(分钟)
const start = new Date(this.formData.startDate).getTime();
const end = new Date(this.formData.endDate).getTime();
this.formData.duration = Math.round((end - start) / (1000 * 60) * 10) / 10;
// Set current time as update time / 设置当前时间为更新时间
// 设置当前时间为更新时间
const now = new Date();
this.formData.insdate = now.toISOString().slice(0, 19).replace('T', ' ');
this.saveLoading = true;
// Call update API / 调用更新接口
// 调用更新接口
updateStoppage(this.formData)
.then(response => {
this.saveLoading = false;
if (response.code === 200) {
this.$message.success('Save successful'); // 保存成功
this.$message.success('保存成功');
this.dialogVisible = false;
// Re-query data / 重新查询数据
// 重新查询数据
this.getStoppageList();
} else {
this.$message.error(response.msg || 'Save failed'); // 保存失败
this.$message.error(response.msg || '保存失败');
}
})
.catch(error => {
this.saveLoading = false;
console.error('Save failed:', error); // 保存失败
this.$message.error('Save failed, please retry'); // 保存失败,请稍后重试
console.error('保存失败:', error);
this.$message.error('保存失败,请稍后重试');
});
}
});
@@ -664,4 +603,4 @@ export default {
::v-deep .el-form-item {
margin-bottom: 15px;
}
</style>
</style>

View File

@@ -26,7 +26,7 @@
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<!-- <el-col :span="1.5"> -->
<el-button
type="primary"
plain
@@ -35,7 +35,7 @@
@click="handleAdd"
v-hasPermi="['system:menu:add']"
>新增</el-button>
</el-col>
<!-- </el-col> -->
<el-col :span="1.5">
<el-button
type="info"