feat(h2-forecast): 实测区/预估区口径分离 —— 对外读路径默认只取实测区
ci/woodpecker/push/main Pipeline failed

- 新增 app/utils/kpi_value_scope.py(口径单一事实源:actual_only_clause / forecast_only_clause / is_forecast_row)
- dashboard.py: /kpis /my-kpis /finance-analysis /predict /my-dashboard / latest_kpi_value 默认剔预估,include_forecast=true 单列返回
- alert_rules.py: 动态阈值白名单去 estimated + 4 处读路径加实测区判据
- 前端 ForecastTag.vue 新增;Dashboard.vue / MyDashboard.vue 预估单列 + 标签(不与实测相加)

Task: finance-20261002-h2-forecast-separation-deploy-fullstack
This commit is contained in:
Hermes CI Fix
2026-10-02 23:33:15 +08:00
parent f32f6e7430
commit 5d7b3cc728
6 changed files with 399 additions and 29 deletions
+15 -1
View File
@@ -87,6 +87,11 @@
:show-text="false"
/>
<div v-else style="height:6px;line-height:6px;color:#c0c4cc;font-size:11px">—</div>
<!-- 预估区(单列,不与上方实测值相加;财务裁定 2026-10-02) -->
<div v-if="k.forecast_value != null" class="kpi-forecast-row">
<ForecastTag />
<span class="kpi-forecast-val">{{ k.forecast_value }}</span>
</div>
</div>
</div>
</div>
@@ -128,6 +133,8 @@
import { ref, computed, onMounted } from "vue"
import { useRouter } from "vue-router"
import api from "../api/index"
// 预估区标签(财务裁定 2026-10-02:预估行单列展示,不与实测相加/同线)
import ForecastTag from "../components/ForecastTag.vue"
// 排序固化: danger(逾期行动/红色预警) 在前, warning(黄色预警) 在后;
// 同 severity 保持后端生成顺序 (overdue→red→yellow), 不改变现有展示次序
@@ -146,6 +153,8 @@ const loading = ref(true)
const kpis = ref<any[]>([])
const actionPlans = ref<any[]>([])
const reminders = ref<any[]>([])
// 预估区(单列,不计入卡片实测值;财务裁定 2026-10-02)
const forecastList = ref<any[]>([])
const todayStr = new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' })
function fmtValue(val: any, code: string) {
@@ -224,8 +233,10 @@ function goToDetail(r: any) {
onMounted(async () => {
try {
const r: any = await api.get('/dashboard/my-dashboard')
// include_forecast=true:预估行**单列返回**(forecast 字段),卡片实测值不受影响
const r: any = await api.get('/dashboard/my-dashboard', { params: { include_forecast: true } })
kpis.value = r.kpis || []
forecastList.value = r.forecast || []
actionPlans.value = r.action_plans || []
reminders.value = r.reminders || []
} catch (e: any) {
@@ -342,6 +353,9 @@ onMounted(async () => {
padding: 0 6px; border-radius: 4px; margin-right: 6px;
}
.kpi-target { font-size: 12px; color: #999; }
/* 预估区(单列一行 + 「预估」标签,不与卡片实测值相加) */
.kpi-forecast-row { display: flex; align-items: center; gap: 4px; margin-top: 6px; }
.kpi-forecast-val { font-size: 12px; color: #b88230; }
/* ── 改善行动 ── */
.plans-section { margin-bottom: 28px; }