Selaa lähdekoodia

跟新智慧井盖菜单

丁烨烨 1 vuosi sitten
vanhempi
commit
61d1594b71

+ 1 - 0
index.html

@@ -12,6 +12,7 @@
 	  type="text/javascript"
 	  src="//api.map.baidu.com/api?type=webgl&v=1.0&ak=jWDCUpsk33htQsF6IEwk4ctkERTOFFH0"
 	></script>
+  <script type="text/javascript" src="https://code.bdstatic.com/bundle_sdk/2_0_0/bmaplib.markerclusterer.min.js"></script>
 	<script src="https://unpkg.com/mapv-three@1.0.10/dist/mapvthree.umd.js"></script>
 	<script src="//mapv.baidu.com/build/mapv.min.js"></script>
 	<script src="https://code.bdstatic.com/npm/mapvgl@1.0.0-beta.189/dist/mapvgl.min.js"></script>

+ 1 - 1
src/views/device/manhole/home/home-index.vue

@@ -154,7 +154,7 @@ function addMarkerEvents(marker, pointData) {
   });
 }
 
-// 7. 信息窗口管理
+// 7. 信息窗口 管理
 async function fetchDeviceInfo(deviceId) {
   try {
     const loading = ElLoading.service({ text: "正在获取设备信息..." });

+ 641 - 1
src/views/device/manhole/ldzh/bjgl.vue

@@ -1 +1,641 @@
-<template>报警管理</template>
+<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" }],
+  type: [{ 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="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="150" show-overflow-tooltip />
+      <el-table-column prop="type" label="类型" min-width="120" show-overflow-tooltip>
+        <template #default="{ row }">
+          {{ deviceType[row.type] }}
+        </template>
+      </el-table-column>
+      <el-table-column
+        prop="location"
+        label="位置"
+        min-width="150"
+        show-overflow-tooltip
+      />
+
+      <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 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
+        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>
+
+    <!-- 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 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.type]
+        }}</el-descriptions-item>
+        <el-descriptions-item label="位置">{{
+          currentDevice.location
+        }}</el-descriptions-item>
+        <el-descriptions-item label="型号">{{
+          currentDevice.model
+        }}</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 v-model="editDialogVisible" title="编辑设备" width="40%">
+      <el-form :model="editForm" label-width="100px">
+        <el-form-item label="设备名称">
+          <el-input v-model="editForm.deviceName" placeholder="请输入设备名称" />
+        </el-form-item>
+        <el-form-item label="位置">
+          <el-input
+            v-model="editForm.location"
+            placeholder="请输入位置 例如(xxxxx-xxxxx)"
+          />
+        </el-form-item>
+        <el-form-item label="备注">
+          <el-input v-model="editForm.remarks" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+      </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-input v-model="addForm.model" placeholder="请输入型号" />
+        </el-form-item>
+        <el-form-item label="类型" prop="model">
+          <el-select v-model="addForm.type" 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="请输入位置 例如(xxxxx-xxxxx)"
+          />
+        </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="addDialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="handleAdd">确认</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<style scoped>
+.device-table-container {
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+</style>