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