feat(admin): 优化后台运维与任务管理

完善平台、基准模型、定价规则和实时负载的紧凑查询与滚动展示,并固定关键操作列。

新增管理员任务记录、批量计费结算和用户组限流、额度及模型权限维护能力,同时补充任务脱敏、查询索引与 OpenAPI 契约。

验证:pnpm openapi、Go 全量测试、pnpm lint、pnpm test、pnpm build、gofmt 与差异格式检查均通过。
This commit is contained in:
2026-07-25 01:32:49 +08:00
parent b29d539d49
commit de10875439
38 changed files with 5015 additions and 425 deletions
+65 -59
View File
@@ -1,7 +1,7 @@
import { useMemo, useState, type FormEvent } from 'react';
import { FileText, Image, Pencil, Plus, RotateCcw, Trash2, Video } from 'lucide-react';
import { FileText, Image, Pencil, Plus, RotateCcw, Search, Trash2, Video } from 'lucide-react';
import type { PricingRule, PricingRuleInput, PricingRuleSet, PricingRuleSetUpsertRequest } from '@easyai-ai-gateway/contracts';
import { Badge, Button, Card, CardContent, CardHeader, CardTitle, ConfirmDialog, FormDialog, Input, Label, Select } from '../../components/ui';
import { Badge, Button, Card, CardContent, ConfirmDialog, FormDialog, Input, Label, Select } from '../../components/ui';
import type { LoadState } from '../../types';
import { unitLabel } from './PricingEditorControls';
import { createDefaultPricingRules, KeyValueEditor, PricingRuleVisualEditor } from './PricingRuleVisualEditor';
@@ -92,68 +92,74 @@ export function PricingRulesPanel(props: {
return (
<div className="pageStack">
<Card>
<CardHeader>
<CardTitle></CardTitle>
<Badge variant="secondary">{props.pricingRuleSets.length}</Badge>
</CardHeader>
<CardContent>
<div className="providerToolbar">
<p></p>
<Button type="button" onClick={openCreateDialog}><Plus size={15} /></Button>
</div>
<div className="modelCatalogFilters">
<Input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="搜索规则名称 / key" />
<Card className="compactAdminTableCard">
<CardContent className="compactAdminTableContent">
<div className="compactAdminToolbar catalogCompactToolbar">
<span className="platformSearchBox compactAdminSearch">
<Search size={15} />
<Input
aria-label="搜索定价规则"
value={query}
placeholder="规则名称、Key 或说明"
onChange={(event) => setQuery(event.target.value)}
/>
</span>
<div className="compactAdminToolbarActions">
<Button type="button" variant="outline" size="sm" disabled={!query} onClick={() => setQuery('')}>
<RotateCcw size={14} />
</Button>
<Button type="button" size="sm" onClick={openCreateDialog}><Plus size={15} /></Button>
</div>
</div>
{(props.message || localError) && <p className="formMessage">{localError || props.message}</p>}
<section className="pricingRuleGrid">
{filtered.map((ruleSet) => (
<article className="pricingRuleCard" key={ruleSet.id}>
<header>
<div>
<strong>{ruleSet.name}</strong>
<span>{ruleSet.ruleSetKey}</span>
</div>
<Badge variant={ruleSet.status === 'active' ? 'success' : 'secondary'}>{ruleSet.status}</Badge>
</header>
<p>{ruleSet.description || '未填写说明'}</p>
<div className="providerCatalogMeta">
<span>{ruleSet.category}</span>
<span>{ruleSet.currency}</span>
<span>{pricingRuleSummaries(ruleSet).length} </span>
</div>
<div className="pricingRuleItems">
{pricingRuleSummaries(ruleSet).map((item) => (
<span key={item.label}>
<strong>{pricingRuleSummaryIcon(item.kind)}{item.label}</strong>
<em>{item.value}</em>
</span>
))}
</div>
<div className="providerCatalogActions">
<Button type="button" variant="outline" size="sm" onClick={() => editRuleSet(ruleSet)}><Pencil size={14} /></Button>
<Button
type="button"
variant="destructive"
size="sm"
disabled={isDefaultRuleSet(ruleSet)}
title={isDefaultRuleSet(ruleSet) ? '默认计价规则不能删除' : undefined}
onClick={() => setPendingDeleteRuleSet(ruleSet)}
>
<Trash2 size={14} />
</Button>
</div>
</article>
))}
{!filtered.length && (
<div className="emptyState"><strong></strong></div>
)}
</section>
</CardContent>
</Card>
<section className="pricingRuleGrid">
{filtered.map((ruleSet) => (
<article className="pricingRuleCard" key={ruleSet.id}>
<header>
<div>
<strong>{ruleSet.name}</strong>
<span>{ruleSet.ruleSetKey}</span>
</div>
<Badge variant={ruleSet.status === 'active' ? 'success' : 'secondary'}>{ruleSet.status}</Badge>
</header>
<p>{ruleSet.description || '未填写说明'}</p>
<div className="providerCatalogMeta">
<span>{ruleSet.category}</span>
<span>{ruleSet.currency}</span>
<span>{pricingRuleSummaries(ruleSet).length} </span>
</div>
<div className="pricingRuleItems">
{pricingRuleSummaries(ruleSet).map((item) => (
<span key={item.label}>
<strong>{pricingRuleSummaryIcon(item.kind)}{item.label}</strong>
<em>{item.value}</em>
</span>
))}
</div>
<div className="providerCatalogActions">
<Button type="button" variant="outline" size="sm" onClick={() => editRuleSet(ruleSet)}><Pencil size={14} /></Button>
<Button
type="button"
variant="destructive"
size="sm"
disabled={isDefaultRuleSet(ruleSet)}
title={isDefaultRuleSet(ruleSet) ? '默认计价规则不能删除' : undefined}
onClick={() => setPendingDeleteRuleSet(ruleSet)}
>
<Trash2 size={14} />
</Button>
</div>
</article>
))}
{!filtered.length && (
<Card><CardContent className="emptyState"><strong></strong></CardContent></Card>
)}
</section>
<FormDialog
ariaLabel={editingId ? '编辑定价规则' : '新增定价规则'}
bodyClassName="pricingRuleFormBody"