<template>
|
<div>
|
<div v-if="loading" class="text-center py-5">
|
<div class="spinner-border text-primary" role="status">
|
<span class="visually-hidden">加载中...</span>
|
</div>
|
</div>
|
|
<div v-else-if="errorMsg">
|
<div class="alert alert-danger">{{ errorMsg }}</div>
|
<router-link to="/" class="btn btn-primary">返回列表</router-link>
|
</div>
|
|
<div v-else>
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div>
|
<h2 class="mb-0">
|
<i class="bi bi-pencil me-2"></i>编辑实例
|
</h2>
|
<p class="text-muted mb-0 mt-1">编辑实例配置: {{ form.id }}</p>
|
</div>
|
<router-link to="/" class="btn btn-outline-secondary">
|
<i class="bi bi-arrow-left me-1"></i>返回列表
|
</router-link>
|
</div>
|
|
<div v-if="isRunning" class="alert alert-warning">
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
实例正在运行中,修改配置后需要重启实例才能生效
|
</div>
|
|
<div class="row justify-content-center">
|
<div class="col-lg-8">
|
<div class="card">
|
<div class="card-body">
|
<form @submit.prevent="handleSubmit">
|
<!-- 基本信息 -->
|
<h5 class="card-title mb-3">基本信息</h5>
|
<div class="row mb-3">
|
<div class="col-md-6">
|
<label for="id" class="form-label">实例ID</label>
|
<input
|
type="text"
|
class="form-control"
|
id="id"
|
v-model="form.id"
|
disabled
|
>
|
<div class="form-text">实例ID创建后不可修改</div>
|
</div>
|
<div class="col-md-6">
|
<label for="name" class="form-label">实例名称 *</label>
|
<input
|
type="text"
|
class="form-control"
|
id="name"
|
v-model="form.name"
|
required
|
>
|
</div>
|
</div>
|
|
<div class="row mb-3">
|
<div class="col-md-6">
|
<label for="plcType" class="form-label">PLC型号 *</label>
|
<select class="form-select" id="plcType" v-model="form.plcType" required>
|
<option value="S7200Smart">S7-200 Smart</option>
|
<option value="S71200">S7-1200</option>
|
<option value="S71500">S7-1500</option>
|
<option value="S7300">S7-300</option>
|
<option value="S7400">S7-400</option>
|
</select>
|
</div>
|
<div class="col-md-6">
|
<label for="port" class="form-label">监听端口 *</label>
|
<input
|
type="number"
|
class="form-control"
|
id="port"
|
v-model.number="form.port"
|
min="1"
|
max="65535"
|
required
|
>
|
</div>
|
</div>
|
|
<div class="row mb-3">
|
<div class="col-md-6">
|
<label for="activationKey" class="form-label">HSL激活码</label>
|
<input
|
type="text"
|
class="form-control"
|
id="activationKey"
|
v-model="form.activationKey"
|
>
|
</div>
|
<div class="col-md-6 d-flex align-items-center">
|
<div class="form-check">
|
<input class="form-check-input" type="checkbox" id="autoStart" v-model="form.autoStart">
|
<label class="form-check-label" for="autoStart">
|
自动启动
|
</label>
|
</div>
|
</div>
|
</div>
|
|
<!-- 内存配置 -->
|
<h5 class="card-title mb-3 mt-4">内存配置</h5>
|
<div class="row mb-3">
|
<div class="col-md-4">
|
<label for="mRegionSize" class="form-label">M区域大小</label>
|
<input
|
type="number"
|
class="form-control"
|
id="mRegionSize"
|
v-model.number="form.mRegionSize"
|
min="0"
|
>
|
</div>
|
<div class="col-md-4">
|
<label for="iRegionSize" class="form-label">I区域大小</label>
|
<input
|
type="number"
|
class="form-control"
|
id="iRegionSize"
|
v-model.number="form.iRegionSize"
|
min="0"
|
>
|
</div>
|
<div class="col-md-4">
|
<label for="qRegionSize" class="form-label">Q区域大小</label>
|
<input
|
type="number"
|
class="form-control"
|
id="qRegionSize"
|
v-model.number="form.qRegionSize"
|
min="0"
|
>
|
</div>
|
</div>
|
|
<div class="row mb-3">
|
<div class="col-md-4">
|
<label for="dbBlockCount" class="form-label">DB块数量</label>
|
<input
|
type="number"
|
class="form-control"
|
id="dbBlockCount"
|
v-model.number="form.dbBlockCount"
|
min="0"
|
>
|
</div>
|
<div class="col-md-4">
|
<label for="dbBlockSize" class="form-label">DB块大小</label>
|
<input
|
type="number"
|
class="form-control"
|
id="dbBlockSize"
|
v-model.number="form.dbBlockSize"
|
min="0"
|
>
|
</div>
|
<div class="col-md-2">
|
<label for="tRegionCount" class="form-label">定时器数量</label>
|
<input
|
type="number"
|
class="form-control"
|
id="tRegionCount"
|
v-model.number="form.tRegionCount"
|
min="0"
|
>
|
</div>
|
<div class="col-md-2">
|
<label for="cRegionCount" class="form-label">计数器数量</label>
|
<input
|
type="number"
|
class="form-control"
|
id="cRegionCount"
|
v-model.number="form.cRegionCount"
|
min="0"
|
>
|
</div>
|
</div>
|
|
<!-- 提交按钮 -->
|
<div class="d-flex gap-2 mt-4">
|
<button type="submit" class="btn btn-primary" :disabled="submitting">
|
<span v-if="submitting" class="spinner-border spinner-border-sm me-1"></span>
|
<i v-else class="bi bi-check-lg me-1"></i>
|
{{ submitting ? '保存中...' : '保存更改' }}
|
</button>
|
<router-link to="/" class="btn btn-outline-secondary">取消</router-link>
|
</div>
|
</form>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { ref, onMounted } from 'vue'
|
import { useRouter, useRoute } from 'vue-router'
|
import * as api from '../api'
|
import type { InstanceConfig, MemoryRegionConfig, SiemensPLCType } from '../types'
|
|
const router = useRouter()
|
const route = useRoute()
|
|
const form = ref({
|
id: '',
|
name: '',
|
plcType: 'S71200' as SiemensPLCType,
|
port: 102,
|
activationKey: '',
|
autoStart: false,
|
mRegionSize: 1024,
|
dbBlockCount: 100,
|
dbBlockSize: 1024,
|
iRegionSize: 256,
|
qRegionSize: 256,
|
tRegionCount: 64,
|
cRegionCount: 64
|
})
|
|
const loading = ref(true)
|
const errorMsg = ref('')
|
const submitting = ref(false)
|
const isRunning = ref(false)
|
|
const id = route.params.id as string
|
|
onMounted(async () => {
|
try {
|
// 获取实例状态
|
const state = await api.getInstance(id)
|
if (!state) {
|
errorMsg.value = `实例 "${id}" 不存在`
|
loading.value = false
|
return
|
}
|
|
isRunning.value = state.status === 'Running'
|
|
// 获取实例配置
|
const config = await api.getInstanceConfig(id)
|
if (!config) {
|
errorMsg.value = `无法加载实例 "${id}" 的配置`
|
loading.value = false
|
return
|
}
|
|
form.value = {
|
id: config.id,
|
name: config.name,
|
plcType: config.plcType,
|
port: config.port,
|
activationKey: config.activationKey,
|
autoStart: config.autoStart,
|
mRegionSize: config.memoryConfig.mRegionSize,
|
dbBlockCount: config.memoryConfig.dBBBlockCount,
|
dbBlockSize: config.memoryConfig.dBBBlockSize,
|
iRegionSize: config.memoryConfig.iRegionSize,
|
qRegionSize: config.memoryConfig.qRegionSize,
|
tRegionCount: config.memoryConfig.tRegionCount,
|
cRegionCount: config.memoryConfig.cRegionCount
|
}
|
} catch (err) {
|
console.error('加载实例配置失败:', err)
|
errorMsg.value = '加载实例配置失败,请查看控制台'
|
} finally {
|
loading.value = false
|
}
|
})
|
|
async function handleSubmit() {
|
submitting.value = true
|
|
try {
|
const memoryConfig: MemoryRegionConfig = {
|
mRegionSize: form.value.mRegionSize > 0 ? form.value.mRegionSize : 1024,
|
dBBBlockCount: form.value.dbBlockCount > 0 ? form.value.dbBlockCount : 100,
|
dBBBlockSize: form.value.dbBlockSize > 0 ? form.value.dbBlockSize : 1024,
|
iRegionSize: form.value.iRegionSize > 0 ? form.value.iRegionSize : 256,
|
qRegionSize: form.value.qRegionSize > 0 ? form.value.qRegionSize : 256,
|
tRegionCount: form.value.tRegionCount > 0 ? form.value.tRegionCount : 64,
|
cRegionCount: form.value.cRegionCount > 0 ? form.value.cRegionCount : 64
|
}
|
|
const config: InstanceConfig = {
|
id: form.value.id,
|
name: form.value.name,
|
plcType: form.value.plcType,
|
port: form.value.port,
|
activationKey: form.value.activationKey,
|
autoStart: form.value.autoStart,
|
memoryConfig
|
}
|
|
const result = await api.updateInstance(form.value.id, config)
|
|
if (result) {
|
alert(`实例 "${form.value.id}" 更新成功!`)
|
router.push('/')
|
} else {
|
alert('更新实例失败')
|
}
|
} catch (err) {
|
console.error('更新实例失败:', err)
|
alert('更新实例失败,请查看控制台')
|
} finally {
|
submitting.value = false
|
}
|
}
|
</script>
|
|
<style scoped>
|
.card-title {
|
color: #495057;
|
font-weight: 600;
|
}
|
|
.form-label {
|
font-weight: 500;
|
color: #495057;
|
}
|
</style>
|