Browse Source

完善日志上报机制

shmily1213 1 tháng trước cách đây
mục cha
commit
fcc7716f4e

+ 3 - 1
src/api/flyio.ts

@@ -42,6 +42,7 @@ fly.interceptors.response.use(
       const { code, msg } = result;
       if (code === 401) {
         logout();
+        return Promise.reject({ code: 401, msg: '未授权,请重新登录', result });
       } else {
         if (code !== 200) {
           uni.$ie.showToast(msg);
@@ -51,7 +52,8 @@ fly.interceptors.response.use(
         }
       }
     } catch (err) {
-      return Promise.reject(result);
+      // 响应数据格式异常,reject 错误对象而不是 result
+      return Promise.reject(err);
     }
   },
   function (err: Error, promise: Promise<any>) {

+ 5 - 1
src/common/enum.ts

@@ -5,7 +5,11 @@ export enum EnumAppConfigKey {
   /**
    * 短信验证码是否开启图形验证
    */
-  SMS_CAPTCHA_ENABLE = 'sys.sms.captchaEnabled'
+  SMS_CAPTCHA_ENABLE = 'sys.sms.captchaEnabled',
+  /**
+   * app 是否开启日志上报
+   */
+  APP_LOG_REPORT_ENABLE = 'app.log.report.enable'
 }
 
 /**

+ 0 - 13
src/common/report.ts

@@ -1,13 +0,0 @@
-export const events = {
-  examStartEnter: 'exam-start-enter',
-  examStartLoadSuccess: 'exam-start-load-success',
-  examStartLoadError: 'exam-start-load-error',
-  examStartGetPaperSuccess: 'exam-start-get-paper-success',
-  examStartGetPaperError: 'exam-start-get-paper-error',
-  examStartInitError: 'exam-start-init-error',
-  ExamStartLoadSlow: 'exam-start-load-slow',
-  ExamStartGetPaperSlow: 'exam-start-get-paper-slow',
-  examStartSubmitSuccess: 'exam-start-submit-success',
-  examStartSubmitError: 'exam-start-submit-error',
-  examStartExit: 'exam-start-exit',
-} as const;

+ 9 - 1
src/hooks/useAppConfig.ts

@@ -9,7 +9,15 @@ export const useAppConfig = () => {
   const isSmsCaptchaEnable = computed(() => {
     return appStore.getAppConfig(EnumAppConfigKey.SMS_CAPTCHA_ENABLE) === 'true';
   });
+  /**
+   * app 是否开启日志上报
+   */
+  const isAppLogReportEnable = computed(() => {
+    return appStore.getAppConfig(EnumAppConfigKey.APP_LOG_REPORT_ENABLE) === 'true';
+  });
+  
   return {
-    isSmsCaptchaEnable
+    isSmsCaptchaEnable,
+    isAppLogReportEnable
   }
 }

+ 63 - 0
src/hooks/useReport.ts

@@ -0,0 +1,63 @@
+import { useUserStore } from "@/store/userStore";
+import { useEnv } from "./useEnv";
+import { useTransferPage } from "./useTransferPage";
+import { useAppConfig } from "./useAppConfig";
+
+export const events = {
+  ExamStartEnter: 'exam-start-enter',
+
+  ExamStartLoadSuccess: 'exam-start-load-success',
+  ExamStartLoadSlow: 'exam-start-load-slow',
+  ExamStartLoadError: 'exam-start-load-error',
+
+  ExamStartCombineData: 'exam-start-combine-data',
+  ExamStartCombineDataSuccess: 'exam-start-combine-data-success',
+  ExamStartCombineDataError: 'exam-start-combine-data-error',
+
+  ExamStartGetPaperSuccess: 'exam-start-get-paper-success',
+  ExamStartGetPaperSlow: 'exam-start-get-paper-slow',
+  ExamStartGetPaperError: 'exam-start-get-paper-error',
+
+  ExamStartBeginExamineeSlow: 'exam-start-begin-examinee-slow',
+  ExamStartBeginExamineeSuccess: 'exam-start-begin-examinee-success',
+  ExamStartBeginExamineeError: 'exam-start-begin-examinee-error',
+
+  ExamStartInitError: 'exam-start-init-error',
+  ExamStartSubmitSuccess: 'exam-start-submit-success',
+  ExamStartSubmitError: 'exam-start-submit-error',
+  ExamStartExit: 'exam-start-exit',
+  PracticeDetailEnter: 'practice-detail-enter',
+} as const;
+
+type EventType = typeof events[keyof typeof events];
+
+const { isAppLogReportEnable } = useAppConfig();
+const userStore = useUserStore();
+const { platform } = useEnv();
+
+export const useReport = () => {
+  const { prevData } = useTransferPage();
+  const report = (event: EventType, extraData: any = {}) => {
+    if (isAppLogReportEnable.value) {
+      uni.report(event, getReportData(extraData));
+    }
+  }
+  const getReportData = (extraData: any = {}) => {
+    return {
+      pageOptions: prevData.value,
+      userInfo: {
+        userName: userStore.userInfo.userName,
+        phonenumber: userStore.userInfo.phonenumber,
+      },
+      platform: platform.value,
+      extraData,
+      createTime: Date.now()
+    }
+  }
+
+  return {
+    report,
+    getReportData,
+    events
+  }
+}

+ 6 - 0
src/pages.json

@@ -571,6 +571,12 @@
           "style": {
             "navigationBarTitleText": ""
           }
+        },
+        {
+          "path": "pages/debug/debug",
+          "style": {
+            "navigationBarTitleText": ""
+          }
         }
       ]
     },

+ 1 - 1
src/pagesMain/pages/index/components/index-popup.vue

@@ -1,5 +1,5 @@
 <template>
-  <ie-popup title="" mode="bottom" ref="popupRef" :showToolbar="false">
+  <ie-popup title="" mode="bottom" ref="popupRef" :close-on-click-overlay="false" :showToolbar="false">
     <view class="popup-content relative">
       <ie-image :is-oss="true" src="/study-bg15.png" custom-class="absolute top-0 left-0 w-full h-392 z-0"
         mode="aspectFill" />

+ 30 - 8
src/pagesOther/pages/personal-center/setting/setting.vue

@@ -40,17 +40,39 @@ const settings = computed(() => [
     handler: () => transferToProtocolPrivacy()
   },
   {
-    title: '清除缓存', //icon_cache
+    title: '清除数据', //icon_cache
     icon: '/static/personal/icon_cache.png',
-    rightIcon: 'reload',
+    // rightIcon: 'reload',
     isLink: true,
-    value: cacheSize.value,
+    value: '',
+    // value: cacheSize.value,
     handler: () => {
-      cleanAllTransferCacheData() // 清理页面大对象
-      if (isLogin.value) {
-        GetInfo() // GetInfo也会清除缓存,借机也更新一下用户信息
-      }
-      calculateCacheSize()
+      // cleanAllTransferCacheData() // 清理页面大对象
+      // if (isLogin.value) {
+      //   GetInfo() // GetInfo也会清除缓存,借机也更新一下用户信息
+      // }
+      // calculateCacheSize()
+      // 清除所有本地数据,重启 app
+      uni.$ie.showModal({
+        title: '提示',
+        content: '清除数据后需要重新登录\n是否继续?',
+      }).then(confirm => {
+        if (confirm) {
+          uni.clearStorageSync();
+          setTimeout(() => {
+            // 再次尝试清除,防止有补偿机制
+            uni.clearStorageSync();
+            // #ifdef H5
+            window.location.href = '/h5/';
+            // #endif
+            // #ifdef MP-WEIXIN
+            wx.restartMiniProgram({
+              path: '/pagesMain/pages/splash/splash'
+            });
+            // #endif
+          }, 100);
+        }
+      })
     }
   },
   {

+ 113 - 39
src/pagesStudy/pages/exam-start/exam-start.vue

@@ -34,8 +34,9 @@ import {
 } from '@/types/injectionSymbols';
 import { useAppStore } from '@/store/appStore';
 import { useEnv } from '@/hooks/useEnv';
-import { events } from '@/common/report';
+import { useReport } from '@/hooks/useReport';
 
+const { report, events } = useReport();
 const appStore = useAppStore();
 const { platform } = useEnv();
 const userStore = useUserStore();
@@ -206,10 +207,11 @@ const handleSubmit = (tempSave: boolean = false) => {
     const start = Date.now();
     await commitExamineePaper(params);
     const costTime = Date.now() - start;
-    uni.report(events.examStartSubmitSuccess, getReportData({ time: costTime }));
+    report(events.ExamStartSubmitSuccess, { time: costTime });
     if (isSimulationExam.value || isTestExam.value) {
       if (!tempSave) {
         setTimeout(async () => {
+          report(events.ExamStartExit);
           uni.$ie.hideLoading();
           await nextTick();
           confirmQuit.value = true;
@@ -233,6 +235,7 @@ const handleSubmit = (tempSave: boolean = false) => {
     } else if (isPracticeExam.value) {
       if (!tempSave) {
         setTimeout(async () => {
+          report(events.ExamStartExit);
           uni.$ie.hideLoading();
           await nextTick();
           confirmQuit.value = true;
@@ -249,6 +252,7 @@ const handleSubmit = (tempSave: boolean = false) => {
           });
         }, 2500);
       } else {
+        report(events.ExamStartExit);
         uni.$ie.hideLoading();
         confirmQuit.value = true;
         confirmShowing.value = false;
@@ -312,9 +316,7 @@ const getOpenExamineeWithTimeoutCheck = async (params: Study.OpenExamineeRequest
       }
       // 上报超时数据,超时时间单位为秒
       // 每个时间点如果请求还未返回,都会上报一次
-      uni.report(events.ExamStartLoadSlow, getReportData({
-        time: timeout
-      }));
+      report(events.ExamStartLoadSlow, { time: timeout });
     }, timeout) as unknown as number;
     timers.push(timer);
   });
@@ -357,9 +359,7 @@ const getPaperWithTimeoutCheck = async (params: Study.GetExamPaperRequestDTO) =>
       }
       // 上报超时数据,超时时间单位为秒
       // 每个时间点如果请求还未返回,都会上报一次
-      uni.report(events.ExamStartGetPaperSlow, getReportData({
-        time: timeout
-      }));
+      report(events.ExamStartGetPaperSlow, { time: timeout });
     }, timeout) as unknown as number;
     timers.push(timer);
   });
@@ -380,6 +380,49 @@ const getPaperWithTimeoutCheck = async (params: Study.GetExamPaperRequestDTO) =>
   }
 };
 
+/**
+ * 带超时检测的 beginExaminee 请求
+ * 在 3s, 5s, 10s, 15s, 20s 这 5 个时间点检测超时并上报
+ * 每个时间点如果请求还未返回,都会上报一次
+ */
+const beginExamineeWithTimeoutCheck = async (examineeId: number) => {
+  // 超时时间档次(单位:毫秒)
+  const timeoutLevels = [3000, 5000, 10000, 15000, 20000];
+  // 存储所有定时器ID,用于清理
+  const timers: number[] = [];
+  // 请求是否已完成
+  let isCompleted = false;
+
+  // 创建超时检测定时器
+  timeoutLevels.forEach((timeout) => {
+    const timer = setTimeout(() => {
+      // 如果请求已完成,不进行上报
+      if (isCompleted) {
+        return;
+      }
+      // 上报超时数据,超时时间单位为秒
+      // 每个时间点如果请求还未返回,都会上报一次
+      report(events.ExamStartBeginExamineeSlow, { time: timeout });
+    }, timeout) as unknown as number;
+    timers.push(timer);
+  });
+
+  try {
+    // 执行请求
+    const result = await beginExaminee(examineeId);
+    // 标记请求已完成
+    isCompleted = true;
+    // 清除所有定时器
+    timers.forEach((timer) => clearTimeout(timer));
+    return result;
+  } catch (error) {
+    // 请求失败时也要清除定时器
+    isCompleted = true;
+    timers.forEach((timer) => clearTimeout(timer));
+    throw error;
+  }
+};
+
 // 1、加载知识点练习数据
 const loadPracticeData = async () => {
   const { paperType, readonly, practiceInfo } = prevData.value;
@@ -405,13 +448,9 @@ const loadPracticeData = async () => {
       data = res.data || {};
       const costTime = Date.now() - start;
       console.log('开卷用时:', costTime);
-      uni.report(events.examStartLoadSuccess, getReportData({
-        time: costTime
-      }));
+      report(events.ExamStartLoadSuccess, { time: costTime, request: params, response: res.data || {} });
     } catch (error) {
-      uni.report(events.examStartLoadError, getReportData({
-        error: error
-      }));
+      report(events.ExamStartLoadError, { error: error });
     }
   }
 
@@ -433,8 +472,16 @@ const loadExamData = async () => {
       const res = await getExamineeResult(simulationInfo.examineeId);
       data = res.data;
     } else {
-      const res = await beginExaminee(simulationInfo.examineeId);
-      data = res.data || {};
+      try {
+        const start = Date.now();
+        const res = await beginExamineeWithTimeoutCheck(simulationInfo.examineeId);
+        data = res.data || {};
+        const costTime = Date.now() - start;
+        report(events.ExamStartBeginExamineeSuccess, { time: costTime, request: { examineeId: simulationInfo.examineeId }, response: res.data || {} });
+      } catch (error) {
+        report(events.ExamStartBeginExamineeError, { error: error });
+        throw error;
+      }
     }
     if (!data) {
       uni.$ie.hideLoading();
@@ -472,22 +519,49 @@ const loadExamData = async () => {
 // }
 const combinePaperData = async (examinee: Study.Examinee, paperType: EnumPaperType) => {
   examineeId.value = examinee.examineeId;
-  if (examinee.paperId) {
+  report(events.ExamStartCombineData, {
+    envUser: localStorage.getItem('ie-user'),
+    envApp: localStorage.getItem('ie-app'),
+  });
+
+  if (!examinee.paperId) {
+    report(events.ExamStartGetPaperError, {
+      error: '获取试卷数据失败,没有paperId',
+      examineeId: examinee.examineeId
+    });
+    return;
+  }
+
+  // 第一步:请求试卷数据(单独 try-catch)
+  let res;
+  try {
     const start = Date.now();
-    const res = await getPaperWithTimeoutCheck({
+    res = await getPaperWithTimeoutCheck({
       type: paperType,
       id: examinee.paperId
     });
     const costTime = Date.now() - start;
+    report(events.ExamStartGetPaperSuccess, {
+      time: costTime,
+      paperId: examinee.paperId,
+      paperType: paperType
+    });
+  } catch (error: any) {
+    // 请求失败的错误上报
+    report(events.ExamStartGetPaperError, {
+      error: error
+    });
+    throw error; // 继续抛出,让外层处理
+  }
+
+  // 第二步:处理和组装数据(单独 try-catch)
+  try {
     paperData.value = res.data;
     paperData.value.questions = restoreQuestion(examinee.questions, res.data.questions);
     console.log('初始化数据', paperData.value.questions)
     setQuestionList(paperData.value.questions);
     setDuration(examinee.duration || 0);
 
-    uni.report(events.examStartGetPaperSuccess, getReportData({
-      time: costTime
-    }));
     await nextTick();
     const targetQuestion = flatQuestionList.value.find(item => item.id === prevData.value.questionId);
     if (targetQuestion) {
@@ -519,10 +593,16 @@ const combinePaperData = async (examinee: Study.Examinee, paperType: EnumPaperTy
         startTime();
       }
     }
-  } else {
-    uni.report(events.examStartGetPaperError, getReportData({
-      error: '获取试卷数据失败,没有paperId'
-    }));
+    report(events.ExamStartCombineDataSuccess, {
+      paperId: examinee.paperId,
+      paperType: paperType
+    });
+  } catch (error: any) {
+    // 数据处理失败的错误上报
+    report(events.ExamStartCombineDataError, {
+      error: error
+    });
+    throw error; // 继续抛出,让外层处理
   }
 }
 const handleSwiperTipNext = () => {
@@ -545,24 +625,18 @@ const loadData = async () => {
       loadExamData();
     }
   } catch (error) {
-    uni.report(events.examStartInitError, getReportData(error));
+    report(events.ExamStartInitError, { error });
+    uni.$ie.showToast('加载失败,请稍后重试');
+    setTimeout(() => {
+      uni.$ie.hideLoading();
+      transferBack();
+    }, 1000);
   }
 };
-const getReportData = (extraData: any = {}) => {
-  return {
-    pageOptions: prevData.value,
-    userInfo: {
-      userName: userStore.userInfo.userName,
-      phonenumber: userStore.userInfo.phonenumber,
-    },
-    platform: platform.value,
-    extraData,
-    createTime: Date.now()
-  }
-}
+
 onLoad(() => {
   console.log(prevData.value)
-  uni.report(events.examStartEnter, getReportData());
+  report(events.ExamStartEnter);
   loadData();
   uni.addInterceptor('navigateBack', {
     invoke: (e) => {

+ 33 - 28
src/pagesStudy/pages/knowledge-practice-detail/knowledge-practice-detail.vue

@@ -41,11 +41,13 @@
 import RateChart from '@/pagesStudy/pages/simulation-analysis/components/rate-chart.vue';
 import ExamStat from '@/pagesStudy/pages/simulation-analysis/components/exam-stat.vue';
 import { useTransferPage } from '@/hooks/useTransferPage';
-import { Study, Transfer } from '@/types';
+import type { Study, Transfer } from '@/types';
 import { getExamineeResult } from '@/api/modules/study';
 import { EnumPaperType } from '@/common/enum';
-const { prevData, transferTo } = useTransferPage<Transfer.PracticeResultPageOptions, Transfer.ExamAnalysisPageOptions>();
+import { useReport } from '@/hooks/useReport';
 
+const { prevData, transferTo } = useTransferPage<Transfer.PracticeResultPageOptions, Transfer.ExamAnalysisPageOptions>();
+const { report, events } = useReport();
 
 const rightRate = computed(() => {
   const { totalCount = 0, wrongCount = 0 } = examineeData.value || {};
@@ -80,7 +82,7 @@ const handleQuestionDetail = (item: Study.Question) => {
   }
   transferTo('/pagesStudy/pages/exam-start/exam-start', {
     data: {
-      name: paperName.value,
+      // name: paperName.value,
       paperType: prevData.value.paperType || EnumPaperType.PRACTICE,
       readonly: true,
       questionId: item.id,
@@ -88,7 +90,9 @@ const handleQuestionDetail = (item: Study.Question) => {
         name: prevData.value.name,
         relateId: examineeData.value.knowledgeId,
         directed: prevData.value.directed,
-        examineeId: examineeData.value.examineeId
+        examineeId: examineeData.value.examineeId,
+        // 对口升学
+        questionType: prevData.value.questionType
       },
     }
   });
@@ -99,38 +103,38 @@ const handleStartPractice = () => {
     console.error('knowledgeId is null');
     return;
   }
+  const pageOptions: Transfer.ExamAnalysisPageOptions = {
+    paperType: prevData.value.paperType || EnumPaperType.PRACTICE,
+    readonly: false,
+    practiceInfo: {
+      name: prevData.value.name,
+      relateId: knowledgeId,
+      directed: prevData.value.directed,
+      questionType: prevData.value.questionType
+    },
+  }
   transferTo('/pagesStudy/pages/exam-start/exam-start', {
-    data: {
-      name: paperName.value,
-      paperType: prevData.value.paperType || EnumPaperType.PRACTICE,
-      practiceInfo: {
-        name: prevData.value.name,
-        relateId: knowledgeId,
-        directed: prevData.value.directed,
-        // 对口升学
-        isVHS: prevData.value.isVHS,
-        questionType: prevData.value.questionType
-      },
-    } as Transfer.ExamAnalysisPageOptions
+    data: pageOptions
   });
 }
 const handleViewAnalysis = () => {
   if (!examineeData.value) {
     return;
   }
+  const pageOptions: Transfer.ExamAnalysisPageOptions = {
+    paperType: prevData.value.paperType || EnumPaperType.PRACTICE,
+    readonly: true,
+    practiceInfo: {
+      name: prevData.value.name,
+      relateId: examineeData.value.knowledgeId,
+      directed: prevData.value.directed,
+      examineeId: examineeData.value.examineeId,
+      // 对口升学
+      questionType: prevData.value.questionType
+    },
+  }
   transferTo('/pagesStudy/pages/exam-start/exam-start', {
-    data: {
-      paperType: EnumPaperType.PRACTICE,
-      readonly: true,
-      practiceInfo: {
-        name: prevData.value.name,
-        relateId: examineeData.value.knowledgeId,
-        directed: prevData.value.directed,
-        examineeId: examineeData.value.examineeId,
-        // 对口升学
-        questionType: prevData.value.questionType
-      },
-    } as Transfer.ExamAnalysisPageOptions
+    data: pageOptions
   });
 }
 const loadData = async () => {
@@ -143,6 +147,7 @@ const loadData = async () => {
   }
 }
 onLoad(() => {
+  report(events.PracticeDetailEnter)
   console.log(prevData.value)
   loadData();
 });

+ 3 - 3
src/pagesStudy/pages/textbooks-practice/textbooks-practice.vue

@@ -30,7 +30,7 @@ import { useAuth } from '@/hooks/useAuth';
 
 const { prevData, transferTo } = useTransferPage();
 const userStore = useUserStore();
-const pagingRef = ref();
+const pagingRef = ref<ZPagingInstance>();
 const { hasPermission } = useAuth();
 
 const pageTitle = computed(() => {
@@ -50,10 +50,10 @@ const loadKnowledgeList = async (page: number, size: number) => {
     uni.$ie.showLoading();
     const { data } = await getTextbooksKnowledgeList();
     treeData.value = data as Study.KnowledgeNode[];
-    pagingRef.value.complete(data);
+    pagingRef.value?.complete(data);
   } catch (error) {
     console.log(error);
-    pagingRef.value.complete(false);
+    pagingRef.value?.complete(false);
   } finally {
     uni.$ie.hideLoading();
   }

+ 67 - 0
src/pagesSystem/pages/debug/debug.vue

@@ -0,0 +1,67 @@
+<template>
+  <ie-page bg-color="#F6F8FA">
+    <ie-navbar title="调试" />
+    <view class="p-20">
+      <view class="h-20 my-20">用户数据:</view>
+      <view class="bg-white">
+        <textarea class="p-20 h-400 break-all" v-model="userJson" maxlength="-1"></textarea>
+      </view>
+    </view>
+    <view class="m-20">
+      <uv-button type="primary" @click="handleLoad">加载</uv-button>
+    </view>
+    <view class="p-20">
+      <view class="h-20 my-20">app数据:</view>
+      <view class="bg-white">
+        <textarea class="p-20 h-400 break-all" v-model="appJson" maxlength="-1"></textarea>
+      </view>
+    </view>
+    <view class="m-20">
+      <uv-button type="primary" @click="handleLoad">加载</uv-button>
+    </view>
+    <view class="m-20">
+      <uv-button type="success" @click="handleToHome">进入首页</uv-button>
+    </view>
+  </ie-page>
+</template>
+
+<script lang="ts" setup>
+import { useUserStore } from '@/store/userStore';
+import { useAppStore } from '@/store/appStore';
+
+const userStore = useUserStore();
+const appStore = useAppStore();
+
+const userJson = ref('');
+const appJson = ref('');
+
+const handleLoad = () => {
+  if (userJson.value) {
+    try {
+      userStore.loadFromLocal(userJson.value);
+      uni.$ie.showToast('加载成功');
+    } catch (error) {
+      uni.$ie.showToast('加载失败');
+    }
+  }
+}
+const handleLoadApp = () => {
+  if (appJson.value) {
+    try {
+      appStore.loadFromLocal(appJson.value);
+      uni.$ie.showToast('加载成功');
+    } catch (error) {
+      uni.$ie.showToast('加载失败');
+    }
+  }
+}
+
+const handleToHome = () => {
+  uni.reLaunch({
+    url: '/pagesMain/pages/index/index',
+    type: 'reLaunch'
+  });
+}
+</script>
+
+<style lang="scss"></style>

+ 13 - 0
src/store/appStore.ts

@@ -88,6 +88,19 @@ export const useAppStore = defineStore('ie-app', {
     },
     clear() {
       this.isInitialized = false;
+    },
+    loadFromLocal(state: string) {
+      const value = JSON.parse(state);
+      if (value) {
+        const { appConfig, activeTabbar, statusBarHeight, sysInfo, isInitialized } = value;
+        this.appConfig = appConfig || [];
+        this.activeTabbar = activeTabbar || 0;
+        this.statusBarHeight = statusBarHeight || 0;
+        this.sysInfo = sysInfo || null;
+        this.isInitialized = isInitialized || false;
+        return true;
+      }
+      return false;
     }
   },
   persist: {

+ 47 - 0
src/store/userStore.ts

@@ -321,6 +321,53 @@ export const useUserStore = defineStore('ie-user', {
       //   })
       // }, 300);
     },
+    loadFromLocal(state: string) {
+      const value = JSON.parse(state);
+      if (value) {
+        const { accessToken, user, card, isDefaultModifyPwd, isPasswordExpired,
+          org, rememberPwd, cardNo, cardPassword, directedSchoolList, practiceSettings,
+          isExamGuideShow,
+          tempInfo,
+        } = value;
+        this.accessToken = accessToken;
+        this.user = user;
+        this.card = card;
+        this.isDefaultModifyPwd = isDefaultModifyPwd;
+        this.isPasswordExpired = isPasswordExpired;
+        this.org = org;
+        this.rememberPwd = rememberPwd;
+        this.cardNo = cardNo;
+        this.cardPassword = cardPassword;
+        this.directedSchoolList = directedSchoolList;
+        this.practiceSettings = practiceSettings;
+        this.isExamGuideShow = isExamGuideShow;
+        this.tempInfo = tempInfo;
+        return true;
+      }
+      return false;
+    },
+    clear() {
+      this.accessToken = null;
+      this.user = null;
+      this.isDefaultModifyPwd = false;
+      this.isPasswordExpired = false;
+      this.org = {
+        ...config.defaultOrg,
+      };
+      this.rememberPwd = false;
+      this.cardNo = '';
+      this.cardPassword = '';
+      this.directedSchoolList = [];
+      this.practiceSettings = {
+        reviewMode: EnumReviewMode.AFTER_SUBMIT,
+        autoNext: false
+      };
+      this.isExamGuideShow = false;
+      this.tempInfo = {
+        location: '',
+        examType: undefined,
+      };
+    }
   },
   persist: {
     storage: {