保誠-保戶業務員媒合平台
Tomas
2023-12-25 f065760fa7df1f88747395ab4b55349ce8b2faf0
Update#178944: 移除 lodash 套件
修改14個檔案
213 ■■■■ 已變更過的檔案
PAMapp/components/BackActionBar.vue 3 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/NavBar.vue 9 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/careerSelect.vue 7 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/editConsultantAvatar.vue 5 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/singleSelectBtn.vue 3 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/layouts/default.vue 5 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/layouts/home.vue 3 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/accountSetting/index.vue 49 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/myAppointmentList.vue 6 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/questionnaire/_agentNo.vue 84 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/quickFilter/index.vue 1 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/shared/services/httpClient.ts 12 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/shared/services/login.service.ts 8 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/store/localStorage.service.ts 18 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/BackActionBar.vue
@@ -11,7 +11,6 @@
import { namespace } from 'nuxt-property-decorator';
import { Vue, Component,} from 'vue-property-decorator';
import * as _ from 'lodash';
import { Role } from '~/shared/models/enum/Role';
const appointmentStore = namespace('appointment.store');
@@ -54,7 +53,7 @@
          break;
        case 'agentInfo':
          const agentFeatureLabel = this.$route.name.includes('edit') ? '編輯帳號資訊' : '查看帳號資訊';
          featureLabel = _.isEqual(this.currentRole,Role.ADMIN)
          featureLabel = this.currentRole === Role.ADMIN
                  ? agentFeatureLabel
                  : '業務員資訊'
          break;
PAMapp/components/NavBar.vue
@@ -54,7 +54,6 @@
  import { Vue, Component } from 'vue-property-decorator';
  import { Action, namespace, State, Watch } from 'nuxt-property-decorator';
  import { Role } from '~/shared/models/enum/Role';
  import * as _ from 'lodash';
  import { NotificationList } from '~/shared/models/reviews.model';
  import { AppointmentLog } from '~/shared/models/appointment.model';
  import loginService from '~/shared/services/login.service'
@@ -156,20 +155,20 @@
    routerNavigateTo(url: string): void {
      (this.$refs.dropdown as any).hide();
      _.isEqual(url,'')
      url === ''
        ? this.logout()
        : this.$router.push(_.isEqual(url,'/agentInfo/') ? url+this.consultantId :url);
        : this.$router.push(url === '/agentInfo/' ? url+this.consultantId : url);
    }
    pushRouterByLoginRole(): void {
      const link = _.isEqual(this.currentRole, Role.ADMIN) ? '/myAppointmentList/appointmentList' : '/';
      const link = this.currentRole === Role.ADMIN ? '/myAppointmentList/appointmentList' : '/';
      this.$router.push(link);
    }
    logout(): void {
      loginService.logout().then(() => {
        this.storageClear();
        _.isEqual(this.$route.name, 'index') ? location.reload() : this.$router.push('/');
        this.$route.name === 'index' ? location.reload() : this.$router.push('/');
      });
    }
PAMapp/components/careerSelect.vue
@@ -41,7 +41,6 @@
<script lang="ts">
  import { Component , PropSync , Vue} from "vue-property-decorator";
  import * as _ from 'lodash';
  @Component
  export default class CareerSelect extends Vue {
@@ -83,7 +82,7 @@
    patchInitValue(): void{
      if(this.syncCareerSelect){
        if(_.includes(['外勤','內勤'],this.syncCareerSelect)){
        if (['外勤','內勤'].includes(this.syncCareerSelect)) {
          this.career = this.syncCareerSelect;
        }else{
          this.career = '其他';
@@ -95,8 +94,8 @@
    patchCareer(): void {
      this.showJobDrawer = false;
      this.syncCareerSelect = this.career === '其他'
                          ? _.cloneDeep(this.career_Other)
                          : _.cloneDeep(this.career);
                          ? JSON.parse(JSON.stringify(this.career_Other))
                          : JSON.parse(JSON.stringify(this.career));
    }
    get isCareerValid(): boolean {
PAMapp/components/editConsultantAvatar.vue
@@ -38,7 +38,6 @@
  import { MessageBox } from 'element-ui';
  import { MessageBoxData } from 'element-ui/types/message-box';
  import _ from 'lodash';
  import myConsultantService from '~/shared/services/my-consultant.service';
@@ -74,7 +73,7 @@
    }
    handleAvatarUploaded(file:any): void {
      const isFollowUploadRule =_.includes(file.raw.type,'image/');
      const isFollowUploadRule = file.raw.type.includes('image/');
      isFollowUploadRule ? this.getImgSrc(file) : this.showFileUploadErrorMsg()
    }
@@ -96,7 +95,7 @@
    }
    private splitBase64WithCommon(base64: string): void {
      const splitBase64= _.split(base64, ','); // 為了把 data:image , base64 解析分開;
      const splitBase64 = base64.split(','); // 為了把 data:image , base64 解析分開;
      this.syncPhotoBase64 = splitBase64[1];
      // NOTE: 因為目前以 agentNO 取得 avatar 會失敗,
      // 故加上此判斷來防範不預期顯示'取消按鈕'的狀況。 [Tomas, 2022/1/3]
PAMapp/components/singleSelectBtn.vue
@@ -21,7 +21,6 @@
<script lang="ts">
  import { Component, Prop, PropSync, Vue } from "nuxt-property-decorator";
  import { OptionBtnDto } from "~/shared/models/optionBtnDto.model";
  import * as _ from 'lodash';
  @Component
  export default class SingleSelectBtn extends Vue {
@@ -35,7 +34,7 @@
    //////////////////////////////////////////////////////////////////////
    patchValue(value: string | number): void {
      // 主要解決按鈕點擊兩次能回到,未點選的狀態
      this.syncSingleSelected = _.isEqual(this.syncSingleSelected, value) ? "" : value;
      this.syncSingleSelected = this.syncSingleSelected === value ? "" : value;
    }
  }
</script>
PAMapp/layouts/default.vue
@@ -25,7 +25,6 @@
<script lang="ts">
  import { Vue, Component } from 'vue-property-decorator';
  import * as _ from 'lodash';
  @Component
  export default class DefaultLayout extends Vue {
@@ -52,13 +51,13 @@
    // format to {page}-container tag
    private routeFormatContainClass(route: string): string {
      const needContainBgRoutes = ['recommendConsultant', 'questionnaire-agentNo'];
      return _.includes(needContainBgRoutes, route) ? route + '-container' : '';
      return needContainBgRoutes.includes(route) ? route + '-container' : '';
    };
    // format to {page}-banner or pam-no-banner tag
    private routeFormatBannerClass(route: string): string {
      const needBannerRoutes = ['recommendConsultant', 'quickFilter', 'myConsultantList-consultantList', 'myConsultantList-contactedList', 'myAppointmentList-appointmentList', 'myAppointmentList-contactedList', 'login', 'notification'];
      return _.includes(needBannerRoutes, route) ? route + '-banner' : 'pam-no-banner';
      return needBannerRoutes.includes(route) ? route + '-banner' : 'pam-no-banner';
    };
    private bannerText: FeatureBannerTitle= {
PAMapp/layouts/home.vue
@@ -9,7 +9,6 @@
</template>
<script lang="ts">
    import { Component ,Vue } from "nuxt-property-decorator";
    import * as _ from 'lodash';
    @Component
    export default class DefaultLayout extends Vue {
@@ -34,4 +33,4 @@
        }
    }
</style>
</style>
PAMapp/pages/accountSetting/index.vue
@@ -164,8 +164,6 @@
import { Vue,Component } from 'vue-property-decorator'
import { namespace } from 'vuex-class';
import _ from 'lodash';
import accountSettingService from '~/shared/services/account-setting.service';
import { UserSetting } from '~/shared/models/account.model';
@@ -202,28 +200,29 @@
////////////////////////////////////////////////////////////
  mounted(){
            accountSettingService.getUserAccountSetting().then((userInfo: UserSetting)=>{
                this.defaultUserSetting = _.cloneDeep({
                    name : userInfo.name || '',
                    phone: userInfo.phone || '',
                    email: userInfo.email || '',
                });
                this.phoneValue    = this.defaultUserSetting.phone!;
                this.userNameValue = this.defaultUserSetting.name!;
                this.emailValue    = this.defaultUserSetting.email!;
            })
        }
    accountSettingService.getUserAccountSetting().then((userInfo: UserSetting)=>{
      this.defaultUserSetting = {
        name : userInfo.name || '',
        phone: userInfo.phone || '',
        email: userInfo.email || '',
      };
      this.phoneValue    = this.defaultUserSetting.phone!;
      this.userNameValue = this.defaultUserSetting.name!;
      this.emailValue    = this.defaultUserSetting.email!;
    })
  }
////////////////////////////////////////////////////////////
  editField(fieldName: string): void {
            const enablePromise = new Promise((resolve, reject) => { // 此為promise語法
                resolve((this as any)[`${fieldName}Disabled`] = false);
            });
            const targetInput = this.$refs[fieldName] as any;
            enablePromise.then((_) => {
                targetInput.focus();
            });
        }
      const enablePromise = new Promise((resolve, reject) => { // 此為promise語法
          resolve((this as any)[`${fieldName}Disabled`] = false);
      });
      const targetInput = this.$refs[fieldName] as any;
      enablePromise.then((_) => {
          targetInput.focus();
      });
  }
  updateAccountSetting(): void {
      const editSettingInfo: UserSetting = {
          name: this.userNameValue,
@@ -238,10 +237,10 @@
  }
  private resetSettingForm(): void {
            this.userNameDisabled = true;
            this.userPhoneDisabled = true;
            this.userEmailDisabled = true ;
        }
      this.userNameDisabled = true;
      this.userPhoneDisabled = true;
      this.userEmailDisabled = true ;
  }
  editOtherContactType(){
    this.otherContactType = true;
PAMapp/pages/myAppointmentList.vue
@@ -64,8 +64,6 @@
<script lang="ts">
import { Vue, Component, Watch, namespace } from 'nuxt-property-decorator';
import * as _ from 'lodash';
import appointmentService from '~/shared/services/appointment.service';
import { Appointment } from '~/shared/models/appointment.model';
import { ContactStatus } from '~/shared/models/enum/contact-status';
@@ -183,8 +181,8 @@
    // format to {page}-banner or pam-no-banner tag
    private routeFormatBannerClass(route: string): string {
        const needBannerTags = ['myAppointmentList-appointmentList', 'myAppointmentList-closedList'];
        return _.includes(needBannerTags, route) ? route + '-banner' : 'pam-no-banner';
      const needBannerTags = ['myAppointmentList-appointmentList', 'myAppointmentList-closedList'];
      return needBannerTags.includes(route) ? route + '-banner' : 'pam-no-banner';
    };
}
</script>
PAMapp/pages/questionnaire/_agentNo.vue
@@ -160,7 +160,6 @@
<script lang="ts">
import { Vue, Component, State, Action, Watch, namespace } from 'nuxt-property-decorator';
import { getRequestsFromStorage, removeRequestQuestionFromStorage, setRequestsToStorage } from '~/shared/storageRequests';
import _ from 'lodash';
import accountSettingService from '~/shared/services/account-setting.service';
import appointmentService from '~/shared/services/appointment.service';
@@ -277,37 +276,37 @@
    ];
    quesAboutList = [
                  {
                      title:'健康與保障',
                      content:'唯有把身體照顧好,才是保障幸福之本,不做盲目燃燒的蠟燭,只做綻開的陽光,陪孩子多走一哩路,人生的美正要開展。'
                  },
                  {
                      title:'子女教育',
                      content:'孩子,我們是雙方的導師也是學生,面對未來要並肩作戰,學會勇敢無畏、克服挫折、善於理財,這條路上我們一起學。'
                  },
                  {
                      title:'資產規劃',
                      content:'真正的財富來自嚴謹規劃資產傳承,為人生蓋一堵抵禦財務風險的牆,確保資產穩健成長,替全家族的未來做好萬全準備。'
                  },
                  {
                      title:'樂活退休',
                      content:'拼一輩子,退休後的日子要輕鬆快活,就得提早透過保險商品規劃退休財務,替自己創造穩定收入,為精彩的熟年人生揭開序幕。'
                  },
                  {
                      title:'保單健檢/規劃',
                      content:'全面檢視自己的保障結構是否符合現在或未來的風險移轉需求。'
                  },
                  {
                      title:'分紅保單',
                      content:'分紅保單是兼具「分攤風險」與「紅利共享」特色的保單,具有一定穩定度,讓您可以同時享有壽險保障及紅利!'
                  }
      {
          title:'健康與保障',
          content:'唯有把身體照顧好,才是保障幸福之本,不做盲目燃燒的蠟燭,只做綻開的陽光,陪孩子多走一哩路,人生的美正要開展。'
      },
      {
          title:'子女教育',
          content:'孩子,我們是雙方的導師也是學生,面對未來要並肩作戰,學會勇敢無畏、克服挫折、善於理財,這條路上我們一起學。'
      },
      {
          title:'資產規劃',
          content:'真正的財富來自嚴謹規劃資產傳承,為人生蓋一堵抵禦財務風險的牆,確保資產穩健成長,替全家族的未來做好萬全準備。'
      },
      {
          title:'樂活退休',
          content:'拼一輩子,退休後的日子要輕鬆快活,就得提早透過保險商品規劃退休財務,替自己創造穩定收入,為精彩的熟年人生揭開序幕。'
      },
      {
          title:'保單健檢/規劃',
          content:'全面檢視自己的保障結構是否符合現在或未來的風險移轉需求。'
      },
      {
          title:'分紅保單',
          content:'分紅保單是兼具「分攤風險」與「紅利共享」特色的保單,具有一定穩定度,讓您可以同時享有壽險保障及紅利!'
      }
    ];
    myRequest: AppointmentRequests = {
      name           : '',
      phone          : '',
      email          : '',
      contactType    : _.isEqual(this.userInfo?.contactType,ContactType.SMS) ? ContactType.PHONE: ContactType.EMAIL,
      contactType    : this.userInfo?.contactType === ContactType.SMS ? ContactType.PHONE: ContactType.EMAIL,
      gender         : '',
      age            : '',
      job            : '',
@@ -452,26 +451,21 @@
    ////////////////////////////////////////////////////////////////////////////
    async sentDemand() {
      if (!this.isEditBtn) {
      if (this.isEditBtn) {
        await this.editAppointmentDemand();
      } else {
        // 使用 async/await 來等待異步操作的回傳結果
        const addFavoriteAgentList = [{ agentNo: this.$route.params.agentNo, createdTime: new Date().toISOString() }];
        const response = await queryConsultantService.addFavoriteConsultant(addFavoriteAgentList);
        // 確保異步操作的回傳結果不為 null 或 undefined
        if (!response) {
          throw new Error('queryConsultantService.addFavoriteConsultant returned null-like value.');
        if (response !== null) {
          await this.sentAppointmentDemand();
        } else {
          if (typeof this.editAppointmentDemand === 'function') {
            // 確保 this.editAppointmentDemand 是一個函數
            await this.editAppointmentDemand();
          } else {
            // 處理 this.editAppointmentDemand 未定義的情況
            throw new Error('this.editAppointmentDemand is not defined or not a function.');
          }
          throw new Error('queryConsultantService.addFavoriteConsultant returned null-like value.');
        }
      } else {
        await this.editAppointmentDemand();
      }
      const editSettingInfo: UserSetting = {
@@ -484,10 +478,11 @@
      this.storageUserInfo(this.userInfo);
    }
    private editAppointmentDemand() {
      const info = {
          ...this.myRequest,
          requirement: _.map(this.myRequest.requirement,o=>o).toString(),
          requirement: this.myRequest.requirement.map(o => o).toString(),
          hopeContactTime: this.myRequest.phone && this.phoneValid ? this.getHopeContactTime() :'',
          id: this.appointmentId,
          otherRequirement: null
@@ -502,7 +497,7 @@
    private sentAppointmentDemand() {
        const data: AppointmentParams = {
          ...this.myRequest,
          requirement: _.map(this.myRequest.requirement,o=>o).toString(),
          requirement: this.myRequest.requirement.map(o => o).toString(),
          hopeContactTime: this.myRequest.phone && this.phoneValid ? this.getHopeContactTime() :'',
          agentNo: this.$route.params.agentNo
        };
@@ -543,7 +538,7 @@
    get phoneValid(): boolean {
      const rule = /^09[0-9]{8}$/;
      return this.myRequest.phone
            ? rule.test(this.myRequest.phone) && _.isEqual(this.myRequest.phone.length,10)
            ? rule.test(this.myRequest.phone) && this.myRequest.phone.length === 10
            : true;
    }
@@ -558,9 +553,9 @@
    }
    get isDisabledSubmitBtn(): boolean {
           return _.includes(this.myRequest.contactType,ContactType.PHONE)
      ? !this.isHopeContactTimeDone() || !this.emailValid
      : !this.phoneValid;
      return this.myRequest.contactType.includes(ContactType.PHONE)
        ? !this.isHopeContactTimeDone() || !this.emailValid
        : !this.phoneValid;
    }
    private isHopeContactTimeDone():boolean{
@@ -745,4 +740,3 @@
</style>
PAMapp/pages/quickFilter/index.vue
@@ -71,7 +71,6 @@
  import { Seniority } from '~/shared/models/enum/seniority';
  import { Vue, Component, namespace } from 'nuxt-property-decorator';
  import queryConsultantService from '~/shared/services/query-consultant.service';
  import _ from 'lodash';
  const localStorage = namespace('localStorage');
  const seniorityMap={
PAMapp/shared/services/httpClient.ts
@@ -1,6 +1,4 @@
import { AxiosRequestConfig, AxiosError, AxiosResponse} from 'axios';
import axios from 'axios';
import _ from 'lodash';
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import messageBoxService from './message-box.service';
@@ -86,11 +84,15 @@
      messageBoxService.showErrorMessage('', error);
      return
    }
    if (!_.includes(notRequireInterceptorErrorUrl, error.config.url)) {
    if (!notRequireInterceptorErrorUrl.includes(error.config.url)) {
      switch (error.response.status) {
        case 401:
          Promise.all([messageBoxService.showErrorMessage('登入逾時'), window.$nuxt.$store.dispatch('localStorage/actionStorageClear')]).then(() => {
            _.isEqual(window.$nuxt.$route.name, 'index') ? location.reload() : window.$nuxt.$router.push('/');
            if (window.$nuxt.$route.name === 'index') {
              location.reload();
            } else {
              window.$nuxt.$router.push('/');
            }
          });
          break;
PAMapp/shared/services/login.service.ts
@@ -1,8 +1,6 @@
import { http } from "./httpClient";
import { AxiosResponse } from 'axios';
import _ from "lodash";
import CryptoJS from "crypto-js";
import forge from "node-forge";
import { http } from "./httpClient";
// import CryptoJS from "asmcrypto-js";
import { ConsultantLoginInfo } from "../models/ConsultantLoginInfo";
@@ -73,8 +71,8 @@
    return http.get('/login/validate/get_img_code',{ responseType : 'arraybuffer' })
      .then( response => {
        const toBase64 = window.btoa(
                          _.reduce( new Uint8Array(response.data),(data,byte) =>
                            data + String.fromCharCode(byte),'')
                          Array.from(new Uint8Array(response.data)).reduce((data, byte) =>
                            data + String.fromCharCode(byte), '')
                        );
        const imgSrc = `data:image/jpeg;base64,${toBase64}`;
        return imgSrc;
PAMapp/store/localStorage.service.ts
@@ -1,5 +1,4 @@
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
import _ from 'lodash';
import { Action, Module, Mutation, VuexModule } from 'vuex-module-decorators';
export enum LocalStorageItem {
@@ -32,9 +31,9 @@
   //** 初始物件狀態 **//
  private getInitLocalStorageDto(): storageDataDto {
    const initLocalStorageDto = {} as storageDataDto;
    _.forEach( LocalStorageItem , keyName =>
      initLocalStorageDto[keyName] = this.processOfStorageGetItem(keyName)
    )
    Object.values(LocalStorageItem).forEach(keyName => {
      initLocalStorageDto[keyName] = this.processOfStorageGetItem(keyName);
    });
    return initLocalStorageDto;
  }
  //** 取得 localStorage資料 **/
@@ -42,13 +41,12 @@
    const storageData = localStorage.getItem(keyName);
    const itemType = initialValueOfStorageItemDto[keyName];
    const prepareData = storageData
                          ? _.isEqual(itemType,String)
                          ? typeof itemType === 'string'
                            ? storageData
                            : JSON.parse(storageData)
                          : null;
    return prepareData
  }
  ///////////////////////////////////////////////// Mutation
  /** 儲存進 localStorageDto **/
@@ -64,7 +62,7 @@
  //** 移除全部物件 **//
  @Mutation clearStoreData(): void {
      _.keys(this.localStorageDto)
      Object.keys(this.localStorageDto)
      .forEach(keyName => {
        localStorage.removeItem(keyName);
        this.localStorageDto[keyName]=null;
@@ -75,7 +73,7 @@
  //** 物件儲存 **//
  @Action storeData( data: storageDataDto ): void {
    _.keys(data).forEach(keyName=>{
    Object.keys(data).forEach(keyName=>{
      const newObj = {
        keyName:keyName,
        value:data[keyName]
@@ -87,7 +85,7 @@
  //** 將需要 存進 localStorage 格式 **//
  @Action localStorageSet( setItem:SetItemDto ): void {
    const itemType = initialValueOfStorageItemDto[setItem.keyName];
    const prepareData = _.isEqual(itemType,String)
    const prepareData = typeof itemType === 'string'
                          ? setItem.value
                          : JSON.stringify(setItem.value);
    localStorage.setItem(setItem.keyName,prepareData);