From 3475ce7ce6da370b0ceacb16be3c3e4462a739c2 Mon Sep 17 00:00:00 2001 From: Wang Defa <1+wangdefa@noreply.gitea.bcde.io> Date: Fri, 17 Jul 2026 16:53:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=9E=E4=BC=A0=E6=97=A5=E5=BF=97=E5=8E=BB?= =?UTF-8?q?=E9=AB=98=E5=BA=A6=E9=99=90=E5=88=B6=E4=B8=8E=E6=96=87=E6=A1=88?= =?UTF-8?q?=E5=90=8C=E6=AD=A5,=E9=94=99=E8=AF=AF=20toast=20=E5=8F=AF?= =?UTF-8?q?=E5=B1=95=E5=BC=80=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/request.ts | 11 +++++++++-- src/components/logs/LogEventPanel.vue | 10 +++++----- src/views/SettingsView.vue | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/api/request.ts b/src/api/request.ts index 2aa26a9..cf77d61 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -32,8 +32,15 @@ function buildUrl(path: string, query?: RequestOptions['query']): string { async function parseError(resp: Response): Promise { let message = `请求失败(${resp.status})` try { - const body = (await resp.json()) as { error?: string; hint?: string } - if (body.error) message = body.hint ? `${body.hint}|${body.error}` : body.error + const body = (await resp.json()) as { error?: string; hint?: string; errors?: unknown[] } + if (body.error) { + message = body.hint ? `${body.hint}|${body.error}` : body.error + } else { + // 批量接口(如创建实例)全部失败时返回 errors 数组,逐行合并; + // 调用方以「短标题 + detail」经 useToast 展示,多行在详情块中逐行可读 + const list = (body.errors ?? []).filter((e): e is string => typeof e === 'string') + if (list.length) message = list.join('\n') + } } catch { /* 非 JSON 响应体,保留默认消息 */ } diff --git a/src/components/logs/LogEventPanel.vue b/src/components/logs/LogEventPanel.vue index 0a10d44..82c53fd 100644 --- a/src/components/logs/LogEventPanel.vue +++ b/src/components/logs/LogEventPanel.vue @@ -240,15 +240,15 @@ useAutoRefresh(() => load(true)) :loading="loading" :pagination="pagination" :scroll-x="880" - :max-height="480" :row-key="(r: LogEvent) => r.id" :row-props="rowProps" /> - 在租户详情「其他」tab 一键创建链路后,实例生命周期(Launch/Terminate/InstanceAction)、 - 用户与凭据(Create/Delete/UpdateUser、Create/DeleteApiKey、UpdateUserCapabilities)、 - 区域订阅与策略变更等关键审计事件将自动回传;消息按 MessageId 幂等去重,保留 90 - 天、总量超 2 万条时删除最旧,关键事件另经「通知管理 → 云端事件」推送告警 + 在租户详情「其他」tab 一键创建链路后,实例终止与电源操作(Terminate/InstanceAction; + 创建不回传,避免面板抢机与批量创建刷屏)、用户与凭据(Create/Delete/UpdateUser、 + Create/DeleteApiKey、UpdateUserCapabilities)、区域订阅与策略变更等关键审计事件将自动回传; + 消息按 MessageId 幂等去重,保留 90 天、总量超 2 万条时删除最旧,关键事件另经 + 「通知管理 → 云端事件」推送告警 diff --git a/src/views/SettingsView.vue b/src/views/SettingsView.vue index 4bc5cdd..caab7e6 100644 --- a/src/views/SettingsView.vue +++ b/src/views/SettingsView.vue @@ -89,7 +89,7 @@ const eventRows: { key: keyof NotifyEventsSetting; label: string; hint: string } { key: 'taskStop', label: '任务停止', hint: '抢机连续鉴权失败熔断停止时推送' }, { key: 'loginLock', label: '登录锁定', hint: '同一 IP+用户名连续失败达阈值时推送' }, { key: 'modelDeprecated', label: '模型弃用预警', hint: 'AI 网关在池模型 30 天内被 OCI 弃用时随每日探测推送' }, - { key: 'logEventInstance', label: '实例生命周期', hint: '创建 / 终止 / 电源操作(Launch、Terminate、InstanceAction)' }, + { key: 'logEventInstance', label: '实例生命周期', hint: '终止 / 电源操作(Terminate、InstanceAction);创建不回传,避免抢机噪声' }, { key: 'logEventIdentity', label: '用户与凭据', hint: '用户增删改、API Key 增删、能力变更' }, { key: 'logEventPolicy', label: '策略变更', hint: 'IAM Policy 创建 / 修改 / 删除' }, { key: 'logEventRegion', label: '区域订阅', hint: '订阅新区域(CreateRegionSubscription)' },