新增传动、炉火写入页面新增修改开关
This commit is contained in:
@@ -17,3 +17,20 @@ export function getLastSuccess(groupType) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新模板主表(deviceName 等)
|
||||||
|
export function updateSendTemplate(data) {
|
||||||
|
return request({
|
||||||
|
url: '/business/sendTemplate',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量更新模板明细(address/defaultValueRaw/enabled 等)
|
||||||
|
export function updateSendTemplateItems(data) {
|
||||||
|
return request({
|
||||||
|
url: '/business/sendTemplate/items',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,27 @@
|
|||||||
<el-button @click="reload" icon="el-icon-refresh" size="small" :loading="loading">
|
<el-button @click="reload" icon="el-icon-refresh" size="small" :loading="loading">
|
||||||
Refresh
|
Refresh
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
|
<!-- Edit template switch / 编辑模板开关 -->
|
||||||
|
<el-switch
|
||||||
|
v-model="editTemplate"
|
||||||
|
active-text="Edit Template"
|
||||||
|
inactive-text="View"
|
||||||
|
style="margin: 0 12px"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
v-if="editTemplate"
|
||||||
|
type="success"
|
||||||
|
plain
|
||||||
|
icon="el-icon-check"
|
||||||
|
size="small"
|
||||||
|
:loading="savingTemplate"
|
||||||
|
@click="saveTemplate"
|
||||||
|
>
|
||||||
|
Save Template
|
||||||
|
</el-button>
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
v-if="lastSuccess && lastSuccess.lastSendTime"
|
v-if="lastSuccess && lastSuccess.lastSendTime"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -51,7 +72,19 @@
|
|||||||
:key="item.templateItemId || item.paramCode"
|
:key="item.templateItemId || item.paramCode"
|
||||||
>
|
>
|
||||||
<el-form-item :label="item.labelEn">
|
<el-form-item :label="item.labelEn">
|
||||||
<el-input v-model="form[item.paramCode]" :placeholder="getPlaceholder(item)" />
|
<!-- Value input / 值输入框 -->
|
||||||
|
<el-input v-model="form[item.paramCode]" :placeholder="getPlaceholder(item)">
|
||||||
|
<template v-if="editTemplate" slot="append">
|
||||||
|
<!-- Address edit button / 点位编辑按钮 -->
|
||||||
|
<el-button type="text" @click="openEditAddress(item)">Addr</el-button>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
|
<!-- Inline address editor in edit mode / 编辑模式下显示当前点位 -->
|
||||||
|
<div v-if="editTemplate" class="addr-inline">
|
||||||
|
<span class="addr-label">Address:</span>
|
||||||
|
<el-input v-model="item.address" size="mini" placeholder="ns=2;s=..." />
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -62,158 +95,195 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Edit Address Dialog / 编辑点位弹窗 -->
|
||||||
|
<el-dialog title="Edit OPC Address" :visible.sync="addressDialogVisible" width="650px" append-to-body>
|
||||||
|
<div v-if="editingItem">
|
||||||
|
<div style="margin-bottom: 8px; font-weight: 600;">{{ editingItem.labelEn }}</div>
|
||||||
|
<el-input v-model="editingItem.address" placeholder="ns=2;s=..." />
|
||||||
|
<div style="margin-top: 8px; color: #909399; font-size: 12px;">
|
||||||
|
<!-- 中文注释:这里修改的是模板点位地址,保存后会同步到数据库 -->
|
||||||
|
修改的是模板点位地址,点击 "Save Template" 后同步到数据库。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="addressDialogVisible=false">Cancel</el-button>
|
||||||
|
<el-button type="primary" @click="addressDialogVisible=false">OK</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Import APIs / 引入接口
|
// Import APIs / 引入接口
|
||||||
import { createSendJob, executeSendJob } from '@/api/l2/sendJob';
|
import { createSendJob, executeSendJob } from '@/api/l2/sendJob'
|
||||||
import { getSendTemplate, getLastSuccess } from '@/api/l2/sendTemplate';
|
import { getSendTemplate, getLastSuccess, updateSendTemplate, updateSendTemplateItems } from '@/api/l2/sendTemplate'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FurnaceSend',
|
name: 'FurnaceSend',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false, // Loading state for the whole page / 页面加载状态
|
loading: false, // Loading / 加载
|
||||||
sending: false, // Sending state for the button / 发送按钮加载状态
|
sending: false, // Sending / 发送中
|
||||||
template: null, // Template data from backend / 从后端获取的模板数据
|
savingTemplate: false, // Saving template / 保存模板中
|
||||||
lastSuccess: null, // Last successful send data / 最近一次成功发送的数据
|
editTemplate: false, // Edit template switch / 编辑模板开关
|
||||||
form: {} // Form values (paramCode -> value) / 表单值(参数编码 -> 值)
|
|
||||||
};
|
template: null, // Template / 模板
|
||||||
|
lastSuccess: null, // Last success / 上次成功
|
||||||
|
form: {}, // Form values / 表单值
|
||||||
|
|
||||||
|
addressDialogVisible: false,
|
||||||
|
editingItem: null
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// Template items sorted by itemNo / 按序号排序的模板明细
|
|
||||||
templateItems() {
|
templateItems() {
|
||||||
if (!this.template || !Array.isArray(this.template.items)) return [];
|
if (!this.template || !Array.isArray(this.template.items)) return []
|
||||||
return [...this.template.items]
|
return [...this.template.items]
|
||||||
.filter(i => i.enabled === undefined || i.enabled === 1)
|
.filter(i => i.enabled === undefined || i.enabled === 1)
|
||||||
.sort((a, b) => (a.itemNo || 0) - (b.itemNo || 0));
|
.sort((a, b) => (a.itemNo || 0) - (b.itemNo || 0))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.reload();
|
this.reload()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// Reload all data / 重新加载所有数据
|
|
||||||
async reload() {
|
async reload() {
|
||||||
this.loading = true;
|
this.loading = true
|
||||||
try {
|
try {
|
||||||
// Fetch template and last success data in parallel / 并行获取模板和上次成功记录
|
const [templateRes, lastRes] = await Promise.all([
|
||||||
const [templateRes, lastSuccessRes] = await Promise.all([
|
|
||||||
getSendTemplate('FURNACE_DEFAULT'),
|
getSendTemplate('FURNACE_DEFAULT'),
|
||||||
getLastSuccess('FURNACE')
|
getLastSuccess('FURNACE')
|
||||||
]);
|
])
|
||||||
|
|
||||||
// Process template data / 处理模板数据
|
this.template = templateRes && templateRes.code === 200 ? templateRes.data : null
|
||||||
if (templateRes && templateRes.code === 200) {
|
this.lastSuccess = lastRes && lastRes.code === 200 ? lastRes.data : null
|
||||||
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();
|
|
||||||
|
|
||||||
|
this.initializeForm()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e)
|
||||||
this.$message.error('Load data failed');
|
this.$message.error('Load data failed')
|
||||||
|
this.template = null
|
||||||
|
this.lastSuccess = null
|
||||||
|
this.form = {}
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Initialize form values / 初始化表单值
|
|
||||||
initializeForm() {
|
initializeForm() {
|
||||||
const init = {};
|
const init = {}
|
||||||
if (!this.templateItems.length) {
|
if (!this.templateItems.length) {
|
||||||
this.form = {};
|
this.form = {}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.templateItems.forEach(item => {
|
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 || '')
|
||||||
const lastValue = this.lastSuccess?.values?.[item.paramCode];
|
})
|
||||||
init[item.paramCode] = lastValue !== undefined ? lastValue : (item.defaultValueRaw || '');
|
this.form = init
|
||||||
});
|
|
||||||
this.form = init;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Apply last success values to the form / 将上次成功值应用到表单
|
|
||||||
applyLastSuccessValues() {
|
applyLastSuccessValues() {
|
||||||
if (!this.lastSuccess || !this.lastSuccess.values) {
|
if (!this.lastSuccess || !this.lastSuccess.values) {
|
||||||
this.$message.info('No last success data to apply.');
|
this.$message.info('No last success data')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.templateItems.forEach(item => {
|
this.templateItems.forEach(item => {
|
||||||
const lastValue = this.lastSuccess.values[item.paramCode];
|
const v = this.lastSuccess.values[item.paramCode]
|
||||||
if (lastValue !== undefined) {
|
if (v !== undefined) {
|
||||||
this.$set(this.form, item.paramCode, lastValue);
|
this.$set(this.form, item.paramCode, String(v))
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
this.$message.success('Last success values applied.');
|
this.$message.success('Last success values applied')
|
||||||
},
|
},
|
||||||
|
|
||||||
// Get placeholder for input / 获取输入框的占位提示
|
|
||||||
getPlaceholder(item) {
|
getPlaceholder(item) {
|
||||||
const lastValue = this.lastSuccess?.values?.[item.paramCode];
|
const lastValue = this.lastSuccess?.values?.[item.paramCode]
|
||||||
if (lastValue !== undefined) {
|
if (lastValue !== undefined) return `Last: ${lastValue}`
|
||||||
return `Last: ${lastValue}`;
|
if (item.defaultValueRaw) return `Default: ${item.defaultValueRaw}`
|
||||||
}
|
return 'Please enter'
|
||||||
if (item.defaultValueRaw) {
|
|
||||||
return `Default: ${item.defaultValueRaw}`;
|
|
||||||
}
|
|
||||||
return 'Please enter';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Format time for display / 格式化时间显示
|
formatTime(t) {
|
||||||
formatTime(timeStr) {
|
if (!t) return ''
|
||||||
if (!timeStr) return '';
|
return new Date(t).toLocaleString()
|
||||||
const date = new Date(timeStr);
|
},
|
||||||
return date.toLocaleString();
|
|
||||||
|
openEditAddress(item) {
|
||||||
|
this.editingItem = item
|
||||||
|
this.addressDialogVisible = true
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveTemplate() {
|
||||||
|
if (!this.template || !this.template.templateId) {
|
||||||
|
this.$message.error('Template not loaded')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.savingTemplate = true
|
||||||
|
try {
|
||||||
|
// 1) update template main (deviceName etc.) / 更新模板主表
|
||||||
|
await updateSendTemplate({
|
||||||
|
templateId: this.template.templateId,
|
||||||
|
deviceName: this.template.deviceName,
|
||||||
|
enabled: this.template.enabled,
|
||||||
|
remark: this.template.remark
|
||||||
|
})
|
||||||
|
|
||||||
|
// 2) batch update template items (address/default value) / 批量更新模板明细
|
||||||
|
const itemsPayload = this.templateItems.map(it => ({
|
||||||
|
templateItemId: it.templateItemId,
|
||||||
|
address: it.address,
|
||||||
|
defaultValueRaw: it.defaultValueRaw,
|
||||||
|
enabled: it.enabled,
|
||||||
|
remark: it.remark
|
||||||
|
}))
|
||||||
|
|
||||||
|
await updateSendTemplateItems(itemsPayload)
|
||||||
|
this.$message.success('Template saved')
|
||||||
|
this.editTemplate = false
|
||||||
|
await this.reload()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error(e.message || 'Save template failed')
|
||||||
|
} finally {
|
||||||
|
this.savingTemplate = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Confirm before sending / 发送前确认
|
|
||||||
handleSend() {
|
handleSend() {
|
||||||
this.$confirm('Confirm to send furnace parameters?', 'Warning', {
|
this.$confirm('Confirm to send furnace parameters?', 'Warning', {
|
||||||
confirmButtonText: 'Confirm',
|
confirmButtonText: 'Confirm',
|
||||||
cancelButtonText: 'Cancel',
|
cancelButtonText: 'Cancel',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.doSend();
|
this.doSend()
|
||||||
}).catch(() => {});
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
|
|
||||||
// Execute send logic / 执行发送逻辑
|
|
||||||
async doSend() {
|
async doSend() {
|
||||||
if (!this.template) {
|
if (!this.template) {
|
||||||
this.$message.error('Template not loaded');
|
this.$message.error('Template not loaded')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (!this.templateItems.length) {
|
if (!this.templateItems.length) {
|
||||||
this.$message.error('Template is empty');
|
this.$message.error('Template is empty')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sending = true;
|
this.sending = true
|
||||||
try {
|
try {
|
||||||
const items = this.templateItems.map(item => ({
|
const items = this.templateItems.map(item => ({
|
||||||
paramCode: item.paramCode,
|
paramCode: item.paramCode,
|
||||||
address: item.address,
|
address: item.address,
|
||||||
valueRaw: String(this.form[item.paramCode] || ''),
|
valueRaw: String(this.form[item.paramCode] || ''),
|
||||||
setTime: new Date()
|
setTime: new Date()
|
||||||
})).filter(it => !!it.address); // Filter out items with no address / 过滤掉没有地址的项
|
})).filter(it => !!it.address)
|
||||||
|
|
||||||
if (!items.length) {
|
if (!items.length) {
|
||||||
this.$message.error('No valid OPC address found in template');
|
this.$message.error('No valid OPC address found in template')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const dto = {
|
const dto = {
|
||||||
@@ -226,27 +296,25 @@ export default {
|
|||||||
items
|
items
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
}
|
||||||
|
|
||||||
const createRes = await createSendJob(dto);
|
const createRes = await createSendJob(dto)
|
||||||
const jobId = createRes.data;
|
const jobId = createRes.data
|
||||||
if (!jobId) throw new Error('Create send job failed');
|
if (!jobId) throw new Error('Create send job failed')
|
||||||
|
|
||||||
await executeSendJob(jobId);
|
await executeSendJob(jobId)
|
||||||
this.$message.success('Send success');
|
this.$message.success('Send success')
|
||||||
|
|
||||||
// Refresh last success data after sending / 发送成功后刷新上次记录
|
|
||||||
this.reload();
|
|
||||||
|
|
||||||
|
await this.reload()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e)
|
||||||
this.$message.error(e.message || 'Send failed');
|
this.$message.error(e.message || 'Send failed')
|
||||||
} finally {
|
} finally {
|
||||||
this.sending = false;
|
this.sending = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -255,6 +323,10 @@ export default {
|
|||||||
}
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
.card-grid-container {
|
.card-grid-container {
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
@@ -279,7 +351,13 @@ export default {
|
|||||||
.empty-data {
|
.empty-data {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
.el-form-item {
|
.addr-inline {
|
||||||
margin-bottom: 12px;
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
.addr-label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 6px;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user