
+++ client/resources/api/unified.js
... | ... | @@ -0,0 +1,26 @@ |
1 | +import apiClient from "./index"; | |
2 | + | |
3 | +// 연동된 계정 목록 조회 | |
4 | +export const findAllLink = () => { | |
5 | + return apiClient.post(`/mbr/unified/linkedAccounts.json`); | |
6 | +} | |
7 | + | |
8 | +// 계정 연동 | |
9 | +export const linkAccount = params => { | |
10 | + return apiClient.post(`/mbr/unified/linkAccount.json`, params); | |
11 | +} | |
12 | + | |
13 | +// 계정 연동 해제 | |
14 | +export const unlinkAccount = params => { | |
15 | + return apiClient.post(`/mbr/unified/unlinkAccount.json`, params); | |
16 | +} | |
17 | + | |
18 | +// 계정 재연동 | |
19 | +export const reLinkAccount = params => { | |
20 | + return apiClient.post(`/mbr/unified/reLinkAccount.json`, params); | |
21 | +} | |
22 | + | |
23 | +// 기본 프로필 설정 | |
24 | +export const setPrimaryProfile = params => { | |
25 | + return apiClient.post(`/mbr/unified/setPrimaryProfile.json`, params); | |
26 | +}(파일 끝에 줄바꿈 문자 없음) |
--- client/views/component/userInfo/UserInfoView.vue
+++ client/views/component/userInfo/UserInfoView.vue
... | ... | @@ -83,7 +83,7 @@ |
83 | 83 |
|
84 | 84 |
<div v-if="showOpt.isSmsAgree" class="layout"> |
85 | 85 |
<p class="form-title">문자수신</p> |
86 |
- <p>{{ mbrVO.smsRcptnAgreYn }}</p> |
|
86 |
+ <p>{{ mbrVO.smsRcptnAgreYn === 'Y' ? '수신' : '미수신' }}</p> |
|
87 | 87 |
<!-- <div class="check-area"> |
88 | 88 |
<div class="form-check"> |
89 | 89 |
<input |
... | ... | @@ -114,7 +114,7 @@ |
114 | 114 |
|
115 | 115 |
<div v-if="showOpt.isEmlAgree" class="layout"> |
116 | 116 |
<p class="form-title">이메일수신</p> |
117 |
- <p>{{ mbrVO.emlRcptnAgreYn }}</p> |
|
117 |
+ <p>{{ mbrVO.emlRcptnAgreYn === 'Y' ? '수신' : '미수신' }}</p> |
|
118 | 118 |
<!-- <div class="check-area"> |
119 | 119 |
<div class="form-check"> |
120 | 120 |
<input |
... | ... | @@ -236,6 +236,9 @@ |
236 | 236 |
<template v-if="pageRole == 'adm' && pageAuth.delAuthrt == 'Y'" class="gd-1"> |
237 | 237 |
<button class="btn sm red" @click="fnDelete">삭제</button> |
238 | 238 |
</template> |
239 |
+ <template v-if="pageRole == 'portal' && pageAuth.delAuthrt == 'Y'" class="gd-1"> |
|
240 |
+ <button class="btn sm red" @click="fnSelfDelete">회원탈퇴</button> |
|
241 |
+ </template> |
|
239 | 242 |
</div> |
240 | 243 |
</template> |
241 | 244 |
|
... | ... | @@ -245,6 +248,7 @@ |
245 | 248 |
defaultAdminInfoParams, |
246 | 249 |
defaultUserInfoParams, |
247 | 250 |
} from "../../../resources/js/defaultUserInfoParams"; |
251 |
+import { mapActions } from "vuex"; |
|
248 | 252 |
|
249 | 253 |
// COMPONENT |
250 | 254 |
import UserAuthorList from "./UserAuthorList.vue"; |
... | ... | @@ -315,6 +319,7 @@ |
315 | 319 |
} |
316 | 320 |
} |
317 | 321 |
this.mbrVO = response.data.data; |
322 |
+ this.$emit('mbrVO', this.mbrVO); |
|
318 | 323 |
this.changeFormat(); // 휴대폰번호, 전화번호, 이메일 표기변경 |
319 | 324 |
} catch (error) { |
320 | 325 |
const errorData = error.response.data; |
... | ... | @@ -402,6 +407,35 @@ |
402 | 407 |
} |
403 | 408 |
} |
404 | 409 |
}, |
410 |
+ |
|
411 |
+ |
|
412 |
+ // 회원탈퇴 |
|
413 |
+ ...mapActions(["logout"]), |
|
414 |
+ async fnSelfDelete() { |
|
415 |
+ if (this.mbrVO.sysPvsnYn == 0) { |
|
416 |
+ alert("시스템에서 제공하는 정보는 삭제할 수 없습니다."); |
|
417 |
+ return; |
|
418 |
+ } |
|
419 |
+ var isDelete = confirm("정말로 회원탈퇴 하시겠습니까?"); |
|
420 |
+ if (!isDelete) { |
|
421 |
+ return; |
|
422 |
+ } |
|
423 |
+ // 데이터 세팅 |
|
424 |
+ let data = this.mbrVO; |
|
425 |
+ // 실행 |
|
426 |
+ try { |
|
427 |
+ const response = await mbrDeleteProc(data); |
|
428 |
+ alert(response.data["message"]); |
|
429 |
+ await this.logout(); |
|
430 |
+ } catch (error) { |
|
431 |
+ const errorData = error.response.data; |
|
432 |
+ if (errorData.message != null && errorData.message != "") { |
|
433 |
+ alert(error.response.data.message); |
|
434 |
+ } else { |
|
435 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
436 |
+ } |
|
437 |
+ } |
|
438 |
+ }, |
|
405 | 439 |
}, |
406 | 440 |
}; |
407 | 441 |
</script> |
--- client/views/pages/user/portal/myPage/myInfo/MyInfoView.vue
+++ client/views/pages/user/portal/myPage/myInfo/MyInfoView.vue
... | ... | @@ -5,13 +5,34 @@ |
5 | 5 |
<p>내 정보</p> |
6 | 6 |
</div> |
7 | 7 |
|
8 |
- <UserInfoView :pageId="pageId" /> |
|
8 |
+ <UserInfoView :pageId="pageId" @child-mbrVO="mbrVO = $event"/> |
|
9 |
+ <div> |
|
10 |
+ <p>SNS 계정 연동 설정</p> |
|
11 |
+ </div> |
|
12 |
+ <div> |
|
13 |
+ <div v-for="link in linkList" :key="link.id" class="sns-link-item"> |
|
14 |
+ <div v-if="linkList.length > 1 && link.lgnOffrType !== 'S'"> |
|
15 |
+ <div class="sns-link-info"> |
|
16 |
+ <span>{{ convertOffrType(link.lgnOffrType) }}</span> |
|
17 |
+ <!-- <span>{{ link.snsEml }}</span> --> |
|
18 |
+ </div> |
|
19 |
+ <div class="switch-container"> |
|
20 |
+ <label class="switch"> |
|
21 |
+ <input type="checkbox" v-model="link.linkVtlzYn" @change="toggleLink(link)"> |
|
22 |
+ <span class="slider"></span> |
|
23 |
+ </label> |
|
24 |
+ <p>{{ link.linkVtlzYn ? '연동' : '해제' }}</p> |
|
25 |
+ </div> |
|
26 |
+ </div> |
|
27 |
+ </div> |
|
28 |
+ </div> |
|
9 | 29 |
</div> |
10 | 30 |
</div> |
11 | 31 |
</template> |
12 | 32 |
|
13 | 33 |
<script> |
14 | 34 |
import pageAuthMixin from "../../../../../../views/common/pageAuthMixin.js"; |
35 |
+import { findAllLink, unlinkAccount, reLinkAccount, setPrimaryProfile } from "../../../../../../resources/api/unified.js"; |
|
15 | 36 |
// COMPONENETS |
16 | 37 |
import UserInfoView from "../../../../../component/userInfo/UserInfoView.vue"; |
17 | 38 |
|
... | ... | @@ -23,7 +44,121 @@ |
23 | 44 |
data() { |
24 | 45 |
return { |
25 | 46 |
pageId: this.$store.state.mbrId, // 페이지 아이디 |
47 |
+ |
|
48 |
+ linkList: [], // 연동된 계정 목록 |
|
49 |
+ mbrVO: {}, |
|
26 | 50 |
}; |
27 | 51 |
}, |
52 |
+ created() { |
|
53 |
+ this.findAllLink(); // 연동된 계정 목록 조회 |
|
54 |
+ }, |
|
55 |
+ methods: { |
|
56 |
+ // 연동된 계정 목록 조회 |
|
57 |
+ async findAllLink() { |
|
58 |
+ try { |
|
59 |
+ const res = await findAllLink(); |
|
60 |
+ if (res.status == 200) { |
|
61 |
+ this.linkList = res.data.data; |
|
62 |
+ } |
|
63 |
+ } catch (error) { |
|
64 |
+ const errorData = error.response?.data; |
|
65 |
+ if (errorData?.message != null && errorData?.message != "") { |
|
66 |
+ alert(error.response.data.message); |
|
67 |
+ } else { |
|
68 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
69 |
+ } |
|
70 |
+ } |
|
71 |
+ }, |
|
72 |
+ |
|
73 |
+ // 연동 버튼 클릭 |
|
74 |
+ async toggleLink(link) { |
|
75 |
+ const checked = link.linkVtlzYn; |
|
76 |
+ if (!confirm(checked ? "연동을 설정하시겠습니까?" : "연동을 해제하시겠습니까?")) { |
|
77 |
+ link.linkVtlzYn = !checked; // 체크박스 상태 되돌리기 |
|
78 |
+ return; |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ const proc = checked ? reLinkAccount : unlinkAccount; |
|
82 |
+ try { |
|
83 |
+ const res = await proc({ lgnOffrType: link.lgnOffrType }); |
|
84 |
+ if (res.status == 200) { |
|
85 |
+ alert(res.data.message); |
|
86 |
+ } |
|
87 |
+ } catch (error) { |
|
88 |
+ const errorData = error.response?.data; |
|
89 |
+ if (errorData?.message != null && errorData?.message != "") { |
|
90 |
+ alert(error.response.data.message); |
|
91 |
+ } else { |
|
92 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
93 |
+ } |
|
94 |
+ } |
|
95 |
+ }, |
|
96 |
+ |
|
97 |
+ // SNS 계정 타입 변환 |
|
98 |
+ convertOffrType(code) { |
|
99 |
+ switch (code) { |
|
100 |
+ case 'G': return '구글'; |
|
101 |
+ case 'K': return '카카오'; |
|
102 |
+ case 'N': return '네이버'; |
|
103 |
+ case 'S': return '시스템'; |
|
104 |
+ default: return '기타'; |
|
105 |
+ } |
|
106 |
+ } |
|
107 |
+ }, |
|
28 | 108 |
}; |
29 |
-</script>(파일 끝에 줄바꿈 문자 없음) |
|
109 |
+</script> |
|
110 |
+ |
|
111 |
+<style scoped> |
|
112 |
+.switch-container { |
|
113 |
+ display: flex; |
|
114 |
+ align-items: center; |
|
115 |
+ gap: 10px; |
|
116 |
+ font-family: Arial, sans-serif; |
|
117 |
+} |
|
118 |
+ |
|
119 |
+.switch { |
|
120 |
+ position: relative; |
|
121 |
+ display: inline-block; |
|
122 |
+ width: 50px; |
|
123 |
+ height: 28px; |
|
124 |
+} |
|
125 |
+ |
|
126 |
+.switch input { |
|
127 |
+ opacity: 0; |
|
128 |
+ width: 0; |
|
129 |
+ height: 0; |
|
130 |
+} |
|
131 |
+ |
|
132 |
+.slider { |
|
133 |
+ position: absolute; |
|
134 |
+ cursor: pointer; |
|
135 |
+ background-color: #ccc; |
|
136 |
+ transition: 0.4s; |
|
137 |
+ border-radius: 34px; |
|
138 |
+ top: 0; |
|
139 |
+ left: 0; |
|
140 |
+ right: 0; |
|
141 |
+ bottom: 0; |
|
142 |
+} |
|
143 |
+ |
|
144 |
+.slider:before { |
|
145 |
+ position: absolute; |
|
146 |
+ content: ""; |
|
147 |
+ height: 20px; |
|
148 |
+ width: 20px; |
|
149 |
+ left: 4px; |
|
150 |
+ bottom: 4px; |
|
151 |
+ background-color: white; |
|
152 |
+ transition: 0.4s; |
|
153 |
+ border-radius: 50%; |
|
154 |
+} |
|
155 |
+ |
|
156 |
+/* Checked 상태일 때 */ |
|
157 |
+input:checked+.slider { |
|
158 |
+ background-color: #4caf50; |
|
159 |
+} |
|
160 |
+ |
|
161 |
+input:checked+.slider:before { |
|
162 |
+ transform: translateX(22px); |
|
163 |
+} |
|
164 |
+</style>(파일 끝에 줄바꿈 문자 없음) |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?