增加告警页面(带bug)
This commit is contained in:
333
src/views/alarm/ThresholdAlarmList.vue
Normal file
333
src/views/alarm/ThresholdAlarmList.vue
Normal file
@@ -0,0 +1,333 @@
|
||||
<template>
|
||||
<div class="threshold-alarm-list">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="title-container">
|
||||
<h2 class="page-title">阈值告警配置</h2>
|
||||
<el-button type="text" @click="loadData()" class="refresh-btn" title="刷新列表">
|
||||
<el-icon :size="20"><Refresh /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<el-button type="primary" @click="handleAddRule">新增规则</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
||||
<!-- 区域告警规则 -->
|
||||
<el-tab-pane label="区域告警" name="area">
|
||||
<el-table :data="areaAlarms.list" v-loading="loading">
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="area_controller_id" label="区域主控ID" min-width="120" />
|
||||
<el-table-column prop="sensor_type" label="传感器类型" min-width="120">
|
||||
<template #default="scope">{{ formatSensorType(scope.row.sensor_type) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="level" label="告警等级" min-width="100">
|
||||
<template #default="scope">{{ formatSeverity(scope.row.level) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="触发条件" min-width="150">
|
||||
<template #default="scope">
|
||||
{{ `${scope.row.operator} ${scope.row.thresholds}` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" align="center">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="handleEditRule(scope.row)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="handleDeleteRule(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination-container"
|
||||
:current-page="areaAlarms.pagination.currentPage"
|
||||
:page-size="areaAlarms.pagination.pageSize"
|
||||
:total="areaAlarms.pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 设备告警规则 -->
|
||||
<el-tab-pane label="设备告警" name="device">
|
||||
<el-table :data="deviceAlarms.list" v-loading="loading">
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="device_id" label="设备ID" min-width="120" />
|
||||
<el-table-column prop="sensor_type" label="传感器类型" min-width="120">
|
||||
<template #default="scope">{{ formatSensorType(scope.row.sensor_type) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="level" label="告警等级" min-width="100">
|
||||
<template #default="scope">{{ formatSeverity(scope.row.level) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="触发条件" min-width="150">
|
||||
<template #default="scope">
|
||||
{{ `${scope.row.operator} ${scope.row.thresholds}` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" align="center">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="handleEditRule(scope.row)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="handleDeleteRule(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination-container"
|
||||
:current-page="deviceAlarms.pagination.currentPage"
|
||||
:page-size="deviceAlarms.pagination.pageSize"
|
||||
:total="deviceAlarms.pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑规则' : '新增规则'" width="500px" @close="resetForm">
|
||||
<el-form :model="form" ref="ruleForm" label-width="100px">
|
||||
<el-form-item v-if="activeTab === 'area'" label="区域主控ID" prop="area_controller_id" required>
|
||||
<el-input v-model.number="form.area_controller_id" :disabled="isEdit"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="activeTab === 'device'" label="设备ID" prop="device_id" required>
|
||||
<el-input v-model.number="form.device_id" :disabled="isEdit"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="传感器类型" prop="sensor_type" required>
|
||||
<el-select v-model="form.sensor_type" placeholder="请选择" :disabled="isEdit">
|
||||
<el-option v-for="(label, key) in SensorType" :key="key" :label="label" :value="key"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="告警等级" prop="level" required>
|
||||
<el-select v-model="form.level" placeholder="请选择">
|
||||
<el-option v-for="(label, key) in SeverityLevel" :key="key" :label="label" :value="key"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作符" prop="operator" required>
|
||||
<el-select v-model="form.operator" placeholder="请选择">
|
||||
<el-option v-for="(label, key) in Operator" :key="key" :label="label" :value="key"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="阈值" prop="thresholds" required>
|
||||
<el-input-number v-model="form.thresholds"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Refresh } from '@element-plus/icons-vue';
|
||||
import { AlarmApi } from '../../api/alarm.js';
|
||||
import { SensorType, SeverityLevel, Operator } from '../../enums.js';
|
||||
|
||||
export default {
|
||||
name: 'ThresholdAlarmList',
|
||||
components: {
|
||||
Refresh,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
SensorType,
|
||||
SeverityLevel,
|
||||
Operator,
|
||||
activeTab: 'area',
|
||||
loading: false,
|
||||
areaAlarms: {
|
||||
list: [],
|
||||
pagination: { currentPage: 1, pageSize: 10, total: 0 },
|
||||
},
|
||||
deviceAlarms: {
|
||||
list: [],
|
||||
pagination: { currentPage: 1, pageSize: 10, total: 0 },
|
||||
},
|
||||
dialogVisible: false,
|
||||
isEdit: false,
|
||||
form: {
|
||||
id: null,
|
||||
area_controller_id: null,
|
||||
device_id: null,
|
||||
sensor_type: '',
|
||||
level: '',
|
||||
operator: '',
|
||||
thresholds: 0,
|
||||
},
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadData();
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 加载阈值告警数据
|
||||
* @param {string} [tabName] - 可选参数,当前激活的tab名称,用于确保调用正确的API
|
||||
*/
|
||||
async loadData(tabName) {
|
||||
this.loading = true;
|
||||
try {
|
||||
const currentTab = tabName || this.activeTab;
|
||||
if (currentTab === 'area') {
|
||||
const { currentPage, pageSize } = this.areaAlarms.pagination;
|
||||
const response = await AlarmApi.getAreaThresholdAlarms({ page: currentPage, page_size: pageSize });
|
||||
this.areaAlarms.list = response.list || [];
|
||||
this.areaAlarms.pagination.total = response.pagination?.total || 0;
|
||||
} else {
|
||||
const { currentPage, pageSize } = this.deviceAlarms.pagination;
|
||||
const response = await AlarmApi.getDeviceThresholdAlarms({ page: currentPage, page_size: pageSize });
|
||||
this.deviceAlarms.list = response.list || [];
|
||||
this.deviceAlarms.pagination.total = response.pagination?.total || 0;
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('加载告警规则失败: ' + (error.message || '未知错误'));
|
||||
console.error('加载告警规则失败:', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 处理标签页切换事件
|
||||
* @param {object} tab - 当前激活的tab对象
|
||||
*/
|
||||
handleTabClick(tab) {
|
||||
// 重置分页到第一页
|
||||
if (tab.paneName === 'area') {
|
||||
this.areaAlarms.pagination.currentPage = 1;
|
||||
} else {
|
||||
this.deviceAlarms.pagination.currentPage = 1;
|
||||
}
|
||||
this.loadData(tab.paneName); // 显式传递paneName
|
||||
},
|
||||
handleSizeChange(newSize) {
|
||||
const pagination = this.activeTab === 'area' ? this.areaAlarms.pagination : this.deviceAlarms.pagination;
|
||||
pagination.pageSize = newSize;
|
||||
this.loadData();
|
||||
},
|
||||
handlePageChange(newPage) {
|
||||
const pagination = this.activeTab === 'area' ? this.areaAlarms.pagination : this.deviceAlarms.pagination;
|
||||
pagination.currentPage = newPage;
|
||||
this.loadData();
|
||||
},
|
||||
handleAddRule() {
|
||||
this.isEdit = false;
|
||||
this.resetForm();
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
handleEditRule(rule) {
|
||||
this.isEdit = true;
|
||||
this.form = { ...rule };
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
async handleDeleteRule(rule) {
|
||||
try {
|
||||
await this.$confirm('确认删除这条规则吗?', '提示', { type: 'warning' });
|
||||
if (this.activeTab === 'area') {
|
||||
await AlarmApi.deleteAreaThresholdAlarm(rule.id);
|
||||
} else {
|
||||
// 注意:设备告警删除接口需要 sensor_type
|
||||
await AlarmApi.deleteDeviceThresholdAlarm(rule.id, { sensor_type: rule.sensor_type });
|
||||
}
|
||||
this.$message.success('删除成功');
|
||||
await this.loadData();
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
this.$message.error('删除失败: ' + (error.message || '未知错误'));
|
||||
}
|
||||
}
|
||||
},
|
||||
async submitForm() {
|
||||
try {
|
||||
await this.$refs.ruleForm.validate();
|
||||
const apiCall = this.isEdit ? this.updateRule : this.createRule;
|
||||
await apiCall();
|
||||
this.dialogVisible = false;
|
||||
this.$message.success(this.isEdit ? '更新成功' : '创建成功');
|
||||
} catch (error) {
|
||||
if (error) { // validation error
|
||||
console.log('表单验证失败');
|
||||
}
|
||||
} finally {
|
||||
await this.loadData();
|
||||
}
|
||||
},
|
||||
async createRule() {
|
||||
const { id, ...requestBody } = this.form;
|
||||
if (this.activeTab === 'area') {
|
||||
await AlarmApi.createAreaThresholdAlarm(requestBody);
|
||||
} else {
|
||||
await AlarmApi.createDeviceThresholdAlarm(requestBody);
|
||||
}
|
||||
},
|
||||
async updateRule() {
|
||||
const { id, ...requestBody } = this.form;
|
||||
if (this.activeTab === 'area') {
|
||||
await AlarmApi.updateAreaThresholdAlarm(id, requestBody);
|
||||
} else {
|
||||
await AlarmApi.updateDeviceThresholdAlarm(id, requestBody);
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.form = {
|
||||
id: null,
|
||||
area_controller_id: null,
|
||||
device_id: null,
|
||||
sensor_type: '',
|
||||
level: '',
|
||||
operator: '',
|
||||
thresholds: 0,
|
||||
};
|
||||
if (this.$refs.ruleForm) {
|
||||
this.$refs.ruleForm.resetFields();
|
||||
}
|
||||
},
|
||||
formatSensorType(type) {
|
||||
return SensorType[type] || type;
|
||||
},
|
||||
formatSeverity(level) {
|
||||
return SeverityLevel[level] || level;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.threshold-alarm-list {
|
||||
padding: 20px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.title-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
.refresh-btn {
|
||||
color: black;
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
}
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user