1
This commit is contained in:
Vendored
+6
-6
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -28,7 +28,7 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script type="module" crossorigin src="/assets/index-Dfcsk8qj.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DrSOP-Lq.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-D7ShJUt4.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -456,6 +456,10 @@ export async function updateUserMenus(userId: string, allowedMenus: string[] | n
|
||||
await api.put(`/admin/users/${userId}/menus`, { allowed_menus: allowedMenus });
|
||||
}
|
||||
|
||||
export async function updateUserAdminStatus(userId: string, isAdmin: boolean): Promise<void> {
|
||||
await api.put(`/admin/users/${userId}/admin-status`, { is_admin: isAdmin });
|
||||
}
|
||||
|
||||
export async function resetUserPassword(userId: string, newPassword: string): Promise<void> {
|
||||
await api.put(`/admin/users/${userId}/reset-password`, { new_password: newPassword });
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
Button, Card, Checkbox, Form, Input, InputNumber, message, Modal, Popconfirm, Progress, Select, Space, Switch, Table, Tabs, Tag, Typography,
|
||||
} from 'antd';
|
||||
import {
|
||||
UserOutlined, WalletOutlined, SearchOutlined, StopOutlined, CheckCircleOutlined, PlusOutlined, MenuOutlined, LockOutlined, SettingOutlined, SaveOutlined, DatabaseOutlined, TeamOutlined, PictureOutlined,
|
||||
UserOutlined, WalletOutlined, SearchOutlined, StopOutlined, CheckCircleOutlined, PlusOutlined, MenuOutlined, LockOutlined, SettingOutlined, SaveOutlined, DatabaseOutlined, TeamOutlined, PictureOutlined, SecurityScanOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import {
|
||||
adjustCredits,
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
updateUserTeam,
|
||||
updateSystemConfig,
|
||||
updateUserMenus,
|
||||
updateUserAdminStatus,
|
||||
} from '../api';
|
||||
import type { AdminTeamOption, AdminUser, AdminUserResourceCapacityOut, PrivatePortraitConfig, ResourceCapacityUnit, ResourceCapacityUsage, SystemConfig } from '../types';
|
||||
import { formatDate } from '../utils/formatDate';
|
||||
@@ -379,6 +380,16 @@ const AdminUsers: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleAdminStatus = async (user: AdminUser) => {
|
||||
try {
|
||||
await updateUserAdminStatus(user.id, !user.isAdmin);
|
||||
message.success(user.isAdmin ? '已取消超级管理员' : '已设为超级管理员');
|
||||
load();
|
||||
} catch (e: any) {
|
||||
message.error(e?.message || '设置失败');
|
||||
}
|
||||
};
|
||||
|
||||
const isAdminTab = activeTab === 'admin';
|
||||
|
||||
const columns = [
|
||||
@@ -397,7 +408,7 @@ const AdminUsers: React.FC = () => {
|
||||
<div>
|
||||
<div style={{ fontWeight: 600 }}>
|
||||
{r.username}
|
||||
{r.isAdmin && <Tag color="orange" style={{ marginLeft: 6, fontSize: 10 }}>管理员</Tag>}
|
||||
{r.isAdmin && <Tag color="orange" style={{ marginLeft: 6, fontSize: 10 }}>超级管理员</Tag>}
|
||||
</div>
|
||||
<div style={{ color: '#94a3b8', fontSize: 12 }}>{r.email}</div>
|
||||
</div>
|
||||
@@ -476,7 +487,7 @@ const AdminUsers: React.FC = () => {
|
||||
render: (v: string) => <Typography.Text type="secondary" style={{ fontSize: 12 }}>{formatDate(v)}</Typography.Text>,
|
||||
},
|
||||
{
|
||||
title: '操作', key: 'action', width: 540, fixed: 'right' as const,
|
||||
title: '操作', key: 'action', width: 560, fixed: 'right' as const,
|
||||
render: (_: any, r: AdminUser) => (
|
||||
<Space size={4} wrap>
|
||||
{!isAdminTab && (
|
||||
@@ -509,6 +520,17 @@ const AdminUsers: React.FC = () => {
|
||||
{!isAdminTab && r.frontendUserKind === 'internal' && (
|
||||
<Button type="link" size="small" onClick={() => handleUpdateFrontendKind(r, 'external')}>取消内部</Button>
|
||||
)}
|
||||
{isAdminTab && (
|
||||
<Popconfirm
|
||||
title={r.isAdmin ? '确定取消该用户的超级管理员权限?' : '确定将该用户设为超级管理员?'}
|
||||
onConfirm={() => handleToggleAdminStatus(r)}
|
||||
>
|
||||
<Button type="link" size="small" style={{ color: r.isAdmin ? '#f59e0b' : '#6366f1' }}
|
||||
icon={<SecurityScanOutlined />}>
|
||||
{r.isAdmin ? '取消超级管理员' : '设为超级管理员'}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
<Button type="link" size="small" icon={<MenuOutlined />}
|
||||
onClick={() => openMenuModal(r)}>
|
||||
菜单权限
|
||||
|
||||
@@ -279,6 +279,26 @@ async def update_user_status(
|
||||
return {"message": "ok"}
|
||||
|
||||
|
||||
@router.put("/users/{user_id}/admin-status")
|
||||
async def update_user_admin_status(
|
||||
user_id: str,
|
||||
body: dict,
|
||||
admin: User = Depends(get_admin_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
is_admin = body.get("is_admin", False)
|
||||
result = await db.execute(select(User).where(User.id == user_id).limit(1))
|
||||
user = result.scalar_one_or_none()
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="用户不存在")
|
||||
if user.user_type != "admin":
|
||||
raise HTTPException(status_code=400, detail="仅后台用户支持设置超级管理员状态")
|
||||
user.is_admin = is_admin
|
||||
await db.flush()
|
||||
await log_operation(db, admin.id, admin.username, f"{is_admin and '设为' or '取消'}超级管理员", "PUT", f"/admin/users/{user_id}/admin-status")
|
||||
return {"message": "ok"}
|
||||
|
||||
|
||||
@router.put("/users/{user_id}/frontend-kind", response_model=AdminUserOut)
|
||||
async def update_user_frontend_kind(
|
||||
user_id: str,
|
||||
|
||||
Reference in New Issue
Block a user