feat(opc): 添加计划写入触发功能及相关配置

后续的配置是追踪的点位配置和写入的点位配置已经做好持久化在页面上配置完保存重启OPC即可实现持久化
后续的代码修改:从哪里开始而不是从最小的钢卷号开始,因为对方数据库里面的计划有几百条,写入的时候写入哪个计划的钢卷信息给一级都是需要修改代码的,现在默认的都是第一个钢卷

添加写入计数器、来源和目标节点的配置,支持从计划表读取数据并写入到指定开卷机的OPC节点。包括:
1. 在models.py中添加相关字段
2. 在opc_service.py中实现写入触发逻辑
3. 在OpcConfig.vue中添加配置界面
4. 更新相关API接口以支持新配置
This commit is contained in:
2026-04-13 16:09:48 +08:00
parent fc8b38d44d
commit 95ec77afae
6 changed files with 263 additions and 21 deletions

View File

@@ -7,17 +7,17 @@
<el-input v-model="form.opc_url" placeholder="opc.tcp://192.168.1.100:4840" style="width:360px" />
<span class="hint">opc.tcp://IP:PORT</span>
</el-form-item>
<el-form-item label="计数器节点 ID">
<el-input v-model="form.counter_node" placeholder="ns=2;s=PL.TRACKMAP.COUNTER" style="width:360px" />
<span class="hint">节点值变化时触发采集</span>
</el-form-item>
<el-form-item label="轮询间隔(秒)">
<el-input-number v-model="form.poll_interval" :min="1" :max="60" style="width:120px" />
</el-form-item>
</el-form>
<div class="panel-title" style="margin-top:16px">跟踪信号节点配置</div>
<div class="panel-title" style="margin-top:16px">追踪节点配置</div>
<el-form :model="form" label-width="155px" size="small">
<el-form-item label="追踪计数器节点">
<el-input v-model="form.counter_node" placeholder="ns=2;s=PL.TRACKMAP.COUNTER" style="width:360px" />
<span class="hint">追踪流程计数器节点值变化时触发采集</span>
</el-form-item>
<el-form-item label="信号1(入口钢卷)">
<el-input v-model="form.signal1_node" placeholder="ns=2;s=PL.Signal.EntryCoil" style="width:360px" />
<span class="hint">入口钢卷信号01触发</span>
@@ -28,6 +28,36 @@
</el-form-item>
</el-form>
<div class="panel-title" style="margin-top:16px">计划写入触发节点配置</div>
<el-form :model="form" label-width="155px" size="small">
<el-form-item label="写入计数器节点">
<el-input v-model="form.write_counter_node" placeholder="ns=2;s=PL.Material.Counter" style="width:360px" />
<span class="hint">计数器变化触发写入流程与追踪计数器分开</span>
</el-form-item>
<el-form-item label="起始位置节点">
<el-input v-model="form.write_source_node" placeholder="ns=2;s=PL.Material.Source" style="width:360px" />
<span class="hint">读到100表示来源为计划表</span>
</el-form-item>
<el-form-item label="目标位置节点">
<el-input v-model="form.write_target_node" placeholder="ns=2;s=PL.Material.Target" style="width:360px" />
<span class="hint">1=一号开卷机, 2=二号开卷机</span>
</el-form-item>
</el-form>
<div class="panel-title" style="margin-top:16px">一号开卷机字段映射</div>
<div v-for="field in writeFieldDefs" :key="'u1-' + field.key" class="node-row">
<div class="field-label">{{ field.label }}</div>
<span class="arrow"></span>
<el-input v-model="writeNodes['1'][field.key]" :placeholder="field.placeholder" size="small" style="width:320px" />
</div>
<div class="panel-title" style="margin-top:16px">二号开卷机字段映射</div>
<div v-for="field in writeFieldDefs" :key="'u2-' + field.key" class="node-row">
<div class="field-label">{{ field.label }}</div>
<span class="arrow"></span>
<el-input v-model="writeNodes['2'][field.key]" :placeholder="field.placeholder" size="small" style="width:320px" />
</div>
<div class="panel-title" style="margin-top:16px">跟踪图节点映射</div>
<div style="font-size:12px;color:#888;margin-bottom:10px">
Oracle列名 OPC节点ID必须包含 <b>position</b>
@@ -71,7 +101,29 @@ export default {
data() {
return {
loading: false, saving: false,
form: { opc_url: '', counter_node: '', poll_interval: 2, signal1_node: '', signal2_node: '' },
form: {
opc_url: '',
counter_node: '',
poll_interval: 2,
signal1_node: '',
signal2_node: '',
write_counter_node: '',
write_source_node: '',
write_target_node: ''
},
writeFieldDefs: [
{ key: 'setup_data_revision', label: '设置数据修改', placeholder: 'ns=2;s=PL.Setup.DataRevision' },
{ key: 'coilid', label: '钢卷ID', placeholder: 'ns=2;s=PL.Entry1.CoilId' },
{ key: 'entry_coil_weight', label: '入口钢卷重量', placeholder: 'ns=2;s=PL.Entry1.Weight' },
{ key: 'entry_of_coil_length', label: '长度', placeholder: 'ns=2;s=PL.Entry1.Length' },
{ key: 'entry_coil_width', label: '宽度', placeholder: 'ns=2;s=PL.Entry1.Width' },
{ key: 'entry_coil_thickness', label: '厚度', placeholder: 'ns=2;s=PL.Entry1.Thickness' },
{ key: 'entry_of_coil_inner_diameter', label: '钢卷内径', placeholder: 'ns=2;s=PL.Entry1.InnerDiameter' },
{ key: 'entry_of_coil_outer_diameter', label: '钢卷外径', placeholder: 'ns=2;s=PL.Entry1.OuterDiameter' },
{ key: 'alloy_code', label: '合金代码', placeholder: 'ns=2;s=PL.Entry1.AlloyCode' },
{ key: 'material', label: '材质', placeholder: 'ns=2;s=PL.Entry1.Material' }
],
writeNodes: { '1': {}, '2': {} },
nodeList: [],
status: { running: false, last_counter: null, last_update: null, log: [], track_state: '' },
statusTimer: null
@@ -93,6 +145,13 @@ export default {
this.form.poll_interval = cfg.poll_interval
this.form.signal1_node = cfg.signal1_node || ''
this.form.signal2_node = cfg.signal2_node || ''
this.form.write_counter_node = cfg.write_counter_node || ''
this.form.write_source_node = cfg.write_source_node || ''
this.form.write_target_node = cfg.write_target_node || ''
this.writeNodes = {
'1': { ...(cfg.write_nodes?.['1'] || {}) },
'2': { ...(cfg.write_nodes?.['2'] || {}) }
}
this.nodeList = Object.entries(cfg.trackmap_nodes || {}).map(([col, node]) => ({ col, node }))
} catch (e) { this.$message.error('加载失败: ' + e.message) }
finally { this.loading = false }
@@ -114,7 +173,7 @@ export default {
}
this.saving = true
try {
await opcApi.saveConfig({ ...this.form, trackmap_nodes })
await opcApi.saveConfig({ ...this.form, trackmap_nodes, write_nodes: this.writeNodes })
this.$message.success('配置已保存OPC服务已重启')
this.loadStatus()
} catch (e) { this.$message.error('保存失败: ' + e.message) }
@@ -134,6 +193,7 @@ export default {
.hint { font-size:11px; color:#999; margin-left:10px; }
.node-row { display:flex; align-items:center; gap:8px; margin-bottom:7px; padding:5px 8px; background:#fafafa; border:1px solid #eee; border-radius:2px; }
.arrow { font-size:14px; color:#888; font-weight:600; }
.field-label { width: 180px; color:#666; font-size:12px; }
.log-box { background:#fafafa; border:1px solid #e8e8e8; border-radius:2px; padding:8px 12px; height:180px; overflow-y:auto; font-family:monospace; }
.log-line { font-size:11px; color:#555; line-height:1.7; border-bottom:1px solid #f0f0f0; }
</style>

View File

@@ -7,7 +7,7 @@
<span style="flex:1"></span>
<el-button size="small" type="warning" @click="triggerSignal1">模拟信号1(入口)</el-button>
<el-button size="small" type="success" @click="triggerSignal2">模拟信号2(焊接完成)</el-button>
<span style="font-size:12px;color:#666">提示: 追踪4个位置,按钢卷号升序(最小的先进产线)</span>
<span style="font-size:12px;color:#666">1.出口 2.酸洗 3.入口活套 4.开卷机 提示:(最小的先进产线)</span>
</div>
<div class="panel" style="padding:0;margin-top:10px">