保誠-保戶業務員媒合平台
wayne
2022-03-10 e8241decc705f9db3e46aed7b3a3f8b3188cf820
Merge branch 'Phase3' into pollex-dev

修改10個檔案
新增1個檔案
165 ■■■■ 已變更過的檔案
PAMapp/components/Client/ClientCard.vue 4 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/Interview/InterviewMsg.vue 17 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/agentInfo/_agentNo.vue 31 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/agentInfo/edit/_agentNo.vue 2 ●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/appointment/_appointmentId/close/index.vue 8 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/appointment/_appointmentId/index.vue 6 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/store/localStorage.ts 3 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/security/provider/CustomAuthenticationProvider.java 1 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/security/provider/EServiceAuthenticationProvider.java 85 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/web/rest/EServiceResource.java 6 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/resources/config/application-uat.yml 2 ●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/Client/ClientCard.vue
@@ -77,12 +77,12 @@
                  v-else-if="client.communicateStatus === contactStatus.CONTACTED">
                  çµæ¡ˆ
                </div>
                <div
                <!-- <div
                  class="invite-msg smTxt_bold"
                  @click.stop="inviteReview"
                  v-else-if="!client.satisfactionScore">
                  ç™¼é€æ»¿æ„åº¦
                </div>
                </div> -->
                <div
                    class="date xsTxt text--black"
PAMapp/components/Interview/InterviewMsg.vue
@@ -102,11 +102,12 @@
    }
    addInterview() {
      const message = this.getMessage();
      const appointmentInformation: ToInformAppointment = {
        appointmentId: this.client.id,
        email        : this.client?.email,
        interviewDate: this.interviewTime,
        message      : this.interviewTxt,
        message,
        phone        : this.client?.phone,
      };
      appointmentService.informAppointment(appointmentInformation).then((_) => {
@@ -121,6 +122,20 @@
      this.getMyAppointmentList();
    }
    private getMessage(): string {
      const targetDate = new Date(this.interviewTime);
      const interviewTime = `${targetDate.getFullYear()}å¹´${targetDate.getMonth() + 1}月${targetDate.getDate()}日 ${targetDate.getHours()}時${targetDate.getMinutes()}分`;
      let result = '';
      if(this.loginConsultant.phoneNumber && this.loginConsultant.email) {
        result = "您好!我是保誠媒合平台的保險顧問" + this.loginConsultant.name + ",感謝您的預約!我預計會在下述的時間與您聯繫"+"\n" + interviewTime + "\n" +"以下是我的電話號碼/Email:"+"\n" + this.loginConsultant.phoneNumber + "\n" + this.loginConsultant.email + "\n"+"若此時間不方便,請與我聯繫!謝謝!"}
        else if (!this.loginConsultant.phoneNumber && this.loginConsultant.email) {
            result = "您好!我是保誠媒合平台的保險顧問" + this.loginConsultant.name + ",感謝您的預約!我預計會在下述的時間與您聯繫"+"\n" + interviewTime + "\n" +"以下是我的Email:"+"\n" + this.loginConsultant.email + "\n"+"若此時間不方便,請與我聯繫!謝謝!"
        } else {
          result = "您好!我是保誠媒合平台的保險顧問" + this.loginConsultant.name + ",感謝您的預約!我預計會在下述的時間與您聯繫"+"\n" + interviewTime + "\n" +"以下是我的電話號碼:"+"\n" + this.loginConsultant.phoneNumber + "\n"+"若此時間不方便,請與我聯繫!謝謝!"
        }
        return result;
    }
    get isBtnDisabled() :Boolean {
      const isFormValid = this.client.phone ? this.interviewTxt && this.interviewTime :this.interviewTxt
      return !isFormValid
PAMapp/pages/agentInfo/_agentNo.vue
@@ -1,5 +1,5 @@
<template>
    <div>
    <div v-if="!!agentInfo">
      <el-row
        type="flex"
        justify="center">
@@ -110,26 +110,13 @@
        </el-col>
      </el-row> -->
      <!-- <el-row
      <el-row
        type="flex"
        class="pam-paragraph">
        <el-col :span="24" class="pam-field">
          <div class="pam-field__label pam-progress__label">
            <div>
              <div class="pam-field__title">
                <i class="pam-icon icon-thumbs-up"
                  ></i>諮詢度表現 <i class="pl-5 text--primary icon-information" @click="alertFieldInfo('evaluation')"></i>
              </div>
            </div>
            <div class="xsTxt">
              {{ agentInfo.evaluation }}/50 (近一個月/累計)
            </div>
          </div>
          <div class="pam-field__content pam-field-evaluation pt-10">
            <el-progress :show-text="false" :stroke-width="15" :percentage="agentInfo.evaluation * 2"></el-progress>
          </div>
        </el-col>
      </el-row> -->
        <UiField icon="thumbs-up" label="諮詢度表現">
            {{ agentInfo.nearlyMonthAppointmentCount || 0 }} / {{ agentInfo.allAppointmentCount || 0 }} (近一個月/累計)
        </UiField>
      </el-row>
      <div class="consultant-edit-btn">
        <UiField icon="flag" label="溝通風格">
@@ -273,11 +260,13 @@
  }
  get agentName(): string {
    return `${this.agentInfo.name}(${this.agentInfo.role})`;
    if (!this.agentInfo) return '';
    return `${this.agentInfo?.name}(${this.agentInfo?.role})`;
  }
  get displayCommunicationStyleList(): string[] {
    return this.agentInfo.communicationStyle.split('、').filter((item) => item);
    if (!this.agentInfo) return [];
    return this.agentInfo?.communicationStyle.split('、').filter((item) => item);
  }
}
PAMapp/pages/agentInfo/edit/_agentNo.vue
@@ -1,5 +1,5 @@
<template>
    <div class="edit-agent-info-page">
    <div class="edit-agent-info-page" v-if="!!agentInfo">
      <el-row
        type="flex"
PAMapp/pages/appointment/_appointmentId/close/index.vue
@@ -17,7 +17,7 @@
          class="pam-paragraph" style="flex-direction: column">
          <UiField label="身分證字號/居留證字號" :labelSize="20" class="required">
            <input
              class="appointment-client-detail-close__input"
              class="appointment-client-detail-close__input mt-10"
              :class="{'is-invalid':!identityIdValid}"
              v-model="appointmentCloseInfo.policyholderIdentityId"
              placeholder="請輸入"
@@ -33,7 +33,7 @@
          class="pam-paragraph">
          <UiField label="商品代碼Plan Code" :labelSize="20" class="required">
            <input
              class="appointment-client-detail-close__input"
              class="appointment-client-detail-close__input mt-10"
              v-model="appointmentCloseInfo.planCode"
              placeholder="請輸入"
              type="text">
@@ -46,6 +46,7 @@
          <UiField label="進件時間" :labelSize="20" class="required">
            <DateTimePicker
              :defaultValue="appointmentCloseInfo.policyEntryDate"
              class="mt-10"
              @changeDateTime="appointmentCloseDate = $event"></DateTimePicker>
          </UiField>
        </el-row>
@@ -56,7 +57,7 @@
          class="pam-paragraph">
          <UiField label="未成交原因" :labelSize="20" class="required">
            <UiSelect :closeReason.sync="appointmentCloseInfo.closedReason"
              :options="appointmentFailReason"/>
              :options="appointmentFailReason" class="mt-10"/>
          </UiField>
          <input
            v-if="appointmentCloseInfo.closedReason === 'other'
@@ -73,6 +74,7 @@
        class="pam-paragraph">
        <UiField label="備註" :labelSize="20">
          <el-input
          class="mt-10"
            type="textarea"
            :rows="3"
            placeholder="請輸入"
PAMapp/pages/appointment/_appointmentId/index.vue
@@ -1,5 +1,5 @@
<template>
  <div class="appointment-client-detail-page">
  <div class="appointment-client-detail-page" v-if="!!appointmentDetail">
    <div class="date-detail">
      <div>{{ appointmentDetail.appointmentDate | formatDate }}預約</div>
      <div>{{ appointmentDetail.consultantReadTime | formatDate }}
@@ -55,9 +55,9 @@
        </div>
      </div>
      <div class=" btn-center" v-if="showWhenAppointmentHasClosed">
      <!-- <div class=" btn-center" v-if="showWhenAppointmentHasClosed">
        <el-button @click="inviteReview">發送滿意度</el-button>
      </div>
      </div> -->
      <div class="client-detail-action" v-if="showWhenAppointmentHasContacted">
        <el-button @click="closeAppointment" class="desktop-client-detail-action-btn" >結案</el-button>
PAMapp/store/localStorage.ts
@@ -110,6 +110,9 @@
    localStorage.removeItem('consultant_id');
    localStorage.removeItem('appointment');
    localStorage.removeItem('login_consultant');
    localStorage.removeItem('notContactAppointmentIdFromMsg');
    localStorage.removeItem('satisfactionIdFromMsg');
    localStorage.removeItem('appointmentIdFromMsg');
    this.id_token = localStorage.getItem('id_token');
    this.current_role = localStorage.getItem('current_role');
    this.consultant_id = localStorage.getItem('consultant_id');
pamapi/src/main/java/com/pollex/pam/security/provider/CustomAuthenticationProvider.java
@@ -1,6 +1,5 @@
package com.pollex.pam.security.provider;
import com.pollex.pam.business.security.provider.EServiceAuthenticationProvider;
import com.pollex.pam.config.ApplicationProperties;
import com.pollex.pam.business.security.token.EServiceAuthenticationToken;
import com.pollex.pam.security.token.OtpAuthenticationToken;
pamapi/src/main/java/com/pollex/pam/security/provider/EServiceAuthenticationProvider.java
¤ñ¹ï·sÀÉ®×
@@ -0,0 +1,85 @@
package com.pollex.pam.security.provider;
import com.pollex.pam.business.domain.Consultant;
import com.pollex.pam.business.enums.ConsultantDetailEnum;
import com.pollex.pam.business.repository.ConsultantRepository;
import com.pollex.pam.business.service.EServiceConnectService;
import com.pollex.pam.business.service.dto.EServiceResponse;
import com.pollex.pam.business.web.errors.ConsultantDisableException;
import com.pollex.pam.business.config.AppProperties;
import com.pollex.pam.business.security.token.EServiceAuthenticationToken;
import com.pollex.pam.business.web.errors.EServiceErrorException;
import com.pollex.pam.config.ApplicationProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.security.GeneralSecurityException;
import java.util.*;
@Component
public class EServiceAuthenticationProvider {
    private static final String E_SERVICE_LOGIN_SUCCESS_CODE = "true";
    private static final Logger log = LoggerFactory.getLogger(EServiceAuthenticationProvider.class);
    @Autowired
    ApplicationProperties applicationProperties;
    @Autowired
    ConsultantRepository consultantRepository;
    @Autowired
    EServiceConnectService eServiceConnectService;
    public Authentication authenticate(EServiceAuthenticationToken authenticationToken) throws AuthenticationException {
        String account = authenticationToken.getPrincipal();
        String credentials = authenticationToken.getCredentials();
        if(applicationProperties.isMockLogin()){
            return getConsultantTokenAndRecordLoginTime(account, credentials);
        }
        try {
            ResponseEntity<EServiceResponse> responseEntity = eServiceConnectService.loginByEService(account, credentials);
            if(HttpStatus.OK.equals(responseEntity.getStatusCode())) {
                EServiceResponse eServiceResponse = responseEntity.getBody();
                log.debug("eService response = {}", eServiceResponse);
                if(E_SERVICE_LOGIN_SUCCESS_CODE.equals(eServiceResponse.getIssuccess())){
                    return getConsultantTokenAndRecordLoginTime(account, credentials);
                }
                else {
                    throw new EServiceErrorException(eServiceResponse.getMsg());
                }
            }
            throw new RuntimeException("eService http error!, response http status code = " + responseEntity.getStatusCode());
        } catch (GeneralSecurityException e) {
            throw new RuntimeException("General Security SSL error!");
        }
    }
    private UsernamePasswordAuthenticationToken getConsultantTokenAndRecordLoginTime(String account, String credential) throws ConsultantDisableException {
        Consultant consultant = consultantRepository.findOneByAgentNo(account).orElseThrow(() -> new UsernameNotFoundException("該顧問資料並不存在於媒合平台系統中"));
        List<GrantedAuthority> grantedAuths = Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(account, credential, grantedAuths);
        Map<String, String> details = new HashMap<>();
        details.put(ConsultantDetailEnum.ID.getValue(), consultant.getId().toString());
        details.put(ConsultantDetailEnum.NAME.getValue(), consultant.getName());
        details.put(ConsultantDetailEnum.AGENT_NO.getValue(), account);
        authenticationToken.setDetails(details);
        return authenticationToken;
    }
}
pamapi/src/main/java/com/pollex/pam/web/rest/EServiceResource.java
@@ -1,6 +1,7 @@
package com.pollex.pam.web.rest;
import com.pollex.pam.business.aop.logging.audit.AuditLoggingInject;
import com.pollex.pam.business.service.ConsultantService;
import com.pollex.pam.security.jwt.JWTFilter;
import com.pollex.pam.security.jwt.TokenProvider;
import com.pollex.pam.business.security.token.EServiceAuthenticationToken;
@@ -29,6 +30,9 @@
    @Autowired
    TokenProvider tokenProvider;
    @Autowired
    ConsultantService consultantService;
    @AuditLoggingInject(type = CONSULTANT_LOGIN)
    @PostMapping("/authenticate")
    public ResponseEntity<UserJWTController.JWTToken> authorize(@RequestBody EServiceLoginVM eServiceLoginVM) {
@@ -38,7 +42,9 @@
        );
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        consultantService.updateLoginTime(eServiceLoginVM.getUsername());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        String jwt = tokenProvider.createToken(authentication, false);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer" + jwt);
pamapi/src/main/resources/config/application-uat.yml
@@ -117,7 +117,7 @@
  e-service-login-url: https://eserviceuat.pcalife.com.tw/sso/chatbotValidate
  e-service-login-func: ValidateUsrLogin
  e-service-login-sys: epos
  front-end-domain: https://vtwlifeopensysuat.pru.intranet.asia/pam
  front-end-domain: https://onlineuat.pcalife.com.tw/pam
  sms:
    send-notify-msg: true
    url: https://vtwlifeopensysuat.pru.intranet.asia/MesgQueueMgmnt/rest/smsSendMsgResource