保誠-保戶業務員媒合平台
fixed#132096: 查看完聯絡清單(或登出後再登入),顧問清單的黃點並不會消失
修改5個檔案
新增2個檔案
189 ■■■■ 已變更過的檔案
PAMapp/assets/ts/api/appointment.ts 16 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/api/consultant.ts 51 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/models/consultant.model.ts 2 ●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/services/httpClient.ts 67 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/services/my-consultant.service.ts 23 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/Consultant/ConsultantCard.vue 15 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/store/index.ts 15 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/api/appointment.ts
@@ -1,5 +1,5 @@
import { service } from '~/assets/ts/api/share';
import { AxiosResponse } from 'axios';
import { http } from '~/assets/ts/services/httpClient';
import { AppointmentLog } from '../models/appointment.model';
// å–得所有預約清單
@@ -7,7 +7,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.get('/consultant/getMyAppointment', {headers}).then(res => res.data);
    return http.get('/consultant/getMyAppointment', {headers}).then(res => res.data);
}
// æ¨™è¨˜ç‚ºå·²è¯çµ¡
@@ -16,7 +16,7 @@
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    // TODO: è·Ÿå¾Œç«¯ç¢ºèªï¼Œé€™è£¡çš„ API ä¸æ‡‰è©²å‚³å›ž void, è€Œæ˜¯æ‡‰è©²æ˜¯æ›´æ–°å¾Œçš„資料 - Ben 2021/11/16
    return service.post('/appointment/markAsContacted/'+appointmentId, undefined, {headers})
    return http.post('/appointment/markAsContacted/'+appointmentId, undefined, {headers})
            .then(res => res.data)
}
@@ -24,7 +24,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.get('/satisfaction/getMySatisfaction', { headers }).then(res => res.data);
    return http.get('/satisfaction/getMySatisfaction', { headers }).then(res => res.data);
}
@@ -33,7 +33,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.post('/consultant/record/allAppointmentsView', undefined, {headers})
    return http.post('/consultant/record/allAppointmentsView', undefined, {headers})
}
// è®€å–預約單時觸發
@@ -41,7 +41,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.post('/appointment/recordRead/' + appointmentId, undefined, {headers})
    return http.post('/appointment/recordRead/' + appointmentId, undefined, {headers})
}
@@ -65,4 +65,4 @@
    consultantReadTime: Date,
    contactTime      : Date,
    satisfactionScore: number
}
}
PAMapp/assets/ts/api/consultant.ts
@@ -1,54 +1,45 @@
import { service } from '~/assets/ts/api/share';
import { AxiosResponse } from 'axios';
import { AppointmentDetail } from '../models/AppointmentDetail';
import { ConsultantLoginInfo } from '../models/ConsultantLoginInfo';
import _ from 'lodash';
import { UserSetting } from '../models/account.model';
import { Consultant } from '~/assets/ts/models/consultant.model';
import { http } from '../services/httpClient';
// é¡§å®¢ç™»å…¥(TODO: OTP認證開發前 æš«æ™‚使用)
export function login(user: any) {
    return service.post('/authenticate', user)
    return http.post('/authenticate', user)
}
// é¡§å®¢ç™»å…¥-發送OTP
export function sendOtp(loginInfo: LoginRequest) {
    return service.post<OtpInfo>('/otp/sendOtp', loginInfo).then(res => res.data)
    return http.post<OtpInfo>('/otp/sendOtp', loginInfo).then(res => res.data)
}
// é¡§å®¢ç™»å…¥-驗證otp並登入
export function loginVerify(loginVerify: LoginVerify) {
    return service.post('/otp/verify', loginVerify)
    return http.post('/otp/verify', loginVerify)
}
// é¡§å®¢è¨»å†Š
export function register(registerInfo: RegisterInfo) {
    return service.post('/otp/register', registerInfo)
    return http.post('/otp/register', registerInfo)
}
// æŽ¨è–¦ä¿éšªé¡§å•
export function recommend() {
    return service.get<Consultant[]>('/consultant/recommend')
            .then(res => res.data);
}
// æˆ‘的顧問清單
export function getFavoriteConsultant() {
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.get<Consultant[]>('/consultant/favorite', {headers})
    return http.get<Consultant[]>('/consultant/recommend')
            .then(res => res.data);
}
// å¿«é€Ÿç¯©é¸
export function fastQuery(data: FastQueryParams) {
    return service.post('/consultant/fastQuery', data)
    return http.post('/consultant/fastQuery', data)
}
// åš´é¸é…å°
export function strictQuery(data:StrictQueryParams):Promise<AxiosResponse<AgentOfStrictQuery[]>>{
    return service.post('/consultant/strictQuery', data)
    return http.post('/consultant/strictQuery', data)
}
// åŠ å…¥é¡§å•
@@ -56,7 +47,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.post('/consultant/favorite', {agentNoList}, {headers})
    return http.post('/consultant/favorite', {agentNoList}, {headers})
}
// é ç´„前詢問
@@ -64,12 +55,12 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.post('/appointment/customer/create', data, {headers})
    return http.post('/appointment/customer/create', data, {headers})
}
//顧問詳細資訊
export function getConsultantDetail(agentNo:string){
    return service.get('/consultant/detail', {params:{agentNo:agentNo}})
    return http.get('/consultant/detail', {params:{agentNo:agentNo}})
}
// ç§»é™¤é¡§å•
@@ -77,12 +68,12 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.delete('/consultant/favorite/'+agentId, {headers})
    return http.delete('/consultant/favorite/'+agentId, {headers})
}
// å–得驗證碼圖片
export function getImgOfVerification():Promise<string>{
  return service.get('/login/validate/get_img_code',{ responseType : 'arraybuffer' })
  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),''));
      const imgSrc = `data:image/jpeg;base64,${toBase64}`;
@@ -92,12 +83,12 @@
// é©—證碼 é©—è­‰
export function getVerificationStatus(imgCode:string):Promise<AxiosResponse<boolean>>{
  return service.get('/login/validate/verify_img_code/'+imgCode);
  return http.get('/login/validate/verify_img_code/'+imgCode);
}
// é¡§å•ç™»å…¥
export function logInToConsultant(consultantDto:ConsultantLoginInfo):Promise<AxiosResponse<RequestOfLoginSuccess>>{
    return service.post('/eService/authenticate',consultantDto);
    return http.post('/eService/authenticate',consultantDto);
}
// å–得預約單細節
@@ -105,7 +96,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.get('/appointment/getDetail/'+apointmentId, {headers})
    return http.get('/appointment/getDetail/'+apointmentId, {headers})
}
//取得使用者帳號資訊
@@ -113,7 +104,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.get<UserSetting>('/customer/info', {headers}).then(res => res.data);
    return http.get<UserSetting>('/customer/info', {headers}).then(res => res.data);
}
//更新使用者帳號資訊
@@ -121,7 +112,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.put('/customer/info', params ,{headers}).then(res => res.data);
    return http.put('/customer/info', params ,{headers}).then(res => res.data);
}
//客戶進行滿意度評分
@@ -130,7 +121,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.post('/satisfaction/create', data ,{headers});
    return http.post('/satisfaction/create', data ,{headers});
}
// å–消預約
@@ -138,7 +129,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.delete('/appointment/'+appointment ,{headers});
    return http.delete('/appointment/'+appointment ,{headers});
}
// ç·¨è¼¯é ç´„
@@ -146,7 +137,7 @@
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.put('/appointment', editAppointmentParams, {headers});
    return http.put('/appointment', editAppointmentParams, {headers});
}
export interface FastQueryParams {
PAMapp/assets/ts/models/consultant.model.ts
@@ -7,10 +7,10 @@
    contactStatus?     : string;
    createTime         : Date | string;
    updateTime         : Date | string;
    customerViewTime?  : Date | string;
    role               : string;
    seniority          : string,
    appointments?      : Appointment[];
    new                : boolean,
}
export interface Appointment {
PAMapp/assets/ts/services/httpClient.ts
¤ñ¹ï·sÀÉ®×
@@ -0,0 +1,67 @@
import { AxiosRequestConfig, AxiosError, AxiosResponse} from 'axios';
import ErrorMessageBox from '../errorService';
import axios from 'axios';
import _ from 'lodash';
const notRequireInterceptorErrorUrl = [
  '/otp/verify',
  '/eService/authenticate',
  '/login/validate/get_img_code',
  '/login/validate/verify_img_code',
];
export const http = axios.create({
  baseURL: process.env.BASE_URL,
  withCredentials: true
});
http.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    loadingStart();
    addHttpHeader(config);
    return config;
  }
);
http.interceptors.response.use(
  (response: AxiosResponse) => {
    loadingFinish();
    return response;
  },
  (error: AxiosError) => {
    loadingFinish();
    showErrorMessageBox(error)
    return Promise.reject(error);
  }
);
function addHttpHeader(config: AxiosRequestConfig): void {
  config.headers = {
    Authorization: 'Bearer ' + localStorage.getItem('id_token')
  }
}
function loadingStart(): void {
  window.$nuxt.$loading.start();
};
function loadingFinish(): void {
  window.$nuxt.$loading.finish();
};
function showErrorMessageBox(error: any): void {
  // console.log('error', error, error.response);
  if (!_.includes(notRequireInterceptorErrorUrl, error.config.url)) {
    switch (error.response.status) {
      case 401:
        Promise.all([ErrorMessageBox('登入逾時'), window.$nuxt.$store.dispatch('localStorage/actionStorageClear')]).then(() => {
          _.isEqual(window.$nuxt.$route.name, 'index') ? location.reload() : window.$nuxt.$router.push('/');
        });
        break;
      default:
        ErrorMessageBox('', error);
        break;
    }
  }
};
PAMapp/assets/ts/services/my-consultant.service.ts
¤ñ¹ï·sÀÉ®×
@@ -0,0 +1,23 @@
import { http } from "./httpClient";
import { Consultant } from "../models/consultant.model";
class MyConsultantService {
  async getFavoriteConsultantList(): Promise<Consultant[]> {
    return http.get<Consultant[]>('/consultant/favorite').then((res) => {
      const hasNewConsultant = res.data.find((consultant) => !consultant.customerViewTime);
      if (hasNewConsultant) {
        this.viewMyConsultantList();
      };
      return res.data;
    });
  }
  private viewMyConsultantList(): void {
    http.post('/consultant/favorite/view');
  }
}
export default new MyConsultantService();
PAMapp/components/Consultant/ConsultantCard.vue
@@ -1,8 +1,8 @@
<template>
    <div>
        <el-row type="flex" class="rowStyle">
        <el-row type="flex" class="rowStyle" :class="{'new': !agentInfo.customerViewTime }">
            <el-col :xs="2" :sm="1" :class="{'state': agentInfo.new}"></el-col>
            <el-col :xs="2" :sm="1"></el-col>
            <el-col :xs="22" :sm="23">
                <el-row type="flex">
                    <el-col class="flex_column" :xs="5" :sm="3">
@@ -11,7 +11,7 @@
                            :fileName="avatarFileName"
                            @click.native="showAgentDetail(agentInfo.agentNo)"
                        ></UiAvatar>
                            <!-- TODO:隱藏滿意度 -->
                        <!-- TODO:隱藏滿意度 -->
                        <div v-if="!hideReviews">
                            <i class="icon-star pam-icon icon--yellow satisfaction"  v-if="!(latestContactedAppointment && !latestContactedAppointment.satisfactionScore)"></i>
                            <span v-if="agentInfo.contactStatus === 'contacted' && latestContactedAppointment && latestContactedAppointment.satisfactionScore">
@@ -322,13 +322,10 @@
        margin-bottom: 10px;
        display: flex;
        justify-content: space-between;
        border-left: 4px solid transparent;
        .state {
            width: 10px;
            height: 10px;
            border-radius: 50px;
            background-color: $YELLOW;
            margin: auto 0;
        &.new {
            border-color: $YELLOW;
        }
        .satisfaction {
PAMapp/store/index.ts
@@ -1,11 +1,12 @@
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators'
import { ClientInfo, getMyAppointmentList, getMyReviewLog } from '~/assets/ts/api/appointment';
import { recommend, AgentOfStrictQuery, getFavoriteConsultant, addFavoriteConsultant, deleteConsultant, strictQuery } from '~/assets/ts/api/consultant';
import { recommend, AgentOfStrictQuery, addFavoriteConsultant, deleteConsultant, strictQuery } from '~/assets/ts/api/consultant';
import { getFavoriteFromStorage, setFavoriteToStorage } from '~/assets/ts/storageConsultant';
import  myConsultantService from '~/assets/ts/services/my-consultant.service';
import { Consultant } from '~/assets/ts/models/consultant.model';
import { AppointmentLog } from '~/assets/ts/models/appointment.model';
import { getFavoriteFromStorage, setFavoriteToStorage } from '~/assets/ts/storageConsultant';
import { Role } from '~/assets/ts/models/enum/Role';
@Module
export default class Store extends VuexModule {
    recommendList: Consultant[] = [];
@@ -63,8 +64,8 @@
            })
        }
        getFavoriteConsultant().then(data => {
            this.context.commit('updateConsultantList', data)
        myConsultantService.getFavoriteConsultantList().then(data => {
            this.context.commit('updateConsultantList', data);
        })
    }
@@ -144,4 +145,4 @@
        });
    }
}
}