PAMapp/assets/pam-animation.css | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/assets/scss/vendors/elementUI/_dropdown.scss | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/assets/ts/api/share.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/BackActionBar.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/NavBar.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/loading.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/nuxt.config.js | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/consultantLogin/index.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/login/index.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/store/localStorage.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 |
PAMapp/assets/pam-animation.css
¤ñ¹ï·sÀÉ®× @@ -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; } 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; &:first-child{ padding-top: 0px; } } .pam-header__dropdown-divider { 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; } } .popper__arrow { display: none; &::after { @@ -24,7 +35,7 @@ } } @include desktop{ .pam-header__dropdown { .el-dropdown-menu.pam-header__dropdown { top: 78px !important; } } PAMapp/assets/ts/api/share.ts
@@ -5,23 +5,25 @@ }) 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{ setTimeout(() => { window.$nuxt.$loading.start(); }); } function loadingFinish():void{ 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> PAMapp/components/NavBar.vue
@@ -1,25 +1,29 @@ <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" <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="(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 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> @@ -29,65 +33,72 @@ <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: å OTPèªèéç¼å æ«æä½¿ç¨ 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 { @@ -118,20 +129,24 @@ 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; } } .pam-header__title--sub { padding-top: 2px; font-size: 12px; @@ -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,9 +178,22 @@ } } .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%; @@ -171,16 +203,19 @@ 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{ font-size: 30px; letter-spacing: 1.5px; } .pam-header__title--sub{ font-size: 20px; letter-spacing: 2px; PAMapp/components/loading.vue
@@ -1,7 +1,7 @@ <template> <div class="pam-loading" v-if="isLoading"> <lottie :options="defaultOptions" <div class="pam-loading" v-if="isLoading"> <lottie :options="defaultOptions" :width="250" :height="250" :loop="true"/> @@ -18,7 +18,9 @@ }) export default class Loading extends Vue { isLoading=false; defaultOptions={ animationData: require('@/assets/lottie/loading.json')}; defaultOptions = { animationData: require('@/assets/lottie/loading.json') }; start():void{ this.isLoading = true; } @@ -26,9 +28,11 @@ this.isLoading = false; } } </script> <style lang="scss" scoped> <style lang="scss" scoped> .pam-loading{ position: absolute; background-color: rgba(#222222,0.5); @@ -39,4 +43,5 @@ justify-content: center; align-items: center; } </style> 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', 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'); }) } 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); }) }; PAMapp/store/localStorage.ts
¤ñ¹ï·sÀÉ®× @@ -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'); } }