+
+
+
+
+ Production Plan
+
+
+
+
+
+
+
+
{{ index + 1 }}
+
+
Plan ID: {{ plan.planid || '-' }}
+
+
Coil ID: {{ plan.coilid || '-' }}
+
+
+
{{ getPlanStatusText(plan.status) }}
+
+
+ Steel Grade: {{ plan.steelGrade || '-' }}
+
+ Sequence: {{ plan.seqid || '-' }}
+
+
-
-
- {{ selectedPlan.planid || '-' }}
-
- {{ selectedPlan.coilid || '-' }}
-
- {{ selectedPlan.seqid || '-' }}
-
-
-
-
- {{ getPlanStatusText(selectedPlan.status) }}
-
-
- {{ selectedPlan.steelGrade || '-' }}
-
-
-
- {{ selectedPlan.entryThick ? selectedPlan.entryThick + ' mm' : '-' }}
-
-
-
- {{ selectedPlan.entryWidth ? selectedPlan.entryWidth + ' mm' : '-' }}
-
-
-
- {{ selectedPlan.entryWeight ? selectedPlan.entryWeight + ' t' : '-' }}
-
-
-
- {{ selectedPlan.entryLength ? selectedPlan.entryLength + ' mm' : '-' }}
-
- {{ selectedPlan.orderNo || '-' }}
-
- {{ selectedPlan.unitCode || '-' }}
-
- {{ selectedPlan.planType || '-' }}
-
-
-
-
-
+
+
+
+
+ Plan Detail
+
+
+
+
+
+
+
+
+
+
+
Current Position
+
+
{{ selectedPlanPosition.positionNameCn }}
+
{{ selectedPlanPosition.positionNameEn }}
+
+
+
-
-
- {{ formatDateTime(selectedPlan.onlineDate) }}
+ {{ selectedPlan.planid || '-' }}
+
+ {{ selectedPlan.coilid || '-' }}
+
+ {{ selectedPlan.seqid || '-' }}
+
+
+
+
+ {{ getPlanStatusText(selectedPlan.status) }}
+
-
-
- {{ formatDateTime(selectedPlan.startDate) }}
+ {{ selectedPlan.steelGrade || '-' }}
+
+
+
+ {{ selectedPlan.entryThick ? selectedPlan.entryThick + ' mm' : '-' }}
-
-
- {{ formatDateTime(selectedPlan.endDate) }}
+
+
+ {{ selectedPlan.entryWidth ? selectedPlan.entryWidth + ' mm' : '-' }}
+
+
+ {{ selectedPlan.entryWeight ? selectedPlan.entryWeight + ' t' : '-' }}
+
+
+
+ {{ selectedPlan.entryLength ? selectedPlan.entryLength + ' mm' : '-' }}
+
+ {{ selectedPlan.orderNo || '-' }}
+
+ {{ selectedPlan.unitCode || '-' }}
+
+ {{ selectedPlan.planType || '-' }}
+
-
-
-
-
-
-
-
- Recent Operation
-
-
- {{ getOperationConfig(signalData.operation).icon }} {{ getOperationText(signalData.operation) }}
-
-
-
-
- {{ signalData.autoFlag === 1 ? 'Manual' : 'Auto' }}
-
-
-
-
Operation Type:
-
-
- {{ getOperationText(signalData.operation) }}
-
-
-
Coil ID: {{ producingCoilId || signalData.entryMatId || '-' }}
-
-
Plan ID: {{ signalData.planId || '-' }}
-
-
- Pay-off Reel: {{ signalData.porIdx }}
-
-
-
- Take-up Reel: {{ signalData.trIdx }}
-
-
-
-
Virtual Coil
-
+
+
+
+
Time Information
+
+
+
+
+ {{ formatDateTime(selectedPlan.onlineDate) }}
+
+
+
+ {{ formatDateTime(selectedPlan.startDate) }}
+
+
+
+ {{ formatDateTime(selectedPlan.endDate) }}
+
+
-
-
-
-
Operations
-
-
-
Coil Online
-
-
Manual Unload
-
-
Full Return
-
-
Half Return
-
-
Unload & Block
-
+
+
+
+
+ Recent Operation
+
+
+ {{ getOperationConfig(signalData.operation).icon }} {{ getOperationText(signalData.operation) }}
+
+
+
+
+ {{ signalData.autoFlag === 1 ? 'Manual' : 'Auto' }}
+
+
+
+
Operation Type:
+
+
+ {{ getOperationText(signalData.operation) }}
+
+
+
Coil ID: {{ producingCoilId || signalData.entryMatId || '-' }}
+
+
Plan ID: {{ signalData.planId || '-' }}
+
+
+ Pay-off Reel: {{ signalData.porIdx }}
+
+
+
+ Take-up Reel: {{ signalData.trIdx }}
+
+
+
+ Virtual Coil
+
+
+
+
+
+
+
+
Operations
+
+
+ Coil Online
+
+ Manual Unload
+
+ Full Return
+
+ Half Return
+
+ Unload & Block
+
+
+
+
+
+
Basic Info
+
+
+
+ | Position Name |
+
+ {{ selectedCard.positionNameCn || '-' }} |
+
+
+ | Position Code |
+
+ {{ selectedCard.positionNameEn || '-' }} |
+
+
+ | Coil ID |
+
+ {{ selectedCard.matId || '-' }} |
+
+
+ | Plan ID |
+
+ {{ selectedCard.planId || '-' }} |
+
+
+ | Plan No |
+
+ {{ selectedCard.planNo || '-' }} |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Confirm Adjustment
+
-
-
-
Basic Info
-
-
-
- | Position Name |
-
- {{ selectedCard.positionNameCn || '-' }} |
-
-
- | Position Code |
-
- {{ selectedCard.positionNameEn || '-' }} |
-
-
- | Coil ID |
-
- {{ selectedCard.matId || '-' }} |
-
-
- | Plan ID |
-
- {{ selectedCard.planId || '-' }} |
-
-
- | Plan No |
-
- {{ selectedCard.planNo || '-' }} |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Confirm Adjustment
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- No calculation result data
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No calculation result data
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+ .plan-order.order-ready {
+ background: #409eff;
+ }
+
+ .plan-order.order-new {
+ background: #909399;
+ }
+
+ /* 绿色点闪烁动画 */
+ @keyframes blink-green-dot {
+ 0%, 100% {
+ background: #67c23a;
+ box-shadow: 0 0 5px rgba(103, 194, 58, 0.5);
+ }
+ 50% {
+ background: #85ce61;
+ box-shadow: 0 0 10px rgba(103, 194, 58, 0.8);
+ }
+ }
+
+ .plan-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ }
+
+ .plan-row {
+ display: flex;
+ align-items: center;
+ font-size: 13px;
+ }
+
+ .plan-label {
+ color: #909399;
+ min-width: 60px;
+ flex-shrink: 0;
+ }
+
+ .plan-value {
+ color: #303133;
+ font-weight: 500;
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .plan-status {
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ /* WebSocket 状态栏 */
+ .ws-status-bar {
+ display: flex;
+ gap: 15px;
+ padding: 10px;
+ background: #f5f7fa;
+ border-radius: 4px;
+ margin-bottom: 10px;
+ align-items: center;
+ }
+
+ .ws-status-bar i {
+ font-size: 18px;
+ color: #606266;
+ cursor: pointer;
+ }
+
+ /* 分区头部增强 */
+ .section-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .section-info {
+ font-size: 13px;
+ color: #67c23a;
+ font-weight: 500;
+ }
+
+ /* 信号信息面板 */
+ .signal-info {
+ padding: 10px 0;
+ }
+
+ .signal-info.signal-warning {
+ background: #fef0f0;
+ padding: 15px;
+ border-radius: 4px;
+ border: 1px solid #fde2e2;
+ }
+
+ .signal-info.signal-success {
+ background: #f0f9ff;
+ padding: 15px;
+ border-radius: 4px;
+ border: 1px solid #c6e2ff;
+ }
+
+ .signal-info.signal-complete {
+ background: #f0f9ff;
+ padding: 15px;
+ border-radius: 4px;
+ border: 1px solid #b3e19d;
+ }
+
+ .signal-detail {
+ margin-top: 10px;
+ font-size: 13px;
+ line-height: 2;
+ }
+
+ .signal-detail div {
+ padding: 4px 0;
+ }
+
+ .text-warning {
+ color: #e6a23c;
+ font-weight: 600;
+ font-size: 14px;
+ }
+
+ .text-success {
+ color: #67c23a;
+ font-weight: 600;
+ font-size: 14px;
+ }
+
+ /* 计算结果头部 */
+ .calc-result-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+ padding-bottom: 10px;
+ border-bottom: 1px solid #ebeef5;
+ font-size: 14px;
+ }
+
+ /* 生产计划详情 */
+ .plan-detail-content {
+ overflow-y: auto;
+ }
+
+ /* 位置信息提示卡片 */
+ .position-alert {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 15px;
+ margin-bottom: 15px;
+ background: #f0f9ff;
+ border: 1px solid #b3d8ff;
+ border-left: 4px solid #409eff;
+ border-radius: 4px;
+ }
+
+ .position-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ background: #409eff;
+ border-radius: 50%;
+ color: #fff;
+ font-size: 20px;
+ flex-shrink: 0;
+ }
+
+ .position-info {
+ flex: 1;
+ }
+
+ .position-label {
+ font-size: 12px;
+ color: #909399;
+ margin-bottom: 4px;
+ }
+
+ .position-name {
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ margin-bottom: 2px;
+ }
+
+ .position-code {
+ font-size: 12px;
+ color: #606266;
+ font-family: 'Courier New', monospace;
+ }
+
+ .plan-time-info {
+ margin-top: 15px;
+ padding-top: 15px;
+ border-top: 1px solid #ebeef5;
+ }
+
+ .info-subtitle {
+ font-size: 13px;
+ font-weight: 600;
+ color: #606266;
+ margin-bottom: 10px;
+ }
+
+ .panel-title {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .panel-title i {
+ margin-right: 5px;
+ }
+
+
\ No newline at end of file
From 83e335cf6ae1f185d11084e153b37e8b548904c9 Mon Sep 17 00:00:00 2001
From: 86156 <823267011@qq.com>
Date: Fri, 2 Jan 2026 14:30:52 +0800
Subject: [PATCH 5/7] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BC=A0=E5=8A=A8?=
=?UTF-8?q?=E3=80=81=E7=82=89=E7=81=AB=E5=86=99=E5=85=A5=E9=A1=B5=E9=9D=A2?=
=?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BF=AE=E6=94=B9=E5=BC=80=E5=85=B3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/l2/send/drive.vue | 2 +-
src/views/l2/send/furnace.vue | 26 +++++++++-----------------
2 files changed, 10 insertions(+), 18 deletions(-)
diff --git a/src/views/l2/send/drive.vue b/src/views/l2/send/drive.vue
index 501081f..f84a8ad 100644
--- a/src/views/l2/send/drive.vue
+++ b/src/views/l2/send/drive.vue
@@ -166,7 +166,7 @@ export default {
this.lastSuccess = lastRes && lastRes.code === 200 ? lastRes.data : null
// plans / 获取计划
- const planRes = await listPlan({ status: 'NEW,READY' })
+ const planRes = await listPlan({ status: 'NEW,READY,ONLINE,PRODUCING' })
const planList = planRes.rows || []
const tasks = planList.map(async (p) => {
diff --git a/src/views/l2/send/furnace.vue b/src/views/l2/send/furnace.vue
index 470547c..98d6632 100644
--- a/src/views/l2/send/furnace.vue
+++ b/src/views/l2/send/furnace.vue
@@ -121,30 +121,22 @@ export default {
}
},
created() {
+ // 不 await:避免阻塞页面渲染;异常会在 Promise 链上抛出到控制台/全局拦截
this.reload()
},
methods: {
async reload() {
this.loading = true
- try {
- const [templateRes, lastRes] = await Promise.all([
- getSendTemplate('FURNACE_DEFAULT'),
- getLastSuccess('FURNACE')
- ])
+ const [templateRes, lastRes] = await Promise.all([
+ getSendTemplate('FURNACE_DEFAULT'),
+ getLastSuccess('FURNACE')
+ ])
- this.template = templateRes && templateRes.code === 200 ? templateRes.data : null
- this.lastSuccess = lastRes && lastRes.code === 200 ? lastRes.data : null
+ this.template = templateRes && templateRes.code === 200 ? templateRes.data : null
+ this.lastSuccess = lastRes && lastRes.code === 200 ? lastRes.data : null
- this.initializeForm()
- } catch (e) {
- console.error(e)
- this.$message.error('Load data failed')
- this.template = null
- this.lastSuccess = null
- this.form = {}
- } finally {
- this.loading = false
- }
+ this.initializeForm()
+ this.loading = false
},
initializeForm() {
From fd890611c87ac3aac406615f340c7b8b8531946b Mon Sep 17 00:00:00 2001
From: 86156 <823267011@qq.com>
Date: Fri, 2 Jan 2026 16:00:10 +0800
Subject: [PATCH 6/7] =?UTF-8?q?=E5=86=99=E5=85=A5=E5=8A=9F=E8=83=BD?=
=?UTF-8?q?=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/l2/sendTemplate.js | 9 +
.../send/components/FurnaceHistoryPanel.vue | 138 ++++++++
src/views/l2/send/drive.vue | 116 ++++--
src/views/l2/send/furnace.vue | 331 +++++++++++++++---
.../l2/track/components/LatestSetValues.vue | 4 +-
src/views/l2/track/rect.vue | 2 +-
6 files changed, 523 insertions(+), 77 deletions(-)
create mode 100644 src/views/l2/send/components/FurnaceHistoryPanel.vue
diff --git a/src/api/l2/sendTemplate.js b/src/api/l2/sendTemplate.js
index d34bc82..b152e4d 100644
--- a/src/api/l2/sendTemplate.js
+++ b/src/api/l2/sendTemplate.js
@@ -34,3 +34,12 @@ export function updateSendTemplateItems(data) {
data
})
}
+
+// 批量保存模板明细(新增/更新/删除)- 仅提交变更,避免请求体过大
+export function batchSaveSendTemplateItems(data) {
+ return request({
+ url: '/business/sendTemplate/items/batchSave',
+ method: 'put',
+ data
+ })
+}
diff --git a/src/views/l2/send/components/FurnaceHistoryPanel.vue b/src/views/l2/send/components/FurnaceHistoryPanel.vue
new file mode 100644
index 0000000..0ca3075
--- /dev/null
+++ b/src/views/l2/send/components/FurnaceHistoryPanel.vue
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+ Reset
+
+
+
+
+
+
+
+
+
+
+
+ Apply
+ Detail
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/l2/send/drive.vue b/src/views/l2/send/drive.vue
index f84a8ad..038f454 100644
--- a/src/views/l2/send/drive.vue
+++ b/src/views/l2/send/drive.vue
@@ -52,7 +52,7 @@
-
+
+
+
+
@@ -90,34 +98,52 @@ import { getLastSuccess } from '@/api/l2/sendTemplate'
// Drive fields definition (English UI, Chinese comments) / 传动字段定义(英文界面,中文注释)
// 说明:key 必须与 setupForm 字段一致(来自 plan/components/setupForm.vue)
+// Drive + Plan fields definition (show effect first; OPC address can be edited later)
+// 传动 + 计划字段定义(先把效果做出来;OPC点位后续可协商配置)
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' },
+ // ---- Drive tension / 传动张力 ----
+ { key: 'porTension', label: 'Pay-off Reel Tension', source: 'setup' },
+ { key: 'celTension', label: 'Entry Loop Tension', source: 'setup' },
+ { key: 'cleanTension', label: 'Cleaning Section Tension', source: 'setup' },
+ { key: 'furTension', label: 'Furnace Zone Tension', source: 'setup' },
+ { key: 'towerTension', label: 'Cooling Tower Tension', source: 'setup' },
+ { key: 'tmNoneTension', label: 'TM No Tension', source: 'setup' },
+ { key: 'tmEntryTension', label: 'TM Entry Tension', source: 'setup' },
+ { key: 'tmExitTension', label: 'TM Exit Tension', source: 'setup' },
+ { key: 'tlNoneTension', label: 'TL No Tension', source: 'setup' },
+ { key: 'tlExitTension', label: 'TL Exit Tension', source: 'setup' },
+ { key: 'coatTension', label: 'Post-treatment Tension', source: 'setup' },
+ { key: 'cxlTension', label: 'Exit Loop Tension', source: 'setup' },
+ { key: 'trTension', label: 'Take-up Reel Tension', source: 'setup' },
- { 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' },
+ // ---- TL / TM setup ----
+ { key: 'tlElong', label: 'TL Elongation', source: 'setup' },
+ { key: 'tlLvlMesh1', label: 'TL Leveling Roll Mesh 1', source: 'setup' },
+ { key: 'tlLvlMesh2', label: 'TL Leveling Roll Mesh 2', source: 'setup' },
+ { key: 'tlAcbMesh', label: 'TL Anti-crossbow Mesh', source: 'setup' },
- { 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: 'TM Bending Force', source: 'setup' },
+ { key: 'tmAcrMesh', label: 'TM Anti-crimping Roll Mesh', source: 'setup' },
+ { key: 'tmBrMesh', label: 'TM Anti-tremor Roll Mesh', source: 'setup' },
+ { key: 'tmRollforce', label: 'TM Roll Force', source: 'setup' },
+
+ // ---- Plan (from listPlan response) / 计划参数(来自 listPlan 返回)----
+ { key: 'entryWidth', label: 'Entry Width', source: 'plan' },
+ { key: 'entryThick', label: 'Entry Thick', source: 'plan' },
+ { key: 'entryWeight', label: 'Entry Weight', source: 'plan' },
+ { key: 'entryLength', label: 'Entry Length', source: 'plan' },
+
+ { key: 'steelGrade', label: 'Steel Grade', source: 'plan' },
+
+ { key: 'spmElongation', label: 'SPM Elongation', source: 'plan' },
+ { key: 'spmRollforce', label: 'SPM Roll Force', source: 'plan' },
+ { key: 'spmBendingForce', label: 'SPM Bending Force', source: 'plan' },
+
+ { key: 'yieldPoint', label: 'Yield Point', source: 'plan' }
]
-// OPC address mapping (must align with back-end OpcMessageIdsManager.pdiSetupIds) / OPC点位映射(需与后端一致)
-// 中文注释:这里用“字段名->OPC地址”的方式直接组装发送items
+// OPC address mapping / OPC点位映射
+// 说明:此处后续可协商配置;当前允许在页面上编辑(默认可为空)
const DRIVE_ADDRESS = {
porTension: 'ns=2;s=ProcessCGL.PLCLine.L2Setup.tensionPorBR1',
celTension: 'ns=2;s=ProcessCGL.PLCLine.L2Setup.tensionBR3',
@@ -151,7 +177,9 @@ export default {
loading: false,
lastSuccess: null,
plans: [],
- driveFields: DRIVE_FIELDS
+ driveFields: DRIVE_FIELDS,
+ // 可编辑的 OPC 点位(默认从常量拷贝;你也可以后续改成从后端/本地存储加载)
+ driveAddress: { ...DRIVE_ADDRESS }
}
},
created() {
@@ -167,7 +195,8 @@ export default {
// plans / 获取计划
const planRes = await listPlan({ status: 'NEW,READY,ONLINE,PRODUCING' })
- const planList = planRes.rows || []
+ // 兼容后端返回结构:既可能是 {rows: []} 也可能是 {data: []}
+ const planList = (planRes && (planRes.rows || planRes.data)) || []
const tasks = planList.map(async (p) => {
let setup = {}
@@ -180,14 +209,27 @@ export default {
const params = {}
this.driveFields.forEach(f => {
- const fromSetup = setup[f.key]
+ const fromPlan = p ? p[f.key] : undefined
+ const fromSetup = setup ? setup[f.key] : undefined
const fromLast = this.lastSuccess?.values?.[f.key]
- if (fromSetup !== undefined && fromSetup !== null && String(fromSetup) !== '') {
- params[f.key] = String(fromSetup)
- } else if (fromLast !== undefined && fromLast !== null) {
- params[f.key] = String(fromLast)
+
+ // 优先级:setup(如果字段来自setup) / plan(如果字段来自plan) -> lastSuccess -> ''
+ if (f.source === 'plan') {
+ if (fromPlan !== undefined && fromPlan !== null && String(fromPlan) !== '') {
+ params[f.key] = String(fromPlan)
+ } else if (fromLast !== undefined && fromLast !== null) {
+ params[f.key] = String(fromLast)
+ } else {
+ params[f.key] = ''
+ }
} else {
- params[f.key] = ''
+ if (fromSetup !== undefined && fromSetup !== null && String(fromSetup) !== '') {
+ params[f.key] = String(fromSetup)
+ } else if (fromLast !== undefined && fromLast !== null) {
+ params[f.key] = String(fromLast)
+ } else {
+ params[f.key] = ''
+ }
}
})
@@ -252,18 +294,24 @@ export default {
try {
const items = this.driveFields.map(f => ({
paramCode: f.key,
- address: DRIVE_ADDRESS[f.key],
+ // OPC点位允许为空:为空则本次不发送该字段(先做效果,后续再配置)
+ address: this.driveAddress[f.key],
valueRaw: String(plan.params[f.key] || ''),
setTime: new Date()
})).filter(it => !!it.address)
+ if (!items.length) {
+ this.$message.warning('OPC点位为空:当前没有可发送的字段(请先在输入框里填写点位)')
+ return
+ }
+
const dto = {
deviceName: 'CGL_LINE_1',
groups: [
{
groupNo: 1,
groupType: 'DRIVE',
- groupName: `Drive Params for ${plan.steelGrade || ''}`,
+ groupName: `Drive/Plan Params for ${plan.steelGrade || ''}`,
items
}
]
diff --git a/src/views/l2/send/furnace.vue b/src/views/l2/send/furnace.vue
index 98d6632..1060242 100644
--- a/src/views/l2/send/furnace.vue
+++ b/src/views/l2/send/furnace.vue
@@ -36,8 +36,31 @@
>
Apply Last Success Values
+
+
+ History
+
+
+
+
+
+
@@ -62,27 +85,54 @@
-
-
-
+
-
-
+
-
-
- Address:
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ Last Success: {{ getLastValue(item) }}
+
+
+ Default: {{ getDefaultValue(item) }}
+
+
+Modified
+
+
+
+
+
+ Address:
+
+
+
+
+
+
+
@@ -96,10 +146,18 @@
diff --git a/src/views/l2/track/rect.vue b/src/views/l2/track/rect.vue
index 6f4b1a5..442da82 100644
--- a/src/views/l2/track/rect.vue
+++ b/src/views/l2/track/rect.vue
@@ -16,42 +16,51 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Furnace Setup
+ Drive Setup
+
@@ -2372,6 +2381,7 @@ import { getDriveSetupValue, getFurnaceSetupValue } from '@/api/l2/setupValue'
/* WebSocket 状态栏 */
.ws-status-bar {
display: flex;
+ justify-content: space-between;
gap: 15px;
padding: 10px;
background: #f5f7fa;
@@ -2379,6 +2389,24 @@ import { getDriveSetupValue, getFurnaceSetupValue } from '@/api/l2/setupValue'
margin-bottom: 10px;
align-items: center;
}
+
+ .ws-status-left {
+ display: flex;
+ gap: 15px;
+ align-items: center;
+ }
+
+ .ws-status-right {
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ }
+
+ .ws-status-right .el-button {
+ min-width: 140px;
+ height: 34px;
+ font-weight: 600;
+ }
.ws-status-bar i {
font-size: 18px;