Преглед изворни кода

修改 公共广播系统接口 物业管理系统接口 信息引导及发布系统接口 门禁系统接口 会议系统接口

bzd_lxf пре 1 месец
родитељ
комит
5bf8300122
32 измењених фајлова са 7158 додато и 39 уклоњено
  1. 149 2
      pm-admin/src/main/java/com/pm/web/controller/accessControl/AccessControlController.java
  2. 935 0
      pm-admin/src/main/java/com/pm/web/controller/buildingEquipmentMonitoring/BuildingEquipmentMonitoringController.java
  3. 205 0
      pm-admin/src/main/java/com/pm/web/controller/driverInfo/DriverInfoController.java
  4. 642 0
      pm-admin/src/main/java/com/pm/web/controller/estateManagement/EstateManagementController.java
  5. 767 0
      pm-admin/src/main/java/com/pm/web/controller/publicBroadcasting/PublicBroadcastingController.java
  6. 11 0
      pm-system/src/main/java/com/pm/repairOrder/service/impl/RepairOrderServiceImpl.java
  7. 19 0
      pm_ui/src/api/accessControl/accessControl.js
  8. 35 0
      pm_ui/src/api/buildingEquipmentMonitoring/buildingEquipmentMonitoring.js
  9. 9 0
      pm_ui/src/api/driverInfo/driverInfo.js
  10. 70 0
      pm_ui/src/api/estateManagement/estateManagement.js
  11. 36 0
      pm_ui/src/api/publicBroadcasting/publicBroadcasting.js
  12. 114 0
      pm_ui/src/views/accessControl/index.vue
  13. 120 0
      pm_ui/src/views/accessControl/index2.vue
  14. 289 0
      pm_ui/src/views/buildingEquipmentMonitoring/index.vue
  15. 405 0
      pm_ui/src/views/buildingEquipmentMonitoring/index2.vue
  16. 336 0
      pm_ui/src/views/buildingEquipmentMonitoring/index3.vue
  17. 412 0
      pm_ui/src/views/buildingEquipmentMonitoring/index4.vue
  18. 121 0
      pm_ui/src/views/driverInfo/index.vue
  19. 132 0
      pm_ui/src/views/estateManagement/index.vue
  20. 156 0
      pm_ui/src/views/estateManagement/index2.vue
  21. 151 0
      pm_ui/src/views/estateManagement/index3.vue
  22. 142 0
      pm_ui/src/views/estateManagement/index4.vue
  23. 148 0
      pm_ui/src/views/estateManagement/index5.vue
  24. 143 0
      pm_ui/src/views/estateManagement/index6.vue
  25. 142 0
      pm_ui/src/views/estateManagement/index7.vue
  26. 382 0
      pm_ui/src/views/estateManagement/index8.vue
  27. 161 0
      pm_ui/src/views/publicBroadcasting/index.vue
  28. 246 0
      pm_ui/src/views/publicBroadcasting/index2.vue
  29. 315 0
      pm_ui/src/views/publicBroadcasting/index3.vue
  30. 296 0
      pm_ui/src/views/publicBroadcasting/index4.vue
  31. 33 11
      pm_ui/src/views/repairOrder/repairOrder/index.vue
  32. 36 26
      pm_ui/src/views/repairOrder/repairOrder/index2.vue

+ 149 - 2
pm-admin/src/main/java/com/pm/web/controller/accessControl/AccessControlController.java

@@ -7,13 +7,16 @@ import okhttp3.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 门禁管理
@@ -29,6 +32,150 @@ public class AccessControlController  extends BaseController {
     @Autowired
     private InterfaceInfoService interfaceInfoService;
 
+    // 模拟生成固定的门禁设备数据
+    private List<Map<String, Object>> generateDoorDeviceData() {
+        return Arrays.asList(
+                // 同一位置设备分布(A座1楼大厅有3台设备)
+                Map.of("id", "Device1", "location", "A座1楼大厅", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-01 08:00:00", "eventType", "正常通行", "actions", "解锁门", "processStatus", "已完成"),
+                Map.of("id", "Device2", "location", "A座1楼大厅", "doorStatus", "关闭", "deviceStatus", "Offline", "lastEventTime", "2023-10-01 09:30:00", "eventType", "非法入侵", "actions", "触发警报", "processStatus", "待处理"),
+                Map.of("id", "Device3", "location", "A座1楼大厅", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-01 10:15:00", "eventType", "正常通行", "actions", "解锁门", "processStatus", "已完成"),
+
+                // B座2楼实验室有2台设备
+                Map.of("id", "Device4", "location", "B座2楼实验室", "doorStatus", "关闭", "deviceStatus", "Offline", "lastEventTime", "2023-10-02 08:45:00", "eventType", "正常通行", "actions", "锁门", "processStatus", "已完成"),
+                Map.of("id", "Device5", "location", "B座2楼实验室", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-02 14:20:00", "eventType", "火警触发", "actions", "触发警报", "processStatus", "进行中"),
+
+                // C座3楼会议室有3台设备
+                Map.of("id", "Device6", "location", "C座3楼会议室", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-03 09:00:00", "eventType", "正常通行", "actions", "解锁门", "processStatus", "已完成"),
+                Map.of("id", "Device7", "location", "C座3楼会议室", "doorStatus", "关闭", "deviceStatus", "Offline", "lastEventTime", "2023-10-03 11:30:00", "eventType", "非法入侵", "actions", "触发警报", "processStatus", "待处理"),
+                Map.of("id", "Device8", "location", "C座3楼会议室", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-03 16:45:00", "eventType", "正常通行", "actions", "解锁门", "processStatus", "已完成"),
+
+                // D座4楼办公室有2台设备
+                Map.of("id", "Device9", "location", "D座4楼办公室", "doorStatus", "关闭", "deviceStatus", "Offline", "lastEventTime", "2023-10-04 08:15:00", "eventType", "正常通行", "actions", "锁门", "processStatus", "已完成"),
+                Map.of("id", "Device10", "location", "D座4楼办公室", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-04 15:30:00", "eventType", "火警触发", "actions", "触发警报", "processStatus", "进行中"),
+
+                // E座5楼休息区有5台设备
+                Map.of("id", "Device11", "location", "E座5楼休息区", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-05 09:45:00", "eventType", "正常通行", "actions", "解锁门", "processStatus", "已完成"),
+                Map.of("id", "Device12", "location", "E座5楼休息区", "doorStatus", "关闭", "deviceStatus", "Offline", "lastEventTime", "2023-10-05 13:20:00", "eventType", "正常通行", "actions", "锁门", "processStatus", "已完成"),
+                Map.of("id", "Device13", "location", "E座5楼休息区", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-05 16:10:00", "eventType", "非法入侵", "actions", "触发警报", "processStatus", "待处理"),
+                Map.of("id", "Device14", "location", "E座5楼休息区", "doorStatus", "关闭", "deviceStatus", "Offline", "lastEventTime", "2023-10-05 18:45:00", "eventType", "正常通行", "actions", "锁门", "processStatus", "已完成"),
+                Map.of("id", "Device15", "location", "E座5楼休息区", "doorStatus", "开启", "deviceStatus", "Online", "lastEventTime", "2023-10-05 20:30:00", "eventType", "火警触发", "actions", "触发警报", "processStatus", "进行中")
+        );
+    }
+    private List<Map<String, Object>> generateAttendanceRecordsData() {
+        return Arrays.asList(
+            // 张伟(市场部) - 4次打卡(上班、午休外出、午休返回、下班)
+            Map.of("employeeId", "E0001", "name", "张伟", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 08:30:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "上班打卡", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0001", "name", "张伟", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 12:00:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "午休外出", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0001", "name", "张伟", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 13:00:00", "accessResult", "成功", "attendanceStatus", "Absent", "relatedEvent", "午休返回", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0001", "name", "张伟", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 18:00:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "下班打卡", "dailyAccessCount", 4),
+
+            // 李娜(市场部) - 3次打卡(上班、午休返回、下班)
+            Map.of("employeeId", "E0002", "name", "李娜", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 08:35:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "上班打卡", "dailyAccessCount", 3),
+            Map.of("employeeId", "E0002", "name", "李娜", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 13:10:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "午休返回", "dailyAccessCount", 3),
+            Map.of("employeeId", "E0002", "name", "李娜", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 18:15:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "下班打卡", "dailyAccessCount", 3),
+
+            // 王军(市场部) - 迟到(2次打卡)
+            Map.of("employeeId", "E0003", "name", "王军", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 09:10:00", "accessResult", "失败", "attendanceStatus", "Absent", "relatedEvent", "上班迟到", "dailyAccessCount", 2),
+            Map.of("employeeId", "E0003", "name", "王军", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 18:30:00", "accessResult", "成功", "attendanceStatus", "Absent", "relatedEvent", "下班打卡", "dailyAccessCount", 2),
+
+            // 陈雨(市场部) - 4次打卡
+            Map.of("employeeId", "E0004", "name", "陈雨", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 08:45:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "上班打卡", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0004", "name", "陈雨", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 12:15:00", "accessResult", "成功", "attendanceStatus", "Absent", "relatedEvent", "午休外出", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0004", "name", "陈雨", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 13:15:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "午休返回", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0004", "name", "陈雨", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 18:45:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "下班打卡", "dailyAccessCount", 4),
+
+            // 刘畅(市场部) - 3次打卡
+            Map.of("employeeId", "E0005", "name", "刘畅", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 08:20:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "上班打卡", "dailyAccessCount", 3),
+            Map.of("employeeId", "E0005", "name", "刘畅", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 12:30:00", "accessResult", "成功", "attendanceStatus", "Absent", "relatedEvent", "午休外出", "dailyAccessCount", 3),
+            Map.of("employeeId", "E0005", "name", "刘畅", "department", "市场部", "accessLocation", "A座1楼门禁", "accessTime", "2023-10-01 18:00:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "下班打卡", "dailyAccessCount", 3),
+
+            // 周敏(研发部) - 4次打卡
+            Map.of("employeeId", "E0006", "name", "周敏", "department", "研发部", "accessLocation", "B座2楼门禁", "accessTime", "2023-10-01 08:50:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "上班打卡", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0006", "name", "周敏", "department", "研发部", "accessLocation", "B座2楼门禁", "accessTime", "2023-10-01 12:10:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "午休外出", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0006", "name", "周敏", "department", "研发部", "accessLocation", "B座2楼门禁", "accessTime", "2023-10-01 13:20:00", "accessResult", "成功", "attendanceStatus", "Absent", "relatedEvent", "午休返回", "dailyAccessCount", 4),
+            Map.of("employeeId", "E0006", "name", "周敏", "department", "研发部", "accessLocation", "B座2楼门禁", "accessTime", "2023-10-01 19:00:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "下班打卡", "dailyAccessCount", 4),
+
+            // 吴浩(研发部) - 迟到(2次打卡)
+            Map.of("employeeId", "E0007", "name", "吴浩", "department", "研发部", "accessLocation", "B座2楼门禁", "accessTime", "2023-10-01 09:40:00", "accessResult", "失败", "attendanceStatus", "Absent", "relatedEvent", "上班迟到", "dailyAccessCount", 2),
+            Map.of("employeeId", "E0007", "name", "吴浩", "department", "研发部", "accessLocation", "B座2楼门禁", "accessTime", "2023-10-01 19:30:00", "accessResult", "成功", "attendanceStatus", "Absent", "relatedEvent", "下班打卡", "dailyAccessCount", 2),
+
+            // 钱芳(财务部) - 3次打卡
+            Map.of("employeeId", "E0012", "name", "钱芳", "department", "财务部", "accessLocation", "C座3楼门禁", "accessTime", "2023-10-01 18:15:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "下班打卡", "dailyAccessCount", 4),
+
+            // 周珊(人力资源部) - 3次打卡
+            Map.of("employeeId", "E0013", "name", "周珊", "department", "人力资源部", "accessLocation", "D座4楼门禁", "accessTime", "2023-10-01 08:35:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "上班打卡", "dailyAccessCount", 3),
+            Map.of("employeeId", "E0013", "name", "周珊", "department", "人力资源部", "accessLocation", "D座4楼门禁", "accessTime", "2023-10-01 12:15:00", "accessResult", "成功", "attendanceStatus", "Present", "relatedEvent", "午休外出", "dailyAccessCount", 3)
+        );
+    }
+
+    // 查询门禁设备状态(支持分页和条件查询)
+    @GetMapping("/door-devices")
+    public Map<String, Object> getDoorDevices() throws Exception {
+        List<Map<String, Object>> data = generateDoorDeviceData();
+        PageData pd = this.getPageData();
+        String location = pd.getString("location");
+        String deviceStatus = pd.getString("deviceStatus");
+        // 条件过滤
+        if (location != null && !location.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("location").toString().contains(location))
+                    .collect(Collectors.toList());
+        }
+        if (deviceStatus != null && !deviceStatus.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceStatus").toString().equalsIgnoreCase(deviceStatus))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    // 查询考勤记录(支持分页和条件查询)
+    @GetMapping("/attendance-records")
+    public Map<String, Object> getAttendanceRecords() throws Exception {
+        List<Map<String, Object>> data = generateAttendanceRecordsData();
+        PageData pd = this.getPageData();
+        String name = pd.getString("name");
+        String attendanceStatus = pd.getString("attendanceStatus");
+        // 条件过滤
+        if (name != null && !name.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("name").toString().contains(name))
+                    .collect(Collectors.toList());
+        }
+        if (attendanceStatus != null && !attendanceStatus.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("attendanceStatus").toString().equalsIgnoreCase(attendanceStatus))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
     /**
      * 查询门禁管理列表
      * @return

+ 935 - 0
pm-admin/src/main/java/com/pm/web/controller/buildingEquipmentMonitoring/BuildingEquipmentMonitoringController.java

@@ -0,0 +1,935 @@
+package com.pm.web.controller.buildingEquipmentMonitoring;
+
+import com.pm.common.config.PageData;
+import com.pm.common.core.controller.BaseController;
+import com.pm.interfaceInfo.service.InterfaceInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**
+ * 建筑设备监控
+ */
+@RestController
+@RequestMapping("/buildingEquipmentMonitoring/info")
+public class BuildingEquipmentMonitoringController extends BaseController {
+
+
+    /**
+     * 查询url 访问接口
+     */
+    @Autowired
+    private InterfaceInfoService interfaceInfoService;
+
+
+    public static List<Map<String, Object>> generateDeviceData() {
+        return Arrays.asList(
+                // 基础设备(正常状态)
+                createDeviceEntry(
+                        "DEV-001", "主控制器", "CONTROLLER", "MK-2000",
+                        "100,200,150", "1F", "中央控制室",
+                        "正常", "#52c41a",
+                        "/models/controller.obj", "{\"speed\":1.0,\"rotation\":0}",
+                        null, null, null,
+                        "MQTT", "START/STOP/REBOOT"
+                ),
+                // 传感器设备(警告状态)
+                createDeviceEntry(
+                        "DEV-002", "温度传感器A", "SENSOR", "TEMP-100",
+                        "150,300,180", "1F", "东侧走廊",
+                        "警告", "#faad14",
+                        "/models/sensor.obj", "{\"pulse\":true}",
+                        "WARN-001", "温度异常(45℃)", "2025-06-05 09:30:15",
+                        "HTTP", "READ/RESET/CALIBRATE"
+                ),
+                // 执行器设备(故障状态)
+                createDeviceEntry(
+                        "DEV-003", "通风扇B", "ACTUATOR", "FAN-3000",
+                        "200,150,220", "2F", "南侧机房",
+                        "故障", "#f5222d",
+                        "/models/fan.obj", "{\"speed\":0,\"angle\":90}",
+                        "ERR-002", "电机过载", "2025-06-05 11:15:40",
+                        "Modbus", "START/STOP/SET_SPEED"
+                ),
+                // 广播设备(正常状态)
+                createDeviceEntry(
+                        "DEV-004", "扬声器Z", "BROADCASTER", "SPEAKER-500",
+                        "300,200,250", "1F", "大厅",
+                        "正常", "#52c41a",
+                        "/models/speaker.obj", "{\"volume\":75}",
+                        null, null, null,
+                        "TCP", "PLAY/STOP/SET_VOLUME"
+                ),
+                // 监控设备(正常状态)
+                createDeviceEntry(
+                        "DEV-005", "摄像头C", "MONITOR", "CAM-200",
+                        "180,120,300", "3F", "西侧入口",
+                        "正常", "#52c41a",
+                        "/models/camera.obj", "{\"rotation\":180,\"zoom\":1.5}",
+                        null, null, null,
+                        "RTSP", "ROTATE/ZOOM/RECORD"
+                ),
+                // 新增15条模拟数据(包含不同状态和位置)
+                createDeviceEntry(
+                        "DEV-006", "烟雾报警器D", "ALARM", "SMOKE-100",
+                        "120,280,170", "1F", "消防通道",
+                        "警告", "#faad14",
+                        "/models/alarm.obj", "{\"blink\":true}",
+                        "WARN-003", "烟雾浓度异常", "2025-06-05 13:45:22",
+                        "ZigBee", "TEST/RESET/SILENCE"
+                ),
+                createDeviceEntry(
+                        "DEV-007", "温度传感器E", "SENSOR", "TEMP-100",
+                        "170,320,190", "1F", "东侧机房",
+                        "正常", "#52c41a",
+                        "/models/sensor.obj", "{\"pulse\":true}",
+                        null, null, null,
+                        "HTTP", "READ/RESET/CALIBRATE"
+                ),
+                createDeviceEntry(
+                        "DEV-008", "紧急按钮F", "INPUT", "BUTTON-50",
+                        "250,180,160", "2F", "电梯厅",
+                        "正常", "#52c41a",
+                        "/models/button.obj", "{\"pressed\":false}",
+                        null, null, null,
+                        "TCP", "PRESS/RELEASE/TEST"
+                ),
+                createDeviceEntry(
+                        "DEV-009", "通风扇G", "ACTUATOR", "FAN-3000",
+                        "220,160,230", "2F", "北侧机房",
+                        "故障", "#f5222d",
+                        "/models/fan.obj", "{\"speed\":0,\"angle\":45}",
+                        "ERR-004", "扇叶损坏", "2025-06-05 14:20:35",
+                        "Modbus", "START/STOP/SET_SPEED"
+                ),
+                createDeviceEntry(
+                        "DEV-010", "扬声器H", "BROADCASTER", "SPEAKER-500",
+                        "310,210,260", "1F", "会议室",
+                        "正常", "#52c41a",
+                        "/models/speaker.obj", "{\"volume\":60}",
+                        null, null, null,
+                        "TCP", "PLAY/STOP/SET_VOLUME"
+                ),
+                createDeviceEntry(
+                        "DEV-011", "摄像头I", "MONITOR", "CAM-200",
+                        "190,130,310", "3F", "东侧走廊",
+                        "正常", "#52c41a",
+                        "/models/camera.obj", "{\"rotation\":270,\"zoom\":1.0}",
+                        null, null, null,
+                        "RTSP", "ROTATE/ZOOM/RECORD"
+                ),
+                createDeviceEntry(
+                        "DEV-012", "湿度传感器J", "SENSOR", "HUMI-200",
+                        "130,290,180", "1F", "消防通道",
+                        "正常", "#52c41a",
+                        "/models/sensor.obj", "{\"pulse\":true}",
+                        null, null, null,
+                        "HTTP", "READ/RESET/CALIBRATE"
+                ),
+                createDeviceEntry(
+                        "DEV-013", "门禁控制器K", "CONTROLLER", "DOOR-1000",
+                        "280,170,150", "2F", "财务室",
+                        "警告", "#faad14",
+                        "/models/controller.obj", "{\"lock\":true}",
+                        "WARN-005", "多次无效刷卡", "2025-06-05 15:10:55",
+                        "MQTT", "UNLOCK/LOCK/RESET"
+                ),
+                createDeviceEntry(
+                        "DEV-014", "消防栓控制器L", "CONTROLLER", "FIRE-500",
+                        "160,240,165", "1F", "东侧楼梯间",
+                        "正常", "#52c41a",
+                        "/models/controller.obj", "{\"status\":\"idle\"}",
+                        null, null, null,
+                        "CAN", "TEST/ACTIVATE/RESET"
+                ),
+                createDeviceEntry(
+                        "DEV-015", "空调控制器M", "CONTROLLER", "AC-3000",
+                        "230,210,240", "2F", "南侧办公室",
+                        "正常", "#52c41a",
+                        "/models/controller.obj", "{\"temp\":24,\"mode\":\"cool\"}",
+                        null, null, null,
+                        "Modbus", "SET_TEMP/SET_MODE/START/STOP"
+                ),
+                createDeviceEntry(
+                        "DEV-016", "扬声器N", "BROADCASTER", "SPEAKER-500",
+                        "320,220,270", "1F", "餐厅",
+                        "故障", "#f5222d",
+                        "/models/speaker.obj", "{\"volume\":0}",
+                        "ERR-006", "音频输出异常", "2025-06-05 16:30:10",
+                        "TCP", "PLAY/STOP/SET_VOLUME"
+                ),
+                createDeviceEntry(
+                        "DEV-017", "摄像头O", "MONITOR", "CAM-200",
+                        "200,140,320", "3F", "南侧走廊",
+                        "正常", "#52c41a",
+                        "/models/camera.obj", "{\"rotation\":90,\"zoom\":2.0}",
+                        null, null, null,
+                        "RTSP", "ROTATE/ZOOM/RECORD"
+                ),
+                createDeviceEntry(
+                        "DEV-018", "压力传感器P", "SENSOR", "PRESS-150",
+                        "140,300,195", "1F", "西侧机房",
+                        "正常", "#52c41a",
+                        "/models/sensor.obj", "{\"pulse\":true}",
+                        null, null, null,
+                        "HTTP", "READ/RESET/CALIBRATE"
+                ),
+                createDeviceEntry(
+                        "DEV-019", "紧急广播Q", "BROADCASTER", "EMG-1000",
+                        "270,190,170", "2F", "大厅",
+                        "正常", "#52c41a",
+                        "/models/speaker.obj", "{\"volume\":100}",
+                        null, null, null,
+                        "TCP", "PLAY/STOP/SET_VOLUME"
+                ),
+                createDeviceEntry(
+                        "DEV-020", "主备控制器R", "CONTROLLER", "MK-2000",
+                        "110,210,160", "1F", "中央控制室",
+                        "正常", "#52c41a",
+                        "/models/controller.obj", "{\"speed\":0.8,\"rotation\":180}",
+                        null, null, null,
+                        "MQTT", "START/STOP/REBOOT"
+                )
+        );
+    }
+
+    private static Map<String, Object> createDeviceEntry(
+            String deviceId, String deviceName, String deviceType, String model,
+            String location, String floor, String area,
+            String status, String statusColor,
+            String modelPath, String animationParams,
+            String alarmCode, String alarmDescription, String triggerTime,
+            String controlProtocol, String commandSet
+    ) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("deviceId", deviceId); // 设备ID
+        data.put("deviceName", deviceName); // 设备名称
+        data.put("deviceType", deviceType); // 设备类型
+        data.put("model", model); // 型号
+        data.put("location", location); // 安装位置(X,Y,Z坐标)
+        data.put("floor", floor); // 楼层
+        data.put("area", area); // 区域
+        data.put("status", status); // 运行状态(正常/警告/故障)
+        data.put("statusColor", statusColor); // 状态颜色值
+        data.put("modelPath", modelPath); // 模型文件路径
+        data.put("animationParams", animationParams); // 动画参数
+        data.put("alarmCode", alarmCode); // 当前告警代码
+        data.put("alarmDescription", alarmDescription); // 告警描述
+        data.put("triggerTime", triggerTime); // 触发时间
+        data.put("controlProtocol", controlProtocol); // 设备控制协议
+        data.put("commandSet", commandSet); // 指令集
+        return data;
+    }
+
+
+
+
+    public static List<Map<String, Object>> generateConfigurationData() {
+        return Arrays.asList(
+                // 主控制室组态图
+                createConfigEntry(
+                        "CFG-001", "/configs/main_control_room.dwg", "V1.2",
+                        Arrays.asList(
+                                createDeviceBinding("DEV-001", 100, 200),
+                                createDeviceBinding("DEV-002", 150, 180)
+                        ),
+                        Arrays.asList(
+                                createMonitorParam("温度", 23.5, "℃"),
+                                createMonitorParam("压力", 1.2, "MPa")
+                        ),
+                        "{\"温度\": {\"low\":\"#ffd700\", \"high\":\"#ff4500\"}, \"压力\": {\"low\":\"#90ee90\", \"high\":\"#ff6347\"}",
+                        "{\"温度\": {\"blink\": true, \"threshold\": 30}, \"压力\": {\"blink\": false, \"threshold\": 1.5}}",
+                        "NUMERIC",
+                        "SCENE-001",
+                        "{\"x\": 50, \"y\": 30, \"zoom\": 1.2}"
+                ),
+                // 空调系统组态图
+                createConfigEntry(
+                        "CFG-002", "/configs/air_conditioning.dwg", "V2.0",
+                        Arrays.asList(
+                                createDeviceBinding("DEV-015", 80, 160),
+                                createDeviceBinding("DEV-016", 220, 90)
+                        ),
+                        Arrays.asList(
+                                createMonitorParam("电流", 5.8, "A"),
+                                createMonitorParam("风速", 4.2, "m/s")
+                        ),
+                        "{\"电流\": {\"low\":\"#add8e6\", \"high\":\"#ff0000\"}, \"风速\": {\"low\":\"#f0e68c\", \"high\":\"#483d8b\"}}",
+                        "{\"电流\": {\"blink\": true, \"threshold\": 6.0}, \"风速\": {\"blink\": true, \"threshold\": 5.0}}",
+                        "PERCENTAGE",
+                        "SCENE-002",
+                        "{\"x\": 80, \"y\": 60, \"rotation\": 90}"
+                ),
+                // 消防系统组态图
+                createConfigEntry(
+                        "CFG-003", "/configs/fire_system.dwg", "V1.1",
+                        Arrays.asList(
+                                createDeviceBinding("DEV-006", 120, 250),
+                                createDeviceBinding("DEV-014", 280, 110)
+                        ),
+                        Arrays.asList(
+                                createMonitorParam("烟雾浓度", 0.3, "ppm"),
+                                createMonitorParam("水压", 0.8, "MPa")
+                        ),
+                        "{\"烟雾浓度\": {\"low\":\"#ffffff\", \"high\":\"#ff0000\"}, \"水压\": {\"low\":\"#40e0d0\", \"high\":\"#ffd700\"}}",
+                        "{\"烟雾浓度\": {\"blink\": true, \"threshold\": 0.5}, \"水压\": {\"blink\": false, \"threshold\": 0.6}}",
+                        "DECIMAL",
+                        "SCENE-003",
+                        "{\"x\": 150, \"y\": 180, \"zoom\": 1.5}"
+                ),
+                // 新增7条模拟数据
+                createConfigEntry(
+                        "CFG-004", "/configs/water_system.dwg", "V1.3",
+                        Arrays.asList(createDeviceBinding("DEV-008", 90, 190)),
+                        Arrays.asList(createMonitorParam("流量", 30.2, "m³/h")),
+                        "{\"流量\": {\"low\":\"#87ceeb\", \"high\":\"#ff69b4\"}}",
+                        "{\"流量\": {\"blink\": true, \"threshold\": 35.0}}",
+                        "NUMERIC",
+                        "SCENE-004",
+                        "{\"x\": 70, \"y\": 40, \"zoom\": 1.0}"
+                ),
+                createConfigEntry(
+                        "CFG-005", "/configs/elevator_system.dwg", "V2.1",
+                        Arrays.asList(createDeviceBinding("DEV-003", 170, 130), createDeviceBinding("DEV-009", 240, 150)),
+                        Arrays.asList(createMonitorParam("电压", 220, "V"), createMonitorParam("负载率", 65, "%")),
+                        "{\"电压\": {\"low\":\"#9370db\", \"high\":\"#ff8c00\"}, \"负载率\": {\"low\":\"#98fb98\", \"high\":\"#ff4500\"}}",
+                        "{\"电压\": {\"blink\": false, \"threshold\": 240}, \"负载率\": {\"blink\": true, \"threshold\": 80}}",
+                        "PERCENTAGE",
+                        "SCENE-005",
+                        "{\"x\": 120, \"y\": 90, \"rotation\": 0}"
+                ),
+                createConfigEntry(
+                        "CFG-006", "/configs/lighting_system.dwg", "V1.0",
+                        Arrays.asList(createDeviceBinding("DEV-004", 210, 230), createDeviceBinding("DEV-010", 300, 170)),
+                        Arrays.asList(createMonitorParam("照度", 500, "lux"), createMonitorParam("开关状态", 1, "布尔")),
+                        "{\"照度\": {\"low\":\"#f5f5dc\", \"high\":\"#ffff00\"}, \"开关状态\": {\"low\":\"#d3d3d3\", \"high\":\"#00ff00\"}}",
+                        "{\"照度\": {\"blink\": true, \"threshold\": 600}, \"开关状态\": {\"blink\": false, \"threshold\": 0}}",
+                        "NUMERIC",
+                        "SCENE-001",
+                        "{\"x\": 180, \"y\": 110, \"zoom\": 0.8}"
+                ),
+                createConfigEntry(
+                        "CFG-007", "/configs/power_system.dwg", "V1.5",
+                        Arrays.asList(createDeviceBinding("DEV-005", 140, 280), createDeviceBinding("DEV-011", 260, 200)),
+                        Arrays.asList(createMonitorParam("频率", 50, "Hz"), createMonitorParam("功率因数", 0.92, "-")),
+                        "{\"频率\": {\"low\":\"#4682b4\", \"high\":\"#ff00ff\"}, \"功率因数\": {\"low\":\"#f08080\", \"high\":\"#2e8b57\"}}",
+                        "{\"频率\": {\"blink\": false, \"threshold\": 51}, \"功率因数\": {\"blink\": true, \"threshold\": 0.95}}",
+                        "DECIMAL",
+                        "SCENE-003",
+                        "{\"x\": 200, \"y\": 160, \"zoom\": 1.3}"
+                ),
+                createConfigEntry(
+                        "CFG-008", "/configs/factory_area.dwg", "V3.0",
+                        Arrays.asList(createDeviceBinding("DEV-012", 110, 300), createDeviceBinding("DEV-018", 190, 220)),
+                        Arrays.asList(createMonitorParam("湿度", 55, "%"), createMonitorParam("气压", 101.3, "kPa")),
+                        "{\"湿度\": {\"low\":\"#8470ff\", \"high\":\"#ffd700\"}, \"气压\": {\"low\":\"#add8e6\", \"high\":\"#ff6347\"}}",
+                        "{\"湿度\": {\"blink\": true, \"threshold\": 60}, \"气压\": {\"blink\": false, \"threshold\": 100.0}}",
+                        "PERCENTAGE",
+                        "SCENE-006",
+                        "{\"x\": 60, \"y\": 70, \"rotation\": 45}"
+                ),
+                createConfigEntry(
+                        "CFG-009", "/configs/laboratory.dwg", "V1.4",
+                        Arrays.asList(createDeviceBinding("DEV-013", 230, 140), createDeviceBinding("DEV-017", 290, 270)),
+                        Arrays.asList(createMonitorParam("PH值", 7.2, "-"), createMonitorParam("浊度", 5.0, "NTU")),
+                        "{\"PH值\": {\"low\":\"#ff0000\", \"high\":\"#0000ff\"}, \"浊度\": {\"low\":\"#f5f5f5\", \"high\":\"#a9a9a9\"}}",
+                        "{\"PH值\": {\"blink\": true, \"threshold\": 7.5}, \"浊度\": {\"blink\": true, \"threshold\": 8.0}}",
+                        "DECIMAL",
+                        "SCENE-002",
+                        "{\"x\": 130, \"y\": 80, \"zoom\": 1.1}"
+                ),
+                createConfigEntry(
+                        "CFG-010", "/configs/warehouse.dwg", "V1.1",
+                        Arrays.asList(createDeviceBinding("DEV-019", 160, 120), createDeviceBinding("DEV-020", 250, 180)),
+                        Arrays.asList(createMonitorParam("库存量", 850, "件"), createMonitorParam("出入库速率", 30, "件/h")),
+                        "{\"库存量\": {\"low\":\"#ff69b4\", \"high\":\"#00ff7f\"}, \"出入库速率\": {\"low\":\"#8b4513\", \"high\":\"#40e0d0\"}}",
+                        "{\"库存量\": {\"blink\": false, \"threshold\": 500}, \"出入库速率\": {\"blink\": true, \"threshold\": 50}}",
+                        "NUMERIC",
+                        "SCENE-004",
+                        "{\"x\": 90, \"y\": 50, \"zoom\": 0.9}"
+                ),
+                createConfigEntry(
+                        "CFG-010", "/configs/warehouse.dwg", "V1.1",
+                        Arrays.asList(createDeviceBinding("DEV-019", 160, 120), createDeviceBinding("DEV-020", 250, 180)),
+                        Arrays.asList(createMonitorParam("库存量", 850, "件"), createMonitorParam("出入库速率", 30, "件/h")),
+                        "{\"库存量\": {\"low\":\"#ff69b4\", \"high\":\"#00ff7f\"}, \"出入库速率\": {\"low\":\"#8b4513\", \"high\":\"#40e0d0\"}}",
+                        "{\"库存量\": {\"blink\": false, \"threshold\": 500}, \"出入库速率\": {\"blink\": true, \"threshold\": 50}}",
+                        "NUMERIC",
+                        "SCENE-004",
+                        "{\"x\": 90, \"y\": 50, \"zoom\": 0.9}"
+                ),
+                createConfigEntry(
+                        "CFG-010", "/configs/warehouse.dwg", "V1.1",
+                        Arrays.asList(createDeviceBinding("DEV-019", 160, 120), createDeviceBinding("DEV-020", 250, 180)),
+                        Arrays.asList(createMonitorParam("库存量", 850, "件"), createMonitorParam("出入库速率", 30, "件/h")),
+                        "{\"库存量\": {\"low\":\"#ff69b4\", \"high\":\"#00ff7f\"}, \"出入库速率\": {\"low\":\"#8b4513\", \"high\":\"#40e0d0\"}}",
+                        "{\"库存量\": {\"blink\": false, \"threshold\": 500}, \"出入库速率\": {\"blink\": true, \"threshold\": 50}}",
+                        "NUMERIC",
+                        "SCENE-004",
+                        "{\"x\": 90, \"y\": 50, \"zoom\": 0.9}"
+                )
+        );
+    }
+
+    private static Map<String, Object> createConfigEntry(
+            String configId, String drawingPath, String version,
+            List<Map<String, Object>> deviceBindings,
+            List<Map<String, Object>> monitorParams,
+            String colorThresholds,
+            String blinkRules,
+            String displayFormat,
+            String associatedSceneId,
+            String hotspotParams
+    ) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("configId", configId); // 组态图ID
+        data.put("drawingPath", drawingPath); // 图纸路径
+        data.put("version", version); // 版本号
+        data.put("deviceBindings", deviceBindings); // 设备绑定信息
+        data.put("monitorParams", monitorParams); // 监控参数
+        data.put("colorThresholds", colorThresholds); // 颜色阈值
+        data.put("blinkRules", blinkRules); // 闪烁规则
+        data.put("displayFormat", displayFormat); // 数值显示格式
+        data.put("associatedSceneId", associatedSceneId); // 关联的三维场景ID
+        data.put("hotspotParams", hotspotParams); // 热点跳转参数
+        return data;
+    }
+
+    private static Map<String, Object> createDeviceBinding(String deviceId, int x, int y) {
+        Map<String, Object> binding = new HashMap<>();
+        binding.put("deviceId", deviceId);
+        binding.put("x", x);
+        binding.put("y", y);
+        return binding;
+    }
+
+    private static Map<String, Object> createMonitorParam(String name, double value, String unit) {
+        Map<String, Object> param = new HashMap<>();
+        param.put("name", name);
+        param.put("value", value);
+        param.put("unit", unit);
+        return param;
+    }
+
+    public static List<Map<String, Object>> generateAreaData() {
+        return Arrays.asList(
+                // 一级区域:园区
+                createAreaEntry(
+                        "AREA-001", "智慧园区", null, 1,
+                        Arrays.asList(
+                                createDeviceStat("CONTROLLER", 5, 90.0, 2.0),
+                                createDeviceStat("SENSOR", 20, 95.0, 1.0),
+                                createDeviceStat("ACTUATOR", 8, 87.5, 5.0)
+                        ),
+                        "{\"lat\":30.123,\"lng\":120.456,\"heatData\":[[100,200,0.8],[150,180,0.6]]}",
+                        "0.85,1200,92",
+                        "CONTROLLER,SENSOR",
+                        "在线,故障"
+                ),
+                createAreaEntry(
+                        "AREA-001", "智慧园区", null, 1,
+                        Arrays.asList(
+                                createDeviceStat("CONTROLLER", 5, 90.0, 2.0),
+                                createDeviceStat("SENSOR", 20, 95.0, 1.0),
+                                createDeviceStat("ACTUATOR", 8, 87.5, 5.0)
+                        ),
+                        "{\"lat\":30.123,\"lng\":120.456,\"heatData\":[[100,200,0.8],[150,180,0.6]]}",
+                        "0.85,1200,92",
+                        "CONTROLLER,SENSOR",
+                        "在线,故障"
+                ),
+                createAreaEntry(
+                        "AREA-001", "智慧园区", null, 1,
+                        Arrays.asList(
+                                createDeviceStat("CONTROLLER", 5, 90.0, 2.0),
+                                createDeviceStat("SENSOR", 20, 95.0, 1.0),
+                                createDeviceStat("ACTUATOR", 8, 87.5, 5.0)
+                        ),
+                        "{\"lat\":30.123,\"lng\":120.456,\"heatData\":[[100,200,0.8],[150,180,0.6]]}",
+                        "0.85,1200,92",
+                        "CONTROLLER,SENSOR",
+                        "在线,故障"
+                ),
+                // 二级区域:1号大楼
+                createAreaEntry(
+                        "AREA-002", "1号大楼", "AREA-001", 2,
+                        Arrays.asList(
+                                createDeviceStat("CONTROLLER", 2, 100.0, 0.0),
+                                createDeviceStat("SENSOR", 8, 98.0, 0.0),
+                                createDeviceStat("BROADCASTER", 3, 90.0, 0.0)
+                        ),
+                        "{\"lat\":30.124,\"lng\":120.457,\"heatData\":[[80,160,0.9],[220,90,0.7]]}",
+                        "0.78,800,95",
+                        "SENSOR,BROADCASTER",
+                        "在线"
+                ),createAreaEntry(
+                        "AREA-002", "1号大楼", "AREA-001", 2,
+                        Arrays.asList(
+                                createDeviceStat("CONTROLLER", 2, 100.0, 0.0),
+                                createDeviceStat("SENSOR", 8, 98.0, 0.0),
+                                createDeviceStat("BROADCASTER", 3, 90.0, 0.0)
+                        ),
+                        "{\"lat\":30.124,\"lng\":120.457,\"heatData\":[[80,160,0.9],[220,90,0.7]]}",
+                        "0.78,800,95",
+                        "SENSOR,BROADCASTER",
+                        "在线"
+                ),
+                // 二级区域:2号大楼
+                createAreaEntry(
+                        "AREA-003", "2号大楼", "AREA-001", 2,
+                        Arrays.asList(
+                                createDeviceStat("ACTUATOR", 5, 80.0, 10.0),
+                                createDeviceStat("MONITOR", 6, 92.0, 3.0),
+                                createDeviceStat("ALARM", 4, 95.0, 0.0)
+                        ),
+                        "{\"lat\":30.125,\"lng\":120.458,\"heatData\":[[120,250,0.7],[280,110,0.5]]}",
+                        "0.91,1500,88",
+                        "ACTUATOR,MONITOR",
+                        "在线,故障"
+                ),
+                // 三级区域:1楼大厅(AREA-002子区域)
+                createAreaEntry(
+                        "AREA-004", "1楼大厅", "AREA-002", 3,
+                        Arrays.asList(
+                                createDeviceStat("SENSOR", 3, 100.0, 0.0),
+                                createDeviceStat("BROADCASTER", 2, 100.0, 0.0)
+                        ),
+                        "{\"lat\":30.1245,\"lng\":120.4572,\"heatData\":[[210,230,0.95],[300,170,0.9]]}",
+                        "0.88,300,98",
+                        "SENSOR",
+                        "在线"
+                ),
+                // 三级区域:2楼机房(AREA-003子区域)
+                createAreaEntry(
+                        "AREA-005", "2楼机房", "AREA-003", 3,
+                        Arrays.asList(
+                                createDeviceStat("ACTUATOR", 3, 75.0, 15.0),
+                                createDeviceStat("MONITOR", 4, 90.0, 5.0)
+                        ),
+                        "{\"lat\":30.1255,\"lng\":120.4583,\"heatData\":[[170,130,0.6],[240,150,0.8]]}",
+                        "0.95,2000,85",
+                        "ACTUATOR",
+                        "故障"
+                ),
+                // 新增5个区域数据
+                createAreaEntry(
+                        "AREA-006", "3号大楼", "AREA-001", 2,
+                        Arrays.asList(
+                                createDeviceStat("INPUT", 2, 100.0, 0.0),
+                                createDeviceStat("ALARM", 5, 96.0, 0.0)
+                        ),
+                        "{\"lat\":30.126,\"lng\":120.459,\"heatData\":[[110,300,0.8],[190,220,0.7]]}",
+                        "0.82,600,94",
+                        "INPUT,ALARM",
+                        "在线"
+                ),
+                createAreaEntry(
+                        "AREA-007", "地下车库", "AREA-001", 2,
+                        Arrays.asList(
+                                createDeviceStat("SENSOR", 10, 90.0, 2.0),
+                                createDeviceStat("ACTUATOR", 4, 85.0, 5.0)
+                        ),
+                        "{\"lat\":30.122,\"lng\":120.455,\"heatData\":[[90,190,0.7],[140,280,0.6]]}",
+                        "0.75,1000,90",
+                        "SENSOR,ACTUATOR",
+                        "在线,故障"
+                ),
+                createAreaEntry(
+                        "AREA-008", "实验室", "AREA-003", 3,
+                        Arrays.asList(
+                                createDeviceStat("MONITOR", 3, 95.0, 0.0),
+                                createDeviceStat("ALARM", 2, 100.0, 0.0)
+                        ),
+                        "{\"lat\":30.1258,\"lng\":120.4588,\"heatData\":[[230,140,0.9],[290,270,0.8]]}",
+                        "0.90,1800,93",
+                        "MONITOR",
+                        "在线"
+                ),
+                createAreaEntry(
+                        "AREA-009", "会议室", "AREA-002", 3,
+                        Arrays.asList(
+                                createDeviceStat("BROADCASTER", 2, 100.0, 0.0),
+                                createDeviceStat("SENSOR", 1, 100.0, 0.0)
+                        ),
+                        "{\"lat\":30.1242,\"lng\":120.4575,\"heatData\":[[310,210,0.98],[320,220,0.95]]}",
+                        "0.85,200,99",
+                        "BROADCASTER",
+                        "在线"
+                ),
+                createAreaEntry(
+                        "AREA-0010", "天台", "AREA-003", 3,
+                        Arrays.asList(
+                                createDeviceStat("ACTUATOR", 1, 100.0, 0.0),
+                                createDeviceStat("SENSOR", 1, 100.0, 0.0)
+                        ),
+                        "{\"lat\":30.1259,\"lng\":120.4589,\"heatData\":[[160,120,1.0],[250,180,0.9]]}",
+                        "0.99,50,100",
+                        "ACTUATOR,SENSOR",
+                        "在线"
+                )
+        );
+    }
+
+    private static Map<String, Object> createAreaEntry(
+            String areaId, String areaName, String parentAreaId, int level,
+            List<Map<String, Object>> deviceStats,
+            String heatmapData,
+            String keyMetrics,
+            String deviceFilters,
+            String statusFilters
+    ) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("areaId", areaId); // 区域ID
+        data.put("areaName", areaName); // 区域名称
+        data.put("parentAreaId", parentAreaId); // 父区域ID
+        data.put("level", level); // 层级
+        data.put("deviceStats", deviceStats); // 设备统计
+        data.put("heatmapData", heatmapData); // 位置热力图数据
+        data.put("keyMetrics", keyMetrics); // 关键指标(平均能耗,最大负载,健康指数)
+        data.put("deviceFilters", deviceFilters); // 设备类型过滤器
+        data.put("statusFilters", statusFilters); // 状态过滤器
+        return data;
+    }
+
+    private static Map<String, Object> createDeviceStat(
+            String deviceType, double count, double onlineRate, double faultRate
+    ) {
+        Map<String, Object> stat = new HashMap<>();
+        stat.put("deviceType", deviceType);
+        stat.put("count", count);
+        stat.put("onlineRate", onlineRate);
+        stat.put("faultRate", faultRate);
+        return stat;
+    }
+
+
+    public static List<Map<String, Object>> generateControlCommands() {
+        return Arrays.asList(
+                // 基础指令
+                createCommandEntry(
+                        "CMD-001", Arrays.asList("DEV-001", "DEV-002"), "SET_TEMPERATURE", "{\"targetTemp\":24}",
+                        "SUCCESS", "2025-06-03 10:05:23", "陈俊杰", "192.168.1.101",
+                        "调整主控制室温度", "ON", 500, "NONE",
+                        "每天08:00自动执行", "办公模式", "与消防系统联动"
+                ),
+                createCommandEntry(
+                        "CMD-002", Arrays.asList("DEV-015"), "SET_SPEED", "{\"speedLevel\":3}",
+                        "PENDING", "2025-06-03 10:12:45", "林思彤", "192.168.1.102",
+                        "设置空调风速", "WAITING", 0, "NONE",
+                        "每周一09:00", "节能模式", "无"
+                ),
+                createCommandEntry(
+                        "CMD-003", Arrays.asList("DEV-006", "DEV-014"), "TRIGGER_ALARM", "{}",
+                        "FAILED", "2025-06-03 10:20:18", "陈俊杰", "192.168.1.101",
+                        "测试消防报警", "ERROR", 800, "ALARM_MODULE_FAILURE",
+                        "火灾检测触发", "紧急模式", "切断非消防电源"
+                ),
+                createCommandEntry(
+                        "CMD-004", Arrays.asList("DEV-008"), "START_PUMP", "{}",
+                        "SUCCESS", "2025-06-03 11:00:00", "王伟东", "192.168.1.103",
+                        "启动水泵", "OK", 300, "NONE",
+                        "水位低于阈值时", "供水模式", "联动水位传感器"
+                ),
+                createCommandEntry(
+                        "CMD-005", Arrays.asList("DEV-003", "DEV-009"), "ADJUST_VOLTAGE", "{\"voltage\":220}",
+                        "PENDING", "2025-06-03 13:15:30", "林思彤", "192.168.1.102",
+                        "调整电梯电压", "IDLE", 0, "NONE",
+                        "每月15日维护", "检修模式", "无"
+                ),
+                // 新增指令(6-10)
+                createCommandEntry(
+                        "CMD-006", Arrays.asList("DEV-004"), "TURN_ON_LIGHT", "{}",
+                        "SUCCESS", "2025-06-03 14:45:12", "黄雅琪", "192.168.1.104",
+                        "打开照明系统", "COMPLETED", 200, "NONE",
+                        "日落自动开启", "照明模式", "联动光照传感器"
+                ),
+                createCommandEntry(
+                        "CMD-007", Arrays.asList("DEV-005"), "STOP_GENERATOR", "{}",
+                        "FAILED", "2025-06-03 15:23:47", "陈俊杰", "192.168.1.101",
+                        "停止备用发电机", "TIMEOUT", 1200, "COMMUNICATION_ERROR",
+                        "市电恢复时", "备用模式", "联动电力监测"
+                ),
+                createCommandEntry(
+                        "CMD-008", Arrays.asList("DEV-012", "DEV-018"), "SET_HUMIDITY", "{\"humidity\":55}",
+                        "SUCCESS", "2025-06-03 16:08:59", "王伟东", "192.168.1.103",
+                        "调节工厂湿度", "DONE", 450, "NONE",
+                        "每小时自动调节", "生产模式", "无"
+                ),
+                createCommandEntry(
+                        "CMD-009", Arrays.asList("DEV-013"), "CALIBRATE_PH", "{\"offset\":-0.1}",
+                        "PROCESSING", "2025-06-03 17:30:00", "黄雅琪", "192.168.1.104",
+                        "校准实验室PH值", "CALIBRATING", 600, "NONE",
+                        "每周三17:00", "校准模式", "联动水质监测"
+                ),
+                createCommandEntry(
+                        "CMD-010", Arrays.asList("DEV-019", "DEV-020"), "RESET_DEVICE", "{}",
+                        "SUCCESS", "2025-06-03 18:00:00", "赵宇航", "192.168.1.105",
+                        "重置仓库设备", "RESET_OK", 350, "NONE",
+                        "设备异常时自动", "重置模式", "联动设备状态检测"
+                ),
+                // 新增指令(11-15)
+                createCommandEntry(
+                        "CMD-011", Arrays.asList("DEV-021"), "UPDATE_FIRMWARE", "{\"version\":\"v2.3.1\"}",
+                        "SUCCESS", "2025-06-03 09:30:15", "周文静", "192.168.1.106",
+                        "升级传感器固件", "UPDATED", 1500, "NONE",
+                        "每月1日自动升级", "维护模式", "无"
+                ),
+                createCommandEntry(
+                        "CMD-012", Arrays.asList("DEV-022", "DEV-023"), "OPEN_VALVE", "{\"degree\":75}",
+                        "FAILED", "2025-06-03 12:45:32", "王伟东", "192.168.1.103",
+                        "打开排水阀", "VALVE_ERROR", 900, "MECHANICAL_FAILURE",
+                        "水位超过阈值时", "防洪模式", "联动水位传感器"
+                ),
+                createCommandEntry(
+                        "CMD-013", Arrays.asList("DEV-024"), "SET_FREQUENCY", "{\"hz\":50}",
+                        "PENDING", "2025-06-03 14:20:10", "林思彤", "192.168.1.102",
+                        "设置电机频率", "WAITING_CONFIRM", 0, "NONE",
+                        "根据负载自动调整", "智能模式", "联动功率监测"
+                ),
+                createCommandEntry(
+                        "CMD-014", Arrays.asList("DEV-025"), "ENABLE_SECURITY", "{}",
+                        "SUCCESS", "2025-06-03 17:15:45", "吴思远", "192.168.1.107",
+                        "启用安防系统", "SECURED", 400, "NONE",
+                        "下班后自动启用", "安防模式", "联动摄像头"
+                ),
+                createCommandEntry(
+                        "CMD-015", Arrays.asList("DEV-026", "DEV-027"), "SWITCH_MODE", "{\"mode\":\"auto\"}",
+                        "PROCESSING", "2025-06-03 18:30:20", "陈俊杰", "192.168.1.101",
+                        "切换自动模式", "SWITCHING", 700, "NONE",
+                        "日出/日落自动切换", "智能模式", "联动光照传感器"
+                )
+        );
+    }
+
+    private static Map<String, Object> createCommandEntry(
+            String cmdId, List<String> targetDevices, String cmdType, String params,
+            String status, String timestamp, String operatorId, String ipAddress,
+            String operationDetail, String feedbackStatus, int executionTime, String errorCode,
+            String scheduleTask, String sceneMode, String linkageRule
+    ) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("cmdId", cmdId);
+        data.put("targetDevices", targetDevices);
+        data.put("cmdType", cmdType);
+        data.put("params", params);
+        data.put("status", status);
+        data.put("timestamp", timestamp);
+        data.put("operatorId", operatorId);
+        data.put("ipAddress", ipAddress);
+        data.put("operationDetail", operationDetail);
+        data.put("feedbackStatus", feedbackStatus);
+        data.put("executionTime", executionTime);
+        data.put("errorCode", errorCode);
+        data.put("scheduleTask", scheduleTask);
+        data.put("sceneMode", sceneMode);
+        data.put("linkageRule", linkageRule);
+        return data;
+    }
+
+
+
+    @GetMapping("/generateDeviceConfigurationData")
+    public Map<String, Object> getGenerateDeviceConfigurationData() throws Exception {
+        List<Map<String, Object>> data = generateConfigurationData();
+        PageData pd = this.getPageData();
+        String deviceId = pd.getString("deviceId");
+        String version = pd.getString("version");
+        String configId = pd.getString("configId");
+        String displayFormat = pd.getString("displayFormat");
+        // 条件过滤    configId: '',
+        //  version: '',
+        if (deviceId != null && !deviceId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceId").toString().contains(deviceId))
+                    .collect(Collectors.toList());
+        }
+        if (version != null && !version.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("version").toString().contains(version))
+                    .collect(Collectors.toList());
+        }
+        if (configId != null && !configId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("configId").toString().contains(configId))
+                    .collect(Collectors.toList());
+        }
+        if (displayFormat != null && !displayFormat.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("displayFormat").toString().contains(displayFormat))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+    @GetMapping("/generateDeviceData")
+    public Map<String, Object> getGenerateDeviceData() throws Exception {
+        List<Map<String, Object>> data = generateDeviceData();
+        PageData pd = this.getPageData();
+        String deviceName = pd.getString("deviceName");
+        String deviceType = pd.getString("deviceType");
+        String floor = pd.getString("floor");
+        String area = pd.getString("area");
+        String status = pd.getString("status");
+        // 条件过滤
+        if (deviceName != null && !deviceName.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceName").toString().contains(deviceName))
+                    .collect(Collectors.toList());
+        }
+        if (deviceType != null && !deviceType.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceType").toString().contains(deviceType))
+                    .collect(Collectors.toList());
+        }
+        if (floor != null && !floor.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("floor").toString().contains(floor))
+                    .collect(Collectors.toList());
+        }
+        if (area != null && !area.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("area").toString().contains(area))
+                    .collect(Collectors.toList());
+        }
+        if (status != null && !status.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("status").toString().contains(status))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    @GetMapping("/generateAreaData")
+    public Map<String, Object> getGenerateAreaData() throws Exception {
+        List<Map<String, Object>> data = generateAreaData();
+        PageData pd = this.getPageData();
+        String deviceName = pd.getString("deviceName");
+        String deviceType = pd.getString("deviceType");
+        String floor = pd.getString("floor");
+        String area = pd.getString("area");
+        String status = pd.getString("status");
+        // 条件过滤
+        if (deviceName != null && !deviceName.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceName").toString().contains(deviceName))
+                    .collect(Collectors.toList());
+        }
+        if (deviceType != null && !deviceType.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceType").toString().contains(deviceType))
+                    .collect(Collectors.toList());
+        }
+        if (floor != null && !floor.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("floor").toString().contains(floor))
+                    .collect(Collectors.toList());
+        }
+        if (area != null && !area.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("area").toString().contains(area))
+                    .collect(Collectors.toList());
+        }
+        if (status != null && !status.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("status").toString().contains(status))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+    @GetMapping("/generateCommandsData")
+    public Map<String, Object> getGenerateCommandsData() throws Exception {
+        List<Map<String, Object>> data = generateControlCommands();
+        PageData pd = this.getPageData();
+        String cmdId = pd.getString("cmdId");
+        String cmdType = pd.getString("cmdType");
+        String operatorId = pd.getString("operatorId");
+        String feedbackStatus = pd.getString("feedbackStatus");
+        String status = pd.getString("status");
+        // 条件过滤
+        if (cmdId != null && !cmdId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("cmdId").toString().contains(cmdId))
+                    .collect(Collectors.toList());
+        }
+        if (cmdType != null && !cmdType.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("cmdType").toString().contains(cmdType))
+                    .collect(Collectors.toList());
+        }
+        if (operatorId != null && !operatorId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("operatorId").toString().contains(operatorId))
+                    .collect(Collectors.toList());
+        }
+        if (feedbackStatus != null && !feedbackStatus.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("feedbackStatus").toString().contains(feedbackStatus))
+                    .collect(Collectors.toList());
+        }
+        if (status != null && !status.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("status").toString().contains(status))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+}

+ 205 - 0
pm-admin/src/main/java/com/pm/web/controller/driverInfo/DriverInfoController.java

@@ -0,0 +1,205 @@
+package com.pm.web.controller.driverInfo;
+
+import com.pm.common.config.PageData;
+import com.pm.common.core.controller.BaseController;
+import com.pm.interfaceInfo.service.InterfaceInfoService;
+import okhttp3.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 信息引导及发布系统接口
+ */
+@RestController
+@RequestMapping("/driverInfo/info")
+public class DriverInfoController  extends BaseController {
+
+
+    /**
+     * 查询url 访问接口
+     */
+    @Autowired
+    private InterfaceInfoService interfaceInfoService;
+
+    // 生成模拟数据
+    private List<Map<String, Object>> generateDeviceData() {
+        return Arrays.asList(
+                Map.of("id", "DEV2024001", "name", "主入口LED屏", "location", "A栋大厅正门", "deviceType", "户外全彩", "status", "在线", "ipAddress", "192.168.1.10", "screenSize", "86英寸", "lastOnlineTime", "2025-05-30 10:23:15"),
+                Map.of("id", "DEV2024002", "name", "电梯广告机", "location", "B1层电梯厅", "deviceType", "液晶广告机", "status", "离线", "ipAddress", "192.168.1.11", "screenSize", "55英寸", "lastOnlineTime", "2025-05-29 18:40:22"),
+                Map.of("id", "DEV2024003", "name", "会议室投影", "location", "3F-301会议室", "deviceType", "激光投影", "status", "在线", "ipAddress", "192.168.1.12", "screenSize", "120英寸", "lastOnlineTime", "2025-05-30 09:15:33"),
+                Map.of("id", "DEV2024004", "name", "停车场引导屏", "location", "P2层C区通道", "deviceType", "单色LED", "status", "故障", "ipAddress", "192.168.1.13", "screenSize", "-", "lastOnlineTime", "2025-05-28 14:57:01"),
+                Map.of("id", "DEV2024005", "name", "餐厅信息屏", "location", "员工餐厅入口", "deviceType", "触摸一体机", "status", "在线", "ipAddress", "192.168.1.14", "screenSize", "65英寸", "lastOnlineTime", "2025-05-30 11:05:44"),
+                Map.of("id", "DEV2024006", "name", "户外广告牌", "location", "园区南门", "deviceType", "全彩LED", "status", "在线", "ipAddress", "192.168.1.15", "screenSize", "320英寸", "lastOnlineTime", "2025-05-30 08:30:19"),
+                Map.of("id", "DEV2024007", "name", "前台信息终端", "location", "总部服务台", "deviceType", "立式广告机", "status", "在线", "ipAddress", "192.168.1.16", "screenSize", "43英寸", "lastOnlineTime", "2025-05-30 10:44:37"),
+                Map.of("id", "DEV2024008", "name", "仓库监控屏", "location", "物流中心D区", "deviceType", "监控电视", "status", "离线", "ipAddress", "192.168.1.17", "screenSize", "75英寸", "lastOnlineTime", "2025-05-27 16:20:58"),
+                Map.of("id", "DEV2024009", "name", "展厅互动屏", "location", "创新展厅2号位", "deviceType", "触摸桌", "status", "在线", "ipAddress", "192.168.1.18", "screenSize", "85英寸", "lastOnlineTime", "2025-05-30 09:51:26"),
+                Map.of("id", "DEV2024010", "name", "消防信息屏", "location", "安全通道1F", "deviceType", "应急屏", "status", "故障", "ipAddress", "192.168.1.19", "screenSize", "32英寸", "lastOnlineTime", "2025-05-29 22:10:05"),
+                Map.of("id", "DEV2024011", "name", "户外气象屏", "location", "园区东广场", "deviceType", "全彩LED", "status", "在线", "ipAddress", "192.168.1.20", "screenSize", "240英寸", "lastOnlineTime", "2025-05-30 07:45:11"),
+                Map.of("id", "DEV2024012", "name", "会议预约屏", "location", "行政楼2F走廊", "deviceType", "电子墨水屏", "status", "在线", "ipAddress", "192.168.1.21", "screenSize", "21.5英寸", "lastOnlineTime", "2025-05-30 10:30:48"),
+                Map.of("id", "DEV2024013", "name", "医疗宣教屏", "location", "医务室门口", "deviceType", "壁挂广告机", "status", "离线", "ipAddress", "192.168.1.22", "screenSize", "50英寸", "lastOnlineTime", "2025-05-26 11:15:39"),
+                Map.of("id", "DEV2024014", "name", "车间看板", "location", "生产车间3线", "deviceType", "工业电视", "status", "在线", "ipAddress", "192.168.1.23", "screenSize", "65英寸", "lastOnlineTime", "2025-05-30 08:17:54"),
+                Map.of("id", "DEV2024015", "name", "访客登记屏", "location", "西门接待处", "deviceType", "触摸一体机", "status", "在线", "ipAddress", "192.168.1.24", "screenSize", "32英寸", "lastOnlineTime", "2025-05-30 11:22:06")
+        );
+    }
+
+    // 查询信息引导及发布(支持分页和条件查询)
+    @GetMapping("/driverList")
+    public Map<String, Object> getDoorDevices() throws Exception {
+        List<Map<String, Object>> data = generateDeviceData();
+        PageData pd = this.getPageData();
+        String location = pd.getString("location");
+        String name = pd.getString("name");
+        // 条件过滤
+        if (location != null && !location.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("location").toString().contains(location))
+                    .collect(Collectors.toList());
+        }
+        if (name != null && !name.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("name").toString().equalsIgnoreCase(name))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    /**
+     * 查询门禁管理列表
+     * @return
+     */
+    @GetMapping("/list")
+    public String list()
+    {
+        PageData pd = this.getPageData();
+        Response response = null;
+        try{
+            String name = "";
+            String appoint_time = "";
+            if (pd.containsKey("search")){
+                name = pd.getString("search");
+            }
+            if (pd.containsKey("appoint_time")){
+                appoint_time = pd.getString("appoint_time");
+            }
+            String info = "{\n" +
+                    "  \"date\": \""+pd.getString("date")+"\",\n" +
+                    "  \"search\": \""+name+"\",\n" +
+                    "  \"locationId\": [],\n" +
+                    "  \"capacity\": [],\n" +
+                    "  \"deviceType\": [],\n" +
+                    "  \"roomType\": [\n" +
+                    "    -1\n" +
+                    "  ],\n" +
+                    "  \"appoint_time\": \""+appoint_time+"\",\n" +
+                    "  \"status\": 1,\n" +
+                    "  \"page\": "+pd.getInteger("pageNum")+",\n" +
+                    "  \"page_size\": "+pd.getInteger("pageSize")+"\n" +
+                    "}";
+            PageData interface_info = interfaceInfoService.selectInterfaceInfoByName(pd.getString("interfaceName"));
+
+            pd.put("url",interface_info.get("url"));
+            OkHttpClient client = new OkHttpClient().newBuilder()
+                    .build();
+            MediaType mediaType = MediaType.parse("application/json");
+            RequestBody body = RequestBody.create(mediaType, info);
+            Request request = new Request.Builder()
+                    .url(interface_info.getString("url"))
+                    .method("POST", body)
+                    .addHeader("Content-Type", "application/json")
+                    .build();
+            response = client.newCall(request).execute();
+        } catch (Exception e){
+            e.printStackTrace();
+        }
+        try {
+            return response.body().string();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 查询历史记录
+     * @return
+     */
+    @GetMapping("/listHistory")
+    public String listHistory() throws Exception {
+        PageData pd = this.getPageData();
+        // 获取接口地址
+        PageData interface_info = interfaceInfoService.selectInterfaceInfoByName(pd.getString("interfaceName"));
+        String url = interface_info.getString("url");
+
+        // 构造请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("date", pd.getString("date"));
+        params.put("search", pd.getString("search"));
+        //params.put("appoint_time", );
+        params.put("status", String.valueOf(pd.getInteger("status")));
+        params.put("page", String.valueOf(pd.getInteger("pageNum")));
+        params.put("pageSize", String.valueOf(pd.getInteger("pageSize")));
+        params.put("locationId", ""); // 空数组
+        params.put("capacity", "");  // 空数组
+        params.put("deviceType", ""); // 空数组
+        params.put("roomType", "-1");
+        params.put("is_external", String.valueOf(pd.getInteger("is_external")));
+
+        // 构造完整的 URL
+        StringBuilder urlBuilder = new StringBuilder(url);
+        boolean firstParam = true;
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
+                if (firstParam) {
+                    urlBuilder.append("?");
+                    firstParam = false;
+                } else {
+                    urlBuilder.append("&");
+                }
+                urlBuilder.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
+                        .append("=")
+                        .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
+            }
+        }
+
+        // 使用 OkHttpClient 发送 GET 请求
+        OkHttpClient client = new OkHttpClient().newBuilder()
+                .build();
+
+        Request request = new Request.Builder()
+                .url(urlBuilder.toString())
+                .method("GET", null)
+                .build();
+
+        try (Response response = client.newCall(request).execute()) {
+            if (!response.isSuccessful()) {
+                throw new RuntimeException("External API call failed with status code: " + response.code());
+            }
+            return response.body().string();
+        } catch (IOException e) {
+            throw new RuntimeException("Error calling external API", e);
+        }
+    }
+}

+ 642 - 0
pm-admin/src/main/java/com/pm/web/controller/estateManagement/EstateManagementController.java

@@ -0,0 +1,642 @@
+package com.pm.web.controller.estateManagement;
+
+import com.pm.common.config.PageData;
+import com.pm.common.core.controller.BaseController;
+import com.pm.interfaceInfo.service.InterfaceInfoService;
+import okhttp3.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 物业管理
+ */
+@RestController
+@RequestMapping("/estateManagement/info")
+public class EstateManagementController  extends BaseController {
+
+
+    /**
+     * 查询url 访问接口
+     */
+    @Autowired
+    private InterfaceInfoService interfaceInfoService;
+
+    // 生成模拟数据 业主档案
+    private List<Map<String, Object>> generateOwnerData() {
+        return Arrays.asList(
+                Map.of("ownerId", "OWN2024001", "name", "林建国", "buildingNo", "8栋", "roomNo", "101", "phone", "13800138000", "moveInDate", "2020-05-18", "emergencyContact", "林小伟", "parkingSpace", "A-01", "petInfo", "金毛犬,体重30kg"),
+                Map.of("ownerId", "OWN2024002", "name", "刘文静", "buildingNo", "3栋", "roomNo", "202", "phone", "13500135000", "moveInDate", "2021-03-22", "emergencyContact", "张明", "parkingSpace", "B-12", "petInfo", "无"),
+                Map.of("ownerId", "OWN2024003", "name", "王浩宇", "buildingNo", "5栋", "roomNo", "303", "phone", "13900139000", "moveInDate", "2019-12-05", "emergencyContact", "陈燕", "parkingSpace", "C-05", "petInfo", "布偶猫,已绝育"),
+                Map.of("ownerId", "OWN2024004", "name", "赵敏", "buildingNo", "2栋", "roomNo", "404", "phone", "13600136000", "moveInDate", "2022-08-10", "emergencyContact", "赵亮", "parkingSpace", "D-18", "petInfo", "无"),
+                Map.of("ownerId", "OWN2024005", "name", "陈思远", "buildingNo", "9栋", "roomNo", "505", "phone", "13700137000", "moveInDate", "2020-07-25", "emergencyContact", "李娜", "parkingSpace", "E-09", "petInfo", "鹦鹉,笼养"),
+                Map.of("ownerId", "OWN2024006", "name", "周雨欣", "buildingNo", "6栋", "roomNo", "606", "phone", "13400134000", "moveInDate", "2023-01-15", "emergencyContact", "周建国", "parkingSpace", "F-20", "petInfo", "无"),
+                Map.of("ownerId", "OWN2024007", "name", "吴俊杰", "buildingNo", "1栋", "roomNo", "707", "phone", "13300133000", "moveInDate", "2018-09-08", "emergencyContact", "吴敏", "parkingSpace", "G-03", "petInfo", "柴犬,疫苗齐全"),
+                Map.of("ownerId", "OWN2024008", "name", "郑梦琪", "buildingNo", "4栋", "roomNo", "808", "phone", "13200132000", "moveInDate", "2021-11-30", "emergencyContact", "郑海涛", "parkingSpace", "H-15", "petInfo", "无"),
+                Map.of("ownerId", "OWN2024009", "name", "王伟", "buildingNo", "7栋", "roomNo", "909", "phone", "13100131000", "moveInDate", "2020-04-12", "emergencyContact", "张婷", "parkingSpace", "I-07", "petInfo", "金鱼,5条"),
+                Map.of("ownerId", "OWN2024010", "name", "李佳怡", "buildingNo", "10栋", "roomNo", "1010", "phone", "18800188000", "moveInDate", "2022-06-01", "emergencyContact", "李建军", "parkingSpace", "J-22", "petInfo", "无"),
+                Map.of("ownerId", "OWN2024011", "name", "张雪", "buildingNo", "3栋", "roomNo", "1111", "phone", "18500185000", "moveInDate", "2023-03-18", "emergencyContact", "张强", "parkingSpace", "B-08", "petInfo", "乌龟,两只"),
+                Map.of("ownerId", "OWN2024012", "name", "陈明", "buildingNo", "5栋", "roomNo", "1212", "phone", "18600186000", "moveInDate", "2019-07-20", "emergencyContact", "陈璐", "parkingSpace", "C-14", "petInfo", "无"),
+                Map.of("ownerId", "OWN2024013", "name", "周思远", "buildingNo", "8栋", "roomNo", "1313", "phone", "18700187000", "moveInDate", "2021-02-28", "emergencyContact", "周洋", "parkingSpace", "A-16", "petInfo", "兔子,白色"),
+                Map.of("ownerId", "OWN2024014", "name", "吴雨", "buildingNo", "6栋", "roomNo", "1414", "phone", "18900189000", "moveInDate", "2020-10-05", "emergencyContact", "吴静", "parkingSpace", "F-04", "petInfo", "无毛猫,需特殊照顾"),
+                Map.of("ownerId", "OWN2024015", "name", "郑浩然", "buildingNo", "2栋", "roomNo", "1515", "phone", "18000180000", "moveInDate", "2022-12-31", "emergencyContact", "郑云", "parkingSpace", "D-24", "petInfo", "无")
+        );
+    }
+
+    // 生成模拟数据 物业费用信息
+    private List<Map<String, Object>> generateFeeData() {
+        return Arrays.asList(
+                Map.of("billId", "FEE2024001", "ownerId", "OWN2024001", "feeType", "物业费", "dueAmount", 800.00, "paidAmount", 800.00, "arrearsStatus", "已结清", "dueDate", "2024-05-31"),
+                Map.of("billId", "FEE2024002", "ownerId", "OWN2024002", "feeType", "水费", "dueAmount", 56.80, "paidAmount", 0.00, "arrearsStatus", "未缴纳", "dueDate", "2024-05-20"),
+                Map.of("billId", "FEE2024003", "ownerId", "OWN2024003", "feeType", "电费", "dueAmount", 123.50, "paidAmount", 123.50, "arrearsStatus", "已结清", "dueDate", "2024-05-15"),
+                Map.of("billId", "FEE2024004", "ownerId", "OWN2024004", "feeType", "物业费", "dueAmount", 750.00, "paidAmount", 300.00, "arrearsStatus", "部分缴纳", "dueDate", "2024-06-30"),
+                Map.of("billId", "FEE2024005", "ownerId", "OWN2024005", "feeType", "水费", "dueAmount", 48.20, "paidAmount", 48.20, "arrearsStatus", "已结清", "dueDate", "2024-05-25"),
+                Map.of("billId", "FEE2024006", "ownerId", "OWN2024006", "feeType", "电费", "dueAmount", 98.70, "paidAmount", 0.00, "arrearsStatus", "未缴纳", "dueDate", "2024-05-10"),
+                Map.of("billId", "FEE2024007", "ownerId", "OWN2024007", "feeType", "物业费", "dueAmount", 900.00, "paidAmount", 900.00, "arrearsStatus", "已结清", "dueDate", "2024-05-31"),
+                Map.of("billId", "FEE2024008", "ownerId", "OWN2024008", "feeType", "水费", "dueAmount", 62.30, "paidAmount", 0.00, "arrearsStatus", "未缴纳", "dueDate", "2024-05-20"),
+                Map.of("billId", "FEE2024009", "ownerId", "OWN2024009", "feeType", "电费", "dueAmount", 156.90, "paidAmount", 156.90, "arrearsStatus", "已结清", "dueDate", "2024-05-15"),
+                Map.of("billId", "FEE2024010", "ownerId", "OWN2024010", "feeType", "物业费", "dueAmount", 850.00, "paidAmount", 500.00, "arrearsStatus", "部分缴纳", "dueDate", "2024-06-30"),
+                Map.of("billId", "FEE2024011", "ownerId", "OWN2024011", "feeType", "水费", "dueAmount", 52.50, "paidAmount", 52.50, "arrearsStatus", "已结清", "dueDate", "2024-05-25"),
+                Map.of("billId", "FEE2024012", "ownerId", "OWN2024012", "feeType", "电费", "dueAmount", 89.40, "paidAmount", 0.00, "arrearsStatus", "未缴纳", "dueDate", "2024-05-10"),
+                Map.of("billId", "FEE2024013", "ownerId", "OWN2024013", "feeType", "物业费", "dueAmount", 780.00, "paidAmount", 780.00, "arrearsStatus", "已结清", "dueDate", "2024-05-31"),
+                Map.of("billId", "FEE2024014", "ownerId", "OWN2024014", "feeType", "水费", "dueAmount", 59.10, "paidAmount", 0.00, "arrearsStatus", "未缴纳", "dueDate", "2024-05-20"),
+                Map.of("billId", "FEE2024015", "ownerId", "OWN2024015", "feeType", "电费", "dueAmount", 112.20, "paidAmount", 112.20, "arrearsStatus", "已结清", "dueDate", "2024-05-15")
+        );
+    }
+
+    // 生成模拟数据 设施设备信息
+    private List<Map<String, Object>> generateFacilityData() {
+        return Arrays.asList(
+                Map.of("deviceId", "DEV2024001", "name", "乘客电梯", "deviceType", "电梯", "location", "1栋1单元", "brandModel", "通力KONE 3000", "maintenanceCycle", "15天", "status", "正常", "lastMaintenanceDate", "2024-05-20"),
+                Map.of("deviceId", "DEV2024002", "name", "消防水泵", "deviceType", "水泵", "location", "地下车库B区", "brandModel", "上海东方泵业 D120-50", "maintenanceCycle", "30天", "status", "正常", "lastMaintenanceDate", "2024-05-10"),
+                Map.of("deviceId", "DEV2024003", "name", "配电箱", "deviceType", "配电箱", "location", "3栋负一层", "brandModel", "施耐德 Electric iPM", "maintenanceCycle", "90天", "status", "正常", "lastMaintenanceDate", "2024-04-30"),
+                Map.of("deviceId", "DEV2024004", "name", "中央空调主机", "deviceType", "空调", "location", "设备机房", "brandModel", "大金 VRV-X7", "maintenanceCycle", "60天", "status", "待维保", "lastMaintenanceDate", "2024-03-25"),
+                Map.of("deviceId", "DEV2024005", "name", "自动扶梯", "deviceType", "电梯", "location", "商业中心1楼", "brandModel", "迅达 Schindler 9300AE", "maintenanceCycle", "15天", "status", "正常", "lastMaintenanceDate", "2024-05-18"),
+                Map.of("deviceId", "DEV2024006", "name", "生活水泵", "deviceType", "水泵", "location", "水泵房", "brandModel", "格兰富 CR32-4", "maintenanceCycle", "30天", "status", "正常", "lastMaintenanceDate", "2024-05-05"),
+                Map.of("deviceId", "DEV2024007", "name", "消防控制柜", "deviceType", "消防设备", "location", "1栋消防控制室", "brandModel", "北大青鸟 JBF-11S", "maintenanceCycle", "60天", "status", "正常", "lastMaintenanceDate", "2024-04-20"),
+                Map.of("deviceId", "DEV2024008", "name", "电梯", "deviceType", "电梯", "location", "2栋2单元", "brandModel", "日立 HGP-825-C090", "maintenanceCycle", "15天", "status", "维修中", "lastMaintenanceDate", "2024-05-15"),
+                Map.of("deviceId", "DEV2024009", "name", "配电箱", "deviceType", "配电箱", "location", "5栋首层", "brandModel", "ABB MNS", "maintenanceCycle", "90天", "status", "正常", "lastMaintenanceDate", "2024-04-10"),
+                Map.of("deviceId", "DEV2024010", "name", "景观喷泉泵", "deviceType", "水泵", "location", "中心花园", "brandModel", "威乐 WILO-SL 202", "maintenanceCycle", "45天", "status", "正常", "lastMaintenanceDate", "2024-05-01"),
+                Map.of("deviceId", "DEV2024011", "name", "电梯", "deviceType", "电梯", "location", "3栋3单元", "brandModel", "通力KONE MonoSpace", "maintenanceCycle", "15天", "status", "正常", "lastMaintenanceDate", "2024-05-22"),
+                Map.of("deviceId", "DEV2024012", "name", "消防栓泵", "deviceType", "水泵", "location", "地下车库A区", "brandModel", "凯泉 KQL200/315-45/4", "maintenanceCycle", "30天", "status", "正常", "lastMaintenanceDate", "2024-05-08"),
+                Map.of("deviceId", "DEV2024013", "name", "监控主机", "deviceType", "监控设备", "location", "物业监控室", "brandModel", "海康威视 DS-8664N-I8", "maintenanceCycle", "60天", "status", "正常", "lastMaintenanceDate", "2024-04-15"),
+                Map.of("deviceId", "DEV2024014", "name", "电梯", "deviceType", "电梯", "location", "4栋1单元", "brandModel", "奥的斯 Gen2", "maintenanceCycle", "15天", "status", "待维保", "lastMaintenanceDate", "2024-03-28"),
+                Map.of("deviceId", "DEV2024015", "name", "配电箱", "deviceType", "配电箱", "location", "6栋负一层", "brandModel", "西门子 SIVACON 8PS", "maintenanceCycle", "90天", "status", "正常", "lastMaintenanceDate", "2024-04-05")
+        );
+    }
+
+    // 生成模拟数据 安防监控中心
+    private List<Map<String, Object>> generateSecurityData() {
+        return Arrays.asList(
+                Map.of("cameraId", "CAM2024001", "location", "园区南门", "status", "在线", "storagePath", "/video/2024/CAM2024001", "lastTriggerTime", "2024-05-30 14:23:15", "alarmType", "人脸识别"),
+                Map.of("cameraId", "CAM2024002", "location", "1栋电梯厅", "status", "故障", "storagePath", "/video/2024/CAM2024002", "lastTriggerTime", "2024-05-29 09:40:22", "alarmType", "越界报警"),
+                Map.of("cameraId", "CAM2024003", "location", "地下车库B区", "status", "在线", "storagePath", "/video/2024/CAM2024003", "lastTriggerTime", "2024-05-30 10:15:33", "alarmType", "人脸识别"),
+                Map.of("cameraId", "CAM2024004", "location", "中心花园", "status", "在线", "storagePath", "/video/2024/CAM2024004", "lastTriggerTime", "2024-05-28 14:57:01", "alarmType", "越界报警"),
+                Map.of("cameraId", "CAM2024005", "location", "商业中心1楼", "status", "在线", "storagePath", "/video/2024/CAM2024005", "lastTriggerTime", "2024-05-30 11:05:44", "alarmType", "人脸识别"),
+                Map.of("cameraId", "CAM2024006", "location", "3栋走廊", "status", "故障", "storagePath", "/video/2024/CAM2024006", "lastTriggerTime", "2024-05-30 08:30:19", "alarmType", "越界报警"),
+                Map.of("cameraId", "CAM2024007", "location", "消防通道", "status", "在线", "storagePath", "/video/2024/CAM2024007", "lastTriggerTime", "2024-05-30 10:44:37", "alarmType", "人脸识别"),
+                Map.of("cameraId", "CAM2024008", "location", "停车场入口", "status", "在线", "storagePath", "/video/2024/CAM2024008", "lastTriggerTime", "2024-05-27 16:20:58", "alarmType", "越界报警"),
+                Map.of("cameraId", "CAM2024009", "location", "2栋电梯厅", "status", "在线", "storagePath", "/video/2024/CAM2024009", "lastTriggerTime", "2024-05-30 09:51:26", "alarmType", "人脸识别"),
+                Map.of("cameraId", "CAM2024010", "location", "设备机房", "status", "故障", "storagePath", "/video/2024/CAM2024010", "lastTriggerTime", "2024-05-29 22:10:05", "alarmType", "越界报警"),
+                Map.of("cameraId", "CAM2024011", "location", "园区东门", "status", "在线", "storagePath", "/video/2024/CAM2024011", "lastTriggerTime", "2024-05-30 07:45:11", "alarmType", "人脸识别"),
+                Map.of("cameraId", "CAM2024012", "location", "行政楼大厅", "status", "在线", "storagePath", "/video/2024/CAM2024012", "lastTriggerTime", "2024-05-30 10:30:48", "alarmType", "越界报警"),
+                Map.of("cameraId", "CAM2024013", "location", "食堂后厨", "status", "在线", "storagePath", "/video/2024/CAM2024013", "lastTriggerTime", "2024-05-26 11:15:39", "alarmType", "人脸识别"),
+                Map.of("cameraId", "CAM2024014", "location", "4栋楼梯间", "status", "在线", "storagePath", "/video/2024/CAM2024014", "lastTriggerTime", "2024-05-30 08:17:54", "alarmType", "越界报警"),
+                Map.of("cameraId", "CAM2024015", "location", "监控室", "status", "在线", "storagePath", "/video/2024/CAM2024015", "lastTriggerTime", "2024-05-30 11:22:06", "alarmType", "人脸识别")
+        );
+    }
+
+    // 生成模拟数据 工单管理
+    private List<Map<String, Object>> generateWorkOrderData() {
+        return Arrays.asList(
+                Map.of("orderId", "WO2024001", "submitter", "林建国", "type", "维修", "urgency", "紧急", "handler", "张三", "status", "处理中", "duration", "2.5小时"),
+                Map.of("orderId", "WO2024002", "submitter", "刘文静", "type", "清洁", "urgency", "普通", "handler", "李四", "status", "待接单", "duration", "-"),
+                Map.of("orderId", "WO2024003", "submitter", "王浩宇", "type", "投诉", "urgency", "普通", "handler", "-", "status", "待接单", "duration", "-"),
+                Map.of("orderId", "WO2024004", "submitter", "赵敏", "type", "维修", "urgency", "紧急", "handler", "王五", "status", "完成", "duration", "4小时"),
+                Map.of("orderId", "WO2024005", "submitter", "陈思远", "type", "清洁", "urgency", "普通", "handler", "赵六", "status", "处理中", "duration", "1.5小时"),
+                Map.of("orderId", "WO2024006", "submitter", "周雨欣", "type", "投诉", "urgency", "紧急", "handler", "陈七", "status", "完成", "duration", "3小时"),
+                Map.of("orderId", "WO2024007", "submitter", "吴俊杰", "type", "维修", "urgency", "普通", "handler", "周八", "status", "待接单", "duration", "-"),
+                Map.of("orderId", "WO2024008", "submitter", "郑梦琪", "type", "清洁", "urgency", "普通", "handler", "吴九", "status", "处理中", "duration", "2小时"),
+                Map.of("orderId", "WO2024009", "submitter", "王伟", "type", "投诉", "urgency", "紧急", "handler", "郑十", "status", "完成", "duration", "2.5小时"),
+                Map.of("orderId", "WO2024010", "submitter", "李佳怡", "type", "维修", "urgency", "普通", "handler", "王十一", "status", "待接单", "duration", "-"),
+                Map.of("orderId", "WO2024011", "submitter", "张雪", "type", "清洁", "urgency", "普通", "handler", "李十二", "status", "完成", "duration", "1小时"),
+                Map.of("orderId", "WO2024012", "submitter", "陈明", "type", "投诉", "urgency", "紧急", "handler", "张十三", "status", "处理中", "duration", "3.5小时"),
+                Map.of("orderId", "WO2024013", "submitter", "周思远", "type", "维修", "urgency", "紧急", "handler", "陈十四", "status", "完成", "duration", "5小时"),
+                Map.of("orderId", "WO2024014", "submitter", "吴雨", "type", "清洁", "urgency", "普通", "handler", "周十五", "status", "待接单", "duration", "-"),
+                Map.of("orderId", "WO2024015", "submitter", "郑浩然", "type", "投诉", "urgency", "普通", "handler", "吴十六", "status", "处理中", "duration", "2小时")
+        );
+    }
+
+    // 能源监测台
+    private List<Map<String, Object>> generateEnergyData() {
+        return Arrays.asList(
+                Map.of("meterId", "EM2024001", "buildingNo", "1栋", "lastMonthReading", 1250.0, "currentMonthReading", 1380.0, "warningValue", 1500.0, "yoyChange", "+10.4%"),
+                Map.of("meterId", "EM2024002", "buildingNo", "2栋", "lastMonthReading", 860.0, "currentMonthReading", 920.0, "warningValue", 1000.0, "yoyChange", "+6.9%"),
+                Map.of("meterId", "EM2024003", "buildingNo", "3栋", "lastMonthReading", 2300.0, "currentMonthReading", 2550.0, "warningValue", 2800.0, "yoyChange", "+10.9%"),
+                Map.of("meterId", "EM2024004", "buildingNo", "4栋", "lastMonthReading", 1500.0, "currentMonthReading", 1680.0, "warningValue", 1800.0, "yoyChange", "+12.0%"),
+                Map.of("meterId", "EM2024005", "buildingNo", "5栋", "lastMonthReading", 950.0, "currentMonthReading", 1020.0, "warningValue", 1100.0, "yoyChange", "+7.4%"),
+                Map.of("meterId", "EM2024006", "buildingNo", "6栋", "lastMonthReading", 3200.0, "currentMonthReading", 3500.0, "warningValue", 3800.0, "yoyChange", "+9.4%"),
+                Map.of("meterId", "EM2024007", "buildingNo", "7栋", "lastMonthReading", 1800.0, "currentMonthReading", 1950.0, "warningValue", 2100.0, "yoyChange", "+8.3%"),
+                Map.of("meterId", "EM2024008", "buildingNo", "8栋", "lastMonthReading", 2100.0, "currentMonthReading", 2320.0, "warningValue", 2500.0, "yoyChange", "+10.5%"),
+                Map.of("meterId", "EM2024009", "buildingNo", "9栋", "lastMonthReading", 1450.0, "currentMonthReading", 1580.0, "warningValue", 1700.0, "yoyChange", "+8.9%"),
+                Map.of("meterId", "EM2024010", "buildingNo", "10栋", "lastMonthReading", 2800.0, "currentMonthReading", 3050.0, "warningValue", 3300.0, "yoyChange", "+8.9%"),
+                Map.of("meterId", "EM2024011", "buildingNo", "11栋", "lastMonthReading", 1650.0, "currentMonthReading", 1780.0, "warningValue", 1950.0, "yoyChange", "+7.9%"),
+                Map.of("meterId", "EM2024012", "buildingNo", "12栋", "lastMonthReading", 3100.0, "currentMonthReading", 3420.0, "warningValue", 3700.0, "yoyChange", "+10.3%"),
+                Map.of("meterId", "EM2024013", "buildingNo", "13栋", "lastMonthReading", 1900.0, "currentMonthReading", 2050.0, "warningValue", 2200.0, "yoyChange", "+7.9%"),
+                Map.of("meterId", "EM2024014", "buildingNo", "14栋", "lastMonthReading", 2400.0, "currentMonthReading", 2650.0, "warningValue", 2900.0, "yoyChange", "+10.4%"),
+                Map.of("meterId", "EM2024015", "buildingNo", "15栋", "lastMonthReading", 1750.0, "currentMonthReading", 1890.0, "warningValue", 2050.0, "yoyChange", "+8.0%")
+        );
+    }
+
+    //租赁资产管家
+    private List<Map<String, Object>> generateRentalData() {
+        return Arrays.asList(
+                Map.of("propertyId", "PROP2024001", "area", 89.5, "layout", "两室一厅", "monthlyRent", 3200.0, "tenant", "张明", "contractStart", "2024-01-15", "contractEnd", "2025-01-14", "depositStatus", "已收", "history", "2023年租给李华"),
+                Map.of("propertyId", "PROP2024002", "area", 120.3, "layout", "三室两厅", "monthlyRent", 4500.0, "tenant", "王芳", "contractStart", "2024-03-20", "contractEnd", "2025-03-19", "depositStatus", "已收", "history", "2022年租给赵强"),
+                Map.of("propertyId", "PROP2024003", "area", 65.2, "layout", "一室一厅", "monthlyRent", 2500.0, "tenant", "李强", "contractStart", "2024-02-05", "contractEnd", "2025-02-04", "depositStatus", "已收", "history", "2023年租给刘洋"),
+                Map.of("propertyId", "PROP2024004", "area", 140.8, "layout", "四室两厅", "monthlyRent", 6800.0, "tenant", "赵敏", "contractStart", "2024-01-10", "contractEnd", "2025-01-09", "depositStatus", "已收", "history", "2022年租给陈明"),
+                Map.of("propertyId", "PROP2024005", "area", 95.7, "layout", "两室两厅", "monthlyRent", 3800.0, "tenant", "陈丽", "contractStart", "2024-04-01", "contractEnd", "2025-03-31", "depositStatus", "已收", "history", "2023年租给周佳"),
+                Map.of("propertyId", "PROP2024006", "area", 75.3, "layout", "一室一厅", "monthlyRent", 2800.0, "tenant", "周明", "contractStart", "2024-03-15", "contractEnd", "2025-03-14", "depositStatus", "已收", "history", "2022年租给吴昊"),
+                Map.of("propertyId", "PROP2024007", "area", 110.2, "layout", "三室一厅", "monthlyRent", 4200.0, "tenant", "吴佳", "contractStart", "2024-02-20", "contractEnd", "2025-02-19", "depositStatus", "已收", "history", "2023年租给郑华"),
+                Map.of("propertyId", "PROP2024008", "area", 80.5, "layout", "两室一厅", "monthlyRent", 3300.0, "tenant", "郑丽", "contractStart", "2024-01-25", "contractEnd", "2025-01-24", "depositStatus", "已收", "history", "2022年租给王磊"),
+                Map.of("propertyId", "PROP2024009", "area", 135.6, "layout", "四室两厅", "monthlyRent", 6500.0, "tenant", "王强", "contractStart", "2024-03-05", "contractEnd", "2025-03-04", "depositStatus", "已收", "history", "2023年租给赵丽"),
+                Map.of("propertyId", "PROP2024010", "area", 90.2, "layout", "两室两厅", "monthlyRent", 3600.0, "tenant", "赵丽", "contractStart", "2024-02-10", "contractEnd", "2025-02-09", "depositStatus", "已收", "history", "2022年租给陈晨"),
+                Map.of("propertyId", "PROP2024011", "area", 70.8, "layout", "一室一厅", "monthlyRent", "2600.0", "tenant", "陈晨", "contractStart", "2024-04-15", "contractEnd", "2025-04-14", "depositStatus", "已收", "history", "2023年租给周明"),
+                Map.of("propertyId", "PROP2024012", "area", 125.4, "layout", "三室两厅", "monthlyRent", 4800.0, "tenant", "周佳", "contractStart", "2024-03-20", "contractEnd", "2025-03-19", "depositStatus", "已收", "history", "2022年租给吴佳"),
+                Map.of("propertyId", "PROP2024013", "area", 85.3, "layout", "两室一厅", "monthlyRent", 3400.0, "tenant", "吴昊", "contractStart", "2024-01-30", "contractEnd", "2025-01-29", "depositStatus", "已收", "history", "2023年租给郑丽"),
+                Map.of("propertyId", "PROP2024014", "area", 115.7, "layout", "三室一厅", "monthlyRent", 4400.0, "tenant", "郑华", "contractStart", "2024-02-15", "contractEnd", "2025-02-14", "depositStatus", "已收", "history", "2022年租给王强"),
+                Map.of("propertyId", "PROP2024015", "area", 98.6, "layout", "两室两厅", "monthlyRent", 3900.0, "tenant", "王磊", "contractStart", "2024-03-01", "contractEnd", "2025-02-28", "depositStatus", "已收", "history", "2023年租给赵丽")
+        );
+    }
+
+    //服务工单分析
+    private List<Map<String, Object>> generateWorkOrderAnalysisData() {
+        return Arrays.asList(
+            // 2024年数据
+            Map.of("month", "2024-01", "completionRate", 92.5, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.5, "topIssue", "设备故障"),
+            Map.of("month", "2024-02", "completionRate", 92.5, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.5, "topIssue", "设备故障"),
+            Map.of("month", "2024-03", "completionRate", 92.5, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.5, "topIssue", "设备故障"),
+            Map.of("month", "2024-04", "completionRate", 92.5, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.5, "topIssue", "设备故障"),
+            Map.of("month", "2024-05", "completionRate", 92.5, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.5, "topIssue", "设备故障"),
+            Map.of("month", "2024-06", "completionRate", 92.5, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.5, "topIssue", "设备故障"),
+            Map.of("month", "2024-07", "completionRate", 92.5, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.5, "topIssue", "设备故障"),
+            Map.of("month", "2024-08", "completionRate", 92.5, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.5, "topIssue", "设备故障"),
+            Map.of("month", "2024-09", "completionRate", 94.3, "avgResponseTime", 2.4, "reworkRate", 2.9, "satisfactionScore", 4.6, "topIssue", "公共区域卫生"),
+            Map.of("month", "2024-10", "completionRate", 91.8, "avgResponseTime", 3.1, "reworkRate", 3.5, "satisfactionScore", 4.3, "topIssue", "停车管理"),
+            Map.of("month", "2024-11", "completionRate", 95.7, "avgResponseTime", 2.2, "reworkRate", 2.3, "satisfactionScore", 4.7, "topIssue", "电梯维护"),
+            Map.of("month", "2024-12", "completionRate", 93.9, "avgResponseTime", 2.6, "reworkRate", 3.0, "satisfactionScore", 4.5, "topIssue", "公共设施维修"),
+            // 2025年数据
+            Map.of("month", "2025-01", "completionRate", 92.8, "avgResponseTime", 2.7, "reworkRate", 3.1, "satisfactionScore", 4.4, "topIssue", "设备故障"),
+            Map.of("month", "2025-02", "completionRate", 96.1, "avgResponseTime", 2.0, "reworkRate", 2.2, "satisfactionScore", 4.8, "topIssue", "公共区域卫生"),
+            Map.of("month", "2025-03", "completionRate", 94.7, "avgResponseTime", 2.3, "reworkRate", 2.8, "satisfactionScore", 4.6, "topIssue", "停车管理"),
+            Map.of("month", "2025-04", "completionRate", 93.2, "avgResponseTime", 2.5, "reworkRate", 2.9, "satisfactionScore", 4.5, "topIssue", "电梯维护"),
+            Map.of("month", "2025-05", "completionRate", 95.4, "avgResponseTime", 2.1, "reworkRate", 2.4, "satisfactionScore", 4.7, "topIssue", "公共设施维修"),
+            Map.of("month", "2025-06", "completionRate", 92.6, "avgResponseTime", 2.8, "reworkRate", 3.2, "satisfactionScore", 4.4, "topIssue", "设备故障"),
+            Map.of("month", "2025-07", "completionRate", 94.9, "avgResponseTime", 2.3, "reworkRate", 2.7, "satisfactionScore", 4.6, "topIssue", "公共区域卫生"),
+            Map.of("month", "2025-08", "completionRate", 93.5, "avgResponseTime", 2.6, "reworkRate", 3.0, "satisfactionScore", 4.5, "topIssue", "停车管理"),
+            Map.of("month", "2025-09", "completionRate", 95.8, "avgResponseTime", 2.0, "reworkRate", 2.2, "satisfactionScore", 4.8, "topIssue", "电梯维护"),
+            Map.of("month", "2025-10", "completionRate", 94.2, "avgResponseTime", 2.4, "reworkRate", 2.8, "satisfactionScore", 4.6, "topIssue", "公共设施维修")
+        );
+    }
+
+    // 查询业主档案(支持分页和条件查询)
+    @GetMapping("/estateManagementList")
+    public Map<String, Object> getDoorDevices() throws Exception {
+        List<Map<String, Object>> data = generateOwnerData();
+        PageData pd = this.getPageData();
+        String roomNo = pd.getString("roomNo");
+        String name = pd.getString("name");
+        // 条件过滤
+        if (roomNo != null && !roomNo.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("roomNo").toString().contains(roomNo))
+                    .collect(Collectors.toList());
+        }
+        if (name != null && !name.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("name").toString().contains(name))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    /**
+     * 生成模拟的业主档案数据
+     * @return
+     * @throws Exception
+     */
+    @GetMapping("/estateManagementFeeDataList")
+    public Map<String, Object> getFeeData() throws Exception {
+        List<Map<String, Object>> data = generateFeeData();
+        PageData pd = this.getPageData();
+        String billId = pd.getString("billId");
+        String feeType = pd.getString("feeType");
+        // 条件过滤
+        if (billId != null && !billId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("billId").toString().contains(billId))
+                    .collect(Collectors.toList());
+        }
+        if (feeType != null && !feeType.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("feeType").toString().equalsIgnoreCase(feeType))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    /**
+     * 设施设备台账
+     * @return
+     * @throws Exception
+     */
+    @GetMapping("/estateManagementFacilityDataList")
+    public Map<String, Object> getFacilityData() throws Exception {
+        List<Map<String, Object>> data = generateFacilityData();
+        PageData pd = this.getPageData();
+        String deviceId = pd.getString("deviceId");
+        String deviceType = pd.getString("deviceType");
+        // 条件过滤
+        if (deviceId != null && !deviceId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceId").toString().contains(deviceId))
+                    .collect(Collectors.toList());
+        }
+        if (deviceType != null && !deviceType.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceType").toString().equalsIgnoreCase(deviceType))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    /**
+     * 安防监控中心
+     * @return
+     * @throws Exception
+     */
+    @GetMapping("/estateManagementSecurityDataList")
+    public Map<String, Object> getSecurityData() throws Exception {
+        List<Map<String, Object>> data = generateSecurityData();
+        PageData pd = this.getPageData();
+        String cameraId = pd.getString("cameraId");
+        String location = pd.getString("location");
+        // 条件过滤
+        if (cameraId != null && !cameraId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("cameraId").toString().contains(cameraId))
+                    .collect(Collectors.toList());
+        }
+        if (location != null && !location.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("location").toString().contains(location))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    /**
+     * 工单调度平台
+     * @return
+     * @throws Exception
+     */
+    @GetMapping("/estateManagementWorkOrderDataList")
+    public Map<String, Object> getWorkOrderData() throws Exception {
+        List<Map<String, Object>> data = generateWorkOrderData();
+        PageData pd = this.getPageData();
+        String orderId = pd.getString("orderId");
+        String type = pd.getString("type");
+        // 条件过滤
+        if (orderId != null && !orderId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("orderId").toString().contains(orderId))
+                    .collect(Collectors.toList());
+        }
+        if (type != null && !type.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("type").toString().contains(type))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    /**
+     * 工单调度平台
+     * @return
+     * @throws Exception
+     */
+    @GetMapping("/estateManagementEnergyDataList")
+    public Map<String, Object> getEnergyData() throws Exception {
+        List<Map<String, Object>> data = generateEnergyData ();
+        PageData pd = this.getPageData();
+        String meterId = pd.getString("meterId");
+        String buildingNo = pd.getString("buildingNo");
+        // 条件过滤
+        if (meterId != null && !meterId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("meterId").toString().contains(meterId))
+                    .collect(Collectors.toList());
+        }
+        if (buildingNo != null && !buildingNo.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("buildingNo").toString().contains(buildingNo))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    /**
+     * 租赁资产管家
+     * @return
+     * @throws Exception
+     */
+    @GetMapping("/estateManagementRentalDataList")
+    public Map<String, Object> getRentalData() throws Exception {
+        List<Map<String, Object>> data = generateRentalData();
+        PageData pd = this.getPageData();
+        String propertyId = pd.getString("propertyId");
+        String layout = pd.getString("layout");
+        // 条件过滤
+        if (propertyId != null && !propertyId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("propertyId").toString().contains(propertyId))
+                    .collect(Collectors.toList());
+        }
+        if (layout != null && !layout.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("layout").toString().contains(layout))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+    /**
+     * 租赁资产管家
+     * @return
+     * @throws Exception
+     */
+    @GetMapping("/estateManagementWorkOrderAnalysisDataList")
+    public Map<String, Object> getWorkOrderAnalysisData() throws Exception {
+        List<Map<String, Object>> data = generateWorkOrderAnalysisData();
+        PageData pd = this.getPageData();
+        String timeRange = pd.getString("timeRange");
+        String topIssue = pd.getString("topIssue");
+
+        // 解析时间范围参数(独立字段示例)
+        String startMonth = pd.getString("timeRange[0]"); // 开始月份
+        String endMonth = pd.getString("timeRange[1]"); // 结束月份
+        // 时间范围过滤
+        if (startMonth != null && endMonth != null && !startMonth.isEmpty() && !endMonth.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> isWithinTimeRange((String) item.get("month"), startMonth, endMonth))
+                    .collect(Collectors.toList());
+        }
+        if (topIssue != null && !topIssue.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("topIssue").toString().contains(topIssue))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+    /**
+     * 时间范围过滤方法(判断月份是否在[start, end]区间内)
+     */
+    private boolean isWithinTimeRange(String targetMonth, String startMonth, String endMonth) {
+        // 转换为年月数值(如:2024-01 -> 202401)
+        int target = Integer.parseInt(targetMonth.replace("-", ""));
+        int start = Integer.parseInt(startMonth.replace("-", ""));
+        int end = Integer.parseInt(endMonth.replace("-", ""));
+        return target >= start && target <= end;
+    }
+
+
+
+    /**
+     * 查询业主档案列表
+     * @return
+     */
+    @GetMapping("/list")
+    public String list()
+    {
+        PageData pd = this.getPageData();
+        Response response = null;
+        try{
+            String name = "";
+            String appoint_time = "";
+            if (pd.containsKey("search")){
+                name = pd.getString("search");
+            }
+            if (pd.containsKey("appoint_time")){
+                appoint_time = pd.getString("appoint_time");
+            }
+            String info = "{\n" +
+                    "  \"date\": \""+pd.getString("date")+"\",\n" +
+                    "  \"search\": \""+name+"\",\n" +
+                    "  \"locationId\": [],\n" +
+                    "  \"capacity\": [],\n" +
+                    "  \"deviceType\": [],\n" +
+                    "  \"roomType\": [\n" +
+                    "    -1\n" +
+                    "  ],\n" +
+                    "  \"appoint_time\": \""+appoint_time+"\",\n" +
+                    "  \"status\": 1,\n" +
+                    "  \"page\": "+pd.getInteger("pageNum")+",\n" +
+                    "  \"page_size\": "+pd.getInteger("pageSize")+"\n" +
+                    "}";
+            PageData interface_info = interfaceInfoService.selectInterfaceInfoByName(pd.getString("interfaceName"));
+
+            pd.put("url",interface_info.get("url"));
+            OkHttpClient client = new OkHttpClient().newBuilder()
+                    .build();
+            MediaType mediaType = MediaType.parse("application/json");
+            RequestBody body = RequestBody.create(mediaType, info);
+            Request request = new Request.Builder()
+                    .url(interface_info.getString("url"))
+                    .method("POST", body)
+                    .addHeader("Content-Type", "application/json")
+                    .build();
+            response = client.newCall(request).execute();
+        } catch (Exception e){
+            e.printStackTrace();
+        }
+        try {
+            return response.body().string();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 查询历史记录
+     * @return
+     */
+    @GetMapping("/listHistory")
+    public String listHistory() throws Exception {
+        PageData pd = this.getPageData();
+        // 获取接口地址
+        PageData interface_info = interfaceInfoService.selectInterfaceInfoByName(pd.getString("interfaceName"));
+        String url = interface_info.getString("url");
+
+        // 构造请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("date", pd.getString("date"));
+        params.put("search", pd.getString("search"));
+        //params.put("appoint_time", );
+        params.put("status", String.valueOf(pd.getInteger("status")));
+        params.put("page", String.valueOf(pd.getInteger("pageNum")));
+        params.put("pageSize", String.valueOf(pd.getInteger("pageSize")));
+        params.put("locationId", ""); // 空数组
+        params.put("capacity", "");  // 空数组
+        params.put("deviceType", ""); // 空数组
+        params.put("roomType", "-1");
+        params.put("is_external", String.valueOf(pd.getInteger("is_external")));
+
+        // 构造完整的 URL
+        StringBuilder urlBuilder = new StringBuilder(url);
+        boolean firstParam = true;
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
+                if (firstParam) {
+                    urlBuilder.append("?");
+                    firstParam = false;
+                } else {
+                    urlBuilder.append("&");
+                }
+                urlBuilder.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
+                        .append("=")
+                        .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
+            }
+        }
+
+        // 使用 OkHttpClient 发送 GET 请求
+        OkHttpClient client = new OkHttpClient().newBuilder()
+                .build();
+
+        Request request = new Request.Builder()
+                .url(urlBuilder.toString())
+                .method("GET", null)
+                .build();
+
+        try (Response response = client.newCall(request).execute()) {
+            if (!response.isSuccessful()) {
+                throw new RuntimeException("External API call failed with status code: " + response.code());
+            }
+            return response.body().string();
+        } catch (IOException e) {
+            throw new RuntimeException("Error calling external API", e);
+        }
+    }
+}

+ 767 - 0
pm-admin/src/main/java/com/pm/web/controller/publicBroadcasting/PublicBroadcastingController.java

@@ -0,0 +1,767 @@
+package com.pm.web.controller.publicBroadcasting;
+
+import com.pm.common.config.PageData;
+import com.pm.common.core.controller.BaseController;
+import com.pm.interfaceInfo.service.InterfaceInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * 公共广播
+ */
+@RestController
+@RequestMapping("/publicBroadcasting/info")
+public class PublicBroadcastingController   extends BaseController {
+
+
+    /**
+     * 查询url 访问接口
+     */
+    @Autowired
+    private InterfaceInfoService interfaceInfoService;
+
+
+    // 模拟数据
+
+    /**
+     *
+     * @return
+     */
+    public static List<Map<String, Object>> generateBroadcastDeviceData() {
+        return Arrays.asList(
+                createDeviceEntry("BRD-001", "1号楼大厅广播终端", "广播终端", 10.2, 18.5, 0, "1号楼1层大厅", "green", 50.0, "ZONE-B-001", "1号楼公共区", Arrays.asList("BRD-001", "BRD-002"), null, "2025-06-05 08:00:00"),
+                createDeviceEntry("BRD-002", "1号楼走廊广播", "广播终端", 12.7, 22.3, 0, "1号楼1层走廊", "green", 45.0, "ZONE-B-001", "1号楼公共区", Arrays.asList("BRD-001", "BRD-002"), null, "2025-06-05 08:15:00"),
+                createDeviceEntry("BRD-003", "2号楼电梯厅广播", "广播终端", 18.9, 25.6, 2, "2号楼2层电梯厅", "red", 0.0, "ZONE-B-002", "2号楼高区", Arrays.asList("BRD-003"), "F-B-001", "2025-06-05 08:30:00"),
+                createDeviceEntry("BRD-004", "2号楼消防广播", "消防广播", 19.5, 28.7, 3, "2号楼3层安全通道", "green", 60.0, "ZONE-B-002", "2号楼高区", Arrays.asList("BRD-004", "BRD-005"), null, "2025-06-05 08:45:00"),
+                createDeviceEntry("BRD-005", "2号楼安全出口广播", "消防广播", 20.1, 29.3, 3, "2号楼3层安全通道", "green", 60.0, "ZONE-B-002", "2号楼高区", Arrays.asList("BRD-004", "BRD-005"), null, "2025-06-05 09:00:00"),
+                createDeviceEntry("BRD-006", "3号楼会议室广播", "会议广播", 8.3, 5.7, 2, "3号楼2层会议室", "green", 35.0, "ZONE-B-003", "3号楼办公区", Arrays.asList("BRD-006"), null, "2025-06-05 09:15:00"),
+                createDeviceEntry("BRD-007", "3号楼走廊背景音乐", "背景音乐终端", 9.1, 6.2, 2, "3号楼2层走廊", "yellow", 25.0, "ZONE-B-003", "3号楼办公区", Arrays.asList("BRD-007", "BRD-008"), "F-B-002", "2025-06-05 09:30:00"),
+                createDeviceEntry("BRD-008", "3号楼休息区广播", "背景音乐终端", 9.8, 7.5, 2, "3号楼2层休息区", "yellow", 25.0, "ZONE-B-003", "3号楼办公区", Arrays.asList("BRD-007", "BRD-008"), "F-B-002", "2025-06-05 09:45:00"),
+                createDeviceEntry("BRD-009", "地下车库A广播", "环境广播", -5.5, 15.3, -1, "地下1层车库A区", "green", 55.0, "ZONE-B-004", "地下车库区", Arrays.asList("BRD-009", "BRD-010"), null, "2025-06-05 10:00:00"),
+                createDeviceEntry("BRD-010", "地下车库B广播", "环境广播", -6.8, 18.2, -1, "地下1层车库B区", "green", 55.0, "ZONE-B-004", "地下车库区", Arrays.asList("BRD-009", "BRD-010"), null, "2025-06-05 10:15:00"),
+                createDeviceEntry("BRD-011", "园区广场广播", "户外广播", 25.0, 30.0, 0, "园区中心广场", "green", 70.0, "ZONE-B-005", "户外公共区", Arrays.asList("BRD-011"), null, "2025-06-05 10:30:00"),
+                createDeviceEntry("BRD-012", "园区道路广播", "户外广播", 22.5, 35.0, 0, "园区主干道", "green", 70.0, "ZONE-B-005", "户外公共区", Arrays.asList("BRD-012"), null, "2025-06-05 10:45:00"),
+                createDeviceEntry("BRD-013", "食堂广播终端", "公共广播", 14.7, 12.3, 0, "1号楼负1层食堂", "red", 0.0, "ZONE-B-006", "生活服务区", Arrays.asList("BRD-013"), "F-B-003", "2025-06-05 11:00:00"),
+                createDeviceEntry("BRD-014", "健身房广播", "公共广播", 15.2, 13.8, 0, "1号楼负1层健身房", "green", 40.0, "ZONE-B-006", "生活服务区", Arrays.asList("BRD-014"), null, "2025-06-05 11:15:00"),
+                createDeviceEntry("BRD-015", "图书馆广播", "公共广播", 7.5, 8.9, 2, "3号楼1层图书馆", "green", 30.0, "ZONE-B-003", "3号楼办公区", Arrays.asList("BRD-015"), null, "2025-06-05 11:30:00")
+        );
+    }
+
+    private static Map<String, Object> createDeviceEntry(
+            String deviceId, String deviceName, String deviceType,
+            double xCoord, double yCoord, double zCoord,
+            String area, String status, double volume,
+            String zoneId, String zoneName, List<String> deviceList,
+            String faultCode, String lastCheckTime
+    ) {
+        Map<String, Object> map = new HashMap<>();
+        map.put("deviceId", deviceId);
+        map.put("deviceName", deviceName);
+        map.put("deviceType", deviceType);
+        map.put("xCoord", xCoord);
+        map.put("yCoord", yCoord);
+        map.put("zCoord", zCoord);
+        map.put("area", area);
+        map.put("status", status);
+        map.put("volume", volume);
+        map.put("zoneId", zoneId);
+        map.put("zoneName", zoneName);
+        map.put("deviceList", deviceList);
+
+        // 手动处理 null 值
+        if (faultCode != null) {
+            map.put("faultCode", faultCode);
+        } else {
+            map.put("faultCode", ""); // 或 null,取决于前端能否处理
+        }
+
+        map.put("lastCheckTime", lastCheckTime);
+        return map;
+    }
+
+
+    public static List<Map<String, Object>> generateBroadcastData() {
+        return Arrays.asList(
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-001");
+                    put("targetZoneIds", "ZONE-ALL");
+                    put("currentVolume", 75.0);
+                    put("setVolume", 75.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-001");
+                    put("contentCode", "EMG-ALARM");
+                    put("priority", 1);
+                    put("broadcastStatus", "进行中");
+                    put("startTime", "2025-06-05 08:00:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-002");
+                    put("targetZoneIds", "ZONE-001,ZONE-002");
+                    put("currentVolume", 60.0);
+                    put("setVolume", 60.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-002");
+                    put("contentCode", "PAGE-ANNOUNCE");
+                    put("priority", 2);
+                    put("broadcastStatus", "已完成");
+                    put("startTime", "2025-06-05 08:30:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-003");
+                    put("targetZoneIds", "ZONE-003");
+                    put("currentVolume", 0.0);
+                    put("setVolume", 50.0);
+                    put("switchStatus", "关闭");
+                    put("operator", "ADMIN-001");
+                    put("contentCode", "NOTICE-INFO");
+                    put("priority", 3);
+                    put("broadcastStatus", "未开始");
+                    put("startTime", "2025-06-05 09:00:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-004");
+                    put("targetZoneIds", "ZONE-ALL");
+                    put("currentVolume", 100.0);
+                    put("setVolume", 100.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-003");
+                    put("contentCode", "EMG-FIRE");
+                    put("priority", 1);
+                    put("broadcastStatus", "进行中");
+                    put("startTime", "2025-06-05 09:15:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-005");
+                    put("targetZoneIds", "ZONE-004");
+                    put("currentVolume", 45.0);
+                    put("setVolume", 50.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-002");
+                    put("contentCode", "NOTICE-MAINTENANCE");
+                    put("priority", 3);
+                    put("broadcastStatus", "进行中");
+                    put("startTime", "2025-06-05 10:00:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-006");
+                    put("targetZoneIds", "ZONE-001");
+                    put("currentVolume", 55.0);
+                    put("setVolume", 55.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-001");
+                    put("contentCode", "PAGE-STAFF");
+                    put("priority", 2);
+                    put("broadcastStatus", "已完成");
+                    put("startTime", "2025-06-05 10:30:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-007");
+                    put("targetZoneIds", "ZONE-002,ZONE-003");
+                    put("currentVolume", 70.0);
+                    put("setVolume", 70.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-003");
+                    put("contentCode", "EMG-EVACUATION");
+                    put("priority", 1);
+                    put("broadcastStatus", "进行中");
+                    put("startTime", "2025-06-05 11:00:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-008");
+                    put("targetZoneIds", "ZONE-ALL");
+                    put("currentVolume", 80.0);
+                    put("setVolume", 80.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-002");
+                    put("contentCode", "NOTICE-FESTIVAL");
+                    put("priority", 3);
+                    put("broadcastStatus", "未开始");
+                    put("startTime", "2025-06-05 11:30:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-009");
+                    put("targetZoneIds", "ZONE-004");
+                    put("currentVolume", 30.0);
+                    put("setVolume", 40.0);
+                    put("switchStatus", "关闭");
+                    put("operator", "ADMIN-001");
+                    put("contentCode", "NOTICE-REMINDER");
+                    put("priority", 3);
+                    put("broadcastStatus", "未开始");
+                    put("startTime", "2025-06-05 12:00:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-010");
+                    put("targetZoneIds", "ZONE-001,ZONE-004");
+                    put("currentVolume", 65.0);
+                    put("setVolume", 65.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-003");
+                    put("contentCode", "PAGE-GUEST");
+                    put("priority", 2);
+                    put("broadcastStatus", "已完成");
+                    put("startTime", "2025-06-05 13:00:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-011");
+                    put("targetZoneIds", "ZONE-ALL");
+                    put("currentVolume", 90.0);
+                    put("setVolume", 90.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-002");
+                    put("contentCode", "EMG-SECURITY");
+                    put("priority", 1);
+                    put("broadcastStatus", "进行中");
+                    put("startTime", "2025-06-05 13:30:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-012");
+                    put("targetZoneIds", "ZONE-002");
+                    put("currentVolume", 50.0);
+                    put("setVolume", 50.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-001");
+                    put("contentCode", "NOTICE-UPDATE");
+                    put("priority", 3);
+                    put("broadcastStatus", "已完成");
+                    put("startTime", "2025-06-05 14:00:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-013");
+                    put("targetZoneIds", "ZONE-003,ZONE-004");
+                    put("currentVolume", 40.0);
+                    put("setVolume", 40.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-003");
+                    put("contentCode", "PAGE-EMERGENCY");
+                    put("priority", 2);
+                    put("broadcastStatus", "进行中");
+                    put("startTime", "2025-06-05 14:30:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-014");
+                    put("targetZoneIds", "ZONE-ALL");
+                    put("currentVolume", 100.0);
+                    put("setVolume", 100.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-002");
+                    put("contentCode", "EMG-TEST");
+                    put("priority", 1);
+                    put("broadcastStatus", "进行中");
+                    put("startTime", "2025-06-05 15:00:00");
+                }},
+                new HashMap<String, Object>() {{
+                    put("taskId", "TASK-015");
+                    put("targetZoneIds", "ZONE-001,ZONE-003");
+                    put("currentVolume", 58.0);
+                    put("setVolume", 60.0);
+                    put("switchStatus", "开启");
+                    put("operator", "ADMIN-001");
+                    put("contentCode", "NOTICE-CLEANING");
+                    put("priority", 3);
+                    put("broadcastStatus", "未开始");
+                    put("startTime", "2025-06-05 15:30:00");
+                }}
+        );
+    }
+
+    public static List<Map<String, Object>> generateSystemData() {
+        return Arrays.asList(
+                // 紧急通知(全区,设备总数100,故障数5)
+                createContentEntry(
+                        "CONT-001", "EMERGENCY", "/audio/emergency/alarm.mp3",
+                        "CONT-001", "ZONE-ALL", "80%",
+                        "100/5", "HIGH", Arrays.asList("DEV-012", "DEV-045"), "2025-06-03 08:30:15",
+                        65.2, 12.5, 78.3
+                ),
+                // 日常通知(分区1+2,设备总数50,故障数2)
+                createContentEntry(
+                        "CONT-002", "NORMAL", "/audio/normal/notice1.mp3",
+                        "CONT-002", "ZONE-001,ZONE-002", "45%",
+                        "50/2", "MEDIUM", Arrays.asList("DEV-023"), "2025-06-03 09:15:30",
+                        45.8, 8.2, 65.7
+                ),
+                // 背景音乐(分区3+4,无故障)
+                createContentEntry(
+                        "CONT-003", "MUSIC", "/audio/music/bg1.mp3",
+                        "CONT-003", "ZONE-003,ZONE-004", "100%",
+                        "48/0", "NONE", null, null,
+                        30.1, 5.3, 82.4
+                ),
+                // 寻呼(分区1,设备总数25,故障数1)
+                createContentEntry(
+                        "CONT-004", "PAGING", "/audio/paging/staff.mp3",
+                        "CONT-004", "ZONE-001", "20%",
+                        "25/1", "LOW", Arrays.asList("DEV-018"), "2025-06-03 10:05:45",
+                        55.7, 9.8, 70.1
+                ),
+                // 紧急演练(全区,设备总数100,故障数3)
+                createContentEntry(
+                        "CONT-005", "DRILL", "/audio/emergency/drill.mp3",
+                        "CONT-005", "ZONE-ALL", "0%",
+                        "100/3", "HIGH", Arrays.asList("DEV-007", "DEV-032", "DEV-056"), "2025-06-03 11:20:00",
+                        78.9, 15.3, 60.5
+                ),
+                // 新增10条模拟数据(包含不同设备数和故障数)
+                createContentEntry(
+                        "CONT-006", "NORMAL", "/audio/normal/notice2.mp3",
+                        "CONT-006", "ZONE-002", "60%",
+                        "30/1", "LOW", Arrays.asList("DEV-028"), "2025-06-03 12:00:00",
+                        40.2, 6.5, 75.0
+                ),
+                createContentEntry(
+                        "CONT-007", "EMERGENCY", "/audio/emergency/fire.mp3",
+                        "CONT-007", "ZONE-ALL", "90%",
+                        "100/2", "HIGH", Arrays.asList("DEV-015"), "2025-06-03 13:30:00",
+                        68.5, 10.8, 72.3
+                ),
+                createContentEntry(
+                        "CONT-008", "MUSIC", "/audio/music/bg2.mp3",
+                        "CONT-008", "ZONE-003", "75%",
+                        "24/0", "NONE", null, null,
+                        35.6, 4.9, 85.1
+                ),
+                createContentEntry(
+                        "CONT-009", "PAGING", "/audio/paging/guest.mp3",
+                        "CONT-009", "ZONE-001,ZONE-003", "30%",
+                        "40/2", "MEDIUM", Arrays.asList("DEV-019", "DEV-033"), "2025-06-03 14:45:00",
+                        52.1, 8.7, 68.4
+                ),
+                createContentEntry(
+                        "CONT-010", "DRILL", "/audio/emergency/evacuation.mp3",
+                        "CONT-010", "ZONE-004", "0%",
+                        "18/1", "LOW", Arrays.asList("DEV-041"), "2025-06-03 15:30:00",
+                        58.9, 11.2, 63.7
+                ),
+                createContentEntry(
+                        "CONT-011", "NORMAL", "/audio/normal/reminder.mp3",
+                        "CONT-011", "ZONE-002,ZONE-004", "55%",
+                        "36/0", "NONE", null, null,
+                        38.4, 5.6, 80.2
+                ),
+                createContentEntry(
+                        "CONT-012", "EMERGENCY", "/audio/emergency/security.mp3",
+                        "CONT-012", "ZONE-ALL", "100%",
+                        "100/0", "NONE", null, "2025-06-03 16:15:00",
+                        60.3, 9.3, 77.5
+                ),
+                createContentEntry(
+                        "CONT-013", "MUSIC", "/audio/music/bg3.mp3",
+                        "CONT-013", "ZONE-001,ZONE-004", "40%",
+                        "28/1", "LOW", Arrays.asList("DEV-009"), "2025-06-03 17:00:00",
+                        42.7, 7.4, 73.6
+                ),
+                createContentEntry(
+                        "CONT-014", "PAGING", "/audio/paging/staff.mp3",
+                        "CONT-014", "ZONE-003", "25%",
+                        "15/0", "NONE", null, null,
+                        32.0, 3.8, 88.0
+                ),
+                createContentEntry(
+                        "CONT-015", "DRILL", "/audio/emergency/test.mp3",
+                        "CONT-015", "ZONE-ALL", "10%",
+                        "100/4", "HIGH", Arrays.asList("DEV-005", "DEV-021", "DEV-047", "DEV-053"), "2025-06-03 18:00:00",
+                        75.1, 14.6, 59.8
+                )
+        );
+    }
+
+    private static Map<String, Object> createContentEntry(
+            String contentId, String contentType, String audioPath,
+            String currentPlayContent, String playZones, String progress,
+            String zoneStatusMatrix, String alarmLevel, List<String> faultyDevices, String triggerTime,
+            double cpuLoad, double networkLatency, double storageUsage
+    ) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("contentId", contentId);
+        data.put("contentType", contentType);
+        data.put("audioPath", audioPath);
+        data.put("currentPlayContent", currentPlayContent);
+        data.put("playZones", playZones);
+        data.put("progress", progress);
+        data.put("zoneStatusMatrix", zoneStatusMatrix); // 新增字段
+        data.put("alarmLevel", alarmLevel);
+        data.put("faultyDevices", faultyDevices);
+        data.put("triggerTime", triggerTime);
+        data.put("cpuLoad", cpuLoad);
+        data.put("networkLatency", networkLatency);
+        data.put("storageUsage", storageUsage);
+        return data;
+    }
+
+    // 日志
+    public static List<Map<String, Object>> generateAuditLogData() {
+        return Arrays.asList(
+                // 广播操作审计(控制类型)
+                createLogEntry(
+                        "LOG-20250605001", "2025-06-05 08:00:00", "ADMIN-001",
+                        "控制", "TARGET-ZONE-ALL", null, null,
+                        "成功", "全区", "500ms",
+                        "192.168.1.101", "DEVICE-001", "SIGN-1a2b3c"
+                ),
+                // 配置变更审计(配置类型)
+                createLogEntry(
+                        "LOG-20250605002", "2025-06-05 08:15:30", "ADMIN-002",
+                        "配置", "VOLUME-SETTING", "60dB", "75dB",
+                        "成功", "分区1-2", "800ms",
+                        "192.168.1.102", "DEVICE-002", "SIGN-4d5e6f"
+                ),
+                // 广播任务审计(广播类型,带修改记录)
+                createLogEntry(
+                        "LOG-20250605003", "2025-06-05 09:00:00", "ADMIN-001",
+                        "广播", "TASK-001", "未开始", "进行中",
+                        "成功", "分区3", "300ms",
+                        "192.168.1.101", "DEVICE-001", "SIGN-7g8h9i"
+                ),
+                // 失败操作审计(控制类型)
+                createLogEntry(
+                        "LOG-20250605004", "2025-06-05 09:30:00", "ADMIN-003",
+                        "控制", "TARGET-ZONE-004", null, null,
+                        "失败", "分区4", "200ms",
+                        "192.168.1.103", "DEVICE-003", "SIGN-0j1k2l"
+                ),
+                // 批量配置变更(配置类型,多对象)
+                createLogEntry(
+                        "LOG-20250605005", "2025-06-05 10:00:00", "ADMIN-002",
+                        "配置", "ZONE-001,ZONE-003", "开启", "关闭",
+                        "成功", "分区1+3", "1200ms",
+                        "192.168.1.102", "DEVICE-002", "SIGN-3m4n5o"
+                ),
+                // 紧急广播审计(广播类型)
+                createLogEntry(
+                        "LOG-20250605006", "2025-06-05 10:30:00", "ADMIN-001",
+                        "广播", "EMG-ALARM", null, null,
+                        "成功", "全区", "400ms",
+                        "192.168.1.101", "DEVICE-001", "SIGN-6p7q8r"
+                ),
+                // 权限变更审计(配置类型)
+                createLogEntry(
+                        "LOG-20250605007", "2025-06-05 11:00:00", "ADMIN-003",
+                        "配置", "USER-ROLE", "普通用户", "管理员",
+                        "成功", "用户ADMIN-004", "500ms",
+                        "192.168.1.103", "DEVICE-003", "SIGN-9s0t1u"
+                ),
+                // 定时任务配置(配置类型)
+                createLogEntry(
+                        "LOG-20250605008", "2025-06-05 11:30:00", "ADMIN-002",
+                        "配置", "CRON-JOB", "0 0 9 * * MON", "0 0 10 * * TUE",
+                        "成功", "定时任务ID-001", "700ms",
+                        "192.168.1.102", "DEVICE-002", "SIGN-2v3w4x"
+                ),
+                // 设备重启审计(控制类型)
+                createLogEntry(
+                        "LOG-20250605009", "2025-06-05 12:00:00", "ADMIN-001",
+                        "控制", "DEVICE-005", null, null,
+                        "成功", "设备5", "600ms",
+                        "192.168.1.101", "DEVICE-001", "SIGN-5y6z7a"
+                ),
+                // 失败的广播操作(广播类型)
+                createLogEntry(
+                        "LOG-20250605010", "2025-06-05 12:30:00", "ADMIN-003",
+                        "广播", "TASK-002", "已取消", "失败",
+                        "失败", "分区2", "350ms",
+                        "192.168.1.103", "DEVICE-003", "SIGN-8b9c0d"
+                ),
+                // 音量批量调整(配置类型)
+                createLogEntry(
+                        "LOG-20250605011", "2025-06-05 13:00:00", "ADMIN-002",
+                        "配置", "VOLUME-BATCH", "45dB", "55dB",
+                        "成功", "分区1-4", "1500ms",
+                        "192.168.1.102", "DEVICE-002", "SIGN-1e2f3g"
+                ),
+                // 安全策略变更(配置类型)
+                createLogEntry(
+                        "LOG-20250605012", "2025-06-05 13:30:00", "ADMIN-001",
+                        "配置", "SECURITY-POLICY", "允许匿名访问", "禁止匿名访问",
+                        "成功", "系统全局", "900ms",
+                        "192.168.1.101", "DEVICE-001", "SIGN-4h5i6j"
+                ),
+                // 手动寻呼审计(广播类型)
+                createLogEntry(
+                        "LOG-20250605013", "2025-06-05 14:00:00", "ADMIN-003",
+                        "广播", "PAGE-GUEST", null, null,
+                        "成功", "分区1+2", "450ms",
+                        "192.168.1.103", "DEVICE-003", "SIGN-7k8l9m"
+                ),
+                // 设备参数修改(配置类型)
+                createLogEntry(
+                        "LOG-20250605014", "2025-06-05 14:30:00", "ADMIN-002",
+                        "配置", "DEVICE-002/PARAM", "阈值80%", "阈值90%",
+                        "成功", "设备2参数", "850ms",
+                        "192.168.1.102", "DEVICE-002", "SIGN-0n1o2p"
+                ),
+                // 分区故障处理(控制类型)
+                createLogEntry(
+                        "LOG-20250605015", "2025-06-05 15:00:00", "ADMIN-001",
+                        "控制", "ZONE-003/RECOVER", null, null,
+                        "成功", "分区3", "1000ms",
+                        "192.168.1.101", "DEVICE-001", "SIGN-3q4r5s"
+                ),
+                // 备份操作审计(配置类型)
+                createLogEntry(
+                        "LOG-20250605016", "2025-06-05 15:30:00", "ADMIN-003",
+                        "配置", "SYSTEM-BACKUP", "未备份", "已备份",
+                        "成功", "系统数据", "2000ms",
+                        "192.168.1.103", "DEVICE-003", "SIGN-6t7u8v"
+                ),
+                // 权限回收审计(配置类型)
+                createLogEntry(
+                        "LOG-20250605017", "2025-06-05 16:00:00", "ADMIN-002",
+                        "配置", "USER-ROLE/ADMIN-005", "管理员", "普通用户",
+                        "成功", "用户ADMIN-005", "600ms",
+                        "192.168.1.102", "DEVICE-002", "SIGN-9w0x1y"
+                ),
+                // 紧急按钮触发(控制类型)
+                createLogEntry(
+                        "LOG-20250605018", "2025-06-05 16:30:00", "ADMIN-001",
+                        "控制", "EMERGENCY-BUTTON", null, null,
+                        "成功", "全区", "300ms",
+                        "192.168.1.101", "DEVICE-001", "SIGN-2z3a4b"
+                ),
+                // 固件升级审计(配置类型)
+                createLogEntry(
+                        "LOG-20250605019", "2025-06-05 17:00:00", "ADMIN-003",
+                        "配置", "DEVICE-004/FIRMWARE", "V1.0.1", "V1.0.2",
+                        "成功", "设备4", "1800ms",
+                        "192.168.1.103", "DEVICE-003", "SIGN-5c6d7e"
+                ),
+                // 测试操作审计(控制类型,失败)
+                createLogEntry(
+                        "LOG-20250605020", "2025-06-05 17:30:00", "ADMIN-002",
+                        "控制", "TEST-OPERATION", null, null,
+                        "失败", "测试环境", "120ms",
+                        "192.168.1.102", "DEVICE-002", "SIGN-8f9g0h"
+                )
+        );
+    }
+
+    private static Map<String, Object> createLogEntry(
+            String logId, String operateTime, String operator,
+            String operateType, String targetObject, String oldValue, String newValue,
+            String successStatus, String affectRange, String duration,
+            String ipAddress, String deviceFingerprint, String digitalSignature
+    ) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("logId", logId); // 日志ID
+        data.put("operateTime", operateTime); // 操作时间
+        data.put("operator", operator); // 操作人
+        data.put("operateType", operateType); // 操作类型(控制/广播/配置)
+        data.put("targetObject", targetObject); // 目标对象
+        data.put("oldValue", oldValue); // 修改前值(配置变更时有效)
+        data.put("newValue", newValue); // 修改后值(配置变更时有效)
+        data.put("successStatus", successStatus); // 成功状态(成功/失败)
+        data.put("affectRange", affectRange); // 影响范围
+        data.put("duration", duration); // 耗时
+        data.put("ipAddress", ipAddress); // IP地址
+        data.put("deviceFingerprint", deviceFingerprint); // 设备指纹
+        data.put("digitalSignature", digitalSignature); // 数字签名
+        return data;
+    }
+
+
+    // 查询门禁设备状态(支持分页和条件查询)
+
+    /**
+     * 1. 三维设备地图
+     * 功能整合:
+     * 设备位置展示(三维坐标)
+     * 实时状态监控(颜色标识)
+     * 分区配置管理
+     * 故障状态监视
+     * @throws Exception
+     */
+    @GetMapping("/broadcastDevice")
+    public Map<String, Object> getBroadcastDevice() throws Exception {
+        List<Map<String, Object>> data = generateBroadcastDeviceData();
+        PageData pd = this.getPageData();
+        String deviceId = pd.getString("deviceId");
+        String area = pd.getString("area");
+        // 条件过滤
+        if (deviceId != null && !deviceId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("deviceId").toString().contains(deviceId))
+                    .collect(Collectors.toList());
+        }
+        if (area != null && !area.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("area").toString().contains(area))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+
+    /**
+     * 2. 广播控制中心
+     * 功能整合:
+     * 音量大小控制
+     * 分区开关控制
+     * 广播任务发起
+     * 紧急广播喊话
+     * @throws Exception
+     */
+    @GetMapping("/broadcastTask")
+    public Map<String, Object> getbroadcastTask() throws Exception {
+        List<Map<String, Object>> data = generateBroadcastData();
+        PageData pd = this.getPageData();
+        String targetZone = pd.getString("targetZone");
+        String contentType = pd.getString("contentType");
+        String broadcastStatus = pd.getString("broadcastStatus");
+        // 条件过滤
+        if (targetZone != null && !targetZone.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("targetZoneIds").toString().contains(targetZone))
+                    .collect(Collectors.toList());
+        }
+        if (contentType != null && !contentType.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("contentCode").toString().contains(contentType))
+                    .collect(Collectors.toList());
+        }
+        if (broadcastStatus != null && !broadcastStatus.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("broadcastStatus").toString().contains(broadcastStatus))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+
+    /**
+     * 2. 广播控制中心
+     * 功能整合:
+     * 音量大小控制
+     * 分区开关控制
+     * 广播任务发起
+     * 紧急广播喊话
+     * @throws Exception
+     */
+    @GetMapping("/broadcastDataGenerator")
+    public Map<String, Object> getBroadcastDataGenerator() throws Exception {
+        List<Map<String, Object>> data = generateSystemData();
+        PageData pd = this.getPageData();
+        String contentId = pd.getString("contentId");
+        String playZone = pd.getString("playZone");
+        String contentType = pd.getString("contentType");
+        String alarmLevel = pd.getString("alarmLevel");
+        // 条件过滤
+        if (contentId != null && !contentId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("contentId").toString().contains(contentId))
+                    .collect(Collectors.toList());
+        }
+        if (playZone != null && !playZone.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("playZones").toString().contains(playZone))
+                    .collect(Collectors.toList());
+        }
+        if (contentType != null && !contentType.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("contentCode").toString().contains(contentType))
+                    .collect(Collectors.toList());
+        }
+        if (alarmLevel != null && !alarmLevel.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("alarmLevel").toString().contains(alarmLevel))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+    /**
+     * 2. 广播控制中心
+     * 功能整合:
+     * 音量大小控制
+     * 分区开关控制
+     * 广播任务发起
+     * 紧急广播喊话
+     * @throws Exception
+     */
+    @GetMapping("/broadcastLog")
+    public Map<String, Object> getBroadcastLog() throws Exception {
+        List<Map<String, Object>> data = generateAuditLogData();
+        PageData pd = this.getPageData();
+        String logId = pd.getString("logId");
+        String operator = pd.getString("operator");
+        String operateType = pd.getString("operateType");
+        String successStatus = pd.getString("successStatus");
+        // 条件过滤
+        if (logId != null && !logId.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("logId").toString().contains(logId))
+                    .collect(Collectors.toList());
+        }
+        if (operator != null && !operator.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("operator").toString().contains(operator))
+                    .collect(Collectors.toList());
+        }
+        if (operateType != null && !operateType.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("operateType").toString().contains(operateType))
+                    .collect(Collectors.toList());
+        }
+        if (successStatus != null && !successStatus.isEmpty()) {
+            data = data.stream()
+                    .filter(item -> item.get("successStatus").toString().contains(successStatus))
+                    .collect(Collectors.toList());
+        }
+
+        // 分页逻辑
+        int total = data.size();
+        int fromIndex = (pd.getInteger("pageNum") - 1) * pd.getInteger("pageSize");
+        int toIndex = Math.min(fromIndex + pd.getInteger("pageSize"), total);
+        List<Map<String, Object>> pageData = data.subList(fromIndex, toIndex);
+
+        // 返回结果
+        Map<String, Object> response = Map.of(
+                "msg", "操作成功",
+                "code", 200,
+                "data", Map.of("list", pageData,"total", total)
+        );
+        return response;
+    }
+}

+ 11 - 0
pm-system/src/main/java/com/pm/repairOrder/service/impl/RepairOrderServiceImpl.java

@@ -62,6 +62,10 @@ public class RepairOrderServiceImpl implements IRepairOrderService
     {
         pd.put("id", IdUtils.simpleUUID());
         pd.put("createTime", DateUtils.getTime());
+        if(pd.containsKey("finishBy")&&!pd.getString("finishBy").equals("")){
+            pd.put("assignTime", DateUtils.getTime());
+            pd.put("orderStatus", 1);
+        }
         return repairOrderMapper.insertRepairOrder(pd);
     }
 
@@ -75,6 +79,13 @@ public class RepairOrderServiceImpl implements IRepairOrderService
     public int updateRepairOrder(PageData pd)
     {
         pd.put("updateTime", DateUtils.getTime());
+        if(pd.containsKey("finishBy")&&!pd.getString("finishBy").equals("")){
+            pd.put("assignTime", DateUtils.getTime());
+            pd.put("orderStatus", 1);
+        }
+        if (pd.containsKey("finishTime")&&!pd.getString("finishTime").equals("")){
+            pd.put("orderStatus", 2);
+        }
         return repairOrderMapper.updateRepairOrder(pd);
     }
 

+ 19 - 0
pm_ui/src/api/accessControl/accessControl.js

@@ -0,0 +1,19 @@
+import request from '@/utils/request'
+
+// 查询门禁设备状态
+export function listAccessControl(query) {
+    return request({
+        url: '/accessControl/info/door-devices',
+        method: 'get',
+        params: query
+    })
+}
+// 查询考勤记录
+export function listAccessControlAttendance(query) {
+    return request({
+        url: '/accessControl/info/attendance-records',
+        method: 'get',
+        params: query
+    })
+}
+

+ 35 - 0
pm_ui/src/api/buildingEquipmentMonitoring/buildingEquipmentMonitoring.js

@@ -0,0 +1,35 @@
+import request from "@/utils/request.js";
+
+/*三维设备监控中心*/
+export function getBuildingEquipmentMonitoringList(query) {
+    return request({
+        url: '/buildingEquipmentMonitoring/info/generateDeviceData',
+        method: 'get',
+        params: query
+    })
+}
+/*二维组态图管理*/
+export function getBuildingEquipmentMonitoringConfigurationList(query) {
+    return request({
+        url: '/buildingEquipmentMonitoring/info/generateDeviceConfigurationData',
+        method: 'get',
+        params: query
+    })
+}
+
+/*区域设备分析台*/
+export function getBuildingEquipmentMonitoringAreaList(query) {
+    return request({
+        url: '/buildingEquipmentMonitoring/info/generateAreaData',
+        method: 'get',
+        params: query
+    })
+}
+/*区域设备分析台*/
+export function getBuildingEquipmentMonitoringCommandsList(query) {
+    return request({
+        url: '/buildingEquipmentMonitoring/info/generateCommandsData',
+        method: 'get',
+        params: query
+    })
+}

+ 9 - 0
pm_ui/src/api/driverInfo/driverInfo.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request.js";
+
+export function driverInfoList(query) {
+    return request({
+        url: '/driverInfo/info/driverList',
+        method: 'get',
+        params: query
+    })
+}

+ 70 - 0
pm_ui/src/api/estateManagement/estateManagement.js

@@ -0,0 +1,70 @@
+import request from "@/utils/request.js";
+
+/*业主档案*/
+export function getEstateManagementList(query) {
+    return request({
+        url: '/estateManagement/info/estateManagementList',
+        method: 'get',
+        params: query
+    })
+}
+
+/*物业费用中心*/
+export function getEstateManagementFeeDataList(query) {
+    return request({
+        url: '/estateManagement/info/estateManagementFeeDataList',
+        method: 'get',
+        params: query
+    })
+}
+/*设施设备列表*/
+export function getEstateManagementFacilityDataList(query) {
+    return request({
+        url: '/estateManagement/info/estateManagementFacilityDataList',
+        method: 'get',
+        params: query
+    })
+}
+/*安防监控中心*/
+export function getEstateManagementSecurityDataList(query) {
+    return request({
+        url: '/estateManagement/info/estateManagementSecurityDataList',
+        method: 'get',
+        params: query
+    })
+}
+
+/*工单调度平台*/
+export function getEstateManagementWorkOrderDataList(query) {
+    return request({
+        url: '/estateManagement/info/estateManagementWorkOrderDataList',
+        method: 'get',
+        params: query
+    })
+}
+/*能源监测台	*/
+export function getEstateManagementEnergyDataList(query) {
+    return request({
+        url: '/estateManagement/info/estateManagementEnergyDataList',
+        method: 'get',
+        params: query
+    })
+}
+
+/*租赁资产管家	*/
+export function getEstateManagementRentalDataList(query) {
+    return request({
+        url: '/estateManagement/info/estateManagementRentalDataList',
+        method: 'get',
+        params: query
+    })
+}
+
+/*租赁资产管家	*/
+export function getEstateManagementWorkOrderAnalysisDataList(query) {
+    return request({
+        url: '/estateManagement/info/estateManagementWorkOrderAnalysisDataList',
+        method: 'get',
+        params: query
+    })
+}

+ 36 - 0
pm_ui/src/api/publicBroadcasting/publicBroadcasting.js

@@ -0,0 +1,36 @@
+import request from "@/utils/request.js";
+
+/*广播设备信息*/
+export function getBroadcastDeviceList(query) {
+    return request({
+        url: '/publicBroadcasting/info/broadcastDevice',
+        method: 'get',
+        params: query
+    })
+}
+/*广播设备信息*/
+export function getBroadcastTaskList(query) {
+    return request({
+        url: '/publicBroadcasting/info/broadcastTask',
+        method: 'get',
+        params: query
+    })
+}
+
+/*广播设备信息*/
+export function getBroadcastDataGenerator(query) {
+    return request({
+        url: '/publicBroadcasting/info/broadcastDataGenerator',
+        method: 'get',
+        params: query
+    })
+}
+
+/*广播设备信息*/
+export function getBroadcastLogList(query) {
+    return request({
+        url: '/publicBroadcasting/info/broadcastLog',
+        method: 'get',
+        params: query
+    })
+}

+ 114 - 0
pm_ui/src/views/accessControl/index.vue

@@ -0,0 +1,114 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索栏 -->
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="输入位置" prop="location">
+        <el-input
+            v-model="queryParams.location"
+            placeholder="输入位置"
+            clearable
+            @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="设备状态" prop="deviceStatus">
+        <el-select v-model="queryParams.deviceStatus" placeholder="请选择状态" style="width: 180px;">
+          <el-option label="全部" value="" />
+          <el-option label="在线" value="Online" />
+          <el-option label="离线" value="Offline" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 数据表格 -->
+    <el-table v-loading="loading" :data="doorDevices" border>
+      <el-table-column label="序号" type="index" align="center" width="50" />
+<!--      <el-table-column label="ID" align="center" prop="id" />-->
+      <el-table-column label="位置" align="center" prop="location" />
+      <el-table-column label="门状态" align="center" prop="doorStatus" />
+      <el-table-column label="设备状态" align="center">
+        <template #default="scope">
+          <el-tag :type="getDeviceStatusType(scope.row.deviceStatus)">
+            {{ scope.row.deviceStatus === "Online" ? "在线" : "离线" }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="最后事件时间" align="center" prop="lastEventTime" />
+      <el-table-column label="事件类型" align="center" prop="eventType" />
+      <el-table-column label="操作" align="center" prop="actions" />
+      <el-table-column label="处理状态" align="center" prop="processStatus" />
+    </el-table>
+
+    <!-- 分页器 -->
+    <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+    />
+  </div>
+</template>
+<script setup name="DoorDevices">
+import { listAccessControl } from "@/api/accessControl/accessControl";
+import { ref, reactive } from "vue";
+
+// 定义响应式变量
+const queryRef = ref(null);
+const doorDevices = ref([]); // 门禁设备数据
+const loading = ref(false); // 加载状态
+const showSearch = ref(true); // 是否显示搜索栏
+const total = ref(0); // 总记录数
+
+// 查询参数
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  location: '',
+  deviceStatus: '',
+  interfaceName: "门禁设备"
+});
+
+// 获取门禁设备列表
+const getList = async () => {
+  try {
+    loading.value = true;
+    const response = await listAccessControl(queryParams);
+    doorDevices.value = response.data.list || []; // 确保数据格式正确
+    total.value = response.data.total || 0; // 确保总记录数正确
+  } catch (error) {
+    console.error('获取数据失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索按钮操作
+function handleQuery() {
+  queryParams.pageNum = 1; // 重置到第一页
+  getList();
+}
+
+// 重置按钮操作
+function resetQuery() {
+  queryRef.value.resetFields(); // 重置表单字段
+  handleQuery(); // 重新查询
+}
+// 根据设备状态返回标签类型
+function getDeviceStatusType(status) {
+  if (status === "Online") return "success"; // 在线
+  if (status === "Offline") return "danger"; // 离线
+  return "info"; // 默认
+}
+// 初始化加载数据
+getList();
+</script>
+<style scoped>
+.el-table .cell {
+  white-space: nowrap;
+}
+</style>

+ 120 - 0
pm_ui/src/views/accessControl/index2.vue

@@ -0,0 +1,120 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索栏 -->
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="输入姓名" prop="name">
+        <el-input
+            v-model="queryParams.name"
+            placeholder="输入员工姓名"
+            clearable
+            @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="考勤状态" prop="attendanceStatus">
+        <el-select v-model="queryParams.attendanceStatus" placeholder="请选择状态" style="width: 180px;">
+          <el-option label="全部" value="" />
+          <el-option label="出勤" value="Present" />
+          <el-option label="缺勤" value="Absent" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 数据表格 -->
+    <el-table v-loading="loading" :data="attendanceRecords" border>
+      <el-table-column label="序号" type="index" align="center" width="50" />
+      <el-table-column label="员工姓名" align="center" prop="name" />
+      <el-table-column label="部门" align="center" prop="department" />
+      <el-table-column label="访问位置" align="center" prop="accessLocation" />
+      <el-table-column label="访问时间" align="center">
+        <template #default="scope">
+          {{ scope.row.accessTime }}
+        </template>
+      </el-table-column>
+      <el-table-column label="访问结果" align="center" prop="accessResult" />
+      <el-table-column label="考勤状态" align="center" width="100">
+        <template #default="scope">
+          <el-tag :type="getStatusType(scope.row.attendanceStatus)">
+            {{ scope.row.attendanceStatus==='Present'?'出勤':'缺勤' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="相关事件" align="center" prop="relatedEvent" />
+      <el-table-column label="日访问次数" align="center" prop="dailyAccessCount" />
+    </el-table>
+
+    <!-- 分页器 -->
+    <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+    />
+  </div>
+</template>
+<script setup name="AttendanceRecords">
+import { listAccessControlAttendance } from "@/api/accessControl/accessControl";
+import { ref, reactive } from "vue";
+
+// 定义响应式变量
+const queryRef = ref(null);
+const attendanceRecords = ref([]); // 考勤记录数据
+const loading = ref(false); // 加载状态
+const showSearch = ref(true); // 是否显示搜索栏
+const total = ref(0); // 总记录数
+
+// 查询参数
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  name: '',
+  attendanceStatus: '',
+  interfaceName: "考勤记录"
+});
+
+// 获取考勤记录列表
+const getList = async () => {
+  try {
+    loading.value = true;
+    const response = await listAccessControlAttendance(queryParams);
+    attendanceRecords.value = response.data.list || []; // 确保数据格式正确
+    total.value = response.data.total || 0; // 确保总记录数正确
+  } catch (error) {
+    console.error('获取数据失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索按钮操作
+function handleQuery() {
+  queryParams.pageNum = 1; // 重置到第一页
+  getList();
+}
+
+// 重置按钮操作
+function resetQuery() {
+  queryRef.value.resetFields(); // 重置表单字段
+  handleQuery(); // 重新查询
+}
+
+// 初始化加载数据
+getList();
+
+// 根据考勤状态返回标签类型
+function getStatusType(status) {
+  if (status === "Present") return "success"; // 出勤
+  if (status === "Absent") return "danger"; // 缺勤
+  return "info"; // 默认
+}
+</script>
+<style scoped>
+.el-table .cell {
+  white-space: nowrap;
+}
+</style>

+ 289 - 0
pm_ui/src/views/buildingEquipmentMonitoring/index.vue

@@ -0,0 +1,289 @@
+<template>
+  <div class="device-management-system">
+    <!-- 查询条件区域 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="searchForm" :inline="true" class="search-form">
+        <!-- 设备基础信息条件 -->
+        <el-form-item label="设备ID">
+          <el-input v-model="queryParams.deviceId" placeholder="请输入设备ID" clearable />
+        </el-form-item>
+
+        <el-form-item label="设备名称">
+          <el-input v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable />
+        </el-form-item>
+
+        <el-form-item label="设备类型">
+          <el-select v-model="queryParams.deviceType" placeholder="请选择设备类型" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="控制器" value="CONTROLLER" />
+            <el-option label="传感器" value="SENSOR" />
+            <el-option label="执行器" value="ACTUATOR" />
+            <el-option label="广播设备" value="BROADCASTER" />
+            <el-option label="监控设备" value="MONITOR" />
+            <el-option label="报警设备" value="ALARM" />
+            <el-option label="输入设备" value="INPUT" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 空间定位条件 -->
+        <el-form-item label="楼层">
+          <el-select v-model="queryParams.floor" placeholder="请选择楼层" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="1楼" value="1F" />
+            <el-option label="2楼" value="2F" />
+            <el-option label="3楼" value="3F" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="区域">
+          <el-input v-model="queryParams.area" placeholder="请输入区域" clearable />
+        </el-form-item>
+
+        <!-- 实时状态条件 -->
+        <el-form-item label="运行状态">
+          <el-select v-model="queryParams.status" placeholder="请选择运行状态" style="width: 180px;">
+            <el-option label="正常" value="正常" />
+            <el-option label="警告" value="警告" />
+            <el-option label="故障" value="故障" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
+          <el-button icon="Refresh" @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格区域 -->
+    <el-card class="data-table">
+      <el-table
+          :data="deviceList"
+          border
+          size="small"
+          v-loading="isLoading"
+          row-key="deviceId"
+          @row-click="handleRowClick"
+      >
+        <el-table-column label="设备ID" prop="deviceId" align="center" width="140" />
+        <el-table-column label="设备名称" prop="deviceName" align="center" width="140" />
+        <el-table-column label="设备类型" prop="deviceType" align="center" width="120">
+          <template #default="scope">
+            {{ mapDeviceType(scope.row.deviceType) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="型号" prop="model" align="center" width="120" />
+        <el-table-column label="安装位置" align="center" min-width="200">
+          <template #default="scope">
+            <div>{{ scope.row.floor }}-{{ scope.row.area }}</div>
+            <div class="small-text">({{ scope.row.location }})</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="运行状态" align="center" width="120">
+          <template #default="scope">
+            <el-tag :color="scope.row.statusColor">{{ scope.row.status }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="当前告警" align="center" width="160">
+          <template #default="scope">
+            <div v-if="scope.row.alarmCode">{{ scope.row.alarmCode }}</div>
+            <div v-else>-</div>
+          </template>
+        </el-table-column>
+<!--        <el-table-column label="控制协议" prop="controlProtocol" align="center" width="120" />-->
+      </el-table>
+
+      <!-- 分页组件 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 详情弹窗 -->
+    <el-dialog :visible.sync="detailDialogOpen" title="设备详情" width="800px">
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="设备ID" span="1">{{ detailDevice.deviceId }}</el-descriptions-item>
+        <el-descriptions-item label="设备名称" span="1">{{ detailDevice.deviceName }}</el-descriptions-item>
+        <el-descriptions-item label="设备类型" span="1">{{ mapDeviceType(detailDevice.deviceType) }}</el-descriptions-item>
+        <el-descriptions-item label="型号" span="1">{{ detailDevice.model }}</el-descriptions-item>
+        <el-descriptions-item label="安装位置" span="2">
+          {{ detailDevice.floor }}-{{ detailDevice.area }} ({{ detailDevice.location }})
+        </el-descriptions-item>
+        <el-descriptions-item label="运行状态" span="2">
+          <el-tag :color="detailDevice.statusColor">{{ detailDevice.status }}</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="模型文件" span="2">
+          <el-link :href="detailDevice.modelPath" type="primary" target="_blank">查看模型</el-link>
+        </el-descriptions-item>
+        <el-descriptions-item label="动画参数" span="2">
+          <pre class="small-text">{{ detailDevice.animationParams }}</pre>
+        </el-descriptions-item>
+        <el-descriptions-item label="当前告警" span="2" v-if="detailDevice.alarmCode">
+          <el-alert
+              title="{{ detailDevice.alarmDescription }}"
+              type="danger"
+              :closable="false"
+              show-icon
+          />
+          <div class="mt-2">告警代码: {{ detailDevice.alarmCode }}</div>
+          <div>触发时间: {{ detailDevice.triggerTime }}</div>
+        </el-descriptions-item>
+        <el-descriptions-item label="控制协议" span="1">{{ detailDevice.controlProtocol }}</el-descriptions-item>
+        <el-descriptions-item label="指令集" span="1">{{ detailDevice.commandSet }}</el-descriptions-item>
+      </el-descriptions>
+      <template #footer>
+        <el-button @click="detailDialogOpen = false">关闭</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue';
+import { ElMessage } from 'element-plus';
+import {getBuildingEquipmentMonitoringList} from "@/api/buildingEquipmentMonitoring/buildingEquipmentMonitoring";
+
+// 查询参数
+const queryParams = reactive({
+  deviceId: '',
+  deviceName: '',
+  deviceType: '',
+  floor: '',
+  area: '',
+  status: '',
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "三维设备监控中心"
+});
+
+// 表格数据
+const deviceList = ref([]);
+const total = ref(0);
+const isLoading = ref(false);
+const detailDialogOpen = ref(false);
+const detailDevice = ref({});
+
+// 获取数据
+const getList = async () => {
+  isLoading.value = true;
+  try {
+    let response = await getBuildingEquipmentMonitoringList(queryParams);
+    // 过滤条件处理
+    let filteredData = response.data.list || [];
+
+    // 设备ID过滤
+    if (queryParams.deviceId) {
+      filteredData = filteredData.filter(item => item.deviceId.includes(queryParams.deviceId));
+    }
+
+    // 设备名称过滤
+    if (queryParams.deviceName) {
+      filteredData = filteredData.filter(item => item.deviceName.includes(queryParams.deviceName));
+    }
+
+    // 设备类型过滤
+    if (queryParams.deviceType) {
+      filteredData = filteredData.filter(item => item.deviceType === queryParams.deviceType);
+    }
+
+    // 楼层过滤
+    if (queryParams.floor) {
+      filteredData = filteredData.filter(item => item.floor === queryParams.floor);
+    }
+
+    // 区域过滤
+    if (queryParams.area) {
+      filteredData = filteredData.filter(item => item.area.includes(queryParams.area));
+    }
+
+    // 状态过滤
+    if (queryParams.status) {
+      filteredData = filteredData.filter(item => item.status === queryParams.status);
+    }
+
+    // 分页处理
+    total.value = response.data.total || 0;
+    deviceList.value = filteredData;
+  } catch (error) {
+    ElMessage.error('获取设备数据失败');
+    console.error(error);
+  } finally {
+    isLoading.value = false;
+  }
+};
+
+// 搜索
+const handleSearch = () => {
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 重置
+const resetSearch = () => {
+  queryParams.deviceId = '';
+  queryParams.deviceName = '';
+  queryParams.deviceType = '';
+  queryParams.floor = '';
+  queryParams.area = '';
+  queryParams.status = '';
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 分页
+const handlePageChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 行点击事件(打开详情弹窗)
+const handleRowClick = (row) => {
+  detailDevice.value = { ...row };
+  detailDialogOpen.value = true;
+};
+
+// 设备类型映射
+const mapDeviceType = (type) => {
+  return {
+    'CONTROLLER': '控制器',
+    'SENSOR': '传感器',
+    'ACTUATOR': '执行器',
+    'BROADCASTER': '广播设备',
+    'MONITOR': '监控设备',
+    'ALARM': '报警设备',
+    'INPUT': '输入设备',
+  }[type] || type;
+};
+
+getList()
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+  padding: 20px;
+}
+
+.data-table {
+  min-height: 500px;
+}
+
+.small-text {
+  font-size: 12px;
+  color: #909399;
+}
+
+.mt-2 {
+  margin-top: 8px;
+}
+</style>

+ 405 - 0
pm_ui/src/views/buildingEquipmentMonitoring/index2.vue

@@ -0,0 +1,405 @@
+<template>
+  <div class="configuration-management">
+    <!-- 查询条件区域 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="searchForm" :inline="true" class="search-form">
+        <!-- 组态图基础信息 -->
+        <el-form-item label="组态图ID">
+          <el-input v-model="queryParams.configId" placeholder="请输入组态图ID" clearable />
+        </el-form-item>
+
+        <el-form-item label="版本号">
+          <el-input v-model="queryParams.version" placeholder="请输入版本号" clearable />
+        </el-form-item>
+
+        <!-- 监控参数条件 -->
+        <el-form-item label="参数名称">
+          <el-input v-model="queryParams.paramName" placeholder="请输入参数名称(如温度)" clearable />
+        </el-form-item>
+
+        <!-- 可视化设置条件 -->
+        <el-form-item label="显示格式">
+          <el-select v-model="queryParams.displayFormat" placeholder="请选择显示格式" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="数值" value="NUMERIC" />
+            <el-option label="百分比" value="PERCENTAGE" />
+            <el-option label="小数" value="DECIMAL" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
+          <el-button icon="Refresh" @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格区域 -->
+    <el-card class="data-table">
+      <el-table
+          :data="configList"
+          border
+          size="small"
+          v-loading="isLoading"
+          row-key="configId"
+          @row-click="handleRowClick"
+      >
+        <el-table-column label="组态图ID" prop="configId" align="center" width="140" />
+        <el-table-column label="图纸路径" prop="drawingPath" align="left" min-width="200">
+          <template #default="scope">
+            <el-link :href="scope.row.drawingPath" type="primary" target="_blank">查看图纸</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="版本号" prop="version" align="center" width="100" />
+        <el-table-column label="绑定设备数" align="center" width="100">
+          <template #default="scope">
+            {{ scope.row.deviceBindings.length }}台
+          </template>
+        </el-table-column>
+        <el-table-column label="监控参数" align="center" min-width="200">
+          <template #default="scope">
+            <div v-for="(param, index) in scope.row.monitorParams" :key="index">
+              {{ param.name }}: {{ param.value }}{{ param.unit }}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="显示格式" prop="displayFormat" align="center" width="100">
+          <template #default="scope">
+            {{ mapDisplayFormat(scope.row.displayFormat) }}
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页组件 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 详情弹窗 -->
+    <el-dialog :visible.sync="detailDialogOpen" title="组态图详情" width="1000px">
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="组态图ID" span="1">{{ detailConfig.configId }}</el-descriptions-item>
+        <el-descriptions-item label="图纸路径" span="1">
+          <el-link :href="detailConfig.drawingPath" type="primary" target="_blank">{{ detailConfig.drawingPath }}</el-link>
+        </el-descriptions-item>
+        <el-descriptions-item label="版本号" span="1">{{ detailConfig.version }}</el-descriptions-item>
+        <el-descriptions-item label="关联三维场景" span="1">{{ detailConfig.associatedSceneId }}</el-descriptions-item>
+        <el-descriptions-item label="热点跳转参数" span="2">
+          <pre class="small-text">{{ detailConfig.hotspotParams }}</pre>
+        </el-descriptions-item>
+      </el-descriptions>
+
+      <!-- 设备绑定信息 -->
+      <el-card class="mt-4" title="设备绑定信息">
+        <el-table :data="detailConfig.deviceBindings" border size="small">
+          <el-table-column label="设备ID" prop="deviceId" align="center" width="140" />
+          <el-table-column label="X坐标" prop="x" align="center" width="100" />
+          <el-table-column label="Y坐标" prop="y" align="center" width="100" />
+          <el-table-column label="设备位置" align="center" width="200">
+            <template #default="scope">
+              <div class="device-marker" :style="{ left: scope.row.x + 'px', top: scope.row.y + 'px' }">
+                {{ scope.row.deviceId }}
+              </div>
+            </template>
+          </el-table-column>
+        </el-table>
+        <!-- 模拟组态图背景 -->
+        <div class="configuration-preview" @click="handleCanvasClick">
+          <div v-for="device in detailConfig.deviceBindings" :key="device.deviceId"
+               class="device-point" :style="{ left: device.x + 'px', top: device.y + 'px' }">
+            {{ device.deviceId }}
+          </div>
+        </div>
+      </el-card>
+
+      <!-- 监控参数与可视化设置 -->
+      <el-card class="mt-4" title="监控参数与可视化设置">
+        <el-tabs v-model="activeTab" type="card">
+          <el-tab-pane label="监控参数">
+            <el-table :data="detailConfig.monitorParams" border size="small">
+              <el-table-column label="参数名称" prop="name" align="center" width="140" />
+              <el-table-column label="实时读数" prop="value" align="center" width="120" />
+              <el-table-column label="单位" prop="unit" align="center" width="100" />
+              <el-table-column label="可视化展示" align="center" width="200">
+                <template #default="scope">
+                  <div class="gauge-container">
+                    <div class="gauge" :style="{ width: getGaugeWidth(scope.row) + '%', backgroundColor: getColor(scope.row) }"></div>
+                    <span class="gauge-value">{{ scope.row.value }}{{ scope.row.unit }}</span>
+                  </div>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-tab-pane>
+          <el-tab-pane label="颜色阈值">
+            <pre class="small-text">{{ detailConfig.colorThresholds }}</pre>
+          </el-tab-pane>
+          <el-tab-pane label="闪烁规则">
+            <pre class="small-text">{{ detailConfig.blinkRules }}</pre>
+          </el-tab-pane>
+          <el-tab-pane label="显示格式">
+            <el-tag type="info">{{ mapDisplayFormat(detailConfig.displayFormat) }}</el-tag>
+          </el-tab-pane>
+        </el-tabs>
+      </el-card>
+
+      <template #footer>
+        <el-button @click="detailDialogOpen = false">关闭</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue';
+import { ElMessage } from 'element-plus';
+import {getBuildingEquipmentMonitoringConfigurationList} from "@/api/buildingEquipmentMonitoring/buildingEquipmentMonitoring.js";
+
+// 查询参数
+const queryParams = reactive({
+  configId: '',
+  version: '',
+  deviceId: '',
+  paramName: '',
+  displayFormat: '',
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "二维组态图管理"
+});
+
+// 表格数据
+const configList = ref([]);
+const total = ref(0);
+const isLoading = ref(false);
+const detailDialogOpen = ref(false);
+const detailConfig = ref({});
+const activeTab = ref('监控参数');
+
+// 获取数据
+const getList = async () => {
+  isLoading.value = true;
+  try {
+    let response = await getBuildingEquipmentMonitoringConfigurationList(queryParams);
+    let filteredData = response.data.list;
+
+    // 组态图ID过滤
+    if (queryParams.configId) {
+      filteredData = filteredData.filter(item => item.configId.includes(queryParams.configId));
+    }
+
+    // 版本号过滤
+    if (queryParams.version) {
+      filteredData = filteredData.filter(item => item.version.includes(queryParams.version));
+    }
+
+    // 设备ID过滤
+    if (queryParams.deviceId) {
+      filteredData = filteredData.filter(item =>
+          item.deviceBindings.some(binding => binding.deviceId.includes(queryParams.deviceId))
+      );
+    }
+
+    // 参数名称过滤
+    if (queryParams.paramName) {
+      filteredData = filteredData.filter(item =>
+          item.monitorParams.some(param => param.name.includes(queryParams.paramName))
+      );
+    }
+
+    // 显示格式过滤
+    if (queryParams.displayFormat) {
+      filteredData = filteredData.filter(item => item.displayFormat === queryParams.displayFormat);
+    }
+
+    // 分页处理
+    total.value = response.data.total;
+    configList.value = filteredData;
+  } catch (error) {
+    ElMessage.error('获取组态图数据失败');
+    console.error(error);
+  } finally {
+    isLoading.value = false;
+  }
+};
+
+// 搜索
+const handleSearch = () => {
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 重置
+const resetSearch = () => {
+  queryParams.configId = '';
+  queryParams.version = '';
+  queryParams.deviceId = '';
+  queryParams.paramName = '';
+  queryParams.displayFormat = '';
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 分页
+const handlePageChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 行点击事件(打开详情弹窗)
+const handleRowClick = (row) => {
+  detailConfig.value = JSON.parse(JSON.stringify(row));
+  detailDialogOpen.value = true;
+};
+
+// 显示格式映射
+const mapDisplayFormat = (format) => {
+  return {
+    'NUMERIC': '数值',
+    'PERCENTAGE': '百分比',
+    'DECIMAL': '小数',
+  }[format] || format;
+};
+
+// 计算仪表宽度
+const getGaugeWidth = (param) => {
+  // 简单示例:根据参数值计算宽度百分比
+  if (param.name === '温度') return param.value * 2;
+  if (param.name === '压力') return param.value * 50;
+  if (param.name === '电流') return param.value * 15;
+  if (param.name === '风速') return param.value * 15;
+  if (param.name === '烟雾浓度') return param.value * 100;
+  if (param.name === '水压') return param.value * 50;
+  if (param.name === '流量') return param.value * 2;
+  if (param.name === '负载率') return param.value;
+  if (param.name === '电压') return param.value / 2.2;
+  if (param.name === '照度') return param.value / 5;
+  if (param.name === '频率') return param.value * 2;
+  if (param.name === '功率因数') return param.value * 100;
+  if (param.name === '湿度') return param.value;
+  if (param.name === '气压') return param.value;
+  if (param.name === 'PH值') return param.value * 10;
+  if (param.name === '浊度') return param.value * 10;
+  if (param.name === '库存量') return param.value / 10;
+  if (param.name === '出入库速率') return param.value * 2;
+  return 50;
+};
+
+// 根据参数获取颜色
+const getColor = (param) => {
+  try {
+    const thresholds = JSON.parse(detailConfig.value.colorThresholds || '{}');
+    const paramThresholds = thresholds[param.name] || {};
+
+    // 简单示例:根据参数值判断颜色
+    const value = param.value;
+    if (param.name === '温度') {
+      return value > 30 ? '#ff4500' : '#ffd700';
+    }
+    if (param.name === '压力') {
+      return value > 1.5 ? '#ff6347' : '#90ee90';
+    }
+    // 其他参数颜色逻辑...
+
+    return '#409eff'; // 默认颜色
+  } catch (error) {
+    return '#409eff';
+  }
+};
+
+// 模拟组态图点击
+const handleCanvasClick = (event) => {
+  const rect = event.currentTarget.getBoundingClientRect();
+  const x = event.clientX - rect.left;
+  const y = event.clientY - rect.top;
+
+  // 实际项目中可以添加设备拖拽放置等功能
+  console.log(`点击坐标: (${x}, ${y})`);
+};
+
+getList()
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+  padding: 20px;
+}
+
+.data-table {
+  min-height: 500px;
+}
+
+.small-text {
+  font-size: 12px;
+  color: #909399;
+}
+
+.mt-4 {
+  margin-top: 16px;
+}
+
+.configuration-preview {
+  position: relative;
+  height: 300px;
+  border: 1px solid #ebeef5;
+  margin-top: 10px;
+  background-color: #f5f7fa;
+  background-image:
+      linear-gradient(#ebeef5 1px, transparent 1px),
+      linear-gradient(90deg, #ebeef5 1px, transparent 1px);
+  background-size: 20px 20px;
+}
+
+.device-point {
+  position: absolute;
+  width: 30px;
+  height: 30px;
+  background-color: #409eff;
+  color: white;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 12px;
+  cursor: pointer;
+  transform: translate(-50%, -50%);
+  transition: all 0.2s;
+}
+
+.device-point:hover {
+  transform: translate(-50%, -50%) scale(1.2);
+  z-index: 10;
+}
+
+.gauge-container {
+  height: 24px;
+  background-color: #e9ecef;
+  border-radius: 4px;
+  overflow: hidden;
+  position: relative;
+}
+
+.gauge {
+  height: 100%;
+  transition: width 0.5s;
+}
+
+.gauge-value {
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  transform: translate(-50%, -50%);
+  font-size: 12px;
+  color: #333;
+}
+</style>

+ 336 - 0
pm_ui/src/views/buildingEquipmentMonitoring/index3.vue

@@ -0,0 +1,336 @@
+<template>
+  <div class="area-management-system">
+    <!-- 查询条件区域 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="searchForm" :inline="true" class="search-form">
+        <!-- 区域层级条件 -->
+        <el-form-item label="区域名称">
+          <el-input v-model="queryParams.areaName" placeholder="请输入区域名称" clearable />
+        </el-form-item>
+
+        <el-form-item label="层级">
+          <el-select v-model="queryParams.level" placeholder="请选择层级" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="一级区域" value="1" />
+            <el-option label="二级区域" value="2" />
+            <el-option label="三级区域" value="3" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 设备统计条件 -->
+        <el-form-item label="设备类型">
+          <el-select v-model="queryParams.deviceType" placeholder="请选择设备类型" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="控制器" value="CONTROLLER" />
+            <el-option label="传感器" value="SENSOR" />
+            <el-option label="执行器" value="ACTUATOR" />
+            <el-option label="广播设备" value="BROADCASTER" />
+            <el-option label="监控设备" value="MONITOR" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 状态过滤条件 -->
+        <el-form-item label="设备状态">
+          <el-select v-model="queryParams.status" placeholder="请选择设备状态" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="在线" value="在线" />
+            <el-option label="故障" value="故障" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
+          <el-button icon="Refresh" @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格区域 -->
+    <el-card class="data-table">
+      <el-table
+          :data="areaList"
+          border
+          size="small"
+          v-loading="isLoading"
+          row-key="areaId"
+          @row-click="handleRowClick"
+      >
+        <el-table-column label="区域ID" prop="areaId" align="center"/>
+        <el-table-column label="区域名称" prop="areaName" align="center"/>
+        <el-table-column label="层级" prop="level" align="center" width="100">
+          <template #default="scope">
+            {{ scope.row.level === 1 ? '一级' : scope.row.level === 2 ? '二级' : '三级' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="设备总数" align="center" width="100">
+          <template #default="scope">
+            {{ scope.row.deviceStats.reduce((sum, stat) => sum + stat.count, 0) }}台
+          </template>
+        </el-table-column>
+        <el-table-column label="平均在线率" align="center" width="120">
+          <template #default="scope">
+            {{ getAverageOnlineRate(scope.row.deviceStats).toFixed(1) }}%
+          </template>
+        </el-table-column>
+        <el-table-column label="健康指数" align="center" width="160">
+          <template #default="scope">
+            <div>
+              <span>{{ parseKeyMetrics(scope.row.keyMetrics).healthIndex }} 分</span>
+              <el-progress
+                  :percentage="parseKeyMetrics(scope.row.keyMetrics).healthIndex"
+                  type="line"
+                  :status="getHealthStatus(parseKeyMetrics(scope.row.keyMetrics).healthIndex)"
+                  style="width: 120px; margin-top: 4px;"
+              />
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页组件 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 详情弹窗 -->
+    <el-dialog :visible.sync="detailDialogOpen" title="区域详情" width="1000px">
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="区域ID" span="1">{{ detailArea.areaId }}</el-descriptions-item>
+        <el-descriptions-item label="区域名称" span="1">{{ detailArea.areaName }}</el-descriptions-item>
+        <el-descriptions-item label="父区域" span="1">
+          {{ detailArea.parentAreaId || "无" }}
+        </el-descriptions-item>
+        <el-descriptions-item label="层级" span="1">
+          {{ detailArea.level === 1 ? '一级区域' : detailArea.level === 2 ? '二级区域' : '三级区域' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="关键指标" span="2">
+          <div>平均能耗:{{ getKeyMetric(detailArea.keyMetrics, 0) }} kWh</div>
+          <div>最大负载:{{ getKeyMetric(detailArea.keyMetrics, 1) }} W</div>
+          <div>健康指数:{{ getKeyMetric(detailArea.keyMetrics, 2) }}分</div>
+        </el-descriptions-item>
+      </el-descriptions>
+
+      <!-- 设备统计图表 -->
+      <el-card class="mt-4" title="设备类型分布">
+        <el-chart :height="300">
+          <el-pie-chart
+              :data="chartData"
+              :options="pieOptions"
+          />
+        </el-chart>
+      </el-card>
+
+      <!-- 空间分布热力图 -->
+      <el-card class="mt-4" title="设备位置热力图">
+        <div class="heatmap-container">
+          <div
+              v-for="(point, index) in heatmapPoints"
+              :key="index"
+              class="heatmap-point"
+              :style="{
+              left: point.x + 'px',
+              top: point.y + 'px',
+              width: point.size * 2 + 'px',
+              height: point.size * 2 + 'px',
+              background: `rgba(255, 165, 0, ${point.opacity})`
+            }"
+          />
+        </div>
+      </el-card>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue';
+import { ElMessage, ElProgress } from 'element-plus';
+import { getBuildingEquipmentMonitoringAreaList } from '@/api/buildingEquipmentMonitoring/buildingEquipmentMonitoring';
+
+// 查询参数
+const queryParams = reactive({
+  areaName: '',
+  level: '',
+  deviceType: [],
+  status: [],
+  pageNum: 1,
+  pageSize: 10,
+});
+
+// 表格数据
+const areaList = ref([]);
+const total = ref(0);
+const isLoading = ref(false);
+const detailDialogOpen = ref(false);
+const detailArea = ref({});
+
+// 图表数据
+const chartData = ref([]);
+const pieOptions = computed(() => ({
+  title: { text: '设备类型占比' },
+  legend: { orient: 'vertical', left: 'left' },
+  series: [{ type: 'pie', radius: '50%', data: chartData.value }],
+}));
+
+// 热力图数据
+const heatmapPoints = ref([]);
+
+// 获取数据
+const getList = async () => {
+  isLoading.value = true;
+  try {
+    const response = await getBuildingEquipmentMonitoringAreaList(queryParams);
+    areaList.value = response.data.list;
+    total.value = response.data.total;
+  } catch (error) {
+    ElMessage.error('获取区域数据失败');
+    console.error(error);
+  } finally {
+    isLoading.value = false;
+  }
+};
+
+// 搜索
+const handleSearch = () => {
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 重置
+const resetSearch = () => {
+  queryParams.areaName = '';
+  queryParams.level = '';
+  queryParams.deviceType = [];
+  queryParams.status = [];
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 分页
+const handlePageChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 行点击事件(打开详情弹窗)
+const handleRowClick = (row) => {
+  detailArea.value = { ...row };
+  // 解析设备统计数据
+  chartData.value = row.deviceStats.map(stat => ({
+    name: mapDeviceType(stat.deviceType),
+    value: stat.count,
+    itemStyle: { color: getDeviceTypeColor(stat.deviceType) }
+  }));
+  // 解析热力图数据
+  parseHeatmapData(row.heatmapData);
+  detailDialogOpen.value = true;
+};
+
+// 设备类型映射
+const mapDeviceType = (type) => {
+  return {
+    'CONTROLLER': '控制器',
+    'SENSOR': '传感器',
+    'ACTUATOR': '执行器',
+    'BROADCASTER': '广播设备',
+    'MONITOR': '监控设备',
+  }[type] || type;
+};
+
+// 设备类型颜色
+const getDeviceTypeColor = (type) => {
+  return {
+    'CONTROLLER': '#409eff',
+    'SENSOR': '#67c23a',
+    'ACTUATOR': '#f56c6c',
+    'BROADCASTER': '#e6a23c',
+    'MONITOR': '#909399',
+  }[type] || '#409eff';
+};
+
+// 计算平均在线率
+const getAverageOnlineRate = (stats) => {
+  if (stats.length === 0) return 0;
+  return stats.reduce((sum, stat) => sum + stat.onlineRate, 0) / stats.length;
+};
+
+// 解析关键指标(平均能耗,最大负载,健康指数)
+const parseKeyMetrics = (keyMetricsStr) => {
+  const [averageEnergy, maxLoad, healthIndex] = keyMetricsStr.split(',').map(Number);
+  return {
+    averageEnergy: averageEnergy.toFixed(2), // 平均能耗保留两位小数
+    maxLoad: maxLoad.toFixed(0), // 最大负载取整
+    healthIndex: healthIndex.toFixed(0), // 健康指数取整
+  };
+};
+
+// 获取健康指数进度条状态
+const getHealthStatus = (healthIndex) => {
+  if (healthIndex >= 90) return 'success'; // 绿色
+  if (healthIndex >= 80) return 'warning'; // 黄色
+  return 'danger'; // 红色
+};
+
+// 解析热力图数据
+const parseHeatmapData = (heatmapStr) => {
+  try {
+    const { heatData } = JSON.parse(heatmapStr);
+    heatmapPoints.value = heatData.map(([x, y, opacity], index) => ({
+      id: `point-${index}`,
+      x: x * 2 + 50, // 模拟坐标偏移
+      y: y * 2 + 50,
+      size: opacity * 20, // 气泡大小
+      opacity: opacity // 透明度
+    }));
+  } catch (error) {
+    heatmapPoints.value = [];
+  }
+};
+
+// 初始加载数据
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+  padding: 20px;
+}
+
+.data-table {
+  min-height: 500px;
+}
+
+.el-chart {
+  height: 300px;
+}
+
+.heatmap-container {
+  position: relative;
+  height: 400px;
+  border: 1px solid #ebeef5;
+  background-color: #f5f7fa;
+  overflow: hidden;
+}
+
+.heatmap-point {
+  position: absolute;
+  border-radius: 50%;
+  transition: all 0.2s;
+}
+
+.heatmap-point:hover {
+  opacity: 1;
+  transform: scale(1.2);
+}
+</style>

+ 412 - 0
pm_ui/src/views/buildingEquipmentMonitoring/index4.vue

@@ -0,0 +1,412 @@
+<template>
+  <div class="control-command-system">
+    <!-- 查询条件区域 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="searchForm" :inline="true" class="search-form">
+        <!-- 控制指令条件 -->
+        <el-form-item label="指令ID">
+          <el-input v-model="queryParams.cmdId" placeholder="请输入指令ID" clearable />
+        </el-form-item>
+
+        <el-form-item label="指令类型">
+          <el-select v-model="queryParams.cmdType" placeholder="请选择指令类型" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="参数设置" value="SET_PARAM" />
+            <el-option label="报警触发" value="TRIGGER_ALARM" />
+            <el-option label="设备启停" value="START_STOP" />
+            <el-option label="校准操作" value="CALIBRATE" />
+            <el-option label="设备重置" value="RESET" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 执行状态条件 -->
+        <el-form-item label="指令状态">
+          <el-select v-model="queryParams.status" placeholder="请选择状态" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="待执行" value="PENDING" />
+            <el-option label="成功" value="SUCCESS" />
+            <el-option label="失败" value="FAILED" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 操作审计条件 -->
+        <el-form-item label="操作员ID">
+          <el-input v-model="queryParams.operatorId" placeholder="请输入操作员ID" clearable />
+        </el-form-item>
+
+        <!-- 响应监控条件 -->
+        <el-form-item label="设备反馈">
+          <el-select v-model="queryParams.feedbackStatus" placeholder="请选择反馈状态" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="正常" value="OK" />
+            <el-option label="超时" value="TIMEOUT" />
+            <el-option label="错误" value="ERROR" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
+          <el-button icon="Refresh" @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格区域 -->
+    <el-card class="data-table">
+      <el-table
+          :data="commandList"
+          border
+          size="small"
+          v-loading="isLoading"
+          row-key="cmdId"
+          @row-click="handleRowClick"
+      >
+        <el-table-column label="指令ID" prop="cmdId" align="center" width="140" />
+        <el-table-column label="目标设备" align="center" >
+          <template #default="scope">
+            <el-tag
+                v-for="device in scope.row.targetDevices"
+                :key="device"
+                size="small"
+                type="info"
+            >
+              {{ device }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="指令类型" prop="cmdType" align="center" />
+        <el-table-column label="指令状态" prop="status" align="center" width="120">
+        <template #default="scope">
+          <el-tag
+              :type="getStatusColor(scope.row.status)"
+              :effect="scope.row.status === 'SUCCESS' ? 'light' : 'dark'"
+          >
+            {{ mapStatus(scope.row.status) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+        <el-table-column label="操作员" prop="operatorId" align="center" width="100" />
+        <el-table-column label="执行时间" prop="timestamp" align="center" width="180" />
+        <el-table-column label="执行耗时" align="center" width="120">
+          <template #default="scope">
+            {{ scope.row.executionTime }} ms
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页组件 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 详情弹窗 -->
+    <el-dialog :visible.sync="detailDialogOpen" title="指令详情" width="1000px">
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="指令ID" span="1">{{ detailCommand.cmdId }}</el-descriptions-item>
+        <el-descriptions-item label="指令类型" span="1">{{ mapCmdType(detailCommand.cmdType) }}</el-descriptions-item>
+        <el-descriptions-item label="目标设备" span="2">
+          <el-tag
+              v-for="device in detailCommand.targetDevices"
+              :key="device"
+              size="medium"
+              type="info"
+          >
+            {{ device }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="指令状态" span="1">
+          <el-badge
+              :text="mapStatus(detailCommand.status)"
+              :type="getStatusColor(detailCommand.status)"
+              :icon="getStatusIcon(detailCommand.status)"
+          />
+        </el-descriptions-item>
+        <el-descriptions-item label="执行时间" span="1">{{ detailCommand.timestamp }}</el-descriptions-item>
+        <el-descriptions-item label="操作员" span="1">{{ detailCommand.operatorId }}</el-descriptions-item>
+        <el-descriptions-item label="IP地址" span="1">{{ detailCommand.ipAddress }}</el-descriptions-item>
+        <el-descriptions-item label="操作详情" span="2">{{ detailCommand.operationDetail }}</el-descriptions-item>
+      </el-descriptions>
+
+      <!-- 响应监控信息 -->
+      <el-card class="mt-4" title="设备响应与执行详情">
+        <el-row :gutter="20">
+          <el-col span="12">
+            <el-card class="response-card">
+              <div class="card-title">反馈状态</div>
+              <div class="status-icon" :class="getStatusClass(detailCommand.feedbackStatus)"></div>
+              <div>{{ mapFeedbackStatus(detailCommand.feedbackStatus) }}</div>
+            </el-card>
+          </el-col>
+          <el-col span="12">
+            <el-card class="execution-card">
+              <div class="card-title">执行耗时</div>
+              <div class="time-value">{{ detailCommand.executionTime }} ms</div>
+              <div v-if="detailCommand.errorCode !== 'NONE'">
+                <div class="error-title">异常代码</div>
+                <div class="error-code">{{ detailCommand.errorCode }}</div>
+                <el-tooltip content="点击查看错误详情" placement="top">
+                  <el-button
+                      type="text"
+                      size="small"
+                      @click="showErrorDialog"
+                  >
+                    查看详情
+                  </el-button>
+                </el-tooltip>
+              </div>
+            </el-card>
+          </el-col>
+        </el-row>
+      </el-card>
+
+      <!-- 策略配置信息 -->
+      <el-card class="mt-4" title="策略配置与联动规则">
+        <el-row :gutter="16">
+          <el-col span="12">
+            <h4>定时任务</h4>
+            <p>{{ detailCommand.scheduleTask || "无定时任务" }}</p>
+          </el-col>
+          <el-col span="12">
+            <h4>场景模式</h4>
+            <p>{{ detailCommand.sceneMode || "无场景模式" }}</p>
+          </el-col>
+        </el-row>
+        <el-row :gutter="16" class="mt-4">
+          <el-col span="24">
+            <h4>联动规则</h4>
+            <p>{{ detailCommand.linkageRule || "无联动配置" }}</p>
+          </el-col>
+        </el-row>
+      </el-card>
+
+      <!-- 错误详情弹窗 -->
+      <el-dialog
+          v-model="errorDialogOpen"
+          title="错误详情"
+          width="400px"
+      >
+        <p>异常代码:{{ detailCommand.errorCode }}</p>
+        <p>处理建议:{{ getErrorSuggestion(detailCommand.errorCode) }}</p>
+      </el-dialog>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue';
+import { ElMessage, ElBadge, ElDialog } from 'element-plus';
+import {
+  getBuildingEquipmentMonitoringCommandsList
+} from "@/api/buildingEquipmentMonitoring/buildingEquipmentMonitoring";
+
+// 查询参数
+const queryParams = reactive({
+  cmdId: '',
+  cmdType: '',
+  status: '',
+  operatorId: '',
+  feedbackStatus: '',
+  pageNum: 1,
+  pageSize: 10,
+});x
+
+// 表格数据
+const commandList = ref([]);
+const total = ref(0);
+const isLoading = ref(false);
+const detailDialogOpen = ref(false);
+const detailCommand = ref({});
+const errorDialogOpen = ref(false);
+
+// 指令状态映射
+const mapStatus = (status) => {
+  const statusMap = {
+    'PENDING': '待执行',
+    'SUCCESS': '成功',
+    'FAILED': '失败',
+    'PROCESSING': '处理中',
+    'RETRYING': '重试中',
+    'CANCELED': '已取消'
+  };
+  return statusMap[status] || status;
+};
+
+// 状态颜色映射
+const getStatusColor = (status) => {
+  const colorMap = {
+    'PENDING': 'warning',
+    'SUCCESS': 'success',
+    'FAILED': 'danger',
+    'PROCESSING': 'primary',
+    'RETRYING': 'info',
+    'CANCELED': 'info'
+  };
+  return colorMap[status] || 'info';
+};
+
+const mapFeedbackStatus = (status) => {
+  return {
+    OK: '设备正常响应',
+    TIMEOUT: '响应超时',
+    ERROR: '响应错误',
+  }[status] || status;
+};
+
+// 指令类型映射
+const mapCmdType = (type) => {
+  return {
+    SET_PARAM: '参数设置',
+    TRIGGER_ALARM: '报警触发',
+    START_STOP: '设备启停',
+    CALIBRATE: '校准操作',
+    RESET: '设备重置',
+  }[type] || type;
+};
+
+// 状态图标与颜色
+const getStatusIcon = (status) => {
+  return {
+    PENDING: 'el-icon-clock',
+    SUCCESS: '',
+    FAILED: 'el-icon-error',
+  }[status] || 'el-icon-info';
+};
+
+const getStatusClass = (status) => {
+  return {
+    OK: 'status-ok',
+    TIMEOUT: 'status-timeout',
+    ERROR: 'status-error',
+  }[status] || 'status-unknown';
+};
+
+// 错误处理建议
+const getErrorSuggestion = (errorCode) => {
+  return {
+    ALARM_MODULE_FAILURE: '检查报警模块连接状态',
+    COMMUNICATION_ERROR: '重启通信设备并检查网络',
+    TIMEOUT: '增加指令超时时间设置',
+    DEFAULT_ERROR: '联系系统管理员',
+  }[errorCode] || 'DEFAULT_ERROR';
+};
+
+// 获取数据
+const getList = async () => {
+  isLoading.value = true;
+  try {
+    const response = await getBuildingEquipmentMonitoringCommandsList(queryParams);
+    commandList.value = response.data.list;
+    total.value = response.data.total;
+  } catch (error) {
+    ElMessage.error('获取指令数据失败');
+    console.error(error);
+  } finally {
+    isLoading.value = false;
+  }
+};
+
+// 搜索
+const handleSearch = () => {
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 重置
+const resetSearch = () => {
+  queryParams.cmdId = '';
+  queryParams.cmdType = '';
+  queryParams.status = '';
+  queryParams.operatorId = '';
+  queryParams.feedbackStatus = '';
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 分页
+const handlePageChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 行点击事件
+const handleRowClick = (row) => {
+  detailCommand.value = { ...row };
+  detailDialogOpen.value = true;
+};
+
+// 显示错误详情
+const showErrorDialog = () => {
+  errorDialogOpen.value = true;
+};
+
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+  padding: 20px;
+}
+
+.data-table {
+  min-height: 500px;
+}
+
+.el-badge {
+  font-size: 14px;
+}
+
+.response-card, .execution-card {
+  height: 150px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.status-icon {
+  width: 48px;
+  height: 48px;
+  border-radius: 50%;
+  margin-bottom: 12px;
+}
+
+.status-ok { background-color: #67c23a; }
+.status-timeout { background-color: #e6a23c; }
+.status-error { background-color: #f56c6c; }
+
+.time-value {
+  font-size: 24px;
+  font-weight: 500;
+  color: #333;
+}
+
+.error-title {
+  color: #f56c6c;
+  margin-top: 16px;
+}
+
+.error-code {
+  font-size: 14px;
+  color: #666;
+}
+
+.card-title {
+  font-size: 16px;
+  font-weight: 500;
+  margin-bottom: 8px;
+}
+</style>

+ 121 - 0
pm_ui/src/views/driverInfo/index.vue

@@ -0,0 +1,121 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索栏 -->
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="设备名称" prop="name">
+        <el-input
+            v-model="queryParams.name"
+            placeholder="输入设备名称"
+            clearable
+            @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="安装位置" prop="location">
+        <el-input
+            v-model="queryParams.location"
+            placeholder="输入安装位置"
+            clearable
+            @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 数据表格 -->
+    <el-table v-loading="loading" :data="devices" border>
+      <el-table-column label="序号" type="index" align="center" width="50" />
+      <el-table-column label="设备ID" align="center" prop="id" />
+      <el-table-column label="设备名称" align="center" prop="name" />
+      <el-table-column label="安装位置" align="center" prop="location" />
+      <el-table-column label="设备类型" align="center" prop="deviceType" />
+      <el-table-column label="状态" align="center">
+        <template #default="scope">
+          <el-tag :type="getStatusType(scope.row.status)">
+            {{ scope.row.status }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="IP地址" align="center" prop="ipAddress" />
+      <el-table-column label="屏幕尺寸" align="center" prop="screenSize" />
+      <el-table-column label="最后在线时间" align="center" prop="lastOnlineTime" />
+    </el-table>
+
+    <!-- 分页器 -->
+    <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+    />
+  </div>
+</template>
+
+<script setup name="DeviceManagement">
+import { ref, reactive } from "vue";
+import {driverInfoList} from "@/api/driverInfo/driverInfo";
+
+// 定义响应式变量
+const queryRef = ref(null);
+const devices = ref([]); // 设备数据
+const loading = ref(false); // 加载状态
+const showSearch = ref(true); // 是否显示搜索栏
+const total = ref(0); // 总记录数
+
+// 查询参数
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  name: '',
+  location: '',
+  interfaceName: "信息引导及发布"
+});
+
+// 获取设备列表
+const getList = async () => {
+  try {
+    loading.value = true;
+    const response = await driverInfoList(queryParams);
+    devices.value = response.data.list || []; // 确保数据格式正确
+    total.value = response.data.total || 0; // 确保总记录数正确
+  } catch (error) {
+    console.error('获取数据失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索按钮操作
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置到第一页
+  getList();
+};
+
+// 重置按钮操作
+const resetQuery = () => {
+  queryRef.value.resetFields(); // 重置表单字段
+  handleQuery(); // 重新查询
+};
+
+// 根据状态返回标签类型
+const getStatusType = (status) => {
+  if (status === "在线") return "success";
+  if (status === "离线") return "warning";
+  if (status === "故障") return "danger";
+  return "info";
+};
+
+// 初始化加载数据
+getList();
+</script>
+
+<style scoped>
+.el-table .cell {
+  white-space: nowrap;
+}
+</style>

+ 132 - 0
pm_ui/src/views/estateManagement/index.vue

@@ -0,0 +1,132 @@
+<template>
+  <div class="owner-management">
+    <!-- 搜索栏 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryRef" :inline="true" class="filter-form">
+        <el-form-item label="业主姓名" prop="name">
+          <el-input
+              v-model="queryParams.name"
+              placeholder="请输入业主姓名"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item label="房号" prop="roomNo">
+          <el-input
+              v-model="queryParams.roomNo"
+              placeholder="请输入房号(如:101)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="device-table">
+      <el-table v-loading="loading" :data="owners" border>
+        <el-table-column label="序号" type="index" align="center" width="180" />
+        <el-table-column label="业主ID" align="center" prop="ownerId" width="120" />
+        <el-table-column label="姓名" align="center" prop="name" width="120" />
+        <el-table-column label="楼栋号" align="center" prop="buildingNo" width="180" />
+        <el-table-column label="房号" align="center" prop="roomNo" width="120" />
+        <el-table-column label="联系方式" align="center" prop="phone" width="150" />
+        <el-table-column label="入住日期" align="center" prop="moveInDate" width="180" />
+        <el-table-column label="紧急联系人" align="center" prop="emergencyContact" width="180" />
+        <el-table-column label="车位号" align="center" prop="parkingSpace" width="180" />
+        <el-table-column label="宠物登记信息" align="center" prop="petInfo" />
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { getEstateManagementList } from "@/api/estateManagement/estateManagement"; // 假设API路径
+
+// 查询参数
+const queryParams = reactive({
+  name: "", // 业主姓名
+  roomNo: "", // 房号
+  pageNum: 1, // 当前页码
+  pageSize: 10, // 每页条数
+  interfaceName: "业主档案"
+});
+
+// 表格数据
+const owners = ref([]);
+const total = ref(0);
+const loading = ref(false);
+
+// 获取业主列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    const response = await getEstateManagementList(queryParams);
+    owners.value = response.data.list || [];
+    total.value = response.data.total || 0;
+  } catch (error) {
+    console.error("获取业主数据失败", error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.name = "";
+  queryParams.roomNo = "";
+  handleQuery();
+};
+
+// 分页事件
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  getList();
+};
+
+const handleCurrentChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.el-table .cell {
+  white-space: normal; /* 允许单元格内容换行 */
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 156 - 0
pm_ui/src/views/estateManagement/index2.vue

@@ -0,0 +1,156 @@
+<template>
+  <div class="fee-management">
+    <!-- 搜索栏 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryRef" :inline="true" class="filter-form">
+        <el-form-item label="账单编号" prop="billId">
+          <el-input
+              v-model="queryParams.billId"
+              placeholder="请输入账单编号(如:FEE2024001)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item label="费用类型" prop="feeType">
+          <el-select
+              v-model="queryParams.feeType"
+              placeholder="请选择费用类型"
+              style="width: 180px;"
+          >
+            <el-option label="全部" value="" />
+            <el-option label="物业费" value="物业费" />
+            <el-option label="水费" value="水费" />
+            <el-option label="电费" value="电费" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="device-table">
+      <el-table v-loading="loading" :data="feeRecords" border>
+        <el-table-column label="序号" type="index" align="center" />
+        <el-table-column label="账单编号" align="center" prop="billId" />
+        <el-table-column label="业主ID" align="center" prop="ownerId"  />
+        <el-table-column label="费用类型" align="center" prop="feeType" />
+        <el-table-column label="应收金额" align="right" prop="dueAmount" >
+          <template #default="scope">
+            ¥ {{ scope.row.dueAmount | numberFormat }}
+          </template>
+        </el-table-column>
+        <el-table-column label="实收金额" align="right" prop="paidAmount" >
+          <template #default="scope">
+            ¥ {{ scope.row.paidAmount | numberFormat }}
+          </template>
+        </el-table-column>
+        <el-table-column label="欠费状态" align="center" prop="arrearsStatus" >
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.arrearsStatus)">
+              {{ scope.row.arrearsStatus }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="缴费期限" align="center" prop="dueDate" />
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import {getEstateManagementFeeDataList} from "@/api/estateManagement/estateManagement.js"; // 金额格式化工具
+
+// 查询参数
+const queryParams = reactive({
+  billId: "", // 账单编号(支持精确查询)
+  feeType: "", // 费用类型(物业费/水费/电费)
+  pageNum: 1, // 当前页码
+  pageSize: 10, // 每页条数
+  interfaceName: "物业费用中心"
+});
+
+// 表格数据
+const feeRecords = ref([]);
+const total = ref(0);
+const loading = ref(false);
+
+// 获取费用记录列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    const response = await getEstateManagementFeeDataList(queryParams);
+    feeRecords.value = response.data.list || [];
+    total.value = response.data.total || 0;
+  } catch (error) {
+    console.error("获取费用数据失败", error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.billId = "";
+  queryParams.feeType = "";
+  handleQuery();
+};
+
+// 分页事件
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  getList();
+};
+
+const handleCurrentChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+// 状态标签类型映射
+const getStatusType = (status) => {
+  if (status === "已结清") return "success";
+  if (status === "部分缴纳") return "warning";
+  if (status === "未缴纳") return "danger";
+  return "info";
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.el-table .cell {
+  white-space: nowrap;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 151 - 0
pm_ui/src/views/estateManagement/index3.vue

@@ -0,0 +1,151 @@
+<template>
+  <div class="facility-management">
+    <!-- 搜索栏 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryRef" :inline="true" class="filter-form">
+        <el-form-item label="设备ID" prop="deviceId">
+          <el-input
+              v-model="queryParams.deviceId"
+              placeholder="请输入设备ID(如:DEV2024001)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item label="设备类型" prop="deviceType">
+          <el-select
+              v-model="queryParams.deviceType"
+              placeholder="请选择设备类型"
+              style="width: 180px;"
+          >
+            <el-option label="全部" value="" />
+            <el-option label="电梯" value="电梯" />
+            <el-option label="水泵" value="水泵" />
+            <el-option label="配电箱" value="配电箱" />
+            <el-option label="空调" value="空调" />
+            <el-option label="消防设备" value="消防设备" />
+            <el-option label="监控设备" value="监控设备" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="device-table">
+      <el-table v-loading="loading" :data="facilities" border>
+        <el-table-column label="序号" type="index" align="center"  />
+        <el-table-column label="设备ID" align="center" prop="deviceId"  />
+        <el-table-column label="名称" align="center" prop="name"  />
+        <el-table-column label="安装位置" align="center" prop="location"  />
+        <el-table-column label="品牌型号" align="center" prop="brandModel"  />
+        <el-table-column label="维保周期" align="center" prop="maintenanceCycle"  />
+        <el-table-column label="当前状态" align="center" prop="status" >
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.status)">
+              {{ scope.row.status }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="上次维保日期" align="center" prop="lastMaintenanceDate"  />
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import {getEstateManagementFacilityDataList} from "@/api/estateManagement/estateManagement"; // 假设API路径
+
+// 查询参数
+const queryParams = reactive({
+  deviceId: "", // 设备ID(支持精确查询)
+  deviceType: "", // 设备类型(电梯/水泵/配电箱等)
+  pageNum: 1, // 当前页码
+  pageSize: 10, // 每页条数
+  interfaceName: "设施设备台账"
+});
+
+// 表格数据
+const facilities = ref([]);
+const total = ref(0);
+const loading = ref(false);
+
+// 获取设施设备列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    const response = await getEstateManagementFacilityDataList(queryParams);
+    facilities.value = response.data.list || [];
+    total.value = response.data.total || 0;
+  } catch (error) {
+    console.error("获取设施设备数据失败", error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.deviceId = "";
+  queryParams.deviceType = "";
+  handleQuery();
+};
+
+// 分页事件
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  getList();
+};
+
+const handleCurrentChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+// 状态标签类型映射
+const getStatusType = (status) => {
+  if (status === "正常") return "success";
+  if (status === "待维保") return "warning";
+  if (status === "维修中") return "danger";
+  return "info";
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.el-table .cell {
+  white-space: nowrap;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 142 - 0
pm_ui/src/views/estateManagement/index4.vue

@@ -0,0 +1,142 @@
+<template>
+  <div class="security-monitoring">
+    <!-- 搜索栏 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryRef" :inline="true" class="filter-form">
+        <el-form-item label="摄像头ID" prop="cameraId">
+          <el-input
+              v-model="queryParams.cameraId"
+              placeholder="请输入摄像头ID(如:CAM2024001)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item label="安装位置" prop="location">
+          <el-input
+              v-model="queryParams.location"
+              placeholder="请输入位置(如:园区南门)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="device-table">
+      <el-table v-loading="loading" :data="cameras" border>
+        <el-table-column label="序号" type="index" align="center" />
+        <el-table-column label="摄像头ID" align="center" prop="cameraId" />
+        <el-table-column label="位置" align="center" prop="location" />
+        <el-table-column label="状态" align="center" prop="status" width="80">
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.status)">
+              {{ scope.row.status }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="录像存储路径" align="left" prop="storagePath" />
+        <el-table-column label="最后触发时间" align="center" prop="lastTriggerTime" />
+        <el-table-column label="报警类型" align="center" prop="alarmType" />
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import {getEstateManagementSecurityDataList} from "@/api/estateManagement/estateManagement"; // 假设API路径
+
+// 查询参数(两个条件:cameraId、location)
+const queryParams = reactive({
+  cameraId: "", // 摄像头ID(精确查询)
+  location: "", // 安装位置(支持模糊查询)
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "安防监控中心"
+});
+
+// 表格数据
+const cameras = ref([]);
+const total = ref(0);
+const loading = ref(false);
+
+// 获取安防数据列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    const response = await getEstateManagementSecurityDataList(queryParams);
+    cameras.value = response.data.list || [];
+    total.value = response.data.total || 0;
+  } catch (error) {
+    console.error("获取安防数据失败", error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.cameraId = "";
+  queryParams.location = "";
+  handleQuery();
+};
+
+// 分页事件
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  getList();
+};
+
+const handleCurrentChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+// 状态标签类型映射
+const getStatusType = (status) => {
+  if (status === "在线") return "success";
+  if (status === "故障") return "danger";
+  return "info";
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.el-table .cell {
+  white-space: normal; /* 允许长路径换行 */
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 148 - 0
pm_ui/src/views/estateManagement/index5.vue

@@ -0,0 +1,148 @@
+<template>
+  <div class="work-order-platform">
+    <!-- 搜索栏 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryRef" :inline="true" class="filter-form">
+        <el-form-item label="工单号" prop="orderId">
+          <el-input
+              v-model="queryParams.orderId"
+              placeholder="请输入工单号(如:WO2024001)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item label="工单类型" prop="type">
+          <el-select
+              v-model="queryParams.type"
+              placeholder="请选择工单类型"
+              style="width: 180px;"
+          >
+            <el-option label="全部" value="" />
+            <el-option label="维修" value="维修" />
+            <el-option label="清洁" value="清洁" />
+            <el-option label="投诉" value="投诉" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="device-table">
+      <el-table v-loading="loading" :data="workOrders" border>
+        <el-table-column label="序号" type="index" align="center" />
+        <el-table-column label="工单号" align="center" prop="orderId" />
+        <el-table-column label="提交人" align="center" prop="submitter" />
+        <el-table-column label="工单类型" align="center" prop="type" />
+        <el-table-column label="紧急程度" align="center" prop="urgency" />
+        <el-table-column label="处理人" align="center" prop="handler" />
+        <el-table-column label="进度" align="center" prop="status" >
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.status)">
+              {{ scope.row.status }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="耗时" align="center" prop="duration" />
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { getEstateManagementWorkOrderDataList } from "@/api/estateManagement/estateManagement"; // 假设API路径
+
+// 查询参数(两个条件:orderId、type)
+const queryParams = reactive({
+  orderId: "", // 工单号(精确查询)
+  type: "", // 工单类型(维修/清洁/投诉)
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "工单调度平台"
+});
+
+// 表格数据
+const workOrders = ref([]);
+const total = ref(0);
+const loading = ref(false);
+
+// 获取工单列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    const response = await getEstateManagementWorkOrderDataList(queryParams);
+    workOrders.value = response.data.list || [];
+    total.value = response.data.total || 0;
+  } catch (error) {
+    console.error("获取工单数据失败", error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.orderId = "";
+  queryParams.type = "";
+  handleQuery();
+};
+
+// 分页事件
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  getList();
+};
+
+const handleCurrentChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+// 状态标签类型映射
+const getStatusType = (status) => {
+  if (status === "待接单") return "warning";
+  if (status === "处理中") return "info";
+  if (status === "完成") return "success";
+  return "info";
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.el-table .cell {
+  white-space: nowrap;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 143 - 0
pm_ui/src/views/estateManagement/index6.vue

@@ -0,0 +1,143 @@
+<template>
+  <div class="energy-monitoring">
+    <!-- 搜索栏 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryRef" :inline="true" class="filter-form">
+        <el-form-item label="计量点ID" prop="meterId">
+          <el-input
+              v-model="queryParams.meterId"
+              placeholder="请输入计量点ID(如:EM2024001)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item label="楼栋号" prop="buildingNo">
+          <el-input
+              v-model="queryParams.buildingNo"
+              placeholder="请输入楼栋号(如:1栋)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="device-table">
+      <el-table v-loading="loading" :data="energyRecords" border>
+        <el-table-column label="序号" type="index" align="center" />
+        <el-table-column label="计量点ID" align="center" prop="meterId" />
+        <el-table-column label="楼栋号" align="center" prop="buildingNo" />
+        <el-table-column label="上月读数" align="right" prop="lastMonthReading" />
+        <el-table-column label="本月读数" align="right" prop="currentMonthReading" />
+        <el-table-column label="异常用量预警值" align="right" prop="warningValue" />
+        <el-table-column label="同比变化率" align="center" prop="yoyChange" >
+          <template #default="scope">
+            <el-tag :type="getChangeType(scope.row.yoyChange)">
+              {{ scope.row.yoyChange }}
+            </el-tag>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import {getEstateManagementEnergyDataList} from "@/api/estateManagement/estateManagement"; // 假设API路径
+
+// 查询参数(两个条件:meterId、buildingNo)
+const queryParams = reactive({
+  meterId: "", // 计量点ID(精确查询)
+  buildingNo: "", // 楼栋号(支持模糊查询)
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "能源监测台"
+});
+
+// 表格数据
+const energyRecords = ref([]);
+const total = ref(0);
+const loading = ref(false);
+
+// 获取能源数据列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    const response = await getEstateManagementEnergyDataList(queryParams);
+    energyRecords.value = response.data.list || [];
+    total.value = response.data.total || 0;
+  } catch (error) {
+    console.error("获取能源数据失败", error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.meterId = "";
+  queryParams.buildingNo = "";
+  handleQuery();
+};
+
+// 分页事件
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  getList();
+};
+
+const handleCurrentChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+// 同比变化率标签类型映射
+const getChangeType = (changeRate) => {
+  const rate = parseFloat(changeRate);
+  if (rate > 10) return "danger"; // 超过10%显示红色警告
+  if (rate > 5) return "warning"; // 超过5%显示黄色警告
+  return "success"; // 低于5%显示绿色正常
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.el-table .cell {
+  white-space: nowrap;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 142 - 0
pm_ui/src/views/estateManagement/index7.vue

@@ -0,0 +1,142 @@
+<template>
+  <div class="rental-management">
+    <!-- 搜索栏 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryRef" :inline="true" class="filter-form">
+        <el-form-item label="房源编号" prop="propertyId">
+          <el-input
+              v-model="queryParams.propertyId"
+              placeholder="请输入房源编号(如:PROP2024001)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item label="户型" prop="layout">
+          <el-select
+              v-model="queryParams.layout"
+              placeholder="请选择户型"
+              style="width: 180px;"
+          >
+            <el-option label="全部" value="" />
+            <el-option label="一室一厅" value="一室一厅" />
+            <el-option label="两室一厅" value="两室一厅" />
+            <el-option label="两室两厅" value="两室两厅" />
+            <el-option label="三室一厅" value="三室一厅" />
+            <el-option label="三室两厅" value="三室两厅" />
+            <el-option label="四室两厅" value="四室两厅" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="device-table">
+      <el-table v-loading="loading" :data="properties" border>
+        <el-table-column label="序号" type="index" align="center"   />
+        <el-table-column label="房源编号" align="center" prop="propertyId"   />
+        <el-table-column label="面积(㎡)" align="right" prop="area"   />
+        <el-table-column label="户型" align="center" prop="layout"   />
+        <el-table-column label="月租金(元)" align="right" prop="monthlyRent"   />
+        <el-table-column label="租客信息" align="center" prop="tenant"   />
+        <el-table-column label="合同起止日" align="center"  >
+          <template #default="scope">
+            {{ scope.row.contractStart }} - {{ scope.row.contractEnd }}
+          </template>
+        </el-table-column>
+        <el-table-column label="押金状态" align="center" prop="depositStatus"   />
+        <el-table-column label="历史租赁记录" align="left" prop="history" />
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { getEstateManagementRentalDataList } from "@/api/estateManagement/estateManagement"; // 假设API路径
+
+// 查询参数(两个条件:propertyId、layout)
+const queryParams = reactive({
+  propertyId: "", // 房源编号(精确查询)
+  layout: "", // 户型(下拉选择)
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "租赁资产管家"
+});
+
+// 表格数据
+const properties = ref([]);
+const total = ref(0);
+const loading = ref(false);
+
+// 获取房源列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    const response = await getEstateManagementRentalDataList(queryParams);
+    properties.value = response.data.list || [];
+    total.value = response.data.total || 0;
+  } catch (error) {
+    console.error("获取房源数据失败", error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.propertyId = "";
+  queryParams.layout = "";
+  handleQuery();
+};
+
+// 分页事件
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  getList();
+};
+
+const handleCurrentChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.el-table .cell {
+  white-space: normal; /* 允许历史记录换行 */
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 382 - 0
pm_ui/src/views/estateManagement/index8.vue

@@ -0,0 +1,382 @@
+<template>
+  <div class="work-order-analysis">
+    <!-- 搜索栏 -->
+    <el-card class="filter-section">
+      <el-form :model="queryParams" ref="searchForm" :inline="true" class="search-form">
+        <el-form-item label="统计时间" prop="timeRange">
+          <el-date-picker
+              v-model="queryParams.timeRange"
+              type="monthrange"
+              range-separator="至"
+              start-placeholder="开始月份"
+              end-placeholder="结束月份"
+              format="YYYY-MM"
+              value-format="YYYY-MM"
+              :picker-options="pickerOptions"
+              style="width: 300px;"
+          />
+        </el-form-item>
+
+        <el-form-item label="高频问题分类" prop="topIssue">
+          <el-select
+              v-model="queryParams.topIssue"
+              placeholder="请选择高频问题"
+              style="width: 200px;"
+          >
+            <el-option label="全部" value="" />
+            <el-option label="设备故障" value="设备故障" />
+            <el-option label="公共区域卫生" value="公共区域卫生" />
+            <el-option label="停车管理" value="停车管理" />
+            <el-option label="电梯维护" value="电梯维护" />
+            <el-option label="公共设施维修" value="公共设施维修" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="getList" :disabled="isLoading">
+            查询
+          </el-button>
+          <el-button icon="Refresh" @click="resetSearch" :disabled="isLoading">
+            重置
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据展示区域 -->
+    <el-card class="analysis-container">
+      <!-- 关键指标卡片(带背景色) -->
+      <div class="key-metrics">
+        <el-card
+            v-for="(metric, index) in keyMetrics"
+            :key="metric.title"
+            class="metric-card"
+            :style="{ background: metricColors[index] }"
+        >
+          <div class="metric-title">{{ metric.title }}</div>
+          <div class="metric-value">
+            {{ metric.value || "-" }}
+            <span v-if="metric.unit">{{ metric.unit }}</span>
+          </div>
+        </el-card>
+      </div>
+
+      <!-- 数据表格 -->
+      <el-table
+          v-loading="isLoading"
+          :data="analysisData"
+          border
+          v-show="analysisData.length > 0"
+      >
+        <el-table-column label="统计月份" prop="month" align="center" />
+        <el-table-column label="工单完成率" prop="completionRate" align="right">
+          <template #default="scope">
+            {{ scope.row.completionRate }}%
+          </template>
+        </el-table-column>
+        <el-table-column label="平均响应时长" prop="avgResponseTime" align="right">
+          <template #default="scope">
+            {{ scope.row.avgResponseTime }}小时
+          </template>
+        </el-table-column>
+        <el-table-column label="返工率" prop="reworkRate" align="right">
+          <template #default="scope">
+            {{ scope.row.reworkRate }}%
+          </template>
+        </el-table-column>
+        <el-table-column label="满意度评分" prop="satisfactionScore" align="right">
+          <template #default="scope">
+            {{ scope.row.satisfactionScore }}/5
+          </template>
+        </el-table-column>
+        <el-table-column label="高频问题" prop="topIssue" align="center" />
+      </el-table>
+
+      <!-- 空数据提示 -->
+      <div class="empty-tip" v-show="!analysisData.length && !isLoading">
+        <el-icon><CircleClose /></el-icon>
+        <span>暂无符合条件的工单数据</span>
+      </div>
+
+      <!-- 分页组件 -->
+      <el-pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:current-page="queryParams.pageNum"
+          v-model:page-size="queryParams.pageSize"
+          @current-change="handlePageChange"
+          @size-change="handleSizeChange"
+          layout="total, sizes, prev, pager, next, jumper"
+          class="pagination"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, watch } from "vue";
+import { getEstateManagementWorkOrderAnalysisDataList } from "@/api/estateManagement/estateManagement";
+
+// 查询参数
+const queryParams = reactive({
+  timeRange: [], // 时间范围数组 ["start", "end"]
+  topIssue: "",
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "服务工单分析",
+});
+
+const total = ref(0);
+const analysisData = ref([]);
+const isLoading = ref(false);
+
+// 关键指标
+const keyMetrics = ref([
+  { title: "平均完成率", value: null, unit: "%" },
+  { title: "平均响应时长", value: null, unit: "小时" },
+  { title: "平均返工率", value: null, unit: "%" },
+  { title: "平均满意度", value: null, unit: "/5" },
+]);
+
+// 日期格式化函数(修复年份和月份显示)
+const formatDate = (date) => {
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, "0"); // 确保两位月份
+  return `${year}-${month}`; // 返回完整格式如 "2025-01"
+};
+
+// 日期选择器快捷选项
+const pickerOptions = {
+  shortcuts: [
+    {
+      text: "近1个月",
+      onClick(picker) {
+        const end = new Date();
+        const start = new Date();
+        start.setMonth(start.getMonth() - 1);
+        picker.$emit("input", [formatDate(start), formatDate(end)]);
+      },
+    },
+    {
+      text: "近3个月",
+      onClick(picker) {
+        const end = new Date();
+        const start = new Date();
+        start.setMonth(start.getMonth() - 3);
+        picker.$emit("input", [formatDate(start), formatDate(end)]);
+      },
+    },
+    {
+      text: "近6个月",
+      onClick(picker) {
+        const end = new Date();
+        const start = new Date();
+        start.setMonth(start.getMonth() - 5);
+        picker.$emit("input", [formatDate(start), formatDate(end)]);
+      },
+    },
+  ],
+};
+
+// 获取数据
+const getList = async () => {
+  if (isLoading.value) return;
+  isLoading.value = true;
+
+  try {
+    const [startMonth, endMonth] = queryParams.timeRange;
+
+    const params = {
+      ...queryParams,
+      startMonth,
+      endMonth,
+    };
+
+    const response = await getEstateManagementWorkOrderAnalysisDataList(params);
+    analysisData.value = response.data.list || [];
+    total.value = response.data.total || 0;
+    updateKeyMetrics(analysisData.value);
+  } catch (error) {
+    console.error("数据获取失败:", error);
+  } finally {
+    isLoading.value = false;
+  }
+};
+
+// 更新关键指标
+const updateKeyMetrics = (data) => {
+  if (data.length === 0) {
+    keyMetrics.value = keyMetrics.value.map(metric => ({ ...metric, value: null }));
+    return;
+  }
+
+  const completionRate = data.reduce((sum, item) => sum + item.completionRate, 0) / data.length;
+  const avgResponseTime = data.reduce((sum, item) => sum + item.avgResponseTime, 0) / data.length;
+  const reworkRate = data.reduce((sum, item) => sum + item.reworkRate, 0) / data.length;
+  const satisfactionScore = data.reduce((sum, item) => sum + item.satisfactionScore, 0) / data.length;
+
+  keyMetrics.value = [
+    { title: "平均完成率", value: completionRate.toFixed(1), unit: "%" },
+    { title: "平均响应时长", value: avgResponseTime.toFixed(1), unit: "小时" },
+    { title: "平均返工率", value: reworkRate.toFixed(1), unit: "%" },
+    { title: "平均满意度", value: satisfactionScore.toFixed(1), unit: "/5" },
+  ];
+};
+
+// 重置搜索条件
+const resetSearch = () => {
+  queryParams.timeRange = [];
+  queryParams.topIssue = "";
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 分页处理
+const handlePageChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  getList();
+};
+
+// 初始化默认查询(近6个月)
+watch(
+    () => queryParams.timeRange.length,
+    (hasRange) => {
+      if (!hasRange) {
+        const end = new Date();
+        const start = new Date();
+        start.setMonth(start.getMonth() - 12); // 近6个月
+
+        // 确保生成正确的年份和月份
+        queryParams.timeRange = [formatDate(start), formatDate(end)];
+        console.log("初始化时间范围:", queryParams.timeRange); // 调试输出
+
+        // 延迟执行,确保DOM更新
+        setTimeout(() => {
+          getList();
+        }, 100);
+      }
+    },
+    { immediate: true }
+);
+// 新增:关键指标背景色(4种不同颜色循环)
+const metricColors = ref([
+  "#e0f2f1", "#e3f2fd", "#fce4ec", "#f9fbe7", // 绿色、蓝色、粉色、黄色系
+]);
+</script>
+
+<style scoped>
+.filter-section {
+  margin-bottom: 20px;
+  padding: 20px;
+  background: #f8f9fa;
+  border-radius: 8px;
+}
+
+.key-metrics {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
+  gap: 24px;
+  margin-bottom: 32px;
+}
+
+.metric-card {
+  padding: 24px;
+  background: #fff;
+  border-radius: 12px;
+  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
+  text-align: center;
+  transition: transform 0.2s ease;
+}
+
+.metric-title {
+  font-size: 14px;
+  color: #6c757d;
+  margin-bottom: 8px;
+}
+
+.metric-value {
+  font-size: 24px;
+  font-weight: 500;
+  color: #333;
+}
+
+.detail-table {
+  width: 100%;
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+.empty-tip {
+  padding: 40px;
+  text-align: center;
+  color: #6c757d;
+}
+
+.el-pagination {
+  margin-top: 24px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.el-table th {
+  background: #f5f7fa;
+  font-weight: 500;
+}
+.key-metrics {
+  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); /* 调整卡片宽度 */
+  gap: 32px; /* 增加间距 */
+}
+
+.metric-card {
+  padding: 32px 24px; /* 增加内边距 */
+  border-radius: 16px; /* 更圆润的边框 */
+  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08); /* 更深的阴影 */
+  transition: all 0.3s ease; /* 平滑过渡 */
+  cursor: pointer; /* 鼠标悬停手势 */
+}
+
+/* 鼠标悬停效果 */
+.metric-card:hover {
+  transform: translateY(-4px);
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+}
+
+/* 不同指标的背景色(对应metricColors数组) */
+.metric-card:nth-child(1) { background: #e0f2f1; }
+.metric-card:nth-child(2) { background: #e3f2fd; }
+.metric-card:nth-child(3) { background: #fce4ec; }
+.metric-card:nth-child(4) { background: #f9fbe7; }
+
+.metric-title {
+  font-size: 16px; /* 更大的标题字体 */
+  color: #4a4a4a; /* 深灰色标题 */
+  margin-bottom: 12px;
+}
+
+.metric-value {
+  font-size: 32px; /* 更大的数值字体 */
+  font-weight: 600;
+  color: #212121; /* 深黑色数值 */
+}
+
+/* 表格和分页样式优化 */
+.detail-table {
+  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
+  border-radius: 12px;
+  overflow: hidden;
+}
+
+.el-table th {
+  background: #f0f4f8; /* 更浅的表头背景 */
+  font-weight: 500;
+}
+
+.el-pagination {
+  margin-top: 40px;
+}
+</style>

+ 161 - 0
pm_ui/src/views/publicBroadcasting/index.vue

@@ -0,0 +1,161 @@
+<template>
+  <div class="broadcast-management">
+    <!-- 搜索栏 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryRef" :inline="true" class="filter-form">
+        <el-form-item label="设备ID" prop="deviceId">
+          <el-input
+              v-model="queryParams.deviceId"
+              placeholder="请输入设备ID(如:BRD-001)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item label="所属区域" prop="area">
+          <el-input
+              v-model="queryParams.area"
+              placeholder="请输入区域(如:1号楼1层大厅)"
+              clearable
+              @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="device-table">
+      <el-table v-loading="loading" :data="deviceList" border>
+        <el-table-column label="序号" type="index" align="center" />
+        <el-table-column label="设备ID" align="center" prop="deviceId" />
+        <el-table-column label="设备名称" align="center" prop="deviceName" />
+        <el-table-column label="设备类型" align="center" prop="deviceType" />
+        <el-table-column label="所属区域" align="center" prop="area" />
+        <el-table-column label="运行状态" align="center" prop="status">
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.status)">
+              {{ scope.row.status === 'green' ? '正常' : scope.row.status === 'red' ? '故障' : '警告' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="音量值" align="right" prop="volume">
+          <template #default="scope">
+            <span>{{ scope.row.volume }} dB</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="故障代码" align="center" prop="faultCode">
+          <template #default="scope">
+            <span v-if="scope.row.faultCode" style="color: #ff4d4f">{{ scope.row.faultCode }}</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="最后检测时间" align="center" prop="lastCheckTime" />
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { getBroadcastDeviceList } from "@/api/publicBroadcasting/publicBroadcasting"; // 假设API路径
+
+// 查询参数(两个条件:deviceId、area)
+const queryParams = reactive({
+  deviceId: "", // 设备ID(精确查询)
+  area: "", // 所属区域(支持模糊查询)
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "广播设备管理"
+});
+
+// 表格数据
+const deviceList = ref([]);
+const total = ref(0);
+const loading = ref(false);
+
+// 获取设备列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    const response = await getBroadcastDeviceList(queryParams);
+    deviceList.value = response.data.list || [];
+    total.value = response.data.total || 0;
+  } catch (error) {
+    console.error("获取广播设备数据失败", error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.deviceId = "";
+  queryParams.area = "";
+  handleQuery();
+};
+
+// 状态标签类型映射
+const getStatusType = (status) => {
+  switch (status) {
+    case 'green': return 'success';
+    case 'red': return 'danger';
+    case 'yellow': return 'warning';
+    default: return '';
+  }
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.el-table .cell {
+  white-space: nowrap;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+/* 状态标签样式调整 */
+.el-tag.success {
+  background-color: #52c41a !important;
+  color: white;
+}
+
+.el-tag.danger {
+  background-color: #ff4d4f !important;
+  color: white;
+}
+
+.el-tag.warning {
+  background-color: #faad14 !important;
+  color: white;
+}
+</style>

+ 246 - 0
pm_ui/src/views/publicBroadcasting/index2.vue

@@ -0,0 +1,246 @@
+<template>
+  <div class="broadcast-task-management">
+    <!-- 查询条件 -->
+    <el-card class="filter-section">
+      <el-form :model="queryParams" ref="searchForm" :inline="true" class="search-form">
+        <!-- 控制对象条件 -->
+        <el-form-item label="目标分区" style="width: 220px;">
+          <el-select v-model="queryParams.targetZone" placeholder="请选择目标分区">
+            <el-option label="全部" value="" />
+            <el-option label="全区" value="ZONE-ALL" />
+            <el-option label="分区1" value="ZONE-001" />
+            <el-option label="分区2" value="ZONE-002" />
+            <el-option label="分区3" value="ZONE-003" />
+            <el-option label="分区4" value="ZONE-004" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 广播任务条件 -->
+        <el-form-item label="内容类型" style="width: 220px;">
+          <el-select v-model="queryParams.contentType" placeholder="请选择内容类型">
+            <el-option label="全部" value="" />
+            <el-option label="紧急通知" value="EMG" />
+            <el-option label="寻呼广播" value="PAGE" />
+            <el-option label="普通通知" value="NOTICE" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 执行状态条件 -->
+        <el-form-item label="任务状态" style="width: 220px;">
+          <el-select v-model="queryParams.broadcastStatus" placeholder="请选择任务状态">
+            <el-option label="全部" value="" />
+            <el-option label="进行中" value="进行中" />
+            <el-option label="已完成" value="已完成" />
+            <el-option label="未开始" value="未开始" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
+          <el-button icon="Refresh" @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="data-table">
+      <el-table
+          :data="broadcastList"
+          border
+          v-loading="isLoading"
+      >
+        <el-table-column label="任务ID" prop="taskId" align="center" width="120" />
+        <el-table-column label="目标分区" prop="targetZoneIds" align="center">
+          <template #default="scope">
+            {{ scope.row.targetZoneIds === 'ZONE-ALL' ? '全区' : scope.row.targetZoneIds.split(',').join('、') }}
+          </template>
+        </el-table-column>
+        <el-table-column label="当前音量" prop="currentVolume" align="right" width="100">
+          <template #default="scope">
+            <span>{{ scope.row.currentVolume }} dB</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="设定音量" prop="setVolume" align="right" width="100">
+          <template #default="scope">
+            <span>{{ scope.row.setVolume }} dB</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="开关状态" prop="switchStatus" align="center" width="100">
+          <template #default="scope">
+            <el-tag :type="getTagType(scope.row.switchStatus)">
+              {{ scope.row.switchStatus }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="内容类型" prop="contentCode" align="center">
+          <template #default="scope">
+            {{ getContentName(scope.row.contentCode) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="优先级" prop="priority" align="center" width="80">
+          <template #default="scope">
+            <el-badge :value="scope.row.priority" :type="priorityToType(scope.row.priority)" />
+          </template>
+        </el-table-column>
+        <el-table-column label="任务状态" prop="broadcastStatus" align="center" width="120">
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.broadcastStatus)">
+              {{ scope.row.broadcastStatus }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作人" prop="operator" align="center" width="120" />
+        <el-table-column label="开始时间" prop="startTime" align="center" width="180" />
+      </el-table>
+
+      <!-- 分页器 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { getBroadcastTaskList } from "@/api/publicBroadcasting/publicBroadcasting"; // 假设API路径
+
+// 查询参数
+const queryParams = reactive({
+  targetZone: '', // 目标分区(ZONE-ALL或分区ID)
+  contentType: '', // 内容类型(EMG/PAGE/NOTICE)
+  broadcastStatus: '', // 任务状态
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "广播控制中心"
+});
+
+// 表格数据
+const broadcastList = ref([]);
+const total = ref(0);
+const isLoading = ref(false);
+
+const getList = async () => {
+  isLoading.value = true;
+  try {
+    const mockData = getBroadcastTaskList(queryParams);
+    // 过滤条件处理
+    let filteredData = (await mockData).data.list;
+
+    // 目标分区过滤
+    if (queryParams.targetZone) {
+      filteredData = filteredData.filter(item =>
+          item.targetZoneIds.includes(queryParams.targetZone) ||
+          (queryParams.targetZone === 'ZONE-ALL' && item.targetZoneIds === 'ZONE-ALL')
+      );
+    }
+
+    // 内容类型过滤(前缀匹配)
+    if (queryParams.contentType) {
+      filteredData = filteredData.filter(item =>
+          item.contentCode.startsWith(queryParams.contentType)
+      );
+    }
+
+    // 任务状态过滤
+    if (queryParams.broadcastStatus) {
+      filteredData = filteredData.filter(item =>
+          item.broadcastStatus === queryParams.broadcastStatus
+      );
+    }
+
+    // 分页处理
+    const start = (queryParams.pageNum - 1) * queryParams.pageSize;
+    const end = start + queryParams.pageSize;
+    broadcastList.value = filteredData.slice(start, end);
+    total.value = filteredData.length;
+  } catch (error) {
+    console.error("获取数据失败", error);
+  } finally {
+    isLoading.value = false;
+  }
+};
+
+// 搜索方法
+const handleSearch = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置查询
+const resetSearch = () => {
+  queryParams.targetZone = '';
+  queryParams.contentType = '';
+  queryParams.broadcastStatus = '';
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 状态标签类型映射
+const getTagType = (status) => {
+  return status === '开启' ? 'success' : status === '关闭' ? 'danger' : '';
+};
+
+// 内容类型转名称(完整映射)
+const getContentName = (code) => {
+  return {
+    'EMG-ALARM': '紧急警报',
+    'EMG-FIRE': '消防紧急',
+    'EMG-EVACUATION': '紧急疏散',
+    'PAGE-ANNOUNCE': '寻呼广播',
+    'PAGE-STAFF': '员工寻呼',
+    'PAGE-GUEST': '访客寻呼',
+    'NOTICE-INFO': '普通通知',
+    'NOTICE-MAINTENANCE': '维修通知',
+    'NOTICE-FESTIVAL': '节日通知',
+    'NOTICE-REMINDER': '提醒通知',
+    'NOTICE-UPDATE': '系统更新'
+  }[code] || '未知类型';
+};
+
+// 优先级转标签类型
+const priorityToType = (priority) => {
+  return priority === 1 ? 'danger' : priority === 2 ? 'warning' : 'success';
+};
+
+// 任务状态标签类型
+const getStatusType = (status) => {
+  return {
+    '进行中': 'info',
+    '已完成': 'success',
+    '未开始': 'warning'
+  }[status] || '';
+};
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+/* 样式保持不变 */
+.filter-section {
+  margin-bottom: 20px;
+  padding: 20px;
+}
+
+.data-table {
+  min-height: 400px;
+}
+
+.el-table .cell {
+  white-space: nowrap;
+  padding: 8px 12px;
+}
+
+.el-tag {
+  margin-right: 5px;
+}
+
+.el-badge {
+  margin-left: 5px;
+}
+</style>

+ 315 - 0
pm_ui/src/views/publicBroadcasting/index3.vue

@@ -0,0 +1,315 @@
+<template>
+  <div class="content-management-system">
+    <!-- 查询条件区域 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="queryForm" :inline="true" class="filter-form">
+        <el-form-item label="内容ID">
+          <el-input v-model="queryParams.contentId" placeholder="请输入内容ID" clearable />
+        </el-form-item>
+
+        <el-form-item label="内容类型">
+          <el-select v-model="queryParams.contentType" placeholder="请选择内容类型" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="紧急通知" value="EMERGENCY" />
+            <el-option label="日常通知" value="NORMAL" />
+            <el-option label="背景音乐" value="MUSIC" />
+            <el-option label="寻呼" value="PAGING" />
+            <el-option label="演练" value="DRILL" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="播放分区">
+          <el-select v-model="queryParams.playZone" placeholder="请选择播放分区" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="全区" value="ZONE-ALL" />
+            <el-option label="分区1" value="ZONE-001" />
+            <el-option label="分区2" value="ZONE-002" />
+            <el-option label="分区3" value="ZONE-003" />
+            <el-option label="分区4" value="ZONE-004" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="告警级别">
+          <el-select v-model="queryParams.alarmLevel" placeholder="请选择告警级别" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="无告警" value="NONE" />
+            <el-option label="低" value="LOW" />
+            <el-option label="中" value="MEDIUM" />
+            <el-option label="高" value="HIGH" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格区域 -->
+    <el-card class="data-table">
+      <el-table :data="contentList" border v-loading="loading">
+        <el-table-column label="内容ID" prop="contentId" align="center" width="120" />
+        <el-table-column label="内容类型" prop="contentType" align="center" width="120">
+          <template #default="scope">
+            {{ getContentTypeName(scope.row.contentType) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="音频路径" prop="audioPath" align="left" min-width="200">
+          <template #default="scope">
+<!--            <el-link :href="scope.row.audioPath" type="primary" target="_blank">查看</el-link>-->
+            <span>{{ scope.row.audioPath }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="播放分区" prop="playZones" align="center">
+          <template #default="scope">
+            {{ formatZones(scope.row.playZones) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="播放进度" prop="progress" align="center" width="120">
+          <template #default="scope">
+            <el-progress :percentage="parseInt(scope.row.progress)" :color="getProgressColor(scope.row.progress)" />
+          </template>
+        </el-table-column>
+        <el-table-column label="分区状态" prop="zoneStatusMatrix" align="center" width="150">
+          <template #default="scope">
+            <span>{{ scope.row.zoneStatusMatrix.split('/')[0] }}台设备</span>
+            <span v-if="parseInt(scope.row.zoneStatusMatrix.split('/')[1]) > 0" class="text-danger ml-2">
+              {{ scope.row.zoneStatusMatrix.split('/')[1] }}台故障
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column label="告警级别" prop="alarmLevel" align="center" width="100">
+          <template #default="scope">
+            <el-tag :type="getAlarmLevelType(scope.row.alarmLevel)">{{ getAlarmLevelName(scope.row.alarmLevel) }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="触发时间" prop="triggerTime" align="center" width="180" />
+        <el-table-column label="CPU负载" prop="cpuLoad" align="right" width="100">
+          <template #default="scope">
+            <span>{{ scope.row.cpuLoad }}%</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="网络延迟" prop="networkLatency" align="right" width="100">
+          <template #default="scope">
+            <span>{{ scope.row.networkLatency }}ms</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="存储空间" prop="storageUsage" align="right" width="100">
+          <template #default="scope">
+            <span>{{ scope.row.storageUsage }}%</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页组件 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import {getBroadcastDataGenerator} from "@/api/publicBroadcasting/publicBroadcasting";
+
+// 查询参数
+const queryParams = reactive({
+  contentId: '',
+  contentType: '',
+  playZone: '',
+  alarmLevel: '',
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "广播内容与状态看板"
+});
+
+// 表格数据
+const contentList = ref([]);
+const total = ref(0);
+const loading = ref(false);
+const detailDialogVisible = ref(false);
+const detailContent = ref({});
+
+// 获取数据列表
+const getList = async () => {
+  loading.value = true;
+  try {
+    let response = await getBroadcastDataGenerator(queryParams);
+
+    // 处理返回数据
+    let filteredData = response.data.list || [];
+
+    // 内容ID过滤
+    if (queryParams.contentId) {
+      filteredData = filteredData.filter(item =>
+          (item.contentId || '').includes(queryParams.contentId) // 新增空值处理
+      );
+    }
+
+    // 内容类型过滤
+    if (queryParams.contentType) {
+      filteredData = filteredData.filter(item =>
+          item.contentType === queryParams.contentType
+      );
+    }
+
+    // 播放分区过滤(关键修复点)
+    if (queryParams.playZone) {
+      filteredData = filteredData.filter(item => {
+        // 处理 playZones 可能为 undefined/null/数组的情况
+        const playZones = item.playZones || ''; // 设默认空字符串
+        const targetZone = queryParams.playZone;
+
+        // 如果是数组,转为字符串
+        if (Array.isArray(playZones)) {
+          return playZones.includes(targetZone);
+        } else {
+          return playZones.includes(targetZone);
+        }
+      });
+    }
+
+    // 告警级别过滤
+    if (queryParams.alarmLevel) {
+      filteredData = filteredData.filter(item =>
+          item.alarmLevel === queryParams.alarmLevel
+      );
+    }
+
+    // 处理分页
+    if (response.data && response.data.list) {
+      // 使用后端分页数据
+      contentList.value = response.data.list;
+      total.value = response.data.total || response.data.list.length;
+    } else {
+      // 手动分页(模拟数据)
+      total.value = filteredData.length;
+      const start = (queryParams.pageNum - 1) * queryParams.pageSize;
+      const end = start + queryParams.pageSize;
+      contentList.value = filteredData.slice(start, end);
+    }
+  } catch (error) {
+    console.error('获取内容列表失败', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 搜索方法
+const handleQuery = () => {
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 重置方法
+const resetQuery = () => {
+  queryParams.contentId = '';
+  queryParams.contentType = '';
+  queryParams.playZone = '';
+  queryParams.alarmLevel = '';
+  handleQuery();
+};
+
+// 分页事件处理
+const handlePageChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  queryParams.pageNum = 1; // 重置页码
+  getList();
+};
+
+// 格式化分区显示
+const formatZones = (zones) => {
+  if (!zones) return '-';
+  if (zones === 'ZONE-ALL') return '全区';
+
+  const zoneMap = {
+    'ZONE-001': '分区1',
+    'ZONE-002': '分区2',
+    'ZONE-003': '分区3',
+    'ZONE-004': '分区4'
+  };
+
+  return zones.split(',').map(zone => zoneMap[zone] || zone).join('、');
+};
+
+// 获取内容类型名称
+const getContentTypeName = (type) => {
+  const typeMap = {
+    'EMERGENCY': '紧急通知',
+    'NORMAL': '日常通知',
+    'MUSIC': '背景音乐',
+    'PAGING': '寻呼',
+    'DRILL': '演练'
+  };
+  return typeMap[type] || type;
+};
+
+// 获取告警级别名称
+const getAlarmLevelName = (level) => {
+  const levelMap = {
+    'NONE': '无告警',
+    'LOW': '低',
+    'MEDIUM': '中',
+    'HIGH': '高'
+  };
+  return levelMap[level] || level;
+};
+
+// 获取告警级别标签类型
+const getAlarmLevelType = (level) => {
+  const typeMap = {
+    'NONE': 'success',
+    'LOW': 'info',
+    'MEDIUM': 'warning',
+    'HIGH': 'danger'
+  };
+  return typeMap[level] || '';
+};
+
+// 获取进度条颜色
+const getProgressColor = (progress) => {
+  const value = parseInt(progress);
+  if (value === 100) return '#52c41a'; // 完成
+  if (value === 0) return '#f5222d'; // 未开始
+  return '#1890ff'; // 进行中
+};
+
+// 查看详情
+const showDetail = (row) => {
+  detailContent.value = row;
+  detailDialogVisible.value = true;
+};
+
+
+// 初始化加载
+getList();
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+}
+
+.data-table {
+  min-height: 400px;
+}
+
+.text-danger {
+  color: #f5222d;
+}
+
+.ml-2 {
+  margin-left: 8px;
+}
+</style>

+ 296 - 0
pm_ui/src/views/publicBroadcasting/index4.vue

@@ -0,0 +1,296 @@
+<template>
+  <div class="audit-log-management">
+    <!-- 查询条件区域 -->
+    <el-card class="filter-card">
+      <el-form :model="queryParams" ref="searchForm" :inline="true" class="search-form">
+        <!-- 基础信息条件 -->
+        <el-form-item label="日志ID">
+          <el-input v-model="queryParams.logId" placeholder="请输入日志ID" clearable />
+        </el-form-item>
+
+        <el-form-item label="操作人">
+          <el-input v-model="queryParams.operator" placeholder="请输入操作人" clearable />
+        </el-form-item>
+
+        <!-- 操作详情条件 -->
+        <el-form-item label="操作类型">
+          <el-select v-model="queryParams.operateType" placeholder="请选择操作类型" style="width: 180px;">
+            <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="queryParams.successStatus" placeholder="请选择执行状态" style="width: 180px;">
+            <el-option label="全部" value="" />
+            <el-option label="成功" value="成功" />
+            <el-option label="失败" value="失败" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 时间范围条件 -->
+        <el-form-item label="操作时间">
+          <el-date-picker
+              v-model="queryParams.timeRange"
+              type="daterange"
+              range-separator="至"
+              start-placeholder="开始时间"
+              end-placeholder="结束时间"
+              format="YYYY-MM-DD HH:mm:ss"
+              value-format="YYYY-MM-DD HH:mm:ss"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
+          <el-button icon="Refresh" @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格区域 -->
+    <el-card class="data-table">
+      <el-table
+          :data="auditLogList"
+          border
+          size="small"
+          v-loading="isLoading"
+          row-key="logId"
+          @row-click="handleRowClick"
+      >
+        <el-table-column label="日志ID" prop="logId" align="center" width="180" />
+        <el-table-column label="操作时间" prop="operateTime" align="center" width="220" />
+        <el-table-column label="操作人" prop="operator" align="center" width="120" />
+        <el-table-column label="操作类型" prop="operateType" align="center" width="120">
+          <template #default="scope">
+            <el-tag :type="getOperateTypeColor(scope.row.operateType)">
+              {{ mapOperateType(scope.row.operateType) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="目标对象" prop="targetObject" align="center" min-width="180">
+          <template #default="scope">
+            {{ scope.row.targetObject === 'ZONE-ALL' ? '全区' : scope.row.targetObject.replace(/-/g, "分区") }}
+          </template>
+        </el-table-column>
+        <el-table-column label="变更内容" align="center" min-width="200">
+          <template #default="scope">
+            <div v-if="scope.row.operateType === '配置'">
+              <span>修改前:{{ scope.row.oldValue || "-" }}</span><br>
+              <span>修改后:{{ scope.row.newValue || "-" }}</span>
+            </div>
+            <div v-else>-</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="执行状态" prop="successStatus" align="center" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.successStatus === '成功' ? 'success' : 'danger'">
+              {{ scope.row.successStatus }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="影响范围" prop="affectRange" align="center" min-width="180" />
+        <el-table-column label="耗时" prop="duration" align="right" width="100" />
+        <el-table-column label="IP地址" prop="ipAddress" align="center" width="160" />
+        <el-table-column label="设备指纹" prop="deviceFingerprint" align="center" width="160" />
+      </el-table>
+
+      <!-- 分页组件 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 详情弹窗 -->
+    <el-dialog :visible.sync="detailDialogOpen" title="审计日志详情" width="800px">
+      <el-descriptions :column="3" border>
+        <el-descriptions-item label="日志ID" span="1">{{ detailLog.logId }}</el-descriptions-item>
+        <el-descriptions-item label="操作时间" span="1">{{ detailLog.operateTime }}</el-descriptions-item>
+        <el-descriptions-item label="操作人" span="1">{{ detailLog.operator }}</el-descriptions-item>
+        <el-descriptions-item label="操作类型" span="1">
+          <el-tag :type="getOperateTypeColor(detailLog.operateType)">
+            {{ mapOperateType(detailLog.operateType) }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="目标对象" span="2">
+          {{ detailLog.targetObject === 'ZONE-ALL' ? '全区' : detailLog.targetObject.replace(/-/g, "分区") }}
+        </el-descriptions-item>
+        <el-descriptions-item label="变更内容" span="3" v-if="detailLog.operateType === '配置'">
+          <div>
+            <span>修改前:{{ detailLog.oldValue || "无" }}</span><br>
+            <span>修改后:{{ detailLog.newValue || "无" }}</span>
+          </div>
+        </el-descriptions-item>
+        <el-descriptions-item label="执行状态" span="1">
+          <el-tag :type="detailLog.successStatus === '成功' ? 'success' : 'danger'">
+            {{ detailLog.successStatus }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="影响范围" span="1">{{ detailLog.affectRange }}</el-descriptions-item>
+        <el-descriptions-item label="耗时" span="1">{{ detailLog.duration }}</el-descriptions-item>
+        <el-descriptions-item label="IP地址" span="1">{{ detailLog.ipAddress }}</el-descriptions-item>
+        <el-descriptions-item label="设备指纹" span="1">{{ detailLog.deviceFingerprint }}</el-descriptions-item>
+        <el-descriptions-item label="数字签名" span="2">{{ detailLog.digitalSignature }}</el-descriptions-item>
+      </el-descriptions>
+      <template #footer>
+        <el-button @click="detailDialogOpen = false">关闭</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue';
+import { ElMessage } from 'element-plus';
+import {getBroadcastLogList} from "@/api/publicBroadcasting/publicBroadcasting"; // 假设API路径
+
+// 查询参数
+const queryParams = reactive({
+  logId: '',
+  operator: '',
+  operateType: '',
+  successStatus: '',
+  timeRange: null,
+  pageNum: 1,
+  pageSize: 10,
+  interfaceName: "操作日志与审计"
+});
+
+// 表格数据
+const auditLogList = ref([]);
+const total = ref(0);
+const isLoading = ref(false);
+const detailDialogOpen = ref(false);
+const detailLog = ref({});
+
+// 获取数据
+const getList = async () => {
+  isLoading.value = true;
+  try {
+    const mockData = getBroadcastLogList(queryParams);
+    // 过滤条件处理
+    let filteredData =  (await mockData).data.list;
+
+    // 日志ID过滤
+    if (queryParams.logId) {
+      filteredData = filteredData.filter(item => item.logId.includes(queryParams.logId));
+    }
+
+    // 操作人过滤
+    if (queryParams.operator) {
+      filteredData = filteredData.filter(item => item.operator.includes(queryParams.operator));
+    }
+
+    // 操作类型过滤
+    if (queryParams.operateType) {
+      filteredData = filteredData.filter(item => item.operateType === queryParams.operateType);
+    }
+
+    // 执行状态过滤
+    if (queryParams.successStatus) {
+      filteredData = filteredData.filter(item => item.successStatus === queryParams.successStatus);
+    }
+
+    // 时间范围过滤
+    if (queryParams.timeRange && queryParams.timeRange.length === 2) {
+      const [startTime, endTime] = queryParams.timeRange;
+      filteredData = filteredData.filter(item => {
+        const logTime = new Date(item.operateTime);
+        return logTime >= new Date(startTime) && logTime <= new Date(endTime);
+      });
+    }
+
+    // 分页处理
+    total.value = (await mockData).data.total;
+    const start = (queryParams.pageNum - 1) * queryParams.pageSize;
+    const end = start + queryParams.pageSize;
+    auditLogList.value = filteredData.slice(start, end);
+  } catch (error) {
+    ElMessage.error('获取日志数据失败');
+    console.error(error);
+  } finally {
+    isLoading.value = false;
+  }
+};
+
+// 搜索
+const handleSearch = () => {
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 重置
+const resetSearch = () => {
+  queryParams.logId = '';
+  queryParams.operator = '';
+  queryParams.operateType = '';
+  queryParams.successStatus = '';
+  queryParams.timeRange = null;
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 分页
+const handlePageChange = (newPage) => {
+  queryParams.pageNum = newPage;
+  getList();
+};
+
+const handleSizeChange = (newSize) => {
+  queryParams.pageSize = newSize;
+  queryParams.pageNum = 1;
+  getList();
+};
+
+// 行点击事件(打开详情弹窗)
+const handleRowClick = (row) => {
+  detailLog.value = { ...row };
+  detailDialogOpen.value = true;
+};
+
+// 操作类型映射
+const mapOperateType = (type) => {
+  return {
+    '控制': '控制操作',
+    '广播': '广播操作',
+    '配置': '配置变更',
+  }[type] || type;
+};
+
+// 操作类型颜色
+const getOperateTypeColor = (type) => {
+  return {
+    '控制': 'primary',
+    '广播': 'warning',
+    '配置': 'success',
+  }[type] || 'info';
+};
+
+getList()
+</script>
+
+<style scoped>
+.filter-card {
+  margin-bottom: 20px;
+  padding: 20px;
+}
+
+.data-table {
+  min-height: 500px;
+}
+
+.el-descriptions {
+  margin-bottom: 20px;
+}
+
+.el-tag {
+  margin-right: 5px;
+}
+</style>

+ 33 - 11
pm_ui/src/views/repairOrder/repairOrder/index.vue

@@ -83,15 +83,15 @@
       <el-table-column label="项目名称" align="center" prop="projectName" />
       <el-table-column label="派单时间" align="center" prop="assignTime" width="180" sortable>
         <template #default="scope">
-          <span>{{ parseTime(scope.row.assignTime, '{y}-{m}-{d}') }}</span>
+          <span>{{ parseTime(scope.row.assignTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
       <el-table-column label="完成时间" align="center" prop="finishTime" width="180">
         <template #default="scope">
-          <span>{{ parseTime(scope.row.finishTime, '{y}-{m}-{d}') }}</span>
+          <span>{{ parseTime(scope.row.finishTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="完成人" align="center" prop="finishBy" />
+      <el-table-column label="责任人" align="center" prop="finishBy" />
       <el-table-column label="附件" align="center" prop="annex" />
 <!--      <el-table-column label="完成人id" align="center" prop="userId" />-->
       <el-table-column label="工单状态" align="center" prop="orderStatus">
@@ -105,7 +105,7 @@
 <!--          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['repairOrder:repairOrder:edit']">详情</el-button>-->
           <el-button link type="primary" icon="View" @click="showDetail(scope.row)" v-hasPermi="['repairOrder:repairOrder:edit']">详情</el-button>
           <el-button
-              v-if="scope.row.orderStatus === '0'"
+              v-if="scope.row.orderStatus === '0' || scope.row.orderStatus === '1'"
               link
               type="primary"
               icon="Share"
@@ -134,27 +134,29 @@
         <el-descriptions-item label="工单编号">{{ detailData.orderNo }}</el-descriptions-item>
         <el-descriptions-item label="工单内容">{{ detailData.orderContent }}</el-descriptions-item>
         <el-descriptions-item label="项目名称">{{ detailData.projectName }}</el-descriptions-item>
-        <el-descriptions-item label="派单时间">{{ parseTime(detailData.assignTime) }}</el-descriptions-item>
-        <el-descriptions-item label="完成时间">{{ parseTime(detailData.finishTime) }}</el-descriptions-item>
-        <el-descriptions-item label="完成人">{{ detailData.finishBy }}</el-descriptions-item>
+        <el-descriptions-item label="派单时间">{{ parseTime(detailData.assignTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
+        <el-descriptions-item label="完成时间">{{ parseTime(detailData.finishTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
+        <el-descriptions-item label="责任人">{{ detailData.finishBy }}</el-descriptions-item>
         <el-descriptions-item label="工单状态">
           <dict-tag :options="repair_status" :value="detailData.orderStatus"/>
         </el-descriptions-item>
         <el-descriptions-item label="工单备注">{{ detailData.orderRemark }}</el-descriptions-item>
+        <el-descriptions-item label="附件">{{ detailData.annex }}</el-descriptions-item>
       </el-descriptions>
+      <el-button type="primary" @click="downloadFile(detailData.annex)">下载附件</el-button>
     </el-drawer>
 
     <!-- 添加或修改维修工单对话框 -->
     <el-dialog :title="title" v-model="open" width="600px" append-to-body>
       <el-form ref="repairOrderRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="工单编号" prop="orderNo">
-          <el-input v-model="form.orderNo" placeholder="请输入工单编号" disabled="disabled"/>
+          <el-input v-model="form.orderNo" placeholder="请输入工单编号" :disabled="isEdit"/>
         </el-form-item>
         <el-form-item label="工单内容" prop="orderContent">
-          <el-input v-model="form.orderContent" type="textarea" placeholder="请输入内容" disabled="disabled"/>
+          <el-input v-model="form.orderContent" type="textarea" placeholder="请输入内容" :disabled="isEdit"/>
         </el-form-item>
         <el-form-item label="项目名称" prop="projectName"  >
-          <el-input v-model="form.projectName" placeholder="请输入项目名称" disabled="disabled"/>
+          <el-input v-model="form.projectName" placeholder="请输入项目名称" :disabled="isEdit"/>
         </el-form-item>
 <!--        <el-form-item label="派单时间" prop="assignTime">-->
 <!--          <el-date-picker clearable-->
@@ -237,6 +239,8 @@ const userOptions = ref([]);
 
 const detailVisible = ref(false);
 const detailData = ref({});
+const isEdit = ref(false);
+const selectedRows = ref([]);   //  选中的行
 
 const data = reactive({
   form: {},
@@ -259,6 +263,10 @@ function showDetail(row) {
   detailVisible.value = true;
 }
 
+function downloadFile(url) {
+  window.open(import.meta.env.VITE_APP_BASE_API+url);
+}
+
 /** 查询维修工单列表 */
 function getList() {
   loading.value = true;
@@ -324,11 +332,13 @@ function handleSelectionChange(selection) {
   ids.value = selection.map(item => item.id);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
+  selectedRows.value = selection; // 保存选中的行数据
 }
 
 /** 新增按钮操作 */
 function handleAdd() {
   reset();
+  isEdit.value  = false;
   open.value = true;
   title.value = "添加维修工单";
 }
@@ -336,7 +346,6 @@ function handleAdd() {
 function getUserList() {
   listUser().then(response => {
     userOptions.value = response.rows || [];
-    console.log("userOptions.value"+userOptions.value)
   });
 }
 
@@ -347,6 +356,19 @@ onMounted(() => {
 /** 修改按钮操作 */
 function handleUpdate(row) {
   reset();
+  console.log("dfdsd")
+  if (row.orderStatus==undefined){
+    if (selectedRows.value[0].orderStatus != '0' || selectedRows.value[0].orderStatus != '1') {
+      proxy.$modal.msgWarning("该工单已完成,无法修改");
+      return;
+    }
+  }else {
+    if (row.orderStatus != '0' && row.orderStatus != '1') {
+      proxy.$modal.msgWarning("该工单已完成,无法修改");
+      return;
+    }
+  }
+  isEdit.value  = true;
   const _id = row.id || ids.value
   getRepairOrder(_id).then(response => {
     form.value = response.data;

+ 36 - 26
pm_ui/src/views/repairOrder/repairOrder/index2.vue

@@ -9,7 +9,7 @@
             @keyup.enter="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="项目名称321" prop="projectName">
+      <el-form-item label="项目名称" prop="projectName">
         <el-input
             v-model="queryParams.projectName"
             placeholder="请输入项目名称"
@@ -33,7 +33,7 @@
       </el-form-item>
     </el-form>
 
-    <el-row :gutter="10" class="mb8">
+<!--    <el-row :gutter="10" class="mb8">
       <el-col :span="1.5">
         <el-button
             type="primary"
@@ -73,7 +73,7 @@
         >导出</el-button>
       </el-col>
       <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
+    </el-row>-->
 
     <el-table v-loading="loading" :data="repairOrderList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
@@ -83,22 +83,22 @@
       <el-table-column label="项目名称" align="center" prop="projectName" />
       <el-table-column label="派单时间" align="center" prop="assignTime" width="180" sortable>
         <template #default="scope">
-          <span>{{ parseTime(scope.row.assignTime, '{y}-{m}-{d}') }}</span>
+          <span>{{ parseTime(scope.row.assignTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="完成时间" align="center" prop="finishTime" width="180">
+      <el-table-column label="责任人" align="center" prop="finishBy" />
+      <el-table-column label="工单状态" align="center" prop="orderStatus">
         <template #default="scope">
-          <span>{{ parseTime(scope.row.finishTime, '{y}-{m}-{d}') }}</span>
+          <dict-tag :options="repair_status" :value="scope.row.orderStatus"/>
         </template>
       </el-table-column>
-      <el-table-column label="完成人" align="center" prop="finishBy" />
-      <el-table-column label="附件" align="center" prop="annex" />
-<!--      <el-table-column label="完成人id" align="center" prop="userId" />-->
-      <el-table-column label="工单状态" align="center" prop="orderStatus">
+      <el-table-column label="完成时间" align="center" prop="finishTime" width="180">
         <template #default="scope">
-          <dict-tag :options="repair_status" :value="scope.row.orderStatus"/>
+          <span>{{ parseTime(scope.row.finishTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
+      <el-table-column label="附件" align="center" prop="annex" />
+      <!--      <el-table-column label="完成人id" align="center" prop="userId" />-->
       <el-table-column label="工单备注" align="center" prop="orderRemark" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200px">
         <template #default="scope">
@@ -112,7 +112,7 @@
               @click="handleUpdate(scope.row)"
               v-hasPermi="['repairOrder:repairOrder:edit']"
           >处理</el-button>
-          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['repairOrder:repairOrder:remove']">删除</el-button>
+<!--          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['repairOrder:repairOrder:remove']">删除</el-button>-->
         </template>
       </el-table-column>
     </el-table>
@@ -134,50 +134,54 @@
         <el-descriptions-item label="工单编号">{{ detailData.orderNo }}</el-descriptions-item>
         <el-descriptions-item label="工单内容">{{ detailData.orderContent }}</el-descriptions-item>
         <el-descriptions-item label="项目名称">{{ detailData.projectName }}</el-descriptions-item>
-        <el-descriptions-item label="派单时间">{{ parseTime(detailData.assignTime) }}</el-descriptions-item>
-        <el-descriptions-item label="完成时间">{{ parseTime(detailData.finishTime) }}</el-descriptions-item>
-        <el-descriptions-item label="完成人">{{ detailData.finishBy }}</el-descriptions-item>
+        <el-descriptions-item label="派单时间">{{ parseTime(detailData.assignTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
+        <el-descriptions-item label="完成时间">{{ parseTime(detailData.finishTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
+        <el-descriptions-item label="责任人">{{ detailData.finishBy }}</el-descriptions-item>
         <el-descriptions-item label="工单状态">
           <dict-tag :options="repair_status" :value="detailData.orderStatus"/>
         </el-descriptions-item>
         <el-descriptions-item label="工单备注">{{ detailData.orderRemark }}</el-descriptions-item>
+        <el-descriptions-item label="附件">{{ detailData.annex }}</el-descriptions-item>
+
       </el-descriptions>
+      <el-button type="primary" @click="downloadFile(detailData.annex)">下载附件</el-button>
     </el-drawer>
 
     <!-- 添加或修改维修工单对话框 -->
     <el-dialog :title="title" v-model="open" width="600px" append-to-body>
       <el-form ref="repairOrderRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="工单编号" prop="orderNo">
-          <el-input v-model="form.orderNo" placeholder="请输入工单编号" />
+          <el-input v-model="form.orderNo" placeholder="请输入工单编号" disabled/>
         </el-form-item>
         <el-form-item label="工单内容" prop="orderContent">
-          <el-input v-model="form.orderContent" type="textarea" placeholder="请输入内容" />
+          <el-input v-model="form.orderContent" type="textarea" placeholder="请输入内容" disabled/>
         </el-form-item>
         <el-form-item label="项目名称" prop="projectName">
-          <el-input v-model="form.projectName" placeholder="请输入项目名称" />
+          <el-input v-model="form.projectName" placeholder="请输入项目名称" disabled/>
         </el-form-item>
-        <el-form-item label="派单时间" prop="assignTime">
+        <el-form-item label="派单时间" prop="assignTime" >
           <el-date-picker clearable
                           v-model="form.assignTime"
                           type="date"
                           value-format="YYYY-MM-DD"
-                          placeholder="请选择派单时间">
+                          placeholder="请选择派单时间" disabled>
           </el-date-picker>
         </el-form-item>
-        <el-form-item label="完成时间" prop="finishTime">
+        <el-form-item label="完成时间" prop="finishTime" :rules="rules.finishTime">
           <el-date-picker clearable
                           v-model="form.finishTime"
-                          type="date"
-                          value-format="YYYY-MM-DD"
+                          type="datetime"
+                          value-format="YYYY-MM-DD HH:mm:ss"
                           placeholder="请选择完成时间">
           </el-date-picker>
         </el-form-item>
-        <el-form-item label="责任人" prop="finishBy">
+        <el-form-item label="责任人" prop="finishBy" >
           <el-select
               v-model="form.userId"
               placeholder="请选择责任人"
               clearable
               filterable
+              disabled
           >
             <el-option
                 v-for="user in userOptions"
@@ -241,6 +245,7 @@ const detailData = ref({});
 const data = reactive({
   form: {},
   queryParams: {
+    isMe: true,
     pageNum: 1,
     pageSize: 10,
     orderNo: null,
@@ -250,6 +255,9 @@ const data = reactive({
     state:Date.now(),
   },
   rules: {
+    finishTime: [
+      { required: true, message: "完成时间不能为空", trigger: "blur" }
+    ]
   }
 });
 
@@ -260,6 +268,10 @@ function showDetail(row) {
   detailVisible.value = true;
 }
 
+function downloadFile(url) {
+  window.open(import.meta.env.VITE_APP_BASE_API+url);
+}
+
 /** 查询维修工单列表 */
 function getList() {
   loading.value = true;
@@ -337,7 +349,6 @@ function handleAdd() {
 function getUserList() {
   listUser().then(response => {
     userOptions.value = response.rows || [];
-    console.log("userOptions.value"+userOptions.value)
   });
 }
 
@@ -386,7 +397,6 @@ function submitForm() {
 }
 
 /** 删除按钮操作 */
-/** 删除按钮操作 */
 function handleDelete(row) {
   const _ids = row.id || ids.value;
   const deletePromises = [];