diff --git a/.env.development b/.env.development
index 6e87a31..3cbdb98 100644
--- a/.env.development
+++ b/.env.development
@@ -6,9 +6,11 @@ VITE_APP_WORKSPACE=ops
# 应用标题
VITE_APP_TITLE=标准管理系统
VITE_APP_DESCRIPTION="default standard template"
+VITE_USE_MOCK=false
# API 基础URL
-VITE_API_BASE_URL=https://ops-api.apinb.com
+# VITE_API_BASE_URL=https://ops-api.apinb.com
+VITE_API_BASE_URL=http://127.0.0.1
# Logs 本地调试地址(仅 logs 模块使用)
VITE_LOGS_API_BASE_URL=http://127.0.0.1:12440
diff --git a/.env.production b/.env.production
index 8f9f8ee..f1213e6 100644
--- a/.env.production
+++ b/.env.production
@@ -5,6 +5,7 @@ VITE_APP_WORKSPACE=ops
VITE_APP_TITLE=标准管理系统
VITE_APP_DESCRIPTION="default standard template"
+VITE_USE_MOCK=false
# API 基础URL
VITE_API_BASE_URL=https://ops-api.apinb.com
diff --git a/src/api/ops/alertEvent.ts b/src/api/ops/alertEvent.ts
new file mode 100644
index 0000000..f5a3c01
--- /dev/null
+++ b/src/api/ops/alertEvent.ts
@@ -0,0 +1,17 @@
+import { request } from '@/api/request'
+
+export const fetchAlertEvents = (data: {
+ page?: number
+ page_size?: number
+ alert_record_id?: number
+ event_type?: string
+ source?: string
+ severity?: string
+ start_time?: string
+ end_time?: string
+ keyword?: string
+ sort?: string
+ order?: string
+}) => request.get('/Alert/v1/event/list', { params: data })
+
+export const fetchAlertEventDetail = (id: number) => request.get(`/Alert/v1/event/get/${id}`)
diff --git a/src/main.ts b/src/main.ts
index ee16179..6c6ce59 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -5,7 +5,6 @@ import { createApp } from 'vue'
import App from './App.vue'
import directive from './directive'
import i18n from './locale'
-import './mock'
import router from './router'
import store from './store'
// Styles are imported via arco-plugin. See config/plugin/arcoStyleImport.ts in the directory for details
@@ -14,6 +13,10 @@ import store from './store'
import '@/api/interceptor'
import '@/assets/style/global.less'
+if (import.meta.env.VITE_USE_MOCK === 'true') {
+ import('./mock')
+}
+
const app = createApp(App)
app.use(ArcoVue, {})
diff --git a/src/views/ops/pages/alert/detail/index.vue b/src/views/ops/pages/alert/detail/index.vue
index 2dba6c9..5168b73 100644
--- a/src/views/ops/pages/alert/detail/index.vue
+++ b/src/views/ops/pages/alert/detail/index.vue
@@ -174,6 +174,20 @@
+
+
事件流水
+
+
+
+ {{ getEventTypeText(record.event_type) }}
+
+
+
+ {{ formatDateTime(record.occurred_at) }}
+
+
+
+
@@ -206,6 +220,7 @@ import { useRoute, useRouter } from 'vue-router'
import { Message } from '@arco-design/web-vue'
import { IconLeft, IconCheck, IconCheckCircle, IconMute, IconDown, IconUp } from '@arco-design/web-vue/es/icon'
import { fetchAlertRecordDetail, fetchAlertProcessList } from '@/api/ops/alertRecord'
+import { fetchAlertEvents } from '@/api/ops/alertEvent'
import AckDialog from '../tackle/components/AckDialog.vue'
import ResolveDialog from '../tackle/components/ResolveDialog.vue'
import SilenceDialog from '../tackle/components/SilenceDialog.vue'
@@ -215,8 +230,10 @@ const router = useRouter()
const loading = ref(true)
const processLoading = ref(false)
+const eventLoading = ref(false)
const record = ref(null)
const processRecords = ref([])
+const eventRecords = ref([])
const showRawData = ref(false)
// 对话框状态
@@ -277,6 +294,13 @@ const processColumns = [
]
// 加载详情
+const eventColumns = [
+ { title: '时间', dataIndex: 'occurred_at', slotName: 'occurred_at', width: 180 },
+ { title: '事件', dataIndex: 'event_type', slotName: 'event_type', width: 140 },
+ { title: '来源', dataIndex: 'source', width: 120 },
+ { title: '说明', dataIndex: 'message', ellipsis: true, tooltip: true },
+]
+
const loadDetail = async () => {
if (!alertId.value) {
Message.error('告警ID无效')
@@ -315,6 +339,26 @@ const loadProcessRecords = async () => {
}
// 返回
+const loadAlertEvents = async () => {
+ if (!alertId.value) return
+
+ eventLoading.value = true
+ try {
+ const result = await fetchAlertEvents({
+ alert_record_id: alertId.value,
+ page: 1,
+ page_size: 100,
+ sort: 'occurred_at',
+ order: 'desc',
+ })
+ eventRecords.value = result.details?.data || result.data || []
+ } catch (error) {
+ console.error('加载事件流水失败:', error)
+ } finally {
+ eventLoading.value = false
+ }
+}
+
const handleGoBack = () => {
router.back()
}
@@ -343,6 +387,7 @@ const handleSilence = () => {
const handleActionSuccess = () => {
loadDetail()
loadProcessRecords()
+ loadAlertEvents()
}
// 切换原始数据显示
@@ -454,9 +499,42 @@ const getActionText = (action: string) => {
return textMap[action] || action
}
+const getEventTypeColor = (eventType: string) => {
+ const colorMap: Record = {
+ received: 'arcoblue',
+ notified: 'green',
+ ticket_created: 'purple',
+ ticket_create_failed: 'red',
+ policy_load_failed: 'red',
+ policy_disabled: 'gray',
+ suppressed: 'orange',
+ ack: 'gold',
+ resolve: 'green',
+ silence: 'gray',
+ }
+ return colorMap[eventType] || 'blue'
+}
+
+const getEventTypeText = (eventType: string) => {
+ const textMap: Record = {
+ received: '接收告警',
+ notified: '通知发送',
+ ticket_created: '自动建单',
+ ticket_create_failed: '建单失败',
+ policy_load_failed: '策略加载失败',
+ policy_disabled: '策略停用',
+ suppressed: '告警抑制',
+ ack: '确认',
+ resolve: '解决',
+ silence: '屏蔽',
+ }
+ return textMap[eventType] || eventType
+}
+
onMounted(() => {
loadDetail()
loadProcessRecords()
+ loadAlertEvents()
})