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