wanshenmean
2026-03-17 94ad631d316da04c46266ddb1fc6e63e6f8f2fae
Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/DetailsView.vue
@@ -1,5 +1,8 @@
<template>
  <div>
  <div
    v-loading.fullscreen.lock="startActionLoading"
    element-loading-text="正在启动实例,请稍候..."
  >
    <div v-if="loading" class="loading-container">
      <el-icon class="loading-icon" :size="40"><Loading /></el-icon>
      <p>加载中...</p>
@@ -169,11 +172,13 @@
                              <el-switch
                                v-if="row.dataType === 'Bool'"
                                v-model="fieldEditValues[getFieldEditKey(row)]"
                                @change="markFieldDirty(row)"
                                :disabled="!isFieldWritable(row)"
                              />
                              <el-input-number
                                v-else-if="row.dataType === 'Int' || row.dataType === 'DInt' || row.dataType === 'Byte'"
                                v-model="fieldEditValues[getFieldEditKey(row)]"
                                @change="markFieldDirty(row)"
                                :disabled="!isFieldWritable(row)"
                                :controls="false"
                                style="width: 100%"
@@ -181,6 +186,7 @@
                              <el-input
                                v-else
                                v-model="fieldEditValues[getFieldEditKey(row)]"
                                @input="markFieldDirty(row)"
                                :disabled="!isFieldWritable(row)"
                              />
                            </template>
@@ -223,11 +229,13 @@
                          <el-switch
                            v-if="row.dataType === 'Bool'"
                            v-model="fieldEditValues[getFieldEditKey(row)]"
                            @change="markFieldDirty(row)"
                            :disabled="!isFieldWritable(row)"
                          />
                          <el-input-number
                            v-else-if="row.dataType === 'Int' || row.dataType === 'DInt' || row.dataType === 'Byte'"
                            v-model="fieldEditValues[getFieldEditKey(row)]"
                            @change="markFieldDirty(row)"
                            :disabled="!isFieldWritable(row)"
                            :controls="false"
                            style="width: 100%"
@@ -235,6 +243,7 @@
                          <el-input
                            v-else
                            v-model="fieldEditValues[getFieldEditKey(row)]"
                            @input="markFieldDirty(row)"
                            :disabled="!isFieldWritable(row)"
                          />
                        </template>
@@ -311,6 +320,7 @@
const protocolTemplate = ref<ProtocolTemplate | null>(null)
const loading = ref(true)
const errorMsg = ref('')
const startActionLoading = ref(false)
const memoryLoading = ref(false)
const autoRefreshDb = ref(true)
@@ -322,6 +332,7 @@
const expandedDbViews = ref<Record<number, boolean>>({})
const fieldEditValues = ref<Record<string, string | number | boolean>>({})
const writingFieldKeys = ref<Record<string, boolean>>({})
const dirtyFieldKeys = ref<Record<string, boolean>>({})
let refreshTimer: number | null = null
@@ -413,11 +424,29 @@
})
watch(parsedFields, () => {
  const next: Record<string, string | number | boolean> = {}
  // 轮询刷新时,保留用户正在编辑的字段,避免输入值被覆盖。
  const next: Record<string, string | number | boolean> = { ...fieldEditValues.value }
  const validKeys = new Set<string>()
  for (const field of parsedFields.value) {
    const key = buildFieldEditKey(field.templateDbNumber, field.fieldKey)
    validKeys.add(key)
    if (dirtyFieldKeys.value[key] === true) {
      continue
    }
    next[key] = coerceEditValueByType(field.dataType, field.value)
  }
  for (const key of Object.keys(next)) {
    if (!validKeys.has(key)) {
      delete next[key]
    }
  }
  for (const key of Object.keys(dirtyFieldKeys.value)) {
    if (!validKeys.has(key)) {
      delete dirtyFieldKeys.value[key]
    }
  }
  fieldEditValues.value = next
}, { immediate: true })
@@ -530,6 +559,8 @@
      cancelButtonText: '取消',
      type: 'info'
    })
    startActionLoading.value = true
    await api.startInstance(id)
    await loadInstance()
    await loadMemoryData(true)
@@ -539,6 +570,8 @@
      console.error('启动实例失败:', err)
      ElMessage.error('启动失败,请查看控制台')
    }
  } finally {
    startActionLoading.value = false
  }
}
@@ -662,6 +695,14 @@
  return buildFieldEditKey(row.templateDbNumber, row.fieldKey)
}
function markFieldDirty(row: { templateDbNumber: number; fieldKey: string }): void {
  dirtyFieldKeys.value[getFieldEditKey(row)] = true
}
function clearFieldDirty(row: { templateDbNumber: number; fieldKey: string }): void {
  delete dirtyFieldKeys.value[getFieldEditKey(row)]
}
function isFieldWritable(row: { resolvedDbNumber: number | null }): boolean {
  return row.resolvedDbNumber !== null
}
@@ -727,6 +768,7 @@
    const dbBlockCount = instanceConfig.value?.memoryConfig.dbBlockCount || dbBlockNumbers.length || 1
    const dbBlockSize = instanceConfig.value?.memoryConfig.dbBlockSize || nextBytes.length
    dbBlocks.value = splitDbBlocks(nextBytes, dbBlockCount, dbBlockSize, dbBlockNumbers)
    clearFieldDirty(row)
    ElMessage.success(`字段 ${row.fieldKey} 写入成功`)
  } finally {
    writingFieldKeys.value[editKey] = false