Преглед на файлове

feat(device): 重构设备管理页面

- 重新设计了设备管理页面的布局和样式
- 添加了设备类型字典数据
- 优化了设备列表的展示和操作
- 新增了设备预览、编辑和删除功能
- 重构了新增设备的表单和流程
- 优化了搜索和分页功能
nahida преди 1 година
родител
ревизия
bb6c87632e
променени са 6 файла, в които са добавени 580 реда и са изтрити 375 реда
  1. 13 15
      src/layout/components/Navbar.vue
  2. 5 5
      src/layout/index.vue
  3. 1 1
      src/store/modules/dict.js
  4. 3 10
      src/views/device/manhole/index.vue
  5. 554 342
      src/views/device/manhole/ldzh/jgkl.vue
  6. 4 2
      vite.config.js

+ 13 - 15
src/layout/components/Navbar.vue

@@ -9,22 +9,22 @@
       <template v-if="appStore.device !== 'mobile'">
         <header-search id="header-search" class="right-menu-item" />
 
-        <el-tooltip content="源码地址" effect="dark" placement="bottom">
-          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
-        </el-tooltip>
+<!--        <el-tooltip content="源码地址" effect="dark" placement="bottom">-->
+<!--          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />-->
+<!--        </el-tooltip>-->
 
-        <el-tooltip content="文档地址" effect="dark" placement="bottom">
-          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
-        </el-tooltip>
+<!--        <el-tooltip content="文档地址" effect="dark" placement="bottom">-->
+<!--          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />-->
+<!--        </el-tooltip>-->
 
         <screenfull id="screenfull" class="right-menu-item hover-effect" />
 
-        <el-tooltip content="主题模式" effect="dark" placement="bottom">
-          <div class="right-menu-item hover-effect theme-switch-wrapper" @click="toggleTheme">
-            <svg-icon v-if="settingsStore.isDark" icon-class="sunny" />
-            <svg-icon v-if="!settingsStore.isDark" icon-class="moon" />
-          </div>
-        </el-tooltip>
+<!--        <el-tooltip content="主题模式" effect="dark" placement="bottom">-->
+<!--          <div class="right-menu-item hover-effect theme-switch-wrapper" @click="toggleTheme">-->
+<!--            <svg-icon v-if="settingsStore.isDark" icon-class="sunny" />-->
+<!--            <svg-icon v-if="!settingsStore.isDark" icon-class="moon" />-->
+<!--          </div>-->
+<!--        </el-tooltip>-->
 
         <el-tooltip content="布局大小" effect="dark" placement="bottom">
           <size-select id="size-select" class="right-menu-item hover-effect" />
@@ -56,15 +56,13 @@
 </template>
 
 <script setup>
-import { ElMessageBox } from 'element-plus'
+import {ElMessageBox} from 'element-plus'
 import Breadcrumb from '@/components/Breadcrumb'
 import TopNav from '@/components/TopNav'
 import Hamburger from '@/components/Hamburger'
 import Screenfull from '@/components/Screenfull'
 import SizeSelect from '@/components/SizeSelect'
 import HeaderSearch from '@/components/HeaderSearch'
-import RuoYiGit from '@/components/RuoYi/Git'
-import RuoYiDoc from '@/components/RuoYi/Doc'
 import useAppStore from '@/store/modules/app'
 import useUserStore from '@/store/modules/user'
 import useSettingsStore from '@/store/modules/settings'

+ 5 - 5
src/layout/index.vue

@@ -43,20 +43,20 @@
         <tags-view v-if="needTagsView" />
       </div>
       <app-main />
-      <settings ref="settingRef" />   
+      <settings ref="settingRef" />
     </div>
   </div>
 </template>
 
 <script setup>
-import { useWindowSize } from '@vueuse/core'
-import { AppMain, Navbar, Settings, TagsView } from './components'
+import {useWindowSize} from '@vueuse/core'
+import {AppMain, Navbar, Settings, TagsView} from './components'
 
 import useAppStore from '@/store/modules/app'
 import useSettingsStore from '@/store/modules/settings'
 import usePermissionStore from "@/store/modules/permission.js";
-import { useRouter } from "vue-router";
-import { Search } from "@element-plus/icons-vue";
+import {useRouter} from "vue-router";
+import {Search} from "@element-plus/icons-vue";
 
 const settingsStore = useSettingsStore()
 const theme = computed(() => settingsStore.theme);

+ 1 - 1
src/store/modules/dict.js

@@ -2,7 +2,7 @@ const useDictStore = defineStore(
   'dict',
   {
     state: () => ({
-      dict: new Array()
+      dict: new Array("device_type")
     }),
     actions: {
       // 获取字典

+ 3 - 10
src/views/device/manhole/index.vue

@@ -1,13 +1,6 @@
 <script setup>
-import { ref } from "vue";
-import {
-  Menu as IconMenu,
-  House,
-  Monitor,
-  Bell,
-  Location,
-  Setting,
-} from "@element-plus/icons-vue";
+import {ref} from "vue";
+import {Location, Menu as IconMenu,} from "@element-plus/icons-vue";
 import HomeIndex from "./home/home-index.vue";
 //资产管理
 import znzdgl from "./zcgl/znzdgl.vue";
@@ -107,7 +100,7 @@ const handleSelect = (key) => {
       </div>
 
       <el-menu
-        default-active="0"
+        default-active="1"
         class="border-none"
         :collapse="isCollapse"
         background-color="#1f2937"

+ 554 - 342
src/views/device/manhole/ldzh/jgkl.vue

@@ -1,375 +1,587 @@
+<script setup>
+import {computed, onMounted, ref, watch} from 'vue'
+import {AlertTriangle, Plus, RefreshCw, Search, Trash2, Wifi, WifiOff} from 'lucide-vue-next'
+import {ElMessage, ElMessageBox} from 'element-plus'
+import request from "@/utils/request.js"
+import {getDicts} from "@/api/system/dict/data.js";
+
+// Data
+const deviceArr = ref([])
+const search = ref({
+  deviceName: ""
+})
+const loading = ref(false)
+const total = ref(0)
+const currentPage = ref(1)
+const pageSize = ref(10)
+const deviceType = ref({});
+
+
+// 预览对话框
+const previewDialogVisible = ref(false)
+const currentDevice = ref({})
+
+// 编辑对话框
+const editDialogVisible = ref(false)
+const editForm = ref({
+  id: '',
+  deviceName: '',
+  location: '',
+  remarks: ''
+})
+
+// 新增对话框
+const addDialogVisible = ref(false)
+const addForm = ref({
+  deviceName: '',
+  deviceNumber: '',
+  type: '1', // 默认值为1,根据之前的查询条件
+  model: '',
+  location: '',
+  remarks: ''
+})
+const addFormRules = {
+  deviceName: [
+    { required: true, message: '请输入设备名称', trigger: 'blur' }
+  ],
+  deviceNumber: [
+    { required: true, message: '请输入设备编号', trigger: 'blur' }
+  ],
+  model: [
+    { required: true, message: '请输入设备型号', trigger: 'blur' }
+  ]
+}
+const addFormRef = ref(null)
+
+// 多选相关
+const multipleSelection = ref([])
+const hasSelected = computed(() => multipleSelection.value.length > 0)
+
+// Methods
+const getAllDeviceInfo = async () => {
+  loading.value = true
+  try {
+    const arr = [
+      {
+        column: "type",
+        type: "eq",
+        value: "1"
+      }
+    ]
+
+    if (search.value.deviceName) {
+      arr.push({
+        column: "device_name",
+        type: "like",
+        value: search.value.deviceName
+      })
+    }
+
+    const res = await request.get("/base/devices/findByPage", {
+      params: {
+        conditionJson: encodeURIComponent(JSON.stringify(arr)),
+        pageNum: currentPage.value,
+        pageSize: pageSize.value
+      }
+    })
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+      return
+    }
+
+    deviceArr.value = res.data.records
+    total.value = res.data.total
+  } catch (error) {
+    ElMessage.error('获取设备数据失败')
+    console.error(error)
+  } finally {
+    loading.value = false
+  }
+}
+
+const handleSearch = () => {
+  currentPage.value = 1
+  getAllDeviceInfo()
+}
+
+const handleReset = () => {
+  search.value.deviceName = ""
+  currentPage.value = 1
+  getAllDeviceInfo()
+}
+
+const handleSizeChange = (val) => {
+  pageSize.value = val
+  getAllDeviceInfo()
+}
+
+const handleCurrentChange = (val) => {
+  currentPage.value = val
+  getAllDeviceInfo()
+}
+
+// Format date
+const formatDate = (dateString) => {
+  if (!dateString) return '-'
+  const date = new Date(dateString)
+  return date.toLocaleString()
+}
+
+// Watch for search changes
+watch(() => search.value.deviceName, (newVal, oldVal) => {
+  if (newVal === '' && oldVal !== '') {
+    handleSearch()
+  }
+})
+
+// 预览设备信息
+const handlePreview = async (id) => {
+  try {
+    const res = await request.get("/base/devices/getById/" + id)
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+      return
+    }
+    currentDevice.value = res.data
+    previewDialogVisible.value = true
+  } catch (error) {
+    ElMessage.error('获取设备详情失败')
+    console.error(error)
+  }
+}
+
+// 打开编辑对话框
+const openEditDialog = async (id) => {
+  try {
+    const res = await request.get("/base/devices/getById/" + id)
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+      return
+    }
+
+    editForm.value = {
+      id: res.data.id,
+      deviceName: res.data.deviceName,
+      location: res.data.location,
+      remarks: res.data.remarks
+    }
+
+    editDialogVisible.value = true
+  } catch (error) {
+    ElMessage.error('获取设备详情失败')
+    console.error(error)
+  }
+}
+
+// 提交编辑表单
+const handleEdit = async () => {
+  try {
+    const res = await request.post('/base/devices/update', editForm.value)
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+      return
+    }
+
+    ElMessage.success('修改成功')
+    editDialogVisible.value = false
+    getAllDeviceInfo() // 刷新列表
+  } catch (error) {
+    ElMessage.error('修改设备信息失败')
+    console.error(error)
+  }
+}
+
+// 打开新增对话框
+const openAddDialog = () => {
+  addForm.value = {
+    deviceName: '',
+    deviceNumber: '',
+    type: '1',
+    model: '',
+    location: '',
+    remarks: ''
+  }
+  addDialogVisible.value = true
+}
+
+// 提交新增表单
+const handleAdd = async () => {
+  if (!addFormRef.value) return
+
+  addFormRef.value.validate(async (valid) => {
+    if (!valid) return
+
+    try {
+      const res = await request.post('/base/devices/save', addForm.value)
+
+      if (res.code !== 200) {
+        ElMessage.error(res.msg)
+        return
+      }
+
+      ElMessage.success('新增设备成功')
+      addDialogVisible.value = false
+      getAllDeviceInfo() // 刷新列表
+    } catch (error) {
+      ElMessage.error('新增设备失败')
+      console.error(error)
+    }
+  })
+}
+
+// 处理多选
+const handleSelectionChange = (val) => {
+  multipleSelection.value = val
+}
+
+// 删除单个设备
+const handleDelete = async (id) => {
+  try {
+    await ElMessageBox.confirm('确认删除该设备吗?此操作不可恢复', '警告', {
+      confirmButtonText: '确认',
+      cancelButtonText: '取消',
+      type: 'warning'
+    })
+
+    const res = await request.delete('/base/devices/delete', {
+      data: [id]
+    })
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+      return
+    }
+
+    ElMessage.success('删除成功')
+    getAllDeviceInfo() // 刷新列表
+  } catch (error) {
+    if (error !== 'cancel') {
+      ElMessage.error('删除设备失败')
+      console.error(error)
+    }
+  }
+}
+
+// 批量删除设备
+const handleBatchDelete = async () => {
+  if (multipleSelection.value.length === 0) {
+    ElMessage.warning('请至少选择一个设备')
+    return
+  }
+
+  try {
+    await ElMessageBox.confirm(
+        `确认删除选中的 ${multipleSelection.value.length} 个设备吗?此操作不可恢复`,
+        '警告',
+        {
+          confirmButtonText: '确认',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }
+    )
+
+    const ids = multipleSelection.value.map(item => item.id)
+
+    const res = await request.delete('/base/devices/delete', {
+      data: ids
+    })
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg)
+      return
+    }
+
+    ElMessage.success('批量删除成功')
+    getAllDeviceInfo() // 刷新列表
+  } catch (error) {
+    if (error !== 'cancel') {
+      ElMessage.error('批量删除设备失败')
+      console.error(error)
+    }
+  }
+}
+
+const getDeviceType = async () => {
+  const res = await getDicts('device_type');
+  if(res.code !== 200){
+    ElMessage.error(res.msg)
+    return;
+  }
+  deviceType.value = res.data?.reduce((acc, cur) => {
+    acc[cur.dictValue] = cur.dictLabel;
+    return acc;
+  },{})
+  console.log(deviceType.value);
+}
+
+onMounted(() => {
+  getAllDeviceInfo();
+  getDeviceType();
+})
+</script>
+
 <template>
-  <div class="p-5">
-    <!-- 搜索表单 -->
-    <el-form :model="searchForm" label-width="80px">
-      <el-row :gutter="20">
-        <el-col :span="6">
-          <el-form-item label="井盖编号">
-            <el-input v-model="searchForm.id" placeholder="请输入井盖编号"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="6">
-          <el-form-item label="井盖名称">
-            <el-input v-model="searchForm.name" placeholder="请输入井盖名称"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item>
-            <el-button type="primary" @click="search">搜索</el-button>
-            <el-button type="success" @click="addmanholeVisible = true"
-              >添加井盖</el-button
-            >
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
-
-    <!-- 表格 -->
-    <el-table :data="filteredTableData" border>
-      <!-- 设备名称列 -->
-      <el-table-column prop="deviceName" label="设备名称">
-        <template #default="{ row }">
-          <el-input
-            v-if="row.isEditing"
-            v-model="tableData.deviceName"
-            placeholder="请输入设备名称"
-            size="small"
-          />
-          <span v-else>{{ row.deviceName }}</span>
+  <div class="device-table-container p-4">
+    <!-- Header with search -->
+    <div class="mb-4 flex justify-between items-center">
+      <div class="text-xl font-bold">设备管理</div>
+      <div class="flex gap-2">
+        <el-input
+            v-model="search.deviceName"
+            placeholder="搜索设备名称"
+            class="w-64"
+            clearable
+            @keyup.enter="handleSearch"
+        >
+          <template #prefix>
+            <Search class="w-4 h-4 text-gray-400"/>
+          </template>
+        </el-input>
+        <el-button type="primary" @click="handleSearch" class="flex items-center">
+          <Search class="w-4 h-4 mr-1"/>
+          搜索
+        </el-button>
+        <el-button @click="handleReset" class="flex items-center">
+          <RefreshCw class="w-4 h-4 mr-1"/>
+          重置
+        </el-button>
+      </div>
+    </div>
+
+    <!-- 操作按钮 -->
+    <div class="mb-4 flex justify-between">
+      <div class="flex gap-2">
+        <el-button
+            type="primary"
+            @click="openAddDialog"
+            class="flex items-center"
+        >
+          <Plus class="w-4 h-4 mr-1"/>
+          新增设备
+        </el-button>
+
+        <el-button
+            type="danger"
+            :disabled="!hasSelected"
+            @click="handleBatchDelete"
+            class="flex items-center"
+        >
+          <Trash2 class="w-4 h-4 mr-1"/>
+          批量删除
+        </el-button>
+        <span class="ml-2 text-gray-500 flex items-center" v-if="hasSelected">
+          已选择 {{ multipleSelection.length }} 项
+        </span>
+      </div>
+
+    </div>
+
+    <!-- Table -->
+    <el-table
+        :data="deviceArr"
+        border
+        stripe
+        style="width: 100%"
+        v-loading="loading"
+        class="mb-4"
+        @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column type="index" label="序号" width="60" align="center"/>
+      <el-table-column prop="deviceName" label="设备名称" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="deviceNumber" label="设备编号" min-width="150" show-overflow-tooltip/>
+      <el-table-column prop="model" label="型号" min-width="120" show-overflow-tooltip>
+        <template #default="{row}">
+          {{deviceType[row.model]}}
         </template>
       </el-table-column>
+      <el-table-column prop="location" label="位置" min-width="150" show-overflow-tooltip/>
 
-      <!-- <el-table-column prop="deviceName" label="设备名称"></el-table-column> -->
-      <el-table-column prop="deviceNumber" label="设备编号"></el-table-column>
-      <el-table-column prop="type" label="设备类型"></el-table-column>
-      <el-table-column prop="model" label="设备型号"></el-table-column>
-      <el-table-column prop="location" label="位置"></el-table-column>
-      <el-table-column prop="alarmStatus" label="	报警状态"></el-table-column>
-      <el-table-column prop="onlineStatus" label="在线状态"></el-table-column>
-
-      <el-table-column prop="createTime" label="创建时间" width="200"></el-table-column>
-      <el-table-column prop="updateTime" label="修改时间" width="200"></el-table-column>
-      <el-table-column prop="remarks" label="	备注"></el-table-column>
-
-      <!-- 状态列 -->
-      <!-- <el-table-column prop="onlineStatus" label="状态">
-        <template slot-scope="{ row }">
-          <div :class="['status-cell', row.status + '-status']">
-            {{ row.onlineStatus === "0" ? "在线" : "离线" }}
+      <el-table-column label="在线状态" width="120" align="center">
+        <template #default="scope">
+          <div class="flex items-center justify-center">
+            <span v-if="scope.row.onlineStatus === 1" class="flex items-center text-green-500">
+              <Wifi class="w-4 h-4 mr-1"/>
+              在线
+            </span>
+            <span v-else class="flex items-center text-gray-500">
+              <WifiOff class="w-4 h-4 mr-1"/>
+              离线
+            </span>
           </div>
         </template>
-      </el-table-column> -->
+      </el-table-column>
 
-      <!-- <el-table-column label="操作">
-        <template #default="{ row, $index }">
-          <el-button size="small" type="primary" :icon="Edit" circle @click="alterManholePost(row, $index)" />
-          <el-button size="small" type="danger" :icon="Delete" circle />
-          <el-button size="small" :icon="Search" circle @click="showDetail(scope.row)" />
+      <el-table-column label="告警状态" width="120" align="center">
+        <template #default="scope">
+          <el-tag :type="scope.row.alarmStatus === 0 ? 'success' : 'danger'" effect="dark">
+            <div class="flex items-center">
+              <AlertTriangle v-if="scope.row.alarmStatus === 1" class="w-4 h-4 mr-1"/>
+              {{ scope.row.alarmStatus === 0 ? '正常' : '告警' }}
+            </div>
+          </el-tag>
         </template>
-      </el-table-column> -->
-
-      <el-table-column label="操作" width="200">
-        <template #default="{ row, $index }">
-          <div class="action-buttons">
-            <template v-if="row.isEditing">
-              <el-button type="success" size="small" @click="handleSave(row, $index)">
-                保存
-              </el-button>
-              <el-button type="info" size="small" @click="handleCancel(row)">
-                取消
-              </el-button>
-            </template>
-            <template v-else>
-              <el-button
-                size="small"
-                type="primary"
-                :icon="Edit"
-                circle
-                @click="alterManholePost(row, $index)"
-              />
-              <el-button size="small" type="danger" :icon="Delete" circle />
-              <el-button
-                size="small"
-                :icon="Search"
-                circle
-                @click="showDetail(scope.row)"
-              />
-            </template>
-          </div>
+      </el-table-column>
+
+      <el-table-column prop="remarks" label="备注" min-width="150" show-overflow-tooltip/>
+
+      <el-table-column label="创建时间" min-width="180" show-overflow-tooltip>
+        <template #default="scope">
+          {{ formatDate(scope.row.createTime) }}
+        </template>
+      </el-table-column>
+
+      <el-table-column label="更新时间" min-width="180" show-overflow-tooltip>
+        <template #default="scope">
+          {{ formatDate(scope.row.updateTime) }}
+        </template>
+      </el-table-column>
+
+      <el-table-column label="操作" fixed="right" width="220" align="center">
+        <template #default="scope">
+          <el-button type="primary" link size="small" @click="handlePreview(scope.row.id)">预览</el-button>
+          <el-button type="primary" link size="small" @click="openEditDialog(scope.row.id)">编辑</el-button>
+          <el-button type="danger" link size="small" @click="handleDelete(scope.row.id)">删除</el-button>
         </template>
       </el-table-column>
     </el-table>
 
-    <!-- 查看详情弹窗 -->
-    <el-dialog title="井盖详情" v-model="dialogVisible">
-      <el-descriptions :column="1">
-        <el-descriptions-item label="设备名称">{{
-          selectedCover.deviceName
-        }}</el-descriptions-item>
-        <el-descriptions-item label="设备编号">{{
-          selectedCover.deviceNumber
-        }}</el-descriptions-item>
-        <el-descriptions-item label="设备类型">{{
-          selectedCover.type
-        }}</el-descriptions-item>
-        <el-descriptions-item label="设备型号">{{
-          selectedCover.model
-        }}</el-descriptions-item>
-        <el-descriptions-item label="位置">{{
-          selectedCover.location
-        }}</el-descriptions-item>
-        <el-descriptions-item label="报警状态">{{
-          selectedCover.alarmStatus
-        }}</el-descriptions-item>
-        <el-descriptions-item label="在线状态">{{
-          selectedCover.onlineStatus
-        }}</el-descriptions-item>
-        <el-descriptions-item label="创建时间">{{
-          selectedCover.createTime
-        }}</el-descriptions-item>
-        <el-descriptions-item label="	修改时间">{{
-          selectedCover.updateTime
-        }}</el-descriptions-item>
-        <el-descriptions-item label="备注">{{
-          selectedCover.remarks
-        }}</el-descriptions-item>
-      </el-descriptions>
-    </el-dialog>
+    <!-- Pagination -->
+    <div class="flex justify-end">
+      <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="total"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          background
+      />
+    </div>
 
-    <!-- 修改井盖弹窗 -->
-    <el-dialog title="井盖详情" v-model="alterVisible">
-      <el-descriptions :column="1">
-        <el-descriptions-item label="设备名称">{{
-          selectedCover.deviceName
-        }}</el-descriptions-item>
-        <el-descriptions-item label="设备编号">{{
-          selectedCover.deviceNumber
-        }}</el-descriptions-item>
-        <el-descriptions-item label="设备类型">{{
-          selectedCover.type
-        }}</el-descriptions-item>
-        <el-descriptions-item label="设备型号">{{
-          selectedCover.model
-        }}</el-descriptions-item>
-        <el-descriptions-item label="位置">{{
-          selectedCover.location
-        }}</el-descriptions-item>
-        <el-descriptions-item label="报警状态">{{
-          selectedCover.alarmStatus
-        }}</el-descriptions-item>
-        <el-descriptions-item label="在线状态">{{
-          selectedCover.onlineStatus
-        }}</el-descriptions-item>
-        <el-descriptions-item label="创建时间">{{
-          selectedCover.createTime
-        }}</el-descriptions-item>
-        <el-descriptions-item label="	修改时间">{{
-          selectedCover.updateTime
-        }}</el-descriptions-item>
-        <el-descriptions-item label="备注">{{
-          selectedCover.remarks
-        }}</el-descriptions-item>
+    <!-- 预览对话框 -->
+    <el-dialog
+        v-model="previewDialogVisible"
+        title="设备详情"
+        width="50%"
+    >
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="设备名称">{{ currentDevice.deviceName }}</el-descriptions-item>
+        <el-descriptions-item label="设备编号">{{ currentDevice.deviceNumber }}</el-descriptions-item>
+        <el-descriptions-item label="型号">{{ deviceType[currentDevice.model] }}</el-descriptions-item>
+        <el-descriptions-item label="位置">{{ currentDevice.location }}</el-descriptions-item>
+        <el-descriptions-item label="在线状态">
+          <span v-if="currentDevice.onlineStatus === 1" class="flex items-center text-green-500">
+            <Wifi class="w-4 h-4 mr-1"/>
+            在线
+          </span>
+          <span v-else class="flex items-center text-gray-500">
+            <WifiOff class="w-4 h-4 mr-1"/>
+            离线
+          </span>
+        </el-descriptions-item>
+        <el-descriptions-item label="告警状态">
+          <el-tag :type="currentDevice.alarmStatus === 0 ? 'success' : 'danger'" effect="dark">
+            <div class="flex items-center">
+              <AlertTriangle v-if="currentDevice.alarmStatus === 1" class="w-4 h-4 mr-1"/>
+              {{ currentDevice.alarmStatus === 0 ? '正常' : '告警' }}
+            </div>
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="备注" :span="2">{{ currentDevice.remarks }}</el-descriptions-item>
+        <el-descriptions-item label="创建时间" :span="2">{{
+            formatDate(currentDevice.createTime)
+          }}
+        </el-descriptions-item>
+        <el-descriptions-item label="更新时间" :span="2">{{
+            formatDate(currentDevice.updateTime)
+          }}
+        </el-descriptions-item>
       </el-descriptions>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="previewDialogVisible = false">关闭</el-button>
+        </span>
+      </template>
     </el-dialog>
 
-    <!-- 添加井盖弹窗 -->
-    <el-dialog title="添加井盖" v-model="addmanholeVisible" width="50%">
-      <el-form :model="addForm" ref="AddSaveRef" label-width="80px">
+    <!-- 编辑对话框 -->
+    <el-dialog
+        v-model="editDialogVisible"
+        title="编辑设备"
+        width="40%"
+    >
+      <el-form :model="editForm" label-width="100px">
         <el-form-item label="设备名称">
-          <el-input
-            v-model="addForm.deviceName"
-            placeholder="请输入井盖设备名称"
-          ></el-input>
-        </el-form-item>
-        <el-form-item label="设备编号">
-          <el-input
-            v-model="addForm.deviceNumber"
-            placeholder="请输入井盖设备编号"
-          ></el-input>
+          <el-input v-model="editForm.deviceName" placeholder="请输入设备名称"/>
         </el-form-item>
         <el-form-item label="位置">
-          <el-input v-model="addForm.location" placeholder="请输入井盖位置"></el-input>
-        </el-form-item>
-        <el-form-item label="设备型号">
-          <el-input v-model="addForm.model" placeholder="请输入井盖设备型号"></el-input>
+          <el-input v-model="editForm.location" placeholder="请输入位置"/>
         </el-form-item>
         <el-form-item label="备注">
-          <el-input v-model="addForm.remarks" placeholder="请输入井盖备注"></el-input>
+          <el-input v-model="editForm.remarks" type="textarea" placeholder="请输入备注"/>
         </el-form-item>
-        <el-form-item label="设备类型">
-          <el-input v-model="addForm.type" placeholder="请输入井盖设备类型"></el-input>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="editDialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="handleEdit">确认</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <!-- 新增对话框 -->
+    <el-dialog
+        v-model="addDialogVisible"
+        title="新增设备"
+        width="40%"
+    >
+      <el-form
+          ref="addFormRef"
+          :model="addForm"
+          :rules="addFormRules"
+          label-width="100px"
+      >
+        <el-form-item label="设备名称" prop="deviceName">
+          <el-input v-model="addForm.deviceName" placeholder="请输入设备名称"/>
+        </el-form-item>
+        <el-form-item label="设备编号" prop="deviceNumber">
+          <el-input v-model="addForm.deviceNumber" placeholder="请输入设备编号"/>
+        </el-form-item>
+        <el-form-item label="型号" prop="model">
+          <el-select v-model="addForm.model" placeholder="请输入设备型号">
+            <el-option
+                v-for="(item,index) in deviceType"
+                :key="item.value"
+                :label="item"
+                :value="index"
+                :disabled="index !== '1'"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="位置">
+          <el-input v-model="addForm.location" placeholder="请输入位置"/>
+        </el-form-item>
+        <el-form-item label="备注">
+          <el-input v-model="addForm.remarks" type="textarea" placeholder="请输入备注"/>
         </el-form-item>
       </el-form>
       <template #footer>
         <span class="dialog-footer">
-          <el-button @click="resetAddForm">取消</el-button>
-          <el-button type="primary" @click="handleAddSubmit">确定</el-button>
+          <el-button @click="addDialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="handleAdd">确认</el-button>
         </span>
       </template>
     </el-dialog>
   </div>
 </template>
 
-<script setup>
-import { getManholeDataAll, addSave, alterManhole } from "@/api/ldzh/index";
-import { computed, ref } from "vue";
-import { Delete, Edit, Search } from "@element-plus/icons-vue";
-// 表格数据
-const tableData = ref();
-const { proxy } = getCurrentInstance();
-
-// 搜索条件
-const searchForm = ref({
-  id: "",
-  name: "",
-  district: "",
-  street: "",
-  road: "",
-  location: "",
-});
-
-// 控制新增井盖表单的显示与隐藏
-const addmanholeVisible = ref(false);
-// 是否显示详情弹窗
-const dialogVisible = ref(false);
-// 是否显示修改弹窗
-const alterVisible = ref(false);
-// 当前选中的井盖信息
-const selectedCover = ref({});
-
-// 根据搜索条件过滤数据
-const filteredTableData = computed(() => {
-  if (!Object.values(searchForm.value).some((value) => value)) {
-    return tableData.value;
-  }
-
-  return tableData.value.filter((row) => {
-    const matches = [
-      searchForm.value.id && row.id.includes(searchForm.value.id),
-      searchForm.value.name && row.name.includes(searchForm.value.name),
-      searchForm.value.district && row.district.includes(searchForm.value.district),
-      searchForm.value.street && row.street.includes(searchForm.value.street),
-      searchForm.value.road && row.road.includes(searchForm.value.road),
-      searchForm.value.location && row.location.includes(searchForm.value.location),
-    ];
-    return matches.some((match) => match);
-  });
-});
-
-// 搜索逻辑
-function search() {}
-
-// 显示详情
-function showDetail(row) {
-  selectedCover.value = row;
-  dialogVisible.value = true;
-}
-// 新增井盖表单数据
-const addForm = ref({
-  deviceName: "",
-  deviceNumber: "",
-  location: "",
-  model: "",
-  remarks: "",
-  type: "",
-});
-
-// 处理新增井盖表单提交
-function handleAddSubmit() {
-  addSave(addForm.value).then((response) => {
-    proxy.$modal.msgSuccess("新增成功");
-    addmanholeVisible.value = false;
-    getManholeAllData();
-  });
+<style scoped>
+.device-table-container {
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
 }
-
-// 修改井盖表单数据
-const editForm = ref({
-  deviceName: "",
-  type: "",
-  location: "",
-  model: "",
-  remarks: "",
-});
-
-// 原始数据备份
-const originalData = ref({});
-// 进入编辑模式
-const alterManholePost = (row) => {
-  // 关闭其他行的编辑状态
-  tableData.value.forEach((item) => (item.isEditing = false));
-  // 备份原始数据
-  originalData.value = { ...row };
-  // 开启当前行编辑
-  row.isEditing = true;
-  console.log(123, editForm);
-
-  Object.assign(editForm, row);
-};
-
-// 保存修改
-const handleSave = (row, index) => {
-  if (!validateForm()) return;
-
-  Object.assign(row, editForm);
-  row.isEditing = false;
-  proxy.$modal.msgSuccess("保存成功");
-};
-
-// 取消修改
-const handleCancel = (row) => {
-  Object.assign(row, originalData.value);
-  row.isEditing = false;
-  proxy.$modal.msgSuccess("修改已取消");
-};
-
-// // 处理修改井盖表单提交
-// function alterManholePost(res) {
-//   console.log(112, res);
-//   selectedCover.value = res;
-
-//   alterVisible.value = true;
-
-//   // alterManhole(addForm.value).then((response) => {
-//   //   proxy.$modal.msgSuccess("修改成功");
-//   //   addmanholeVisible.value = false;
-//   //   getManholeAllData();
-//   // });
-// }
-
-// 表单验证
-const validateForm = () => {
-  if (!editForm.deviceName?.trim()) {
-    proxy.$modal.msgError("设备名称不能为空");
-    return false;
-  }
-
-  return true;
-};
-
-// 清空新增井盖表单
-function resetAddForm() {
-  addForm.value = {
-    deviceName: "",
-    deviceNumber: "",
-    model: "",
-    model: "",
-    remarks: "",
-    type: "",
-  };
-  addmanholeVisible.value = false;
-}
-
-//获取井盖全部信息
-function getManholeAllData() {
-  getManholeDataAll().then((res) => {
-    tableData.value = res.data;
-    for (var i = 0; i < tableData.value.length; i++) {
-      tableData.value[i].isEditing = false;
-    }
-  });
-}
-getManholeAllData();
-</script>
-
-<style scoped lang="scss"></style>
+</style>

+ 4 - 2
vite.config.js

@@ -1,4 +1,4 @@
-import { defineConfig, loadEnv } from 'vite'
+import {defineConfig, loadEnv} from 'vite'
 import path from 'path'
 import createVitePlugins from './vite/plugins'
 
@@ -36,7 +36,9 @@ export default defineConfig(({ mode, command }) => {
         },
         // https://cn.vitejs.dev/config/#server-proxy
         '/dev-api': {
-          target: 'http://192.168.110.235:8100/background',
+          // target: 'http://192.168.110.235:8100/background',
+          target: 'http://localhost:8100/background',
+          // target: 'http://localhost:8101/',
           changeOrigin: true,
           rewrite: (p) => p.replace(/^\/dev-api/, '')
         },