feat(admin): Phase 3 平台团队+用户管理 — 列/启停/详情/强制改密 + 团队停用拦登录

后端:adminpanel 增 teams(列/详情/启停)+ users(列/启停/强制改密),AdminTeam/User 序列化器;
login 校验团队 status,停用团队成员拒登;停用用户清 token、禁停平台超管;全程 IsPlatformAdmin + 审计。
前端:adminApi teams/users 系列;Admin 团队页(筛选+搜索+详情弹窗+启停)、用户页(启停+改密弹窗,超管行禁操作)。
测试:adminpanel 19 + accounts 22 = 41 单测过;无头 e2e _admin-p3.mjs 7 断言过 + 0 console error
(UI 停用团队→成员登录 400→启用→200;UI 改密→新密码登录 200);tsc+build 绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
seaislee1209
2026-06-19 21:39:15 +08:00
co-authored by Claude Opus 4.8
parent 45a4ceae51
commit 6560633959
12 changed files with 818 additions and 4 deletions
+33
View File
@@ -1,4 +1,7 @@
import type {
AdminTeam,
AdminTeamDetail,
AdminUser,
AITask,
Asset,
AuthPayload,
@@ -531,5 +534,35 @@ export const adminApi = {
},
revokeInvite(id: string) {
return request<Invitation>(`/api/admin/invitations/${id}/revoke/`, { method: "POST" });
},
teams(params?: { status?: string; search?: string; page?: number; page_size?: number }) {
const qs = new URLSearchParams();
if (params?.status) qs.set("status", params.status);
if (params?.search) qs.set("search", params.search);
if (params?.page) qs.set("page", String(params.page));
if (params?.page_size) qs.set("page_size", String(params.page_size));
const q = qs.toString();
return request<Paginated<AdminTeam>>(`/api/admin/teams/${q ? `?${q}` : ""}`);
},
teamDetail(id: string) {
return request<AdminTeamDetail>(`/api/admin/teams/${id}/`);
},
toggleTeam(id: string) {
return request<AdminTeam>(`/api/admin/teams/${id}/toggle/`, { method: "POST" });
},
users(params?: { status?: string; search?: string; page?: number; page_size?: number }) {
const qs = new URLSearchParams();
if (params?.status) qs.set("status", params.status);
if (params?.search) qs.set("search", params.search);
if (params?.page) qs.set("page", String(params.page));
if (params?.page_size) qs.set("page_size", String(params.page_size));
const q = qs.toString();
return request<Paginated<AdminUser>>(`/api/admin/users/${q ? `?${q}` : ""}`);
},
toggleUser(id: string) {
return request<AdminUser>(`/api/admin/users/${id}/toggle/`, { method: "POST" });
},
resetUserPassword(id: string, password: string) {
return request<void>(`/api/admin/users/${id}/reset-password/`, { method: "POST", body: JSON.stringify({ password }) });
}
};