feat: AI事前预警 — 现金流预测+预警扩展+准确率+情景建议
This commit is contained in:
@@ -39,11 +39,11 @@
|
||||
</div>
|
||||
|
||||
<el-table :data="alerts" v-loading="loading" style="width:100%" border stripe size="small">
|
||||
<el-table-column prop="alert_message" label="预警信息" min-width="320">
|
||||
<el-table-column prop="alert_message" label="预警信息" min-width="300">
|
||||
<template #default="{ row }">
|
||||
<div style="display:flex;align-items:center;gap:4px;">
|
||||
<el-tag v-if="isTrendAlert(row.alert_message)" size="small" type="info" effect="plain">趋势</el-tag>
|
||||
<el-tag v-else size="small" type="primary" effect="plain">静态</el-tag>
|
||||
<el-tag v-if="row.alert_type === 'forecast'" size="small" type="warning" effect="plain">🔮预测</el-tag>
|
||||
<el-tag v-else size="small" type="primary" effect="plain">实际</el-tag>
|
||||
<span>{{ row.alert_message }}</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -147,6 +147,8 @@
|
||||
<el-option label="已禁用" :value="0" />
|
||||
</el-select>
|
||||
<el-button type="primary" size="small" @click="loadRules">查询</el-button>
|
||||
<el-button size="small" @click="checkForecastAlerts" :loading="fcLoading">🔮 检查预测值</el-button>
|
||||
<el-button size="small" @click="generateAlertSuggestions" :loading="sgLoading">💡 生成情景建议</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :data="rules" v-loading="rulesLoading" style="width:100%" border stripe size="small">
|
||||
@@ -254,7 +256,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 编辑预警规则弹窗 -->
|
||||
<el-dialog v-model="showRuleForm" title="编辑预警规则" width="500px">
|
||||
<el-dialog v-model="showRuleForm" title="编辑预警规则" width="520px">
|
||||
<el-form :model="ruleForm" label-width="110px" size="small">
|
||||
<el-form-item label="规则类型">
|
||||
<el-select v-model="ruleForm.rule_type" style="width:100%">
|
||||
@@ -264,6 +266,14 @@
|
||||
<el-option label="下降趋势预警" value="trend_down" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="触发条件">
|
||||
<el-select v-model="ruleForm.trigger_on" style="width:100%">
|
||||
<el-option label="实际值超限" value="actual" />
|
||||
<el-option label="预测值超限" value="forecast" />
|
||||
<el-option label="两者都触发" value="both" />
|
||||
</el-select>
|
||||
<span style="color:#909399;font-size:12px;margin-top:2px;display:block;">预测值超限时,系统会检查未来7天现金流预测是否触及阈值</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否启用">
|
||||
<el-switch v-model="ruleForm.enabled" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
@@ -366,6 +376,7 @@ const calcLoading = ref(false)
|
||||
const ruleForm = ref({
|
||||
kpi_id: null as number | null,
|
||||
rule_type: 'static',
|
||||
trigger_on: 'actual',
|
||||
enabled: 1,
|
||||
params: { green: '', yellow: '', red: '', sensitivity: 1.0, threshold_pct: 10 },
|
||||
})
|
||||
@@ -467,6 +478,7 @@ function editRule(row: any) {
|
||||
ruleForm.value = {
|
||||
kpi_id: row.kpi_id,
|
||||
rule_type: row.rule_type,
|
||||
trigger_on: row.trigger_on || 'actual',
|
||||
enabled: row.enabled,
|
||||
params: { green: '', yellow: '', red: '', sensitivity: 1.0, threshold_pct: 10, ...(params || {}) },
|
||||
}
|
||||
@@ -478,6 +490,7 @@ async function saveRule() {
|
||||
try {
|
||||
const data = {
|
||||
rule_type: ruleForm.value.rule_type,
|
||||
trigger_on: ruleForm.value.trigger_on,
|
||||
enabled: ruleForm.value.enabled,
|
||||
params: ruleForm.value.params,
|
||||
}
|
||||
@@ -514,6 +527,29 @@ async function generateRules() {
|
||||
generating.value = false
|
||||
}
|
||||
|
||||
async function checkForecastAlerts() {
|
||||
fcLoading.value = true
|
||||
try {
|
||||
const r: any = await alertRulesApi.checkForecast()
|
||||
ElMessage.success(r.message || '预测值检查完成')
|
||||
loadAlerts()
|
||||
} catch (e) { ElMessage.error('检查失败') }
|
||||
fcLoading.value = false
|
||||
}
|
||||
|
||||
async function generateAlertSuggestions() {
|
||||
sgLoading.value = true
|
||||
try {
|
||||
const r: any = await alertRulesApi.generateSuggestions()
|
||||
ElMessage.success(r.message || '情景建议已生成')
|
||||
loadAlerts()
|
||||
} catch (e) { ElMessage.error('生成失败') }
|
||||
sgLoading.value = false
|
||||
}
|
||||
|
||||
const fcLoading = ref(false)
|
||||
const sgLoading = ref(false)
|
||||
|
||||
async function calcDynamic() {
|
||||
calcLoading.value = true
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user