feat(alerts): 飞书通知支持 Web 界面配置(数据库存储+热更新)
1. 新增 notification_config 模型,飞书配置存数据库(单行id=1) 2. feishu_service 改为从数据库读配置,支持热更新,Web保存即生效 3. alerts.py 新增接口: - GET /alerts/notify/feishu/config 读配置(secret只返回是否已设) - PUT /alerts/notify/feishu/config 保存配置+热更新 (status/test 同步改为走数据库配置) 4. 前端告警中心增加「飞书通知设置」弹窗: - 开关/Webhook/签名密钥/最低级别/类型白名单 - 保存配置、发送测试按钮 5. alert_service.create_alert 推送时按数据库配置判断 配置无需改文件/重启,前端界面直接保存即生效。
This commit is contained in:
@@ -131,6 +131,19 @@ export const alertApi = {
|
||||
},
|
||||
removeFromWhitelist(id) {
|
||||
return api.delete(`/alerts/whitelist/macs/${id}`)
|
||||
},
|
||||
// 飞书通知配置
|
||||
getFeishuConfig() {
|
||||
return api.get('/alerts/notify/feishu/config')
|
||||
},
|
||||
saveFeishuConfig(data) {
|
||||
return api.put('/alerts/notify/feishu/config', {}, { params: data })
|
||||
},
|
||||
getFeishuStatus() {
|
||||
return api.get('/alerts/notify/feishu/status')
|
||||
},
|
||||
testFeishu() {
|
||||
return api.post('/alerts/notify/feishu/test')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
<el-icon><Check /></el-icon>
|
||||
全部确认
|
||||
</el-button>
|
||||
<el-button @click="openFeishuDialog">
|
||||
<el-icon><ChatDotRound /></el-icon>
|
||||
飞书通知设置
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</template>
|
||||
@@ -231,6 +235,47 @@
|
||||
<el-button type="primary" @click="addToWhitelist" :loading="submitting">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 飞书通知设置弹窗 -->
|
||||
<el-dialog v-model="feishuDialogVisible" title="飞书通知设置" width="560px">
|
||||
<el-alert type="info" :closable="false" style="margin-bottom: 16px"
|
||||
title="在飞书群添加「自定义机器人」,将 Webhook 地址填入下方即可。开启后,检测到新告警会自动推送到飞书群。"
|
||||
show-icon />
|
||||
<el-form label-width="110px" label-position="left">
|
||||
<el-form-item label="启用通知">
|
||||
<el-switch v-model="feishuForm.feishu_enabled" active-text="开启" inactive-text="关闭" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Webhook 地址">
|
||||
<el-input v-model="feishuForm.feishu_webhook_url" placeholder="https://open.feishu.cn/open-apis/bot/v2/hook/xxxx" />
|
||||
</el-form-item>
|
||||
<el-form-item label="签名密钥">
|
||||
<el-input v-model="feishuForm.feishu_secret" show-password
|
||||
:placeholder="feishuForm.feishu_secret_set ? '已设置(留空则不修改)' : '机器人开启签名校验时填写'" />
|
||||
<div class="form-tip">机器人开启「签名校验」时必填;未开启留空即可</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="最低级别">
|
||||
<el-select v-model="feishuForm.feishu_min_severity" style="width: 200px">
|
||||
<el-option label="全部 (info起)" value="info" />
|
||||
<el-option label="警告及以上" value="warning" />
|
||||
<el-option label="错误及以上" value="error" />
|
||||
<el-option label="仅严重" value="critical" />
|
||||
</el-select>
|
||||
<div class="form-tip">仅推送大于等于所选级别的告警</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型白名单">
|
||||
<el-input v-model="feishuForm.feishu_alert_types" placeholder="留空=全部推送;如 ip_conflict,device_offline" />
|
||||
<div class="form-tip">逗号分隔告警类型,留空则推送全部类型</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="color: #909399; font-size: 12px; margin-top: 8px;">
|
||||
配置保存后立即生效,无需重启服务。
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="feishuDialogVisible = false">关闭</el-button>
|
||||
<el-button @click="testFeishu" :loading="testing">发送测试</el-button>
|
||||
<el-button type="primary" @click="saveFeishuConfig" :loading="savingFeishu">保存配置</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -463,6 +508,67 @@ const getAlertTypeText = (type) => {
|
||||
|
||||
// 旧 formatDate 已由 @/utils/datetime 统一替代
|
||||
|
||||
// ---- 飞书通知配置 ----
|
||||
const feishuDialogVisible = ref(false)
|
||||
const savingFeishu = ref(false)
|
||||
const testing = ref(false)
|
||||
const feishuForm = reactive({
|
||||
feishu_enabled: false,
|
||||
feishu_webhook_url: '',
|
||||
feishu_secret: '',
|
||||
feishu_secret_set: false,
|
||||
feishu_min_severity: 'warning',
|
||||
feishu_alert_types: ''
|
||||
})
|
||||
|
||||
const openFeishuDialog = async () => {
|
||||
feishuDialogVisible.value = true
|
||||
try {
|
||||
const cfg = await alertApi.getFeishuConfig()
|
||||
feishuForm.feishu_enabled = !!cfg.feishu_enabled
|
||||
feishuForm.feishu_webhook_url = cfg.feishu_webhook_url || ''
|
||||
feishuForm.feishu_secret = ''
|
||||
feishuForm.feishu_secret_set = !!cfg.feishu_secret_set
|
||||
feishuForm.feishu_min_severity = cfg.feishu_min_severity || 'warning'
|
||||
feishuForm.feishu_alert_types = cfg.feishu_alert_types || ''
|
||||
} catch (error) {
|
||||
ElMessage.error('加载飞书配置失败')
|
||||
}
|
||||
}
|
||||
|
||||
const saveFeishuConfig = async () => {
|
||||
savingFeishu.value = true
|
||||
try {
|
||||
const params = {
|
||||
feishu_enabled: feishuForm.feishu_enabled,
|
||||
feishu_webhook_url: feishuForm.feishu_webhook_url,
|
||||
feishu_secret: feishuForm.feishu_secret,
|
||||
feishu_min_severity: feishuForm.feishu_min_severity,
|
||||
feishu_alert_types: feishuForm.feishu_alert_types
|
||||
}
|
||||
const res = await alertApi.saveFeishuConfig(params)
|
||||
ElMessage.success(res.message || '飞书配置已保存')
|
||||
feishuForm.feishu_secret = ''
|
||||
feishuForm.feishu_secret_set = true
|
||||
} catch (error) {
|
||||
ElMessage.error('保存飞书配置失败')
|
||||
} finally {
|
||||
savingFeishu.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const testFeishu = async () => {
|
||||
testing.value = true
|
||||
try {
|
||||
const res = await alertApi.testFeishu()
|
||||
ElMessage.success(res.message || '测试通知已发送')
|
||||
} catch (error) {
|
||||
ElMessage.error(error?.response?.data?.detail || '发送测试失败,请检查配置')
|
||||
} finally {
|
||||
testing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadStats()
|
||||
loadAlerts()
|
||||
|
||||
Reference in New Issue
Block a user