diff --git a/back/api/user.ts b/back/api/user.ts index 9da5ef0d..b50c5492 100644 --- a/back/api/user.ts +++ b/back/api/user.ts @@ -97,6 +97,7 @@ export default (app: Router) => { username: authInfo.username, avatar: authInfo.avatar, twoFactorActivated: authInfo.twoFactorActivated, + role: req.user?.role, }, }); } catch (e) { diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 7d1e7675..a7561195 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -530,5 +530,20 @@ "请输入自定义日志文件夹名称或绝对路径": "Please enter a custom log folder name or absolute path", "请输入自定义日志文件夹名称或 /dev/null": "Please enter a custom log folder name or /dev/null", "日志名称只能包含字母、数字、下划线和连字符": "Log name can only contain letters, numbers, underscores and hyphens", - "日志名称不能超过100个字符": "Log name cannot exceed 100 characters" + "日志名称不能超过100个字符": "Log name cannot exceed 100 characters", + "用户管理": "User Management", + "用户名": "Username", + "密码": "Password", + "角色": "Role", + "管理员": "Admin", + "普通用户": "User", + "启用": "Enabled", + "禁用": "Disabled", + "创建时间": "Created At", + "确认删除选中的用户吗": "Are you sure to delete selected users?", + "请输入用户名": "Please enter username", + "请输入密码": "Please enter password", + "密码长度至少为6位": "Password must be at least 6 characters", + "新增用户": "Add User", + "编辑用户": "Edit User" } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 97e97f20..f7b4bc89 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -530,5 +530,20 @@ "请输入自定义日志文件夹名称或绝对路径": "请输入自定义日志文件夹名称或绝对路径", "请输入自定义日志文件夹名称或 /dev/null": "请输入自定义日志文件夹名称或 /dev/null", "日志名称只能包含字母、数字、下划线和连字符": "日志名称只能包含字母、数字、下划线和连字符", - "日志名称不能超过100个字符": "日志名称不能超过100个字符" + "日志名称不能超过100个字符": "日志名称不能超过100个字符", + "用户管理": "用户管理", + "用户名": "用户名", + "密码": "密码", + "角色": "角色", + "管理员": "管理员", + "普通用户": "普通用户", + "启用": "启用", + "禁用": "禁用", + "创建时间": "创建时间", + "确认删除选中的用户吗": "确认删除选中的用户吗", + "请输入用户名": "请输入用户名", + "请输入密码": "请输入密码", + "密码长度至少为6位": "密码长度至少为6位", + "新增用户": "新增用户", + "编辑用户": "编辑用户" } diff --git a/src/pages/setting/index.tsx b/src/pages/setting/index.tsx index b846b7ee..141713fd 100644 --- a/src/pages/setting/index.tsx +++ b/src/pages/setting/index.tsx @@ -35,6 +35,7 @@ import './index.less'; import useResizeObserver from '@react-hook/resize-observer'; import SystemLog from './systemLog'; import Dependence from './dependence'; +import UserManagement from './userManagement'; const { Text } = Typography; const isDemoEnv = window.__ENV__DeployEnv === 'demo'; @@ -343,6 +344,15 @@ const Setting = () => { label: intl.get('登录日志'), children: , }, + ...(user?.role === 0 && !isDemoEnv + ? [ + { + key: 'user-management', + label: intl.get('用户管理'), + children: , + }, + ] + : []), { key: 'dependence', label: intl.get('依赖设置'), diff --git a/src/pages/setting/userManagement.tsx b/src/pages/setting/userManagement.tsx new file mode 100644 index 00000000..46492560 --- /dev/null +++ b/src/pages/setting/userManagement.tsx @@ -0,0 +1,264 @@ +import intl from 'react-intl-universal'; +import React, { useState, useEffect } from 'react'; +import { + Button, + Table, + Space, + Modal, + Form, + Input, + Select, + message, + Tag, +} from 'antd'; +import { + EditOutlined, + DeleteOutlined, + PlusOutlined, +} from '@ant-design/icons'; +import { request } from '@/utils/http'; +import config from '@/utils/config'; + +const { Option } = Select; + +interface User { + id: number; + username: string; + password?: string; + role: number; + status: number; + createdAt: string; + updatedAt: string; +} + +const UserManagement: React.FC<{ height: number }> = ({ height }) => { + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(false); + const [isModalVisible, setIsModalVisible] = useState(false); + const [editingUser, setEditingUser] = useState(null); + const [form] = Form.useForm(); + + const columns = [ + { + title: intl.get('用户名'), + dataIndex: 'username', + key: 'username', + }, + { + title: intl.get('角色'), + dataIndex: 'role', + key: 'role', + render: (role: number) => ( + + {role === 0 ? intl.get('管理员') : intl.get('普通用户')} + + ), + }, + { + title: intl.get('状态'), + dataIndex: 'status', + key: 'status', + render: (status: number) => ( + + {status === 0 ? intl.get('启用') : intl.get('禁用')} + + ), + }, + { + title: intl.get('创建时间'), + dataIndex: 'createdAt', + key: 'createdAt', + render: (text: string) => text ? new Date(text).toLocaleString() : '-', + }, + { + title: intl.get('操作'), + key: 'action', + render: (_: any, record: User) => ( + + + + + ), + }, + ]; + + const fetchUsers = async () => { + setLoading(true); + try { + const { code, data } = await request.get( + `${config.apiPrefix}user-management` + ); + if (code === 200) { + setUsers(data); + } + } catch (error) { + message.error('Failed to fetch users'); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchUsers(); + }, []); + + const handleAdd = () => { + setEditingUser(null); + form.resetFields(); + setIsModalVisible(true); + }; + + const handleEdit = (record: User) => { + setEditingUser(record); + form.setFieldsValue({ + username: record.username, + role: record.role, + status: record.status, + }); + setIsModalVisible(true); + }; + + const handleDelete = (ids: number[]) => { + Modal.confirm({ + title: intl.get('确认删除'), + content: intl.get('确认删除选中的用户吗'), + onOk: async () => { + try { + const { code, message: msg } = await request.delete( + `${config.apiPrefix}user-management`, + { data: ids } + ); + if (code === 200) { + message.success(msg || intl.get('删除成功')); + fetchUsers(); + } else { + message.error(msg || intl.get('删除失败')); + } + } catch (error: any) { + message.error(error.message || intl.get('删除失败')); + } + }, + }); + }; + + const handleSubmit = async () => { + try { + const values = await form.validateFields(); + + if (editingUser) { + // Update user + const { code, message: msg } = await request.put( + `${config.apiPrefix}user-management`, + { ...values, id: editingUser.id } + ); + if (code === 200) { + message.success(msg || intl.get('更新成功')); + setIsModalVisible(false); + fetchUsers(); + } else { + message.error(msg || intl.get('更新失败')); + } + } else { + // Create user + const { code, message: msg } = await request.post( + `${config.apiPrefix}user-management`, + values + ); + if (code === 200) { + message.success(msg || intl.get('创建成功')); + setIsModalVisible(false); + fetchUsers(); + } else { + message.error(msg || intl.get('创建失败')); + } + } + } catch (error: any) { + message.error(error.message || intl.get('操作失败')); + } + }; + + return ( + <> +
+ +
+ + setIsModalVisible(false)} + > +
+ + + + + + + + + + + + + +
+ + ); +}; + +export default UserManagement;