diff --git a/.env b/.env
index c074e5b..ff8e5ad 100644
--- a/.env
+++ b/.env
@@ -1 +1,5 @@
VITE_API_BASE_URL = http://150.158.121.95
+
+VITE_RSA_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB
+-----END PUBLIC KEY-----"
\ No newline at end of file
diff --git a/package.json b/package.json
index 04856e9..a5c18c8 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,8 @@
"dayjs": "^1.11.18",
"i18next": "^25.5.3",
"i18next-browser-languagedetector": "^8.2.0",
+ "js-base64": "^3.7.8",
+ "jsencrypt": "^3.5.4",
"lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c6d77df..8df5acd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -35,6 +35,12 @@ importers:
i18next-browser-languagedetector:
specifier: ^8.2.0
version: 8.2.0
+ js-base64:
+ specifier: ^3.7.8
+ version: 3.7.8
+ jsencrypt:
+ specifier: ^3.5.4
+ version: 3.5.4
lodash:
specifier: ^4.17.21
version: 4.17.21
@@ -1217,6 +1223,9 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ js-base64@3.7.8:
+ resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
+
js-cookie@3.0.5:
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
engines: {node: '>=14'}
@@ -1228,6 +1237,9 @@ packages:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
+ jsencrypt@3.5.4:
+ resolution: {integrity: sha512-kNjfYEMNASxrDGsmcSQh/rUTmcoRfSUkxnAz+MMywM8jtGu+fFEZ3nJjHM58zscVnwR0fYmG9sGkTDjqUdpiwA==}
+
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
@@ -2769,6 +2781,8 @@ snapshots:
isexe@2.0.0: {}
+ js-base64@3.7.8: {}
+
js-cookie@3.0.5: {}
js-tokens@4.0.0: {}
@@ -2777,6 +2791,8 @@ snapshots:
dependencies:
argparse: 2.0.1
+ jsencrypt@3.5.4: {}
+
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
diff --git a/src/App.tsx b/src/App.tsx
index 28506d3..abf2297 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,8 +3,10 @@ import { CssBaseline, ThemeProvider } from '@mui/material';
import { theme } from './theme';
import AppRoutes from './routes';
import SnackbarProvider from './components/Provider/SnackbarProvider';
+import AuthGuard from './components/AuthGuard';
import './locales';
+import './utils/request'
/**
* 封装MaterialUIApp,将主题、基础样式和路由包裹起来
@@ -15,7 +17,9 @@ function MaterialUIApp() {
-
+
+
+
diff --git a/src/components/AuthGuard.tsx b/src/components/AuthGuard.tsx
new file mode 100644
index 0000000..8fd34f1
--- /dev/null
+++ b/src/components/AuthGuard.tsx
@@ -0,0 +1,52 @@
+import React, { useEffect } from 'react';
+import { useLocation, useNavigate } from 'react-router-dom';
+import { CircularProgress, Box } from '@mui/material';
+
+interface AuthGuardProps {
+ children: React.ReactNode;
+}
+
+const AuthGuard: React.FC = ({ children }) => {
+ const location = useLocation();
+ const navigate = useNavigate();
+
+ // 直接从localStorage检查token,避免React状态更新的延迟
+ const token = localStorage.getItem('token');
+ const isAuthenticated = !!token;
+ const isLoginPage = location.pathname === '/login';
+
+ useEffect(() => {
+ if (isAuthenticated && isLoginPage) {
+ // 已登录用户访问登录页,重定向到首页
+ navigate('/', { replace: true });
+ } else if (!isAuthenticated && !isLoginPage) {
+ // 未登录用户访问其他页面,重定向到登录页并保存当前路径
+ const redirectUrl = encodeURIComponent(location.pathname + location.search);
+ navigate(`/login?redirect=${redirectUrl}`, { replace: true });
+ }
+ }, [isAuthenticated, isLoginPage, location, navigate]);
+
+ // 如果是登录页面,直接渲染
+ if (isLoginPage) {
+ return <>{children}>;
+ }
+
+ // 如果未认证,显示加载状态(实际上会被重定向)
+ if (!isAuthenticated) {
+ return (
+
+
+
+ );
+ }
+
+ // 已认证,渲染子组件
+ return <>{children}>;
+};
+
+export default AuthGuard;
\ No newline at end of file
diff --git a/src/hooks/login-hooks.ts b/src/hooks/login-hooks.ts
new file mode 100644
index 0000000..8ad2126
--- /dev/null
+++ b/src/hooks/login-hooks.ts
@@ -0,0 +1,433 @@
+import { useState, useEffect, useMemo } from 'react';
+import { useNavigate, useSearchParams, useLocation } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+import { useForm } from 'react-hook-form';
+import userService from '../services/user_service';
+import { rsaPsw } from '../utils/encryption';
+
+/**
+ * OAuth回调处理Hook
+ */
+export const useOAuthCallback = () => {
+ const [searchParams, setSearchParams] = useSearchParams();
+ const navigate = useNavigate();
+
+ const error = searchParams.get('error');
+ const newSearchParams: URLSearchParams = useMemo(
+ () => new URLSearchParams(searchParams.toString()),
+ [searchParams],
+ );
+
+ useEffect(() => {
+ if (error) {
+ // 显示错误信息(这里可以集成你的消息提示组件)
+ console.error('OAuth Error:', error);
+ setTimeout(() => {
+ navigate('/login');
+ newSearchParams.delete('error');
+ setSearchParams(newSearchParams);
+ }, 1000);
+ return;
+ }
+
+ const auth = searchParams.get('auth');
+ if (auth) {
+ // 存储认证信息
+ localStorage.setItem('token', auth);
+ newSearchParams.delete('auth');
+ setSearchParams(newSearchParams);
+ navigate('/');
+ }
+ }, [
+ error,
+ searchParams,
+ newSearchParams,
+ navigate,
+ setSearchParams,
+ ]);
+
+ return searchParams.get('auth');
+};
+
+/**
+ * 认证状态管理Hook
+ */
+export const useAuth = () => {
+ const navigate = useNavigate();
+ const location = useLocation();
+ const [searchParams] = useSearchParams();
+ const [isAuthenticated, setIsAuthenticated] = useState(null);
+ const [userInfo, setUserInfo] = useState(null);
+ const [token, setToken] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+
+ // OAuth回调处理
+ const auth = useOAuthCallback();
+
+ // 检查认证状态
+ const checkAuthStatus = () => {
+ try {
+ const storedToken = localStorage.getItem('token');
+ const storedUserInfo = localStorage.getItem('userInfo');
+
+ if (storedToken) {
+ setToken(storedToken);
+ setIsAuthenticated(true);
+
+ if (storedUserInfo) {
+ setUserInfo(JSON.parse(storedUserInfo));
+ }
+ } else {
+ setToken(null);
+ setIsAuthenticated(false);
+ setUserInfo(null);
+ }
+ } catch (error) {
+ console.error('Error checking auth status:', error);
+ setToken(null);
+ setIsAuthenticated(false);
+ setUserInfo(null);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ // 登出功能
+ const logout = () => {
+ localStorage.removeItem('token');
+ localStorage.removeItem('userInfo');
+ setToken(null);
+ setIsAuthenticated(false);
+ setUserInfo(null);
+ navigate('/login');
+ };
+
+ // 更新认证状态
+ const updateAuthStatus = (newToken: string, newUserInfo: any) => {
+ setToken(newToken);
+ setUserInfo(newUserInfo);
+ setIsAuthenticated(true);
+ localStorage.setItem('token', newToken);
+ localStorage.setItem('userInfo', JSON.stringify(newUserInfo));
+ };
+
+ // 带参数重定向到登录页面
+ const redirectToLogin = (returnUrl?: string) => {
+ const currentPath = returnUrl || location.pathname + location.search;
+ if (currentPath !== '/login') {
+ navigate(`/login?redirect=${encodeURIComponent(currentPath)}`);
+ } else {
+ navigate('/login');
+ }
+ };
+
+ // 重定向到指定页面或首页
+ const redirectAfterLogin = () => {
+ const redirectUrl = searchParams.get('redirect');
+ if (redirectUrl) {
+ navigate(decodeURIComponent(redirectUrl));
+ } else {
+ navigate('/');
+ }
+ };
+
+ useEffect(() => {
+ checkAuthStatus();
+ }, [auth]);
+
+ return {
+ isAuthenticated,
+ userInfo,
+ token,
+ isLoading,
+ checkAuthStatus,
+ logout,
+ updateAuthStatus,
+ redirectToLogin,
+ redirectAfterLogin,
+ };
+};
+
+export interface LoginFormData {
+ email: string;
+ password: string;
+ rememberEmail?: boolean;
+}
+
+export interface RegisterFormData {
+ email: string;
+ password: string;
+ nickname: string;
+}
+
+/**
+ * 登录Hook
+ */
+export const useLogin = () => {
+ const { t } = useTranslation();
+ const navigate = useNavigate();
+ const [searchParams] = useSearchParams();
+ const [isLoading, setIsLoading] = useState(false);
+
+ const login = async (data: LoginFormData) => {
+ setIsLoading(true);
+
+ try {
+ // RSA加密密码
+ const encryptedPassword = rsaPsw(data.password);
+ const response = await userService.login({
+ email: data.email.trim(),
+ password: encryptedPassword
+ });
+
+ const { data: res = {} } = response;
+ const { code, message } = res;
+
+ if (code === 0) {
+ // 登录成功,处理token和用户信息
+ const { data: userData } = res;
+ const token = userData.access_token;
+ const userInfo = {
+ ...userData,
+ avatar: userData.avatar,
+ name: userData.nickname,
+ email: userData.email,
+ };
+
+ // 同步更新localStorage
+ localStorage.setItem('token', token);
+ localStorage.setItem('userInfo', JSON.stringify(userInfo));
+
+ // 直接进行重定向,不依赖React状态更新
+ const redirectUrl = searchParams.get('redirect');
+ if (redirectUrl) {
+ navigate(decodeURIComponent(redirectUrl), { replace: true });
+ } else {
+ navigate('/', { replace: true });
+ }
+
+ return { success: true };
+ } else {
+ // 登录失败
+ return {
+ success: false,
+ error: message || t('login.loginFailed')
+ };
+ }
+ } catch (error: any) {
+ // 处理网络错误或其他异常
+ return {
+ success: false,
+ error: error.message || t('login.networkError')
+ };
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return { login, isLoading };
+};
+
+/**
+ * 注册Hook
+ */
+export const useRegister = () => {
+ const { t } = useTranslation();
+ const [isLoading, setIsLoading] = useState(false);
+
+ const register = async (data: RegisterFormData) => {
+ setIsLoading(true);
+
+ try {
+ // RSA加密密码
+ const encryptedPassword = rsaPsw(data.password);
+
+ const response = await userService.register({
+ nickname: data.nickname,
+ email: data.email.trim(),
+ password: encryptedPassword
+ });
+
+ const { data: res = {} } = response;
+ const { code, message } = res;
+
+ if (code === 0) {
+ // 注册成功
+ return {
+ success: true,
+ email: data.email
+ };
+ } else {
+ // 注册失败
+ return {
+ success: false,
+ error: message || t('login.registerFailed')
+ };
+ }
+ } catch (error: any) {
+ // 处理网络错误或其他异常
+ return {
+ success: false,
+ error: error.message || t('login.networkError')
+ };
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return { register, isLoading };
+};
+
+/**
+ * 登录表单管理Hook
+ */
+export const useLoginForm = () => {
+ const { t } = useTranslation();
+ const [tabValue, setTabValue] = useState(0); // 0: 登录, 1: 注册
+ const [error, setError] = useState('');
+
+ // 登录表单
+ const loginForm = useForm({
+ defaultValues: {
+ email: '',
+ password: '',
+ rememberEmail: false
+ }
+ });
+
+ // 注册表单
+ const registerForm = useForm({
+ defaultValues: {
+ email: '',
+ password: '',
+ nickname: ''
+ }
+ });
+
+ const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
+ setTabValue(newValue);
+ setError('');
+ // 清空表单错误
+ loginForm.clearErrors();
+ registerForm.clearErrors();
+ };
+
+ const switchToLogin = (email?: string) => {
+ setTabValue(0);
+ setError('');
+ if (email) {
+ loginForm.setValue('email', email);
+ }
+ };
+
+ const setFormError = (errorMessage: string) => {
+ setError(errorMessage);
+ };
+
+ const clearError = () => {
+ setError('');
+ };
+
+ return {
+ // 表单状态
+ tabValue,
+ setTabValue,
+ error,
+ loginForm,
+ registerForm,
+
+ // 表单操作
+ handleTabChange,
+ switchToLogin,
+ setFormError,
+ clearError,
+
+ // 表单验证规则
+ loginValidation: {
+ email: {
+ required: t('login.emailPlaceholder'),
+ pattern: {
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
+ message: t('login.emailInvalid')
+ }
+ },
+ password: {
+ required: t('login.passwordPlaceholder'),
+ minLength: {
+ value: 6,
+ message: t('login.passwordMinLength')
+ }
+ }
+ },
+ registerValidation: {
+ nickname: {
+ required: t('login.nicknamePlaceholder'),
+ minLength: {
+ value: 2,
+ message: t('login.nicknameMinLength')
+ }
+ },
+ email: {
+ required: t('login.emailPlaceholder'),
+ pattern: {
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
+ message: t('login.emailInvalid')
+ }
+ },
+ password: {
+ required: t('login.passwordPlaceholder'),
+ minLength: {
+ value: 8,
+ message: t('login.passwordMinLength')
+ }
+ }
+ }
+ };
+};
+
+/**
+ * 登录页面主Hook - 整合所有登录相关逻辑
+ */
+export const useLoginPage = () => {
+ const loginHook = useLogin();
+ const registerHook = useRegister();
+ const formHook = useLoginForm();
+
+ const handleLogin = async (data: LoginFormData) => {
+ formHook.clearError();
+ const result = await loginHook.login(data);
+
+ if (!result.success && result.error) {
+ formHook.setFormError(result.error);
+ }
+
+ return result;
+ };
+
+ const handleRegister = async (data: RegisterFormData) => {
+ formHook.clearError();
+ const result = await registerHook.register(data);
+
+ if (result.success) {
+ // 注册成功,切换到登录表单并填入邮箱
+ formHook.registerForm.reset();
+ formHook.switchToLogin(result.email);
+ } else if (result.error) {
+ formHook.setFormError(result.error);
+ }
+
+ return result;
+ };
+
+ const isSubmitting = loginHook.isLoading || registerHook.isLoading;
+
+ return {
+ // 表单相关
+ ...formHook,
+
+ // 提交处理
+ handleLogin,
+ handleRegister,
+ isSubmitting,
+ };
+};
\ No newline at end of file
diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx
index d8b6952..2a6cb85 100644
--- a/src/pages/Login.tsx
+++ b/src/pages/Login.tsx
@@ -1,5 +1,3 @@
-import { useState } from 'react';
-import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import {
Box,
@@ -14,54 +12,35 @@ import {
Toolbar,
Card,
CardContent,
- Alert
+ Alert,
+ Tabs,
+ Tab
} from '@mui/material';
import LanguageSwitcher from '../components/LanguageSwitcher';
-import userService from '../services/user_service';
+import { useLoginPage } from '../hooks/login-hooks';
const Login = () => {
const { t } = useTranslation();
- const [email, setEmail] = useState('');
- const [password, setPassword] = useState('');
- const [rememberEmail, setRememberEmail] = useState(false);
- const [isSubmitting, setIsSubmitting] = useState(false);
- const [emailError, setEmailError] = useState(false);
- const [passwordError, setPasswordError] = useState(false);
- const [loginError, setLoginError] = useState('');
- const navigate = useNavigate();
-
- console.log(t, t('en'), t('login'));
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
-
- const hasEmail = !!email.trim();
- const hasPassword = !!password.trim();
- setEmailError(!hasEmail);
- setPasswordError(!hasPassword);
- setLoginError('');
+ const {
+ // 表单状态
+ tabValue,
+ setTabValue,
+ error,
+ loginForm,
+ registerForm,
- if (!hasEmail || !hasPassword) return;
-
- setIsSubmitting(true);
+ // 表单操作
+ handleTabChange,
- try {
- const response = await userService.login({ email, password });
-
- // if (response.code === 0) {
- // // 登录成功,跳转到主页
- // navigate('/');
- // } else {
- // // 登录失败,显示错误信息
- // setLoginError(response.message || t('login.loginFailed'));
- // }
- } catch (error: any) {
- // 处理网络错误或其他异常
- setLoginError(error.message || t('login.networkError'));
- } finally {
- setIsSubmitting(false);
- }
- };
+ // 提交处理
+ handleLogin,
+ handleRegister,
+ isSubmitting,
+
+ // 验证规则
+ loginValidation,
+ registerValidation
+ } = useLoginPage();
return (
@@ -96,67 +75,138 @@ const Login = () => {
T-Systems Enterprise RAG Empowerment System
-
- {t('login.login')}
-
{t('login.emailLabel')} & {t('login.passwordLabel')}
-
+
+ {/* 标签页 */}
+
+
+
+
-
- {loginError && (
-
- {loginError}
-
- )}
-
- setEmail(e.target.value)}
- error={emailError}
- required
- sx={{ mb: 2 }}
- />
+ {error && (
+
+ {error}
+
+ )}
- setPassword(e.target.value)}
- error={passwordError}
- required
- sx={{ mb: 2 }}
- />
-
-
- setRememberEmail(e.target.checked)}
- id="rememberEmail"
- />
- }
- label={t('login.rememberMe')}
+ {/* 登录表单 */}
+ {tabValue === 0 && (
+
+
+ {t('login.loginDescription')}
+
+
+
-
-
-
+
+
+
+
+ }
+ label={t('login.rememberMe')}
+ />
+
+
+
+
+ )}
+
+ {/* 注册表单 */}
+ {tabValue === 1 && (
+
+
+ {t('login.registerDescription')}
+
+
+
+
+
+
+
+
+
+
+ )}
- {t('login.signInTip')} {t('login.signUp')}.
+ {tabValue === 0 ? (
+ <>
+ {t('login.signInTip')} setTabValue(1)}>{t('login.signUp')}.
+ >
+ ) : (
+ <>
+ {t('login.signUpTip')} setTabValue(0)}>{t('login.login')}.
+ >
+ )}
diff --git a/src/services/user_service.ts b/src/services/user_service.ts
index f0f0aa5..2c52d4c 100644
--- a/src/services/user_service.ts
+++ b/src/services/user_service.ts
@@ -14,7 +14,7 @@ const userService = {
},
// 用户注册
- register: (data: { email: string; password: string; username?: string }) => {
+ register: (data: { email: string; password: string; nickname?: string }) => {
return post(api.register, data);
},
diff --git a/src/utils/encryption.ts b/src/utils/encryption.ts
new file mode 100644
index 0000000..0b8ed9f
--- /dev/null
+++ b/src/utils/encryption.ts
@@ -0,0 +1,36 @@
+import JSEncrypt from 'jsencrypt';
+import { Base64 } from 'js-base64';
+
+// RSA公钥
+let RSA_PUBLIC_KEY = (import.meta.env.VITE_RSA_PUBLIC_KEY as string) || '';
+
+/**
+ * RSA密码加密函数
+ * @param password 明文密码
+ * @returns 加密后的密码
+ */
+export const rsaPsw = (password: string): string => {
+ try {
+ const encrypt = new JSEncrypt();
+ const publicKey = RSA_PUBLIC_KEY;
+ console.log('publicKey', publicKey);
+ encrypt.setPublicKey(publicKey);
+ const encrypted = encrypt.encrypt(Base64.encode(password));
+ return encrypted || password;
+ } catch (error) {
+ console.error('RSA encryption failed:', error);
+ return password;
+ }
+};
+
+/**
+ * 获取RSA公钥
+ * @returns RSA公钥字符串
+ */
+export const getRSAPublicKey = (): string => {
+ return RSA_PUBLIC_KEY;
+};
+
+export const setRSAPublicKey = (key: string) => {
+ RSA_PUBLIC_KEY = key;
+};
\ No newline at end of file
diff --git a/src/utils/request.ts b/src/utils/request.ts
index ff431c0..5c57c42 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -120,26 +120,16 @@ request.interceptors.response.use(
if (response.config.responseType === 'blob') {
return response;
}
-
+ console.log('interceptors.response ------ response', response);
const data: ResponseType = response.data;
// 处理业务错误码
if (data?.code === 100) {
snackbar.error(data?.message);
} else if (data?.code === 401) {
- // notification.error({
- // message: data?.message,
- // description: data?.message,
- // duration: 3,
- // });
notification.error(data?.message);
redirectToLogin();
} else if (data?.code !== 0) {
- // notification.error({
- // message: `${i18n.t('message.hint')} : ${data?.code}`,
- // description: data?.message,
- // duration: 3,
- // });
notification.error(`${i18n.t('message.hint')} : ${data?.code}`, data?.message);
}
@@ -148,19 +138,10 @@ request.interceptors.response.use(
(error) => {
// 处理网络错误
if (error.message === FAILED_TO_FETCH || !error.response) {
- // notification.error({
- // description: i18n.t('message.networkAnomalyDescription'),
- // message: i18n.t('message.networkAnomaly'),
- // });
notification.error(i18n.t('message.networkAnomaly'), i18n.t('message.networkAnomalyDescription'));
} else if (error.response) {
const { status, statusText } = error.response;
const errorText = RetcodeMessage[status as ResultCode] || statusText;
-
- // notification.error({
- // message: `${i18n.t('message.requestError')} ${status}`,
- // description: errorText,
- // });
notification.error(`${i18n.t('message.requestError')} ${status}`, errorText);
}