You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1514 lines
46 KiB
1514 lines
46 KiB
<template> |
|
<div class="energy-warning"> |
|
<!-- 预警统计卡片 --> |
|
<div class="warning-stats"> |
|
<div class="stat-card total"> |
|
<div class="stat-icon"> |
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> |
|
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z" fill="currentColor"/> |
|
<path d="M688 464H336c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16z" fill="currentColor"/> |
|
</svg> |
|
</div> |
|
<div class="stat-info"> |
|
<div class="stat-value">{{ warningStats.total }}</div> |
|
<div class="stat-label">预警总数</div> |
|
</div> |
|
</div> |
|
<div class="stat-card critical"> |
|
<div class="stat-icon"> |
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> |
|
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z" fill="currentColor"/> |
|
<path d="M688 464H336c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16z" fill="currentColor"/> |
|
</svg> |
|
</div> |
|
<div class="stat-info"> |
|
<div class="stat-value">{{ warningStats.critical }}</div> |
|
<div class="stat-label">严重预警</div> |
|
</div> |
|
</div> |
|
<div class="stat-card major"> |
|
<div class="stat-icon"> |
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> |
|
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z" fill="currentColor"/> |
|
<path d="M688 464H336c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16z" fill="currentColor"/> |
|
</svg> |
|
</div> |
|
<div class="stat-info"> |
|
<div class="stat-value">{{ warningStats.major }}</div> |
|
<div class="stat-label">重要预警</div> |
|
</div> |
|
</div> |
|
<div class="stat-card minor"> |
|
<div class="stat-icon"> |
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> |
|
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z" fill="currentColor"/> |
|
<path d="M688 464H336c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16z" fill="currentColor"/> |
|
</svg> |
|
</div> |
|
<div class="stat-info"> |
|
<div class="stat-value">{{ warningStats.minor }}</div> |
|
<div class="stat-label">一般预警</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<!-- 预警筛选 --> |
|
<div class="filter-section"> |
|
<div class="filter-group"> |
|
<div class="filter-item"> |
|
<label>预警级别</label> |
|
<el-select v-model="filterForm.level" placeholder="全部" clearable class="custom-select"> |
|
<el-option label="全部" value=""></el-option> |
|
<el-option label="严重" value="critical"></el-option> |
|
<el-option label="重要" value="major"></el-option> |
|
<el-option label="一般" value="minor"></el-option> |
|
</el-select> |
|
</div> |
|
<div class="filter-item"> |
|
<label>处理状态</label> |
|
<el-select v-model="filterForm.status" placeholder="全部" clearable class="custom-select"> |
|
<el-option label="全部" value=""></el-option> |
|
<el-option label="待处理" value="pending"></el-option> |
|
<el-option label="处理中" value="processing"></el-option> |
|
<el-option label="已处理" value="resolved"></el-option> |
|
</el-select> |
|
</div> |
|
<div class="filter-item"> |
|
<label>部门名称</label> |
|
<el-select v-model="filterForm.department" placeholder="全部" clearable class="custom-select"> |
|
<el-option label="全部" value=""></el-option> |
|
<el-option label="办公楼A" value="OA"></el-option> |
|
<el-option label="办公楼B" value="OB"></el-option> |
|
<el-option label="商场区域" value="SM"></el-option> |
|
<el-option label="停车场" value="PK"></el-option> |
|
</el-select> |
|
</div> |
|
<div class="filter-item"> |
|
<label>预警时间</label> |
|
<el-date-picker |
|
v-model="filterForm.dateRange" |
|
type="daterange" |
|
range-separator="至" |
|
start-placeholder="开始日期" |
|
end-placeholder="结束日期" |
|
value-format="yyyy-MM-dd" |
|
class="custom-picker" |
|
></el-date-picker> |
|
</div> |
|
</div> |
|
<div class="filter-actions"> |
|
<el-input |
|
v-model="filterForm.keyword" |
|
placeholder="搜索项目/部门" |
|
clearable |
|
class="search-input custom-input" |
|
></el-input> |
|
<div class="primary-btn"><el-button type="primary" @click="handleSearch" class="custom-btn">查询</el-button></div> |
|
<el-button @click="handleReset" class="custom-btn">重置</el-button> |
|
<div class="success-btn"><el-button type="success" @click="handleExport" class="custom-btn">导出</el-button></div> |
|
</div> |
|
</div> |
|
|
|
<!-- 预警列表 --> |
|
<div class="warning-list"> |
|
<div class="list-header"> |
|
<div class="list-title">预警列表</div> |
|
<div class="list-info"> |
|
共 {{ filteredWarnings.length }} 条预警 |
|
</div> |
|
</div> |
|
<div class="table-container"> |
|
<table class="warning-table"> |
|
<thead> |
|
<tr> |
|
<th>预警ID</th> |
|
<th>预警级别</th> |
|
<th>部门名称</th> |
|
<th>项目名称</th> |
|
<th>能耗类型</th> |
|
<th>实际值</th> |
|
<th>阈值</th> |
|
<th>超出比例</th> |
|
<th>预警时间</th> |
|
<th>处理状态</th> |
|
<th>操作</th> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
<tr v-for="warning in paginatedWarnings" :key="warning.id"> |
|
<td>{{ warning.id }}</td> |
|
<td> |
|
<span class="level-badge" :class="warning.level"> |
|
{{ getLevelText(warning.level) }} |
|
</span> |
|
</td> |
|
<td>{{ warning.department }}</td> |
|
<td>{{ warning.projectName }}</td> |
|
<td>{{ warning.energyType }}</td> |
|
<td class="value-cell">{{ warning.actualValue }} kWh</td> |
|
<td class="value-cell">{{ warning.threshold }} kWh</td> |
|
<td> |
|
<span class="exceed-badge">{{ warning.exceedRatio }}%</span> |
|
</td> |
|
<td>{{ warning.warningTime }}</td> |
|
<td> |
|
<span class="status-badge" :class="warning.status"> |
|
{{ getStatusText(warning.status) }} |
|
</span> |
|
</td> |
|
<td class="action-cell"> |
|
<div class="action-buttons"> |
|
<div class="primary-btn" v-if="warning.status === 'pending'"><el-button |
|
type="primary" |
|
size="small" |
|
@click="handleWarning(warning)" |
|
class="action-btn" |
|
> |
|
处理 |
|
</el-button></div> |
|
<el-button |
|
size="small" |
|
@click="viewDetail(warning)" |
|
class="action-btn" |
|
> |
|
详情 |
|
</el-button> |
|
<el-dropdown @command="(cmd) => handleCommand(cmd, warning)" class="action-dropdown"> |
|
<el-button size="small" class="action-btn"> |
|
更多 |
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" style="margin-left: 0.04rem; width: 0.1rem; height: 0.1rem;"> |
|
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z" fill="currentColor"/> |
|
<path d="M688 464H336c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16z" fill="currentColor"/> |
|
</svg> |
|
</el-button> |
|
<template #dropdown> |
|
<el-dropdown-menu class="custom-dropdown-menu"> |
|
<el-dropdown-item command="markResolved" v-if="warning.status !== 'resolved'">标记已处理</el-dropdown-item> |
|
<el-dropdown-item command="exportReport" divided>导出报告</el-dropdown-item> |
|
</el-dropdown-menu> |
|
</template> |
|
</el-dropdown> |
|
</div> |
|
</td> |
|
</tr> |
|
</tbody> |
|
</table> |
|
</div> |
|
|
|
<!-- 分页 --> |
|
<div class="pagination-container"> |
|
<el-pagination |
|
v-model:current-page="currentPage" |
|
v-model:page-size="pageSize" |
|
:page-sizes="[10, 20, 50, 100]" |
|
:total="filteredWarnings.length" |
|
layout="total, sizes, prev, pager, next, jumper" |
|
@size-change="handleSizeChange" |
|
@current-change="handleCurrentChange" |
|
class="custom-pagination" |
|
></el-pagination> |
|
</div> |
|
</div> |
|
|
|
<!-- 预警趋势图 --> |
|
<div class="chart-section"> |
|
<div class="section-header"> |
|
<div class="section-title"> |
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> |
|
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z" fill="currentColor"/> |
|
<path d="M688 464H336c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16z" fill="currentColor"/> |
|
</svg> |
|
预警趋势 |
|
</div> |
|
</div> |
|
<div class="chart-container"> |
|
<div ref="warningTrendChart" class="chart"></div> |
|
</div> |
|
</div> |
|
|
|
<!-- 预警详情弹窗 --> |
|
<el-dialog |
|
v-model="detailDialogVisible" |
|
title="预警详情" |
|
width="700px" |
|
class="custom-dialog" |
|
> |
|
<div class="detail-content" v-if="selectedWarning"> |
|
<div class="detail-section"> |
|
<div class="section-title">基本信息</div> |
|
<div class="info-grid"> |
|
<div class="info-item"> |
|
<span class="item-label">预警ID:</span> |
|
<span class="item-value">{{ selectedWarning.id }}</span> |
|
</div> |
|
<div class="info-item"> |
|
<span class="item-label">预警级别:</span> |
|
<span class="item-value level-badge" :class="selectedWarning.level"> |
|
{{ getLevelText(selectedWarning.level) }} |
|
</span> |
|
</div> |
|
<div class="info-item"> |
|
<span class="item-label">部门名称:</span> |
|
<span class="item-value">{{ selectedWarning.department }}</span> |
|
</div> |
|
<div class="info-item"> |
|
<span class="item-label">项目名称:</span> |
|
<span class="item-value">{{ selectedWarning.projectName }}</span> |
|
</div> |
|
<div class="info-item"> |
|
<span class="item-label">能耗类型:</span> |
|
<span class="item-value">{{ selectedWarning.energyType }}</span> |
|
</div> |
|
<div class="info-item"> |
|
<span class="item-label">预警时间:</span> |
|
<span class="item-value">{{ selectedWarning.warningTime }}</span> |
|
</div> |
|
<div class="info-item"> |
|
<span class="item-label">实际值:</span> |
|
<span class="item-value">{{ selectedWarning.actualValue }} kWh</span> |
|
</div> |
|
<div class="info-item"> |
|
<span class="item-label">阈值:</span> |
|
<span class="item-value">{{ selectedWarning.threshold }} kWh</span> |
|
</div> |
|
<div class="info-item full-width"> |
|
<span class="item-label">超出比例:</span> |
|
<span class="item-value exceed-badge">{{ selectedWarning.exceedRatio }}%</span> |
|
</div> |
|
<div class="info-item full-width"> |
|
<span class="item-label">预警描述:</span> |
|
<span class="item-value">{{ selectedWarning.description }}</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="detail-section" v-if="selectedWarning.handleRecord"> |
|
<div class="section-title">处理记录</div> |
|
<div class="process-timeline"> |
|
<div |
|
v-for="(record, index) in selectedWarning.handleRecord" |
|
:key="index" |
|
class="timeline-item" |
|
> |
|
<div class="timeline-dot" :class="record.type"></div> |
|
<div class="timeline-content"> |
|
<div class="timeline-title">{{ record.title }}</div> |
|
<div class="timeline-time">{{ record.time }}</div> |
|
<div class="timeline-desc" v-if="record.description">{{ record.description }}</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
<template #footer> |
|
<el-button @click="detailDialogVisible = false" class="custom-btn">关闭</el-button> |
|
</template> |
|
</el-dialog> |
|
|
|
<!-- 处理预警弹窗 --> |
|
<el-dialog |
|
v-model="handleDialogVisible" |
|
title="处理预警" |
|
width="600px" |
|
class="custom-dialog" |
|
> |
|
<el-form :model="handleForm" :rules="handleRules" ref="handleFormRef" label-width="100px"> |
|
<el-form-item label="处理方式" prop="handleType"> |
|
<el-select v-model="handleForm.handleType" class="custom-select"> |
|
<el-option label="调整设备参数" value="adjust"></el-option> |
|
<el-option label="关闭部分设备" value="close"></el-option> |
|
<el-option label="检查设备状态" value="check"></el-option> |
|
<el-option label="通知负责人" value="notify"></el-option> |
|
</el-select> |
|
</el-form-item> |
|
<el-form-item label="处理说明" prop="handleDescription"> |
|
<el-input |
|
v-model="handleForm.handleDescription" |
|
type="textarea" |
|
:rows="4" |
|
placeholder="请输入处理说明" |
|
class="custom-input" |
|
></el-input> |
|
</el-form-item> |
|
<el-form-item label="处理人" prop="handler"> |
|
<el-input v-model="handleForm.handler" placeholder="请输入处理人" class="custom-input"></el-input> |
|
</el-form-item> |
|
</el-form> |
|
<template #footer> |
|
<el-button @click="handleDialogVisible = false" class="custom-btn">取消</el-button> |
|
<el-button type="primary" @click="submitHandle" class="custom-btn">提交</el-button> |
|
</template> |
|
</el-dialog> |
|
</div> |
|
</template> |
|
|
|
<script> |
|
import * as echarts from 'echarts'; |
|
|
|
export default { |
|
name: "EnergyWarning", |
|
data() { |
|
return { |
|
warningStats: { |
|
total: 56, |
|
critical: 8, |
|
major: 18, |
|
minor: 30 |
|
}, |
|
filterForm: { |
|
level: "", |
|
status: "", |
|
department: "", |
|
keyword: "", |
|
dateRange: [] |
|
}, |
|
currentPage: 1, |
|
pageSize: 10, |
|
warningList: [], |
|
detailDialogVisible: false, |
|
handleDialogVisible: false, |
|
selectedWarning: null, |
|
handleForm: { |
|
handleType: "", |
|
handleDescription: "", |
|
handler: "" |
|
}, |
|
handleRules: { |
|
handleType: [{ required: true, message: "请选择处理方式", trigger: "change" }], |
|
handleDescription: [{ required: true, message: "请输入处理说明", trigger: "blur" }], |
|
handler: [{ required: true, message: "请输入处理人", trigger: "blur" }] |
|
}, |
|
warningTrendChart: null |
|
}; |
|
}, |
|
computed: { |
|
filteredWarnings() { |
|
let warnings = [...this.warningList]; |
|
|
|
if (this.filterForm.level) { |
|
warnings = warnings.filter(w => w.level === this.filterForm.level); |
|
} |
|
|
|
if (this.filterForm.status) { |
|
warnings = warnings.filter(w => w.status === this.filterForm.status); |
|
} |
|
|
|
if (this.filterForm.department) { |
|
warnings = warnings.filter(w => w.departmentCode === this.filterForm.department); |
|
} |
|
|
|
if (this.filterForm.keyword) { |
|
const keyword = this.filterForm.keyword.toLowerCase(); |
|
warnings = warnings.filter(w => |
|
w.projectName.toLowerCase().includes(keyword) || |
|
w.department.toLowerCase().includes(keyword) || |
|
w.id.toLowerCase().includes(keyword) |
|
); |
|
} |
|
|
|
if (this.filterForm.dateRange && this.filterForm.dateRange.length === 2) { |
|
const [start, end] = this.filterForm.dateRange; |
|
warnings = warnings.filter(w => w.warningDate >= start && w.warningDate <= end); |
|
} |
|
|
|
return warnings; |
|
}, |
|
paginatedWarnings() { |
|
const start = (this.currentPage - 1) * this.pageSize; |
|
const end = start + this.pageSize; |
|
return this.filteredWarnings.slice(start, end); |
|
} |
|
}, |
|
mounted() { |
|
this.initWarningList(); |
|
this.$nextTick(() => { |
|
this.initCharts(); |
|
}); |
|
window.addEventListener('resize', this.handleResize); |
|
}, |
|
beforeDestroy() { |
|
window.removeEventListener('resize', this.handleResize); |
|
this.destroyCharts(); |
|
}, |
|
methods: { |
|
getLevelText(level) { |
|
const map = { |
|
critical: "严重", |
|
major: "重要", |
|
minor: "一般" |
|
}; |
|
return map[level] || level; |
|
}, |
|
getStatusText(status) { |
|
const map = { |
|
pending: "待处理", |
|
processing: "处理中", |
|
resolved: "已处理" |
|
}; |
|
return map[status] || status; |
|
}, |
|
initWarningList() { |
|
const now = new Date(); |
|
this.warningList = [ |
|
{ |
|
id: "WRN202403040001", |
|
level: "critical", |
|
department: "办公楼A", |
|
departmentCode: "OA", |
|
projectName: "办公楼A照明系统", |
|
energyType: "LED照明", |
|
actualValue: 1256.8, |
|
threshold: 1000, |
|
exceedRatio: 25.68, |
|
warningTime: "2024-03-04 10:30:25", |
|
warningDate: "2024-03-04", |
|
status: "pending", |
|
description: "办公楼A照明系统能耗超出阈值25.68%,请及时检查", |
|
handleRecord: [ |
|
{ type: "warning", title: "预警触发", time: "2024-03-04 10:30:25", description: "系统能耗超出阈值" } |
|
] |
|
}, |
|
{ |
|
id: "WRN202403040002", |
|
level: "critical", |
|
department: "商场区域", |
|
departmentCode: "SM", |
|
projectName: "商场区域照明系统", |
|
energyType: "景观照明", |
|
actualValue: 856.5, |
|
threshold: 650, |
|
exceedRatio: 31.77, |
|
warningTime: "2024-03-04 09:15:42", |
|
warningDate: "2024-03-04", |
|
status: "processing", |
|
description: "商场区域景观照明能耗超出阈值31.77%,正在进行处理", |
|
handleRecord: [ |
|
{ type: "warning", title: "预警触发", time: "2024-03-04 09:15:42", description: "系统能耗超出阈值" }, |
|
{ type: "process", title: "开始处理", time: "2024-03-04 09:20:00", description: "已通知负责人" } |
|
] |
|
}, |
|
{ |
|
id: "WRN202403040003", |
|
level: "major", |
|
department: "办公楼B", |
|
departmentCode: "OB", |
|
projectName: "办公楼B照明系统", |
|
energyType: "LED照明", |
|
actualValue: 1125.6, |
|
threshold: 1000, |
|
exceedRatio: 12.56, |
|
warningTime: "2024-03-04 08:45:18", |
|
warningDate: "2024-03-04", |
|
status: "pending", |
|
description: "办公楼B照明系统能耗超出阈值12.56%", |
|
handleRecord: [ |
|
{ type: "warning", title: "预警触发", time: "2024-03-04 08:45:18", description: "系统能耗超出阈值" } |
|
] |
|
}, |
|
{ |
|
id: "WRN202403030004", |
|
level: "major", |
|
department: "停车场", |
|
departmentCode: "PK", |
|
projectName: "停车场照明系统", |
|
energyType: "LED照明", |
|
actualValue: 928.5, |
|
threshold: 850, |
|
exceedRatio: 9.24, |
|
warningTime: "2024-03-03 16:22:33", |
|
warningDate: "2024-03-03", |
|
status: "resolved", |
|
description: "停车场照明系统能耗超出阈值9.24%,已处理", |
|
handleRecord: [ |
|
{ type: "warning", title: "预警触发", time: "2024-03-03 16:22:33", description: "系统能耗超出阈值" }, |
|
{ type: "process", title: "调整设备参数", time: "2024-03-03 16:30:00", description: "已调整照明亮度" }, |
|
{ type: "resolved", title: "预警已处理", time: "2024-03-03 17:15:00", description: "能耗已恢复正常" } |
|
] |
|
}, |
|
{ |
|
id: "WRN202403030005", |
|
level: "minor", |
|
department: "办公楼A", |
|
departmentCode: "OA", |
|
projectName: "办公楼A照明系统", |
|
energyType: "应急照明", |
|
actualValue: 256.8, |
|
threshold: 240, |
|
exceedRatio: 7.00, |
|
warningTime: "2024-03-03 14:10:22", |
|
warningDate: "2024-03-03", |
|
status: "resolved", |
|
description: "办公楼A应急照明能耗超出阈值7.00%,已处理", |
|
handleRecord: [ |
|
{ type: "warning", title: "预警触发", time: "2024-03-03 14:10:22", description: "系统能耗超出阈值" }, |
|
{ type: "process", title: "检查设备", time: "2024-03-03 14:20:00", description: "设备运行正常" }, |
|
{ type: "resolved", title: "预警已处理", time: "2024-03-03 14:30:00", description: "已恢复正常" } |
|
] |
|
}, |
|
{ |
|
id: "WRN202403020006", |
|
level: "minor", |
|
department: "商场区域", |
|
departmentCode: "SM", |
|
projectName: "商场区域照明系统", |
|
energyType: "走廊照明", |
|
actualValue: 385.2, |
|
threshold: 360, |
|
exceedRatio: 7.00, |
|
warningTime: "2024-03-02 11:30:45", |
|
warningDate: "2024-03-02", |
|
status: "resolved", |
|
description: "商场区域走廊照明能耗超出阈值7.00%,已处理", |
|
handleRecord: [ |
|
{ type: "warning", title: "预警触发", time: "2024-03-02 11:30:45", description: "系统能耗超出阈值" }, |
|
{ type: "process", title: "调整亮度", time: "2024-03-02 11:40:00", description: "已降低亮度" }, |
|
{ type: "resolved", title: "预警已处理", time: "2024-03-02 12:00:00", description: "能耗已恢复正常" } |
|
] |
|
} |
|
]; |
|
|
|
for (let i = 7; i <= 56; i++) { |
|
const levels = ["critical", "major", "minor"]; |
|
const statuses = ["pending", "processing", "resolved"]; |
|
const departments = [ |
|
{ name: "办公楼A", code: "OA" }, |
|
{ name: "办公楼B", code: "OB" }, |
|
{ name: "商场区域", code: "SM" }, |
|
{ name: "停车场", code: "PK" } |
|
]; |
|
const energyTypes = ["LED照明", "应急照明", "景观照明", "走廊照明"]; |
|
const date = new Date(now.getTime() - Math.random() * 30 * 24 * 60 * 60 * 1000); |
|
|
|
const dept = departments[Math.floor(Math.random() * departments.length)]; |
|
const energyType = energyTypes[Math.floor(Math.random() * energyTypes.length)]; |
|
const threshold = 200 + Math.random() * 800; |
|
const exceedRatio = 5 + Math.random() * 30; |
|
const actualValue = threshold * (1 + exceedRatio / 100); |
|
|
|
this.warningList.push({ |
|
id: `WRN2024${String(i).padStart(7, '0')}`, |
|
level: levels[Math.floor(Math.random() * levels.length)], |
|
department: dept.name, |
|
departmentCode: dept.code, |
|
projectName: `${dept.name}照明系统`, |
|
energyType: energyType, |
|
actualValue: actualValue.toFixed(1), |
|
threshold: threshold.toFixed(1), |
|
exceedRatio: exceedRatio.toFixed(2), |
|
warningTime: date.toISOString().slice(0, 19).replace('T', ' '), |
|
warningDate: date.toISOString().slice(0, 10), |
|
status: statuses[Math.floor(Math.random() * statuses.length)], |
|
description: `${dept.name}${energyType}能耗超出阈值${exceedRatio.toFixed(2)}%`, |
|
handleRecord: [ |
|
{ type: "warning", title: "预警触发", time: date.toISOString().slice(0, 19).replace('T', ' '), description: "系统能耗超出阈值" } |
|
] |
|
}); |
|
} |
|
}, |
|
initCharts() { |
|
this.initWarningTrendChart(); |
|
}, |
|
initWarningTrendChart() { |
|
if (!this.$refs.warningTrendChart) return; |
|
|
|
if (this.warningTrendChart) { |
|
this.warningTrendChart.dispose(); |
|
} |
|
|
|
this.warningTrendChart = echarts.init(this.$refs.warningTrendChart); |
|
|
|
const dates = []; |
|
const criticalData = []; |
|
const majorData = []; |
|
const minorData = []; |
|
const now = new Date(); |
|
|
|
for (let i = 29; i >= 0; i--) { |
|
const date = new Date(now); |
|
date.setDate(date.getDate() - i); |
|
dates.push(date.toISOString().slice(5, 10)); |
|
|
|
criticalData.push(Math.round(Math.random() * 5)); |
|
majorData.push(Math.round(Math.random() * 10)); |
|
minorData.push(Math.round(Math.random() * 15)); |
|
} |
|
|
|
const option = { |
|
backgroundColor: "transparent", |
|
tooltip: { |
|
trigger: "axis", |
|
backgroundColor: "rgba(30, 30, 50, 0.95)", |
|
borderColor: "rgba(255, 255, 255, 0.2)", |
|
textStyle: { |
|
color: "#ffffff" |
|
} |
|
}, |
|
legend: { |
|
data: ["严重预警", "重要预警", "一般预警"], |
|
textStyle: { |
|
color: "#ffffff" |
|
}, |
|
top: 10 |
|
}, |
|
grid: { |
|
left: "3%", |
|
right: "4%", |
|
bottom: "3%", |
|
containLabel: true |
|
}, |
|
xAxis: { |
|
type: "category", |
|
boundaryGap: false, |
|
data: dates, |
|
axisLine: { |
|
lineStyle: { |
|
color: "rgba(255, 255, 255, 0.3)" |
|
} |
|
}, |
|
axisLabel: { |
|
color: "#ffffff" |
|
} |
|
}, |
|
yAxis: { |
|
type: "value", |
|
name: "预警数量", |
|
nameTextStyle: { |
|
color: "#ffffff" |
|
}, |
|
axisLine: { |
|
lineStyle: { |
|
color: "rgba(255, 255, 255, 0.3)" |
|
} |
|
}, |
|
axisLabel: { |
|
color: "#ffffff" |
|
}, |
|
splitLine: { |
|
lineStyle: { |
|
color: "rgba(255, 255, 255, 0.1)" |
|
} |
|
} |
|
}, |
|
series: [ |
|
{ |
|
name: "严重预警", |
|
type: "line", |
|
smooth: true, |
|
data: criticalData, |
|
itemStyle: { |
|
color: "#EE6666" |
|
}, |
|
areaStyle: { |
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
|
{ offset: 0, color: "rgba(238, 102, 102, 0.5)" }, |
|
{ offset: 1, color: "rgba(238, 102, 102, 0.05)" } |
|
]) |
|
} |
|
}, |
|
{ |
|
name: "重要预警", |
|
type: "line", |
|
smooth: true, |
|
data: majorData, |
|
itemStyle: { |
|
color: "#FAC858" |
|
}, |
|
areaStyle: { |
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
|
{ offset: 0, color: "rgba(250, 200, 88, 0.5)" }, |
|
{ offset: 1, color: "rgba(250, 200, 88, 0.05)" } |
|
]) |
|
} |
|
}, |
|
{ |
|
name: "一般预警", |
|
type: "line", |
|
smooth: true, |
|
data: minorData, |
|
itemStyle: { |
|
color: "#91CC75" |
|
}, |
|
areaStyle: { |
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
|
{ offset: 0, color: "rgba(145, 204, 117, 0.5)" }, |
|
{ offset: 1, color: "rgba(145, 204, 117, 0.05)" } |
|
]) |
|
} |
|
} |
|
] |
|
}; |
|
|
|
this.warningTrendChart.setOption(option); |
|
}, |
|
handleSearch() { |
|
this.currentPage = 1; |
|
}, |
|
handleReset() { |
|
this.filterForm = { |
|
level: "", |
|
status: "", |
|
department: "", |
|
keyword: "", |
|
dateRange: [] |
|
}; |
|
this.currentPage = 1; |
|
}, |
|
handleExport() { |
|
this.$message.success("预警列表导出成功"); |
|
}, |
|
handleSizeChange(size) { |
|
this.pageSize = size; |
|
this.currentPage = 1; |
|
}, |
|
handleCurrentChange(page) { |
|
this.currentPage = page; |
|
}, |
|
viewDetail(warning) { |
|
this.selectedWarning = warning; |
|
this.detailDialogVisible = true; |
|
}, |
|
handleWarning(warning) { |
|
this.selectedWarning = warning; |
|
this.handleForm = { |
|
handleType: "", |
|
handleDescription: "", |
|
handler: "" |
|
}; |
|
this.handleDialogVisible = true; |
|
}, |
|
submitHandle() { |
|
this.$refs.handleFormRef.validate((valid) => { |
|
if (valid) { |
|
const warning = this.warningList.find(w => w === this.selectedWarning); |
|
if (warning) { |
|
warning.status = "processing"; |
|
warning.handleRecord.push({ |
|
type: "process", |
|
title: "开始处理", |
|
time: new Date().toISOString().slice(0, 19).replace('T', ' '), |
|
description: `${this.handleForm.handler}:${this.handleForm.handleDescription}` |
|
}); |
|
} |
|
this.$message.success("预警处理已提交"); |
|
this.handleDialogVisible = false; |
|
} |
|
}); |
|
}, |
|
handleCommand(command, warning) { |
|
if (command === "markResolved") { |
|
warning.status = "resolved"; |
|
warning.handleRecord.push({ |
|
type: "resolved", |
|
title: "标记已处理", |
|
time: new Date().toISOString().slice(0, 19).replace('T', ' '), |
|
description: "用户手动标记为已处理" |
|
}); |
|
this.$message.success("已标记为已处理"); |
|
} else if (command === "exportReport") { |
|
this.$message.success(`导出预警${warning.id}的报告成功`); |
|
} |
|
}, |
|
handleResize() { |
|
if (this.warningTrendChart) this.warningTrendChart.resize(); |
|
}, |
|
destroyCharts() { |
|
if (this.warningTrendChart) { |
|
this.warningTrendChart.dispose(); |
|
this.warningTrendChart = null; |
|
} |
|
} |
|
} |
|
}; |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
.energy-warning { |
|
padding: 0.16rem; |
|
} |
|
|
|
.warning-stats { |
|
display: grid; |
|
grid-template-columns: repeat(auto-fit, minmax(2rem, 1fr)); |
|
gap: 0.15rem; |
|
margin-bottom: 0.16rem; |
|
|
|
.stat-card { |
|
display: flex; |
|
align-items: center; |
|
padding: 0.2rem; |
|
background: rgba(255, 255, 255, 0.03); |
|
border-radius: 0.08rem; |
|
|
|
&.total { |
|
background: linear-gradient(135deg, rgba(84, 112, 198, 0.2) 0%, rgba(115, 192, 222, 0.2) 100%); |
|
border: 1px solid rgba(84, 112, 198, 0.3); |
|
} |
|
|
|
&.critical { |
|
background: linear-gradient(135deg, rgba(238, 102, 102, 0.2) 0%, rgba(229, 57, 53, 0.2) 100%); |
|
border: 1px solid rgba(238, 102, 102, 0.3); |
|
} |
|
|
|
&.major { |
|
background: linear-gradient(135deg, rgba(250, 200, 88, 0.2) 0%, rgba(255, 179, 0, 0.2) 100%); |
|
border: 1px solid rgba(250, 200, 88, 0.3); |
|
} |
|
|
|
&.minor { |
|
background: linear-gradient(135deg, rgba(145, 204, 117, 0.2) 0%, rgba(102, 187, 106, 0.2) 100%); |
|
border: 1px solid rgba(145, 204, 117, 0.3); |
|
} |
|
|
|
.stat-icon { |
|
width: 0.5rem; |
|
height: 0.5rem; |
|
border-radius: 50%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
margin-right: 0.15rem; |
|
background: rgba(255, 255, 255, 0.1); |
|
|
|
svg { |
|
width: 0.26rem; |
|
height: 0.26rem; |
|
fill: #ffffff; |
|
} |
|
} |
|
|
|
.stat-info { |
|
flex: 1; |
|
|
|
.stat-value { |
|
font-size: 0.28rem; |
|
color: #15e1fd; |
|
font-weight: bold; |
|
margin-bottom: 0.03rem; |
|
} |
|
|
|
.stat-label { |
|
font-size: 0.13rem; |
|
color: #ffffff; |
|
opacity: 0.7; |
|
} |
|
} |
|
} |
|
} |
|
|
|
.filter-section { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: flex-start; |
|
padding: 0.2rem; |
|
background: rgba(255, 255, 255, 0.05); |
|
border-radius: 0.08rem; |
|
margin-bottom: 0.16rem; |
|
flex-wrap: wrap; |
|
gap: 0.15rem; |
|
|
|
.filter-group { |
|
display: flex; |
|
gap: 0.15rem; |
|
flex-wrap: wrap; |
|
flex: 1; |
|
min-width: 0; |
|
|
|
.filter-item { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 0.08rem; |
|
min-width: 1.5rem; |
|
|
|
label { |
|
font-size: 0.13rem; |
|
color: #ffffff; |
|
opacity: 0.7; |
|
} |
|
|
|
::v-deep .custom-select, |
|
::v-deep .custom-picker { |
|
.el-input__wrapper, |
|
.el-select__wrapper { |
|
background: rgba(255, 255, 255, 0.1); |
|
border: 1px solid rgba(255, 255, 255, 0.2); |
|
|
|
.el-input__inner { |
|
color: #ffffff; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
.filter-actions { |
|
display: flex; |
|
gap: 0.1rem; |
|
|
|
.search-input { |
|
width: 2rem; |
|
} |
|
|
|
::v-deep .custom-btn { |
|
background: rgba(255, 255, 255, 0.1); |
|
border: 1px solid rgba(255, 255, 255, 0.2); |
|
color: #ffffff; |
|
|
|
&:hover { |
|
background: rgba(255, 255, 255, 0.2); |
|
} |
|
|
|
&.el-button--primary { |
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
border: none; |
|
|
|
&:hover { |
|
background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%); |
|
} |
|
} |
|
|
|
&.el-button--success { |
|
background: linear-gradient(135deg, #91CC75 0%, #66BB6A 100%); |
|
border: none; |
|
|
|
&:hover { |
|
background: linear-gradient(135deg, #7CB342 0%, #558B2F 100%); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
.warning-list { |
|
background: rgba(255, 255, 255, 0.03); |
|
border-radius: 0.08rem; |
|
padding: 0.2rem; |
|
margin-bottom: 0.16rem; |
|
|
|
.list-header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
margin-bottom: 0.2rem; |
|
|
|
.list-title { |
|
font-size: 0.16rem; |
|
color: #ffffff; |
|
font-weight: bold; |
|
padding-left: 0.12rem; |
|
border-left: 0.04rem solid #15e1fd; |
|
} |
|
|
|
.list-info { |
|
font-size: 0.14rem; |
|
color: #ffffff; |
|
opacity: 0.7; |
|
} |
|
} |
|
|
|
.table-container { |
|
overflow-x: auto; |
|
border-radius: 0.04rem; |
|
background: rgba(255, 255, 255, 0.02); |
|
|
|
.warning-table { |
|
width: 100%; |
|
border-collapse: collapse; |
|
min-width: 12rem; |
|
|
|
thead { |
|
position: sticky; |
|
top: 0; |
|
z-index: 10; |
|
|
|
tr { |
|
background: linear-gradient(135deg, rgba(21, 225, 253, 0.1) 0%, rgba(145, 204, 117, 0.1) 100%); |
|
|
|
th { |
|
padding: 0.12rem 0.1rem; |
|
text-align: left; |
|
font-size: 0.13rem; |
|
color: #15e1fd; |
|
font-weight: 600; |
|
border-bottom: 2px solid rgba(21, 225, 253, 0.3); |
|
white-space: nowrap; |
|
|
|
&:first-child { |
|
padding-left: 0.15rem; |
|
border-top-left-radius: 0.04rem; |
|
} |
|
|
|
&:last-child { |
|
padding-right: 0.15rem; |
|
border-top-right-radius: 0.04rem; |
|
} |
|
} |
|
} |
|
} |
|
|
|
tbody { |
|
tr { |
|
transition: all 0.3s ease; |
|
background: rgba(255, 255, 255, 0.02); |
|
|
|
&:nth-child(even) { |
|
background: rgba(255, 255, 255, 0.04); |
|
} |
|
|
|
&:hover { |
|
background: rgba(21, 225, 253, 0.1); |
|
transform: translateX(0.02rem); |
|
} |
|
|
|
td { |
|
padding: 0.12rem 0.1rem; |
|
font-size: 0.12rem; |
|
color: #ffffff; |
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08); |
|
vertical-align: middle; |
|
|
|
&:first-child { |
|
padding-left: 0.15rem; |
|
} |
|
|
|
&:last-child { |
|
padding-right: 0.15rem; |
|
} |
|
|
|
.value-cell { |
|
font-weight: 500; |
|
color: #FAC858; |
|
} |
|
|
|
.level-badge { |
|
display: inline-block; |
|
padding: 0.04rem 0.12rem; |
|
border-radius: 0.04rem; |
|
font-size: 0.11rem; |
|
font-weight: 500; |
|
white-space: nowrap; |
|
box-shadow: 0 0.02rem 0.04rem rgba(0, 0, 0, 0.2); |
|
|
|
&.critical { |
|
background: linear-gradient(135deg, rgba(238, 102, 102, 0.25) 0%, rgba(229, 57, 53, 0.25) 100%); |
|
color: #FF8A80; |
|
border: 1px solid rgba(238, 102, 102, 0.4); |
|
} |
|
|
|
&.major { |
|
background: linear-gradient(135deg, rgba(250, 200, 88, 0.25) 0%, rgba(255, 179, 0, 0.25) 100%); |
|
color: #FFE082; |
|
border: 1px solid rgba(250, 200, 88, 0.4); |
|
} |
|
|
|
&.minor { |
|
background: linear-gradient(135deg, rgba(145, 204, 117, 0.25) 0%, rgba(102, 187, 106, 0.25) 100%); |
|
color: #A5D6A7; |
|
border: 1px solid rgba(145, 204, 117, 0.4); |
|
} |
|
} |
|
|
|
.status-badge { |
|
display: inline-block; |
|
padding: 0.04rem 0.12rem; |
|
border-radius: 0.04rem; |
|
font-size: 0.11rem; |
|
font-weight: 500; |
|
white-space: nowrap; |
|
box-shadow: 0 0.02rem 0.04rem rgba(0, 0, 0, 0.2); |
|
|
|
&.pending { |
|
background: linear-gradient(135deg, rgba(238, 102, 102, 0.25) 0%, rgba(229, 57, 53, 0.25) 100%); |
|
color: #FF8A80; |
|
border: 1px solid rgba(238, 102, 102, 0.4); |
|
} |
|
|
|
&.processing { |
|
background: linear-gradient(135deg, rgba(250, 200, 88, 0.25) 0%, rgba(255, 179, 0, 0.25) 100%); |
|
color: #FFE082; |
|
border: 1px solid rgba(250, 200, 88, 0.4); |
|
} |
|
|
|
&.resolved { |
|
background: linear-gradient(135deg, rgba(145, 204, 117, 0.25) 0%, rgba(102, 187, 106, 0.25) 100%); |
|
color: #A5D6A7; |
|
border: 1px solid rgba(145, 204, 117, 0.4); |
|
} |
|
} |
|
|
|
.exceed-badge { |
|
display: inline-block; |
|
padding: 0.04rem 0.12rem; |
|
border-radius: 0.04rem; |
|
font-size: 0.11rem; |
|
font-weight: 500; |
|
color: #EE6666; |
|
background: rgba(238, 102, 102, 0.2); |
|
border: 1px solid rgba(238, 102, 102, 0.4); |
|
} |
|
|
|
.action-cell { |
|
display: flex; |
|
align-items: center; |
|
gap: 0.06rem; |
|
flex-wrap: nowrap; |
|
|
|
.action-btn, |
|
.action-dropdown { |
|
::v-deep .el-button--small { |
|
padding: 0.04rem 0.1rem; |
|
font-size: 0.11rem; |
|
border-radius: 0.04rem; |
|
font-weight: 500; |
|
transition: all 0.3s ease; |
|
white-space: nowrap; |
|
|
|
&:not(.el-button--primary):not(.el-button--default) { |
|
background: rgba(255, 255, 255, 0.1); |
|
border: 1px solid rgba(255, 255, 255, 0.2); |
|
color: #ffffff; |
|
|
|
&:hover { |
|
background: rgba(255, 255, 255, 0.2); |
|
} |
|
} |
|
|
|
&.el-button--primary { |
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
border: none; |
|
color: #ffffff; |
|
box-shadow: 0 0.04rem 0.08rem rgba(102, 126, 234, 0.3); |
|
|
|
&:hover { |
|
background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%); |
|
transform: translateY(-0.02rem); |
|
box-shadow: 0 0.06rem 0.12rem rgba(102, 126, 234, 0.4); |
|
} |
|
|
|
&:active { |
|
transform: translateY(0); |
|
} |
|
} |
|
|
|
svg { |
|
width: 0.1rem; |
|
height: 0.1rem; |
|
fill: #ffffff; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
.pagination-container { |
|
display: flex; |
|
justify-content: center; |
|
padding-top: 0.2rem; |
|
|
|
::v-deep .custom-pagination { |
|
.el-pagination__total, |
|
.el-pagination__jump, |
|
.el-pager li { |
|
color: #ffffff; |
|
} |
|
|
|
.el-pager li { |
|
background: rgba(255, 255, 255, 0.05); |
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
|
|
&:hover { |
|
background: rgba(255, 255, 255, 0.1); |
|
} |
|
|
|
&.is-active { |
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
border-color: transparent; |
|
} |
|
} |
|
|
|
.btn-prev, |
|
.btn-next { |
|
background: rgba(255, 255, 255, 0.05); |
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
color: #ffffff; |
|
|
|
&:hover { |
|
background: rgba(255, 255, 255, 0.1); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
.chart-section { |
|
background: rgba(255, 255, 255, 0.03); |
|
border-radius: 0.08rem; |
|
padding: 0.2rem; |
|
|
|
.section-header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
margin-bottom: 0.2rem; |
|
|
|
.section-title { |
|
font-size: 0.16rem; |
|
color: #ffffff; |
|
font-weight: bold; |
|
padding-left: 0.12rem; |
|
border-left: 0.04rem solid #15e1fd; |
|
display: flex; |
|
align-items: center; |
|
gap: 0.08rem; |
|
|
|
svg { |
|
width: 0.18rem; |
|
height: 0.18rem; |
|
fill: #15e1fd; |
|
} |
|
} |
|
} |
|
|
|
.chart-container { |
|
background: rgba(255, 255, 255, 0.02); |
|
border-radius: 0.04rem; |
|
padding: 0.1rem; |
|
|
|
.chart { |
|
width: 100%; |
|
height: 4rem; |
|
} |
|
} |
|
} |
|
|
|
::v-deep .custom-dialog { |
|
.el-dialog { |
|
background: rgba(30, 30, 50, 0.95); |
|
border: 1px solid rgba(255, 255, 255, 0.1); |
|
} |
|
|
|
.el-dialog__header { |
|
background: rgba(255, 255, 255, 0.05); |
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1); |
|
} |
|
|
|
.el-dialog__title { |
|
color: #ffffff; |
|
} |
|
|
|
.el-dialog__headerbtn .el-dialog__close { |
|
color: #ffffff; |
|
} |
|
|
|
.detail-content { |
|
.detail-section { |
|
margin-bottom: 0.3rem; |
|
|
|
.section-title { |
|
font-size: 0.15rem; |
|
color: #15e1fd; |
|
font-weight: bold; |
|
margin-bottom: 0.15rem; |
|
padding-left: 0.12rem; |
|
border-left: 0.04rem solid #15e1fd; |
|
} |
|
|
|
.info-grid { |
|
display: grid; |
|
grid-template-columns: repeat(2, 1fr); |
|
gap: 0.15rem; |
|
|
|
.info-item { |
|
display: flex; |
|
justify-content: space-between; |
|
padding: 0.12rem; |
|
background: rgba(255, 255, 255, 0.03); |
|
border-radius: 0.06rem; |
|
|
|
&.full-width { |
|
grid-column: 1 / -1; |
|
} |
|
|
|
.item-label { |
|
font-size: 0.13rem; |
|
color: #ffffff; |
|
opacity: 0.7; |
|
} |
|
|
|
.item-value { |
|
font-size: 0.13rem; |
|
color: #ffffff; |
|
|
|
&.level-badge { |
|
padding: 0.03rem 0.1rem; |
|
border-radius: 0.03rem; |
|
font-size: 0.11rem; |
|
|
|
&.critical { |
|
background: rgba(238, 102, 102, 0.2); |
|
color: #EE6666; |
|
} |
|
|
|
&.major { |
|
background: rgba(250, 200, 88, 0.2); |
|
color: #FAC858; |
|
} |
|
|
|
&.minor { |
|
background: rgba(145, 204, 117, 0.2); |
|
color: #91CC75; |
|
} |
|
} |
|
|
|
&.exceed-badge { |
|
padding: 0.03rem 0.1rem; |
|
border-radius: 0.03rem; |
|
font-size: 0.11rem; |
|
color: #EE6666; |
|
background: rgba(238, 102, 102, 0.2); |
|
} |
|
} |
|
} |
|
} |
|
|
|
.process-timeline { |
|
.timeline-item { |
|
display: flex; |
|
margin-bottom: 0.2rem; |
|
|
|
.timeline-dot { |
|
width: 0.1rem; |
|
height: 0.1rem; |
|
border-radius: 50%; |
|
margin-right: 0.15rem; |
|
margin-top: 0.03rem; |
|
|
|
&.warning { |
|
background: #EE6666; |
|
} |
|
|
|
&.process { |
|
background: #FAC858; |
|
} |
|
|
|
&.resolved { |
|
background: #91CC75; |
|
} |
|
} |
|
|
|
.timeline-content { |
|
flex: 1; |
|
|
|
.timeline-title { |
|
font-size: 0.13rem; |
|
color: #ffffff; |
|
font-weight: bold; |
|
margin-bottom: 0.05rem; |
|
} |
|
|
|
.timeline-time { |
|
font-size: 0.11rem; |
|
color: #ffffff; |
|
opacity: 0.6; |
|
margin-bottom: 0.05rem; |
|
} |
|
|
|
.timeline-desc { |
|
font-size: 0.12rem; |
|
color: #ffffff; |
|
opacity: 0.8; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
::v-deep .el-form { |
|
.el-form-item__label { |
|
color: #ffffff; |
|
opacity: 0.7; |
|
} |
|
|
|
.custom-input, |
|
.custom-select { |
|
.el-input__wrapper, |
|
.el-select__wrapper { |
|
background: rgba(255, 255, 255, 0.1); |
|
border: 1px solid rgba(255, 255, 255, 0.2); |
|
|
|
.el-input__inner { |
|
color: #ffffff; |
|
} |
|
} |
|
} |
|
} |
|
|
|
::v-deep .el-dropdown-menu { |
|
background: rgba(30, 30, 50, 0.98); |
|
border: 1px solid rgba(255, 255, 255, 0.15); |
|
box-shadow: 0 0.08rem 0.24rem rgba(0, 0, 0, 0.4); |
|
border-radius: 0.06rem; |
|
padding: 0.08rem 0; |
|
|
|
.el-dropdown-menu__item { |
|
color: #ffffff; |
|
padding: 0.1rem 0.16rem; |
|
font-size: 0.13rem; |
|
transition: all 0.3s ease; |
|
|
|
&:hover { |
|
background: linear-gradient(135deg, rgba(21, 225, 253, 0.15) 0%, rgba(145, 204, 117, 0.15) 100%); |
|
color: #15e1fd; |
|
} |
|
|
|
&.is-divided { |
|
position: relative; |
|
margin-top: 0.08rem; |
|
|
|
&::before { |
|
content: ""; |
|
position: absolute; |
|
top: -0.04rem; |
|
left: 0.1rem; |
|
right: 0.1rem; |
|
height: 1px; |
|
background: rgba(255, 255, 255, 0.1); |
|
} |
|
} |
|
} |
|
} |
|
|
|
@media (max-width: 1485px) { |
|
.warning-stats { |
|
grid-template-columns: repeat(2, 1fr); |
|
} |
|
|
|
.filter-section { |
|
flex-direction: column; |
|
} |
|
|
|
.filter-actions { |
|
width: 100%; |
|
margin-top: 0.1rem; |
|
|
|
.search-input { |
|
flex: 1; |
|
} |
|
} |
|
|
|
.table-container { |
|
.warning-table { |
|
thead tr th, |
|
tbody tr td { |
|
font-size: 0.11rem; |
|
padding: 0.08rem; |
|
} |
|
} |
|
} |
|
} |
|
</style>
|
|
|