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
+98 -7
View File
@@ -1,8 +1,9 @@
import type { AdminSection, ApiDocSection, PageKey, PlaygroundMode, WorkspaceSection, WorkspaceTaskQuery } from './types';
import type { AdminSection, AdminTaskQuery, ApiDocSection, PageKey, PlaygroundMode, WorkspaceSection, WorkspaceTaskQuery } from './types';
export interface AppRouteState {
activePage: PageKey;
adminSection: AdminSection;
adminTaskQuery: AdminTaskQuery;
apiDocSection: ApiDocSection;
playgroundMode: PlaygroundMode;
workspaceSection: WorkspaceSection;
@@ -12,6 +13,7 @@ export interface AppRouteState {
export const defaultRouteState: AppRouteState = {
activePage: 'home',
adminSection: 'overview',
adminTaskQuery: defaultAdminTaskQuery(),
apiDocSection: 'openApiOverview',
playgroundMode: 'chat',
workspaceSection: 'overview',
@@ -31,14 +33,15 @@ const adminPaths: Record<AdminSection, string> = {
globalModels: '/admin/providers',
baseModels: '/admin/base-models',
pricing: '/admin/pricing',
billingSettlements: '/admin/billing-settlements',
platforms: '/admin/platforms',
realtimeLoad: '/admin/realtime-load',
tasks: '/admin/tasks',
tenants: '/admin/tenants',
users: '/admin/users',
userGroups: '/admin/user-groups',
auditLogs: '/admin/audit-logs',
runtime: '/admin/runtime',
accessRules: '/admin/access-rules',
systemSettings: '/admin/system-settings',
};
@@ -82,19 +85,20 @@ export function parseAppRoute(input = currentLocationPath()): AppRouteState {
const url = new URL(input, origin);
const path = normalizePath(url.pathname);
const workspaceTaskQuery = parseWorkspaceTaskQuery(url.searchParams);
const adminTaskQuery = parseAdminTaskQuery(url.searchParams);
if (path === '/') return { ...defaultRouteState };
if (path.startsWith('/playground')) {
return { ...defaultRouteState, activePage: 'playground', playgroundMode: parsePlaygroundMode(path), workspaceTaskQuery };
return { ...defaultRouteState, activePage: 'playground', playgroundMode: parsePlaygroundMode(path), workspaceTaskQuery, adminTaskQuery };
}
if (path === '/models') return { ...defaultRouteState, activePage: 'models', workspaceTaskQuery };
if (path === '/models') return { ...defaultRouteState, activePage: 'models', workspaceTaskQuery, adminTaskQuery };
if (path.startsWith('/workspace')) {
return { ...defaultRouteState, activePage: 'workspace', workspaceSection: parseWorkspaceSection(path), workspaceTaskQuery };
return { ...defaultRouteState, activePage: 'workspace', workspaceSection: parseWorkspaceSection(path), workspaceTaskQuery, adminTaskQuery };
}
if (path.startsWith('/admin')) {
return { ...defaultRouteState, activePage: 'admin', adminSection: parseAdminSection(path), workspaceTaskQuery };
return { ...defaultRouteState, activePage: 'admin', adminSection: parseAdminSection(path), workspaceTaskQuery, adminTaskQuery };
}
if (path.startsWith('/docs')) {
return { ...defaultRouteState, activePage: 'docs', apiDocSection: parseDocSection(path), workspaceTaskQuery };
return { ...defaultRouteState, activePage: 'docs', apiDocSection: parseDocSection(path), workspaceTaskQuery, adminTaskQuery };
}
return { ...defaultRouteState };
}
@@ -130,6 +134,28 @@ export function pathForWorkspaceTaskQuery(query: WorkspaceTaskQuery) {
return `${workspacePaths.tasks}${suffix ? `?${suffix}` : ''}`;
}
export function pathForAdminTaskQuery(query: AdminTaskQuery) {
const normalized = normalizeAdminTaskQuery(query);
const search = new URLSearchParams();
if (normalized.query) search.set('q', normalized.query);
if (normalized.tenantId) search.set('tenantId', normalized.tenantId);
if (normalized.userId) search.set('userId', normalized.userId);
if (normalized.userGroupId) search.set('userGroupId', normalized.userGroupId);
if (normalized.status) search.set('status', normalized.status);
if (normalized.platformId) search.set('platformId', normalized.platformId);
if (normalized.model) search.set('model', normalized.model);
if (normalized.modelType) search.set('modelType', normalized.modelType);
if (normalized.runMode) search.set('runMode', normalized.runMode);
if (normalized.billingStatus) search.set('billingStatus', normalized.billingStatus);
if (normalized.apiKey) search.set('apiKey', normalized.apiKey);
if (normalized.createdFrom) search.set('createdFrom', normalized.createdFrom);
if (normalized.createdTo) search.set('createdTo', normalized.createdTo);
if (normalized.page !== 1) search.set('page', String(normalized.page));
if (normalized.pageSize !== 20) search.set('pageSize', String(normalized.pageSize));
const suffix = search.toString();
return `${adminPaths.tasks}${suffix ? `?${suffix}` : ''}`;
}
export function pathForAdminSection(section: AdminSection) {
return adminPaths[section] ?? adminPaths.overview;
}
@@ -150,6 +176,7 @@ function parseAdminSection(path: string): AdminSection {
if (path === '/admin') return 'overview';
if (path === '/admin/models/global') return 'baseModels';
if (path === '/admin/usergroups') return 'userGroups';
if (path === '/admin/access-rules') return 'userGroups';
return adminSections[path] ?? 'overview';
}
@@ -207,6 +234,70 @@ export function workspaceTaskQueryKey(query: WorkspaceTaskQuery) {
return JSON.stringify(normalized);
}
export function defaultAdminTaskQuery(): AdminTaskQuery {
return {
query: '',
tenantId: '',
userId: '',
userGroupId: '',
status: '',
platformId: '',
model: '',
modelType: '',
runMode: '',
billingStatus: '',
apiKey: '',
createdFrom: '',
createdTo: '',
page: 1,
pageSize: 20,
};
}
export function normalizeAdminTaskQuery(query: AdminTaskQuery): AdminTaskQuery {
return {
query: query.query.trim(),
tenantId: query.tenantId.trim(),
userId: query.userId.trim(),
userGroupId: query.userGroupId.trim(),
status: query.status.trim(),
platformId: query.platformId.trim(),
model: query.model.trim(),
modelType: query.modelType.trim(),
runMode: query.runMode.trim(),
billingStatus: query.billingStatus.trim(),
apiKey: query.apiKey.trim(),
createdFrom: query.createdFrom.trim(),
createdTo: query.createdTo.trim(),
page: positiveInt(query.page, 1),
pageSize: Math.min(100, Math.max(1, positiveInt(query.pageSize, 20))),
};
}
export function adminTaskQueryKey(query: AdminTaskQuery) {
return JSON.stringify(normalizeAdminTaskQuery(query));
}
function parseAdminTaskQuery(search: URLSearchParams): AdminTaskQuery {
return normalizeAdminTaskQuery({
query: search.get('q') ?? search.get('query') ?? '',
tenantId: search.get('tenantId') ?? '',
userId: search.get('userId') ?? '',
userGroupId: search.get('userGroupId') ?? '',
status: search.get('status') ?? '',
platformId: search.get('platformId') ?? '',
model: search.get('model') ?? '',
modelType: search.get('modelType') ?? '',
runMode: search.get('runMode') ?? '',
billingStatus: search.get('billingStatus') ?? '',
apiKey: search.get('apiKey') ?? '',
createdFrom: search.get('createdFrom') ?? search.get('from') ?? '',
createdTo: search.get('createdTo') ?? search.get('to') ?? '',
page: Number(search.get('page') ?? 1),
pageSize: Number(search.get('pageSize') ?? 20),
});
}
function parseWorkspaceTaskQuery(search: URLSearchParams): WorkspaceTaskQuery {
return normalizeWorkspaceTaskQuery({
query: search.get('q') ?? search.get('query') ?? '',