新增传动、炉火写入页面
This commit is contained in:
36
src/api/l2/sendJob.js
Normal file
36
src/api/l2/sendJob.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import request from '@/utils/l2-request'
|
||||||
|
|
||||||
|
// 创建发送任务
|
||||||
|
export function createSendJob(data) {
|
||||||
|
return request({
|
||||||
|
url: '/business/sendJob',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行发送任务
|
||||||
|
export function executeSendJob(jobId) {
|
||||||
|
return request({
|
||||||
|
url: `/business/sendJob/${jobId}/execute`,
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询发送任务列表(用于历史追溯,此页面暂不使用)
|
||||||
|
export function listSendJob(query) {
|
||||||
|
return request({
|
||||||
|
url: '/business/sendJob/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取发送任务详情(用于历史追溯,此页面暂不使用)
|
||||||
|
export function getSendJob(jobId) {
|
||||||
|
return request({
|
||||||
|
url: `/business/sendJob/${jobId}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
19
src/api/l2/sendTemplate.js
Normal file
19
src/api/l2/sendTemplate.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import request from '@/utils/L2Request'
|
||||||
|
|
||||||
|
// 获取发送模板(含明细)
|
||||||
|
export function getSendTemplate(templateCode) {
|
||||||
|
return request({
|
||||||
|
url: `/business/sendTemplate/${templateCode}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取最近一次成功发送(用于推荐值 + 上次发送时间显示)
|
||||||
|
export function getLastSuccess(groupType) {
|
||||||
|
return request({
|
||||||
|
url: '/business/sendJob/lastSuccess',
|
||||||
|
method: 'get',
|
||||||
|
params: { groupType }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
13
src/api/l2/template.js
Normal file
13
src/api/l2/template.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import request from '@/utils/l2-request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按模板编码查询发送模板(含明细)
|
||||||
|
* @param {string} templateCode 模板编码,如 FURNACE_DEFAULT
|
||||||
|
*/
|
||||||
|
export function getSendTemplate(templateCode) {
|
||||||
|
return request({
|
||||||
|
url: `/business/sendTemplate/${templateCode}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
321
src/views/l2/send/drive.vue
Normal file
321
src/views/l2/send/drive.vue
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<!-- Page Title / 页面标题 -->
|
||||||
|
<h2 class="page-title">Drive Parameter Sending</h2>
|
||||||
|
|
||||||
|
<!-- 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"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="el-icon-magic-stick"
|
||||||
|
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
|
||||||
|
v-for="plan in plans"
|
||||||
|
:key="plan.id"
|
||||||
|
:xs="24"
|
||||||
|
:sm="12"
|
||||||
|
:md="8"
|
||||||
|
class="card-col"
|
||||||
|
>
|
||||||
|
<el-card class="parameter-card" shadow="hover">
|
||||||
|
<div slot="header" class="card-header">
|
||||||
|
<!-- Steel Grade only / 只展示钢种,不展示计划 -->
|
||||||
|
<span class="card-title">Steel Grade: {{ plan.steelGrade || '-' }}</span>
|
||||||
|
|
||||||
|
<div class="header-right">
|
||||||
|
<!-- Last send time / 上次发送时间 -->
|
||||||
|
<span v-if="lastSuccess && lastSuccess.lastSendTime" class="last-send-time">
|
||||||
|
<i class="el-icon-time"></i>
|
||||||
|
Last Sent: {{ formatTime(lastSuccess.lastSendTime) }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-s-promotion"
|
||||||
|
@click="handleSend(plan)"
|
||||||
|
:loading="plan.sending"
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<!-- Template-driven form / 按模板渲染可编辑表单 -->
|
||||||
|
<el-form :model="plan.params" label-position="top" size="mini">
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col
|
||||||
|
v-for="item in templateItems"
|
||||||
|
:key="item.templateItemId || item.paramCode"
|
||||||
|
:span="12"
|
||||||
|
>
|
||||||
|
<el-form-item :label="item.labelEn">
|
||||||
|
<el-input
|
||||||
|
v-model="plan.params[item.paramCode]"
|
||||||
|
:placeholder="getPlaceholder(item)"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<div v-if="plans.length === 0 && !loading" class="empty-data">
|
||||||
|
<el-empty description="No Data"></el-empty>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Import APIs / 引入接口
|
||||||
|
import { listPlan } from '@/api/l2/plan'
|
||||||
|
import { listSetup } from '@/api/business/setup'
|
||||||
|
import { createSendJob, executeSendJob } from '@/api/l2/sendJob'
|
||||||
|
import { getSendTemplate, getLastSuccess } from '@/api/l2/sendTemplate'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DriveSend',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false, // Loading state / 加载状态
|
||||||
|
template: null, // Template data / 模板数据
|
||||||
|
lastSuccess: null, // Last success data / 上次成功记录
|
||||||
|
plans: [] // Plans with editable params / 带可编辑参数的钢种卡片
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// Template items sorted by itemNo / 模板明细按序号排序
|
||||||
|
templateItems() {
|
||||||
|
if (!this.template || !Array.isArray(this.template.items)) return []
|
||||||
|
return [...this.template.items]
|
||||||
|
.filter(i => i.enabled === undefined || i.enabled === 1)
|
||||||
|
.sort((a, b) => (a.itemNo || 0) - (b.itemNo || 0))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.reload()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// Reload all / 重新加载:模板 + 上次成功记录 + 计划卡片
|
||||||
|
async reload() {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
// 1) Load template + last success in parallel / 并行加载模板与上次成功记录
|
||||||
|
const [tplRes, lastRes] = await Promise.all([
|
||||||
|
getSendTemplate('DRIVE_DEFAULT'),
|
||||||
|
getLastSuccess('DRIVE')
|
||||||
|
])
|
||||||
|
|
||||||
|
// 后端返回 AjaxResult:{code,msg,data}
|
||||||
|
this.template = tplRes ? tplRes.data : null
|
||||||
|
this.lastSuccess = lastRes ? lastRes.data : null
|
||||||
|
|
||||||
|
if (!this.template || !this.templateItems.length) {
|
||||||
|
this.$message.error('DRIVE_DEFAULT template is empty')
|
||||||
|
this.plans = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Load plans / 再加载计划(卡片只展示钢种)
|
||||||
|
const planRes = await listPlan({ status: 'NEW,READY' })
|
||||||
|
const planList = planRes.rows || []
|
||||||
|
|
||||||
|
// 3) For each plan fetch setup, and map to template paramCode
|
||||||
|
// 每条计划拉取setup并映射到模板paramCode;优先级:setup值 > 上次成功值 > 模板默认值
|
||||||
|
const tasks = planList.map(async (p) => {
|
||||||
|
let setup = {}
|
||||||
|
try {
|
||||||
|
const setupRes = await listSetup({ coilid: p.coilid, planid: p.planid })
|
||||||
|
setup = (setupRes.rows && setupRes.rows.length > 0) ? setupRes.rows[0] : {}
|
||||||
|
} catch (e) {
|
||||||
|
setup = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {}
|
||||||
|
this.templateItems.forEach(item => {
|
||||||
|
const fromSetup = setup[item.paramCode]
|
||||||
|
const fromLast = this.lastSuccess && this.lastSuccess.values ? this.lastSuccess.values[item.paramCode] : undefined
|
||||||
|
|
||||||
|
if (fromSetup !== undefined && fromSetup !== null && String(fromSetup) !== '') {
|
||||||
|
params[item.paramCode] = String(fromSetup)
|
||||||
|
} else if (fromLast !== undefined && fromLast !== null) {
|
||||||
|
params[item.paramCode] = String(fromLast)
|
||||||
|
} else {
|
||||||
|
params[item.paramCode] = item.defaultValueRaw || ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...p,
|
||||||
|
setup,
|
||||||
|
params,
|
||||||
|
sending: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.plans = await Promise.all(tasks)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error('Load failed')
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Apply last success values to all cards / 将上次成功值应用到所有卡片(覆盖当前输入)
|
||||||
|
applyLastSuccessValues() {
|
||||||
|
if (!this.lastSuccess || !this.lastSuccess.values) {
|
||||||
|
this.$message.info('No last success data')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.plans.forEach(plan => {
|
||||||
|
this.templateItems.forEach(item => {
|
||||||
|
const v = this.lastSuccess.values[item.paramCode]
|
||||||
|
if (v !== undefined) {
|
||||||
|
this.$set(plan.params, item.paramCode, String(v))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$message.success('Last success values applied')
|
||||||
|
},
|
||||||
|
|
||||||
|
// Placeholder shows last/default / 占位符显示上次值或默认值
|
||||||
|
getPlaceholder(item) {
|
||||||
|
const fromLast = this.lastSuccess && this.lastSuccess.values ? this.lastSuccess.values[item.paramCode] : undefined
|
||||||
|
if (fromLast !== undefined) {
|
||||||
|
return `Last: ${fromLast}`
|
||||||
|
}
|
||||||
|
if (item.defaultValueRaw) {
|
||||||
|
return `Default: ${item.defaultValueRaw}`
|
||||||
|
}
|
||||||
|
return 'Please enter'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Format time / 格式化时间
|
||||||
|
formatTime(t) {
|
||||||
|
if (!t) return ''
|
||||||
|
const d = new Date(t)
|
||||||
|
return d.toLocaleString()
|
||||||
|
},
|
||||||
|
|
||||||
|
// Send / 发送
|
||||||
|
handleSend(plan) {
|
||||||
|
this.$confirm(
|
||||||
|
`Confirm to send parameters for Steel Grade [${plan.steelGrade || '-'}]?`,
|
||||||
|
'Warning',
|
||||||
|
{
|
||||||
|
confirmButtonText: 'Confirm',
|
||||||
|
cancelButtonText: 'Cancel',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => this.doSend(plan)).catch(() => {})
|
||||||
|
},
|
||||||
|
|
||||||
|
async doSend(plan) {
|
||||||
|
if (!this.template) {
|
||||||
|
this.$message.error('Template not loaded')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
plan.sending = true
|
||||||
|
try {
|
||||||
|
// Build items from template / 按模板组装发送明细
|
||||||
|
const items = this.templateItems.map(item => ({
|
||||||
|
paramCode: item.paramCode,
|
||||||
|
address: item.address,
|
||||||
|
valueRaw: String(plan.params[item.paramCode] || ''),
|
||||||
|
setTime: new Date()
|
||||||
|
})).filter(it => !!it.address)
|
||||||
|
|
||||||
|
if (!items.length) {
|
||||||
|
this.$message.error('No valid OPC address')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const dto = {
|
||||||
|
deviceName: this.template.deviceName,
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
groupNo: 1,
|
||||||
|
groupType: 'DRIVE',
|
||||||
|
groupName: `Drive Params for ${plan.steelGrade || ''}`,
|
||||||
|
items
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const createRes = await createSendJob(dto)
|
||||||
|
const jobId = createRes.data
|
||||||
|
if (!jobId) throw new Error('Create send job failed')
|
||||||
|
|
||||||
|
await executeSendJob(jobId)
|
||||||
|
this.$message.success('Send success')
|
||||||
|
|
||||||
|
// Refresh last success time / 发送成功后刷新上次成功记录与时间
|
||||||
|
await this.reload()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error(e.message || 'Send failed')
|
||||||
|
} finally {
|
||||||
|
plan.sending = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.page-title {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.card-grid-container {
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.card-col {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.parameter-card .card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.card-title {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.last-send-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
.empty-data {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
285
src/views/l2/send/furnace.vue
Normal file
285
src/views/l2/send/furnace.vue
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<!-- Page Title / 页面标题 -->
|
||||||
|
<h2 class="page-title">Furnace Parameter Sending</h2>
|
||||||
|
|
||||||
|
<!-- 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"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="el-icon-magic-stick"
|
||||||
|
size="small"
|
||||||
|
@click="applyLastSuccessValues"
|
||||||
|
>
|
||||||
|
Apply Last Success Values
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 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>
|
||||||
|
<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) }}
|
||||||
|
</span>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-s-promotion"
|
||||||
|
@click="handleSend"
|
||||||
|
:loading="sending"
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Template-driven editable form / 按模板渲染可编辑表单 -->
|
||||||
|
<el-form :model="form" label-position="top" size="mini">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col
|
||||||
|
:span="12"
|
||||||
|
v-for="item in templateItems"
|
||||||
|
:key="item.templateItemId || item.paramCode"
|
||||||
|
>
|
||||||
|
<el-form-item :label="item.labelEn">
|
||||||
|
<el-input v-model="form[item.paramCode]" :placeholder="getPlaceholder(item)" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div v-if="!loading && templateItems.length === 0" class="empty-data">
|
||||||
|
<el-empty description="Template is empty or not found"></el-empty>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Import APIs / 引入接口
|
||||||
|
import { createSendJob, executeSendJob } from '@/api/l2/sendJob';
|
||||||
|
import { getSendTemplate, getLastSuccess } from '@/api/l2/sendTemplate';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FurnaceSend',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false, // Loading state for the whole page / 页面加载状态
|
||||||
|
sending: false, // Sending state for the button / 发送按钮加载状态
|
||||||
|
template: null, // Template data from backend / 从后端获取的模板数据
|
||||||
|
lastSuccess: null, // Last successful send data / 最近一次成功发送的数据
|
||||||
|
form: {} // Form values (paramCode -> value) / 表单值(参数编码 -> 值)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// Template items sorted by itemNo / 按序号排序的模板明细
|
||||||
|
templateItems() {
|
||||||
|
if (!this.template || !Array.isArray(this.template.items)) return [];
|
||||||
|
return [...this.template.items]
|
||||||
|
.filter(i => i.enabled === undefined || i.enabled === 1)
|
||||||
|
.sort((a, b) => (a.itemNo || 0) - (b.itemNo || 0));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.reload();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// Reload all data / 重新加载所有数据
|
||||||
|
async reload() {
|
||||||
|
this.loading = true;
|
||||||
|
try {
|
||||||
|
// Fetch template and last success data in parallel / 并行获取模板和上次成功记录
|
||||||
|
const [templateRes, lastSuccessRes] = await Promise.all([
|
||||||
|
getSendTemplate('FURNACE_DEFAULT'),
|
||||||
|
getLastSuccess('FURNACE')
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Process template data / 处理模板数据
|
||||||
|
if (templateRes && templateRes.code === 200) {
|
||||||
|
this.template = templateRes.data;
|
||||||
|
} else {
|
||||||
|
this.$message.error('Load template failed');
|
||||||
|
this.template = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process last success data / 处理上次成功记录
|
||||||
|
if (lastSuccessRes && lastSuccessRes.code === 200) {
|
||||||
|
this.lastSuccess = lastSuccessRes.data;
|
||||||
|
} else {
|
||||||
|
this.lastSuccess = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize form with recommended values / 使用推荐值初始化表单
|
||||||
|
this.initializeForm();
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
this.$message.error('Load data failed');
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Initialize form values / 初始化表单值
|
||||||
|
initializeForm() {
|
||||||
|
const init = {};
|
||||||
|
if (!this.templateItems.length) {
|
||||||
|
this.form = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.templateItems.forEach(item => {
|
||||||
|
// Priority: last success value > template default value > empty string
|
||||||
|
// 优先级:上次成功值 > 模板默认值 > 空字符串
|
||||||
|
const lastValue = this.lastSuccess?.values?.[item.paramCode];
|
||||||
|
init[item.paramCode] = lastValue !== undefined ? lastValue : (item.defaultValueRaw || '');
|
||||||
|
});
|
||||||
|
this.form = init;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Apply last success values to the form / 将上次成功值应用到表单
|
||||||
|
applyLastSuccessValues() {
|
||||||
|
if (!this.lastSuccess || !this.lastSuccess.values) {
|
||||||
|
this.$message.info('No last success data to apply.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.templateItems.forEach(item => {
|
||||||
|
const lastValue = this.lastSuccess.values[item.paramCode];
|
||||||
|
if (lastValue !== undefined) {
|
||||||
|
this.$set(this.form, item.paramCode, lastValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.$message.success('Last success values applied.');
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get placeholder for input / 获取输入框的占位提示
|
||||||
|
getPlaceholder(item) {
|
||||||
|
const lastValue = this.lastSuccess?.values?.[item.paramCode];
|
||||||
|
if (lastValue !== undefined) {
|
||||||
|
return `Last: ${lastValue}`;
|
||||||
|
}
|
||||||
|
if (item.defaultValueRaw) {
|
||||||
|
return `Default: ${item.defaultValueRaw}`;
|
||||||
|
}
|
||||||
|
return 'Please enter';
|
||||||
|
},
|
||||||
|
|
||||||
|
// Format time for display / 格式化时间显示
|
||||||
|
formatTime(timeStr) {
|
||||||
|
if (!timeStr) return '';
|
||||||
|
const date = new Date(timeStr);
|
||||||
|
return date.toLocaleString();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Confirm before sending / 发送前确认
|
||||||
|
handleSend() {
|
||||||
|
this.$confirm('Confirm to send furnace parameters?', 'Warning', {
|
||||||
|
confirmButtonText: 'Confirm',
|
||||||
|
cancelButtonText: 'Cancel',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
this.doSend();
|
||||||
|
}).catch(() => {});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Execute send logic / 执行发送逻辑
|
||||||
|
async doSend() {
|
||||||
|
if (!this.template) {
|
||||||
|
this.$message.error('Template not loaded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.templateItems.length) {
|
||||||
|
this.$message.error('Template is empty');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sending = true;
|
||||||
|
try {
|
||||||
|
const items = this.templateItems.map(item => ({
|
||||||
|
paramCode: item.paramCode,
|
||||||
|
address: item.address,
|
||||||
|
valueRaw: String(this.form[item.paramCode] || ''),
|
||||||
|
setTime: new Date()
|
||||||
|
})).filter(it => !!it.address); // Filter out items with no address / 过滤掉没有地址的项
|
||||||
|
|
||||||
|
if (!items.length) {
|
||||||
|
this.$message.error('No valid OPC address found in template');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dto = {
|
||||||
|
deviceName: this.template.deviceName,
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
groupNo: 1,
|
||||||
|
groupType: 'FURNACE',
|
||||||
|
groupName: this.template.templateName || 'Furnace Settings',
|
||||||
|
items
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const createRes = await createSendJob(dto);
|
||||||
|
const jobId = createRes.data;
|
||||||
|
if (!jobId) throw new Error('Create send job failed');
|
||||||
|
|
||||||
|
await executeSendJob(jobId);
|
||||||
|
this.$message.success('Send success');
|
||||||
|
|
||||||
|
// Refresh last success data after sending / 发送成功后刷新上次记录
|
||||||
|
this.reload();
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
this.$message.error(e.message || 'Send failed');
|
||||||
|
} finally {
|
||||||
|
this.sending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.page-title {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.card-grid-container {
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.parameter-card .card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.card-title {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.last-send-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
.empty-data {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
</el-menu>
|
</el-menu>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<!-- Right main content area / 右侧主内容区 -->
|
<!-- Right main content area / 右侧主内容区 -->
|
||||||
<el-col :span="20" class="content-col">
|
<el-col :span="20" class="content-col">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
@@ -124,7 +124,7 @@ export default {
|
|||||||
padding: 15px;
|
padding: 15px;
|
||||||
background: #e8e8e8;
|
background: #e8e8e8;
|
||||||
border-bottom: 1px solid #d4d4d4;
|
border-bottom: 1px solid #d4d4d4;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -137,23 +137,23 @@ export default {
|
|||||||
border-right: none;
|
border-right: none;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
::v-deep .el-menu-item {
|
::v-deep .el-menu-item {
|
||||||
height: 48px;
|
height: 48px;
|
||||||
line-height: 48px;
|
line-height: 48px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
color: #333;
|
color: #333;
|
||||||
border-right: 2px solid #999;
|
border-right: 2px solid #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
i {
|
i {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -177,4 +177,4 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user