后台支持多账号与页面访问权限

保留环境变量管理员作为 owner,并新增可持久化管理的 member 账号
建立一级页面权限、实时会话失效和后端逐请求鉴权
统一操作记录与配置记录展示管理员显示名称,隐藏内部主体标识
补充账号管理页面、生成绑定、定向测试和技术文档
This commit is contained in:
2026-07-14 19:18:54 +08:00
parent a597fcd076
commit bddc25b4e0
52 changed files with 3742 additions and 88 deletions
@@ -1,16 +1,61 @@
import { afterEach, expect, test, vi } from 'vitest';
import {
createAdminAccount,
executeAdminRechargeRefund,
getAdminUserDetail,
listAdminRechargeOrders,
resolveAdminRechargeRefundManualReview,
updateAdminAccount,
} from './adminApiClient';
afterEach(() => {
vi.unstubAllGlobals();
});
test('后台账号创建和更新携带 owner 会话与 Tab 权限', async () => {
const fetchMock = vi.fn().mockImplementation(() =>
Promise.resolve(
new Response(JSON.stringify({account: {accountId: 'member-1'}}), {
status: 200,
}),
),
);
vi.stubGlobal('fetch', fetchMock);
await createAdminAccount('owner-token', {
username: 'operator',
displayName: '运营',
password: 'secret123',
tabPermissions: ['dashboard', 'tracking'],
enabled: true,
});
await updateAdminAccount('owner-token', 'member/1', {
displayName: '运营二组',
tabPermissions: ['tracking'],
enabled: false,
});
expect(fetchMock.mock.calls[0]?.[0]).toBe('/admin/api/accounts');
expect(fetchMock.mock.calls[0]?.[1]).toEqual(
expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({Authorization: 'Bearer owner-token'}),
}),
);
expect(fetchMock.mock.calls[1]?.[0]).toBe('/admin/api/accounts/member%2F1');
expect(fetchMock.mock.calls[1]?.[1]).toEqual(
expect.objectContaining({
method: 'PUT',
body: JSON.stringify({
displayName: '运营二组',
tabPermissions: ['tracking'],
enabled: false,
}),
}),
);
});
test('充值订单查询按后台契约序列化筛选参数', async () => {
const fetchMock = vi.fn().mockResolvedValue(
new Response(JSON.stringify({ entries: [] }), {
+31
View File
@@ -1,4 +1,7 @@
import type {
AdminAccountListResponse,
AdminCreateAccountRequest,
AdminCreateAccountResponse,
AdminUpsertCreationEntryEventBannersRequest,
AdminUpsertCreationEntryTypeConfigRequest,
AdminCreationEntryConfigResponse,
@@ -39,6 +42,8 @@ import type {
AdminTrackingEventListResponse,
AdminUpdateWorkVisibilityRequest,
AdminUpdateWorkVisibilityResponse,
AdminUpdateAccountRequest,
AdminUpdateAccountResponse,
AdminUploadedEditorShowcaseCampaignImage,
AdminUpsertEditorShowcaseCampaignRequest,
AdminUpsertFeatureGateConfigRequest,
@@ -188,6 +193,32 @@ export function getAdminMe(token: string) {
return request<AdminMeResponse>('/admin/api/me', { token });
}
export function listAdminAccounts(token: string) {
return request<AdminAccountListResponse>('/admin/api/accounts', {token});
}
export function createAdminAccount(
token: string,
payload: AdminCreateAccountRequest,
) {
return request<AdminCreateAccountResponse>('/admin/api/accounts', {
method: 'POST',
token,
body: payload,
});
}
export function updateAdminAccount(
token: string,
accountId: string,
payload: AdminUpdateAccountRequest,
) {
return request<AdminUpdateAccountResponse>(
`/admin/api/accounts/${encodeURIComponent(accountId)}`,
{method: 'PUT', token, body: payload},
);
}
export function getAdminOverview(token: string) {
return request<AdminOverviewResponse>('/admin/api/overview', { token });
}
+50
View File
@@ -36,10 +36,53 @@ export interface AdminSessionPayload {
username: string;
displayName: string;
roles: string[];
accountRole: 'owner' | 'member';
tabPermissions: string[];
issuedAt: string;
expiresAt: string;
}
export interface AdminAccountPayload {
accountId: string;
username: string;
displayName: string;
accountRole: 'owner' | 'member';
tabPermissions: string[];
enabled: boolean;
tokenVersion: number;
createdBy: string;
updatedBy: string;
createdAt: string;
updatedAt: string;
}
export interface AdminAccountListResponse {
accounts: AdminAccountPayload[];
}
export interface AdminCreateAccountRequest {
username: string;
displayName: string;
password: string;
tabPermissions: string[];
enabled: boolean;
}
export interface AdminCreateAccountResponse {
account: AdminAccountPayload;
}
export interface AdminUpdateAccountRequest {
displayName: string;
password?: string;
tabPermissions: string[];
enabled: boolean;
}
export interface AdminUpdateAccountResponse {
account: AdminAccountPayload;
}
export interface AdminLoginResponse {
token: string;
admin: AdminSessionPayload;
@@ -629,6 +672,7 @@ export interface ProfileCodeOperationAdminResponse {
code: string;
action: 'create' | 'update' | 'disable' | string;
operatorUserId: string;
operatorDisplayName: string;
createdAt: string;
}
@@ -665,8 +709,10 @@ export interface ProfileTaskConfigAdminResponse {
enabled: boolean;
sortOrder: number;
createdBy: string;
createdByDisplayName: string;
createdAt: string;
updatedBy: string;
updatedByDisplayName: string;
updatedAt: string;
}
@@ -705,8 +751,10 @@ export interface ProfileWalletConfigAdminResponse {
configId: string;
initialMudPoints: number;
createdBy: string;
createdByDisplayName: string;
createdAt: string;
updatedBy: string;
updatedByDisplayName: string;
updatedAt: string;
}
@@ -762,8 +810,10 @@ export interface AdminWalletManualRestrictionPayload {
frozen: boolean;
reason: string;
createdByAdminUserId: string;
createdByAdminDisplayName: string;
createdAtMicros: number;
updatedByAdminUserId: string;
updatedByAdminDisplayName: string;
updatedAtMicros: number;
}