join.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. <template>
  2. <div class="login-wrap type--join">
  3. <!-- header -->
  4. <div class="login--header">
  5. <div class="login--header--l">
  6. <div class="logo">
  7. <!-- prettier-ignore -->
  8. SHOPDELI
  9. </div>
  10. </div>
  11. <div class="login--header--r"></div>
  12. </div>
  13. <!-- login -->
  14. <div class="login-box type--join">
  15. <div class="login-r">
  16. <!-- <h2 class="mk--title"></h2> -->
  17. <div class="tit-login">
  18. <strong>{{ titleh }} 회원가입</strong>
  19. <!-- <span><i>*</i>필수입력 항목</span> -->
  20. </div>
  21. <div v-show="form.formValue0 === 'Y'" class="login-input-wrap">
  22. <div class="txt-field-box">
  23. <v-text-field
  24. :disabled="useStore.getSnsTempData?.ID ? true : false"
  25. v-model="form.formValue1"
  26. placeholder="아이디를 입력해주세요"
  27. class="custom-input"
  28. @blur="checkId"
  29. ></v-text-field>
  30. <v-btn v-if="!useStore.getSnsTempData?.ID" small class="ml-2" @click="checkId"
  31. >중복확인</v-btn
  32. >
  33. </div>
  34. <div class="txt-field-box">
  35. <v-text-field
  36. v-model="form.formValue2"
  37. :type="visible ? 'text' : 'password'"
  38. placeholder="패스워드를 입력해주세요."
  39. class="custom-input"
  40. id="password"
  41. ></v-text-field>
  42. <i
  43. class="ico-eye"
  44. @click.stop="toggleVisibility"
  45. :class="visible ? 'eye-on' : 'eye-off'"
  46. ></i>
  47. <i class="ico"></i>
  48. </div>
  49. <div class="txt-field-box">
  50. <v-text-field
  51. v-model="form.formValue3"
  52. :type="visible ? 'text' : 'password'"
  53. placeholder="패스워드 확인"
  54. class="custom-input"
  55. ></v-text-field>
  56. <i
  57. class="ico-eye"
  58. @click.stop="toggleVisibility"
  59. :class="visible ? 'eye-on' : 'eye-off'"
  60. ></i>
  61. <i class="ico"></i>
  62. </div>
  63. <div class="txt-field-box">
  64. <v-text-field
  65. v-model="form.formValue4"
  66. :maxlength="20"
  67. :counter="20"
  68. :placeholder="'닉네임을 입력해주세요.'"
  69. class="custom-input"
  70. ></v-text-field>
  71. </div>
  72. <div class="txt-field-box">
  73. <v-text-field
  74. v-model="form.formValue5"
  75. :disabled="useStore.getSnsTempData?.NAME ? true : false"
  76. :maxlength="20"
  77. :counter="20"
  78. placeholder="이름을 입력해주세요"
  79. class="custom-input"
  80. ></v-text-field>
  81. </div>
  82. <div class="txt-field-box">
  83. <v-select
  84. v-model="form.formValue6"
  85. :items="form.formValueItems6"
  86. item-title="text"
  87. item-value="value"
  88. class="custom-select"
  89. ></v-select>
  90. </div>
  91. <div class="txt-field-box">
  92. <v-text-field
  93. v-model="form.formValue7"
  94. placeholder="소셜 ID 또는 주소를 입력해주세요."
  95. class="custom-input"
  96. ></v-text-field>
  97. </div>
  98. <div class="txt-field-box phone">
  99. <v-text-field
  100. placeholder=""
  101. class="custom-input"
  102. v-model="form.formValue8"
  103. ></v-text-field>
  104. -
  105. <v-text-field
  106. placeholder="1234"
  107. class="custom-input"
  108. v-model="form.formValue9"
  109. ></v-text-field>
  110. -
  111. <v-text-field
  112. placeholder="5678"
  113. class="custom-input"
  114. v-model="form.formValue10"
  115. ></v-text-field>
  116. </div>
  117. <div class="txt-field-box email">
  118. <v-text-field
  119. v-model="form.formValue12"
  120. :disabled="useStore.getSnsTempData?.EMAIL"
  121. class="custom-input"
  122. placeholder=""
  123. ></v-text-field>
  124. <span v-if="form.formValue11 != 'direct'">@</span>
  125. <v-select
  126. :disabled="useStore.getSnsTempData?.EMAIL ? true : false"
  127. v-model="form.formValue11"
  128. :items="form.formValueItems11"
  129. item-title="text"
  130. item-value="value"
  131. class="custom-select"
  132. ></v-select>
  133. </div>
  134. <div class="txt-field-box">
  135. <v-textarea
  136. v-model="form.formValue13"
  137. placeholder="자기소개를 입력해주세요. 벤더사들이 참고할 수 있도록 작성해주세요."
  138. class="custom-textarea"
  139. rows="3"
  140. ></v-textarea>
  141. </div>
  142. </div>
  143. <div v-show="form.formValue0 === 'N'" class="login-input-wrap">
  144. <div class="txt-field-box">
  145. <v-text-field
  146. v-model="formVendor.formValue1"
  147. placeholder="아이디를 입력해주세요"
  148. class="custom-input"
  149. ></v-text-field>
  150. <v-btn
  151. v-if="!useStore.getSnsTempData?.ID"
  152. class="ml-2 custom-btn mini btn-white"
  153. @click="checkIdVendor"
  154. >중복확인</v-btn
  155. >
  156. </div>
  157. <div class="txt-field-box">
  158. <v-text-field
  159. v-model="formVendor.formValue2"
  160. :type="visible ? 'text' : 'password'"
  161. placeholder="패스워드를 입력해주세요."
  162. class="custom-input"
  163. id="password"
  164. ></v-text-field>
  165. <i
  166. class="ico-eye"
  167. @click.stop="toggleVisibility"
  168. :class="visible ? 'eye-on' : 'eye-off'"
  169. ></i>
  170. <i class="ico"></i>
  171. </div>
  172. <div class="txt-field-box">
  173. <v-text-field
  174. v-model="formVendor.formValue3"
  175. :type="visible ? 'text' : 'password'"
  176. placeholder="패스워드 확인"
  177. class="custom-input"
  178. ></v-text-field>
  179. <i
  180. class="ico-eye"
  181. @click.stop="toggleVisibility"
  182. :class="visible ? 'eye-on' : 'eye-off'"
  183. ></i>
  184. <i class="ico"></i>
  185. </div>
  186. <div class="txt-field-box">
  187. <v-text-field
  188. v-model="formVendor.formValue4"
  189. :maxlength="20"
  190. :counter="20"
  191. placeholder="회사명"
  192. class="custom-input"
  193. ></v-text-field>
  194. </div>
  195. <div class="txt-field-box">
  196. <v-text-field
  197. v-model="formVendor.formValue5"
  198. :maxlength="20"
  199. :counter="20"
  200. placeholder="담당자 명"
  201. class="custom-input"
  202. ></v-text-field>
  203. </div>
  204. <div class="txt-field-box phone">
  205. <v-text-field
  206. placeholder=""
  207. class="custom-input"
  208. v-model="formVendor.formValue8"
  209. ></v-text-field>
  210. -
  211. <v-text-field
  212. placeholder="1234"
  213. class="custom-input"
  214. v-model="formVendor.formValue9"
  215. ></v-text-field>
  216. -
  217. <v-text-field
  218. placeholder="5678"
  219. class="custom-input"
  220. v-model="formVendor.formValue10"
  221. ></v-text-field>
  222. </div>
  223. <div class="txt-field-box email">
  224. <v-text-field
  225. v-model="formVendor.formValue12"
  226. class="custom-input"
  227. placeholder=""
  228. ></v-text-field>
  229. <span v-if="formVendor.formValue11 != 'direct'">@</span>
  230. <v-select
  231. v-model="formVendor.formValue11"
  232. :items="formVendor.formValueItems11"
  233. item-title="text"
  234. item-value="value"
  235. class="custom-select"
  236. ></v-select>
  237. </div>
  238. <div class="mt-5 d-flex agree--box">
  239. <v-checkbox class="custom-check type2" v-model="formVendor.formValue13">
  240. <template v-slot:label>개인정보약관동의</template>
  241. </v-checkbox>
  242. <v-checkbox class="custom-check type2" v-model="formVendor.formValue14">
  243. <template v-slot:label>제3자 정보동의</template>
  244. </v-checkbox>
  245. </div>
  246. </div>
  247. <div class="login-btn-wrap">
  248. <v-btn
  249. v-show="form.formValue0 === 'Y'"
  250. class="custom-btn btn-blue"
  251. @click.stop="joinMember('influence')"
  252. >회원가입</v-btn
  253. >
  254. <v-btn
  255. v-show="typeParam === 'vendor'"
  256. class="custom-btn btn-blue"
  257. @click.stop="joinMember('vendor')"
  258. >회원가입</v-btn
  259. >
  260. <v-btn
  261. v-show="typeParam === 'brand'"
  262. class="custom-btn btn-blue"
  263. @click.stop="joinMember('brand')"
  264. >회원가입</v-btn
  265. >
  266. </div>
  267. </div>
  268. </div>
  269. <!-- footer -->
  270. <div class="login-footer">
  271. <div class="login--footer--l">
  272. <p>COPYRIGHT@2025 SHOPDELI INC. ALL RIGHTS RESERVED.</p>
  273. <p>마포구 합정동</p>
  274. </div>
  275. </div>
  276. </div>
  277. </template>
  278. <script setup>
  279. /************************
  280. * import
  281. ************************/
  282. const { $log, $toast } = useNuxtApp();
  283. /************************
  284. * layout setting
  285. ************************/
  286. definePageMeta({
  287. layout: "loginlayout",
  288. });
  289. /************************
  290. * 전역
  291. ************************/
  292. const titleh = ref("인플루언서");
  293. const useStore = useAuthStore();
  294. const randomString = ref("");
  295. //인플루언서 폼
  296. const form = ref({
  297. formValue0: "Y",
  298. formValue1: useStore.getSnsTempData?.ID || "", // 아이디
  299. formValue2: "", // 패스워드
  300. formValue3: "", // 패스워드 확인
  301. formValue4: "", // 닉네임
  302. formValue5: useStore.getSnsTempData?.NAME || "", // 이름
  303. formValue6: "소셜채널 선택", // 소셜 채널
  304. formValueItems6: [
  305. {
  306. text: "유튜브",
  307. value: "youtube",
  308. },
  309. {
  310. text: "인스타",
  311. value: "instagram",
  312. },
  313. {
  314. text: "네이버 블로그",
  315. value: "naverblog",
  316. },
  317. {
  318. text: "네이버 카페",
  319. value: "navercafe",
  320. },
  321. {
  322. text: "스마트스토어",
  323. value: "smartstore",
  324. },
  325. ], // 소셜 채널 아이템
  326. formValue7: "", // 소셜 ID 또는 주소
  327. formValue8: "010", // 휴대폰1
  328. formValue9: "", // 휴대폰2
  329. formValue10: "", // 휴대폰3
  330. formValue11: "email", // 이메일1
  331. formValueItems11: [
  332. {
  333. text: "이메일 선택",
  334. value: "email",
  335. },
  336. {
  337. text: "직접입력",
  338. value: "direct",
  339. },
  340. {
  341. text: "naver.com",
  342. value: "naver",
  343. },
  344. {
  345. text: "gmail.com",
  346. value: "gmail",
  347. },
  348. {
  349. text: "daum.net",
  350. value: "daum",
  351. },
  352. ], // 이메일 아이템
  353. formValue12: "", // 이메일2
  354. formValue13: "", // 자기소개
  355. });
  356. //밴더 폼
  357. const formVendor = ref({
  358. formValue0: "",
  359. formValue1: "", // 아이디
  360. formValue2: "", // 패스워드
  361. formValue3: "", // 패스워드 확인
  362. formValue4: "", // 닉네임
  363. formValue5: "", // 이름
  364. formValue6: "소셜채널 선택", // 소셜 채널
  365. formValue7: "", // 소셜 ID 또는 주소
  366. formValue8: "010", // 휴대폰1
  367. formValue9: "", // 휴대폰2
  368. formValue10: "", // 휴대폰3
  369. formValue11: "email", // 이메일1
  370. formValueItems11: [
  371. {
  372. text: "이메일 선택",
  373. value: "email",
  374. },
  375. {
  376. text: "직접입력",
  377. value: "direct",
  378. },
  379. {
  380. text: "naver.com",
  381. value: "naver",
  382. },
  383. {
  384. text: "gmail.com",
  385. value: "gmail",
  386. },
  387. {
  388. text: "daum.net",
  389. value: "daum",
  390. },
  391. ], // 이메일 아이템
  392. formValue12: "",
  393. formValue13: "", // 개인정보약관동의
  394. formValue14: "", // 제3자 정보동의
  395. });
  396. /************************
  397. * 함수
  398. ************************/
  399. const generateRandomAlphanumeric = (length) => {
  400. const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  401. let result = "";
  402. const charsLength = chars.length;
  403. for (let i = 0; i < length; i++) {
  404. result += chars.charAt(Math.floor(Math.random() * charsLength));
  405. }
  406. return result;
  407. };
  408. const checkId = async () => {
  409. if (!form.value.formValue1) {
  410. $toast.error("아이디를 입력해주세요.");
  411. return;
  412. }
  413. // 아이디 형식 검사 (영문, 숫자 조합 6~20자)
  414. const idRegex = /^[a-zA-Z0-9]{6,20}$/;
  415. if (!idRegex.test(form.value.formValue1)) {
  416. $toast.error("아이디는 영문, 숫자 조합 6~20자로 입력해주세요.");
  417. return;
  418. }
  419. try {
  420. const response = await useAxios().post("/auth/checkId", {
  421. ID: form.value.formValue1,
  422. TYPE: "influence",
  423. });
  424. if (response.data.isDuplicate) {
  425. $toast.error("이미 사용중인 아이디입니다.");
  426. } else {
  427. $toast.success("사용 가능한 아이디입니다.");
  428. }
  429. } catch (error) {
  430. console.error("ID check error:", error);
  431. $toast.error("아이디 중복 확인 중 오류가 발생했습니다.");
  432. }
  433. };
  434. const checkIdVendor = async () => {
  435. if (!formVendor.value.formValue1) {
  436. $toast.error("아이디를 입력해주세요.");
  437. return;
  438. }
  439. // 아이디 형식 검사 (영문, 숫자 조합 6~20자)
  440. const idRegex = /^[a-zA-Z0-9]{6,20}$/;
  441. if (!idRegex.test(formVendor.value.formValue1)) {
  442. $toast.error("아이디는 영문, 숫자 조합 6~20자로 입력해주세요.");
  443. return;
  444. }
  445. try {
  446. const response = await useAxios().post("/auth/checkId", {
  447. ID: formVendor.value.formValue1,
  448. TYPE: typeParam.value,
  449. });
  450. if (response.data.isDuplicate) {
  451. $toast.error("이미 사용중인 아이디입니다.");
  452. } else {
  453. $toast.success("사용 가능한 아이디입니다.");
  454. }
  455. } catch (error) {
  456. console.error("ID check error:", error);
  457. $toast.error("아이디 중복 확인 중 오류가 발생했습니다.");
  458. }
  459. };
  460. // 회원가입 전에 아이디 유효성 검사 추가
  461. const joinMember = async (id_type) => {
  462. if (!useStore.getSnsTempData?.ID) {
  463. if (id_type === "vendor") {
  464. if (!formVendor.value.formValue1) {
  465. $toast.error("아이디를 입력해주세요.");
  466. return;
  467. }
  468. // const idRegex = /^[a-zA-Z0-9]{6,20}$/;
  469. // if (!idRegex.test(form.value.formValue1)) {
  470. // $toast.error("아이디는 영문, 숫자 조합 6~20자로 입력해주세요.");
  471. // return;
  472. // }
  473. } else {
  474. if (!formVendor.value.formValue1) {
  475. $toast.error("아이디를 입력해주세요.");
  476. return;
  477. }
  478. }
  479. }
  480. let _req = "";
  481. let _api = "";
  482. if (id_type === "influence") {
  483. _api = "/auth/joinmember";
  484. _req = {
  485. ID: form.value.formValue1,
  486. PASSWORD: form.value.formValue2,
  487. NAME: form.value.formValue5,
  488. NICK_NAME: form.value.formValue4 || "", //닉네임 없으면 빈문자
  489. PHONE: `${form.value.formValue8}-${form.value.formValue9}-${form.value.formValue10}`,
  490. EMAIL: form.value.formValue12,
  491. SNS_TYPE: form.value.formValue6,
  492. SNS_LINK_ID: form.value.formValue7,
  493. ADD_INFO1: form.value.formValue13,
  494. GOOGLE_REFRESH_TOKEN: useStore.getSnsTempData?.GOOGLE_REFRESH_TOKEN || "",
  495. TYPE: useStore.getSnsTempData ? "1" : "0", // SNS 가입일경우 1, 일반회원 가입일경우 0
  496. };
  497. } else if (id_type === "vendor") {
  498. _api = "/auth/joinvendor";
  499. _req = {
  500. ID: formVendor.value.formValue1,
  501. PASSWORD: formVendor.value.formValue3,
  502. COMPANY_NAME: formVendor.value.formValue4,
  503. COMPANY_NUMBER: (randomString.value = generateRandomAlphanumeric(100)),
  504. NAME: formVendor.value.formValue5,
  505. HP: `${formVendor.value.formValue8}-${formVendor.value.formValue9}-${formVendor.value.formValue10}`,
  506. EMAIL: formVendor.value.formValue12,
  507. }
  508. } else {
  509. _api = "/auth/joinbrand";
  510. _req = {
  511. ID: formVendor.value.formValue1,
  512. PASSWORD: formVendor.value.formValue3,
  513. COMPANY_NAME: formVendor.value.formValue4,
  514. COMPANY_NUMBER: (randomString.value = generateRandomAlphanumeric(100)),
  515. NAME: formVendor.value.formValue5,
  516. HP: `${formVendor.value.formValue8}-${formVendor.value.formValue9}-${formVendor.value.formValue10}`,
  517. EMAIL: formVendor.value.formValue12,
  518. };
  519. }
  520. useAxios()
  521. .post(_api, _req)
  522. .then((res) => {
  523. if (_req.TYPE === "1") {
  524. // SNS 가입일 경우
  525. useStore.setTempData("");
  526. useUtil.setPageMove("/?type=influence");
  527. return;
  528. }
  529. if (form.value.formValue0 === "Y") {
  530. useUtil.setPageMove("/?type=influence");
  531. } else {
  532. useUtil.setPageMove("/?type=vendor");
  533. }
  534. })
  535. .catch((error) => {
  536. if (error.response) {
  537. console.log("status:", error.response.status, "data:", error.response.data);
  538. // 안전하게 errCode, message 접근
  539. const errData = error.response.data || {};
  540. const errCode = errData.errCode || errData.errorCode || errData.code || "";
  541. const errMsg = errData.message || "알 수 없는 오류가 발생했습니다.";
  542. console.log("errCode:", errCode, "message:", errMsg);
  543. } else {
  544. console.log("error:", error.message, error.code);
  545. }
  546. if (error.response?.status) {
  547. fnLoginSet(error.response.data.messages.message);
  548. }
  549. $log.debug("[join][fnIdPwCheck][error]");
  550. })
  551. .finally(() => {
  552. $log.debug("[join][fnIdPwCheck][finished]");
  553. });
  554. };
  555. /************************
  556. * 반응형 변수
  557. ************************/
  558. const route = useRoute();
  559. const typeParam = ref(route.query.type);
  560. /************************
  561. * 마운트
  562. ************************/
  563. onMounted(() => {
  564. if(typeParam.value === "influence"){
  565. (form.value.formValue0 = "Y");
  566. titleh.value = "인플루언서"
  567. } else if(typeParam.value === "vendor"){
  568. (form.value.formValue0 = "N") ;
  569. titleh.value = "벤더사"
  570. } else {
  571. (form.value.formValue0 = "N") ;
  572. titleh.value = "브랜드사"
  573. }
  574. if (useStore.getSnsTempData?.EMAIL) {
  575. form.value.formValue12 = useStore.getSnsTempData.EMAIL;
  576. form.value.formValue11 = "direct"; // 이메일 직접입력으로 설정
  577. }
  578. });
  579. </script>