gaoluyang
2025-09-23 912ff069e014108f5061cff89713061b01222bb6
设备运行管理
已修改3个文件
939 ■■■■ 文件已修改
src/views/equipmentManagement/ledger/Form.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/operationManagement/index.vue 922 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/Form.vue
@@ -114,6 +114,19 @@
          />
        </el-form-item>
      </el-col>
            <el-col :span="12">
                <el-form-item label="预计运行时间" prop="planRuntimeTime">
                    <el-date-picker
                        style="width: 100%"
                        v-model="form.planRuntimeTime"
                        format="YYYY-MM-DD"
                        value-format="YYYY-MM-DD"
                        type="date"
                        placeholder="请选择录入日期"
                        clearable
                    />
                </el-form-item>
            </el-col>
    </el-row>
  </el-form>
</template>
@@ -143,6 +156,7 @@
    number: [{ required: true, trigger: "blur", message: "请输入" }],
    taxIncludingPriceUnit: [{ required: true, trigger: "blur", message: "请输入" }],
    taxRate: [{ required: true, trigger: "change", message: "请输入" }],
    planRuntimeTime: [{ required: true, trigger: "change", message: "请选择" }],
}
const { form, resetForm } = useFormData({
@@ -160,6 +174,7 @@
  unTaxIncludingPriceTotal: undefined, // 不含税总价
  // createUser: useUserStore().nickName, // 录入人
  createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // 录入日期
    planRuntimeTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), // 录入日期
});
const loadForm = async (id) => {
src/views/equipmentManagement/ledger/index.vue
@@ -211,7 +211,7 @@
            label: "操作",
            align: "center",
            fixed: 'right',
            width: 140,
            width: 150,
            operation: [
                {
                    name: "编辑",
src/views/equipmentManagement/operationManagement/index.vue
@@ -1,203 +1,26 @@
<template>
  <div class="app-container">
    <!-- 统计概览卡片 -->
    <div class="stats-overview">
      <el-row :gutter="20">
        <el-col :span="6">
          <el-card class="stats-card">
            <div class="stats-content">
              <div class="stats-icon running">
                <el-icon><VideoPlay /></el-icon>
              </div>
              <div class="stats-info">
                <div class="stats-value">{{ overviewData.runningDevices }}</div>
                <div class="stats-label">运行设备</div>
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="6">
          <el-card class="stats-card">
            <div class="stats-content">
              <div class="stats-icon stopped">
                <el-icon><VideoPause /></el-icon>
              </div>
              <div class="stats-info">
                <div class="stats-value">{{ overviewData.stoppedDevices }}</div>
                <div class="stats-label">停机设备</div>
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="6">
          <el-card class="stats-card">
            <div class="stats-content">
              <div class="stats-icon alarm">
                <el-icon><Warning /></el-icon>
              </div>
              <div class="stats-info">
                <div class="stats-value">{{ overviewData.alarmCount }}</div>
                <div class="stats-label">报警数量</div>
              </div>
            </div>
          </el-card>
        </el-col>
        <el-col :span="6">
          <el-card class="stats-card">
            <div class="stats-content">
              <div class="stats-icon maintenance">
                <el-icon><Tools /></el-icon>
              </div>
              <div class="stats-info">
                <div class="stats-value">{{ overviewData.maintenanceCount }}</div>
                <div class="stats-label">维护中</div>
              </div>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>
    <!-- 主要内容区域 -->
    <el-row :gutter="20">
      <!-- 左侧:设备启停记录 -->
      <el-col :span="12">
        <el-card class="main-card">
          <template #header>
            <div class="card-header">
              <span>设备启停记录</span>
              <el-button type="primary" size="small" @click="refreshDeviceRecords">
                <el-icon><Refresh /></el-icon>
                刷新
              </el-button>
            </div>
          </template>
          <!-- 设备状态筛选 -->
    <!-- 筛选条件 -->
          <div class="filter-section">
            <el-radio-group v-model="deviceFilter" @change="filterDeviceRecords">
              <el-radio-button label="all">全部</el-radio-button>
              <el-radio-button label="start">启动</el-radio-button>
              <el-radio-button label="stop">停机</el-radio-button>
            </el-radio-group>
      <el-select v-model="deviceFilter" placeholder="设备状态筛选" clearable style="width: 200px; margin-right: 10px;">
        <el-option label="全部" value="all" />
        <el-option label="运行中" value="start" />
        <el-option label="停止运行" value="stop" />
      </el-select>
          </div>
          <!-- 设备记录列表 -->
          <div class="device-records">
            <div
              v-for="record in filteredDeviceRecords"
              :key="record.id"
              class="device-record"
              :class="record.type"
            >
              <div class="record-icon">
                <el-icon v-if="record.type === 'start'"><VideoPlay /></el-icon>
                <el-icon v-else><VideoPause /></el-icon>
              </div>
              <div class="record-content">
                <div class="device-name">{{ record.deviceName }}</div>
                <div class="record-time">{{ record.time }}</div>
                <div class="record-status" :class="record.type">
                  {{ record.type === 'start' ? '设备启动' : '设备停机' }}
                </div>
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
      <!-- 右侧:装置开停工信息 -->
      <el-col :span="12">
        <el-card class="main-card">
    <!-- 设备启停记录表格 -->
    <el-card class="table-card">
          <template #header>
            <div class="card-header">
              <span>装置开停工信息</span>
              <el-button type="success" size="small" @click="refreshUnitInfo">
                <el-icon><Refresh /></el-icon>
                刷新
              </el-button>
            </div>
        <span>设备运行记录</span>
          </template>
          <!-- 装置状态筛选 -->
          <div class="filter-section">
            <el-radio-group v-model="unitFilter" @change="filterUnitInfo">
              <el-radio-button label="all">全部</el-radio-button>
              <el-radio-button label="startup">开工</el-radio-button>
              <el-radio-button label="shutdown">停工</el-radio-button>
              <el-radio-button label="unplanned">非计划停工</el-radio-button>
            </el-radio-group>
          </div>
          <!-- 装置信息列表 -->
          <div class="unit-info">
            <div
              v-for="unit in filteredUnitInfo"
              :key="unit.id"
              class="unit-item"
              :class="unit.status"
            >
              <div class="unit-header">
                <div class="unit-name">{{ unit.unitName }}</div>
                <div class="unit-status" :class="unit.status">
                  {{ getUnitStatusText(unit.status) }}
                </div>
              </div>
              <div class="unit-details">
                <div class="detail-item">
                  <span class="label">开始时间:</span>
                  <span class="value">{{ unit.startTime }}</span>
                </div>
                <div class="detail-item" v-if="unit.endTime">
                  <span class="label">结束时间:</span>
                  <span class="value">{{ unit.endTime }}</span>
                </div>
                <div class="detail-item" v-if="unit.reason">
                  <span class="label">原因:</span>
                  <span class="value">{{ unit.reason }}</span>
                </div>
              </div>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- 报警信息集中展示 -->
    <el-card class="alarm-card">
      <template #header>
        <div class="card-header">
          <span>报警信息集中展示</span>
          <div class="alarm-actions">
            <el-button type="warning" size="small" @click="refreshAlarms">
              <el-icon><Refresh /></el-icon>
              刷新
            </el-button>
            <el-button type="danger" size="small" @click="clearAlarms">
              <el-icon><Delete /></el-icon>
              清除已处理
            </el-button>
          </div>
        </div>
      </template>
      <!-- 报警级别筛选 -->
      <div class="filter-section">
        <el-radio-group v-model="alarmFilter" @change="filterAlarms">
          <el-radio-button label="all">全部</el-radio-button>
          <el-radio-button label="critical">严重</el-radio-button>
          <el-radio-button label="warning">警告</el-radio-button>
          <el-radio-button label="info">信息</el-radio-button>
        </el-radio-group>
      </div>
      <!-- 报警信息表格 -->
      <el-table
        :data="filteredAlarms"
        :data="filteredDeviceRecords"
        style="width: 100%"
        :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
        max-height="400"
        :row-class-name="getRowClassName"
        v-loading="loading"
      >
        <el-table-column
          align="center"
@@ -206,341 +29,277 @@
          width="60"
        />
        <el-table-column
          label="报警时间"
          prop="alarmTime"
          width="150"
          align="center"
        />
        <el-table-column
          label="设备名称"
          prop="deviceName"
          width="150"
          show-overflow-tooltip
        />
        <el-table-column
          label="报警级别"
          prop="level"
          width="100"
          align="center"
        >
          <template #default="scope">
            <el-tag
              :type="getAlarmTagType(scope.row.level)"
              size="small"
            >
              {{ scope.row.level }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="报警内容"
          prop="content"
          min-width="200"
          label="规格型号"
          prop="deviceModel"
          show-overflow-tooltip
        />
        <el-table-column
          label="处理状态"
          label="设备状态"
          prop="status"
          width="100"
          width="150"
          align="center"
        >
          <template #default="scope">
            <!-- 超时未启动时显示警告 -->
            <el-tag 
              :type="scope.row.status === '已处理' ? 'success' : 'danger'"
              v-if="isOverdue(scope.row)"
              type="warning"
              size="small"
              effect="dark"
            >
              <el-icon><Warning /></el-icon>
              超时未启动
            </el-tag>
            <!-- 正常状态时显示设备状态 -->
            <el-tag
              v-else
              :type="getDeviceStatusType(scope.row.status)"
              size="small"
            >
              {{ scope.row.status }}
              <el-icon v-if="scope.row.status === '运行中'"><VideoPlay /></el-icon>
              <el-icon v-else><VideoPause /></el-icon>
              {{ scope.row.status || '未知' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="处理人"
          prop="handler"
          width="100"
          show-overflow-tooltip
        />
          label="计划运行时间"
          prop="planRuntimeTime"
          width="150"
          align="center"
        >
          <template #default="scope">
            {{ scope.row.planRuntimeTime || '-' }}
          </template>
        </el-table-column>
        <el-table-column
          label="开始运行时间"
          prop="startRuntimeTime"
          width="180"
          align="center"
        >
          <template #default="scope">
            {{ scope.row.startRuntimeTime || '-' }}
          </template>
        </el-table-column>
        <el-table-column
          label="结束运行时间"
          prop="endRuntimeTime"
          width="180"
          align="center"
        >
          <template #default="scope">
            {{ scope.row.endRuntimeTime || '-' }}
          </template>
        </el-table-column>
        <el-table-column
          label="运行时长"
          prop="runtimeDuration"
          width="120"
          align="center"
        >
          <template #default="scope">
            {{ scope.row.runtimeDuration || '-' }}
          </template>
        </el-table-column>
        <el-table-column
          label="操作"
          width="120"
          align="center"
        >
          <template #default="scope">
            <!-- 超时未启动时显示启动按钮 -->
            <el-button
              v-if="scope.row.status === '未处理'"
              type="primary"
              v-if="isOverdue(scope.row)"
              type="warning"
              size="small"
              @click="handleAlarm(scope.row)"
              @click="changeDeviceStatus(scope.row, '启动运行')"
            >
              处理
              <el-icon><VideoPlay /></el-icon>
              立即启动
            </el-button>
            <!-- 正常状态时显示对应的操作按钮 -->
            <template v-else>
              <el-button
                v-if="scope.row.status === '运行中'"
                type="danger"
                size="small"
                @click="changeDeviceStatus(scope.row, '停止运行')"
              >
                <el-icon><VideoPause /></el-icon>
                停止运行
            </el-button>
            <el-button
              v-else
              type="info"
                type="success"
              size="small"
              disabled
                @click="changeDeviceStatus(scope.row, '启动运行')"
            >
              已处理
                <el-icon><VideoPlay /></el-icon>
                启动运行
            </el-button>
            </template>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ref, onMounted, computed } from 'vue'
import { ElMessage } from 'element-plus'
import {
  VideoPlay,
  VideoPause,
  Warning,
  Tools,
  Refresh,
  Delete
  Warning
} from '@element-plus/icons-vue'
import {editLedger, getLedgerPage} from "@/api/equipmentManagement/ledger.js";
// 响应式数据
const deviceFilter = ref('all')
const unitFilter = ref('all')
const alarmFilter = ref('all')
// 概览数据
const overviewData = reactive({
  runningDevices: 15,
  stoppedDevices: 3,
  alarmCount: 8,
  maintenanceCount: 2
const loading = ref(false)
const total = ref(0)
const queryParams = ref({
  current: -1,
  size: -1
})
// 移除概览数据,因为现在使用表格展示
// 设备启停记录数据
const deviceRecords = ref([
  {
    id: 1,
    deviceName: '压缩机A-001',
    type: 'start',
    time: '2024-01-15 08:30:25'
  },
  {
    id: 2,
    deviceName: '泵B-002',
    type: 'stop',
    time: '2024-01-15 08:25:10'
  },
  {
    id: 3,
    deviceName: '风机C-003',
    type: 'start',
    time: '2024-01-15 08:20:15'
  },
  {
    id: 4,
    deviceName: '搅拌器D-004',
    type: 'start',
    time: '2024-01-15 08:15:30'
  },
  {
    id: 5,
    deviceName: '加热器E-005',
    type: 'stop',
    time: '2024-01-15 08:10:45'
  },
  {
    id: 6,
    deviceName: '冷却器F-006',
    type: 'start',
    time: '2024-01-15 08:05:20'
  }
])
const deviceRecords = ref([])
const allDeviceRecords = ref([]) // 存储所有原始数据
// 装置开停工信息数据
const unitInfo = ref([
  {
    id: 1,
    unitName: '反应装置A',
    status: 'startup',
    startTime: '2024-01-15 08:00:00',
    endTime: null,
    reason: null
  },
  {
    id: 2,
    unitName: '分离装置B',
    status: 'shutdown',
    startTime: '2024-01-15 07:30:00',
    endTime: '2024-01-15 08:00:00',
    reason: '计划维护'
  },
  {
    id: 3,
    unitName: '精制装置C',
    status: 'unplanned',
    startTime: '2024-01-15 07:45:00',
    endTime: null,
    reason: '设备故障'
  },
  {
    id: 4,
    unitName: '包装装置D',
    status: 'startup',
    startTime: '2024-01-15 08:15:00',
    endTime: null,
    reason: null
  }
])
// 报警信息数据
const alarms = ref([
  {
    id: 1,
    alarmTime: '2024-01-15 08:30:00',
    deviceName: '压缩机A-001',
    level: '严重',
    content: '温度过高报警',
    status: '未处理',
    handler: ''
  },
  {
    id: 2,
    alarmTime: '2024-01-15 08:25:00',
    deviceName: '泵B-002',
    level: '警告',
    content: '压力异常',
    status: '已处理',
    handler: '张三'
  },
  {
    id: 3,
    alarmTime: '2024-01-15 08:20:00',
    deviceName: '风机C-003',
    level: '信息',
    content: '运行时间达到维护周期',
    status: '未处理',
    handler: ''
  },
  {
    id: 4,
    alarmTime: '2024-01-15 08:15:00',
    deviceName: '搅拌器D-004',
    level: '严重',
    content: '振动异常',
    status: '未处理',
    handler: ''
  },
  {
    id: 5,
    alarmTime: '2024-01-15 08:10:00',
    deviceName: '加热器E-005',
    level: '警告',
    content: '加热效率下降',
    status: '已处理',
    handler: '李四'
  }
])
// 计算属性 - 过滤后的设备记录
// 根据筛选条件过滤数据
const filteredDeviceRecords = computed(() => {
  if (deviceFilter.value === 'all') {
    return deviceRecords.value
  let filtered = allDeviceRecords.value
  // 根据设备状态筛选
  if (deviceFilter.value !== 'all') {
    if (deviceFilter.value === 'start') {
      filtered = filtered.filter(device => device.status === '运行中')
    } else if (deviceFilter.value === 'stop') {
      filtered = filtered.filter(device => device.status === '停止运行')
  }
  return deviceRecords.value.filter(record => record.type === deviceFilter.value)
  }
  return filtered
})
// 计算属性 - 过滤后的装置信息
const filteredUnitInfo = computed(() => {
  if (unitFilter.value === 'all') {
    return unitInfo.value
// 检查设备是否超时未启动
const isOverdue = (device) => {
  if (!device.planRuntimeTime || device.status === '运行中' || device.startRuntimeTime) {
    return false
  }
  return unitInfo.value.filter(unit => unit.status === unitFilter.value)
})
// 计算属性 - 过滤后的报警信息
const filteredAlarms = computed(() => {
  if (alarmFilter.value === 'all') {
    return alarms.value
  const planTime = new Date(device.planRuntimeTime)
  const currentTime = new Date()
  return currentTime > planTime
  }
  return alarms.value.filter(alarm => alarm.level === alarmFilter.value)
})
// 方法
const refreshDeviceRecords = () => {
  ElMessage.success('设备记录已刷新')
  // 这里可以调用API获取最新数据
}
const refreshUnitInfo = () => {
  ElMessage.success('装置信息已刷新')
  // 这里可以调用API获取最新数据
}
const refreshAlarms = () => {
  ElMessage.success('报警信息已刷新')
  // 这里可以调用API获取最新数据
}
const clearAlarms = async () => {
const getList = async () => {
  loading.value = true
  try {
    await ElMessageBox.confirm('确定要清除所有已处理的报警信息吗?', '确认清除', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    alarms.value = alarms.value.filter(alarm => alarm.status === '未处理')
    ElMessage.success('已清除所有已处理的报警信息')
  } catch {
    // 用户取消操作
    const response = await getLedgerPage(queryParams.value)
    if (response.code === 200) {
      allDeviceRecords.value = response.data.records || []
      total.value = response.data.total || 0
    }
  } catch (error) {
    console.error('获取设备列表失败:', error)
    ElMessage.error('获取设备列表失败')
  } finally {
    loading.value = false
  }
}
const filterDeviceRecords = () => {
  // 过滤逻辑已在计算属性中处理
const changeDeviceStatus = async (device, status) => {
  try {
    const currentTime = new Date().toLocaleString('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
      hour12: false
    }).replace(/\//g, '-')
    // 更新设备状态和相关时间字段
    if (status === '启动运行') {
      device.status = '运行中'
      device.startRuntimeTime = currentTime
      device.endRuntimeTime = null // 清空结束时间
      device.runtimeDuration = null // 清空运行时长
    } else {
      device.status = '停止运行'
      device.endRuntimeTime = currentTime
      // 计算运行时长
      if (device.startRuntimeTime) {
        const startTime = new Date(device.startRuntimeTime)
        const endTime = new Date(currentTime)
        const duration = endTime - startTime
        const hours = Math.floor(duration / (1000 * 60 * 60))
        const minutes = Math.floor((duration % (1000 * 60 * 60)) / (1000 * 60))
        device.runtimeDuration = `${hours}小时${minutes}分钟`
      }
    }
    const params = {
            id: device.id,
            status: device.status,
            planRuntimeTime: device.planRuntimeTime,
            startRuntimeTime: device.startRuntimeTime,
            endRuntimeTime: device.endRuntimeTime,
            runtimeDuration: device.runtimeDuration,
        }
    // 调用API更新设备状态
    const response = await editLedger(params)
    if (response.code === 200) {
      ElMessage.success(`${device.deviceName} ${status}成功`)
      // 刷新列表
      await getList()
    } else {
      ElMessage.error(response.msg || '操作失败')
    }
  } catch (error) {
    console.error('更新设备状态失败:', error)
    ElMessage.error('操作失败')
  }
}
const filterUnitInfo = () => {
  // 过滤逻辑已在计算属性中处理
const getDeviceStatusType = (status) => {
  if (status === '运行中') {
    return 'success'
  } else if (status === '停止运行') {
    return 'danger'
  } else {
    return 'info'
  }
}
const filterAlarms = () => {
  // 过滤逻辑已在计算属性中处理
// 获取表格行的类名
const getRowClassName = ({ row }) => {
  if (isOverdue(row)) {
    return 'overdue-row'
  }
  return ''
}
const getUnitStatusText = (status) => {
  const statusMap = {
    startup: '开工中',
    shutdown: '已停工',
    unplanned: '非计划停工'
  }
  return statusMap[status] || status
}
const getAlarmTagType = (level) => {
  const typeMap = {
    '严重': 'danger',
    '警告': 'warning',
    '信息': 'info'
  }
  return typeMap[level] || 'info'
}
const handleAlarm = (alarm) => {
  ElMessageBox.prompt('请输入处理说明', '处理报警', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    inputPlaceholder: '请输入处理说明'
  }).then(({ value }) => {
    alarm.status = '已处理'
    alarm.handler = '当前用户' // 这里应该获取当前登录用户
    ElMessage.success('报警处理完成')
  }).catch(() => {
    // 用户取消操作
  })
}
// 组件挂载时初始化数据
onMounted(() => {
  // 这里可以调用API获取初始数据
  console.log('运行管理页面已加载')
  getList()
})
</script>
@@ -552,251 +311,27 @@
}
.stats-overview {
  margin-bottom: 20px;
}
.stats-card {
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.stats-content {
  display: flex;
  align-items: center;
  padding: 10px 0;
}
.stats-icon {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 15px;
  font-size: 24px;
  color: #fff;
}
.stats-icon.running {
  background: linear-gradient(135deg, #67C23A, #85CE61);
}
.stats-icon.stopped {
  background: linear-gradient(135deg, #F56C6C, #F78989);
}
.stats-icon.alarm {
  background: linear-gradient(135deg, #E6A23C, #EEBE77);
}
.stats-icon.maintenance {
  background: linear-gradient(135deg, #409EFF, #66B1FF);
}
.stats-info {
  flex: 1;
}
.stats-value {
  font-size: 24px;
  font-weight: bold;
  color: #333;
  line-height: 1;
  margin-bottom: 5px;
}
.stats-label {
  font-size: 14px;
  color: #666;
}
.main-card {
  margin-bottom: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.filter-section {
  margin-bottom: 15px;
}
.device-records {
  max-height: 400px;
  overflow-y: auto;
}
.device-record {
  display: flex;
  align-items: center;
  padding: 12px;
  margin-bottom: 8px;
  border-radius: 6px;
  background: #f8f9fa;
  border-left: 4px solid #ddd;
}
.device-record.start {
  border-left-color: #67C23A;
  background: #f0f9ff;
}
.device-record.stop {
  border-left-color: #F56C6C;
  background: #fef0f0;
}
.record-icon {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 12px;
  font-size: 16px;
  color: #fff;
}
.device-record.start .record-icon {
  background: #67C23A;
}
.device-record.stop .record-icon {
  background: #F56C6C;
}
.record-content {
  flex: 1;
}
.device-name {
  font-weight: 500;
  color: #333;
  margin-bottom: 4px;
}
.record-time {
  font-size: 12px;
  color: #666;
  margin-bottom: 4px;
}
.record-status {
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 12px;
  display: inline-block;
}
.record-status.start {
  background: #e1f3d8;
  color: #67C23A;
}
.record-status.stop {
  background: #fde2e2;
  color: #F56C6C;
}
.unit-info {
  max-height: 400px;
  overflow-y: auto;
}
.unit-item {
  margin-bottom: 20px;
  padding: 15px;
  margin-bottom: 12px;
  border-radius: 6px;
  background: #f8f9fa;
  border-left: 4px solid #ddd;
}
.unit-item.startup {
  border-left-color: #67C23A;
  background: #f0f9ff;
}
.unit-item.shutdown {
  border-left-color: #409EFF;
  background: #f0f9ff;
}
.unit-item.unplanned {
  border-left-color: #E6A23C;
  background: #fdf6ec;
}
.unit-header {
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  justify-content: flex-start;
}
.unit-name {
  font-weight: 500;
  color: #333;
  font-size: 14px;
}
.unit-status {
  font-size: 12px;
  padding: 4px 8px;
  border-radius: 12px;
  display: inline-block;
}
.unit-status.startup {
  background: #e1f3d8;
  color: #67C23A;
}
.unit-status.shutdown {
  background: #e1f3ff;
  color: #409EFF;
}
.unit-status.unplanned {
  background: #fdf6ec;
  color: #E6A23C;
}
.unit-details {
  font-size: 12px;
  color: #666;
}
.detail-item {
  margin-bottom: 4px;
}
.detail-item .label {
  font-weight: 500;
  margin-right: 4px;
}
.alarm-card {
.table-card {
  margin-bottom: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.alarm-actions {
  display: flex;
  gap: 8px;
}
:deep(.el-card__header) {
  background: #f8f9fa;
  border-bottom: 1px solid #e9ecef;
  font-weight: 500;
  font-size: 16px;
}
:deep(.el-table .el-table__header-wrapper th) {
@@ -806,19 +341,30 @@
}
:deep(.el-table .el-table__body-wrapper td) {
  padding: 8px 0;
  padding: 12px 0;
}
:deep(.el-radio-button__inner) {
  border-radius: 4px;
:deep(.el-select) {
  width: 100%;
}
:deep(.el-radio-button:first-child .el-radio-button__inner) {
  border-left: 1px solid #dcdfe6;
  border-radius: 4px;
:deep(.el-tag) {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
:deep(.el-radio-button:last-child .el-radio-button__inner) {
  border-radius: 4px;
/* 超时未启动行的样式 */
:deep(.overdue-row) {
  background-color: #fef0f0 !important;
  border-left: 4px solid #f56c6c;
}
:deep(.overdue-row:hover) {
  background-color: #fde2e2 !important;
}
:deep(.overdue-row td) {
  background-color: transparent !important;
}
</style>