feat: add wallet settlement audit flow

This commit is contained in:
2026-05-11 22:59:26 +08:00
parent da1e19d0a9
commit c992f1de60
22 changed files with 1452 additions and 44 deletions
+40 -1
View File
@@ -6,6 +6,7 @@ import type {
GatewayAccessRule,
GatewayAccessRuleUpsertRequest,
GatewayApiKey,
GatewayAuditLog,
GatewayTenantUpsertRequest,
GatewayTask,
GatewayUserUpsertRequest,
@@ -20,6 +21,7 @@ import type {
RuntimePolicySet,
UserGroupUpsertRequest,
UserGroup,
WalletBalanceAdjustmentRequest,
} from '@easyai-ai-gateway/contracts';
import {
batchAccessRules,
@@ -38,6 +40,7 @@ import {
deleteUserGroup,
getHealth,
getTask,
listAuditLogs,
listAccessRules,
listApiKeyAccessRules,
listApiKeys,
@@ -61,6 +64,7 @@ import {
loginLocalAccount,
registerLocalAccount,
replacePlatformModels,
setUserWalletBalance,
type HealthResponse,
updateAccessRule,
updateGatewayUser,
@@ -130,6 +134,7 @@ type DataKey =
| 'userGroups'
| 'tasks'
| 'accessRules'
| 'auditLogs'
| 'apiKeys';
export function App() {
@@ -160,6 +165,7 @@ export function App() {
const [pricingRuleSets, setPricingRuleSets] = useState<PricingRuleSet[]>([]);
const [runtimePolicySets, setRuntimePolicySets] = useState<RuntimePolicySet[]>([]);
const [accessRules, setAccessRules] = useState<GatewayAccessRule[]>([]);
const [auditLogs, setAuditLogs] = useState<GatewayAuditLog[]>([]);
const [rateLimitWindows, setRateLimitWindows] = useState<RateLimitWindow[]>([]);
const [tenants, setTenants] = useState<GatewayTenant[]>([]);
const [users, setUsers] = useState<GatewayUser[]>([]);
@@ -238,6 +244,7 @@ export function App() {
const data = useMemo<ConsoleData>(() => ({
accessRules,
auditLogs,
apiKeys,
baseModels,
modelCatalog,
@@ -253,7 +260,7 @@ export function App() {
tenants,
userGroups,
users,
}), [accessRules, apiKeys, baseModels, modelCatalog, models, platforms, pricingRuleSets, pricingRules, providers, rateLimitWindows, runtimePolicySets, taskResult, tasks, tenants, userGroups, users]);
}), [accessRules, apiKeys, auditLogs, baseModels, modelCatalog, models, platforms, pricingRuleSets, pricingRules, providers, rateLimitWindows, runtimePolicySets, taskResult, tasks, tenants, userGroups, users]);
async function refresh(nextToken = token) {
await ensureRouteData(nextToken, true);
@@ -371,6 +378,9 @@ export function App() {
? listApiKeyAccessRules(nextToken)
: listAccessRules(nextToken))).items);
return;
case 'auditLogs':
setAuditLogs((await listAuditLogs(nextToken)).items);
return;
case 'apiKeys':
setApiKeys((await listApiKeys(nextToken)).items);
}
@@ -527,6 +537,31 @@ export function App() {
}
}
async function saveUserWalletBalance(userId: string, input: WalletBalanceAdjustmentRequest) {
setCoreState('loading');
setCoreMessage('');
try {
const response = await setUserWalletBalance(token, userId, input);
setUsers((current) => current.map((user) => user.id === userId
? {
...user,
walletAccounts: [
response.account,
...(user.walletAccounts ?? []).filter((account) => account.id !== response.account.id),
],
}
: user));
setAuditLogs((current) => [response.auditLog, ...current.filter((item) => item.id !== response.auditLog.id)]);
invalidateDataKeys('auditLogs');
setCoreState('ready');
setCoreMessage('用户余额已更新,审计日志已记录。');
} catch (err) {
setCoreState('error');
setCoreMessage(err instanceof Error ? err.message : '更新用户余额失败');
throw err;
}
}
async function removeUser(userId: string) {
setCoreState('loading');
setCoreMessage('');
@@ -697,6 +732,7 @@ export function App() {
setPricingRuleSets([]);
setRuntimePolicySets([]);
setAccessRules([]);
setAuditLogs([]);
setRateLimitWindows([]);
setTenants([]);
setUsers([]);
@@ -866,6 +902,7 @@ export function App() {
onSaveAccessRule={saveAccessRule}
onSaveTenant={saveTenant}
onSaveUser={saveUser}
onSetUserWalletBalance={saveUserWalletBalance}
onSaveUserGroup={saveUserGroup}
onSectionChange={navigateAdminSection}
/>
@@ -1015,6 +1052,8 @@ function dataKeysForRoute(
return ['users', 'tenants', 'userGroups'];
case 'userGroups':
return ['userGroups'];
case 'auditLogs':
return ['auditLogs'];
case 'accessRules':
return ['accessRules', 'userGroups', 'platforms', 'models'];
default: