Переглянути джерело

feat(device): 新增灯杆设备管理功能

- 添加灯杆设备列表页面,支持搜索、新增、编辑、删除操作
- 实现灯杆设备详情查看功能
- 优化表格展示,增加分页和批量删除功能
-增加表单验证,确保数据完整性
nahida 1 рік тому
батько
коміт
a07b365c36
1 змінених файлів з 526 додано та 0 видалено
  1. 526 0
      src/views/device/pole/index.vue

+ 526 - 0
src/views/device/pole/index.vue

@@ -0,0 +1,526 @@
+<script setup>
+import request from "@/utils/request.js";
+import {onMounted, reactive, ref} from "vue";
+import {
+  ElButton,
+  ElDialog,
+  ElForm,
+  ElFormItem,
+  ElInput,
+  ElMessage,
+  ElMessageBox,
+  ElPagination,
+  ElTable,
+  ElTableColumn
+} from "element-plus";
+import PoleDetail from "@/views/device/pole/pole-detail.vue";
+
+const poleList = ref([]);
+const loading = ref(false);
+const total = ref(0);
+const currentPage = ref(1);
+const pageSize = ref(10);
+const search = ref({
+  deviceName: "",
+});
+
+// 表格多选
+const multipleSelection = ref([]);
+const handleSelectionChange = (val) => {
+  multipleSelection.value = val;
+};
+
+// 对话框控制
+const dialogVisible = ref(false);
+const dialogTitle = ref('');
+const formMode = ref('add'); // 'add' or 'edit'
+
+// 详情对话框控制
+const detailDialogVisible = ref(false);
+const currentCheckDevice = ref('');
+const currentDeviceName = ref('');
+
+// 表单数据
+const formData = reactive({
+  id: '',
+  deviceName: '',
+  deviceNumber: '',
+  model: '',
+  location: '',
+  alarmStatus: '1', // 保留在数据中,但不在表单中显示
+  remarks: '',
+  type: '3' // 固定值
+});
+
+// 表单规则
+const rules = {
+  deviceName: [{ required: true, message: '请输入灯杆名称', trigger: 'blur' }],
+  deviceNumber: [{ required: true, message: '请输入灯杆编号', trigger: 'blur' }]
+};
+
+const formRef = ref(null);
+
+const getList = async () => {
+  loading.value = true;
+  try {
+    const arr = [];
+    arr.push({
+      column: "type",
+      type: "eq",
+      value: "3",
+    });
+    arr.push({
+      column: "create_time",
+      type: "orderByDesc",
+    });
+
+    if(search.value.deviceName){
+      arr.push({
+        column: "device_name",
+        type: "like",
+        value: search.value.deviceName,
+      });
+    }
+
+    const res = await request.get("/base/devices/findByPage", {
+      params: {
+        pageNum: currentPage.value,
+        pageSize: pageSize.value,
+        conditionJson: encodeURIComponent(JSON.stringify(arr))
+      }
+    });
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg);
+      return;
+    }
+
+    poleList.value = res.data.records;
+    total.value = res.data.total;
+  } catch (error) {
+    ElMessage.error("获取数据失败");
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索
+const handleSearch = () => {
+  currentPage.value = 1;
+  getList();
+};
+
+// 重置搜索
+const resetSearch = () => {
+  search.value.deviceName = '';
+  currentPage.value = 1;
+  getList();
+};
+
+// 打开新增对话框
+const openAddDialog = () => {
+  formMode.value = 'add';
+  dialogTitle.value = '新增灯杆设备';
+  // 重置表单
+  Object.assign(formData, {
+    id: '',
+    deviceName: '',
+    deviceNumber: '',
+    model: '',
+    location: '',
+    alarmStatus: '1', // 默认值,但不在表单中显示
+    remarks: '',
+    type: '3'
+  });
+  dialogVisible.value = true;
+};
+
+// 打开编辑对话框
+const openEditDialog = async (row) => {
+  formMode.value = 'edit';
+  dialogTitle.value = '编辑灯杆设备';
+
+  try {
+    // 获取最新的设备信息
+    const deviceInfo = await getDeviceInfo(row.id);
+    if (deviceInfo) {
+      Object.assign(formData, {
+        id: deviceInfo.id,
+        deviceName: deviceInfo.deviceName,
+        deviceNumber: deviceInfo.deviceNumber,
+        model: deviceInfo.model || '',
+        location: deviceInfo.location || '',
+        alarmStatus: deviceInfo.alarmStatus, // 保留原值,但不在表单中显示
+        remarks: deviceInfo.remarks || '',
+        type: '3'
+      });
+      dialogVisible.value = true;
+    }
+  } catch (error) {
+    ElMessage.error("获取设备信息失败");
+  }
+};
+
+// 提交表单
+const submitForm = async () => {
+  if (!formRef.value) return;
+
+  await formRef.value.validate(async (valid) => {
+    if (valid) {
+      if (formMode.value === 'add') {
+        await addDevice();
+      } else {
+        await updateDevice(formData);
+      }
+      dialogVisible.value = false;
+    }
+  });
+};
+
+// 更新设备信息的方法
+const updateDevice = async (data) => {
+  try {
+    const res = await request.post("/base/devices/update", {
+      id: data.id,
+      deviceName: data.deviceName,
+      deviceNumber: data.deviceNumber,
+      model: data.model,
+      location: data.location,
+      remarks: data.remarks,
+      type: '3',
+      alarmStatus: data.alarmStatus // 保留原值传递给API
+    });
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg);
+      return;
+    }
+
+    ElMessage.success("更新成功");
+    getList();
+  } catch (error) {
+    ElMessage.error("更新失败");
+  }
+};
+
+// 根据id查询设备信息
+const getDeviceInfo = async (deviceId) => {
+  try {
+    const res = await request.get("/base/devices/getById/" + deviceId);
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg);
+      return null;
+    }
+
+    return res.data;
+  } catch (error) {
+    ElMessage.error("获取设备信息失败");
+    return null;
+  }
+};
+
+// 删除单个设备
+const handleDelete = (row) => {
+  ElMessageBox.confirm('确认删除该设备?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(() => {
+    deleteDevice([row.id]);
+  }).catch(() => {});
+};
+
+// 批量删除设备
+const handleBatchDelete = () => {
+  if (multipleSelection.value.length === 0) {
+    ElMessage.warning('请至少选择一条记录');
+    return;
+  }
+
+  ElMessageBox.confirm(`确认删除选中的 ${multipleSelection.value.length} 条记录?`, '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(() => {
+    const ids = multipleSelection.value.map(item => item.id);
+    deleteDevice(ids);
+  }).catch(() => {});
+};
+
+// 删除设备信息
+const deleteDevice = async (ids) => {
+  try {
+    const res = await request.delete("/base/devices/delete", {
+      data: ids,
+    });
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg);
+      return;
+    }
+
+    ElMessage.success("删除成功");
+    getList();
+  } catch (error) {
+    ElMessage.error("删除失败");
+  }
+};
+
+// 新增设备信息
+const addDevice = async () => {
+  try {
+    const res = await request.post("/base/devices/save", {
+      deviceName: formData.deviceName,
+      deviceNumber: formData.deviceNumber,
+      location: formData.location,
+      model: formData.model,
+      remarks: formData.remarks,
+      alarmStatus: formData.alarmStatus, // 使用默认值
+      type: "3", // 写死的不能让修改
+    });
+
+    if (res.code !== 200) {
+      ElMessage.error(res.msg);
+      return;
+    }
+
+    ElMessage.success("新增成功");
+    getList();
+  } catch (error) {
+    ElMessage.error("新增失败");
+  }
+};
+
+const handlePageChange = (page) => {
+  currentPage.value = page;
+  getList();
+};
+
+const handleSizeChange = (size) => {
+  pageSize.value = size;
+  currentPage.value = 1;
+  getList();
+};
+
+const formatDate = (dateString) => {
+  if (!dateString) return '-';
+  const date = new Date(dateString);
+  return date.toLocaleString('zh-CN', {
+    year: 'numeric',
+    month: '2-digit',
+    day: '2-digit',
+    hour: '2-digit',
+    minute: '2-digit'
+  });
+};
+
+// 查看详情
+const checkDetail = (row) => {
+  currentCheckDevice.value = row.deviceNumber;
+  currentDeviceName.value = row.deviceName;
+  detailDialogVisible.value = true;
+};
+
+// 关闭详情对话框
+const closeDetailDialog = () => {
+  detailDialogVisible.value = false;
+};
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<template>
+  <div class="w-full p-4">
+    <!-- 搜索区域 -->
+    <div class="bg-gray-50 p-4 mb-4 rounded-md">
+      <el-form :inline="true" class="flex flex-wrap items-end">
+        <el-form-item label="灯杆名称">
+          <el-input v-model="search.deviceName" placeholder="请输入灯杆名称" clearable/>
+        </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="mb-4 flex justify-between">
+      <div>
+        <el-button type="primary" @click="openAddDialog">新增灯杆</el-button>
+        <el-button type="danger" @click="handleBatchDelete" :disabled="multipleSelection.length === 0">批量删除
+        </el-button>
+      </div>
+    </div>
+
+    <!-- 表格区域 -->
+    <el-table
+        :data="poleList"
+        border
+        stripe
+        v-loading="loading"
+        class="w-full"
+        row-key="id"
+        header-row-class-name="bg-gray-100"
+        @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55"/>
+      <el-table-column prop="deviceName" label="灯杆名称" />
+      <el-table-column prop="deviceNumber" label="灯杆编号" />
+      <el-table-column prop="model" label="设备型号" >
+        <template #default="{ row }">
+          {{ row.model || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="location" label="位置">
+        <template #default="{ row }">
+          {{ row.location || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="remarks" label="备注">
+        <template #default="{ row }">
+          {{ row.remarks || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间">
+        <template #default="{ row }">
+          {{ formatDate(row.createTime) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="更新时间">
+        <template #default="{ row }">
+          {{ formatDate(row.updateTime) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" fixed="right">
+        <template #default="{ row }">
+          <el-button type="primary" link @click="openEditDialog(row)">编辑</el-button>
+          <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
+          <el-button type="info" link @click="checkDetail(row)">查看详情</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页区域 -->
+    <div class="flex justify-end mt-4">
+      <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="handlePageChange"
+          background
+      />
+    </div>
+
+    <!-- 新增/编辑对话框 -->
+    <el-dialog
+        v-model="dialogVisible"
+        :title="dialogTitle"
+        width="500px"
+        append-to-body
+        destroy-on-close
+    >
+      <el-form
+          ref="formRef"
+          :model="formData"
+          :rules="rules"
+          label-width="100px"
+          label-position="right"
+      >
+        <el-form-item label="灯杆名称" prop="deviceName">
+          <el-input v-model="formData.deviceName" placeholder="请输入灯杆名称"/>
+        </el-form-item>
+        <el-form-item label="灯杆编号" prop="deviceNumber">
+          <el-input v-model="formData.deviceNumber" placeholder="请输入灯杆编号" :disabled="formMode === 'edit'"/>
+        </el-form-item>
+        <el-form-item label="设备型号">
+          <el-input v-model="formData.model" placeholder="请输入设备型号"/>
+        </el-form-item>
+        <el-form-item label="位置">
+          <el-input v-model="formData.location" placeholder="请输入位置"/>
+        </el-form-item>
+        <el-form-item label="备注">
+          <el-input v-model="formData.remarks" type="textarea" placeholder="请输入备注"/>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="submitForm">确定</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 详情全屏对话框 -->
+    <el-dialog
+        v-model="detailDialogVisible"
+        :title="`灯杆详情 - ${currentDeviceName}`"
+        fullscreen
+        destroy-on-close
+        :show-close="true"
+        :close-on-click-modal="false"
+        :close-on-press-escape="true"
+    >
+      <div class="detail-dialog-content">
+        <PoleDetail :device-number="currentCheckDevice" />
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="closeDetailDialog">关闭</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<style>
+.el-table .warning-row {
+  --el-table-tr-bg-color: var(--el-color-warning-light-9);
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+  .el-form-item {
+    margin-bottom: 12px;
+  }
+
+  .el-form--inline .el-form-item {
+    margin-right: 0;
+    width: 100%;
+  }
+}
+
+/* 详情对话框样式 */
+.detail-dialog-content {
+  padding: 20px;
+  height: calc(100vh - 120px);
+  overflow-y: auto;
+}
+
+.el-dialog__body {
+  padding: 0;
+}
+
+.el-dialog.is-fullscreen {
+  display: flex;
+  flex-direction: column;
+}
+
+.el-dialog.is-fullscreen .el-dialog__header {
+  padding: 16px 20px;
+  margin-right: 0;
+  border-bottom: 1px solid #e4e7ed;
+}
+
+.el-dialog.is-fullscreen .el-dialog__footer {
+  padding: 10px 20px;
+  border-top: 1px solid #e4e7ed;
+  margin-top: auto;
+}
+</style>