增加了子管理员的功能

This commit is contained in:
Monster
2025-08-15 19:13:35 +08:00
parent cc8f3dffbc
commit 0874eacd8b
11 changed files with 923 additions and 23 deletions

View File

@@ -16,9 +16,11 @@ import {
DomainAdminUser,
DomainCreateAdminReq,
DomainExportCompletionDataResp,
DomainGrantRoleReq,
DomainListAdminLoginHistoryResp,
DomainListAdminUserResp,
DomainLoginReq,
DomainRole,
DomainSetting,
DomainUpdateSettingReq,
GetAdminLoginHistoryParams,
@@ -244,6 +246,55 @@ export const getAdminProfile = (params: RequestParams = {}) =>
...params,
});
/**
* @description 获取角色列表
*
* @tags Admin
* @name GetListRole
* @summary 获取角色列表
* @request GET:/api/v1/admin/role
* @response `200` `(WebResp & {
data?: (DomainRole)[],
})` OK
*/
export const getListRole = (params: RequestParams = {}) =>
request<
WebResp & {
data?: DomainRole[];
}
>({
path: `/api/v1/admin/role`,
method: "GET",
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 授权角色
*
* @tags Admin
* @name PostGrantRole
* @summary 授权角色
* @request POST:/api/v1/admin/role
* @response `200` `WebResp` OK
*/
export const postGrantRole = (
param: DomainGrantRoleReq,
params: RequestParams = {},
) =>
request<WebResp>({
path: `/api/v1/admin/role`,
method: "POST",
body: param,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 获取系统设置
*

231
ui/src/api/UserGroup.ts Normal file
View File

@@ -0,0 +1,231 @@
/* eslint-disable */
/* tslint:disable */
// @ts-nocheck
/*
* ---------------------------------------------------------------
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
* ## ##
* ## AUTHOR: acacode ##
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
* ---------------------------------------------------------------
*/
import request, { ContentType, RequestParams } from "./httpClient";
import {
DeleteDeleteGroupParams,
DomainCreateUserGroupReq,
DomainGrantGroupReq,
DomainGroupAddUserReq,
DomainGroupRemoveAdminReq,
DomainGroupRemoveUserReq,
DomainListUserGroupResp,
DomainUpdateUserGroupReq,
DomainUserGroup,
GetListUserGroupParams,
WebResp,
} from "./types";
/**
* @description 列出用户分组
*
* @tags UserGroup
* @name GetListUserGroup
* @summary 列出用户分组
* @request GET:/api/v1/admin/user-group
* @response `200` `(WebResp & {
data?: DomainListUserGroupResp,
})` OK
*/
export const getListUserGroup = (
query: GetListUserGroupParams,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainListUserGroupResp;
}
>({
path: `/api/v1/admin/user-group`,
method: "GET",
query: query,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 更新用户分组
*
* @tags UserGroup
* @name PutUpdateUserGroup
* @summary 更新用户分组
* @request PUT:/api/v1/admin/user-group
* @response `200` `(WebResp & {
data?: DomainUserGroup,
})` OK
*/
export const putUpdateUserGroup = (
param: DomainUpdateUserGroupReq,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainUserGroup;
}
>({
path: `/api/v1/admin/user-group`,
method: "PUT",
body: param,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 创建用户分组
*
* @tags UserGroup
* @name PostCreateGroup
* @summary 创建用户分组
* @request POST:/api/v1/admin/user-group
* @response `200` `(WebResp & {
data?: DomainUserGroup,
})` OK
*/
export const postCreateGroup = (
param: DomainCreateUserGroupReq,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainUserGroup;
}
>({
path: `/api/v1/admin/user-group`,
method: "POST",
body: param,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 删除用户分组
*
* @tags UserGroup
* @name DeleteDeleteGroup
* @summary 删除用户分组
* @request DELETE:/api/v1/admin/user-group
* @response `200` `WebResp` OK
*/
export const deleteDeleteGroup = (
query: DeleteDeleteGroupParams,
params: RequestParams = {},
) =>
request<WebResp>({
path: `/api/v1/admin/user-group`,
method: "DELETE",
query: query,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 从分组中移除管理员
*
* @tags UserGroup
* @name DeleteRemoveAdminFromGroup
* @summary 从分组中移除管理员
* @request DELETE:/api/v1/admin/user-group/admin
* @response `200` `WebResp` OK
*/
export const deleteRemoveAdminFromGroup = (
param: DomainGroupRemoveAdminReq,
params: RequestParams = {},
) =>
request<WebResp>({
path: `/api/v1/admin/user-group/admin`,
method: "DELETE",
body: param,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 授权分组给管理员
*
* @tags UserGroup
* @name PostGrantGroup
* @summary 授权分组给管理员
* @request POST:/api/v1/admin/user-group/grant
* @response `200` `WebResp` OK
*/
export const postGrantGroup = (
param: DomainGrantGroupReq,
params: RequestParams = {},
) =>
request<WebResp>({
path: `/api/v1/admin/user-group/grant`,
method: "POST",
body: param,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 添加用户到分组
*
* @tags UserGroup
* @name PostAddUserToGroup
* @summary 添加用户到分组
* @request POST:/api/v1/admin/user-group/user
* @response `200` `WebResp` OK
*/
export const postAddUserToGroup = (
param: DomainGroupAddUserReq,
params: RequestParams = {},
) =>
request<WebResp>({
path: `/api/v1/admin/user-group/user`,
method: "POST",
body: param,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 从分组中移除用户
*
* @tags UserGroup
* @name DeleteRemoveUserFromGroup
* @summary 从分组中移除用户
* @request DELETE:/api/v1/admin/user-group/user
* @response `200` `WebResp` OK
*/
export const deleteRemoveUserFromGroup = (
param: DomainGroupRemoveUserReq,
params: RequestParams = {},
) =>
request<WebResp>({
path: `/api/v1/admin/user-group/user`,
method: "DELETE",
body: param,
type: ContentType.Json,
format: "json",
...params,
});

View File

@@ -9,6 +9,7 @@ export * from './OpenAiv1'
export * from './SecurityScanning'
export * from './User'
export * from './UserDashboard'
export * from './UserGroup'
export * from './UserManage'
export * from './UserRecord'
export * from './UserSecurityScanning'

View File

@@ -166,6 +166,8 @@ export interface DomainAdminUser {
id?: string;
/** 最后活跃时间 */
last_active_at?: number;
/** 角色 */
role?: DomainRole;
/** 用户状态 active: 正常 inactive: 禁用 */
status?: ConstsAdminStatus;
/** 用户名 */
@@ -243,7 +245,7 @@ export interface DomainCheckModelReq {
api_base: string;
api_header?: string;
/** 接口密钥 */
api_key: string;
api_key?: string;
api_version?: string;
/** 模型名称 */
model_name: string;
@@ -366,9 +368,11 @@ export interface DomainCompletionRecord {
export interface DomainCreateAdminReq {
/** 密码 */
password?: string;
password: string;
/** 角色ID */
role_id: number;
/** 用户名 */
username?: string;
username: string;
}
export interface DomainCreateModelReq {
@@ -409,6 +413,11 @@ export interface DomainCreateSecurityScanningReq {
workspace?: string;
}
export interface DomainCreateUserGroupReq {
/** 组名称 */
name: string;
}
export interface DomainCreateWorkspaceFileReq {
/** 文件内容 */
content?: string;
@@ -525,6 +534,41 @@ export interface DomainGetProviderModelListResp {
models?: DomainProviderModelListItem[];
}
export interface DomainGrantGroupReq {
/** 管理员ID列表 */
admin_ids: string[];
/** 分组ID列表 */
group_ids: string[];
}
export interface DomainGrantRoleReq {
/** 管理员ID */
admin_id?: string;
/** 角色ID列表 */
role_ids?: number[];
}
export interface DomainGroupAddUserReq {
/** 分组ID列表 */
group_ids: string[];
/** 用户ID列表 */
user_ids: string[];
}
export interface DomainGroupRemoveAdminReq {
/** 管理员ID列表 */
admin_ids: string[];
/** 分组ID */
group_id: string;
}
export interface DomainGroupRemoveUserReq {
/** 分组ID */
group_id: string;
/** 用户ID列表 */
user_ids: string[];
}
export interface DomainIPInfo {
/** ASN */
asn?: string;
@@ -641,6 +685,13 @@ export interface DomainListSecurityScanningResp {
total_count?: number;
}
export interface DomainListUserGroupResp {
groups?: DomainUserGroup[];
has_next_page?: boolean;
next_token?: string;
total_count?: number;
}
export interface DomainListUserResp {
has_next_page?: boolean;
next_token?: string;
@@ -832,6 +883,12 @@ export interface DomainReportReq {
user_input?: string;
}
export interface DomainRole {
description?: string;
id?: number;
name?: string;
}
export interface DomainSecurityScanningBrief {
/** 创建时间 */
created_at?: number;
@@ -1049,6 +1106,12 @@ export interface DomainUpdateSettingReq {
force_two_factor_auth?: boolean;
}
export interface DomainUpdateUserGroupReq {
/** 分组id */
id: string;
name: string;
}
export interface DomainUpdateUserReq {
/** 用户ID */
id: string;
@@ -1108,6 +1171,16 @@ export interface DomainUserEvent {
name?: string;
}
export interface DomainUserGroup {
/** 关联的管理员 */
admins?: DomainAdminUser[];
id?: string;
/** 组名 */
name?: string;
/** 关联的用户 */
users?: DomainUser[];
}
export interface DomainUserHeatmap {
count?: number;
date?: number;
@@ -1265,6 +1338,20 @@ export interface GetAdminLoginHistoryParams {
size?: number;
}
export interface GetListUserGroupParams {
/** 下一页标识 */
next_token?: string;
/** 分页 */
page?: number;
/** 每页多少条记录 */
size?: number;
}
export interface DeleteDeleteGroupParams {
/** 分组id */
id: string;
}
export interface GetChatInfoParams {
/** 对话记录ID */
id: string;

View File

@@ -6,10 +6,15 @@ import {
IconButton,
TextField,
Paper,
Select,
MenuItem,
FormControl,
InputLabel,
} from '@mui/material';
import { AdminPanelSettings, Person } from '@mui/icons-material';
import { postCreateAdmin } from '@/api/Admin';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import { deleteDeleteAdmin, getListAdminUser } from '@/api/Admin';
import { deleteDeleteAdmin, getAdminProfile, getListAdminUser, postGrantRole } from '@/api/Admin';
import { Table, Modal, message } from '@c-x/ui';
import { ColumnsType } from '@c-x/ui/dist/Table';
import { useRequest } from 'ahooks';
@@ -44,6 +49,7 @@ const AddAdminModal = ({
postCreateAdmin({
username: data.username,
password,
role_id: data.roleId, // 添加 role_id 参数
}).then(() => {
setIsSuccess(true);
message.success('添加成功');
@@ -53,7 +59,9 @@ const AddAdminModal = ({
useEffect(() => {
if (open) {
reset();
reset({
roleId: 2, // 设置默认角色为普通管理员
});
} else {
setIsSuccess(false);
setPassword(Math.random().toString(36).substring(2, 15));
@@ -85,6 +93,29 @@ const AddAdminModal = ({
/>
)}
/>
<Controller
control={control}
name='roleId'
rules={{ required: '请选择角色' }}
render={({ field }) => (
<FormControl fullWidth required error={!!errors.roleId}>
<InputLabel></InputLabel>
<Select
label='角色'
{...field}
value={field.value || ''} // 确保有默认值
>
<MenuItem value={1}></MenuItem>
<MenuItem value={2}></MenuItem>
</Select>
{errors.roleId && (
<Box sx={{ color: 'error.main', fontSize: '0.75rem', mt: 0.5 }}>
{errors.roleId?.message as string}
</Box>
)}
</FormControl>
)}
/>
<Stack
direction='row'
justifyContent='flex-end'
@@ -154,6 +185,20 @@ const AddAdminModal = ({
const AdminUser = () => {
const [open, setOpen] = useState(false);
const { data, loading, refresh } = useRequest(() => getListAdminUser({}));
const { data: currentAdmin } = useRequest(() => getAdminProfile({}));
const handleRoleChange = (adminId: string, newRoleId: number) => {
postGrantRole({
admin_id: adminId,
role_ids: [newRoleId],
}).then(() => {
message.success('角色更新成功');
refresh();
}).catch(() => {
message.error('角色更新失败');
});
};
const onDeleteAdmin = (data: DomainAdminUser) => {
Modal.confirm({
title: '提示',
@@ -187,21 +232,65 @@ const AdminUser = () => {
},
},
{
title: '加入时间',
dataIndex: 'created_at',
width: 140,
render: (text) => {
return dayjs.unix(text).fromNow();
title: '角色',
dataIndex: 'last_active_at',
render: (text, record) => {
return (
<FormControl fullWidth>
<Select
size='small'
value={record.role?.id || ''}
onChange={(e) => handleRoleChange(record.id!, Number(e.target.value))}
displayEmpty
disabled={record.id === currentAdmin?.id}
renderValue={(value) => {
if (value === 1) {
return (
<Stack direction="row" alignItems="center" gap={1}>
<AdminPanelSettings fontSize="small" />
<span></span>
</Stack>
);
} else if (value === 2) {
return (
<Stack direction="row" alignItems="center" gap={1}>
<Person fontSize="small" />
<span></span>
</Stack>
);
}
return "请选择角色";
}}
sx={{
mr: 1
}}
>
<MenuItem value={1}>
<Stack direction="row" alignItems="center" gap={1}>
<AdminPanelSettings fontSize="small" />
<span></span>
</Stack>
</MenuItem>
<MenuItem value={2}>
<Stack direction="row" alignItems="center" gap={1}>
<Person fontSize="small" />
<span></span>
</Stack>
</MenuItem>
</Select>
</FormControl>
);
},
},
{
title: '最近活跃',
dataIndex: 'last_active_at',
width: 140,
title: '活跃时间',
dataIndex: 'created_at',
width: 120,
render: (text, record) => {
return record.last_active_at === 0
? '从未使用'
: dayjs.unix(text).fromNow();
return <Stack>
<Box>{dayjs.unix(text).fromNow()}</Box>
<Box>{record.last_active_at === 0 ? '从未使用' : dayjs.unix(text).fromNow()}</Box>
</Stack>
},
},
{

View File

@@ -0,0 +1,58 @@
import React, { useState } from 'react';
import { Modal, message } from '@c-x/ui';
import { Box, TextField } from '@mui/material';
import { postCreateGroup } from '@/api/UserGroup';
const CreateGroupModal = ({
open,
onClose,
onCreated, // 添加一个回调函数,用于在创建成功后刷新列表
}: {
open: boolean;
onClose: () => void;
onCreated?: () => void; // 可选的回调函数
}) => {
const [groupName, setGroupName] = useState('');
const handleCreate = async () => {
if (!groupName.trim()) {
message.error('请输入成员组名称');
return;
}
try {
await postCreateGroup({ name: groupName });
message.success('成员组创建成功');
setGroupName(''); // 清空输入框
onCreated?.(); // 调用回调函数刷新列表
onClose(); // 关闭弹窗
} catch (error) {
console.error('创建成员组失败:', error);
message.error('创建成员组失败');
}
};
return (
<Modal
title='创建成员组'
width={500}
open={open}
onOk={handleCreate}
onCancel={onClose}
okText='创建'
cancelText='取消'
>
<Box sx={{ mt: 2 }}>
<TextField
label='成员组名称'
fullWidth
value={groupName}
onChange={(e) => setGroupName(e.target.value)}
variant='outlined'
/>
</Box>
</Modal>
);
};
export default CreateGroupModal;

View File

@@ -0,0 +1,309 @@
import React, { useEffect, useState } from 'react';
import Card from '@/components/card';
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
import { useRequest } from 'ahooks';
import { getListUser } from '@/api/User';
import {
Stack,
Box,
Button,
IconButton,
Menu,
MenuItem,
FormControl,
InputLabel,
Select,
Chip,
SelectChangeEvent,
} from '@mui/material';
import { Table, Modal, message } from '@c-x/ui';
import { ColumnsType } from '@c-x/ui/dist/Table';
import { DomainAdminUser, DomainUser, DomainUserGroup } from '@/api/types';
import { deleteDeleteGroup, getListAdminUser, getListUserGroup } from '@/api';
import { deleteRemoveAdminFromGroup, postGrantGroup, postAddUserToGroup, deleteRemoveUserFromGroup, putUpdateUserGroup } from '@/api/UserGroup';
import CreateGroupModal from './createGroupModal';
import UpdateGroupModal from './updateGroupModal';
import { Check } from '@mui/icons-material';
const GroupList = () => {
const [openCreateGroupModal, setOpenCreateGroupModal] = useState(false);
const [openUpdateGroupModal, setOpenUpdateGroupModal] = useState(false);
const [currentGroup, setCurrentGroup] = useState<DomainUserGroup | null>(null);
const groupData = useRequest(() => getListUserGroup({}));
const userData = useRequest(() => getListUser({}));
const adminData = useRequest(() => getListAdminUser({}));
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const handleClick = (
event: React.MouseEvent<HTMLButtonElement>,
record: DomainUserGroup
) => {
setAnchorEl(event.currentTarget);
setCurrentGroup(record);
};
const handleClose = () => {
setAnchorEl(null);
};
const onDeleteGroup = () => {
handleClose();
Modal.confirm({
title: '提示',
okText: '删除',
okButtonProps: {
color: 'error',
},
content: (
<>
{' '}
<Box component='span' sx={{ fontWeight: 700, color: 'text.primary' }}>
{currentGroup!.name}
</Box>{' '}
</>
),
onOk: () => {
deleteDeleteGroup({ id: currentGroup!.id! }).then(() => {
message.success('删除成功');
groupData.refresh();
});
},
});
};
const onUpdateGroup = () => {
handleClose();
setOpenUpdateGroupModal(true);
};
const columns: ColumnsType<DomainUserGroup> = [
{
title: '成员组',
dataIndex: 'name',
width: 120,
render: (text) => {
return text;
},
},
{
title: '成员',
dataIndex: 'users',
render: (users, record) => {
return <FormControl sx={{ width: '100%' }}>
<InputLabel size='small'></InputLabel>
<Select
multiple
value={(users || []).map((u: DomainUser) => u.id)}
label='成员'
size='small'
renderValue={(selectedIds: string[]) => {
if (!Array.isArray(selectedIds)) return null;
const selectedUsers = (userData.data?.users || []).filter((user: DomainUser) =>
user.id && selectedIds.includes(user.id)
);
return selectedUsers.map((u: DomainUser) => (
<Chip size='small' key={u.id} label={u.username}></Chip>
));
}}
onChange={(event: SelectChangeEvent<string[]>) => {
console.log(event.target)
// 获取当前分组的成员ID列表
const currentUserIds = (users || []).map((user: DomainUser) => user.id!);
// 获取选择的成员ID列表
const selectedUserIds = event.target.value as string[];
// 计算新增的成员ID
const addedUserIds = selectedUserIds.filter(id => !currentUserIds.includes(id));
// 计算移除的成员ID
const removedUserIds = currentUserIds.filter((id: string) => !selectedUserIds.includes(id));
// 调用API添加成员
if (addedUserIds.length > 0) {
postAddUserToGroup({
user_ids: addedUserIds,
group_ids: [record.id!]
}).then(() => {
message.success('成员添加成功');
groupData.refresh();
}).catch(() => {
message.error('成员添加失败');
});
}
// 调用API移除成员
if (removedUserIds.length > 0) {
deleteRemoveUserFromGroup({
user_ids: removedUserIds,
group_id: record.id!
}).then(() => {
message.success('成员移除成功');
groupData.refresh();
}).catch(() => {
message.error('成员移除失败');
});
}
}}
>
{userData.data?.users?.map((user) => (
<MenuItem key={user.username} value={user.id}>
{(users.some((u: DomainUser) => {
return u.id === user.id
})) ? <>
{user.username}<Check sx={{ ml: 2, width: '16px' }} />
</> : <>
{user.username}
</>}
</MenuItem>)
)}
</Select>
</FormControl>;
},
},
{
title: '管理员',
dataIndex: 'admins',
render: (admins, record) => {
return <FormControl sx={{ width: '100%' }}>
<InputLabel size='small'></InputLabel>
<Select
multiple
value={(admins || []).map((u: DomainAdminUser) => u.id)}
label='管理员'
size='small'
renderValue={(selectedIds: string[]) => {
if (!Array.isArray(selectedIds)) return null;
const selectedAdmins = (adminData.data?.users || []).filter((user: DomainAdminUser) =>
user.id && selectedIds.includes(user.id)
);
return selectedAdmins.map((u: DomainAdminUser) => (
<Chip size='small' key={u.id} label={u.username}></Chip>
));
}}
onChange={(event: SelectChangeEvent<string[]>) => {
console.log(event.target)
// 获取当前分组的管理员ID列表
const currentAdminIds = (admins || []).map((user: DomainAdminUser) => user.id!);
// 获取选择的管理员ID列表
const selectedAdminIds = event.target.value as string[];
// 计算新增的管理员ID
const addedAdminIds = selectedAdminIds.filter(id => !currentAdminIds.includes(id));
// 计算移除的管理员ID
const removedAdminIds = currentAdminIds.filter((id: string) => !selectedAdminIds.includes(id));
// 调用API添加管理员
if (addedAdminIds.length > 0) {
postGrantGroup({
admin_ids: addedAdminIds,
group_ids: [record.id!]
}).then(() => {
message.success('管理员添加成功');
groupData.refresh();
}).catch(() => {
message.error('管理员添加失败');
});
}
// 调用API移除管理员
if (removedAdminIds.length > 0) {
deleteRemoveAdminFromGroup({
admin_ids: removedAdminIds,
group_id: record.id!
}).then(() => {
message.success('管理员移除成功');
groupData.refresh();
}).catch(() => {
message.error('管理员移除失败');
});
}
}}
>
{adminData.data?.users?.map((user) => (
<MenuItem key={user.username} value={user.id}>
{(admins.some((u: DomainAdminUser) => {
return u.id === user.id
})) ? <>
{user.username}<Check sx={{ ml: 2, width: '16px' }} />
</> : <>
{user.username}
</>}
</MenuItem>)
)}
</Select>
</FormControl>;
},
},
{
title: '操作',
dataIndex: 'action',
width: 80,
render: (_, record) => {
return (
<IconButton
onClick={(e) => handleClick(e, record)}
sx={{
'&:hover': {
color: 'info.main',
},
}}
>
<MoreHorizIcon />
</IconButton>
);
},
},
];
return (
<Card sx={{ maxHeight: '500px' }}>
<Menu anchorEl={anchorEl} open={!!anchorEl} onClose={handleClose}>
<MenuItem onClick={onUpdateGroup}>
</MenuItem>
<MenuItem sx={{ color: 'error.main' }} onClick={onDeleteGroup}>
</MenuItem>
</Menu>
<Stack
direction='row'
justifyContent='space-between'
alignItems='center'
sx={{ mb: 2 }}
>
<Box sx={{ fontWeight: 700 }}></Box>
<Stack direction='row' gap={1}>
<Button
variant='contained'
color='primary'
onClick={() => setOpenCreateGroupModal(true)}
></Button>
</Stack>
</Stack>
<Table
columns={columns}
height='calc(100% - 53px)'
dataSource={groupData.data?.groups || []}
sx={{ mx: -2 }}
pagination={false}
rowKey='id'
loading={groupData.loading}
/>
<CreateGroupModal
open={openCreateGroupModal}
onClose={() => setOpenCreateGroupModal(false)}
onCreated={() => groupData.refresh()} // 添加 onCreated 回调函数
/>
<UpdateGroupModal
open={openUpdateGroupModal}
onClose={() => setOpenUpdateGroupModal(false)}
onUpdated={() => groupData.refresh()}
group={currentGroup}
/>
</Card>
);
};
export default GroupList;

View File

@@ -14,6 +14,7 @@ import MemberManage from './memberManage';
import LoginHistory from './loginHistory';
import { message } from '@c-x/ui';
import ThirdPartyLoginSettingModal from './thirdPartyLoginSettingModal';
import GroupList from './groupList';
const StyledCard = styled(Card)({
display: 'flex',
@@ -65,14 +66,17 @@ const User = () => {
<Stack gap={2} sx={{ height: '100%' }}>
<Grid container spacing={2} sx={{ height: '100%' }}>
<Grid size={6} sx={{ height: '100%' }}>
<MemberManage />
<Stack gap={2} sx={{ height: '100%' }}>
<GroupList />
<MemberManage />
</Stack>
</Grid>
<Grid size={6} container sx={{ height: '100%' }}>
<Stack gap={2} sx={{ height: '100%' }}>
<StyledCard>
<StyledLabel></StyledLabel>
<Switch
checked={data?.force_two_factor_auth}
checked={!!data?.force_two_factor_auth}
onChange={(e) => {
updateSetting({ force_two_factor_auth: e.target.checked });
}}
@@ -81,7 +85,7 @@ const User = () => {
<StyledCard>
<StyledLabel>使</StyledLabel>
<Switch
checked={data?.disable_password_login}
checked={!!data?.disable_password_login}
onChange={(e) =>
updateSetting({ disable_password_login: e.target.checked })
}
@@ -90,7 +94,7 @@ const User = () => {
<StyledCard>
<StyledLabel></StyledLabel>
<Switch
checked={data?.enable_auto_login}
checked={!!data?.enable_auto_login}
onChange={(e) =>
updateSetting({ enable_auto_login: e.target.checked })
}

View File

@@ -98,7 +98,7 @@ const LoginHistory = () => {
},
];
return (
<Card sx={{ flex: 1, height: 'calc(100% - 358px)' }}>
<Card sx={{ flex: 1, height: '500px' }}>
<Stack
direction='row'
justifyContent='space-between'

View File

@@ -282,7 +282,7 @@ const MemberManage = () => {
},
},
{
title: '',
title: '操作',
dataIndex: 'action',
width: 80,
render: (_, record) => {
@@ -302,7 +302,7 @@ const MemberManage = () => {
},
];
return (
<Card sx={{ flex: 1, height: '100%' }}>
<Card sx={{ flex: 1, height: '500px' }}>
<Menu anchorEl={anchorEl} open={!!anchorEl} onClose={handleClose}>
{currentUser?.status === ConstsUserStatus.UserStatusActive && (
<MenuItem onClick={onLockUser}></MenuItem>

View File

@@ -0,0 +1,70 @@
import React, { useState, useEffect } from 'react';
import { Modal, message } from '@c-x/ui';
import { Box, TextField } from '@mui/material';
import { putUpdateUserGroup } from '@/api/UserGroup';
import { DomainUserGroup } from '@/api/types';
interface UpdateGroupModalProps {
open: boolean;
onClose: () => void;
onUpdated?: () => void;
group: DomainUserGroup | null;
}
const UpdateGroupModal = ({ open, onClose, onUpdated, group }: UpdateGroupModalProps) => {
const [groupName, setGroupName] = useState('');
// 当group变化时更新表单中的组名
useEffect(() => {
if (group) {
setGroupName(group.name || '');
}
}, [group]);
const handleUpdate = async () => {
if (!groupName.trim()) {
message.error('请输入成员组名称');
return;
}
if (!group?.id) {
message.error('无效的成员组');
return;
}
try {
await putUpdateUserGroup({ id: group.id, name: groupName });
message.success('成员组名称更新成功');
setGroupName(''); // 清空输入框
onUpdated?.(); // 调用回调函数刷新列表
onClose(); // 关闭弹窗
} catch (error) {
console.error('更新成员组名称失败:', error);
message.error('更新成员组名称失败');
}
};
return (
<Modal
title='修改成员组名称'
width={500}
open={open}
onOk={handleUpdate}
onCancel={onClose}
okText='确定'
cancelText='取消'
>
<Box sx={{ mt: 2 }}>
<TextField
label='成员组名称'
fullWidth
value={groupName}
onChange={(e) => setGroupName(e.target.value)}
variant='outlined'
/>
</Box>
</Modal>
);
};
export default UpdateGroupModal;