From 338b53c9ed0571319a397873b409f45cb8e4202f Mon Sep 17 00:00:00 2001
From: 劉鈞霖 <benson@gmail.com>
Date: 星期五, 19 十一月 2021 15:24:05 +0800
Subject: [PATCH] [ Update ] : 1.nav bar 下拉選單UI 微調,將localStorage存入store 監聽角色來去改變下拉選單對應項目  2. 顧問登入layout 更改 3.layout page 新增淡入特效 ,

---
 PAMapp/components/BackActionBar.vue                 |   16 +
 PAMapp/components/loading.vue                       |   75 ++++++-----
 PAMapp/pages/consultantLogin/index.vue              |   13 +
 PAMapp/pages/login/index.vue                        |    9 +
 PAMapp/components/NavBar.vue                        |  155 +++++++++++++++----------
 PAMapp/assets/ts/api/share.ts                       |   16 +-
 PAMapp/assets/scss/vendors/elementUI/_dropdown.scss |   27 +++-
 PAMapp/store/localStorage.ts                        |   31 +++++
 PAMapp/assets/pam-animation.css                     |    9 +
 PAMapp/nuxt.config.js                               |    5 
 10 files changed, 233 insertions(+), 123 deletions(-)

diff --git a/PAMapp/assets/pam-animation.css b/PAMapp/assets/pam-animation.css
new file mode 100644
index 0000000..802370d
--- /dev/null
+++ b/PAMapp/assets/pam-animation.css
@@ -0,0 +1,9 @@
+.pam-fade-in-enter-active{
+  transition: 0.5s ease-in;
+}
+.pam-fade-in-enter{
+  opacity: 0;
+}
+.pam-fade-in-enter-to{
+  opacity: 1;
+}
\ No newline at end of file
diff --git a/PAMapp/assets/scss/vendors/elementUI/_dropdown.scss b/PAMapp/assets/scss/vendors/elementUI/_dropdown.scss
index 187f861..1f5f373 100644
--- a/PAMapp/assets/scss/vendors/elementUI/_dropdown.scss
+++ b/PAMapp/assets/scss/vendors/elementUI/_dropdown.scss
@@ -1,21 +1,32 @@
-.pam-header__dropdown {
+.el-dropdown-menu.pam-header__dropdown {
   top:39px !important;
   border-radius: 10px;
   box-shadow: 0 3px 6px $LIGHT_GREY;
   padding: 5px 26px 5px 20px;
-  .pam-header__dropdown-item {
+  .el-dropdown-menu__item{
     width: max-content;
     margin:15px 0px;
     cursor: pointer;
+    color: $PRIMARY_BLACK;
+    background-color: $PRIMARY_WHITE;
+    &.pam-header__dropdown-divider {
+      padding-top: 16px;
+      width: calc(100% + 6px);
+      border-top: 1px solid #CCCCCC;
+    }
     &:first-child{
       padding-top: 0px;
     }
+    &:focus {
+      color: $PRIMARY_BLACK;
+      background-color: $PRIMARY_WHITE;
+    }
+    &:not(.is-disabled):hover{
+      color: $PRIMARY_BLACK;
+      background-color: $PRIMARY_WHITE;
+    }
   }
-  .pam-header__dropdown-divider {
-    padding-top: 16px;
-    width: calc(100% + 6px);
-    border-top: 1px solid #CCCCCC;
-  }
+  
   .popper__arrow {
     display: none;
     &::after {
@@ -24,7 +35,7 @@
   }
 }
 @include desktop{
-  .pam-header__dropdown {
+  .el-dropdown-menu.pam-header__dropdown {
     top: 78px !important;
   }
 }
\ No newline at end of file
diff --git a/PAMapp/assets/ts/api/share.ts b/PAMapp/assets/ts/api/share.ts
index 7bb167f..12fa904 100644
--- a/PAMapp/assets/ts/api/share.ts
+++ b/PAMapp/assets/ts/api/share.ts
@@ -5,25 +5,27 @@
 })
 
 service.interceptors.request.use(function (config: AxiosRequestConfig) {
-    loadingStart;
+  loadingStart();
     return config;
 }, function (error: AxiosError) {
-    loadingFinish;
+  loadingFinish();
     return Promise.reject(error);
 });
 
 service.interceptors.response.use(function (response: AxiosResponse) {
-    loadingFinish;
+  loadingFinish();
     return response;
 }, function (error: AxiosError) {
-    loadingFinish;
+  loadingFinish();
     return Promise.reject(error);
 });
 
-function loadingStart():void{
+function loadingStart(): void {
+  setTimeout(() => {
     window.$nuxt.$loading.start();
+  });
 }
 
-function loadingFinish():void{
+function loadingFinish(): void {
     window.$nuxt.$loading.finish();
-}
\ No newline at end of file
+}
diff --git a/PAMapp/components/BackActionBar.vue b/PAMapp/components/BackActionBar.vue
index dd01052..428fab1 100644
--- a/PAMapp/components/BackActionBar.vue
+++ b/PAMapp/components/BackActionBar.vue
@@ -1,17 +1,20 @@
 <template>
     <nav class="pam-back-action-bar fix-chrome-click--issue">
-        <a @click="$router.push('/')">
+        <a @click="pushRouterByLoginRole">
           <i class="icon-left "></i>{{ label }}
         </a>
     </nav>
 </template>
 
 <script lang="ts">
-import { Vue, Component } from 'vue-property-decorator';
-
+import { namespace } from 'nuxt-property-decorator';
+import { Vue, Component,} from 'vue-property-decorator';
+import * as _ from 'lodash';
+import { Role } from './NavBar.vue';
+const localStorage = namespace('localStorage');
 @Component
 export default class UiCarousel extends Vue {
-
+  @localStorage.Getter currentRole!:string;
   get label(): string {
     if (this.$route.name) {
       const routeName = this.$route.name.split('-')[0];
@@ -43,7 +46,10 @@
       return '�����';
     }
   }
-
+  pushRouterByLoginRole():void{
+    const link = _.isEqual(this.currentRole,Role.ADMIN)? '/myAppointmentList/appointmentList':'/';
+    this.$router.push(link); 
+  }
 }
 </script>
 
diff --git a/PAMapp/components/NavBar.vue b/PAMapp/components/NavBar.vue
index d0a7d46..4dc5d23 100644
--- a/PAMapp/components/NavBar.vue
+++ b/PAMapp/components/NavBar.vue
@@ -1,93 +1,104 @@
 <template>
   <header class="pam-header">
-    <div class="pam-header__logo" @click="$router.push('/')"></div>
+    <div class="pam-header__logo"
+      @click="pushRouterByLoginRole"></div>
     <div class="pam-header__title">
       <div class="pam-header__title--main">���兢蝳��蜓</div>
       <div class="pam-header__title--sub">�����兢蝳�風��</div>
     </div>
-    <div class="pam-header__action-bar" style="position:relaitive">
+    <div class="pam-header__action-bar">
       <i class="icon-bell text--dark-blue cursor--pointer fix-chrome-click--issue"
         @click="$router.push('/notification')"></i>
-      <el-dropdown>
-        <i class="icon-avatar text--dark-blue cursor--pointer fix-chrome-click--issue"></i>
-        <el-dropdown-menu slot="dropdown"
-          class="pam-header__dropdown">
-          <template v-for="(navbarItem,index) in navBarList">
-            <li class="pam-header__dropdown-item fix-chrome-click--issue "
-              :class="{'pam-header__dropdown-divider':navbarItem.title === '憿批��'}"
-              v-if="navbarItem.needRole.includes(loginRole)"
-              :key="index"
-              @click="linkTo(navbarItem.link)">
-              {{navbarItem.title}}
-            </li>
-          </template>
-        </el-dropdown-menu>
-      </el-dropdown>
+        <el-dropdown :class="{'is-open':isOpenDropdown}" 
+          ref="dropdown"
+          trigger="click"
+          @command="routerNavigateTo">
+          <i class="icon-avatar text--dark-blue cursor--pointer fix-chrome-click--issue" @click="isOpenDropdown =!isOpenDropdown" ></i>
+          <el-dropdown-menu
+            class="pam-header__dropdown">
+            <template v-for="(item,index) in navBarList">
+              <el-dropdown-item :key="index"
+                v-if="item.authorityOfRoleList.includes(loginRole)"
+                class="fix-chrome-click--issue"
+                :class="{'pam-header__dropdown-divider':item.title === '憿批��'}"
+                :command="item.routeUrl">
+                {{item.title}}
+              </el-dropdown-item>
+            </template>
+          </el-dropdown-menu>
+        </el-dropdown>
     </div>
   </header>
 </template>
 
 <script lang="ts">
   import { Vue, Component } from 'vue-property-decorator';
+  import { namespace } from 'nuxt-property-decorator';
   import * as _ from 'lodash';
+  const localStorage = namespace('localStorage');
   @Component
   export default class NavBar extends Vue {
+    @localStorage.Mutation storageClear!: () => void;
+    @localStorage.Getter idToken!: string | null;
+    @localStorage.Getter currentRole!: string | null;
+
     navBarList = [{
-        needRole: [Role.NOT_LOGIN],
-        link: '/login',
+        authorityOfRoleList: [Role.NOT_LOGIN],
+        routeUrl: '/login',
         title: '��',
       },
       {
-        needRole: [Role.USER],
-        link: '/accountSetting',
+        authorityOfRoleList: [Role.USER],
+        routeUrl: '/accountSetting',
         title: '�犖撣唾�身摰�',
       },
       {
-        needRole: [Role.ADMIN],
-        link: '/notFinish',
+        authorityOfRoleList: [Role.ADMIN],
+        routeUrl: '/notFinish',
         title: '���董�����',
       },
       {
-        needRole: [Role.USER, Role.ADMIN],
-        link: '/record/contactRecord',
+        authorityOfRoleList: [Role.USER, Role.ADMIN],
+        routeUrl: '/record/contactRecord',
         title: '�������',
       },
       {
-        needRole: [Role.NOT_LOGIN, Role.USER],
-        link: '/myConsultantList/consultantList',
+        authorityOfRoleList: [Role.NOT_LOGIN, Role.USER],
+        routeUrl: '/myConsultantList/consultantList',
         title: '���“���',
       },
       {
-        needRole: [Role.USER, Role.ADMIN],
-        link: '',
+        authorityOfRoleList: [Role.USER, Role.ADMIN],
+        routeUrl: '',
         title: '��',
       },
       {
-        needRole: [Role.NOT_LOGIN],
-        link: '/consultantLogin',
+        authorityOfRoleList: [Role.NOT_LOGIN],
+        routeUrl: '/consultantLogin',
         title: '憿批��',
       },
     ];
-    get idToken(): string | null {
-      return localStorage.getItem('id_token');
-    }
-    get roleOfState(): string | null {
-      return localStorage.getItem('roleOfState');
-    }
+    login_role = Role.NOT_LOGIN;
+    isOpenDropdown = false;
+
     get loginRole(): string {
-      return this.roleOfState && this.idToken ? this.roleOfState : Role.NOT_LOGIN;
+      return this.idToken && this.currentRole ? this.currentRole : Role.NOT_LOGIN;
     }
 
-    linkTo(routerLink: string): void {
-      _.isEqual(routerLink, '') ? this.fakeLogout() : this.$router.push(routerLink);
+    routerNavigateTo(url: string): void {
+      this.isOpenDropdown = !this.isOpenDropdown;
+      (this.$refs.dropdown as any).hide();
+      _.isEqual(url, '') ? this.fakeLogout() : this.$router.push(url);
     }
 
-
+    pushRouterByLoginRole(): void {
+      const link = _.isEqual(this.currentRole, Role.ADMIN) ? '/myAppointmentList/appointmentList' : '/';
+      this.$router.push(link);
+    }
     // TODO: ��TP隤����� ���蝙�
     fakeLogout(): void {
-      localStorage.clear();
-      // this.$router.go(0);
-      window.location.href = '/'
+      this.storageClear();
+      _.isEqual(this.$route.name, 'index') ? location.reload() : this.$router.push('/');
     }
   }
   export enum Role {
@@ -114,26 +125,30 @@
       width: 115px;
       margin: 0 10px;
       background-image: url('~/assets/images/taiwan-logo.png');
-      background-repeat:no-repeat;
+      background-repeat: no-repeat;
       background-size: contain;
       background-position: center;
     }
+
     .pam-header__title {
       flex: 1;
       flex-basis: 160px;
-      border-left:1px #CCCCCC solid;
-      padding-left:10px;
-      .pam-header__title--main {
-        font-size: 16px;
-        font-weight: bold;
-        color: $PRUDENTIAL_GREY;
-        letter-spacing:0.8px;
-        @media screen and (max-width: 352px) {
-          font-size: 12px;
-        }
+      border-left: 1px #CCCCCC solid;
+      padding-left: 10px;
+
+    .pam-header__title--main {
+      font-size: 16px;
+      font-weight: bold;
+      color: $PRUDENTIAL_GREY;
+      letter-spacing: 0.8px;
+
+      @media screen and (max-width: 352px) {
+        font-size: 12px;
       }
-      .pam-header__title--sub {
-        padding-top: 2px;
+    }
+
+    .pam-header__title--sub {
+      padding-top: 2px;
         font-size: 12px;
         transform: scale(0.9);
         -webkit-transform-origin-x: 0;
@@ -145,13 +160,17 @@
 
 
     .pam-header__action-bar {
+      position: relative;
       display: flex;
+      height: 100%;
       font-size: 24px;
       font-weight: bold;
+      align-items: center;
       justify-content: space-around;
 
       i {
         padding: 0px 15px;
+
         @media screen and (max-width: 352px) {
           padding: 0px 10px;
         }
@@ -159,29 +178,45 @@
     }
   }
 
+  .el-dropdown{
+    height: 100%;
+    display: flex;
+    align-items: center;
+    &.is-open {
+        background-color: $PEACH;
+      i {
+        color: $PRIMARY_WHITE;
+      }
+    }
+  } 
+
   @include desktop {
     .pam-header {
       height: $DESKTOP_NAV_BAR;
+
       .pam-header__logo {
         width: 180px;
         height: 100%;
         margin: 0;
         background-image: url('~/assets/images/logo.png');
         background-size: cover;
-        background-repeat:no-repeat;
+        background-repeat: no-repeat;
         background-position: center;
       }
+
       .pam-header__title {
         display: flex;
         justify-content: start;
         align-items: center;
         border: none;
         padding-left: 30px;
-        .pam-header__title--main{
+
+        .pam-header__title--main {
           font-size: 30px;
           letter-spacing: 1.5px;
         }
-        .pam-header__title--sub{
+
+        .pam-header__title--sub {
           font-size: 20px;
           letter-spacing: 2px;
           transform: none;
diff --git a/PAMapp/components/loading.vue b/PAMapp/components/loading.vue
index 228d6c2..f4099e8 100644
--- a/PAMapp/components/loading.vue
+++ b/PAMapp/components/loading.vue
@@ -1,42 +1,47 @@
 <template>
-    <div class="pam-loading" v-if="isLoading">
-        <lottie
-        :options="defaultOptions"
-        :width="250"
-        :height="250"
-        :loop="true"/>
-    </div>
+  <div class="pam-loading"
+    v-if="isLoading">
+    <lottie :options="defaultOptions"
+      :width="250"
+      :height="250"
+      :loop="true" />
+  </div>
 </template>
 
 <script lang="ts">
-    import { Component, Vue } from 'nuxt-property-decorator';
-    import Lottie from 'vue-lottie/src/lottie.vue';
-    @Component({
-        components:{
-            'lottie':Lottie
-        }
-    })
-    export default class Loading extends Vue {
-        isLoading=false;
-        defaultOptions={ animationData: require('@/assets/lottie/loading.json')};
-        start():void{
-            this.isLoading = true;
-        }
-        finish():void{
-            this.isLoading = false;
-        }
+  import { Component, Vue } from 'nuxt-property-decorator';
+  import Lottie from 'vue-lottie/src/lottie.vue';
+  @Component({
+    components: {
+      'lottie': Lottie
     }
+  })
+  export default class Loading extends Vue {
+    isLoading = false;
+    defaultOptions = {
+      animationData: require('@/assets/lottie/loading.json')
+    };
+    start(): void {
+      this.isLoading = true;
+    }
+    finish(): void {
+      this.isLoading = false;
+    }
+  }
+
 </script>
 
-<style lang="scss" scoped>
-    .pam-loading{
-        position: absolute;
-        background-color: rgba(#222222,0.5);
-        width: 100%;
-        height: 100%;
-        z-index: 99;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-    }
-</style>
\ No newline at end of file
+<style lang="scss"
+  scoped>
+  .pam-loading {
+    position: absolute;
+    background-color: rgba(#222222, 0.5);
+    width: 100%;
+    height: 100%;
+    z-index: 99;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+
+</style>
diff --git a/PAMapp/nuxt.config.js b/PAMapp/nuxt.config.js
index d204e9f..2ae6c63 100644
--- a/PAMapp/nuxt.config.js
+++ b/PAMapp/nuxt.config.js
@@ -21,15 +21,16 @@
       { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
     ]
   },
-
+  layoutTransition:'pam-fade-in',
+  pageTransition:'pam-fade-in',
   // Global CSS: https://go.nuxtjs.dev/config-css
   css: [
     'element-ui/lib/theme-chalk/index.css',
     'swiper/css/swiper.css',
     'vue-scroll-picker/dist/style.css',
     '~/assets/scss/main.scss',
+    '~/assets/pam-animation.css'
   ],
-
   // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
   plugins: [
     '~/plugins/element-ui.js',
diff --git a/PAMapp/pages/consultantLogin/index.vue b/PAMapp/pages/consultantLogin/index.vue
index bda41c9..dc5c7b8 100644
--- a/PAMapp/pages/consultantLogin/index.vue
+++ b/PAMapp/pages/consultantLogin/index.vue
@@ -63,13 +63,19 @@
 </template>
 
 <script lang="ts">
+  import { namespace } from 'nuxt-property-decorator';
   import { Vue, Component} from 'vue-property-decorator';
   import { getForgotPasswordLink , getVerificationCodeImg , login } from '~/assets/ts/api/consultant';
   import { Role } from '../../components/NavBar.vue';
+
+  const localStorage = namespace('localStorage');
   @Component({
-    layout: 'default'
+    layout: 'home'
   })
   export default class ConsultantLogin extends Vue {
+    @localStorage.Mutation storageIdToken!: (token:string) => void;
+    @localStorage.Mutation storageRole!: (role:string) => void;
+
     isRemember = false;
     isShowPassword = false;
     consultantDto = {
@@ -113,10 +119,9 @@
             username: 'admin',
             password: 'admin'
         }
-        console.log('user',user);
         login(user).then((res) => {
-            localStorage.setItem('id_token', res.data.id_token);
-            localStorage.setItem('roleOfState',Role.ADMIN)
+            this.storageIdToken(res.data.id_token);
+            this.storageRole(Role.ADMIN);
             this.$router.push('/myAppointmentList/appointmentList');
         })
     }
diff --git a/PAMapp/pages/login/index.vue b/PAMapp/pages/login/index.vue
index 6ee1a95..fca090e 100644
--- a/PAMapp/pages/login/index.vue
+++ b/PAMapp/pages/login/index.vue
@@ -220,11 +220,16 @@
 </template>
 
 <script lang="ts">
+import { namespace } from 'nuxt-property-decorator';
 import { Vue, Component } from 'vue-property-decorator';
 import { login } from '~/assets/ts/api/consultant';
 import { Role } from '../../components/NavBar.vue';
+const localStorage = namespace('localStorage');
 @Component
 export default class Login extends Vue {
+  @localStorage.Mutation storageIdToken!: (token:string) => void;
+  @localStorage.Mutation storageRole!: (role:string) => void;
+
   connectDevice: 'MOBILE' | 'EMAIL' = 'MOBILE';
 
   phoneNumber = '';
@@ -268,8 +273,8 @@
             password: 'user',
         }
         login(user).then((res) => {
-            localStorage.setItem('id_token', res.data.id_token);
-            localStorage.setItem('roleOfState',Role.USER);
+            this.storageIdToken(res.data.id_token);
+            this.storageRole(Role.USER);
             this.$router.go(-1);
         })
   };
diff --git a/PAMapp/store/localStorage.ts b/PAMapp/store/localStorage.ts
new file mode 100644
index 0000000..a9e8ca3
--- /dev/null
+++ b/PAMapp/store/localStorage.ts
@@ -0,0 +1,31 @@
+import { Module, Mutation, VuexModule } from 'vuex-module-decorators';
+
+@Module
+export default class LocalStorage extends VuexModule {
+  id_token:string|null = null;
+  role_State:string|null = null;
+
+  get idToken(): string|null {
+    return this.id_token;
+  };
+
+  get currentRole(): string|null {
+    return this.role_State;
+  };
+
+  @Mutation storageIdToken(token: string): void {
+    localStorage.setItem('id_token', token);
+    this.id_token = localStorage.getItem('id_token') ;
+  };
+
+  @Mutation storageRole(role:string): void {
+    localStorage.setItem('current_role', role);
+    this.role_State = localStorage.getItem('current_role');
+  };
+
+  @Mutation storageClear(): void {
+    localStorage.clear();
+    this.id_token = localStorage.getItem('id_token');
+    this.role_State = localStorage.getItem('roleOfState');
+  }
+}

--
Gitblit v1.8.0