Browse Source

解决多语言问题;云同步的重试机制

sw 1 week ago
parent
commit
25069d556f

+ 1 - 1
src/API/i18n/i18nActions.ts

@@ -55,7 +55,7 @@ function parseI18nMessages(rawData: unknown): I18nMessages {
 export async function fetchI18nMessages(locale: string): Promise<I18nMessages> {
   try {
     const response = await axiosInstance.get(
-      `/pub/trans/${locale}/${locale}.js`,
+      `/pub/trans/${locale}/${locale.split('_')[0]}.js`,
       {
         headers: {
           Accept: 'text/javascript, application/javascript, application/json',

+ 3 - 3
src/API/language.ts

@@ -15,7 +15,7 @@ export interface LanguageListResponse {
 
 // 修改系统语言接口
 export interface ChangeLanguageRequest {
-  lang: string; // en_US.UTF-8, zh_CN.UTF-8
+  lang: string; // en_US, zh_CN
 }
 
 export interface ChangeLanguageResponse {
@@ -27,8 +27,8 @@ export interface ChangeLanguageResponse {
 
 // 语言代码映射:简短代码 -> 完整代码
 const languageMap: Record<string, string> = {
-  en: 'en_US.UTF-8',
-  zh: 'zh_CN.UTF-8',
+  en: 'en_US',
+  zh: 'zh_CN',
 };
 
 /**

+ 2 - 2
src/API/softwareInfo.ts

@@ -5,9 +5,9 @@ export interface SoftwareInfo {
   FPD: string;
   /** 发生器类型 - "Simulator": 模拟设备, "Physics": 物理设备 */
   GEN: string;
-  /** 当前系统语言,如 "zh_CN.UTF-8" */
+  /** 当前系统语言,如 "zh_CN" */
   current_locale: string;
-  /** 默认系统语言,如 "zh_CN.UTF-8" */
+  /** 默认系统语言,如 "zh_CN" */
   default_locale: string;
   language: string[];
   product: string;

+ 6 - 13
src/app.tsx

@@ -53,18 +53,10 @@ function AppContent({ children }: { children: ReactNode }): JSX.Element {
       .dispatch(initializeProductState())
       .unwrap()
       .then((productState) => {
-        // 从 current_locale 提取语言代码 (例如: "zh_CN.UTF-8" -> "zh")
-        const languageCode = productState.language
-          .split('_')[0]
-          .split('.')[0]
-          .toLowerCase();
+        // 从 current_locale 提取语言代码
+        const languageCode = productState.language;
 
-        // 应用启动时加载多语言资源
-        const localeToLoad = ['zh', 'en'].includes(languageCode)
-          ? languageCode
-          : 'en';
-
-        return dispatch(loadI18nMessages(localeToLoad)).unwrap();
+        return dispatch(loadI18nMessages(languageCode)).unwrap();
       })
       .then(() => {
         setIsI18nReady(true);
@@ -120,12 +112,13 @@ function AppContent({ children }: { children: ReactNode }): JSX.Element {
       </div>
     );
   }
-
+  console.log('当前语言:', currentLocale);
+  console.log('messages', messages);
   // children 是将要会渲染的页面
   return (
     <ConfigProvider theme={currentTheme}>
       <IntlProvider
-        locale={currentLocale}
+        locale={currentLocale.split('_')[0]} // en_US -> en
         messages={messages as Record<string, string>}
       >
         <style>

+ 107 - 18
src/pages/security/cloud_sync_expired.tsx

@@ -1,37 +1,126 @@
 // src/pages/check.tsx
-import { useEffect, useState } from 'react';
+import { useEffect, useState, useRef } from 'react';
 import Taro from '@tarojs/taro';
-import { View } from '@tarojs/components';
+import { View, Button } from '@tarojs/components';
 import { getQuota } from '@/API/security/quotaActions';
 
 export default function Check() {
   const [overdueStatus, setoverdueStatus] = useState<boolean | null>(null);
-  useEffect(() => {
-    const checkoverdue = async () => {
-      try {
-        const response = await getQuota();
-        setoverdueStatus(response.data.overdue);
-        console.error(`overdue response: ${JSON.stringify(response)}`);
-        if (!response.data.overdue) {
-          //overdue 为 false 说明没有过期
-          Taro.redirectTo({ url: '/pages/index/index' });
+  const [retryCount, setRetryCount] = useState(0);
+  const [isRetrying, setIsRetrying] = useState(false);
+  const maxRetries = 10;
+  const retryTimeoutRef = useRef<NodeJS.Timeout | null>(null);
+
+  const checkoverdue = async (currentRetry = 0) => {
+    setIsRetrying(true);
+    setRetryCount(currentRetry);
+
+    try {
+      const response = await getQuota();
+      setoverdueStatus(response.data.overdue);
+      console.info(`overdue response: ${JSON.stringify(response)}`);
+
+      if (!response.data.overdue) {
+        // overdue 为 false 说明没有过期
+        setIsRetrying(false);
+        Taro.redirectTo({ url: '/pages/index/index' });
+      } else {
+        // 过期了,需要重试
+        if (currentRetry < maxRetries) {
+          console.info(`Retrying... (${currentRetry + 1}/${maxRetries})`);
+          retryTimeoutRef.current = setTimeout(() => {
+            checkoverdue(currentRetry + 1);
+          }, 1000);
+        } else {
+          // 达到最大重试次数
+          setIsRetrying(false);
+          console.warn('Max retries reached');
         }
-      } catch (error) {
-        setoverdueStatus(true); // 出错时假设为过期,要求重新同步
-        console.error('Error fetching overdue:', error);
       }
-    };
+    } catch (error) {
+      console.error('Error fetching overdue:', error);
+      setoverdueStatus(true); // 出错时假设为过期
+
+      // 出错也需要重试
+      if (currentRetry < maxRetries) {
+        console.info(
+          `Retrying after error... (${currentRetry + 1}/${maxRetries})`
+        );
+        retryTimeoutRef.current = setTimeout(() => {
+          checkoverdue(currentRetry + 1);
+        }, 1000);
+      } else {
+        // 达到最大重试次数
+        setIsRetrying(false);
+        console.warn('Max retries reached after errors');
+      }
+    }
+  };
+
+  const handleManualRetry = () => {
+    // 清除可能存在的自动重试定时器
+    if (retryTimeoutRef.current) {
+      clearTimeout(retryTimeoutRef.current);
+      retryTimeoutRef.current = null;
+    }
+    // 重置状态并重新开始检查
+    setoverdueStatus(null);
+    setRetryCount(0);
+    checkoverdue(0);
+  };
+
+  useEffect(() => {
     checkoverdue();
+
+    // 清理函数:组件卸载时清除定时器
+    return () => {
+      if (retryTimeoutRef.current) {
+        clearTimeout(retryTimeoutRef.current);
+      }
+    };
   }, []);
 
   return (
     <View style={{ paddingTop: '40vh', textAlign: 'center' }}>
       {overdueStatus === null ? (
-        <div>checking...</div>
+        <View>
+          <div>正在检查授权状态...</div>
+          {isRetrying && retryCount > 0 && (
+            <div style={{ marginTop: '10px', fontSize: '14px', color: '#666' }}>
+              重试中... ({retryCount}/{maxRetries})
+            </div>
+          )}
+        </View>
       ) : overdueStatus === true ? (
-        <div>Please sync with the cloud to continue.</div>
+        <View>
+          <div>请与云端同步以继续使用</div>
+          {isRetrying ? (
+            <div style={{ marginTop: '10px', fontSize: '14px', color: '#666' }}>
+              自动重试中... ({retryCount}/{maxRetries})
+            </div>
+          ) : (
+            <div style={{ marginTop: '10px', fontSize: '14px', color: '#999' }}>
+              已重试 {retryCount} 次
+            </div>
+          )}
+          <Button
+            onClick={handleManualRetry}
+            style={{
+              marginTop: '20px',
+              padding: '10px 30px',
+              backgroundColor: '#1890ff',
+              color: '#fff',
+              border: 'none',
+              borderRadius: '4px',
+              cursor: 'pointer',
+            }}
+            disabled={isRetrying}
+          >
+            {isRetrying ? '重试中...' : '手动重试'}
+          </Button>
+        </View>
       ) : (
-        <div>overdue valid, redirecting...</div>
+        <div>授权有效,正在跳转...</div>
       )}
     </View>
   );

+ 3 - 13
src/states/i18nSlice.ts

@@ -3,14 +3,6 @@ import { fetchI18nMessages, I18nMessages } from '../API/i18n/i18nActions';
 import { getLanguageList, changeLanguage, LanguageItem } from '../API/language';
 import { fetchSoftwareInfo } from '../API/softwareInfo';
 
-/**
- * 从 locale 格式提取语言代码
- * 例如: "zh_CN.UTF-8" -> "zh", "en_US.UTF-8" -> "en"
- */
-function extractLanguageCode(locale: string): string {
-  return locale.split('_')[0].split('.')[0];
-}
-
 export interface I18nState {
   messages: I18nMessages;
   currentLocale: string;
@@ -28,8 +20,8 @@ export interface I18nState {
 
 const initialState: I18nState = {
   messages: {},
-  currentLocale: 'en',
-  supportedLocales: ['en', 'zh'],
+  currentLocale: 'en_US',
+  supportedLocales: ['en_US', 'zh_CN'],
   loading: false,
   error: null,
   // 语言管理初始状态
@@ -62,9 +54,7 @@ export const loadAvailableLanguages = createAsyncThunk(
 
     if (languageResponse.data.code === '0x000000') {
       // 从 softwareInfo 获取当前系统语言
-      const currentSystemLocale = extractLanguageCode(
-        softwareInfo.current_locale
-      );
+      const currentSystemLocale = softwareInfo.current_locale;
 
       return {
         languages: languageResponse.data.data,

+ 1 - 1
src/states/productSlice.ts

@@ -12,7 +12,7 @@ interface ProductState {
 
 const initialState: ProductState = {
   productName: 'DROS',
-  language: 'en',
+  language: 'en_US',
   source: 'Browser',
   guest: '',
   fpd: '',