1.新增报警管理部分图表
2.修改箭头为本地图片 3.优化部分样式 4.完成性能比水滴图
This commit is contained in:
BIN
src/assets/demo/archive.png
Normal file
BIN
src/assets/demo/archive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 353 B |
BIN
src/assets/demo/down.png
Normal file
BIN
src/assets/demo/down.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 195 B |
BIN
src/assets/demo/health.png
Normal file
BIN
src/assets/demo/health.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 415 B |
BIN
src/assets/demo/mouse-square.png
Normal file
BIN
src/assets/demo/mouse-square.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 405 B |
BIN
src/assets/demo/sms-tracking.png
Normal file
BIN
src/assets/demo/sms-tracking.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 432 B |
BIN
src/assets/demo/up.png
Normal file
BIN
src/assets/demo/up.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 193 B |
198
src/views/integratedManage/alarmManage/components/fenxiBar.vue
Normal file
198
src/views/integratedManage/alarmManage/components/fenxiBar.vue
Normal file
@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div class="chart-container">
|
||||
<!--组件温度(℃) 图表内容区域 -->
|
||||
<div ref="chartRef" class="chart-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
|
||||
|
||||
// 图表DOM引用
|
||||
const chartRef = ref(null);
|
||||
// 图表实例
|
||||
let chartInstance = null;
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (chartRef.value && !chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
const option = {
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: ["09-04", "09-05", "09-06", "09-07", "09-08", "09-09", "09-10"],
|
||||
axisTick: {
|
||||
show: false // 去除刻度线
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f0f0f0',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
icon: 'square',
|
||||
left: '2%',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemAlign: 'middle', // 设置图例项垂直居中
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "维护提醒",
|
||||
data: [120, 200, 150, 80, 70, 110, 130],
|
||||
type: "bar",
|
||||
itemStyle: {
|
||||
color: "rgb(0, 179, 255)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "数据异常",
|
||||
data: [80, 170, 100, 50, 90, 140, 170],
|
||||
type: "bar",
|
||||
itemStyle: {
|
||||
color: "rgb(22, 93, 255)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "信号减弱",
|
||||
data: [60, 140, 100, 120, 110, 100, 130],
|
||||
type: "bar",
|
||||
itemStyle: {
|
||||
color: "rgb(255, 153, 0)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "温度过高",
|
||||
data: [60, 140, 100, 120, 110, 100, 130],
|
||||
type: "bar",
|
||||
itemStyle: {
|
||||
color: "rgb(250, 220, 25)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "通讯中断",
|
||||
data: [60, 140, 100, 120, 110, 100, 130],
|
||||
type: "bar",
|
||||
itemStyle: {
|
||||
color: "rgb(251, 62, 122)",
|
||||
}
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 响应窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.chart-header h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: calc(100% - 54px);
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.chart-actions button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
padding: 20px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
</style>
|
||||
172
src/views/integratedManage/alarmManage/components/levelPie.vue
Normal file
172
src/views/integratedManage/alarmManage/components/levelPie.vue
Normal file
@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<div class="chart-container">
|
||||
<!--组件温度(℃) 图表内容区域 -->
|
||||
<div ref="chartRef" class="chart-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
|
||||
// 图表DOM引用
|
||||
const chartRef = ref(null);
|
||||
// 图表实例
|
||||
let chartInstance = null;
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (chartRef.value && !chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
grid: {
|
||||
left: '0%',
|
||||
right: '20%',
|
||||
bottom: '0%',
|
||||
top: '0%',
|
||||
containLabel: true
|
||||
},
|
||||
legend: {
|
||||
top: 'middle',
|
||||
orient: 'vertical',
|
||||
right: '5%', // 调整图例位置,使其更靠近左侧
|
||||
itemWidth: 15,
|
||||
itemHeight: 15,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '80%',
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
color: [
|
||||
'rgb(0, 179, 255)', // 提示信息
|
||||
'rgb(45, 214, 131)', // 一般告警
|
||||
'rgb(255, 208, 35)', // 重要告警
|
||||
'rgb(227, 39, 39)' // 严重告警
|
||||
],
|
||||
data: [
|
||||
{ value: 1048, name: '提示信息' },
|
||||
{ value: 735, name: '一般告警' },
|
||||
{ value: 580, name: '重要告警' },
|
||||
{ value: 484, name: '严重告警' },
|
||||
],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 响应窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.chart-header h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.chart-actions button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
padding: 20px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
</style>
|
||||
382
src/views/integratedManage/alarmManage/components/levelSet.vue
Normal file
382
src/views/integratedManage/alarmManage/components/levelSet.vue
Normal file
@ -0,0 +1,382 @@
|
||||
<template>
|
||||
<el-table :data="alarmLevels" :border="false" style="width: 100%">
|
||||
<el-table-column prop="levelName" label="级别名称" align="center">
|
||||
<template #default="scope">
|
||||
<span :class="['level-name', `level-${scope.row.level}`]">{{ scope.row.levelName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="description" label="标识含义" align="center"></el-table-column>
|
||||
<el-table-column prop="priority" label="优先级" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getPriorityType(scope.row.priority)">{{ scope.row.priority }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="responseTime" label="响应时间" align="center">
|
||||
<template #default="scope">
|
||||
<span style="color: #186DF5;">{{ scope.row.responseTime }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="processingMethod" label="处理方式" align="center">
|
||||
<template #default="scope">
|
||||
<div class="process-methods">
|
||||
<el-tag size="small" v-for="method in scope.row.processingMethod" :key="method" :type="getMethodType(method)">{{ method }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="enabled" label="是否启用" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.enabled" active-color="#13ce66" inactive-color="#ff4949" @change="handleEnabledChange(scope.row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" fixed="right" align="center">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleConfig(scope.row)">配置</el-button>
|
||||
<el-button link type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
|
||||
|
||||
<!-- 配置对话框 -->
|
||||
<el-dialog v-model="configDialogVisible" title="告警配置" width="600px">
|
||||
<div v-if="currentConfigData">
|
||||
<h3 class="config-title">{{ currentConfigData.levelName }} - 详细配置</h3>
|
||||
<el-form ref="configFormRef" :model="currentConfigData" label-width="120px">
|
||||
<el-form-item label="告警声音">
|
||||
<el-select v-model="currentConfigData.alarmSound" placeholder="请选择告警声音">
|
||||
<el-option label="默认声音" value="default" />
|
||||
<el-option label="紧急声音" value="urgent" />
|
||||
<el-option label="普通声音" value="normal" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="通知方式">
|
||||
<el-checkbox-group v-model="currentConfigData.notificationMethods">
|
||||
<el-checkbox label="短信" />
|
||||
<el-checkbox label="邮件" />
|
||||
<el-checkbox label="站内信" />
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="告警持续时间">
|
||||
<el-input-number v-model="currentConfigData.duration" :min="1" :max="60" label="分钟" />
|
||||
</el-form-item>
|
||||
<el-form-item label="自动处理">
|
||||
<el-switch v-model="currentConfigData.autoProcess" />
|
||||
</el-form-item>
|
||||
<el-form-item label="处理说明" v-if="currentConfigData.autoProcess">
|
||||
<el-input v-model="currentConfigData.processDescription" type="textarea" placeholder="请输入自动处理说明" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="configDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfigSave">保存配置</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
// 定义告警等级类型
|
||||
interface AlarmLevel {
|
||||
id: number;
|
||||
levelName: string;
|
||||
description: string;
|
||||
priority: string;
|
||||
responseTime: string;
|
||||
processingMethod: string[];
|
||||
enabled: boolean;
|
||||
level: number; // 用于样式区分
|
||||
}
|
||||
|
||||
// 定义配置数据类型
|
||||
interface ConfigData extends AlarmLevel {
|
||||
alarmSound: string;
|
||||
notificationMethods: string[];
|
||||
duration: number;
|
||||
autoProcess: boolean;
|
||||
processDescription: string;
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
const alarmLevels = ref<AlarmLevel[]>([
|
||||
{
|
||||
id: 1,
|
||||
levelName: '严重告警',
|
||||
description: '系统或应用出现严重故障',
|
||||
priority: '一级',
|
||||
responseTime: '15分钟以内',
|
||||
processingMethod: ['系统锁定', '声光报警', '短信通知'],
|
||||
enabled: true,
|
||||
level: 1
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: '重要告警',
|
||||
description: '系统或应用出现严重故障',
|
||||
priority: '二级',
|
||||
responseTime: '30分钟以内',
|
||||
processingMethod: ['声光报警', '短信通知', '系统记录'],
|
||||
enabled: true,
|
||||
level: 2
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
levelName: '一般告警',
|
||||
description: '非关键性故障或潜在风险',
|
||||
priority: '三级',
|
||||
responseTime: '120分钟以内',
|
||||
processingMethod: ['短信通知', '系统记录'],
|
||||
enabled: true,
|
||||
level: 3
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
levelName: '提示信息',
|
||||
description: '系统或应用非关键性变化或即将达到阈值的状态',
|
||||
priority: '四级',
|
||||
responseTime: '24小时以内',
|
||||
processingMethod: ['短信通知'],
|
||||
enabled: false,
|
||||
level: 4
|
||||
}
|
||||
]);
|
||||
|
||||
// 对话框相关状态
|
||||
const configDialogVisible = ref(false);
|
||||
const configFormRef = ref<any>();
|
||||
const currentConfigData = ref<ConfigData | null>(null);
|
||||
|
||||
// 获取优先级对应的标签类型
|
||||
const getPriorityType = (priority: string) => {
|
||||
const priorityMap: Record<string, string> = {
|
||||
'一级': 'danger',
|
||||
'二级': 'warning',
|
||||
'三级': 'success',
|
||||
'四级': 'primary'
|
||||
};
|
||||
return priorityMap[priority] || 'default';
|
||||
};
|
||||
|
||||
// 获取处理方式对应的标签类型
|
||||
const getMethodType = (method: string) => {
|
||||
const methodMap: Record<string, string> = {
|
||||
'系统锁定': 'danger',
|
||||
'声光报警': 'warning',
|
||||
'短信通知': 'primary',
|
||||
'邮件通知': 'info',
|
||||
'系统记录': 'success'
|
||||
};
|
||||
return methodMap[method] || 'info';
|
||||
};
|
||||
|
||||
// 处理启用状态变更
|
||||
const handleEnabledChange = (row: AlarmLevel) => {
|
||||
ElMessage.success(`${row.levelName} ${row.enabled ? '已启用' : '已禁用'}`);
|
||||
// 这里可以添加保存到后端的逻辑
|
||||
};
|
||||
|
||||
// 打开配置对话框
|
||||
const handleConfig = (row: AlarmLevel) => {
|
||||
// 构建配置数据
|
||||
currentConfigData.value = {
|
||||
...row,
|
||||
alarmSound: 'default',
|
||||
notificationMethods: ['短信'],
|
||||
duration: 30,
|
||||
autoProcess: false,
|
||||
processDescription: ''
|
||||
};
|
||||
configDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 保存配置
|
||||
const handleConfigSave = () => {
|
||||
if (currentConfigData.value) {
|
||||
// 找到对应的告警等级并更新
|
||||
const index = alarmLevels.value.findIndex(item => item.id === currentConfigData.value!.id);
|
||||
if (index !== -1) {
|
||||
alarmLevels.value[index] = {
|
||||
...alarmLevels.value[index],
|
||||
enabled: currentConfigData.value!.enabled
|
||||
};
|
||||
}
|
||||
ElMessage.success('配置保存成功');
|
||||
configDialogVisible.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 删除告警等级
|
||||
const handleDelete = (id: number) => {
|
||||
ElMessageBox.confirm('确定要删除该告警等级吗?', '确认删除', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const index = alarmLevels.value.findIndex(item => item.id === id);
|
||||
if (index !== -1) {
|
||||
alarmLevels.value.splice(index, 1);
|
||||
ElMessage.success('删除成功');
|
||||
}
|
||||
}).catch(() => {
|
||||
// 用户取消删除
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.level-set-container {
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.level-name {
|
||||
font-weight: 500;
|
||||
padding: 2px 6px 2px 18px;
|
||||
border-radius: 3px;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.level-name::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.level-1::before {
|
||||
background-color: #ff4949;
|
||||
}
|
||||
|
||||
.level-2::before {
|
||||
background-color: #f7ba1e;
|
||||
}
|
||||
|
||||
.level-3::before {
|
||||
background-color: #13ce66;
|
||||
}
|
||||
|
||||
.level-4::before {
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
.level-name:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.level-1 {
|
||||
color: #ff4949;
|
||||
}
|
||||
|
||||
.level-2 {
|
||||
color: #f7ba1e;
|
||||
}
|
||||
|
||||
.level-3 {
|
||||
color: #13ce66;
|
||||
}
|
||||
|
||||
.level-4 {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.process-methods {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
/* 优化表格样式 */
|
||||
:deep(.el-table) {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.el-table th) {
|
||||
background-color: #fafafa;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
:deep(.el-table tr:hover > td) {
|
||||
background-color: #f0f9ff !important;
|
||||
}
|
||||
|
||||
:deep(.el-table__row:nth-child(even)) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
/* 优化按钮和操作列 */
|
||||
:deep(.el-button--text) {
|
||||
transition: all 0.3s ease;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
:deep(.el-button--text:hover) {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 优化对话框样式 */
|
||||
.config-title {
|
||||
margin-bottom: 20px;
|
||||
color: #303133;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* 优化表单样式 */
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.el-select),
|
||||
:deep(.el-input),
|
||||
:deep(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 768px) {
|
||||
.level-set-container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
321
src/views/integratedManage/alarmManage/components/totalView.vue
Normal file
321
src/views/integratedManage/alarmManage/components/totalView.vue
Normal file
@ -0,0 +1,321 @@
|
||||
<template>
|
||||
<div class="total-view-dashboard">
|
||||
<!-- 今日报警总数 -->
|
||||
<div class="total-view-card blue-border">
|
||||
<div class="total-content">
|
||||
<div class="content-row">
|
||||
<div class="left-section">
|
||||
<div class="total-header">
|
||||
<span class="total-title">今日报警总数</span>
|
||||
</div>
|
||||
<div class="total-number">28</div>
|
||||
</div>
|
||||
<div class="icon-section">
|
||||
<el-icon class="total-icon blue">
|
||||
<img src="@/assets/demo/health.png" alt="">
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="total-comparison">
|
||||
<el-icon class="trend-icon green">
|
||||
<img src="/src/assets/demo/up.png" alt="上升">
|
||||
</el-icon>
|
||||
<span class="comparison-text green">8台</span>
|
||||
<span class="period-text">较上月同期</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 未处理报警 -->
|
||||
<div class="total-view-card purple-border">
|
||||
<div class="total-content">
|
||||
<div class="content-row">
|
||||
<div class="left-section">
|
||||
<div class="total-header">
|
||||
<span class="total-title">未处理报警</span>
|
||||
</div>
|
||||
<div class="total-number">8</div>
|
||||
</div>
|
||||
<div class="icon-section">
|
||||
<el-icon class="total-icon purple">
|
||||
<img src="@/assets/demo/sms-tracking.png" alt="">
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="total-comparison">
|
||||
<el-icon class="trend-icon green">
|
||||
<img src="/src/assets/demo/up.png" alt="上升">
|
||||
</el-icon>
|
||||
<span class="comparison-text green">8台</span>
|
||||
<span class="period-text">较上月同期</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 已处理报警 -->
|
||||
<div class="total-view-card green-border">
|
||||
<div class="total-content">
|
||||
<div class="content-row">
|
||||
<div class="left-section">
|
||||
<div class="total-header">
|
||||
<span class="total-title">已处理报警</span>
|
||||
</div>
|
||||
<div class="total-number">20</div>
|
||||
</div>
|
||||
<div class="icon-section">
|
||||
<el-icon class="total-icon green">
|
||||
<img src="@/assets/demo/archive.png" alt="">
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="total-comparison">
|
||||
<el-icon class="trend-icon green">
|
||||
<img src="/src/assets/demo/up.png" alt="上升">
|
||||
</el-icon>
|
||||
<span class="comparison-text green">8台</span>
|
||||
<span class="period-text">较上月同期</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 严重报警 -->
|
||||
<div class="total-view-card orange-border">
|
||||
<div class="total-content">
|
||||
<div class="content-row">
|
||||
<div class="left-section">
|
||||
<div class="total-header">
|
||||
<span class="total-title">严重报警</span>
|
||||
</div>
|
||||
<div class="total-number">3</div>
|
||||
</div>
|
||||
<div class="icon-section">
|
||||
<el-icon class="total-icon orange">
|
||||
<img src="@/assets/demo/mouse-square.png" alt="">
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="total-comparison">
|
||||
<el-icon class="trend-icon green">
|
||||
<img src="/src/assets/demo/up.png" alt="上升">
|
||||
</el-icon>
|
||||
<span class="comparison-text green">8台</span>
|
||||
<span class="period-text">较上月同期</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.total-view-dashboard {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.total-view-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
height: 150px;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.total-view-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 左侧边框样式 - 使用伪元素创建与指定内容高度一致的边框 */
|
||||
.total-view-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 42px;
|
||||
width: 4px;
|
||||
height: 45px;
|
||||
border-radius: 0 2px 2px 0;
|
||||
transition: height 0.3s ease;
|
||||
}
|
||||
|
||||
.total-view-card:hover::before {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.blue-border::before {
|
||||
background-color: #0080FC;
|
||||
}
|
||||
|
||||
.blue-border {
|
||||
background-color: #EAF5FF;
|
||||
}
|
||||
|
||||
/* 添加卡片背景渐变效果 */
|
||||
.total-view-card::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.3) 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.purple-border::before {
|
||||
background-color: #722ed1;
|
||||
}
|
||||
|
||||
.purple-border {
|
||||
background-color: #F3EDFF;
|
||||
}
|
||||
|
||||
.green-border::before {
|
||||
background-color: #009B72;
|
||||
}
|
||||
|
||||
.green-border {
|
||||
background-color: #E8FFF9;
|
||||
}
|
||||
|
||||
.orange-border::before {
|
||||
background-color: #fa8c16;
|
||||
}
|
||||
|
||||
.orange-border {
|
||||
background-color: #FFF6EC;
|
||||
}
|
||||
|
||||
.total-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.content-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.left-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.icon-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.total-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.total-title {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.total-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.total-icon.blue {
|
||||
background-color: #DBEEFF;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.total-icon.purple {
|
||||
background-color: #E9DEFF;
|
||||
color: #722ed1;
|
||||
}
|
||||
|
||||
.total-icon.green {
|
||||
background-color: #CEFFF2;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.total-icon.orange {
|
||||
background-color: #FFEBD3;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
.total-number {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.total-comparison {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.trend-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.trend-icon.green {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.comparison-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.comparison-text.green {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.period-text {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
.total-view-dashboard {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.total-view-card {
|
||||
flex: 0 0 calc(50% - 8px);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.total-view-card {
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
93
src/views/integratedManage/alarmManage/index.vue
Normal file
93
src/views/integratedManage/alarmManage/index.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="model">
|
||||
<!-- 标题栏 -->
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<TitleComponent title="报警管理" subtitle="配置新能源厂站的报警级别、类型及相关规则" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第一行:报警管理和报警级别分布 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="16">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警管理" :font-level="2" />
|
||||
<totalView />
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<!-- 报警级别分布 -->
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警级别分布" :font-level="2" />
|
||||
<levelPie />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第二行:报警趋势分析 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警趋势分析" :font-level="2" />
|
||||
<fenxiBar />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第三行:报警级别设置 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警级别设置" :font-level="2" />
|
||||
<levelSet />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import TitleComponent from '@/components/TitleComponent/index.vue';
|
||||
import levelPie from '@/views/integratedManage/alarmManage/components/levelPie.vue'
|
||||
import fenxiBar from '@/views/integratedManage/alarmManage/components/fenxiBar.vue'
|
||||
import totalView from '@/views/integratedManage/alarmManage/components/totalView.vue';
|
||||
import levelSet from '@/views/integratedManage/alarmManage/components/levelSet.vue';
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.model {
|
||||
padding: 20px 15px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
|
||||
.content-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.custom-card {
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.custom-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 响应式布局调整 */
|
||||
@media (max-width: 1200px) {
|
||||
.content-row {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.model {
|
||||
padding: 15px 10px;
|
||||
}
|
||||
|
||||
.content-row {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
332
src/views/integratedManage/stateManage/components/manageForm.vue
Normal file
332
src/views/integratedManage/stateManage/components/manageForm.vue
Normal file
@ -0,0 +1,332 @@
|
||||
<template>
|
||||
<div class="manage-form-container">
|
||||
<!-- 搜索和筛选区域 -->
|
||||
|
||||
<!-- 设备信息表格 -->
|
||||
<el-table v-loading="loading" :data="deviceList" style="width: 100%" height="calc(100vh - 300px)">
|
||||
<el-table-column prop="deviceId" label="设备ID" min-width="120" align="center" />
|
||||
<el-table-column prop="deviceName" label="设备名称" min-width="120" align="center" />
|
||||
<el-table-column prop="deviceType" label="类型" min-width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getDeviceTypeTagType(scope.row.deviceType)" :effect="'light'">
|
||||
{{ scope.row.deviceType }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="station" label="所属电站" min-width="120" align="center" />
|
||||
<el-table-column prop="protocol" label="通讯协议" min-width="100" align="center" />
|
||||
<el-table-column prop="ipAddress" label="IP地址" min-width="120" align="center" />
|
||||
<el-table-column prop="lastOnlineTime" label="最后在线时间" min-width="150" align="center" />
|
||||
<el-table-column prop="status" label="状态" min-width="80">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getStatusTagType(scope.row.status)" :effect="getStatusTagEffect(scope.row.status)">
|
||||
{{ getStatusText(scope.row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="150" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link @click="handleDetails(scope.row)" size="small">
|
||||
查看
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="handleConfig(scope.row)" size="small">
|
||||
配置
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="handleDelete(scope.row)" size="small">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页区域 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination v-model:current-page="pagination.currentPage" v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pagination.total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
|
||||
|
||||
// 搜索表单数据
|
||||
const searchForm = reactive({
|
||||
deviceType: '',
|
||||
station: '',
|
||||
protocol: '',
|
||||
status: '',
|
||||
keyword: ''
|
||||
});
|
||||
|
||||
// 表格加载状态
|
||||
const loading = ref(false);
|
||||
|
||||
// 分页数据
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 545
|
||||
});
|
||||
|
||||
// 设备列表数据
|
||||
const deviceList = ref([
|
||||
{
|
||||
deviceId: 'WO-2023-0620-056',
|
||||
deviceName: '逆变器-01',
|
||||
deviceType: '逆变器',
|
||||
station: '兴电基站1',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'normal'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-057',
|
||||
deviceName: '温度传感器-45',
|
||||
deviceType: '传感器',
|
||||
station: '兴电基站2',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'interrupt'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-058',
|
||||
deviceName: '智能电表-03',
|
||||
deviceType: '电表',
|
||||
station: '兴电基站3',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'abnormal'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-059',
|
||||
deviceName: '监控摄像头-02',
|
||||
deviceType: '摄像头',
|
||||
station: '兴电基站4',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'normal'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-060',
|
||||
deviceName: '控制器-07',
|
||||
deviceType: '控制器',
|
||||
station: '兴电基站5',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'normal'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-061',
|
||||
deviceName: '逆变器-02',
|
||||
deviceType: '逆变器',
|
||||
station: '兴电基站1',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'normal'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-062',
|
||||
deviceName: '电流传感器-08',
|
||||
deviceType: '传感器',
|
||||
station: '兴电基站1',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'normal'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-063',
|
||||
deviceName: '多功能电表-12',
|
||||
deviceType: '电表',
|
||||
station: '兴电基站1',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'normal'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-064',
|
||||
deviceName: '门禁摄像头-05',
|
||||
deviceType: '摄像头',
|
||||
station: '兴电基站1',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'normal'
|
||||
},
|
||||
{
|
||||
deviceId: 'WO-2023-0620-065',
|
||||
deviceName: '开关控制器-15',
|
||||
deviceType: '控制器',
|
||||
station: '兴电基站1',
|
||||
protocol: 'Modbus TCP',
|
||||
ipAddress: '192.168.1.101',
|
||||
lastOnlineTime: '2023-06-30 17:00',
|
||||
status: 'normal'
|
||||
}
|
||||
]);
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
normal: '正常',
|
||||
interrupt: '中断',
|
||||
abnormal: '异常'
|
||||
};
|
||||
return statusMap[status] || status;
|
||||
};
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusTagType = (status) => {
|
||||
const typeMap = {
|
||||
normal: 'success',
|
||||
interrupt: 'warning',
|
||||
abnormal: 'danger'
|
||||
};
|
||||
return typeMap[status] || 'default';
|
||||
};
|
||||
|
||||
// 获取状态标签效果
|
||||
const getStatusTagEffect = (status) => {
|
||||
// 正常状态使用浅色效果,其他状态使用深色效果
|
||||
return status === 'normal' ? 'light' : 'dark';
|
||||
};
|
||||
|
||||
// 获取设备类型标签类型
|
||||
const getDeviceTypeTagType = (deviceType) => {
|
||||
const typeMap = {
|
||||
'逆变器': 'primary',
|
||||
'传感器': 'success',
|
||||
'电表': 'warning',
|
||||
'摄像头': 'info',
|
||||
'控制器': 'danger'
|
||||
};
|
||||
return typeMap[deviceType] || 'default';
|
||||
};
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
loading.value = true;
|
||||
// 模拟搜索请求
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
ElMessage.success('搜索成功');
|
||||
// 实际项目中这里应该调用API获取数据
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// 处理添加设备
|
||||
const handleAddDevice = () => {
|
||||
// 实际项目中这里应该打开添加设备的弹窗或跳转到添加页面
|
||||
ElMessage.success('打开添加设备窗口');
|
||||
};
|
||||
|
||||
// 处理批量配置
|
||||
const handleBatchConfig = () => {
|
||||
// 实际项目中这里应该打开批量配置的弹窗
|
||||
ElMessage.success('打开批量配置窗口');
|
||||
};
|
||||
|
||||
// 处理查看详情
|
||||
const handleDetails = (row) => {
|
||||
// 实际项目中这里应该打开设备详情的弹窗或跳转到详情页面
|
||||
ElMessage.success(`查看设备${row.deviceCode}详情`);
|
||||
};
|
||||
|
||||
// 处理配置
|
||||
const handleConfig = (row) => {
|
||||
// 实际项目中这里应该打开设备配置的弹窗
|
||||
ElMessage.success(`配置设备${row.deviceCode}`);
|
||||
};
|
||||
|
||||
// 处理删除
|
||||
const handleDelete = (row) => {
|
||||
ElMessageBox.confirm(
|
||||
`确定要删除设备${row.deviceCode}吗?`,
|
||||
'提示',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
// 实际项目中这里应该调用API删除设备
|
||||
ElMessage.success('删除成功');
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消删除');
|
||||
});
|
||||
};
|
||||
|
||||
// 处理分页大小变化
|
||||
const handleSizeChange = (size) => {
|
||||
pagination.pageSize = size;
|
||||
// 实际项目中这里应该重新请求数据
|
||||
};
|
||||
|
||||
// 处理分页页码变化
|
||||
const handleCurrentChange = (current) => {
|
||||
pagination.currentPage = current;
|
||||
// 实际项目中这里应该重新请求数据
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.manage-form-container {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 表格样式优化 */
|
||||
:deep(.el-table) {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.el-table__header-wrapper) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
:deep(.el-table__row:hover) {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
/* 分页样式优化 */
|
||||
:deep(.el-pagination) {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
214
src/views/integratedManage/stateManage/components/stateTrend.vue
Normal file
214
src/views/integratedManage/stateManage/components/stateTrend.vue
Normal file
@ -0,0 +1,214 @@
|
||||
|
||||
<template>
|
||||
<div class="chart-container">
|
||||
<!--组件温度(℃) 图表内容区域 -->
|
||||
<div ref="chartRef" class="chart-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
|
||||
// 图表DOM引用
|
||||
const chartRef = ref(null);
|
||||
// 图表实例
|
||||
let chartInstance = null;
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (chartRef.value && !chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
// 坐标轴指示器,坐标轴触发有效
|
||||
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
left: '8%',
|
||||
icon: 'square',
|
||||
itemWidth: 12,
|
||||
itemHeight: 12,
|
||||
textStyle: {
|
||||
color: '#4E5969'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#4E5969'
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#EAEBF0'
|
||||
}
|
||||
},
|
||||
data: ['9-12', '9-13', '9-14', '9-15', '9-16', '9-17', '9-18']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
max: 150,
|
||||
interval: 50,
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#4E5969'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#EAEBF0',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '正常',
|
||||
data: [20, 10, 50, 80, 70, 10, 30],
|
||||
type: 'bar',
|
||||
stack: 'one',
|
||||
color: '#7339F5',
|
||||
itemStyle: {
|
||||
// borderWidth: 1,
|
||||
borderColor: 'rgba(255, 255, 255, 1)', //同背景色一样
|
||||
barBorderRadius: 8
|
||||
},
|
||||
barWidth: '20',
|
||||
},
|
||||
{
|
||||
name: '中断',
|
||||
data: [80, 30, 50, 80, 70, 10, 30],
|
||||
type: 'bar',
|
||||
stack: 'one', //堆叠
|
||||
color: '#FF8A00',
|
||||
itemStyle: {
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255, 255, 255, 1)', //同背景色一样
|
||||
barBorderRadius: 8
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '异常',
|
||||
data: [50, 30, 50, 80, 70, 10, 30],
|
||||
type: 'bar',
|
||||
stack: 'one', //堆叠
|
||||
color: '#DE4848',
|
||||
itemStyle: {
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255, 255, 255, 1)', //同背景色一样
|
||||
barBorderRadius: 8
|
||||
},
|
||||
barWidth: '12',
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 响应窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.chart-header h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.chart-actions button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
201
src/views/integratedManage/stateManage/components/statusPie.vue
Normal file
201
src/views/integratedManage/stateManage/components/statusPie.vue
Normal file
@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div class="chart-container">
|
||||
<!--组件温度(℃) 图表内容区域 -->
|
||||
<div ref="chartRef" class="chart-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
|
||||
// 图表DOM引用
|
||||
const chartRef = ref(null);
|
||||
// 图表实例
|
||||
let chartInstance = null;
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (chartRef.value && !chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: function(params) {
|
||||
// 定义名称映射关系
|
||||
const nameMap = {
|
||||
'提示信息': '设备正常',
|
||||
'一般告警': '设备中断',
|
||||
'重要告警': '设备异常'
|
||||
};
|
||||
// 使用ECharts提供的百分比值
|
||||
const percentage = params.percent.toFixed(1);
|
||||
// 返回格式化后的文本
|
||||
return `${nameMap[params.name]}: ${params.value}台 (${percentage}%)`;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '0%',
|
||||
right: '20%',
|
||||
bottom: '0%',
|
||||
top: '0%',
|
||||
containLabel: true
|
||||
},
|
||||
legend: {
|
||||
top: 'middle',
|
||||
orient: 'vertical',
|
||||
right: '5%', // 调整图例位置,使其更靠近左侧
|
||||
itemWidth: 15,
|
||||
itemHeight: 15,
|
||||
formatter: function(name) {
|
||||
// 定义名称映射关系
|
||||
const nameMap = {
|
||||
'提示信息': '设备正常',
|
||||
'一般告警': '设备中断',
|
||||
'重要告警': '设备异常'
|
||||
};
|
||||
// 定义数值映射关系
|
||||
const valueMap = {
|
||||
'提示信息': 28,
|
||||
'一般告警': 45,
|
||||
'重要告警': 55
|
||||
};
|
||||
// 返回格式化后的文本
|
||||
return `${nameMap[name] || name}(${valueMap[name]})`;
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
labelLine: {
|
||||
show: true
|
||||
},
|
||||
color: [
|
||||
'#43CF7C', // 设备正常
|
||||
'#00B3FF', // 设备中断
|
||||
'#FB3E7A', // 设备异常
|
||||
],
|
||||
data: [
|
||||
{ value: 28, name: '提示信息' },
|
||||
{ value: 45, name: '一般告警' },
|
||||
{ value: 55, name: '重要告警' },
|
||||
],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 响应窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.chart-header h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.chart-actions button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
padding: 20px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
</style>
|
||||
93
src/views/integratedManage/stateManage/index.vue
Normal file
93
src/views/integratedManage/stateManage/index.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="model">
|
||||
<!-- 标题栏 -->
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<TitleComponent title="报警管理" subtitle="配置新能源厂站的报警级别、类型及相关规则" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第一行:报警管理和报警级别分布 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="16">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警管理" :font-level="2" />
|
||||
<totalView />
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<!-- 报警级别分布 -->
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警级别分布" :font-level="2" />
|
||||
<statusPie />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第二行:报警趋势分析 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警趋势分析" :font-level="2" />
|
||||
<stateTrend />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第三行:报警管理表单 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警管理表单" :font-level="2" />
|
||||
<manageForm />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import TitleComponent from '@/components/TitleComponent/index.vue';
|
||||
import totalView from '@/views/integratedManage/alarmManage/components/totalView.vue';
|
||||
import stateTrend from '@/views/integratedManage/stateManage/components/stateTrend.vue'
|
||||
import statusPie from '@/views/integratedManage/stateManage/components/statusPie.vue'
|
||||
import manageForm from '@/views/integratedManage/stateManage/components/manageForm.vue';
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.model {
|
||||
padding: 20px 15px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
|
||||
.content-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.custom-card {
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.custom-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 响应式布局调整 */
|
||||
@media (max-width: 1200px) {
|
||||
.content-row {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.model {
|
||||
padding: 15px 10px;
|
||||
}
|
||||
|
||||
.content-row {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -18,8 +18,12 @@
|
||||
<div class="metric-value">{{ props.dashboardData.todayAlarmTotal }}</div>
|
||||
<div class="metric-label">今日报警总数</div>
|
||||
<div class="metric-change">较上周 <span :class="props.dashboardData.updates.todayAlarmTotal.type">
|
||||
{{ props.dashboardData.updates.todayAlarmTotal.type === 'up' ? '↑' : '↓' }}{{ props.dashboardData.updates.todayAlarmTotal.value }}
|
||||
</span></div>
|
||||
<img v-if="props.dashboardData.updates.todayAlarmTotal.type === 'up'" src="/src/assets/demo/up.png"
|
||||
class="trend-icon" alt="上升">
|
||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
||||
props.dashboardData.updates.todayAlarmTotal.value }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
@ -29,8 +33,11 @@
|
||||
<div class="metric-value">{{ props.dashboardData.unhandledAlarms }}</div>
|
||||
<div class="metric-label">未处理报警</div>
|
||||
<div class="metric-change">较上周 <span :class="props.dashboardData.updates.unhandledAlarms.type">
|
||||
{{ props.dashboardData.updates.unhandledAlarms.type === 'up' ? '↑' : '↓' }}{{ props.dashboardData.updates.unhandledAlarms.value }}
|
||||
</span></div>
|
||||
<img v-if="props.dashboardData.updates.unhandledAlarms.type === 'up'" src="/src/assets/demo/up.png"
|
||||
class="trend-icon" alt="上升">
|
||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
||||
props.dashboardData.updates.unhandledAlarms.value }}
|
||||
</span></div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
@ -40,8 +47,11 @@
|
||||
<div class="metric-value">{{ props.dashboardData.handledAlarms }}</div>
|
||||
<div class="metric-label">已处理报警</div>
|
||||
<div class="metric-change">较上周 <span :class="props.dashboardData.updates.handledAlarms.type">
|
||||
{{ props.dashboardData.updates.handledAlarms.type === 'up' ? '↑' : '↓' }}{{ props.dashboardData.updates.handledAlarms.value }}
|
||||
</span></div>
|
||||
<img v-if="props.dashboardData.updates.handledAlarms.type === 'up'" src="/src/assets/demo/up.png"
|
||||
class="trend-icon" alt="上升">
|
||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
||||
props.dashboardData.updates.handledAlarms.value }}
|
||||
</span></div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
@ -50,9 +60,15 @@
|
||||
<div class="metric-card">
|
||||
<div class="metric-value">{{ props.dashboardData.avgProcessTime }}</div>
|
||||
<div class="metric-label">平均处理时长</div>
|
||||
<div class="metric-change">较上周 <span :class="props.dashboardData.updates.avgProcessTime.type">
|
||||
{{ props.dashboardData.updates.avgProcessTime.type === 'up' ? '↑' : '↓' }}{{ props.dashboardData.updates.avgProcessTime.value }}
|
||||
</span></div>
|
||||
<div class="metric-change">
|
||||
较上周
|
||||
<span :class="props.dashboardData.updates.avgProcessTime.type">
|
||||
<img v-if="props.dashboardData.updates.avgProcessTime.type === 'up'" src="/src/assets/demo/up.png"
|
||||
class="trend-icon" alt="上升">
|
||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
||||
props.dashboardData.updates.avgProcessTime.value }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -76,11 +92,17 @@
|
||||
<div class="chart-container">
|
||||
<div class="chart-left-right-layout">
|
||||
<div class="chart-info-container">
|
||||
<div class="chart-title">报警数量(次) </div>
|
||||
<div class="chart-title">报警数量(次) </div>
|
||||
<div class="chart-total">{{ props.chartData.totals.alarmCount }}</div>
|
||||
<div class="chart-value">较昨日 <span :class="props.chartData.dailyChanges.alarmCount.type">
|
||||
{{ props.chartData.dailyChanges.alarmCount.type === 'up' ? '↑' : '↓' }}{{ props.chartData.dailyChanges.alarmCount.value }}
|
||||
</span></div>
|
||||
<div class="chart-value">
|
||||
<span>较昨日</span>
|
||||
<img v-if="props.chartData.dailyChanges.processEfficiency.type === 'up'"
|
||||
src="/src/assets/demo/up.png" class="trend-icon" alt="上升">
|
||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">
|
||||
<span :class="props.chartData.dailyChanges.processEfficiency.type">
|
||||
{{ props.chartData.dailyChanges.processEfficiency.value }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="alarmCountRef" class="chart-content"></div>
|
||||
</div>
|
||||
@ -93,9 +115,15 @@
|
||||
<div class="chart-info-container">
|
||||
<div class="chart-title">报警处理效率(%)</div>
|
||||
<div class="chart-total">{{ props.chartData.totals.processEfficiency }}</div>
|
||||
<div class="chart-value">较昨日 <span :class="props.chartData.dailyChanges.processEfficiency.type">
|
||||
{{ props.chartData.dailyChanges.processEfficiency.type === 'up' ? '↑' : '↓' }}{{ props.chartData.dailyChanges.processEfficiency.value }}
|
||||
</span></div>
|
||||
<div class="chart-value">
|
||||
<span>较昨日</span>
|
||||
<img v-if="props.chartData.dailyChanges.processEfficiency.type === 'up'"
|
||||
src="/src/assets/demo/up.png" class="trend-icon" alt="上升">
|
||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">
|
||||
<span :class="props.chartData.dailyChanges.processEfficiency.type">
|
||||
{{ props.chartData.dailyChanges.processEfficiency.value }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="processEfficiencyRef" class="chart-content"></div>
|
||||
</div>
|
||||
@ -141,7 +169,7 @@ const props = defineProps({
|
||||
processEfficiency: '89%'
|
||||
},
|
||||
dailyChanges: {
|
||||
alarmCount: { value: '0.9%', type: 'down' },
|
||||
alarmCount: { value: '0.9%', type: 'up' },
|
||||
processEfficiency: { value: '0.9%', type: 'down' }
|
||||
}
|
||||
})
|
||||
@ -172,7 +200,7 @@ const initCharts = () => {
|
||||
trigger: 'axis',
|
||||
},
|
||||
grid: {
|
||||
left: '-45px',
|
||||
left: '-38px',
|
||||
right: '0%',
|
||||
bottom: '0%',
|
||||
top: '0%',
|
||||
@ -248,7 +276,7 @@ const initCharts = () => {
|
||||
trigger: 'axis',
|
||||
},
|
||||
grid: {
|
||||
left: '-45px',
|
||||
left: '-38px',
|
||||
right: '0%',
|
||||
bottom: '0%',
|
||||
top: '0%',
|
||||
@ -352,7 +380,7 @@ onUnmounted(() => {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
padding:0 20px;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@ -411,11 +439,18 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.up {
|
||||
color: #ff4d4f;
|
||||
color: #00B87A;
|
||||
}
|
||||
|
||||
.down {
|
||||
color: #52c41a;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.trend-icon {
|
||||
// width: 12px;
|
||||
// height: 12px;
|
||||
margin-right: 2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.trend-container {
|
||||
@ -483,6 +518,24 @@ onUnmounted(() => {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.chart-value span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.chart-value .trend-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
|
||||
@ -68,9 +68,9 @@ const dashboardData = ref({
|
||||
handledAlarms: 16,
|
||||
avgProcessTime: '42分钟',
|
||||
updates: {
|
||||
todayAlarmTotal: { value: '4.2%', type: 'down' },
|
||||
unhandledAlarms: { value: '5%', type: 'up' },
|
||||
handledAlarms: { value: '8%', type: 'down' },
|
||||
todayAlarmTotal: { value: '4.2%', type: 'up' },
|
||||
unhandledAlarms: { value: '5%', type: 'down' },
|
||||
handledAlarms: { value: '8%', type: 'up' },
|
||||
avgProcessTime: { value: '10%', type: 'down' }
|
||||
}
|
||||
});
|
||||
@ -84,7 +84,7 @@ const chartData = ref({
|
||||
processEfficiency: '89%'
|
||||
},
|
||||
dailyChanges: {
|
||||
alarmCount: { value: '0.9%', type: 'down' },
|
||||
alarmCount: { value: '0.9%', type: 'up' },
|
||||
processEfficiency: { value: '0.9%', type: 'down' }
|
||||
}
|
||||
});
|
||||
@ -155,7 +155,7 @@ onMounted(() => {
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.model {
|
||||
padding: 0px 15px;
|
||||
padding: 20px 15px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
</style>
|
||||
@ -6,14 +6,8 @@
|
||||
<div class="card-title">总发电量</div>
|
||||
<div class="card-value">{{ props.statusData.totalPower }}</div>
|
||||
<div class="card-change positive">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18"
|
||||
height="18" viewBox="0 0 18 18" fill="none">
|
||||
<path
|
||||
d="M15.15 5.77505L15.15 5.70006L15.15 5.62505L15.075 5.62505C15.075 5.62505 15 5.62505 14.925 5.55005L11.25 5.55005C10.875 5.55005 10.575 5.85005 10.575 6.22505C10.575 6.60006 10.875 6.90005 11.25 6.90005L13.125 6.90005L9.52501 10.5L7.72501 8.70005C7.35 8.32505 6.60001 8.32505 6.225 8.70005L3.075 11.85C2.85 12.075 2.85 12.525 3.075 12.75C3.22501 12.9001 3.37501 12.975 3.525 12.975C3.67501 12.975 3.82501 12.975 3.975 12.75L6.9 9.82505L8.7 11.625C9.07501 12.0001 9.825 12.0001 10.2 11.625L13.95 7.87505L13.95 9.75006C13.95 10.1251 14.25 10.4251 14.625 10.4251C15 10.4251 15.3 10.1251 15.3 9.75006L15.3 6.37506L15.3 6.15006L15.15 5.77505Z"
|
||||
fill="#00B87A">
|
||||
</path>
|
||||
</svg>
|
||||
{{ props.statusData.totalPowerChange }} 较上周
|
||||
<img src="/src/assets/demo/up.png" alt="" class="change-icon">
|
||||
<span>{{ props.statusData.totalPowerChange }} 较上周</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-right">
|
||||
@ -37,14 +31,8 @@
|
||||
<div class="card-title">系统效率</div>
|
||||
<div class="card-value">{{ props.statusData.efficiency }}</div>
|
||||
<div class="card-change negative">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18"
|
||||
height="18" viewBox="0 0 18 18" fill="none">
|
||||
<path
|
||||
d="M15.15 12.2252L15.15 12.3002L15.15 12.3752L15.075 12.3752C15.075 12.3752 15 12.3752 14.925 12.4502L11.25 12.4502C10.875 12.4502 10.575 12.1502 10.575 11.7752C10.575 11.4002 10.875 11.1002 11.25 11.1002L13.125 11.1002L9.52501 7.5002L7.72501 9.3002C7.35 9.67519 6.60001 9.67519 6.225 9.3002L3.075 6.1502C2.85 5.9252 2.85 5.4752 3.075 5.2502C3.22501 5.10019 3.37501 5.0252 3.525 5.0252C3.67501 5.0252 3.82501 5.0252 3.975 5.2502L6.9 8.1752L8.7 6.3752C9.07501 6.00019 9.825 6.00019 10.2 6.3752L13.95 10.1252L13.95 8.25019C13.95 7.87519 14.25 7.57519 14.625 7.57519C15 7.57519 15.3 7.87519 15.3 8.25019L15.3 11.6252L15.3 11.8502L15.15 12.2252Z"
|
||||
fill="#E32727">
|
||||
</path>
|
||||
</svg>
|
||||
{{ props.statusData.efficiencyChange }} 较上周
|
||||
<img src="/src/assets/demo/down.png" alt="" class="change-icon">
|
||||
<span>{{ props.statusData.efficiencyChange }} 较上周</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-right">
|
||||
@ -65,14 +53,8 @@
|
||||
<div class="card-title">组件温度</div>
|
||||
<div class="card-value">{{ props.statusData.temperature }}</div>
|
||||
<div class="card-change positive">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18"
|
||||
height="18" viewBox="0 0 18 18" fill="none">
|
||||
<path
|
||||
d="M15.15 5.77505L15.15 5.70006L15.15 5.62505L15.075 5.62505C15.075 5.62505 15 5.62505 14.925 5.55005L11.25 5.55005C10.875 5.55005 10.575 5.85005 10.575 6.22505C10.575 6.60006 10.875 6.90005 11.25 6.90005L13.125 6.90005L9.52501 10.5L7.72501 8.70005C7.35 8.32505 6.60001 8.32505 6.225 8.70005L3.075 11.85C2.85 12.075 2.85 12.525 3.075 12.75C3.22501 12.9001 3.37501 12.975 3.525 12.975C3.67501 12.975 3.82501 12.975 3.975 12.75L6.9 9.82505L8.7 11.625C9.07501 12.0001 9.825 12.0001 10.2 11.625L13.95 7.87505L13.95 9.75006C13.95 10.1251 14.25 10.4251 14.625 10.4251C15 10.4251 15.3 10.1251 15.3 9.75006L15.3 6.37506L15.3 6.15006L15.15 5.77505Z"
|
||||
fill="#00B87A">
|
||||
</path>
|
||||
</svg>
|
||||
{{ props.statusData.temperatureChange }} 较上周
|
||||
<img src="/src/assets/demo/up.png" alt="" class="change-icon">
|
||||
<span>{{ props.statusData.temperatureChange }} 较上周</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-right">
|
||||
@ -93,14 +75,8 @@
|
||||
<div class="card-title">日照强度</div>
|
||||
<div class="card-value">{{ props.statusData.sunlight }}</div>
|
||||
<div class="card-change positive">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18"
|
||||
height="18" viewBox="0 0 18 18" fill="none">
|
||||
<path
|
||||
d="M15.15 5.77505L15.15 5.70006L15.15 5.62505L15.075 5.62505C15.075 5.62505 15 5.62505 14.925 5.55005L11.25 5.55005C10.875 5.55005 10.575 5.85005 10.575 6.22505C10.575 6.60006 10.875 6.90005 11.25 6.90005L13.125 6.90005L9.52501 10.5L7.72501 8.70005C7.35 8.32505 6.60001 8.32505 6.225 8.70005L3.075 11.85C2.85 12.075 2.85 12.525 3.075 12.75C3.22501 12.9001 3.37501 12.975 3.525 12.975C3.67501 12.975 3.82501 12.975 3.975 12.75L6.9 9.82505L8.7 11.625C9.07501 12.0001 9.825 12.0001 10.2 11.625L13.95 7.87505L13.95 9.75006C13.95 10.1251 14.25 10.4251 14.625 10.4251C15 10.4251 15.3 10.1251 15.3 9.75006L15.3 6.37506L15.3 6.15006L15.15 5.77505Z"
|
||||
fill="#00B87A">
|
||||
</path>
|
||||
</svg>
|
||||
{{ props.statusData.sunlightChange }} 较上周
|
||||
<img src="/src/assets/demo/up.png" alt="" class="change-icon">
|
||||
<span>{{ props.statusData.sunlightChange }} 较上周</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-right">
|
||||
@ -206,7 +182,7 @@ const props = defineProps({
|
||||
margin-top: 4px;
|
||||
|
||||
&.positive {
|
||||
color: #67c23a;
|
||||
color: #00B87A;
|
||||
}
|
||||
|
||||
&.negative {
|
||||
@ -216,7 +192,7 @@ const props = defineProps({
|
||||
|
||||
.change-icon {
|
||||
font-size: 10px;
|
||||
margin-right: 2px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
|
||||
@ -142,7 +142,7 @@ onUnmounted(() => {
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: calc(100% - 80px);
|
||||
min-height: 200px;
|
||||
min-height: 220px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
@ -185,7 +185,7 @@ onUnmounted(() => {
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: calc(100% - 80px);
|
||||
min-height: 200px;
|
||||
min-height: 220px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
@ -104,7 +104,7 @@ const mockData = ref({
|
||||
totalPower: '3,456.8KWh',
|
||||
totalPowerChange: '8.2%',
|
||||
efficiency: '18.7%',
|
||||
efficiencyChange: '-0.3%',
|
||||
efficiencyChange: '0.3%',
|
||||
temperature: '42.3°C',
|
||||
temperatureChange: '2.1°C',
|
||||
sunlight: '865 W/m²',
|
||||
|
||||
@ -8,7 +8,8 @@
|
||||
</div>
|
||||
<div class="power-amount">{{ value || '2,456.8' }} <span>{{ unit || 'KWh' }}</span></div>
|
||||
<div class="power-growth">
|
||||
<span class="growth-value">{{ growth || '+2.5%' }}</span>
|
||||
<img :src="type === 'up' ? '/src/assets/demo/up.png' : '/src/assets/demo/down.png'" alt="">
|
||||
<span :class="type === 'up' ? 'up' : 'down'">{{ growth+'%' || '2.5'+'%' }}</span>
|
||||
<span class="growth-label">{{ growthLabel || '较昨日' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -37,6 +38,10 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '平均效率'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: '2,456.8'
|
||||
@ -247,11 +252,14 @@ onUnmounted(() => {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.growth-value {
|
||||
font-size: 14px;
|
||||
color: #13C2C2;
|
||||
.up{
|
||||
font-size: 14px;
|
||||
color:#00B87A;
|
||||
}
|
||||
.down{
|
||||
font-size: 14px;
|
||||
color:#ff4d4f;
|
||||
}
|
||||
|
||||
.growth-label {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
|
||||
@ -43,25 +43,20 @@
|
||||
</el-row>
|
||||
<!-- 数据展示-->
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="6">
|
||||
<itembox title="总发电量" value="2,456.8" unit="KWh" growth="+2.5%" growthLabel="较昨日" color="#186DF5"
|
||||
chartType="bar" power="" icon-src="/src/assets/demo/shandian.png"
|
||||
:chartData="[30, 50, 40, 60, 80, 70, 100, 90, 85, 75, 65, 55]"></itembox>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<itembox title="平均效率" value="18.7" unit="%" growth="+2.5%" growthLabel="较昨日" color="#00B87A"
|
||||
chartType="line" icon-src="/src/assets/demo/huojian.png"
|
||||
:chartData="[30, 50, 40, 60, 80, 70, 100, 90, 85, 75, 65, 55]"></itembox>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<itembox title="设备温度" value="43.5" unit="℃" growth="+2.5%" growthLabel="较昨日" color="#FFC300"
|
||||
chartType="line" icon-src="/src/assets/demo/wendu.png"
|
||||
:chartData="[30, 50, 40, 60, 80, 70, 100, 90, 85, 75, 65, 55]"></itembox>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<itembox title="系统可用性" value="18.7" unit="%" growth="+2.5%" growthLabel="较昨日" color="#7948EA"
|
||||
chartType="line" icon-src="/src/assets/demo/use.png"
|
||||
:chartData="[30, 50, 40, 60, 80, 70, 100, 90, 85, 75, 65, 55]"></itembox>
|
||||
<el-col :span="6" v-for="(item, index) in itemBoxData" :key="index">
|
||||
<itembox
|
||||
:title="item.title"
|
||||
:value="item.value"
|
||||
:unit="item.unit"
|
||||
:growth="item.growth"
|
||||
:growthLabel="item.growthLabel"
|
||||
:color="item.color"
|
||||
:chartType="item.chartType"
|
||||
:power="item.power"
|
||||
:icon-src="item.iconSrc"
|
||||
:type="item.type"
|
||||
:chartData="item.chartData">
|
||||
</itembox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 第一行图表 -->
|
||||
@ -159,6 +154,62 @@ const fenxiLineData = ref({
|
||||
}
|
||||
});
|
||||
|
||||
// 创建itembox数据数组,用于循环渲染
|
||||
const itemBoxData = ref([
|
||||
{
|
||||
title: '总发电量',
|
||||
value: '2,456.8',
|
||||
unit: 'KWh',
|
||||
growth: '2.5',
|
||||
growthLabel: '较昨日',
|
||||
color: '#186DF5',
|
||||
chartType: 'bar',
|
||||
power: '',
|
||||
iconSrc: '/src/assets/demo/shandian.png',
|
||||
type: 'up',
|
||||
chartData: [30, 50, 40, 60, 80, 70, 100, 90, 85, 75, 65, 55]
|
||||
},
|
||||
{
|
||||
title: '平均效率',
|
||||
value: '18.7',
|
||||
unit: '%',
|
||||
growth: '2.5',
|
||||
growthLabel: '较昨日',
|
||||
color: '#00B87A',
|
||||
chartType: 'line',
|
||||
power: '',
|
||||
iconSrc: '/src/assets/demo/huojian.png',
|
||||
type: 'up',
|
||||
chartData: [30, 50, 40, 60, 80, 70, 100, 90, 85, 75, 65, 55]
|
||||
},
|
||||
{
|
||||
title: '设备温度',
|
||||
value: '43.5',
|
||||
unit: '℃',
|
||||
growth: '2.5',
|
||||
growthLabel: '较昨日',
|
||||
color: '#FFC300',
|
||||
chartType: 'line',
|
||||
power: '',
|
||||
iconSrc: '/src/assets/demo/wendu.png',
|
||||
type: 'up',
|
||||
chartData: [30, 50, 40, 60, 80, 70, 100, 90, 85, 75, 65, 55]
|
||||
},
|
||||
{
|
||||
title: '系统可用性',
|
||||
value: '18.7',
|
||||
unit: '%',
|
||||
growth: '2.5',
|
||||
growthLabel: '较昨日',
|
||||
color: '#7948EA',
|
||||
chartType: 'line',
|
||||
power: '',
|
||||
iconSrc: '/src/assets/demo/use.png',
|
||||
type: 'up',
|
||||
chartData: [30, 50, 40, 60, 80, 70, 100, 90, 85, 75, 65, 55]
|
||||
}
|
||||
]);
|
||||
|
||||
const tableData = ref([
|
||||
{ time: '00:00', irradiance: 0, powerGeneration: 0.0, efficiency: 24.5, moduleTemperature: 23.5, inverterTemperature: 21.2, status: '停机' },
|
||||
{ time: '08:00', irradiance: 12.5, powerGeneration: 17.2, efficiency: 28.1, moduleTemperature: 26.3, inverterTemperature: 20.3, status: '正常' },
|
||||
|
||||
Reference in New Issue
Block a user