feat: 迁移预警规则管理和历史分类查询

This commit is contained in:
Yvan
2026-11-03 20:19:26 +08:00
parent cd42a1d3f0
commit 7203c34409
31 changed files with 1264 additions and 15 deletions
+96
View File
@@ -0,0 +1,96 @@
<template>
<div>
<div class="kra-search-box">
<el-form :inline="true" :model="query" @submit.prevent="search">
<el-form-item label="监控指标"><el-select v-model="query.monitorMetric" clearable placeholder="全部监控指标" style="width: 160px"><el-option v-for="(label, value) in metrics" :key="value" :value="Number(value)" :label="label" /></el-select></el-form-item>
<el-form-item label="规则名称"><el-input v-model="query.ruleName" clearable placeholder="输入规则名称" /></el-form-item>
<el-form-item><el-button type="primary" icon="search" native-type="submit">搜索</el-button><el-button icon="refresh" @click="reset">重置</el-button></el-form-item>
</el-form>
</div>
<div class="kra-table-box">
<div class="kra-btn-list"><el-button v-if="canCreate" type="primary" icon="plus" @click="open()">新建规则</el-button></div>
<el-alert class="mb-4" type="info" :closable="false" title="同一平台、同一渠道、同类预警未关闭时不重复新建。未处理预警再次命中会刷新;处理中、待审核和审核驳回的记录保持不变。" />
<el-table v-loading="loading" :data="rows" row-key="id">
<el-table-column label="启用状态" width="110"><template #default="{ row }"><el-switch :model-value="row.enabled" :active-value="1" :inactive-value="0" :disabled="!canEdit || busy === row.id" @change="toggle(row, $event)" /></template></el-table-column>
<el-table-column prop="ruleName" label="规则名称" min-width="150" />
<el-table-column label="规则类型" min-width="130"><template #default="{ row }"><el-tag effect="plain" :style="{ color: row.warningColor, borderColor: row.warningColor }">{{ row.ruleTypeLabel }}</el-tag></template></el-table-column>
<el-table-column prop="ruleDescription" label="规则描述" min-width="320" show-overflow-tooltip />
<el-table-column prop="creatorName" label="创建人" min-width="120" />
<el-table-column label="作用范围" min-width="150"><template #default>仅对一级渠道生效</template></el-table-column>
<el-table-column v-if="canEdit || canDelete" label="操作" width="130" fixed="right"><template #default="{ row }"><el-button v-if="canEdit" type="primary" link @click="open(row)">编辑</el-button><el-button v-if="canDelete" type="danger" link @click="remove(row)">删除</el-button></template></el-table-column>
</el-table>
<div class="kra-pagination"><el-pagination v-model:current-page="query.pageNum" v-model:page-size="query.pageSize" :total="total" :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" @size-change="search" @current-change="load" /></div>
</div>
<el-drawer v-model="drawer" append-to-body :title="form.id ? '编辑规则' : '新建规则'" size="480px" destroy-on-close>
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
<el-form-item label="规则名称" prop="ruleName"><el-input v-model="form.ruleName" maxlength="50" placeholder="请输入规则名称" /></el-form-item>
<el-form-item label="规则类型" prop="ruleType"><el-input v-model="form.ruleType" maxlength="20" placeholder="如:注册异常 / 充值异常 / 登录异常" /></el-form-item>
<el-form-item label="监控指标" prop="monitorMetric"><el-select v-model="form.monitorMetric"><el-option v-for="(label, value) in metrics" :key="value" :value="Number(value)" :label="label" /></el-select></el-form-item>
<template v-if="form.monitorMetric !== 3">
<el-form-item label="统计周期(天)" prop="statPeriodDays"><el-input-number v-model="form.statPeriodDays" :min="1" :max="365" :precision="0" /></el-form-item>
<el-form-item label="环比方向" prop="momDirection"><el-select v-model="form.momDirection"><el-option label="环比上升 (异常暴涨)" :value="1" /><el-option label="环比下降 (异常恶化)" :value="2" /></el-select></el-form-item>
<el-form-item label="环比阈值 (%)" prop="momThreshold"><el-input-number v-model="form.momThreshold" :min="1" :max="9999" :precision="2" /></el-form-item>
</template>
<el-form-item v-else label="未登录天数" prop="unloginDays"><el-input-number v-model="form.unloginDays" :min="1" :max="365" :precision="0" /></el-form-item>
<el-form-item label="预警颜色" prop="warningColor"><el-color-picker v-model="form.warningColor" :predefine="colors" color-format="hex" /></el-form-item>
<el-text type="info">作用范围固定为一级渠道。</el-text>
</el-form>
<template #footer><el-button @click="drawer = false">取消</el-button><el-button type="primary" :loading="saving" @click="save">保存</el-button></template>
</el-drawer>
</div>
</template>
<script setup>
import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useUserStore } from '@/pinia/modules/user'
import { useBtnAuth } from '@/utils/btnAuth'
import { listAlertRules, createAlertRule, updateAlertRule, deleteAlertRule, toggleAlertRule } from '@/api/alert'
defineOptions({ name: 'SwAlertRules' })
const user = useUserStore()
const buttons = useBtnAuth()
const admin = computed(() => Number(user.userInfo.authorityId) === 888)
const manage = computed(() => admin.value || Number(user.userInfo.level) === 1)
const canCreate = computed(() => manage.value && (admin.value || buttons['sw:alertRule:add']))
const canEdit = computed(() => manage.value && (admin.value || buttons['sw:alertRule:edit']))
const canDelete = computed(() => manage.value && (admin.value || buttons['sw:alertRule:remove']))
const metrics = { 1: '注册量', 2: '充值金额', 3: '登录天数' }
const colors = ['#f56c6c', '#e6a23c', '#22c55e', '#409eff', '#a855f7']
const query = reactive({ pageNum: 1, pageSize: 10, monitorMetric: undefined, ruleName: '' })
const rows = ref([])
const total = ref(0)
const loading = ref(false)
const saving = ref(false)
const drawer = ref(false)
const busy = ref(0)
const formRef = ref()
const form = ref({})
const rules = Object.fromEntries(['ruleName', 'ruleType', 'monitorMetric', 'statPeriodDays', 'momDirection', 'momThreshold', 'unloginDays', 'warningColor'].map((name) => [name, [{ required: true, message: '请填写完整规则信息', trigger: 'change' }]]))
const load = async () => {
loading.value = true
try { const res = await listAlertRules(query); if (res.code === 0) { rows.value = res.data.rows; total.value = res.data.total } } finally { loading.value = false }
}
const search = () => { query.pageNum = 1; return load() }
const reset = () => { query.monitorMetric = undefined; query.ruleName = ''; return search() }
const open = (row) => {
form.value = { ruleName: '', ruleType: '', monitorMetric: 1, statPeriodDays: 7, momDirection: 1, momThreshold: 20, unloginDays: 7, warningColor: colors[0], ...row }
if (form.value.momThreshold != null) form.value.momThreshold = Number(form.value.momThreshold)
drawer.value = true
}
const save = async () => {
if (!await formRef.value.validate().catch(() => false)) return
saving.value = true
try { const res = await (form.value.id ? updateAlertRule : createAlertRule)(form.value); if (res.code === 0) { ElMessage.success('保存成功'); drawer.value = false; await load() } } finally { saving.value = false }
}
const toggle = async (row, enabled) => {
busy.value = row.id
try { const res = await toggleAlertRule(row.id, enabled); if (res.code === 0) row.enabled = enabled } finally { busy.value = 0 }
}
const remove = async (row) => {
if (!await ElMessageBox.confirm(`确认删除规则「${row.ruleName}」?`, '删除确认', { type: 'warning' }).then(() => true).catch(() => false)) return
const res = await deleteAlertRule(row.id)
if (res.code === 0) { ElMessage.success('删除成功'); await load() }
}
onMounted(load)
</script>