fix(aiops): 保存配置后分析页状态即时同步;分析页布局重排
- enabled 状态在 saveConfig 成功后立即 setEnabled(此前只更新 config, 导致'AI 分析未启用'横幅要等下次请求才消失) - 布局:工具栏改 4 列网格(数据源/时间/应用/问题),执行按钮与提示移到 分隔线下右对齐;未启用横幅加 ✦ 图标 + 「去配置」直达按钮;空态/加载态 加图标居中;消耗行改统计卡风格(数值 tabular 高亮)
This commit is contained in:
1 parent
5d898e3592
commit
2efbed882a
3 files changed
+28
-16
No files matched your search
@@ -20,6 +20,7 @@ export default {
|
||||
},
|
||||
|
||||
analyze: {
|
||||
goConfig: 'Open config',
|
||||
appScope: 'App scope',
|
||||
allApps: 'All apps',
|
||||
appRequired: 'Required (over 1h)',
|
||||
|
||||
@@ -20,6 +20,7 @@ export default {
|
||||
},
|
||||
|
||||
analyze: {
|
||||
goConfig: '去配置',
|
||||
appScope: '应用范围',
|
||||
allApps: '全部应用',
|
||||
appRequired: '必选(超过 1 小时)',
|
||||
|
||||
@@ -190,6 +190,7 @@ export default function AiopsPage() {
|
||||
.filter(Boolean),
|
||||
})
|
||||
setConfig(res.config)
|
||||
setEnabled(Boolean(res.config?.enabled))
|
||||
setApiKeyInput('')
|
||||
toast.success('配置已保存')
|
||||
} catch (err) {
|
||||
@@ -245,13 +246,16 @@ export default function AiopsPage() {
|
||||
{/* ─────────── 分析 ─────────── */}
|
||||
<TabsContent value="analyze" className="space-y-4">
|
||||
{!enabled && (
|
||||
<div className="rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-sm">
|
||||
{t('analyze.notEnabled')}
|
||||
<div className="flex flex-wrap items-center gap-3 rounded-lg border border-warning/40 bg-warning/10 px-4 py-3 text-sm">
|
||||
<Sparkles className="size-4 shrink-0 text-warning" />
|
||||
<span className="flex-1">{t('analyze.notEnabled')}</span>
|
||||
<Button size="sm" variant="outline" onClick={() => setTab('config')}>{t('analyze.goConfig')}</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Card>
|
||||
<CardContent className="flex flex-wrap items-end gap-3 pt-4">
|
||||
<CardContent className="pt-4">
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
<div className="min-w-40 space-y-1">
|
||||
<Label className="text-xs">{t('analyze.source')}</Label>
|
||||
<select
|
||||
@@ -299,7 +303,7 @@ export default function AiopsPage() {
|
||||
</select>
|
||||
{needApp && <p className="text-[11px] text-warning">{t('analyze.appScopeHint')}</p>}
|
||||
</div>
|
||||
<div className="min-w-64 flex-1 space-y-1">
|
||||
<div className="space-y-1 xl:col-span-2">
|
||||
<Label className="text-xs">{t('analyze.question')}</Label>
|
||||
<Input
|
||||
value={question}
|
||||
@@ -308,25 +312,32 @@ export default function AiopsPage() {
|
||||
className="h-9"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex flex-wrap items-center justify-between gap-2 border-t pt-3">
|
||||
<p className="text-xs text-muted-foreground">{t('analyze.runHint')}</p>
|
||||
<Button onClick={runAnalysis} disabled={running || !enabled || (needApp && !app)} className="h-9">
|
||||
{running ? <Loader2 className="mr-1.5 h-4 w-4 animate-spin" /> : <Play className="mr-1.5 h-4 w-4" />}
|
||||
{running ? t('analyze.running') : t('analyze.run')}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
<div className="px-4 pb-3 text-xs text-muted-foreground">{t('analyze.runHint')}</div>
|
||||
</Card>
|
||||
|
||||
{!outcome && !running && (
|
||||
<Card>
|
||||
<CardContent className="py-10 text-center text-sm text-muted-foreground">{t('analyze.empty')}</CardContent>
|
||||
<CardContent className="flex flex-col items-center justify-center gap-2 py-14 text-center">
|
||||
<Sparkles className="size-8 text-muted-foreground/40" />
|
||||
<p className="text-sm text-muted-foreground">{t('analyze.empty')}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{running && (
|
||||
<Card>
|
||||
<CardContent className="flex items-center justify-center gap-2 py-10 text-sm text-muted-foreground">
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
{t('analyze.running')}
|
||||
<CardContent className="flex flex-col items-center justify-center gap-2 py-14 text-center">
|
||||
<Loader2 className="size-7 animate-spin text-primary" />
|
||||
<p className="text-sm font-medium">{t('analyze.running')}</p>
|
||||
<p className="text-xs text-muted-foreground">{t('analyze.runHint')}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
@@ -334,13 +345,12 @@ export default function AiopsPage() {
|
||||
{outcome && (
|
||||
<>
|
||||
{/* 本次消耗:让成本和延迟是可见的 */}
|
||||
<div className="flex flex-wrap items-center gap-4 rounded-md border bg-muted/30 px-3 py-2 text-xs text-muted-foreground">
|
||||
<span>
|
||||
{t('analyze.lastRun')}:{t('analyze.promptTokens')} {fmtNum(outcome.run.promptTokens)} ·{' '}
|
||||
{t('analyze.completionTokens')} {fmtNum(outcome.run.completionTokens)} · {t('analyze.duration')}{' '}
|
||||
{(outcome.run.durationMs / 1000).toFixed(1)}s
|
||||
</span>
|
||||
<Button variant="link" size="sm" className="h-auto p-0 text-xs" onClick={() => setPromptOpen(true)}>
|
||||
<div className="flex flex-wrap items-center gap-x-5 gap-y-1 rounded-lg border bg-muted/30 px-4 py-2.5 text-xs">
|
||||
<span className="font-medium text-foreground">{t('analyze.lastRun')}</span>
|
||||
<span className="text-muted-foreground">{t('analyze.promptTokens')} <span className="tabular-nums text-foreground">{fmtNum(outcome.run.promptTokens)}</span></span>
|
||||
<span className="text-muted-foreground">{t('analyze.completionTokens')} <span className="tabular-nums text-foreground">{fmtNum(outcome.run.completionTokens)}</span></span>
|
||||
<span className="text-muted-foreground">{t('analyze.duration')} <span className="tabular-nums text-foreground">{(outcome.run.durationMs / 1000).toFixed(1)}s</span></span>
|
||||
<Button variant="link" size="sm" className="ml-auto h-auto p-0 text-xs" onClick={() => setPromptOpen(true)}>
|
||||
{t('analyze.viewPrompt')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user