From e76f0739e647fe8a7e0e2618914e2faff554b1b7 Mon Sep 17 00:00:00 2001
From: huang <1532065656@qq.com>
Date: 星期一, 17 十一月 2025 17:33:23 +0800
Subject: [PATCH] 解决冲突

---
 mes-web/src/views/device/DeviceConfigForm.vue |  557 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 557 insertions(+), 0 deletions(-)

diff --git a/mes-web/src/views/device/DeviceConfigForm.vue b/mes-web/src/views/device/DeviceConfigForm.vue
new file mode 100644
index 0000000..5b6f7e6
--- /dev/null
+++ b/mes-web/src/views/device/DeviceConfigForm.vue
@@ -0,0 +1,557 @@
+<template>
+  <div class="device-config-form">
+    <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+    <div class="search-section">
+      <el-form :model="searchForm" :inline="true" class="search-form">
+        <el-form-item label="璁惧绫诲瀷">
+          <el-select v-model="searchForm.deviceType" placeholder="閫夋嫨璁惧绫诲瀷" clearable>
+            <el-option label="PLC鎺у埗鍣�" value="PLC鎺у埗鍣�" />
+            <el-option label="浼犳劅鍣�" value="浼犳劅鍣�" />
+            <el-option label="鎵ц鍣�" value="鎵ц鍣�" />
+            <el-option label="鎺у埗鍣�" value="鎺у埗鍣�" />
+            <el-option label="閲囬泦鍣�" value="閲囬泦鍣�" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="璁惧鐘舵��">
+          <el-select v-model="searchForm.deviceStatus" placeholder="閫夋嫨璁惧鐘舵��" clearable>
+            <el-option label="鍦ㄧ嚎" value="ONLINE" />
+            <el-option label="绂荤嚎" value="OFFLINE" />
+            <el-option label="缁存姢涓�" value="MAINTENANCE" />
+            <el-option label="绂佺敤" value="DISABLED" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鎼滅储鍏抽敭璇�">
+          <el-input v-model="searchForm.keyword" placeholder="璁惧鍚嶇О鎴栫紪鐮�" clearable style="width: 200px;">
+            <template #append>
+              <el-button @click="handleSearch">
+                <el-icon><Search /></el-icon>
+              </el-button>
+            </template>
+          </el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+          <el-button @click="resetSearch">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <!-- 鎵归噺鎿嶄綔鍖哄煙 -->
+    <div class="batch-operation" v-if="selectedDevices.length > 0">
+      <el-alert
+        :title="`宸查�夋嫨 ${selectedDevices.length} 涓澶嘸"
+        type="info"
+        show-icon
+        :closable="false"
+      />
+      <div class="batch-buttons">
+        <el-button type="success" size="small" @click="batchEnable">鎵归噺鍚敤</el-button>
+        <el-button type="warning" size="small" @click="batchDisable">鎵归噺绂佺敤</el-button>
+        <el-button type="danger" size="small" @click="batchDelete">鎵归噺鍒犻櫎</el-button>
+        <el-button size="small" @click="clearSelection">鍙栨秷閫夋嫨</el-button>
+      </div>
+    </div>
+
+    <!-- 璁惧鍒楄〃 -->
+    <div class="table-section">
+      <el-table
+        ref="deviceTable"
+        v-loading="tableLoading"
+        :data="deviceList"
+        @selection-change="handleSelectionChange"
+        border
+        stripe
+        style="width: 100%"
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="deviceName" label="璁惧鍚嶇О" min-width="150" />
+        <el-table-column prop="deviceCode" label="璁惧缂栫爜" width="130" />
+        <el-table-column prop="deviceType" label="璁惧绫诲瀷" width="120">
+          <template #default="scope">
+            <el-tag :type="getDeviceTypeTag(scope.row.deviceType)">
+              {{ scope.row.deviceType }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="plcIp" label="PLC IP" width="140" />
+        <el-table-column prop="port" label="绔彛" width="80" />
+        <el-table-column prop="deviceStatus" label="璁惧鐘舵��" width="100">
+          <template #default="scope">
+            <el-tag :type="getDeviceStatusTag(scope.row.deviceStatus)" size="small">
+              {{ getDeviceStatusText(scope.row.deviceStatus) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="enabled" label="鍚敤鐘舵��" width="100">
+          <template #default="scope">
+            <el-switch
+              v-model="scope.row.enabled"
+              @change="handleStatusChange(scope.row)"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column prop="description" label="鎻忚堪" min-width="200" />
+        <el-table-column prop="sortOrder" label="鎺掑簭" width="80" align="center" />
+        <el-table-column label="鎿嶄綔" width="280" fixed="right">
+          <template #default="scope">
+            <el-button type="primary" size="small" @click="editDevice(scope.row)">
+              缂栬緫
+            </el-button>
+            <el-button type="success" size="small" @click="testConnection(scope.row)">
+              娴嬭瘯杩炴帴
+            </el-button>
+            <el-button type="info" size="small" @click="viewDetails(scope.row)">
+              璇︽儏
+            </el-button>
+            <el-dropdown @command="(command) => handleCommand(command, scope.row)">
+              <el-button type="info" size="small">
+                鏇村<el-icon><ArrowDown /></el-icon>
+              </el-button>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item command="copy">澶嶅埗閰嶇疆</el-dropdown-item>
+                  <el-dropdown-item command="export">瀵煎嚭閰嶇疆</el-dropdown-item>
+                  <el-dropdown-item command="monitor">鐩戞帶</el-dropdown-item>
+                  <el-dropdown-item command="maintenance">缁存姢妯″紡</el-dropdown-item>
+                  <el-dropdown-item command="delete" divided>鍒犻櫎璁惧</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 鍒嗛〉 -->
+    <div class="pagination-section">
+      <el-pagination
+        v-model:current-page="pagination.page"
+        v-model:page-size="pagination.size"
+        :page-sizes="[10, 20, 50, 100]"
+        :total="pagination.total"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+
+    <!-- 璁惧璇︽儏寮圭獥 -->
+    <el-dialog
+      v-model="detailsDialogVisible"
+      title="璁惧璇︽儏"
+      width="70%"
+      :close-on-click-modal="false"
+    >
+      <div class="device-details" v-if="currentDevice">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-card shadow="never">
+              <template #header>
+                <strong>鍩烘湰淇℃伅</strong>
+              </template>
+              <el-descriptions :column="1" border>
+                <el-descriptions-item label="璁惧鍚嶇О">{{ currentDevice.deviceName }}</el-descriptions-item>
+                <el-descriptions-item label="璁惧缂栫爜">{{ currentDevice.deviceCode }}</el-descriptions-item>
+                <el-descriptions-item label="璁惧绫诲瀷">{{ currentDevice.deviceType }}</el-descriptions-item>
+                <el-descriptions-item label="璁惧鐘舵��">
+                  <el-tag :type="getDeviceStatusTag(currentDevice.deviceStatus)" size="small">
+                    {{ getDeviceStatusText(currentDevice.deviceStatus) }}
+                  </el-tag>
+                </el-descriptions-item>
+                <el-descriptions-item label="鍚敤鐘舵��">
+                  <el-switch v-model="currentDevice.enabled" disabled />
+                </el-descriptions-item>
+                <el-descriptions-item label="鎻忚堪">{{ currentDevice.description || '-' }}</el-descriptions-item>
+                <el-descriptions-item label="鎺掑簭">{{ currentDevice.sortOrder || '-' }}</el-descriptions-item>
+              </el-descriptions>
+            </el-card>
+          </el-col>
+          
+          <el-col :span="12">
+            <el-card shadow="never">
+              <template #header>
+                <strong>杩炴帴淇℃伅</strong>
+              </template>
+              <el-descriptions :column="1" border>
+                <el-descriptions-item label="PLC IP">{{ currentDevice.plcIp }}</el-descriptions-item>
+                <el-descriptions-item label="绔彛">{{ currentDevice.port }}</el-descriptions-item>
+                <el-descriptions-item label="閫氫俊鍗忚">{{ currentDevice.communicationProtocol }}</el-descriptions-item>
+                <el-descriptions-item label="杩炴帴瓒呮椂">{{ currentDevice.connectionTimeout }}绉�</el-descriptions-item>
+                <el-descriptions-item label="鏁版嵁閲囬泦闂撮殧">{{ currentDevice.dataCollectionInterval }}绉�</el-descriptions-item>
+                <el-descriptions-item label="閲嶈瘯娆℃暟">{{ currentDevice.retryCount }}</el-descriptions-item>
+              </el-descriptions>
+            </el-card>
+          </el-col>
+        </el-row>
+        
+        <!-- 璁惧鍙傛暟 -->
+        <el-row :gutter="20" style="margin-top: 20px;">
+          <el-col :span="24">
+            <el-card shadow="never">
+              <template #header>
+                <strong>璁惧鍙傛暟</strong>
+              </template>
+              <div v-if="currentDevice.deviceParameters">
+                <el-row :gutter="20">
+                  <el-col :span="8" v-for="(value, key) in currentDevice.deviceParameters" :key="key">
+                    <el-descriptions :column="1" border>
+                      <el-descriptions-item :label="key">{{ value }}</el-descriptions-item>
+                    </el-descriptions>
+                  </el-col>
+                </el-row>
+              </div>
+              <div v-else style="text-align: center; color: #999;">
+                鏆傛棤璁惧鍙傛暟閰嶇疆
+              </div>
+            </el-card>
+          </el-col>
+        </el-row>
+        
+        <!-- 鎵╁睍灞炴�� -->
+        <el-row :gutter="20" style="margin-top: 20px;">
+          <el-col :span="24">
+            <el-card shadow="never">
+              <template #header>
+                <strong>鎵╁睍灞炴��</strong>
+              </template>
+              <div v-if="currentDevice.extendedProperties">
+                <el-row :gutter="20">
+                  <el-col :span="8" v-for="(value, key) in currentDevice.extendedProperties" :key="key">
+                    <el-descriptions :column="1" border>
+                      <el-descriptions-item :label="key">{{ value }}</el-descriptions-item>
+                    </el-descriptions>
+                  </el-col>
+                </el-row>
+              </div>
+              <div v-else style="text-align: center; color: #999;">
+                鏆傛棤鎵╁睍灞炴�ч厤缃�
+              </div>
+            </el-card>
+          </el-col>
+        </el-row>
+      </div>
+      
+      <template #footer>
+        <el-button @click="detailsDialogVisible = false">鍏抽棴</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Search, ArrowDown } from '@element-plus/icons-vue'
+import { deviceConfigApi } from '@/api/device/deviceManagement'
+
+// 鍝嶅簲寮忔暟鎹�
+const deviceTable = ref(null)
+const tableLoading = ref(false)
+const deviceList = ref([])
+const selectedDevices = ref([])
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+  deviceType: '',
+  deviceStatus: '',
+  keyword: ''
+})
+
+// 鍒嗛〉淇℃伅
+const pagination = reactive({
+  page: 1,
+  size: 10,
+  total: 0
+})
+
+// 璁惧璇︽儏寮圭獥
+const detailsDialogVisible = ref(false)
+const currentDevice = ref(null)
+
+// 浜嬩欢瀹氫箟
+const emit = defineEmits(['device-selected', 'refresh-statistics'])
+
+// 鏂规硶瀹氫箟
+const loadDeviceList = async () => {
+  try {
+    tableLoading.value = true
+    const params = {
+      page: pagination.page,
+      size: pagination.size,
+      ...searchForm
+    }
+    
+    const response = await deviceConfigApi.getList(params)
+    deviceList.value = response.data.content || response.data.list || []
+    pagination.total = response.data.total || response.data.totalElements || 0
+  } catch (error) {
+    console.error('鍔犺浇璁惧鍒楄〃澶辫触:', error)
+    ElMessage.error('鍔犺浇璁惧鍒楄〃澶辫触')
+  } finally {
+    tableLoading.value = false
+  }
+}
+
+const handleSearch = () => {
+  pagination.page = 1
+  loadDeviceList()
+}
+
+const resetSearch = () => {
+  searchForm.deviceType = ''
+  searchForm.deviceStatus = ''
+  searchForm.keyword = ''
+  pagination.page = 1
+  loadDeviceList()
+}
+
+const handleSelectionChange = (selection) => {
+  selectedDevices.value = selection
+}
+
+const clearSelection = () => {
+  deviceTable.value?.clearSelection()
+  selectedDevices.value = []
+}
+
+const handleStatusChange = async (row) => {
+  try {
+    if (row.enabled) {
+      await deviceConfigApi.enable(row.id)
+      ElMessage.success('璁惧鍚敤鎴愬姛')
+    } else {
+      await deviceConfigApi.disable(row.id)
+      ElMessage.success('璁惧绂佺敤鎴愬姛')
+    }
+    emit('refresh-statistics')
+  } catch (error) {
+    console.error('鏇存柊璁惧鐘舵�佸け璐�:', error)
+    row.enabled = !row.enabled // 鎭㈠鐘舵��
+    ElMessage.error('鏇存柊璁惧鐘舵�佸け璐�')
+  }
+}
+
+const batchEnable = async () => {
+  try {
+    const deviceIds = selectedDevices.value.map(item => item.id)
+    await deviceConfigApi.batchEnable(deviceIds)
+    ElMessage.success(`鎴愬姛鍚敤 ${deviceIds.length} 涓澶嘸)
+    clearSelection()
+    loadDeviceList()
+    emit('refresh-statistics')
+  } catch (error) {
+    console.error('鎵归噺鍚敤澶辫触:', error)
+    ElMessage.error('鎵归噺鍚敤澶辫触')
+  }
+}
+
+const batchDisable = async () => {
+  try {
+    const deviceIds = selectedDevices.value.map(item => item.id)
+    await deviceConfigApi.batchDisable(deviceIds)
+    ElMessage.success(`鎴愬姛绂佺敤 ${deviceIds.length} 涓澶嘸)
+    clearSelection()
+    loadDeviceList()
+    emit('refresh-statistics')
+  } catch (error) {
+    console.error('鎵归噺绂佺敤澶辫触:', error)
+    ElMessage.error('鎵归噺绂佺敤澶辫触')
+  }
+}
+
+const batchDelete = async () => {
+  try {
+    await ElMessageBox.confirm(
+      `纭畾瑕佸垹闄ら�変腑鐨� ${selectedDevices.value.length} 涓澶囧悧锛熸鎿嶄綔涓嶅彲鎭㈠锛乣,
+      '鎵归噺鍒犻櫎纭',
+      {
+        confirmButtonText: '纭畾鍒犻櫎',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }
+    )
+    
+    const deviceIds = selectedDevices.value.map(item => item.id)
+    await deviceConfigApi.batchDelete(deviceIds)
+    ElMessage.success(`鎴愬姛鍒犻櫎 ${deviceIds.length} 涓澶嘸)
+    clearSelection()
+    loadDeviceList()
+    emit('refresh-statistics')
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('鎵归噺鍒犻櫎澶辫触:', error)
+      ElMessage.error('鎵归噺鍒犻櫎澶辫触')
+    }
+  }
+}
+
+const editDevice = (row) => {
+  emit('device-selected', row)
+}
+
+const testConnection = async (row) => {
+  try {
+    const loading = ElMessageBox.confirm('姝e湪娴嬭瘯璁惧杩炴帴...', '杩炴帴娴嬭瘯', {
+      showCancelButton: false,
+      showConfirmButton: false
+    })
+    
+    const response = await deviceConfigApi.testConnection({ deviceId: row.id })
+    
+    if (response.success) {
+      ElMessage.success(response.data || `璁惧 ${row.deviceName} 杩炴帴娴嬭瘯鎴愬姛`)
+    } else {
+      ElMessage.error(response.message || `璁惧 ${row.deviceName} 杩炴帴娴嬭瘯澶辫触`)
+    }
+  } catch (error) {
+    console.error('杩炴帴娴嬭瘯澶辫触:', error)
+    ElMessage.error('杩炴帴娴嬭瘯澶辫触')
+  }
+}
+
+const viewDetails = (row) => {
+  currentDevice.value = row
+  detailsDialogVisible.value = true
+}
+
+const handleCommand = async (command, row) => {
+  switch (command) {
+    case 'copy':
+      // 澶嶅埗閰嶇疆閫昏緫
+      ElMessage.info('澶嶅埗閰嶇疆鍔熻兘寮�鍙戜腑...')
+      break
+    case 'export':
+      // 瀵煎嚭閰嶇疆閫昏緫
+      ElMessage.info('瀵煎嚭閰嶇疆鍔熻兘寮�鍙戜腑...')
+      break
+    case 'monitor':
+      // 鐩戞帶閫昏緫
+      ElMessage.info('鐩戞帶鍔熻兘寮�鍙戜腑...')
+      break
+    case 'maintenance':
+      // 缁存姢妯″紡閫昏緫
+      try {
+        await deviceConfigApi.setMaintenanceMode(row.id, true)
+        ElMessage.success('璁惧宸茶缃负缁存姢妯″紡')
+        loadDeviceList()
+      } catch (error) {
+        ElMessage.error('璁剧疆缁存姢妯″紡澶辫触')
+      }
+      break
+    case 'delete':
+      await ElMessageBox.confirm('纭畾瑕佸垹闄よ璁惧鍚楋紵', '鍒犻櫎纭')
+      await deviceConfigApi.delete(row.id)
+      ElMessage.success('璁惧鍒犻櫎鎴愬姛')
+      loadDeviceList()
+      emit('refresh-statistics')
+      break
+  }
+}
+
+const handleSizeChange = (size) => {
+  pagination.size = size
+  pagination.page = 1
+  loadDeviceList()
+}
+
+const handleCurrentChange = (page) => {
+  pagination.page = page
+  loadDeviceList()
+}
+
+// 宸ュ叿鍑芥暟
+const getDeviceTypeTag = (type) => {
+  const typeMap = {
+    'PLC鎺у埗鍣�': 'primary',
+    '浼犳劅鍣�': 'success',
+    '鎵ц鍣�': 'warning',
+    '鎺у埗鍣�': 'info',
+    '閲囬泦鍣�': 'success'
+  }
+  return typeMap[type] || 'info'
+}
+
+const getDeviceStatusTag = (status) => {
+  const statusMap = {
+    'ONLINE': 'success',
+    'OFFLINE': 'info',
+    'MAINTENANCE': 'warning',
+    'DISABLED': 'danger'
+  }
+  return statusMap[status] || 'info'
+}
+
+const getDeviceStatusText = (status) => {
+  const statusMap = {
+    'ONLINE': '鍦ㄧ嚎',
+    'OFFLINE': '绂荤嚎',
+    'MAINTENANCE': '缁存姢涓�',
+    'DISABLED': '绂佺敤'
+  }
+  return statusMap[status] || status
+}
+
+// 鏆撮湶鏂规硶
+const refresh = () => {
+  loadDeviceList()
+}
+
+defineExpose({
+  refresh
+})
+
+// 缁勪欢鎸傝浇鏃跺姞杞芥暟鎹�
+onMounted(() => {
+  loadDeviceList()
+})
+</script>
+
+<style scoped>
+.device-config-form {
+  padding: 20px;
+}
+
+.search-section {
+  margin-bottom: 20px;
+  padding: 16px;
+  background-color: #f5f7fa;
+  border-radius: 8px;
+}
+
+.batch-operation {
+  margin-bottom: 16px;
+  padding: 16px;
+  background-color: #e6f7ff;
+  border: 1px solid #91d5ff;
+  border-radius: 8px;
+}
+
+.batch-buttons {
+  margin-top: 12px;
+  display: flex;
+  gap: 8px;
+}
+
+.table-section {
+  margin-bottom: 20px;
+}
+
+.pagination-section {
+  display: flex;
+  justify-content: center;
+}
+
+.device-details {
+  padding: 20px 0;
+}
+
+:deep(.el-table .cell) {
+  white-space: nowrap;
+}
+
+:deep(.el-dropdown-menu__item.is-divided) {
+  border-top: 1px solid #ebeef5;
+  margin-top: 6px;
+  padding-top: 10px;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.8.0