박민혁 박민혁 07-11
250711 박민혁 회원가입 추가 및 로그인 수정
@66d84c8904067a831963ffae0358f505e1bb10d3
client/resources/api/auth.js
--- client/resources/api/auth.js
+++ client/resources/api/auth.js
@@ -1,7 +1,7 @@
 import apiClient from "./index";
 
 // 회원가입 기능
-export const resistProc = (data) => {
+export const registProc = (data) => {
     return apiClient.post(`/auth/register.json`, data);
 };
 
@@ -15,3 +15,12 @@
     return apiClient.post(`/auth/logout.json`);
 };
 
+// 아이디 중복 확인
+export const checkIdProc = (data) => {
+    return apiClient.post(`/auth/checkId.json`, data);
+};
+
+// 이메일 중복 확인
+export const checkEmailProc = (data) => {
+    return apiClient.post(`/auth/checkEmail.json`, data);
+};
client/views/pages/common/Join.vue
--- client/views/pages/common/Join.vue
+++ client/views/pages/common/Join.vue
@@ -1,94 +1,110 @@
 <template>
-  <div class="join-wrap">
-    <div class="login-logo mb50">
-        <img src="../../../resources/img/content/login_logo.svg" alt="로고">
-    </div>
-    <div class="login-box join-box">
-        <div class="tbl-wrap">
-            <table class="tbl data">
-                <colgroup>
-                    <col style="width: 180px;">
-                    <col style="width: auto;">
-                </colgroup>
-                <tbody>
-                    <tr>
-                        <th style="background-color: #eff1fa;">아이디</th>
-                        <td>
-                            <div class="input-group">
-                                <input type="text" class="form-control sm" placeholder="3-15자 영문/숫자 조합으로 입력해주세요" v-model="loginId">
-                                <button class="btn sm black">중복확인</button>
-                            </div>
-                        </td>
-                    </tr>
-                    <tr>
-                        <th  style="background-color: #eff1fa;">비밀번호</th>
-                        <td><input type="password" class="form-control sm" placeholder="3-16자 영문/숫자 조합으로 입력해주세요" v-model="password"></td>
-                    </tr>
-                    <tr>
-                        <th style="background-color: #eff1fa;">비밀번호 확인</th>
-                        <td><input type="password" class="form-control sm" placeholder="3-16자 영문/숫자 조합으로 입력해주세요" v-model="passwordCheck"></td>
-                    </tr>
-                </tbody>
-            </table>
+    <div class="join-wrap">
+        <div class="login-logo mb50">
+            <img src="../../../resources/img/content/login_logo.svg" alt="로고">
         </div>
-        <div class="tbl-wrap">
-            <table class="tbl data">
-                <colgroup>
-                    <col style="width: 180px;">
-                    <col style="width: auto;">
-                </colgroup>
-                <tbody>
-                    <tr>
-                        <th style="background-color: #eff1fa;">이름</th>
-                        <td><input type="text" class="form-control sm" placeholder="한글 15자, 영문 30자까지 가능합니다." v-model="memberName"></td>
-                    </tr>
-                    <tr>
-                        <th style="background-color: #eff1fa;">이메일</th>
-                        <td>
-                            <div class="input-group">
-                                <input type="text" class="form-control sm" placeholder="3-15자 영문/숫자 조합으로 입력해주세요" v-model="email">
-                                <button class="btn sm black">중복확인</button>
-                            </div>
-                        </td>
-                    </tr>
-                </tbody>
-            </table>
-        </div>
-        <div class="tbl-wrap last-table">
-            <table class="tbl data">
-                <colgroup>
-                    <col style="width: 180px;">
-                    <col style="width: auto;">
-                </colgroup>
-                <tbody>
-                    <tr>
-                        <th style="background-color: #eff1fa;border-radius: 1rem 0 0 1rem; ">전화번호</th>
-                        <td>
-                            <div class="input-group mb10">
-                                <input type="text" class="form-control sm" placeholder="-제외 휴대전화 번호를 입력해주세요" v-model="phoneNumber">
-                                <button class="btn sm black">인증번호 발송</button>
-                            </div>
-                            <div class="input-group">
-                                <input type="text" class="form-control sm" placeholder="인증번호 6자리 숫자를 입력해주세요" style="background-color: #ebebeb;" v-model="vertifiCode">
-                                <button class="btn sm black" style="min-width: 119px;">확인</button>
-                            </div>
-                        </td>
-                    </tr>
-                </tbody>
-            </table>
-        </div>
+        <div class="login-box join-box">
+            <div class="tbl-wrap">
+                <table class="tbl data">
+                    <colgroup>
+                        <col style="width: 180px;">
+                        <col style="width: auto;">
+                    </colgroup>
+                    <tbody>
+                        <tr>
+                            <th style="background-color: #eff1fa;">아이디</th>
+                            <td>
+                                <div class="input-group">
+                                    <input type="text" class="form-control sm" placeholder="3-15자 영문/숫자 조합으로 입력해주세요"
+                                        v-model="loginId">
+                                    <button class="btn sm black" @click="checkIdProc">중복확인</button>
+                                </div>
+                            </td>
+                        </tr>
+                        <tr>
+                            <th style="background-color: #eff1fa;">비밀번호</th>
+                            <td><input type="password" class="form-control sm" placeholder="3-16자 영문/숫자 조합으로 입력해주세요"
+                                    v-model="password"></td>
+                        </tr>
+                        <tr>
+                            <th style="background-color: #eff1fa;">비밀번호 확인</th>
+                            <td><input type="password" class="form-control sm mb10"
+                                    placeholder="3-16자 영문/숫자 조합으로 입력해주세요" v-model="passwordCheck">
+                                <div class="error-message " v-if="passwordFail">
+                                    <p><img src="../../../resources/img/component/common/ico_invalid_error_20.svg"
+                                            alt="">비밀번호가 일치하지 않습니다</p>
+                                </div>
+                            </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+            <div class="tbl-wrap">
+                <table class="tbl data">
+                    <colgroup>
+                        <col style="width: 180px;">
+                        <col style="width: auto;">
+                    </colgroup>
+                    <tbody>
+                        <tr>
+                            <th style="background-color: #eff1fa;">이름</th>
+                            <td><input type="text" class="form-control sm" placeholder="한글 15자, 영문 30자까지 가능합니다."
+                                    v-model="memberName"></td>
+                        </tr>
+                        <tr>
+                            <th style="background-color: #eff1fa;">이메일</th>
+                            <td>
+                                <div class="input-group">
+                                    <input type="text" class="form-control sm" placeholder="유효한 이메일 주소를 입력해주세요"
+                                        v-model="email">
+                                    <button class="btn sm black" @click="checkEmailProc">중복확인</button>
+                                </div>
+                            </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+            <div class="tbl-wrap last-table">
+                <table class="tbl data">
+                    <colgroup>
+                        <col style="width: 180px;">
+                        <col style="width: auto;">
+                    </colgroup>
+                    <tbody>
+                        <tr>
+                            <th style="background-color: #eff1fa;border-radius: 1rem 0 0 1rem; ">전화번호</th>
+                            <td>
+                                <div class="input-group mb10">
+                                    <input type="text" class="form-control sm" placeholder="-제외 휴대전화 번호를 입력해주세요"
+                                        v-model="phoneNumber">
+                                    <button class="btn sm black">인증번호 발송</button>
+                                </div>
+                                <div class="input-group">
+                                    <input type="text" class="form-control sm" placeholder="인증번호 6자리 숫자를 입력해주세요"
+                                        style="background-color: #ebebeb;" v-model="vertifiCode">
+                                    <button class="btn sm black" style="min-width: 119px;"
+                                        @click="vertifyCode">확인</button>
+                                </div>
+                            </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
 
-        <div class="layout center justify-center">
-            <button class="btn lg netx-btn" @click="stepGo(2)">다음</button>
-        </div>
+            <div class="layout center justify-center">
+                <button class="btn lg netx-btn" @click="registProc">다음</button>
+            </div>
 
+        </div>
     </div>
-  </div>
 </template>
 
 <script>
+import { errorMessages } from 'vue/compiler-sfc';
+import { registProc, checkIdProc, checkEmailProc } from '../../../resources/api/auth';
 
 export default {
+    inject: ['$alert'],
     data() {
         return {
             loginId: null,
@@ -98,15 +114,180 @@
             email: null,
             phoneNumber: null,
             vertifiCode: null,
+            passwordFail: false,
+            checkId: false,
+            checkEmail: false,
+            errorMessage: "",
         };
     },
-    methods: {},
-    watch: {},
+    methods: {
+        // 회원가입 
+        async registProc() {
+            const vm = this;
+            vm.passwordFail = false;
+            vm.errorMessage = "";
+
+            // 아이디 검증
+            const idRegex = /^[a-zA-Z0-9]{3,15}$/;
+            if (!vm.loginId || !idRegex.test(vm.loginId)) {
+                vm.$alert({ message: '아이디는 영문+숫자 조합의 3~15자여야 합니다.' });
+                return;
+            }
+            if (vm.checkId === false) {
+                vm.$alert({ message: '아이디 중복 확인을 해야합니다.' });
+                return;
+            }
+
+            // 비밀번호 검증
+            const pwRegex = /^[a-zA-Z0-9]{3,16}$/;
+            if (!vm.password || !pwRegex.test(vm.password)) {
+                vm.$alert({ message: '비밀번호는 영문+숫자 조합의 3~16자여야 합니다.' });
+                return;
+            }
+
+            // 비밀번호 확인
+            if (vm.password !== vm.passwordCheck) {
+                vm.passwordFail = true;
+                return;
+            }
+
+            // 이름 검증
+            const name = vm.memberName;
+            if (!name || !(name.length <= 15 || name.length <= 30)) {
+                vm.$alert({ message: '이름을 입력해주세요.' });
+                return;
+            }
+
+            // 이메일 검증
+            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+            if (!vm.email || !emailRegex.test(vm.email)) {
+                vm.$alert({ message: '올바른 이메일 형식을 입력해주세요.' });
+                return;
+            }
+            if (vm.checkEmail === false) {
+                vm.$alert({ message: '이메일 중복 확인을 해야합니다.' });
+                return;
+            }
+
+            // 전화번호 검증
+            const phoneRegex = /^01[016789][0-9]{7,8}$/;
+            if (!vm.phoneNumber || !phoneRegex.test(vm.phoneNumber)) {
+                vm.$alert({ message: '전화번호는 "-" 없이 10~11자리 숫자로 입력해주세요.' });
+                return;
+            }
+
+            // 인증 코드 검증
+            const codeRegex = /^[0-9]{6}$/;
+            if (!vm.vertifiCode || !codeRegex.test(vm.vertifiCode)) {
+                vm.$alert({ message: '인증번호는 6자리 숫자여야 합니다.' });
+
+                return;
+            }
+
+            const loginData = {
+                loginId: vm.loginId,
+                password: vm.password,
+                memberName: vm.memberName,
+                email: vm.email,
+                phoneNumber: vm.phoneNumber
+            }
+            try {
+                const res = await registProc(loginData);
+                if (res.status === 200) {
+                    vm.$alert({ message: '회원가입이 완료되었습니다.' });
+
+                    vm.$router.push({ path: "/login.page" });
+                }
+
+            } catch (error) {
+                vm.errorMessage = '장애가 발생했습니다.\n';
+                vm.showAlert();
+            }
+        },
+        // 아이디 중복 확인
+        async checkIdProc() {
+            const vm = this;
+            vm.checkId = false;
+            // 아이디 검증
+            const idRegex = /^[a-zA-Z0-9]{3,15}$/;
+            if (!vm.loginId || !idRegex.test(vm.loginId)) {
+                vm.$alert({ message: '아이디는 영문+숫자 조합의 3~15자여야 합니다.' });
+                return;
+            }
+
+            const checkIdData = {
+                loginId: vm.loginId,
+            }
+            try {
+                const res = await checkIdProc(checkIdData);
+                if (res.status === 200) {
+                    if (res.data.result > 0) {
+                        vm.$alert({ message: '중복된 아이디입니다.' });
+                    } else {
+                        vm.checkId = true;
+                        vm.$alert({ message: '사용 가능한 아이디입니다.' });
+                    }
+                }
+
+            } catch (error) {
+            }
+        },
+
+        // 이메일 중복 확인
+        async checkEmailProc() {
+            const vm = this;
+            vm.checkEmail = false;
+
+            // 이메일 검증
+            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+            if (!vm.email || !emailRegex.test(vm.email)) {
+                vm.$alert({ message: '올바른 이메일 형식을 입력해주세요.' });
+                return;
+            }
+
+            const checkEmailData = {
+                email: vm.email,
+            }
+            try {
+                const res = await checkEmailProc(checkEmailData);
+                if (res.status === 200) {
+                    if (res.data.result > 0) {
+                        vm.$alert({ message: '중복된 이메일입니다.' });
+                    } else {
+                        vm.checkEmail = true;
+                        vm.$alert({ message: '사용 가능한 이메일입니다.' });
+                    }
+                }
+
+            } catch (error) {
+            }
+        },
+
+        // 인증번호 발송 - 비용이 드는 것이기에 생략
+        async sendMail(){
+
+        },
+
+        // 인증번호 확인 - 발송과 마찬가지로 생략
+        async checkCode() {
+
+        },
+
+    },
+    watch: {
+        // 아이디, 이메일 변경 시 중복 확인 초기화
+        loginId(newVal, oldVal) {
+            this.checkId = false;
+        },
+        email(newVal, oldVal) {
+            this.checkEmail = false;
+        },
+    },
     computed: {},
     components: {},
-    created() {},
-    mounted() {},
-    beforeUnmount() {},
+    created() { },
+    mounted() { },
+    beforeUnmount() { },
 };
 
 </script>
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/common/Login.vue
--- client/views/pages/common/Login.vue
+++ client/views/pages/common/Login.vue
@@ -16,10 +16,7 @@
                     </div>
                 </div>
                 <div class="error-message mb20" v-if="!isValid">
-                    <p><img src="../../../resources/img/component/common/ico_invalid_error_20.svg" alt=""> 아이디 또는 비밀번호가
-                        잘못되었습니다.</p>
-                    <p><img src="../../../resources/img/component/common/ico_invalid_error_20.svg" alt=""> 아이디와 비밀번호를
-                        정확히 입력해주세요.</p>
+                    <p><img src="../../../resources/img/component/common/ico_invalid_error_20.svg" alt=""> {{ errorMessage }}</p>
                 </div>
                 <button class="btn lg primary login-btn mb30" @click="loginProc"><span
                         class="icon-label lbtn">로그인</span></button>
@@ -27,7 +24,7 @@
             <div class="layout center justify-center links">
                 <router-link :to="{ path: '/find.page', query: { type: 'id' } }">아이디 찾기</router-link>
                 <router-link :to="{ path: '/find.page', query: { type: 'pw' } }">비밀번호 찾기</router-link>
-                <router-link to="/join.page">회원가입 찾기</router-link>
+                <router-link to="/join.page">회원가입</router-link>
             </div>
         </div>
     </div>
@@ -42,11 +39,15 @@
             isValid: true,
             loginId: null,
             password: null,
+            errorMessage: "",
         };
     },
     methods: {
+        // 로그인
         async loginProc() {
             const vm = this;
+            vm.isValid = true;
+            vm.errorMessage = ""; 
             // 사용자 아이디와 비밀번호 입력값 검증
             if (!vm.loginId || vm.loginId.trim() === '') {
                 return;
@@ -56,8 +57,8 @@
             }
 
             const loginData = {
-                loginId : vm.loginId,
-                password : vm.password
+                loginId: vm.loginId,
+                password: vm.password
             }
 
             try {
@@ -79,6 +80,9 @@
                     this.$router.push({ path: "/" });
                 }
             } catch (error) {
+                vm.isValid = false;
+                this.errorMessage = error.response?.data?.message || "로그인 중 오류가 발생했습니다.";
+
             }
         },
     },
Add a comment
List