feat(zone): 三区标记M3——新增BotSourceTag组件(最近Bot更新时间/来源/批次,缺失隐藏),接入/kpis/:id、/bot-kpis、/alerts三页 (three-zone P0-①)

This commit is contained in:
Hermes CI Fix
2026-09-03 17:52:10 +08:00
parent 4c01f2bf21
commit 92873456ab
4 changed files with 83 additions and 1 deletions
+45
View File
@@ -0,0 +1,45 @@
<template>
<div v-if="show" class="bot-source-tag">
<span class="bst-label">最近Bot更新:{{ updatedAt }}</span>
<span v-if="source" class="bst-sep">|</span>
<span v-if="source" class="bst-source">来源:{{ source }}</span>
<span v-if="batch && batch !== source" class="bst-sep">|</span>
<span v-if="batch && batch !== source" class="bst-batch">批次:{{ batch }}</span>
</div>
</template>
<script setup lang="ts">
// C区(Bot区)数据标注组件:展示"最近Bot更新时间/来源/批次"
// 无数据时整块隐藏;样式与 Element Plus 灰阶文本一致,不使用 emoji
import { computed } from 'vue'
const props = withDefaults(defineProps<{
/** 最近Bot更新时间,如 '2026-09-03 12:34';空/缺省则按需隐藏 */
updatedAt?: string
/** 来源(Bot名/引擎名),如 finance-bot、预警引擎 */
source?: string
/** 批次(source_batch),如 finance-bot 或导入批次号 */
batch?: string
}>(), { updatedAt: '', source: '', batch: '' })
const show = computed(() => !!(props.updatedAt && props.source))
</script>
<style scoped>
.bot-source-tag {
display: inline-flex;
align-items: center;
flex-wrap: wrap;
font-size: 12px;
color: #909399;
background: #f7f8fa;
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 2px 10px;
line-height: 20px;
white-space: nowrap;
}
.bst-label { color: #606266; }
.bst-sep { margin: 0 4px; color: #dcdfe6; }
.bst-source, .bst-batch { color: #409eff; }
</style>
+12
View File
@@ -9,6 +9,10 @@
</div>
</div>
<div style="margin:0 0 8px;display:flex;justify-content:flex-end;">
<BotSourceTag :updated-at="latestAlertTime" source="预警引擎" />
</div>
<!-- 顶部选项卡 -->
<div style="margin:12px 0;display:flex;gap:12px;align-items:center;">
<el-radio-group v-model="activeTab" size="small">
@@ -342,6 +346,7 @@ import { ref, computed, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { alertApi, userApi, actionPlanApi, kpiApi, alertRulesApi } from '../api/index'
import BotSourceTag from '../components/BotSourceTag.vue'
import RiskCell from '../components/charts/RiskCell.vue'
const route = useRoute()
@@ -398,6 +403,13 @@ function isTrendAlert(msg: string): boolean {
return msg?.startsWith('[趋势') || msg?.startsWith('[动态')
}
// ── C区标注:预警数据由预警引擎(定时规则)自动生成,展示最近生成时间(无预警行则不显示) ──
const latestAlertTime = computed(() => {
const times = alerts.value.map((a: any) => a.created_at || '').filter(Boolean)
if (!times.length) return ''
return formatTime(times.sort((x: string, y: string) => y.localeCompare(x))[0])
})
function formatTime(t: string): string {
if (!t) return '-'
try { return new Date(t).toLocaleString('zh-CN', { hour12: false }) } catch { return t }
+14
View File
@@ -7,6 +7,7 @@
<el-tag type="warning" size="small" effect="plain">2026年7月</el-tag>
</div>
<div class="header-right">
<BotSourceTag :updated-at="latestBotUpdate?.time || ''" :source="latestBotUpdate?.source || ''" :batch="latestBotUpdate?.batch || ''" style="margin-right:10px;" />
<el-button size="small" @click="refresh" :loading="loading">刷新</el-button>
</div>
</div>
@@ -163,6 +164,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { botKpiApi } from '../api/index'
import BotSourceTag from '../components/BotSourceTag.vue'
import { DataBoard, WarningFilled, User } from '@element-plus/icons-vue'
const loading = ref(false)
@@ -193,6 +195,18 @@ const alertsInfo = computed(() => {
return cnt > 0 ? `🚨 ${cnt} 个KPI需要关注` : '✅ 一切正常'
})
// ── C区标注:Bot KPI看板数据最近一次更新(取各KPI最新值回填时间中的最大值,无则不显示) ──
const latestBotUpdate = computed(() => {
const rows = kpis.value.filter((k: any) => k.value_updated_at)
if (!rows.length) return null
const row = rows.slice().sort((a: any, b: any) => String(b.value_updated_at).localeCompare(String(a.value_updated_at)))[0]
return {
time: row.value_updated_at || '',
source: row.value_source_batch || 'finance-bot',
batch: row.value_source_batch || '',
}
})
function formatVal(val: any, unit: string) {
if (val == null) return '-'
if (unit === '%') return val + '%'
+12 -1
View File
@@ -146,7 +146,8 @@
<el-tab-pane label="历史数据" name="history">
<div style="display:flex;justify-content:flex-end;margin-bottom:8px;">
<el-button size="small" type="primary" plain @click="openAddValueDialog">➕ 录入数据</el-button>
<BotSourceTag :updated-at="latestBotValue?.updated_at || ''" :source="latestBotSource" />
<el-button size="small" type="primary" plain @click="openAddValueDialog" style="margin-left:10px;">➕ 录入数据</el-button>
</div>
<v-chart :option="chartOption" autoresize class="full-width-chart" />
<el-table :data="values" size="small" class="data-table">
@@ -359,10 +360,20 @@ import { kpiApi, mapApi, kpiCausalityApi, orgApi, userApi } from '../api/index'
import api from '../api/index'
import { useFormGuard } from '../composables/useFormGuard'
import BotSourceTag from '../components/BotSourceTag.vue'
const route = useRoute()
const kpi = ref<any>(null)
const values = ref<any[]>([])
// ── C区标注:该KPI最近一次Bot回填(source_type=bot 的最新值;无则不显示) ──
const latestBotValue = computed(() => {
const botVals = values.value.filter((v: any) => v.source_type === 'bot' && (v.updated_at || v.source_batch))
if (!botVals.length) return null
return botVals.slice().sort((a: any, b: any) => String(b.updated_at || '').localeCompare(String(a.updated_at || '')))[0]
})
const latestBotSource = computed(() => latestBotValue.value?.source_batch || '')
// ── 人工录入数据 ──
const showAddValue = ref(false)
const addValueSaving = ref(false)