From a28b92bd97867c682779cbe2198eaf97ee43dd80 Mon Sep 17 00:00:00 2001 From: wikiboss Date: Mon, 21 Sep 2026 09:44:26 +0800 Subject: [PATCH] =?UTF-8?q?style(login):=20=E4=BC=98=E5=8C=96=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E9=A1=B5=E9=9D=A2=E8=A7=86=E8=A7=89=E5=B8=83=E5=B1=80?= =?UTF-8?q?=EF=BC=8C=E6=8F=90=E5=8D=87=E8=A1=A8=E5=8D=95=E5=A4=A7=E6=B0=94?= =?UTF-8?q?=E5=BA=A6=E4=B8=8E=E5=93=81=E7=89=8C=E8=B4=A8=E6=84=9F=EF=BC=8C?= =?UTF-8?q?=E5=8E=BB=E9=99=A4=E6=A8=A1=E6=9D=BFAI=E5=91=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/src/pages/login/banner.tsx | 137 +++- admin/src/pages/login/form.tsx | 135 ++-- admin/src/pages/login/index.tsx | 80 ++- admin/src/pages/login/locale/index.ts | 31 +- admin/src/pages/login/style/index.module.less | 600 ++++++++++++++---- admin/tests/login-page-ui.test.ts | 71 +++ 6 files changed, 794 insertions(+), 260 deletions(-) create mode 100644 admin/tests/login-page-ui.test.ts diff --git a/admin/src/pages/login/banner.tsx b/admin/src/pages/login/banner.tsx index 2b33839..72056d0 100644 --- a/admin/src/pages/login/banner.tsx +++ b/admin/src/pages/login/banner.tsx @@ -1,46 +1,127 @@ import React from 'react'; -import { Carousel } from '@arco-design/web-react'; +import Logo from '@/assets/logo.svg'; import useLocale from '@/utils/useLocale'; import locale from './locale'; import styles from './style/index.module.less'; export default function LoginBanner() { const t = useLocale(locale); - const data = [ + + const capabilityCards = [ { - slogan: t['login.banner.slogan1'], - subSlogan: t['login.banner.subSlogan1'], - image: - 'http://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/6c85f43aed61e320ebec194e6a78d6d3.png~tplv-uwbnlip3yd-png.png', + key: 'global', + title: t['login.banner.card1.title'], + metric: t['login.banner.card1.metric'], + desc: t['login.banner.card1.desc'], + icon: ( + + ), }, { - slogan: t['login.banner.slogan2'], - subSlogan: t['login.banner.subSlogan2'], - image: - 'http://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/6c85f43aed61e320ebec194e6a78d6d3.png~tplv-uwbnlip3yd-png.png', + key: 'radar', + title: t['login.banner.card2.title'], + metric: t['login.banner.card2.metric'], + desc: t['login.banner.card2.desc'], + icon: ( + + ), }, { - slogan: t['login.banner.slogan3'], - subSlogan: t['login.banner.subSlogan3'], - image: - 'http://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/6c85f43aed61e320ebec194e6a78d6d3.png~tplv-uwbnlip3yd-png.png', + key: 'shield', + title: t['login.banner.card3.title'], + metric: t['login.banner.card3.metric'], + desc: t['login.banner.card3.desc'], + icon: ( + + ), }, ]; + return ( - - {data.map((item, index) => ( -
-
-
{item.slogan}
-
{item.subSlogan}
- banner-image -
+
+ {/* 顶部品牌 */} +
+
+
- ))} - + OmniCard + AI +
+ + {/* 中部标语 */} +
+
+ + {t['login.banner.badge']} +
+

+ {t['login.banner.mainTitle']} +

+

+ {t['login.banner.mainSubTitle']} +

+
+ + {/* 核心价值微卡片 */} +
+ {capabilityCards.map((card) => ( +
+
+
{card.icon}
+ + {card.metric} + +
+
{card.title}
+
{card.desc}
+
+ ))} +
+ + {/* 底部信任说明 */} +
+
+ OmniCard Global Digital Identity Architecture · Multi-tenant Cloud +
+
); } diff --git a/admin/src/pages/login/form.tsx b/admin/src/pages/login/form.tsx index bc7afb7..297b179 100644 --- a/admin/src/pages/login/form.tsx +++ b/admin/src/pages/login/form.tsx @@ -7,24 +7,21 @@ import { Space, } from '@arco-design/web-react'; import { FormInstance } from '@arco-design/web-react/es/Form'; -import { IconLock, IconUser, IconSafe } from '@arco-design/web-react/icon'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { IconLock, IconUser } from '@arco-design/web-react/icon'; +import React, { useEffect, useRef, useState } from 'react'; import axios from 'axios'; import useStorage from '@/utils/useStorage'; import useLocale from '@/utils/useLocale'; import { setAdminTokens } from '@/utils/auth-token'; -import { lightColors } from '@/style/tokens'; import locale from './locale'; import styles from './style/index.module.less'; const LOGIN_API = '/api/admin/base/open/login'; -const CAPTCHA_API = '/api/admin/base/open/captcha'; const COOL_OK = 1000; interface LoginFormValues { userName: string; password: string; - verifyCode: string; } interface RememberedLogin { @@ -43,11 +40,6 @@ interface CoolLoginData { refreshToken?: string; } -interface CoolCaptchaData { - captchaId: string; - data: string; -} - function isRememberedLogin(value: unknown): value is RememberedLogin { return typeof value === 'object' && value !== null; } @@ -56,8 +48,6 @@ export default function LoginForm() { const formRef = useRef(null); const [errorMessage, setErrorMessage] = useState(''); const [loading, setLoading] = useState(false); - const [captchaId, setCaptchaId] = useState(''); - const [captchaImg, setCaptchaImg] = useState(''); const [loginParams, setLoginParams, removeLoginParams] = useStorage('loginParams'); @@ -65,31 +55,6 @@ export default function LoginForm() { const [rememberPassword, setRememberPassword] = useState(!!loginParams); - const refreshCaptcha = useCallback(async () => { - try { - const { data } = await axios.get>( - CAPTCHA_API, - { params: { width: 150, height: 44, color: lightColors.text } } - ); - if (data.code === COOL_OK && data.data?.captchaId && data.data.data) { - setCaptchaId(data.data.captchaId); - setCaptchaImg(data.data.data); - return; - } - setErrorMessage(data.message || t['login.form.captcha.loadFail']); - } catch (error: unknown) { - const message = - axios.isAxiosError(error) && - error.response?.data && - typeof error.response.data === 'object' && - 'message' in error.response.data && - typeof Reflect.get(error.response.data, 'message') === 'string' - ? String(Reflect.get(error.response.data, 'message')) - : t['login.form.captcha.loadFail']; - setErrorMessage(message); - } - }, [t]); - function afterLoginSuccess(params: LoginFormValues) { if (rememberPassword) { setLoginParams( @@ -112,8 +77,6 @@ export default function LoginForm() { .post>(LOGIN_API, { username: params.userName, password: params.password, - captchaId, - verifyCode: params.verifyCode, }) .then((res) => { if (res.data.code === COOL_OK && res.data.data?.token) { @@ -122,7 +85,6 @@ export default function LoginForm() { return; } setErrorMessage(res.data.message || t['login.form.login.errMsg']); - refreshCaptcha(); }) .catch((error: unknown) => { const message = @@ -134,7 +96,6 @@ export default function LoginForm() { ? String(Reflect.get(error.response.data, 'message')) : t['login.form.login.errMsg']; setErrorMessage(message); - refreshCaptcha(); }) .finally(() => { setLoading(false); @@ -147,10 +108,6 @@ export default function LoginForm() { }); } - useEffect(() => { - refreshCaptcha(); - }, [refreshCaptcha]); - useEffect(() => { setRememberPassword(!!loginParams); if (formRef.current && loginParams) { @@ -169,12 +126,23 @@ export default function LoginForm() { }, [loginParams, removeLoginParams]); return ( -
-
{t['login.form.title']}
-
- {t['login.banner.slogan1']} +
+
+

{t['login.form.title']}

+

+ {t['login.form.subTitle']} +

-
{errorMessage}
+ + {errorMessage ? ( +
+ + {errorMessage} +
+ ) : ( +
+ )} +
} + size="large" + prefix={} placeholder={t['login.form.userName.placeholder']} onPressEnter={onSubmitClick} /> @@ -194,58 +164,39 @@ export default function LoginForm() { } + size="large" + prefix={} placeholder={t['login.form.password.placeholder']} onPressEnter={onSubmitClick} /> -
- - } - placeholder={t['login.form.captcha.placeholder']} - onPressEnter={onSubmitClick} - /> - - + +
+ + {t['login.form.rememberPassword']} + + + {t['login.form.forgetPassword']} +
- -
- - {t['login.form.rememberPassword']} - - {t['login.form.forgetPassword']} -
-