21.03.21 lamplight서비스 프로젝트(요청수정페이지,회원정보페이지,회원수정페이지까지 DB연계 완료)

2021. 3. 21. 20:23Vue.js/Spring & Vue APP 프로젝트(프론트엔드)

#NOTE

-요청 수정 페이지[ㅇ]
-회원정보 수정 페이지[ㅇ]
-평점/후기페이지[...]

#주요소스코드

<OrderModifyPage.vue>

<template>

  <TitleBar>요청서 수정 페이지</TitleBar>

  <section class="section section-article-write-form-box px-2">
    <div class="container mx-auto">
      <div class="px-6 py-6 bg-white rounded-lg shadow-md">
        <form v-if="globalShare.isLogined" v-on:submit.prevent="checkAndModifyOrder">
          <FormRow title="제목">
            <input ref="modifiedOrderTitleElRef" class="form-row-input" type="text" :value="state.order.title">
          </FormRow>
          <FormRow title="장례식장">
            <input ref="modifiedOrderFuneralHomeElRef" class="form-row-input" type="text" :value="state.order.funeralHome">
          </FormRow>
          <FormRow title="옵션1">
            <input ref="modifiedOrderOption1ElRef" class="form-row-input" type="text" :value="state.order.option1">
            <select ref="modifiedOrderOption1qtyElRef" name="option1qty" class="form-row-input w-full rounded-sm" :value="state.order.option1qty">
						  <option value="1">1</option>
						  <option value="2">2</option>
						  <option value="3">3</option>
						  <option value="4">4</option>
						  <option value="5">5</option>
					  </select>
          </FormRow>
          <FormRow title="옵션2">
            <input ref="modifiedOrderOption2ElRef" class="form-row-input" type="text" :value="state.order.option2">
            <select ref="modifiedOrderOption2qtyElRef" name="option1qty" class="form-row-input w-full rounded-sm" :value="state.order.option2qty">
						  <option value="1">1</option>
						  <option value="2">2</option>
						  <option value="3">3</option>
						  <option value="4">4</option>
						  <option value="5">5</option>
					  </select>
          </FormRow>
          <FormRow title="옵션3">
            <input ref="modifiedOrderOption3ElRef" class="form-row-input" type="text" :value="state.order.option3">
            <select ref="modifiedOrderOption3qtyElRef" name="option1qty" class="form-row-input w-full rounded-sm" :value="state.order.option3qty">
						  <option value="1">1</option>
						  <option value="2">2</option>
						  <option value="3">3</option>
						  <option value="4">4</option>
						  <option value="5">5</option>
					  </select>
          </FormRow>
          <FormRow title="옵션4">
            <input ref="modifiedOrderOption4ElRef" class="form-row-input" type="text" :value="state.order.option4">
            <select ref="modifiedOrderOption4qtyElRef" name="option1qty" class="form-row-input w-full rounded-sm" :value="state.order.option4qty">
						  <option value="1">1</option>
						  <option value="2">2</option>
						  <option value="3">3</option>
						  <option value="4">4</option>
						  <option value="5">5</option>
					  </select>
          </FormRow>
          <FormRow title="옵션5">
            <input ref="modifiedOrderOption5ElRef" class="form-row-input" type="text" :value="state.order.option5">
            <select ref="modifiedOrderOption5qtyElRef" name="option1qty" class="form-row-input w-full rounded-sm" :value="state.order.option5qty">
						  <option value="1">1</option>
						  <option value="2">2</option>
						  <option value="3">3</option>
						  <option value="4">4</option>
						  <option value="5">5</option>
					  </select>
          </FormRow>
          <FormRow title="추가 요청 사항">
            <textarea ref="modifiedOrderBodyElRef" class="form-row-input" :value="state.order.body"></textarea>
          </FormRow>
          <FormRow title="완료">
            <div class="btns">
              <input type="submit" value="완료" class="btn-primary" />
            </div>
          </FormRow>
        </form>
        <div v-else>
          <router-link class="btn-link" to="/member/login">로그인</router-link> 후 이용해주세요.
        </div>
      </div>
    </div>
  </section>


</template>

<script lang="ts">
import { defineComponent, reactive, ref, getCurrentInstance, onMounted, watch } from 'vue'
import { MainApi } from '../apis'
import { Router } from 'vue-router'
import { IOrder } from '../types'


export default defineComponent({
  name: 'AddOrderPage',

  props: {
    globalShare: {
      type: Object,
      required: true
    },
    id: {
      type: Number,
      required: true
    }
  },

  setup(props){
    const router:Router = getCurrentInstance()?.appContext.config.globalProperties.$router;
    const mainApi:MainApi = getCurrentInstance()?.appContext.config.globalProperties.$mainApi;

    const modifiedOrderTitleElRef = ref<HTMLInputElement>();
    const modifiedOrderFuneralHomeElRef = ref<HTMLInputElement>();
    const modifiedOrderOption1ElRef = ref<HTMLInputElement>();
    const modifiedOrderOption1qtyElRef = ref<HTMLInputElement>();
    const modifiedOrderOption2ElRef = ref<HTMLInputElement>();
    const modifiedOrderOption2qtyElRef = ref<HTMLInputElement>();
    const modifiedOrderOption3ElRef = ref<HTMLInputElement>();
    const modifiedOrderOption3qtyElRef = ref<HTMLInputElement>();
    const modifiedOrderOption4ElRef = ref<HTMLInputElement>();
    const modifiedOrderOption4qtyElRef = ref<HTMLInputElement>();
    const modifiedOrderOption5ElRef = ref<HTMLInputElement>();
    const modifiedOrderOption5qtyElRef = ref<HTMLInputElement>();
    const modifiedOrderBodyElRef = ref<HTMLInputElement>();

    const state = reactive({
      order: {} as IOrder
    });

    function loadOrder(id:number) {
      mainApi.order_detail(id)
      .then(axiosResponse => {
        state.order = axiosResponse.data.body.order;
      });
    }
    onMounted(() => {
      loadOrder(props.id);
    });
    watch(() => props.id, (newValue, oldValue) => {
      loadOrder(props.id);
    })

    /* 공백 체크 */
    function checkAndModifyOrder(){

      //일반적으로 안해도 되지만 typescript에서는 해야됨
      //제목
      if(modifiedOrderTitleElRef.value == null){
        return;
      }

      const modifiedOrderTitleEl = modifiedOrderTitleElRef.value;
      modifiedOrderTitleEl.value = modifiedOrderTitleEl.value.trim();

      if(modifiedOrderTitleEl.value.length == 0){
        alert('제목을 입력해 주세요.')
        modifiedOrderTitleEl.focus();
        return;
      }

      //장례식장
      if(modifiedOrderFuneralHomeElRef.value == null){
        return;
      }

      const modifiedOrderFuneralHomeEl = modifiedOrderFuneralHomeElRef.value;
      modifiedOrderFuneralHomeEl.value = modifiedOrderFuneralHomeEl.value.trim();

      if(modifiedOrderFuneralHomeEl.value.length == 0){
        alert('장례식장명을 입력해 주세요.')
        modifiedOrderFuneralHomeEl.focus();
        return;
      }

      //옵션1
      if(modifiedOrderOption1ElRef.value == null){
        return;
      }

      const modifiedOrderOption1El = modifiedOrderOption1ElRef.value;
      modifiedOrderOption1El.value = modifiedOrderOption1El.value.trim();

      if(modifiedOrderOption1El.value.length == 0){
        alert('옵션1을 입력해 주세요.')
        modifiedOrderOption1El.focus();
        return;
      }

      //옵션1qty
      if(modifiedOrderOption1qtyElRef.value == null){
        return;
      }

      const modifiedOrderOption1qtyEl = modifiedOrderOption1qtyElRef.value;

      //옵션2
      if(modifiedOrderOption2ElRef.value == null){
        return;
      }

      const modifiedOrderOption2El = modifiedOrderOption2ElRef.value;
      modifiedOrderOption2El.value = modifiedOrderOption2El.value.trim();

      if(modifiedOrderOption1El.value.length == 0){
        alert('옵션2를 입력해 주세요.')
        modifiedOrderOption2El.focus();
        return;
      }

      //옵션2qty
      if(modifiedOrderOption2qtyElRef.value == null){
        return;
      }

      const modifiedOrderOption2qtyEl = modifiedOrderOption2qtyElRef.value;

      //옵션3
      if(modifiedOrderOption3ElRef.value == null){
        return;
      }

      const modifiedOrderOption3El = modifiedOrderOption3ElRef.value;
      modifiedOrderOption3El.value = modifiedOrderOption3El.value.trim();

      if(modifiedOrderOption3El.value.length == 0){
        alert('옵션3을 입력해 주세요.')
        modifiedOrderOption3El.focus();
        return;
      }

      //옵션3qty
      if(modifiedOrderOption3qtyElRef.value == null){
        return;
      }

      const modifiedOrderOption3qtyEl = modifiedOrderOption3qtyElRef.value;

      //옵션4
      if(modifiedOrderOption4ElRef.value == null){
        return;
      }

      const modifiedOrderOption4El = modifiedOrderOption4ElRef.value;
      modifiedOrderOption4El.value = modifiedOrderOption4El.value.trim();

      if(modifiedOrderOption4El.value.length == 0){
        alert('옵션4를 입력해 주세요.')
        modifiedOrderOption4El.focus();
        return;
      }

      //옵션4qty
      if(modifiedOrderOption4qtyElRef.value == null){
        return;
      }

      const modifiedOrderOption4qtyEl = modifiedOrderOption4qtyElRef.value;

      //옵션5
      if(modifiedOrderOption5ElRef.value == null){
        return;
      }

      const modifiedOrderOption5El = modifiedOrderOption5ElRef.value;
      modifiedOrderOption5El.value = modifiedOrderOption5El.value.trim();

      if(modifiedOrderOption5El.value.length == 0){
        alert('옵션5를 입력해 주세요.')
        modifiedOrderOption5El.focus();
        return;
      }

      //옵션5qty
      if(modifiedOrderOption5qtyElRef.value == null){
        return;
      }

      const modifiedOrderOption5qtyEl = modifiedOrderOption5qtyElRef.value;


      //body
      if(modifiedOrderBodyElRef.value == null){
        return;
      }

      const modifiedOrderBodyEl = modifiedOrderBodyElRef.value;
      modifiedOrderBodyEl.value = modifiedOrderBodyEl.value.trim();

      if(modifiedOrderBodyEl.value.length == 0){
        alert('내용을 입력해 주세요.')
        modifiedOrderBodyEl.focus();
        return;
      }

      // 작성 함수로 보내기
      modifyOrder(props.id, modifiedOrderTitleEl.value, modifiedOrderFuneralHomeEl.value, modifiedOrderOption1El.value, parseInt(modifiedOrderOption1qtyEl.value), modifiedOrderOption2El.value, parseInt(modifiedOrderOption2qtyEl.value), modifiedOrderOption3El.value, parseInt(modifiedOrderOption3qtyEl.value), modifiedOrderOption4El.value, parseInt(modifiedOrderOption4qtyEl.value), modifiedOrderOption5El.value, parseInt(modifiedOrderOption5qtyEl.value), modifiedOrderBodyEl.value, state.order.directorId, props.globalShare.loginedMember.id);

    }

    //typescript에서는 title:string, body:string 이런식으로 type을 적어주어야 한다
      function modifyOrder(id:number, title:string, funeralHome:string, option1:string, option1qty:number, option2:string, option2qty:number, option3:string, option3qty:number, option4:string, option4qty:number, option5:string, option5qty:number, body:string, directorId:number, clientId:number){
       
        mainApi.order_doModify(id, title, funeralHome, option1, option1qty, option2, option2qty, option3, option3qty, option4, option4qty, option5, option5qty, body, directorId, clientId)
        .then(axiosResponse => {
          alert(axiosResponse.data.msg);
          
          // 로그인이 fail 상태이면 리턴
          if ( axiosResponse.data.fail ) {
            return;
          }

          //authKey가 있는 상태에서 가능
          const modifiedOrderId = axiosResponse.data.body.id;
          //alert(modifiedArticleId + "번 게시물 등록 완료!!");

          router.replace("detail?id=" + modifiedOrderId);
        });
      }

    return{
        state,
        modifiedOrderTitleElRef,
        modifiedOrderFuneralHomeElRef,
        modifiedOrderOption1ElRef,
        modifiedOrderOption1qtyElRef,
        modifiedOrderOption2ElRef,
        modifiedOrderOption2qtyElRef,
        modifiedOrderOption3ElRef,
        modifiedOrderOption3qtyElRef,
        modifiedOrderOption4ElRef,
        modifiedOrderOption4qtyElRef,
        modifiedOrderOption5ElRef,
        modifiedOrderOption5qtyElRef,
        modifiedOrderBodyElRef,
        checkAndModifyOrder,
      
    }

  }
  
})
</script>

<style scoped>

</style>

<MemberMyPage.vue>

<template>
  <TitleBar>My Page</TitleBar>

  <section class="section section-member-join-form px-2">
    <div class="container mx-auto">
      <div class="px-6 py-6 bg-white rounded-lg shadow-md">
        <div v-if="globalShare.isLogined" v-on:submit.prevent="checkAndJoin">
          <div title="프로필 이미지">
            <img class="h-96 rounded-lg object-cover object-center" :src="'http://localhost:8090' + state.member.extra__thumbImg">
          </div>
          <div title="회원유형">
            <p>회원유형</p>
            {{state.member.authLevel}}
          </div>
          <div title="아이디">
            <p>아이디</p>
            {{state.member.loginId}}
          </div>
          <div title="이름">
            <p>이름</p>
            {{state.member.name}}
          </div>
          <div title="닉네임">
            <p>닉네임</p>
            {{state.member.nickname}}
          </div>
          <div title="전화번호">
            <p>전화번호</p>
            {{state.member.cellphoneNo}}
          </div>
          <div title="이메일">
            <p>이메일</p>
            {{state.member.email}}
          </div>
          <div title="주소">
            <p>주소</p>
            {{state.member.address}}
          </div>
          <div>
            <div class="btns">
              <router-link class="btn-secondary" :to="'/member/doModify?id=' + state.member.id">회원정보수정</router-link>
              <router-link class="btn-danger" to="member/doDelete">탈퇴</router-link>
            </div>
          </div>
        </div>
        <div v-else>
          로그인 후 이용가능합니다.<router-link class="btn-link" to="/">홈</router-link> 으로 이동
        </div>
      </div>
    </div>
  </section>
</template>

<script lang="ts">
import { defineComponent, ref, reactive, watch, getCurrentInstance, onMounted } from 'vue'
import { MainApi } from '../apis'
import { IMember } from '../types'

export default defineComponent({
  name: 'MemberMyPage',
  props: {
    globalShare: {
      type: Object,
      required: true
    },
    id: {
      type: Number,
      required: true
    }
  },
  setup(props) {
    const mainApi:MainApi = getCurrentInstance()?.appContext.config.globalProperties.$mainApi;

    const state = reactive({
      member: {} as IMember
    });

    function loadMember(id:number) {
      mainApi.member_detail(id)
      .then(axiosResponse => {
        state.member = axiosResponse.data.body.member;
      });
    }
    onMounted(() => {
      loadMember(props.id);
    });
    watch(() => props.id, (newValue, oldValue) => {
      loadMember(props.id);
    })

    return {
      state,
    }
  }
})
</script>

<style scoped>
</style> 

<MemberModifyPage.vue>

<template>
  <TitleBar>회원정보수정</TitleBar>

  <section class="section section-member-modify-form px-2">
    <div class="container mx-auto">
      <div class="px-6 py-6 bg-white rounded-lg shadow-md">
        <form v-if="globalShare.isLogined" v-on:submit.prevent="checkAndModify">
          <div title="프로필 이미지">
            <img class="h-96 rounded-lg object-cover object-center" :src="'http://localhost:8090' + state.member.extra__thumbImg">
          </div>
          <FormRow title="프로필 이미지">
            <input ref="profileImgElRef" class="form-row-input" type="file">
          </FormRow>
          <FormRow title="회원유형">
            <select ref="authLevelElRef" :value="state.member.authLevel">
              <option value="3">일반회원</option>
              <option value="4">도우미</option>
              <option value="5">지도사</option>
            </select>
          </FormRow>
          <FormRow title="아이디">
            <input ref="loginIdElRef" class="form-row-input" type="text" :value="state.member.loginId">
          </FormRow>
          <FormRow title="비밀번호">
            <input ref="loginPwElRef" class="form-row-input" type="password" placeholder="비밀번호를 입력해주세요.">
          </FormRow>
          <FormRow title="비밀번호 확인">
            <input ref="loginPwConfirmElRef" class="form-row-input" type="password" placeholder="비밀번호 확인을 해주세요.">
          </FormRow>
          <FormRow title="이름">
            <input ref="nameElRef" class="form-row-input" type="text" :value="state.member.name">
          </FormRow>
          <FormRow title="닉네임">
            <input ref="nicknameElRef" class="form-row-input" type="text" :value="state.member.nickname">
          </FormRow>
          <FormRow title="전화번호">
            <input ref="cellphoneNoElRef" class="form-row-input" type="tel" maxlength="11" :value="state.member.cellphoneNo">
          </FormRow>
          <FormRow title="이메일">
            <input ref="emailElRef" class="form-row-input" type="email" :value="state.member.email">
          </FormRow>
          <FormRow title="시/도">
            <input ref="addressElRef" class="form-row-input" type="text" :value="state.member.address">
          </FormRow>
          <FormRow title="완료">
            <div class="btns">
              <input type="submit" value="완료" class="btn-primary" />
            </div>
          </FormRow>
        </form>
        <div v-else>
          이미 로그인 상태입니다. <router-link class="btn-link" to="/">홈</router-link> 으로 이동
        </div>
      </div>
    </div>
  </section>
</template>

<script lang="ts">
import { defineComponent, ref, reactive, getCurrentInstance, onMounted, watch } from 'vue'
import { MainApi } from '../apis'
import { Router } from 'vue-router'
import { IMember } from '../types'

export default defineComponent({
  name: 'MemberJoinPage',
  props: {
    globalShare: {
      type: Object,
      required: true
    },
    id: {
      type: Number,
      required: true
    }
  },
  setup(props) {
    const router:Router = getCurrentInstance()?.appContext.config.globalProperties.$router;
    const mainApi:MainApi = getCurrentInstance()?.appContext.config.globalProperties.$mainApi;
    const profileImgElRef = ref<HTMLInputElement>();
    const authLevelElRef = ref<HTMLInputElement>();
    const loginIdElRef = ref<HTMLInputElement>();
    const loginPwElRef = ref<HTMLInputElement>();
    const loginPwConfirmElRef = ref<HTMLInputElement>();
    const nameElRef = ref<HTMLInputElement>();
    const nicknameElRef = ref<HTMLInputElement>();
    const cellphoneNoElRef = ref<HTMLInputElement>();
    const emailElRef = ref<HTMLInputElement>();
    const addressElRef = ref<HTMLInputElement>();


    const state = reactive({
      member: {} as IMember
    });

    function loadMember(id:number) {
      mainApi.member_detail(id)
      .then(axiosResponse => {
        state.member = axiosResponse.data.body.member;
      });
    }
    onMounted(() => {
      loadMember(props.id);
    });
    watch(() => props.id, (newValue, oldValue) => {
      loadMember(props.id);
    })

   
    function checkAndModify() {
       // 아이디 체크
      if ( loginIdElRef.value == null ) {
        return;
      }
      
      const loginIdEl = loginIdElRef.value;
      loginIdEl.value = loginIdEl.value.trim();
      
      if ( loginIdEl.value.length == 0 ) {
        alert('아이디를 입력해주세요.');
        loginIdEl.focus();
        return;
      }
      // 비번 체크
      if ( loginPwElRef.value == null ) {
        return;
      }

      const loginPwEl = loginPwElRef.value;
      loginPwEl.value = loginPwEl.value.trim();
      
      if ( loginPwEl.value.length == 0 ) {
        alert('비밀번호를 입력해주세요.');
        loginPwEl.focus();
        return;
      }
      
      // 비번확인 체크
      if ( loginPwConfirmElRef.value == null ) {
        return;
      }

      const loginPwConfirmEl = loginPwConfirmElRef.value;
      
      if ( loginPwEl.value != loginPwConfirmEl.value ) {
        alert('로그인 비번이 일치하지 않습니다.');
        loginPwConfirmEl.focus();
        return;
      }

      // 이름 체크
      if ( nameElRef.value == null ) {
        return;
      }

      const nameEl = nameElRef.value;
      nameEl.value = nameEl.value.trim();

      if ( nameEl.value.length == 0 ) {
        alert('이름을 입력해주세요.');
        nameEl.focus();
        return;
      }

      // 닉네임 체크
      if ( nicknameElRef.value == null ) {
        return;
      }

      const nicknameEl = nicknameElRef.value;
      nicknameEl.value = nicknameEl.value.trim();
      
      if ( nicknameEl.value.length == 0 ) {
        alert('닉네임을 입력해주세요.');
        nicknameEl.focus();
        return;
      }
      
      // 전화번호 체크
      if ( cellphoneNoElRef.value == null ) {
        return;
      }

      const cellphoneNoEl = cellphoneNoElRef.value;
      cellphoneNoEl.value = cellphoneNoEl.value.trim();
      
      if ( cellphoneNoEl.value.length == 0 ) {
        alert('전화번호를 입력해주세요.');
        cellphoneNoEl.focus();
        return;
      }

      // 이메일 체크
      if ( emailElRef.value == null ) {
        return;
      }
      
      const emailEl = emailElRef.value;
      emailEl.value = emailEl.value.trim();
      
      if ( emailEl.value.length == 0 ) {
        alert('이메일을 입력해주세요.');
        emailEl.focus();
        return;
      }

      // 시/도 주소 체크
      if ( addressElRef.value == null ) {
        return;
      }
      
      const addressEl = addressElRef.value;
      addressEl.value = addressEl.value.trim();
      
      if ( addressEl.value.length == 0 ) {
        alert('시/도를 입력해주세요.');
        addressEl.focus();
        return;
      }

     

      if(authLevelElRef.value == null){
        return
      }
      
      const authLevelEl = authLevelElRef.value;
      
      const startFileUpload = (onSuccess:Function) => {
        // ! => 반전
        // a = undefinded(or null) / !a = true / !!a = flase란 의미
        // ? => 만약 profileImgElRef.value?까지가 null이면 여기까지만 실행하겠다라는 의미
        // 즉, !!!profileImgElRef.value?.files의 의미는 해당 파일이 없는지 물어보는 것
        // 없으면 true
        if(!!!profileImgElRef.value?.files){
          onSuccess("");  //파일이 없으면 다음 과정 생략하고 onSuccess() 즉시 실행
          return;
        }

        mainApi.common_genFile_doUpload(profileImgElRef.value?.files[0])
        .then(axiosResponse => {
          
          if ( axiosResponse.data.fail ) {
            alert(axiosResponse.data.msg);
            return;
          }
          else{
            onSuccess(axiosResponse.data.body.genFileIdsStr);
          }
        });
      };


      //회원가입 join함수 시작
      //파일첨부기능 추가로 인해 로직 변경
      //join(loginIdEl.value, loginPwEl.value, nameEl.value, nicknameEl.value, cellphoneNoEl.value, emailEl.value);
      const startModify = (genFileIdsStr:string) =>{
        modify(props.id, parseInt(authLevelEl.value), loginIdEl.value, loginPwEl.value, nameEl.value, nicknameEl.value, cellphoneNoEl.value, emailEl.value, addressEl.value,  genFileIdsStr);
      };

      //startFileUpload 로직을 먼저 실행한 후
      //onSuccess 즉, startJoin를 실행한다. onSuccess = startJoin
      //실행 순서 : 1.첨부파일이 있는지 확인하고 업로드까지 진행하는 startFileUpload함수 종료 후 2.회원가입 join함수가 실행된다.
      startFileUpload(startModify);


      
    }
    function modify(id:number, authLevel:number, loginId:string, loginPw:string, name:string, nickname:string, cellphoneNo:string, email:string, address:string, genFileIdsStr:string) {
      mainApi.member_doModify(id, authLevel, loginId, loginPw, name, nickname, cellphoneNo, email, address, genFileIdsStr)
        .then(axiosResponse => {
          
          alert(axiosResponse.data.msg);
          if ( axiosResponse.data.fail ) {
            return;
          }
          
          router.replace('/member/detail?id=' + id)
        });
    }
    return {
      state,
      checkAndModify,
      profileImgElRef,
      authLevelElRef,
      loginIdElRef,
      loginPwElRef,
      loginPwConfirmElRef,
      nameElRef,
      nicknameElRef,
      cellphoneNoElRef,
      emailElRef,
      addressElRef
    }
  }
})
</script>

<style scoped>
</style>