From a7e20c9c5aaf7096fb89847fc666caba437fd911 Mon Sep 17 00:00:00 2001 From: wikiboss Date: Mon, 21 Sep 2026 10:43:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(mpuniapp):=20=E9=87=8D=E6=9E=84=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E9=A1=B5=E9=9D=A2=E4=B8=BA=E7=91=9E=E5=A3=AB=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E4=B8=BB=E4=B9=89=E6=9E=81=E7=AE=80=E5=93=81=E7=89=8C?= =?UTF-8?q?=E6=84=9F=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AE=BD=E5=B1=8F=E5=B1=85?= =?UTF-8?q?=E4=B8=AD=E4=B8=8E=E7=A7=BB=E5=8A=A8=E7=AB=AF=E8=87=AA=E9=80=82?= =?UTF-8?q?=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/test/mpuniapp/login.test.ts | 47 ++++++++++++++++++++++++++++- mpuniapp/pages/common/login.uvue | 2 +- mpuniapp/pages/common/useLogin.uts | 9 +++--- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/backend/test/mpuniapp/login.test.ts b/backend/test/mpuniapp/login.test.ts index a75ef79..a1063a9 100644 --- a/backend/test/mpuniapp/login.test.ts +++ b/backend/test/mpuniapp/login.test.ts @@ -32,6 +32,7 @@ type LoginState = { email: string; submitting: boolean; errorMessage: string; + countdown: number; }; type UseLoginModule = { @@ -41,6 +42,8 @@ type UseLoginModule = { sendMagicLink: (state: LoginState) => boolean; sendSmsCode: (state: LoginState) => boolean; tapSocialLogin: (provider: 'google' | 'apple') => void; + resolveLoginText: (key: string) => string; + tickCountdown: (state: LoginState) => void; }; describe('OmniCard AI 用户端统一登录业务逻辑测试 (useLogin.uts)', () => { @@ -49,6 +52,7 @@ describe('OmniCard AI 用户端统一登录业务逻辑测试 (useLogin.uts)', ( let lastRequestOptions: UniRequestOption | null; let requestCallCount: number; let navigateBackCount: number; + let switchTabCount: number; beforeEach(() => { storageMap = new Map(); @@ -56,6 +60,7 @@ describe('OmniCard AI 用户端统一登录业务逻辑测试 (useLogin.uts)', ( lastRequestOptions = null; requestCallCount = 0; navigateBackCount = 0; + switchTabCount = 0; jest.resetModules(); (global as { uni?: Record }).uni = { @@ -66,6 +71,9 @@ describe('OmniCard AI 用户端统一登录业务逻辑测试 (useLogin.uts)', ( toastCalls.push(options); }, reLaunch: jest.fn(), + switchTab: (_options: { url: string }) => { + switchTabCount += 1; + }, navigateBack: () => { navigateBackCount += 1; }, @@ -98,13 +106,14 @@ describe('OmniCard AI 用户端统一登录业务逻辑测试 (useLogin.uts)', ( } describe('1. completeLogin 写入本地凭证', () => { - it('1.1 completeLogin 会 setStorage token', () => { + it('1.1 completeLogin 会 setStorage token 并跳转名片页', () => { const { completeLogin } = loadUseLogin(); const ok = completeLogin('mock_jwt_login_t09'); expect(ok).toBe(true); expect(storageMap.get('token')).toBe('mock_jwt_login_t09'); + expect(switchTabCount).toBe(1); }); it('1.2 传入 tenantId 时同步写入 tenant_id', () => { @@ -114,6 +123,7 @@ describe('OmniCard AI 用户端统一登录业务逻辑测试 (useLogin.uts)', ( expect(storageMap.get('token')).toBe('mock_jwt_login_t09'); expect(storageMap.get('tenant_id')).toBe('tenant_omni_88'); + expect(switchTabCount).toBe(1); }); it('1.3 未传 tenantId 时不写入 tenant_id', () => { @@ -123,6 +133,7 @@ describe('OmniCard AI 用户端统一登录业务逻辑测试 (useLogin.uts)', ( expect(storageMap.get('token')).toBe('mock_jwt_only_token'); expect(storageMap.has('tenant_id')).toBe(false); + expect(switchTabCount).toBe(1); }); }); @@ -175,4 +186,38 @@ describe('OmniCard AI 用户端统一登录业务逻辑测试 (useLogin.uts)', ( expect(toastCalls[1].title).toContain('即将开放'); }); }); + + describe('4. 极简品牌感文案与国际化解析', () => { + it('4.1 正确解析品牌感文案,杜绝空字符串与硬编码', () => { + const { resolveLoginText } = loadUseLogin(); + + expect(resolveLoginText('brandTag').length).toBeGreaterThan(0); + expect(resolveLoginText('subtitle').length).toBeGreaterThan(0); + expect(resolveLoginText('orContinueWith').length).toBeGreaterThan(0); + expect(resolveLoginText('termsNotice').length).toBeGreaterThan(0); + expect(resolveLoginText('termsOfService').length).toBeGreaterThan(0); + expect(resolveLoginText('privacyPolicy').length).toBeGreaterThan(0); + }); + }); + + describe('5. 验证码倒计时机制', () => { + it('5.1 手机号合法时发送验证码触发 60s 倒计时', () => { + const { createLoginState, sendSmsCode, tickCountdown } = loadUseLogin(); + + const state = createLoginState(); + state.phone = '13800138000'; + + sendSmsCode(state); + expect(state.countdown).toBe(60); + + // 递减一次 + tickCountdown(state); + expect(state.countdown).toBe(59); + + // 倒计时中不能重复触发 + const again = sendSmsCode(state); + expect(again).toBe(false); + expect(state.countdown).toBe(59); + }); + }); }); diff --git a/mpuniapp/pages/common/login.uvue b/mpuniapp/pages/common/login.uvue index 42056c3..7582adf 100644 --- a/mpuniapp/pages/common/login.uvue +++ b/mpuniapp/pages/common/login.uvue @@ -190,7 +190,7 @@ const isRtlMode = computed((): boolean => { }); function t(key: LoginCopyKey | string): string { - return resolveLoginText(key); + return resolveLoginText(key, currentLang.value); } const codeButtonText = computed((): string => { diff --git a/mpuniapp/pages/common/useLogin.uts b/mpuniapp/pages/common/useLogin.uts index 466fc06..90320cb 100644 --- a/mpuniapp/pages/common/useLogin.uts +++ b/mpuniapp/pages/common/useLogin.uts @@ -3,7 +3,7 @@ * 第一版可用骨架:不接真实 Google / Apple SDK,不伪造成功登录 */ -import { getCurrentLocale, getOmniText } from '../../common/locale.uts'; +import { getCurrentLocale, getOmniText, OmniLocale } from '../../common/locale.uts'; import { setAuthToken, setTenantId } from '../../common/request.uts'; export type LoginTab = 'phone' | 'email'; @@ -55,12 +55,13 @@ function isZhLocale(): boolean { /** * 登录文案:能复用 locale.uts 的走词典,缺 key 时中英简单分支 */ -export function resolveLoginText(key: LoginCopyKey | string): string { +export function resolveLoginText(key: LoginCopyKey | string, targetLocale?: string): string { + const loc = targetLocale != null && targetLocale !== '' ? targetLocale : getCurrentLocale(); if (key === 'loginSuccess') { - return getOmniText(getCurrentLocale(), 'common.success'); + return getOmniText(loc as OmniLocale, 'common.success'); } - const zh = isZhLocale(); + const zh = loc === 'zh-CN'; if (key === 'title') { return zh ? '登录 OmniCard' : 'Sign in to OmniCard'; }