Bläddra i källkod

新增2-4系统接口优化

wangshuangpan 1 månad sedan
förälder
incheckning
3751caf484

+ 180 - 0
pm-admin/src/main/java/com/pm/web/controller/device/IbmsDeviceAlarmsController.java

@@ -0,0 +1,180 @@
+package com.pm.web.controller.device;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.pm.common.annotation.Log;
+import com.pm.common.core.controller.BaseController;
+import com.pm.common.core.domain.AjaxResult;
+import com.pm.common.enums.BusinessType;
+import com.pm.common.config.PageData;
+import com.pm.common.utils.poi.ExcelUtilPageData;
+import com.pm.device.service.IIbmsDeviceAlarmsService;
+import com.pm.common.core.page.TableDataInfo;
+
+/**
+ * 设备告警Controller
+ *
+ * @author system
+ * @date 2025-01-06
+ */
+@RestController
+@RequestMapping("/device/alarm")
+public class IbmsDeviceAlarmsController extends BaseController
+{
+    @Autowired
+    private IIbmsDeviceAlarmsService ibmsDeviceAlarmService;
+
+    /**
+     * 查询设备告警列表
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:list')")
+    @GetMapping("/list")
+    public TableDataInfo list()
+    {
+        PageData pd = this.getPageData();
+        startPage();
+        List<PageData> list = ibmsDeviceAlarmService.selectIbmsDeviceAlarmList(pd);
+
+        // 获取统计信息
+        PageData stats = ibmsDeviceAlarmService.selectAlarmStatistics(pd);
+
+        TableDataInfo dataTable = getDataTable(list);
+        // 将统计信息添加到返回结果中
+        if (stats != null) {
+            Map<String, Object> extData = new HashMap<>();
+            extData.put("stats", stats);
+            dataTable.setExtData(extData);
+        }
+
+        return dataTable;
+    }
+
+    /**
+     * 导出设备告警列表
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:export')")
+    @Log(title = "设备告警", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response)
+    {
+        try {
+            PageData pd = this.getPageData();
+            List<PageData> list = ibmsDeviceAlarmService.selectIbmsDeviceAlarmList(pd);
+            String filename = "设备告警记录";
+            String[] titles = {
+                    "告警编码,alarmCode",
+                    "设备编码,deviceCode",
+                    "设备名称,deviceName",
+                    "设备类型,deviceType",
+                    "子系统类型,subsystemType",
+                    "告警级别,alarmLevel",
+                    "告警类型,alarmType",
+                    "告警描述,alarmDesc",
+                    "楼栋,buildingName",
+                    "楼层,floorName",
+                    "房间,roomName",
+                    "空间位置,spaceLocation",
+                    "告警时间,alarmTime",
+                    "复位状态,isReset",
+                    "复位时间,resetTime",
+                    "复位人,resetBy",
+                    "服务单号,serviceOrderNo",
+                    "处理状态,handleStatus"
+            };
+            ExcelUtilPageData.exportXLSX(response, null, null, filename, titles, list);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 获取设备告警详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(ibmsDeviceAlarmService.selectIbmsDeviceAlarmById(id));
+    }
+
+    /**
+     * 获取告警详情(包含处理记录)
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:query')")
+    @GetMapping(value = "/detail/{id}")
+    public AjaxResult getDetail(@PathVariable("id") Long id)
+    {
+        return success(ibmsDeviceAlarmService.getAlarmDetail(id));
+    }
+
+    /**
+     * 新增设备告警
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:add')")
+    @Log(title = "设备告警", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody PageData pd)
+    {
+        return toAjax(ibmsDeviceAlarmService.insertIbmsDeviceAlarm(pd));
+    }
+
+    /**
+     * 修改设备告警
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:edit')")
+    @Log(title = "设备告警", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody PageData pd)
+    {
+        return toAjax(ibmsDeviceAlarmService.updateIbmsDeviceAlarm(pd));
+    }
+
+    /**
+     * 复位告警
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:reset')")
+    @Log(title = "设备告警复位", businessType = BusinessType.UPDATE)
+    @PostMapping("/reset")
+    public AjaxResult reset(@RequestBody PageData pd)
+    {
+        return toAjax(ibmsDeviceAlarmService.resetAlarm(pd));
+    }
+
+    /**
+     * 创建服务单
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:createOrder')")
+    @Log(title = "创建服务单", businessType = BusinessType.OTHER)
+    @PostMapping("/createOrder")
+    public AjaxResult createServiceOrder(@RequestBody PageData pd)
+    {
+        Map<String, Object> result = ibmsDeviceAlarmService.createServiceOrder(pd);
+        if ((boolean) result.get("success")) {
+            return AjaxResult.success(result);
+        } else {
+            return AjaxResult.error((String) result.get("msg"));
+        }
+    }
+
+    /**
+     * 删除设备告警
+     */
+    @PreAuthorize("@ss.hasPermi('device:alarm:remove')")
+    @Log(title = "设备告警", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(ibmsDeviceAlarmService.deleteIbmsDeviceAlarmByIds(ids));
+    }
+}

+ 10 - 1
pm-common/src/main/java/com/pm/common/core/page/TableDataInfo.java

@@ -2,6 +2,7 @@ package com.pm.common.core.page;
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 表格分页数据对象
@@ -17,7 +18,7 @@ public class TableDataInfo implements Serializable
 
     /** 列表数据 */
     private List<?> rows;
-
+    Map<String, Object> extData; // /** 列表对象 */
     /** 消息状态码 */
     private int code;
 
@@ -43,6 +44,14 @@ public class TableDataInfo implements Serializable
         this.total = total;
     }
 
+    public Map<String, Object> getExtData() {
+        return extData;
+    }
+
+    public void setExtData(Map<String, Object> extData) {
+        this.extData = extData;
+    }
+
     public long getTotal()
     {
         return total;

+ 85 - 0
pm-system/src/main/java/com/pm/device/mapper/IbmsDeviceAlarmsMapper.java

@@ -0,0 +1,85 @@
+package com.pm.device.mapper;
+
+import java.util.List;
+import com.pm.common.config.PageData;
+
+/**
+ * 设备告警Mapper接口
+ *
+ * @author system
+ * @date 2025-01-06
+ */
+public interface IbmsDeviceAlarmsMapper
+{
+    /**
+     * 查询设备告警
+     *
+     * @param id 设备告警主键
+     * @return 设备告警
+     */
+    public PageData selectIbmsDeviceAlarmById(Long id);
+
+    /**
+     * 查询设备告警列表
+     *
+     * @param pd
+     * @return 设备告警集合
+     */
+    public List<PageData> selectIbmsDeviceAlarmList(PageData pd);
+
+    /**
+     * 查询告警统计信息
+     *
+     * @param pd
+     * @return 统计信息
+     */
+    public PageData selectAlarmStatistics(PageData pd);
+
+    /**
+     * 新增设备告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    public int insertIbmsDeviceAlarm(PageData pd);
+
+    /**
+     * 修改设备告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    public int updateIbmsDeviceAlarm(PageData pd);
+
+    /**
+     * 复位告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    public int resetAlarm(PageData pd);
+
+    /**
+     * 更新服务单号
+     *
+     * @param pd
+     * @return 结果
+     */
+    public int updateServiceOrderNo(PageData pd);
+
+    /**
+     * 删除设备告警
+     *
+     * @param id 设备告警主键
+     * @return 结果
+     */
+    public int deleteIbmsDeviceAlarmById(Long id);
+
+    /**
+     * 批量删除设备告警
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteIbmsDeviceAlarmByIds(Long[] ids);
+}

+ 94 - 0
pm-system/src/main/java/com/pm/device/service/IIbmsDeviceAlarmsService.java

@@ -0,0 +1,94 @@
+package com.pm.device.service;
+
+import java.util.List;
+import java.util.Map;
+import com.pm.common.config.PageData;
+
+/**
+ * 设备告警Service接口
+ *
+ * @author system
+ * @date 2025-01-06
+ */
+public interface IIbmsDeviceAlarmsService
+{
+    /**
+     * 查询设备告警
+     *
+     * @param id 设备告警主键
+     * @return 设备告警
+     */
+    public PageData selectIbmsDeviceAlarmById(Long id);
+
+    /**
+     * 查询设备告警列表
+     *
+     * @param pd
+     * @return 设备告警集合
+     */
+    public List<PageData> selectIbmsDeviceAlarmList(PageData pd);
+
+    /**
+     * 查询告警统计信息
+     *
+     * @param pd
+     * @return 统计信息
+     */
+    public PageData selectAlarmStatistics(PageData pd);
+
+    /**
+     * 新增设备告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    public int insertIbmsDeviceAlarm(PageData pd);
+
+    /**
+     * 修改设备告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    public int updateIbmsDeviceAlarm(PageData pd);
+
+    /**
+     * 复位告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    public int resetAlarm(PageData pd);
+
+    /**
+     * 创建服务单
+     *
+     * @param pd
+     * @return 结果
+     */
+    public Map<String, Object> createServiceOrder(PageData pd);
+
+    /**
+     * 获取告警详情(包含处理记录)
+     *
+     * @param id
+     * @return 告警详情
+     */
+    public Map<String, Object> getAlarmDetail(Long id);
+
+    /**
+     * 批量删除设备告警
+     *
+     * @param ids 需要删除的设备告警主键集合
+     * @return 结果
+     */
+    public int deleteIbmsDeviceAlarmByIds(Long[] ids);
+
+    /**
+     * 删除设备告警信息
+     *
+     * @param id 设备告警主键
+     * @return 结果
+     */
+    public int deleteIbmsDeviceAlarmById(Long id);
+}

+ 246 - 0
pm-system/src/main/java/com/pm/device/service/impl/IbmsDeviceAlarmsServiceImpl.java

@@ -0,0 +1,246 @@
+package com.pm.device.service.impl;
+
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.ArrayList;
+import com.pm.common.utils.DateUtils;
+import com.pm.common.utils.SecurityUtils;
+import com.pm.common.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.pm.device.mapper.IbmsDeviceAlarmsMapper;
+import com.pm.device.service.IIbmsDeviceAlarmsService;
+import com.pm.common.config.PageData;
+
+/**
+ * 设备告警Service业务层处理
+ *
+ * @author system
+ * @date 2025-01-06
+ */
+@Service
+public class IbmsDeviceAlarmsServiceImpl implements IIbmsDeviceAlarmsService
+{
+    @Autowired
+    private IbmsDeviceAlarmsMapper ibmsDeviceAlarmMapper;
+
+    /**
+     * 查询设备告警
+     *
+     * @param id 设备告警主键
+     * @return 设备告警
+     */
+    @Override
+    public PageData selectIbmsDeviceAlarmById(Long id)
+    {
+        return ibmsDeviceAlarmMapper.selectIbmsDeviceAlarmById(id);
+    }
+
+    /**
+     * 查询设备告警列表
+     *
+     * @param pd
+     * @return 设备告警
+     */
+    @Override
+    public List<PageData> selectIbmsDeviceAlarmList(PageData pd)
+    {
+        return ibmsDeviceAlarmMapper.selectIbmsDeviceAlarmList(pd);
+    }
+
+    /**
+     * 查询告警统计信息
+     *
+     * @param pd
+     * @return 统计信息
+     */
+    @Override
+    public PageData selectAlarmStatistics(PageData pd)
+    {
+        return ibmsDeviceAlarmMapper.selectAlarmStatistics(pd);
+    }
+
+    /**
+     * 新增设备告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    @Override
+    public int insertIbmsDeviceAlarm(PageData pd)
+    {
+        // 生成告警编码
+        if (StringUtils.isEmpty(pd.getString("alarmCode"))) {
+            pd.put("alarmCode", generateAlarmCode());
+        }
+        pd.put("createTime", DateUtils.getTime());
+        pd.put("updateTime", DateUtils.getTime());
+        return ibmsDeviceAlarmMapper.insertIbmsDeviceAlarm(pd);
+    }
+
+    /**
+     * 修改设备告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    @Override
+    public int updateIbmsDeviceAlarm(PageData pd)
+    {
+        pd.put("updateTime", DateUtils.getTime());
+        return ibmsDeviceAlarmMapper.updateIbmsDeviceAlarm(pd);
+    }
+
+    /**
+     * 复位告警
+     *
+     * @param pd
+     * @return 结果
+     */
+    @Override
+    public int resetAlarm(PageData pd)
+    {
+        pd.put("resetTime", DateUtils.getTime());
+        pd.put("resetBy", SecurityUtils.getUsername());
+        pd.put("updateTime", DateUtils.getTime());
+        Integer id=(Integer)  pd.get("id");
+        // 记录操作日志
+        recordAlarmLog(id, "手动复位告警", SecurityUtils.getUsername());
+        
+        return ibmsDeviceAlarmMapper.resetAlarm(pd);
+    }
+
+    /**
+     * 创建服务单
+     *
+     * @param pd
+     * @return 结果
+     */
+    @Override
+    public Map<String, Object> createServiceOrder(PageData pd)
+    {
+        Map<String, Object> result = new HashMap<>();
+        
+        try {
+            // 生成服务单号
+            String serviceOrderNo = generateServiceOrderNo();
+            Integer alarmId=(Integer) pd.get("alarmId");
+            // 更新告警记录的服务单号
+            PageData updatePd = new PageData();
+            updatePd.put("id", pd.get("alarmId"));
+            updatePd.put("serviceOrderNo", serviceOrderNo);
+            updatePd.put("updateTime", DateUtils.getTime());
+            ibmsDeviceAlarmMapper.updateServiceOrderNo(updatePd);
+            
+            // 记录操作日志
+            recordAlarmLog(alarmId,
+                "创建服务单,单号:" + serviceOrderNo + ",服务类型:" + pd.getString("serviceType"), 
+                SecurityUtils.getUsername());
+            
+            // TODO: 这里应该调用服务单系统的接口创建实际的服务单
+            // 模拟调用外部接口
+            result.put("success", true);
+            result.put("serviceOrderNo", serviceOrderNo);
+            result.put("msg", "服务单创建成功");
+            
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("msg", "服务单创建失败:" + e.getMessage());
+        }
+        
+        return result;
+    }
+
+    /**
+     * 获取告警详情(包含处理记录)
+     *
+     * @param id
+     * @return 告警详情
+     */
+    @Override
+    public Map<String, Object> getAlarmDetail(Long id)
+    {
+        Map<String, Object> result = new HashMap<>();
+        
+        // 获取告警基本信息
+        PageData alarm = ibmsDeviceAlarmMapper.selectIbmsDeviceAlarmById(id);
+        result.put("data", alarm);
+        
+        // 获取处理记录(模拟数据)
+        List<Map<String, Object>> logs = getAlarmLogs(id);
+        result.put("logs", logs);
+        
+        return result;
+    }
+
+    /**
+     * 批量删除设备告警
+     *
+     * @param ids 需要删除的设备告警主键
+     * @return 结果
+     */
+    @Override
+    public int deleteIbmsDeviceAlarmByIds(Long[] ids)
+    {
+        return ibmsDeviceAlarmMapper.deleteIbmsDeviceAlarmByIds(ids);
+    }
+
+    /**
+     * 删除设备告警信息
+     *
+     * @param id 设备告警主键
+     * @return 结果
+     */
+    @Override
+    public int deleteIbmsDeviceAlarmById(Long id)
+    {
+        return ibmsDeviceAlarmMapper.deleteIbmsDeviceAlarmById(id);
+    }
+
+    /**
+     * 生成告警编码
+     */
+    private String generateAlarmCode() {
+        String dateStr = DateUtils.dateTimeNow("yyyyMMdd");
+        // TODO: 实际应该从数据库获取当天的序号
+        String seq = String.format("%04d", (int)(Math.random() * 10000));
+        return "ALM" + dateStr + seq;
+    }
+
+    /**
+     * 生成服务单号
+     */
+    private String generateServiceOrderNo() {
+        String dateStr = DateUtils.dateTimeNow("yyyyMMdd");
+        // TODO: 实际应该从数据库获取当天的序号
+        String seq = String.format("%04d", (int)(Math.random() * 10000));
+        return "SVC" + dateStr + seq;
+    }
+
+    /**
+     * 记录告警操作日志
+     */
+    private void recordAlarmLog(Integer alarmId, String content, String operator) {
+        // TODO: 实际应该插入到告警日志表中
+        // 这里仅作为示例,实际项目中应该有专门的日志表
+    }
+
+    /**
+     * 获取告警处理记录(模拟数据)
+     */
+    private List<Map<String, Object>> getAlarmLogs(Long alarmId) {
+        List<Map<String, Object>> logs = new ArrayList<>();
+        
+        // 模拟一些处理记录
+        Map<String, Object> log1 = new HashMap<>();
+        log1.put("id", 1);
+        log1.put("alarmId", alarmId);
+        log1.put("content", "系统自动生成告警");
+        log1.put("operator", "系统");
+        log1.put("createTime", "2025-01-06 08:30:00");
+        logs.add(log1);
+        
+        return logs;
+    }
+}

+ 203 - 0
pm-system/src/main/resources/mapper/device/IbmsDeviceAlarmsMapper.xml

@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pm.device.mapper.IbmsDeviceAlarmsMapper">
+
+    <resultMap type="pd" id="IbmsDeviceAlarmResult">
+        <result property="id"    column="id"    />
+        <result property="alarmCode"    column="alarm_code"    />
+        <result property="deviceCode"    column="device_code"    />
+        <result property="deviceName"    column="device_name"    />
+        <result property="deviceType"    column="device_type"    />
+        <result property="subsystemType"    column="subsystem_type"    />
+        <result property="alarmLevel"    column="alarm_level"    />
+        <result property="alarmType"    column="alarm_type"    />
+        <result property="alarmDesc"    column="alarm_desc"    />
+        <result property="buildingName"    column="building_name"    />
+        <result property="floorName"    column="floor_name"    />
+        <result property="roomName"    column="room_name"    />
+        <result property="spaceLocation"    column="space_location"    />
+        <result property="alarmTime"    column="alarm_time"    />
+        <result property="isReset"    column="is_reset"    />
+        <result property="resetTime"    column="reset_time"    />
+        <result property="resetBy"    column="reset_by"    />
+        <result property="serviceOrderNo"    column="service_order_no"    />
+        <result property="handleStatus"    column="handle_status"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectIbmsDeviceAlarmVo">
+        select id, alarm_code, device_code, device_name, device_type, subsystem_type,
+               alarm_level, alarm_type, alarm_desc, building_name, floor_name, room_name,
+               space_location, alarm_time, is_reset, reset_time, reset_by,
+               service_order_no, handle_status, create_time, update_time
+        from ibms_device_alarms
+    </sql>
+
+    <select id="selectIbmsDeviceAlarmList" parameterType="pd" resultMap="IbmsDeviceAlarmResult">
+        <include refid="selectIbmsDeviceAlarmVo"/>
+        <where>
+            <if test="alarmCode != null and alarmCode != ''">
+                and alarm_code like concat('%', #{alarmCode}, '%')
+            </if>
+            <if test="deviceCode != null and deviceCode != ''">
+                and device_code = #{deviceCode}
+            </if>
+            <if test="deviceName != null and deviceName != ''">
+                and device_name like concat('%', #{deviceName}, '%')
+            </if>
+            <if test="deviceType != null and deviceType != ''">
+                and device_type = #{deviceType}
+            </if>
+            <if test="alarmLevel != null">
+                and alarm_level = #{alarmLevel}
+            </if>
+            <if test="buildingName != null and buildingName != ''">
+                and building_name = #{buildingName}
+            </if>
+            <if test="floorName != null and floorName != ''">
+                and floor_name = #{floorName}
+            </if>
+            <if test="isReset != null">
+                and is_reset = #{isReset}
+            </if>
+            <if test="beginTime != null and beginTime != ''">
+                and alarm_time &gt;= #{beginTime}
+            </if>
+            <if test="endTime != null and endTime != ''">
+                and alarm_time &lt;= #{endTime}
+            </if>
+        </where>
+        order by alarm_time desc
+    </select>
+
+    <select id="selectIbmsDeviceAlarmById" parameterType="Long" resultMap="IbmsDeviceAlarmResult">
+        <include refid="selectIbmsDeviceAlarmVo"/>
+        where id = #{id}
+    </select>
+
+    <!-- 统计查询 -->
+    <select id="selectAlarmStatistics" resultType="pd">
+        select
+        count(1) as total,
+        sum(case when is_reset = 0 then 1 else 0 end) as unreset,
+        sum(case when alarm_level >= 3 then 1 else 0 end) as highLevel,
+        sum(case when date(alarm_time) = curdate() then 1 else 0 end) as today
+        from ibms_device_alarms
+        <where>
+            <if test="beginTime != null and beginTime != ''">
+                and alarm_time &gt;= #{beginTime}
+            </if>
+            <if test="endTime != null and endTime != ''">
+                and alarm_time &lt;= #{endTime}
+            </if>
+        </where>
+    </select>
+
+    <insert id="insertIbmsDeviceAlarm" parameterType="pd" useGeneratedKeys="true" keyProperty="id">
+        insert into ibms_device_alarms
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="alarmCode != null and alarmCode != ''">alarm_code,</if>
+            <if test="deviceCode != null and deviceCode != ''">device_code,</if>
+            <if test="deviceName != null and deviceName != ''">device_name,</if>
+            <if test="deviceType != null and deviceType != ''">device_type,</if>
+            <if test="subsystemType != null and subsystemType != ''">subsystem_type,</if>
+            <if test="alarmLevel != null">alarm_level,</if>
+            <if test="alarmType != null and alarmType != ''">alarm_type,</if>
+            <if test="alarmDesc != null and alarmDesc != ''">alarm_desc,</if>
+            <if test="buildingName != null and buildingName != ''">building_name,</if>
+            <if test="floorName != null and floorName != ''">floor_name,</if>
+            <if test="roomName != null and roomName != ''">room_name,</if>
+            <if test="spaceLocation != null and spaceLocation != ''">space_location,</if>
+            <if test="alarmTime != null">alarm_time,</if>
+            <if test="isReset != null">is_reset,</if>
+            <if test="resetTime != null">reset_time,</if>
+            <if test="resetBy != null and resetBy != ''">reset_by,</if>
+            <if test="serviceOrderNo != null and serviceOrderNo != ''">service_order_no,</if>
+            <if test="handleStatus != null">handle_status,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="alarmCode != null and alarmCode != ''">#{alarmCode},</if>
+            <if test="deviceCode != null and deviceCode != ''">#{deviceCode},</if>
+            <if test="deviceName != null and deviceName != ''">#{deviceName},</if>
+            <if test="deviceType != null and deviceType != ''">#{deviceType},</if>
+            <if test="subsystemType != null and subsystemType != ''">#{subsystemType},</if>
+            <if test="alarmLevel != null">#{alarmLevel},</if>
+            <if test="alarmType != null and alarmType != ''">#{alarmType},</if>
+            <if test="alarmDesc != null and alarmDesc != ''">#{alarmDesc},</if>
+            <if test="buildingName != null and buildingName != ''">#{buildingName},</if>
+            <if test="floorName != null and floorName != ''">#{floorName},</if>
+            <if test="roomName != null and roomName != ''">#{roomName},</if>
+            <if test="spaceLocation != null and spaceLocation != ''">#{spaceLocation},</if>
+            <if test="alarmTime != null">#{alarmTime},</if>
+            <if test="isReset != null">#{isReset},</if>
+            <if test="resetTime != null">#{resetTime},</if>
+            <if test="resetBy != null and resetBy != ''">#{resetBy},</if>
+            <if test="serviceOrderNo != null and serviceOrderNo != ''">#{serviceOrderNo},</if>
+            <if test="handleStatus != null">#{handleStatus},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+        </trim>
+    </insert>
+
+    <update id="updateIbmsDeviceAlarm" parameterType="pd">
+        update ibms_device_alarms
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="alarmCode != null and alarmCode != ''">alarm_code = #{alarmCode},</if>
+            <if test="deviceCode != null and deviceCode != ''">device_code = #{deviceCode},</if>
+            <if test="deviceName != null and deviceName != ''">device_name = #{deviceName},</if>
+            <if test="deviceType != null and deviceType != ''">device_type = #{deviceType},</if>
+            <if test="subsystemType != null and subsystemType != ''">subsystem_type = #{subsystemType},</if>
+            <if test="alarmLevel != null">alarm_level = #{alarmLevel},</if>
+            <if test="alarmType != null and alarmType != ''">alarm_type = #{alarmType},</if>
+            <if test="alarmDesc != null and alarmDesc != ''">alarm_desc = #{alarmDesc},</if>
+            <if test="buildingName != null and buildingName != ''">building_name = #{buildingName},</if>
+            <if test="floorName != null and floorName != ''">floor_name = #{floorName},</if>
+            <if test="roomName != null and roomName != ''">room_name = #{roomName},</if>
+            <if test="spaceLocation != null and spaceLocation != ''">space_location = #{spaceLocation},</if>
+            <if test="alarmTime != null">alarm_time = #{alarmTime},</if>
+            <if test="isReset != null">is_reset = #{isReset},</if>
+            <if test="resetTime != null">reset_time = #{resetTime},</if>
+            <if test="resetBy != null and resetBy != ''">reset_by = #{resetBy},</if>
+            <if test="serviceOrderNo != null and serviceOrderNo != ''">service_order_no = #{serviceOrderNo},</if>
+            <if test="handleStatus != null">handle_status = #{handleStatus},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <!-- 复位告警 -->
+    <update id="resetAlarm" parameterType="pd">
+        update ibms_device_alarms
+        set is_reset = 1,
+            reset_time = #{resetTime},
+            reset_by = #{resetBy},
+            update_time = #{updateTime}
+        where id = #{id}
+    </update>
+
+    <!-- 更新服务单号 -->
+    <update id="updateServiceOrderNo" parameterType="pd">
+        update ibms_device_alarms
+        set service_order_no = #{serviceOrderNo},
+            handle_status = 1,
+            update_time = #{updateTime}
+        where id = #{id}
+    </update>
+
+    <delete id="deleteIbmsDeviceAlarmById" parameterType="Long">
+        delete from ibms_device_alarms where id = #{id}
+    </delete>
+
+    <delete id="deleteIbmsDeviceAlarmByIds" parameterType="String">
+        delete from ibms_device_alarms where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 79 - 0
pm_ui/src/api/device/alarm.js

@@ -0,0 +1,79 @@
+import request from '@/utils/request'
+
+// 查询设备告警列表
+export function listDeviceAlarm(query) {
+    return request({
+        url: '/device/alarm/list',
+        method: 'get',
+        params: query
+    })
+}
+
+// 查询设备告警详细
+export function getDeviceAlarm(id) {
+    return request({
+        url: '/device/alarm/' + id,
+        method: 'get'
+    })
+}
+
+// 获取告警详情(包含处理记录)
+export function getAlarmDetail(id) {
+    return request({
+        url: '/device/alarm/detail/' + id,
+        method: 'get'
+    })
+}
+
+// 新增设备告警
+export function addDeviceAlarm(data) {
+    return request({
+        url: '/device/alarm',
+        method: 'post',
+        data: data
+    })
+}
+
+// 修改设备告警
+export function updateDeviceAlarm(data) {
+    return request({
+        url: '/device/alarm',
+        method: 'put',
+        data: data
+    })
+}
+
+// 删除设备告警
+export function delDeviceAlarm(id) {
+    return request({
+        url: '/device/alarm/' + id,
+        method: 'delete'
+    })
+}
+
+// 导出设备告警
+export function exportDeviceAlarm(query) {
+    return request({
+        url: '/device/alarm/export',
+        method: 'post',
+        params: query
+    })
+}
+
+// 复位告警
+export function resetAlarm(data) {
+    return request({
+        url: '/device/alarm/reset',
+        method: 'post',
+        data: data
+    })
+}
+
+// 创建服务单
+export function createServiceOrder(data) {
+    return request({
+        url: '/device/alarm/createOrder',
+        method: 'post',
+        data: data
+    })
+}

+ 571 - 0
pm_ui/src/views/device/waring/index2.vue

@@ -0,0 +1,571 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" label-width="80px">
+      <el-form-item label="告警级别" prop="alarmLevel">
+        <el-select v-model="queryParams.alarmLevel" placeholder="请选择告警级别" clearable style="width: 150px">
+          <el-option label="低" :value="1" />
+          <el-option label="中" :value="2" />
+          <el-option label="高" :value="3" />
+          <el-option label="紧急" :value="4" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="设备类型" prop="deviceType">
+        <el-select v-model="queryParams.deviceType" placeholder="请选择设备类型" clearable style="width: 150px">
+          <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 label="空间位置" prop="spaceLocation">
+        <el-cascader
+            v-model="queryParams.spaceLocation"
+            :options="spaceOptions"
+            :props="{ expandTrigger: 'hover', value: 'label', label: 'label' }"
+            placeholder="请选择空间位置"
+            clearable
+            style="width: 200px"
+        />
+      </el-form-item>
+      <el-form-item label="复位状态" prop="isReset">
+        <el-select v-model="queryParams.isReset" placeholder="请选择复位状态" clearable style="width: 150px">
+          <el-option label="未复位" :value="0" />
+          <el-option label="已复位" :value="1" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="告警时间" prop="timeRange">
+        <el-date-picker
+            v-model="queryParams.timeRange"
+            type="datetimerange"
+            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="getList">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+<!--    <el-row :gutter="10" class="mb8">-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--            type="warning"-->
+<!--            plain-->
+<!--            icon="Download"-->
+<!--            @click="handleExport"-->
+<!--            v-hasPermi="['device:alarm:export']"-->
+<!--        >导出</el-button>-->
+<!--      </el-col>-->
+<!--    </el-row>-->
+
+    <!-- 告警统计卡片 -->
+    <el-row :gutter="20" class="mb20">
+      <el-col :span="6">
+        <el-card class="stat-card">
+          <div class="stat-item">
+            <div class="stat-title">总告警数</div>
+            <div class="stat-value total">{{ alarmStats.total }}</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card class="stat-card">
+          <div class="stat-item">
+            <div class="stat-title">未复位</div>
+            <div class="stat-value unreset">{{ alarmStats.unreset }}</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card class="stat-card">
+          <div class="stat-item">
+            <div class="stat-title">高级别告警</div>
+            <div class="stat-value high">{{ alarmStats.highLevel }}</div>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card class="stat-card">
+          <div class="stat-item">
+            <div class="stat-title">今日新增</div>
+            <div class="stat-value today">{{ alarmStats.today }}</div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="alarmList" stripe border @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="告警编码" prop="alarmCode" width="150" />
+      <el-table-column label="设备信息" width="200">
+        <template #default="scope">
+          <div>{{ scope.row.deviceName }}</div>
+          <div class="text-small">{{ scope.row.deviceCode }}</div>
+        </template>
+      </el-table-column>
+      <el-table-column label="告警级别" prop="alarmLevel" width="100" align="center">
+        <template #default="scope">
+          <el-tag :type="alarmLevelType(scope.row.alarmLevel)" effect="dark">
+            {{ alarmLevelText(scope.row.alarmLevel) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="告警类型" prop="alarmType" width="120" />
+      <el-table-column label="告警描述" prop="alarmDesc" min-width="200" show-overflow-tooltip />
+      <el-table-column label="空间位置" prop="spaceLocation" width="180" show-overflow-tooltip />
+      <el-table-column label="告警时间" prop="alarmTime" width="160">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.alarmTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="复位状态" prop="isReset" width="100" align="center">
+        <template #default="scope">
+          <el-tag :type="scope.row.isReset === 1 ? 'success' : 'danger'">
+            {{ scope.row.isReset === 1 ? '已复位' : '未复位' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="处理状态" prop="handleStatus" width="100" align="center">
+        <template #default="scope">
+          <el-tag :type="handleStatusType(scope.row.handleStatus)">
+            {{ handleStatusText(scope.row.handleStatus) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="200" fixed="right">
+        <template #default="scope">
+          <el-button
+              v-if="scope.row.isReset === 0"
+              link
+              type="primary"
+              icon="Refresh"
+              @click="handleReset(scope.row)"
+              v-hasPermi="['device:alarm:reset']"
+          >复位</el-button>
+          <el-button
+              v-if="!scope.row.serviceOrderNo"
+              link
+              type="primary"
+              icon="Document"
+              @click="handleCreateOrder(scope.row)"
+              v-hasPermi="['device:alarm:createOrder']"
+          >创建服务单</el-button>
+          <el-button link type="primary" icon="View" @click="handleDetail(scope.row)">详情</el-button>
+        </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-drawer
+        v-model="detailVisible"
+        title="告警详情"
+        direction="rtl"
+        size="45%"
+    >
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="告警编码">{{ currentAlarm.alarmCode }}</el-descriptions-item>
+        <el-descriptions-item label="告警级别">
+          <el-tag :type="alarmLevelType(currentAlarm.alarmLevel)" effect="dark">
+            {{ alarmLevelText(currentAlarm.alarmLevel) }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="设备编码">{{ currentAlarm.deviceCode }}</el-descriptions-item>
+        <el-descriptions-item label="设备名称">{{ currentAlarm.deviceName }}</el-descriptions-item>
+        <el-descriptions-item label="设备类型">{{ currentAlarm.deviceType }}</el-descriptions-item>
+        <el-descriptions-item label="子系统类型">{{ currentAlarm.subsystemType }}</el-descriptions-item>
+        <el-descriptions-item label="告警类型">{{ currentAlarm.alarmType }}</el-descriptions-item>
+        <el-descriptions-item label="空间位置">{{ currentAlarm.spaceLocation }}</el-descriptions-item>
+        <el-descriptions-item label="告警描述" :span="2">{{ currentAlarm.alarmDesc }}</el-descriptions-item>
+        <el-descriptions-item label="告警时间">{{ parseTime(currentAlarm.alarmTime) }}</el-descriptions-item>
+        <el-descriptions-item label="复位状态">
+          <el-tag :type="currentAlarm.isReset === 1 ? 'success' : 'danger'">
+            {{ currentAlarm.isReset === 1 ? '已复位' : '未复位' }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="复位时间" v-if="currentAlarm.isReset === 1">
+          {{ parseTime(currentAlarm.resetTime) }}
+        </el-descriptions-item>
+        <el-descriptions-item label="复位人" v-if="currentAlarm.isReset === 1">
+          {{ currentAlarm.resetBy }}
+        </el-descriptions-item>
+        <el-descriptions-item label="服务单号" v-if="currentAlarm.serviceOrderNo">
+          {{ currentAlarm.serviceOrderNo }}
+        </el-descriptions-item>
+        <el-descriptions-item label="处理状态">
+          <el-tag :type="handleStatusType(currentAlarm.handleStatus)">
+            {{ handleStatusText(currentAlarm.handleStatus) }}
+          </el-tag>
+        </el-descriptions-item>
+      </el-descriptions>
+
+      <!-- 告警处理记录时间线 -->
+      <div class="timeline-container" v-if="alarmLogs && alarmLogs.length > 0">
+        <h4>处理记录</h4>
+        <el-timeline>
+          <el-timeline-item
+              v-for="(log, index) in alarmLogs"
+              :key="index"
+              :timestamp="parseTime(log.createTime)"
+              placement="top"
+          >
+            <el-card>
+              <p>{{ log.content }}</p>
+              <p class="text-small">操作人:{{ log.operator }}</p>
+            </el-card>
+          </el-timeline-item>
+        </el-timeline>
+      </div>
+    </el-drawer>
+
+    <!-- 创建服务单对话框 -->
+    <el-dialog v-model="orderDialogVisible" title="创建服务单" width="600px" append-to-body>
+      <el-form ref="orderFormRef" :model="orderForm" :rules="orderRules" label-width="100px">
+        <el-form-item label="告警编码">
+          <el-input v-model="orderForm.alarmCode" disabled />
+        </el-form-item>
+        <el-form-item label="设备名称">
+          <el-input v-model="orderForm.deviceName" disabled />
+        </el-form-item>
+        <el-form-item label="服务类型" prop="serviceType">
+          <el-select v-model="orderForm.serviceType" 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 label="紧急程度" prop="urgency">
+          <el-radio-group v-model="orderForm.urgency">
+            <el-radio :label="1">一般</el-radio>
+            <el-radio :label="2">紧急</el-radio>
+            <el-radio :label="3">特急</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="问题描述" prop="description">
+          <el-input
+              v-model="orderForm.description"
+              type="textarea"
+              :rows="4"
+              placeholder="请输入问题描述"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="orderDialogVisible = false">取 消</el-button>
+          <el-button type="primary" @click="submitOrder">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue'
+import { listDeviceAlarm, exportDeviceAlarm, resetAlarm, createServiceOrder, getAlarmDetail } from '@/api/device/alarm'
+
+const { proxy } = getCurrentInstance()
+
+// 查询参数
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  alarmLevel: null,
+  deviceType: null,
+  spaceLocation: [],
+  isReset: null,
+  timeRange: []
+})
+
+// 空间位置级联选择器选项
+const spaceOptions = ref([
+  {
+    label: 'A栋',
+    children: [
+      { label: '1F' },
+      { label: '2F' },
+      { label: '3F' },
+      { label: '4F' },
+      { label: '5F' }
+    ]
+  },
+  {
+    label: 'B栋',
+    children: [
+      { label: '1F' },
+      { label: '2F' },
+      { label: '3F' },
+      { label: '4F' },
+      { label: '5F' }
+    ]
+  },
+  {
+    label: 'C栋',
+    children: [
+      { label: '1F' },
+      { label: '2F' },
+      { label: '3F' },
+      { label: '4F' }
+    ]
+  },
+  {
+    label: 'D栋',
+    children: [
+      { label: '1F' },
+      { label: '2F' },
+      { label: '3F' }
+    ]
+  },
+  {
+    label: 'E栋',
+    children: [
+      { label: 'B1F' },
+      { label: '1F' },
+      { label: '2F' }
+    ]
+  }
+])
+
+// 数据列表
+const alarmList = ref([])
+const total = ref(0)
+const loading = ref(false)
+const ids = ref([])
+
+// 告警统计
+const alarmStats = ref({
+  total: 0,
+  unreset: 0,
+  highLevel: 0,
+  today: 0
+})
+
+// 详情相关
+const detailVisible = ref(false)
+const currentAlarm = ref({})
+const alarmLogs = ref([])
+
+// 创建服务单相关
+const orderDialogVisible = ref(false)
+const orderForm = ref({
+  alarmId: null,
+  alarmCode: '',
+  deviceName: '',
+  serviceType: '',
+  urgency: 1,
+  description: ''
+})
+
+const orderRules = {
+  serviceType: [
+    { required: true, message: '请选择服务类型', trigger: 'change' }
+  ],
+  description: [
+    { required: true, message: '请输入问题描述', trigger: 'blur' }
+  ]
+}
+
+// 告警级别配置
+const alarmLevelType = (level) => {
+  const types = ['', 'info', 'warning', 'danger', 'danger']
+  return types[level] || 'info'
+}
+
+const alarmLevelText = (level) => {
+  const texts = ['', '低', '中', '高', '紧急']
+  return texts[level] || '未知'
+}
+
+// 处理状态配置
+const handleStatusType = (status) => {
+  const types = ['warning', 'primary', 'success']
+  return types[status] || 'info'
+}
+
+const handleStatusText = (status) => {
+  const texts = ['待处理', '处理中', '已处理']
+  return texts[status] || '未知'
+}
+
+// 查询告警列表
+function getList() {
+  loading.value = true
+  const params = {
+    ...queryParams,
+    pageNum: queryParams.pageNum,
+    pageSize: queryParams.pageSize
+  }
+
+  // 处理空间位置参数
+  if (queryParams.spaceLocation && queryParams.spaceLocation.length > 0) {
+    params.buildingName = queryParams.spaceLocation[0]
+    params.floorName = queryParams.spaceLocation[1]
+  }
+
+  // 处理时间范围参数
+  if (queryParams.timeRange && queryParams.timeRange.length === 2) {
+    params.beginTime = queryParams.timeRange[0]
+    params.endTime = queryParams.timeRange[1]
+  }
+
+  listDeviceAlarm(params).then(response => {
+    alarmList.value = response.rows
+    total.value = response.total
+    // 更新统计数据
+    if (response.extData.stats) {
+      alarmStats.value = response.extData.stats
+    }
+    loading.value = false
+  })
+}
+
+// 重置查询
+function resetQuery() {
+  proxy.resetForm('queryRef')
+  queryParams.pageNum = 1
+  queryParams.spaceLocation = []
+  getList()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+}
+
+// 导出
+function handleExport() {
+  const params = {
+    ...queryParams,
+    pageNum: undefined,
+    pageSize: undefined
+  }
+  if (queryParams.timeRange && queryParams.timeRange.length === 2) {
+    params.beginTime = queryParams.timeRange[0]
+    params.endTime = queryParams.timeRange[1]
+  }
+  proxy.$modal.confirm('确认导出设备告警记录吗?').then(() => {
+    exportDeviceAlarm(params).then(response => {
+      proxy.download(response.msg)
+    })
+  })
+}
+
+// 手动复位
+function handleReset(row) {
+  proxy.$modal.confirm(`确认复位告警"${row.alarmCode}"吗?`).then(() => {
+    return resetAlarm({ id: row.id })
+  }).then(() => {
+    proxy.$modal.msgSuccess('复位成功')
+    getList()
+  })
+}
+
+// 创建服务单
+function handleCreateOrder(row) {
+  orderForm.value = {
+    alarmId: row.id,
+    alarmCode: row.alarmCode,
+    deviceName: row.deviceName,
+    serviceType: '',
+    urgency: row.alarmLevel >= 3 ? 2 : 1,
+    description: row.alarmDesc
+  }
+  orderDialogVisible.value = true
+}
+
+// 提交服务单
+function submitOrder() {
+  proxy.$refs.orderFormRef.validate(valid => {
+    if (valid) {
+      createServiceOrder(orderForm.value).then(response => {
+        proxy.$modal.msgSuccess('服务单创建成功')
+        orderDialogVisible.value = false
+        getList()
+      })
+    }
+  })
+}
+
+// 查看详情
+function handleDetail(row) {
+  getAlarmDetail(row.id).then(response => {
+    currentAlarm.value = response.data
+    alarmLogs.value = response.logs || []
+    detailVisible.value = true
+  })
+}
+
+// 初始化
+getList()
+</script>
+
+<style scoped>
+.stat-card {
+  height: 100px;
+  margin-bottom: 20px;
+}
+
+.stat-item {
+  text-align: center;
+  padding: 10px;
+}
+
+.stat-title {
+  font-size: 14px;
+  color: #909399;
+  margin-bottom: 10px;
+}
+
+.stat-value {
+  font-size: 28px;
+  font-weight: bold;
+}
+
+.stat-value.total {
+  color: #409EFF;
+}
+
+.stat-value.unreset {
+  color: #F56C6C;
+}
+
+.stat-value.high {
+  color: #E6A23C;
+}
+
+.stat-value.today {
+  color: #67C23A;
+}
+
+.text-small {
+  font-size: 12px;
+  color: #909399;
+}
+
+.timeline-container {
+  margin: 20px;
+}
+
+.timeline-container h4 {
+  margin-bottom: 20px;
+}
+
+.mb20 {
+  margin-bottom: 20px;
+}
+</style>