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/DeviceConfigList.vue | 538 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 538 insertions(+), 0 deletions(-)
diff --git a/mes-web/src/views/device/DeviceConfigList.vue b/mes-web/src/views/device/DeviceConfigList.vue
new file mode 100644
index 0000000..adad720
--- /dev/null
+++ b/mes-web/src/views/device/DeviceConfigList.vue
@@ -0,0 +1,538 @@
+<template>
+ <div class="device-config-list">
+ <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+ <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="涓婂ぇ杞�" 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 type="info" size="small" :loading="plcOperationLoading" @click="batchPlcRequest">鎵归噺PLC璇锋眰</el-button>
+ <el-button type="info" size="small" :loading="plcOperationLoading" @click="batchPlcReport">鎵归噺PLC姹囨姤</el-button>
+ <el-button type="info" size="small" :loading="plcOperationLoading" @click="batchPlcReset">鎵归噺PLC閲嶇疆</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="120" />
+ <el-table-column prop="deviceCode" label="璁惧缂栫爜" width="120" />
+ <el-table-column prop="deviceType" label="璁惧绫诲瀷" width="100">
+ <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="130" />
+ <el-table-column prop="plcType" label="PLC绫诲瀷" width="100" />
+ <el-table-column prop="moduleName" label="妯″潡鍚嶇О" min-width="120" />
+ <el-table-column prop="isPrimary" label="涓绘帶璁惧" width="100" align="center">
+ <template #default="scope">
+ <el-tag v-if="scope.row.isPrimary" type="success" size="small">涓绘帶</el-tag>
+ <span v-else>-</span>
+ </template>
+ </el-table-column>
+ <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"
+ :disabled="scope.row.isPrimary"
+ @change="handleStatusChange(scope.row)"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column prop="lastHeartbeat" label="鏈�鍚庡績璺�" width="150">
+ <template #default="scope">
+ {{ formatDateTime(scope.row.lastHeartbeat) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="200" fixed="right">
+ <template #default="scope">
+ <el-button type="primary" size="small" @click="editDevice(scope.row)">
+ 缂栬緫
+ </el-button>
+ <el-button type="warning" size="small" :loading="plcOperationLoading" @click="handleSinglePlcRequest(scope.row)">
+ PLC璇锋眰
+ </el-button>
+ <el-button type="success" size="small" @click="healthCheck(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="view">鏌ョ湅璇︽儏</el-dropdown-item>
+ <el-dropdown-item command="copy" :disabled="scope.row.isPrimary">澶嶅埗閰嶇疆</el-dropdown-item>
+ <el-dropdown-item command="reset">閲嶇疆璁惧</el-dropdown-item>
+ <el-dropdown-item command="plc-report">PLC姹囨姤</el-dropdown-item>
+ <el-dropdown-item command="plc-reset">PLC閲嶇疆</el-dropdown-item>
+ <el-dropdown-item command="delete" divided :disabled="scope.row.isPrimary">
+ 鍒犻櫎璁惧
+ </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>
+ </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, devicePlcApi } from '@/api/device/deviceManagement'
+
+// 鍝嶅簲寮忔暟鎹�
+const deviceTable = ref(null)
+const tableLoading = ref(false)
+const deviceList = ref([])
+const selectedDevices = ref([])
+const plcOperationLoading = ref(false)
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+ deviceType: '',
+ deviceStatus: '',
+ keyword: ''
+})
+
+// 鍒嗛〉淇℃伅
+const pagination = reactive({
+ page: 1,
+ size: 10,
+ total: 0
+})
+
+// 浜嬩欢瀹氫箟
+const emit = defineEmits(['device-selected', 'refresh-statistics'])
+
+// 鏂规硶瀹氫箟
+const loadDeviceList = async () => {
+ try {
+ tableLoading.value = true
+ const params = {
+ pageNum: pagination.page,
+ pageSize: pagination.size,
+ deviceType: searchForm.deviceType || undefined,
+ status: searchForm.deviceStatus || undefined,
+ deviceCode: searchForm.keyword || undefined
+ }
+
+ const response = await deviceConfigApi.getList(params)
+ // MyBatis-Plus Page 瀵硅薄缁撴瀯锛歿 records: [], total: 0 }
+ if (response && response.data) {
+ deviceList.value = response.data.records || response.data.content || response.data.list || []
+ pagination.total = response.data.total || response.data.totalElements || 0
+ } else {
+ deviceList.value = []
+ pagination.total = 0
+ }
+ } catch (error) {
+ console.error('鍔犺浇璁惧鍒楄〃澶辫触:', error)
+ ElMessage.error('鍔犺浇璁惧鍒楄〃澶辫触: ' + (error.response?.data?.message || error.message))
+ deviceList.value = []
+ pagination.total = 0
+ } 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 getSelectedDeviceIds = () => selectedDevices.value.map(item => item.id || item.deviceId)
+
+const plcOperationLabelMap = {
+ request: 'PLC璇锋眰',
+ report: 'PLC姹囨姤',
+ reset: 'PLC閲嶇疆'
+}
+
+const executePlcOperation = async (deviceIds, operation) => {
+ const ids = deviceIds?.filter(Boolean) || []
+ if (ids.length === 0) {
+ ElMessage.warning('璇峰厛閫夋嫨璁惧')
+ return
+ }
+ plcOperationLoading.value = true
+ try {
+ let response
+ switch (operation) {
+ case 'request':
+ response = await devicePlcApi.triggerRequests(ids)
+ break
+ case 'report':
+ response = await devicePlcApi.triggerReports(ids)
+ break
+ case 'reset':
+ response = await devicePlcApi.resetDevices(ids)
+ break
+ default:
+ throw new Error('鏈煡鐨凱LC鎿嶄綔绫诲瀷')
+ }
+ const results = response?.data || []
+ const successCount = results.filter(item => item.success).length
+ const label = plcOperationLabelMap[operation] || 'PLC鎿嶄綔'
+ if (results.length === 0) {
+ ElMessage.warning(`${label}鏈繑鍥炵粨鏋渀)
+ } else if (successCount === results.length) {
+ ElMessage.success(`${label}鎴愬姛锛�${successCount}/${results.length}锛塦)
+ } else {
+ ElMessage.warning(`${label}閮ㄥ垎鎴愬姛锛�${successCount}/${results.length}锛塦)
+ }
+ } catch (error) {
+ console.error('鎵цPLC鎿嶄綔澶辫触:', error)
+ const label = plcOperationLabelMap[operation] || 'PLC鎿嶄綔'
+ ElMessage.error(`${label}澶辫触锛�${error.response?.data?.message || error.message}`)
+ } finally {
+ plcOperationLoading.value = false
+ }
+}
+
+const handleSinglePlcRequest = (row) => executePlcOperation([row.id || row.deviceId], 'request')
+const handleSinglePlcReport = (row) => executePlcOperation([row.id || row.deviceId], 'report')
+const handleSinglePlcReset = (row) => executePlcOperation([row.id || row.deviceId], 'reset')
+
+const batchPlcRequest = () => executePlcOperation(getSelectedDeviceIds(), 'request')
+const batchPlcReport = () => executePlcOperation(getSelectedDeviceIds(), 'report')
+const batchPlcReset = () => executePlcOperation(getSelectedDeviceIds(), 'reset')
+
+const handleStatusChange = async (row) => {
+ try {
+ if (row.enabled) {
+ await deviceConfigApi.enable(row.id || row.deviceId)
+ ElMessage.success('璁惧鍚敤鎴愬姛')
+ } else {
+ await deviceConfigApi.disable(row.id || row.deviceId)
+ ElMessage.success('璁惧绂佺敤鎴愬姛')
+ }
+ emit('refresh-statistics')
+ loadDeviceList() // 鍒锋柊鍒楄〃
+ } catch (error) {
+ console.error('鏇存柊璁惧鐘舵�佸け璐�:', error)
+ row.enabled = !row.enabled // 鎭㈠鐘舵��
+ ElMessage.error('鏇存柊璁惧鐘舵�佸け璐�: ' + (error.response?.data?.message || error.message))
+ }
+}
+
+const batchEnable = async () => {
+ try {
+ const deviceIds = selectedDevices.value.map(item => item.id || item.deviceId)
+ await deviceConfigApi.batchEnable(deviceIds)
+ ElMessage.success(`鎴愬姛鍚敤 ${deviceIds.length} 涓澶嘸)
+ clearSelection()
+ loadDeviceList()
+ emit('refresh-statistics')
+ } catch (error) {
+ console.error('鎵归噺鍚敤澶辫触:', error)
+ ElMessage.error('鎵归噺鍚敤澶辫触: ' + (error.response?.data?.message || error.message))
+ }
+}
+
+const batchDisable = async () => {
+ try {
+ const deviceIds = selectedDevices.value.map(item => item.id || item.deviceId)
+ await deviceConfigApi.batchDisable(deviceIds)
+ ElMessage.success(`鎴愬姛绂佺敤 ${deviceIds.length} 涓澶嘸)
+ clearSelection()
+ loadDeviceList()
+ emit('refresh-statistics')
+ } catch (error) {
+ console.error('鎵归噺绂佺敤澶辫触:', error)
+ ElMessage.error('鎵归噺绂佺敤澶辫触: ' + (error.response?.data?.message || error.message))
+ }
+}
+
+const batchDelete = async () => {
+ try {
+ await ElMessageBox.confirm(
+ `纭畾瑕佸垹闄ら�変腑鐨� ${selectedDevices.value.length} 涓澶囧悧锛熸鎿嶄綔涓嶅彲鎭㈠锛乣,
+ '鎵归噺鍒犻櫎纭',
+ {
+ confirmButtonText: '纭畾鍒犻櫎',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning'
+ }
+ )
+
+ const deviceIds = selectedDevices.value.map(item => item.id || item.deviceId)
+ // 閫愪釜鍒犻櫎
+ for (const deviceId of deviceIds) {
+ await deviceConfigApi.delete(deviceId)
+ }
+ 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 healthCheck = async (row) => {
+ try {
+ const response = await deviceConfigApi.healthCheck(row.id || row.deviceId)
+ if (response && response.data) {
+ ElMessage.success(`璁惧鍋ュ悍妫�鏌ュ畬鎴愶紝鐘舵�侊細${response.data.status || '姝e父'}`)
+ } else {
+ ElMessage.success('璁惧鍋ュ悍妫�鏌ュ畬鎴�')
+ }
+ } catch (error) {
+ console.error('鍋ュ悍妫�鏌ュけ璐�:', error)
+ ElMessage.error('鍋ュ悍妫�鏌ュけ璐�: ' + (error.response?.data?.message || error.message))
+ }
+}
+
+const handleCommand = async (command, row) => {
+ switch (command) {
+ case 'view':
+ // 鏌ョ湅璇︽儏閫昏緫
+ ElMessage.info('鏌ョ湅璇︽儏鍔熻兘寮�鍙戜腑...')
+ break
+ case 'copy':
+ // 澶嶅埗閰嶇疆閫昏緫
+ ElMessage.info('澶嶅埗閰嶇疆鍔熻兘寮�鍙戜腑...')
+ break
+ case 'reset':
+ // 閲嶇疆璁惧閫昏緫
+ await ElMessageBox.confirm('纭畾瑕侀噸缃澶囬厤缃悧锛�', '閲嶇疆纭')
+ ElMessage.success('璁惧閲嶇疆鎴愬姛')
+ break
+ case 'plc-report':
+ await executePlcOperation([row.id || row.deviceId], 'report')
+ break
+ case 'plc-reset':
+ await executePlcOperation([row.id || row.deviceId], 'reset')
+ break
+ case 'delete':
+ if (row.isPrimary) {
+ ElMessage.warning('涓绘帶璁惧涓嶈兘鍒犻櫎')
+ return
+ }
+ await ElMessageBox.confirm('纭畾瑕佸垹闄よ璁惧鍚楋紵', '鍒犻櫎纭', {
+ confirmButtonText: '纭畾鍒犻櫎',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning'
+ })
+ await deviceConfigApi.delete(row.id || row.deviceId)
+ 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 = {
+ '涓婂ぇ杞�': 'primary',
+ '澶х悊鐗�': 'success',
+ '鐜荤拑瀛樺偍': 'warning'
+ }
+ 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 formatDateTime = (dateTime) => {
+ if (!dateTime) return '-'
+ return new Date(dateTime).toLocaleString()
+}
+
+// 鏆撮湶鏂规硶
+const refresh = () => {
+ loadDeviceList()
+}
+
+defineExpose({
+ refresh
+})
+
+// 缁勪欢鎸傝浇鏃跺姞杞芥暟鎹�
+onMounted(() => {
+ loadDeviceList()
+})
+</script>
+
+<style scoped>
+.device-config-list {
+ padding: 20px;
+}
+
+.search-section {
+ margin-bottom: 20px;
+ padding: 16px;
+ background-color: #f5f7fa;
+ border-radius: 8px;
+}
+
+.search-form {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+}
+
+.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;
+}
+
+: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