feat: 完成前端多语言支持和菜单优化
- 缩短菜单标题,解决显示不全问题 - 添加跟随系统语言选项,作为默认选项 - 移除语言切换时的页面刷新,实现无刷新切换 - 完成主要页面的多语言替换: * ConfigPage - 全局配置页面 * ResetPassword - 重置密码页面 * LeaderList - Leader 列表页面 * UserList - 用户列表页面 * Statistics - 统计信息页面 * OrderList - 订单列表页面 * TemplateList - 模板列表页面 * CopyTradingList - 跟单配置列表页面 - 添加简体中文、繁体中文和英文的完整翻译键 - 优化语言设置页面,支持跟随系统语言
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Card, Table, Button, Space, Tag, Popconfirm, message, Typography, Modal, Form, Input } from 'antd'
|
||||
import { PlusOutlined, ReloadOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { apiService } from '../services/api'
|
||||
import { useMediaQuery } from 'react-responsive'
|
||||
|
||||
@@ -15,6 +16,7 @@ interface User {
|
||||
}
|
||||
|
||||
const UserList: React.FC = () => {
|
||||
const { t, i18n } = useTranslation()
|
||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||
const [users, setUsers] = useState<User[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
@@ -37,11 +39,11 @@ const UserList: React.FC = () => {
|
||||
if (response.data.code === 0 && response.data.data) {
|
||||
setUsers(response.data.data)
|
||||
} else {
|
||||
message.error(response.data.msg || '获取用户列表失败')
|
||||
message.error(response.data.msg || t('userList.fetchFailed') || '获取用户列表失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('获取用户列表失败:', error)
|
||||
const errorMsg = error.response?.data?.msg || error.message || '获取用户列表失败'
|
||||
const errorMsg = error.response?.data?.msg || error.message || t('userList.fetchFailed') || '获取用户列表失败'
|
||||
message.error(errorMsg)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
@@ -59,16 +61,16 @@ const UserList: React.FC = () => {
|
||||
password: values.password
|
||||
})
|
||||
if (response.data.code === 0) {
|
||||
message.success('创建用户成功')
|
||||
message.success(t('userList.createSuccess') || '创建用户成功')
|
||||
setCreateModalVisible(false)
|
||||
createForm.resetFields()
|
||||
fetchUsers()
|
||||
} else {
|
||||
message.error(response.data.msg || '创建用户失败')
|
||||
message.error(response.data.msg || t('userList.createFailed') || '创建用户失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('创建用户失败:', error)
|
||||
const errorMsg = error.response?.data?.msg || error.message || '创建用户失败'
|
||||
const errorMsg = error.response?.data?.msg || error.message || t('userList.createFailed') || '创建用户失败'
|
||||
message.error(errorMsg)
|
||||
}
|
||||
}
|
||||
@@ -82,17 +84,17 @@ const UserList: React.FC = () => {
|
||||
newPassword: values.newPassword
|
||||
})
|
||||
if (response.data.code === 0) {
|
||||
message.success('更新密码成功')
|
||||
message.success(t('userList.updatePasswordSuccess') || '更新密码成功')
|
||||
setUpdatePasswordModalVisible(false)
|
||||
setSelectedUser(null)
|
||||
updatePasswordForm.resetFields()
|
||||
fetchUsers()
|
||||
} else {
|
||||
message.error(response.data.msg || '更新密码失败')
|
||||
message.error(response.data.msg || t('userList.updatePasswordFailed') || '更新密码失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('更新密码失败:', error)
|
||||
const errorMsg = error.response?.data?.msg || error.message || '更新密码失败'
|
||||
const errorMsg = error.response?.data?.msg || error.message || t('userList.updatePasswordFailed') || '更新密码失败'
|
||||
message.error(errorMsg)
|
||||
}
|
||||
}
|
||||
@@ -103,7 +105,7 @@ const UserList: React.FC = () => {
|
||||
newPassword: values.newPassword
|
||||
})
|
||||
if (response.data.code === 0) {
|
||||
message.success('修改密码成功,请重新登录')
|
||||
message.success(t('userList.updateOwnPasswordSuccess') || '修改密码成功,请重新登录')
|
||||
setUpdateOwnPasswordModalVisible(false)
|
||||
updateOwnPasswordForm.resetFields()
|
||||
// 延迟跳转到登录页
|
||||
@@ -111,11 +113,11 @@ const UserList: React.FC = () => {
|
||||
window.location.href = '/login'
|
||||
}, 1000)
|
||||
} else {
|
||||
message.error(response.data.msg || '修改密码失败')
|
||||
message.error(response.data.msg || t('userList.updateOwnPasswordFailed') || '修改密码失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('修改密码失败:', error)
|
||||
const errorMsg = error.response?.data?.msg || error.message || '修改密码失败'
|
||||
const errorMsg = error.response?.data?.msg || error.message || t('userList.updateOwnPasswordFailed') || '修改密码失败'
|
||||
message.error(errorMsg)
|
||||
}
|
||||
}
|
||||
@@ -124,14 +126,14 @@ const UserList: React.FC = () => {
|
||||
try {
|
||||
const response = await apiService.users.delete({ userId: user.id })
|
||||
if (response.data.code === 0) {
|
||||
message.success('删除用户成功')
|
||||
message.success(t('userList.deleteSuccess') || '删除用户成功')
|
||||
fetchUsers()
|
||||
} else {
|
||||
message.error(response.data.msg || '删除用户失败')
|
||||
message.error(response.data.msg || t('userList.deleteFailed') || '删除用户失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('删除用户失败:', error)
|
||||
const errorMsg = error.response?.data?.msg || error.message || '删除用户失败'
|
||||
const errorMsg = error.response?.data?.msg || error.message || t('userList.deleteFailed') || '删除用户失败'
|
||||
message.error(errorMsg)
|
||||
}
|
||||
}
|
||||
@@ -144,30 +146,30 @@ const UserList: React.FC = () => {
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
title: t('userList.username') || '用户名',
|
||||
dataIndex: 'username',
|
||||
key: 'username'
|
||||
},
|
||||
{
|
||||
title: '角色',
|
||||
title: t('userList.role') || '角色',
|
||||
dataIndex: 'isDefault',
|
||||
key: 'isDefault',
|
||||
width: 100,
|
||||
render: (isDefault: boolean) => (
|
||||
<Tag color={isDefault ? 'red' : 'blue'}>
|
||||
{isDefault ? '默认账户' : '普通用户'}
|
||||
{isDefault ? t('userList.defaultAccount') || '默认账户' : t('userList.normalUser') || '普通用户'}
|
||||
</Tag>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
title: t('common.createdAt') || '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
key: 'createdAt',
|
||||
width: 180,
|
||||
render: (timestamp: number) => new Date(timestamp).toLocaleString('zh-CN')
|
||||
render: (timestamp: number) => new Date(timestamp).toLocaleString(i18n.language || 'zh-CN')
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: t('common.actions') || '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
render: (_: any, record: User) => {
|
||||
@@ -186,13 +188,13 @@ const UserList: React.FC = () => {
|
||||
setUpdatePasswordModalVisible(true)
|
||||
}}
|
||||
>
|
||||
修改密码
|
||||
{t('userList.updatePassword') || '修改密码'}
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title="确定要删除这个用户吗?"
|
||||
title={t('userList.deleteConfirm') || '确定要删除这个用户吗?'}
|
||||
onConfirm={() => handleDelete(record)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
okText={t('common.confirm') || '确定'}
|
||||
cancelText={t('common.cancel') || '取消'}
|
||||
>
|
||||
<Button
|
||||
type="link"
|
||||
@@ -200,7 +202,7 @@ const UserList: React.FC = () => {
|
||||
size="small"
|
||||
icon={<DeleteOutlined />}
|
||||
>
|
||||
删除
|
||||
{t('common.delete') || '删除'}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</>
|
||||
@@ -219,20 +221,20 @@ const UserList: React.FC = () => {
|
||||
<div>
|
||||
<Card>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
|
||||
<Title level={4} style={{ margin: 0 }}>用户管理</Title>
|
||||
<Title level={4} style={{ margin: 0 }}>{t('userList.title') || '用户管理'}</Title>
|
||||
<Space>
|
||||
<Button
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => setUpdateOwnPasswordModalVisible(true)}
|
||||
>
|
||||
修改我的密码
|
||||
{t('userList.updateMyPassword') || '修改我的密码'}
|
||||
</Button>
|
||||
<Button
|
||||
icon={<ReloadOutlined />}
|
||||
onClick={fetchUsers}
|
||||
loading={loading}
|
||||
>
|
||||
刷新
|
||||
{t('common.refresh') || '刷新'}
|
||||
</Button>
|
||||
{isDefaultUser && (
|
||||
<Button
|
||||
@@ -240,7 +242,7 @@ const UserList: React.FC = () => {
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => setCreateModalVisible(true)}
|
||||
>
|
||||
新增用户
|
||||
{t('userList.addUser') || '新增用户'}
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
@@ -253,7 +255,7 @@ const UserList: React.FC = () => {
|
||||
pagination={{
|
||||
pageSize: isMobile ? 10 : 20,
|
||||
showSizeChanger: !isMobile,
|
||||
showTotal: (total) => `共 ${total} 条`
|
||||
showTotal: (total) => t('userList.total', { total }) || `共 ${total} 条`
|
||||
}}
|
||||
scroll={isMobile ? { x: 600 } : undefined}
|
||||
/>
|
||||
@@ -261,15 +263,15 @@ const UserList: React.FC = () => {
|
||||
|
||||
{/* 创建用户弹窗 */}
|
||||
<Modal
|
||||
title="新增用户"
|
||||
title={t('userList.addUser') || '新增用户'}
|
||||
open={createModalVisible}
|
||||
onCancel={() => {
|
||||
setCreateModalVisible(false)
|
||||
createForm.resetFields()
|
||||
}}
|
||||
onOk={() => createForm.submit()}
|
||||
okText="创建"
|
||||
cancelText="取消"
|
||||
okText={t('userList.createUser') || '创建'}
|
||||
cancelText={t('common.cancel') || '取消'}
|
||||
>
|
||||
<Form
|
||||
form={createForm}
|
||||
@@ -278,29 +280,29 @@ const UserList: React.FC = () => {
|
||||
>
|
||||
<Form.Item
|
||||
name="username"
|
||||
label="用户名"
|
||||
label={t('userList.username') || '用户名'}
|
||||
rules={[
|
||||
{ required: true, message: '请输入用户名' }
|
||||
{ required: true, message: t('userList.usernameRequired') || '请输入用户名' }
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入用户名" />
|
||||
<Input placeholder={t('userList.usernamePlaceholder') || '请输入用户名'} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="password"
|
||||
label="密码"
|
||||
label={t('userList.password') || '密码'}
|
||||
rules={[
|
||||
{ required: true, message: '请输入密码' },
|
||||
{ min: 6, message: '密码至少6位' }
|
||||
{ required: true, message: t('userList.passwordRequired') || '请输入密码' },
|
||||
{ min: 6, message: t('userList.passwordMinLength') || '密码至少6位' }
|
||||
]}
|
||||
>
|
||||
<Input.Password placeholder="至少6位" />
|
||||
<Input.Password placeholder={t('userList.passwordPlaceholder') || '至少6位'} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
{/* 修改密码弹窗(管理员修改其他用户密码) */}
|
||||
<Modal
|
||||
title="修改密码"
|
||||
title={t('userList.updatePassword') || '修改密码'}
|
||||
open={updatePasswordModalVisible}
|
||||
onCancel={() => {
|
||||
setUpdatePasswordModalVisible(false)
|
||||
@@ -308,8 +310,8 @@ const UserList: React.FC = () => {
|
||||
updatePasswordForm.resetFields()
|
||||
}}
|
||||
onOk={() => updatePasswordForm.submit()}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
okText={t('common.confirm') || '确定'}
|
||||
cancelText={t('common.cancel') || '取消'}
|
||||
>
|
||||
<Form
|
||||
form={updatePasswordForm}
|
||||
@@ -318,28 +320,28 @@ const UserList: React.FC = () => {
|
||||
>
|
||||
<Form.Item
|
||||
name="newPassword"
|
||||
label="新密码"
|
||||
label={t('userList.newPassword') || '新密码'}
|
||||
rules={[
|
||||
{ required: true, message: '请输入新密码' },
|
||||
{ min: 6, message: '密码至少6位' }
|
||||
{ required: true, message: t('userList.newPasswordRequired') || '请输入新密码' },
|
||||
{ min: 6, message: t('userList.passwordMinLength') || '密码至少6位' }
|
||||
]}
|
||||
>
|
||||
<Input.Password placeholder="至少6位" />
|
||||
<Input.Password placeholder={t('userList.passwordPlaceholder') || '至少6位'} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
{/* 修改我的密码弹窗(默认账户修改自己密码) */}
|
||||
<Modal
|
||||
title="修改我的密码"
|
||||
title={t('userList.updateMyPasswordTitle') || '修改我的密码'}
|
||||
open={updateOwnPasswordModalVisible}
|
||||
onCancel={() => {
|
||||
setUpdateOwnPasswordModalVisible(false)
|
||||
updateOwnPasswordForm.resetFields()
|
||||
}}
|
||||
onOk={() => updateOwnPasswordForm.submit()}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
okText={t('common.confirm') || '确定'}
|
||||
cancelText={t('common.cancel') || '取消'}
|
||||
>
|
||||
<Form
|
||||
form={updateOwnPasswordForm}
|
||||
@@ -348,13 +350,13 @@ const UserList: React.FC = () => {
|
||||
>
|
||||
<Form.Item
|
||||
name="newPassword"
|
||||
label="新密码"
|
||||
label={t('userList.newPassword') || '新密码'}
|
||||
rules={[
|
||||
{ required: true, message: '请输入新密码' },
|
||||
{ min: 6, message: '密码至少6位' }
|
||||
{ required: true, message: t('userList.newPasswordRequired') || '请输入新密码' },
|
||||
{ min: 6, message: t('userList.passwordMinLength') || '密码至少6位' }
|
||||
]}
|
||||
>
|
||||
<Input.Password placeholder="至少6位" />
|
||||
<Input.Password placeholder={t('userList.passwordPlaceholder') || '至少6位'} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user