Merge branch 'main' into wordDict
This commit is contained in:
commit
646c775d6a
38
src/common/commonApi.js
Normal file
38
src/common/commonApi.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
작성자 : 박지윤
|
||||||
|
작성일 : 2025-02-04
|
||||||
|
수정자 :
|
||||||
|
수정일 :
|
||||||
|
설명 : 공통 api
|
||||||
|
*/
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import $api from '@api';
|
||||||
|
|
||||||
|
const commonApi = () => {
|
||||||
|
const colorList = ref([]);
|
||||||
|
const mbtiList = ref([]);
|
||||||
|
const pwhintList = ref([]);
|
||||||
|
|
||||||
|
const CommonCode = async (endpoint, targetList) => {
|
||||||
|
try {
|
||||||
|
const response = await $api.get(`/user/${endpoint}`);
|
||||||
|
targetList.value = response.data.data.map(item => ({
|
||||||
|
label: item.CMNCODNAM,
|
||||||
|
value: item.CMNCODVAL
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching ${endpoint}:`, error);
|
||||||
|
targetList.value = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await CommonCode("color", colorList);
|
||||||
|
await CommonCode("mbti", mbtiList);
|
||||||
|
await CommonCode("pwhint", pwhintList);
|
||||||
|
});
|
||||||
|
|
||||||
|
return { colorList, mbtiList, pwhintList };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default commonApi;
|
||||||
@ -16,7 +16,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch, watchEffect } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
title: {
|
||||||
@ -69,13 +69,16 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['update:data']);
|
const emit = defineEmits(['update:data']);
|
||||||
const selectData = ref(props.value);
|
const selectData = ref(props.value);
|
||||||
|
|
||||||
|
// data 변경 감지
|
||||||
watchEffect(() => {
|
watch(() => props.data, (newData) => {
|
||||||
if (props.isCommon && props.data.length > 0) {
|
if (props.isCommon && newData.length > 0) {
|
||||||
selectData.value = props.data[0].value; // 첫 번째 옵션의 값으로 설정
|
selectData.value = newData[0].value;
|
||||||
} else {
|
emit('update:data', selectData.value);
|
||||||
selectData.value = props.value; // 기본값으로 설정
|
|
||||||
}
|
}
|
||||||
emit('update:data', selectData.value);
|
}, { immediate: true });
|
||||||
})
|
|
||||||
|
// selectData 변경 감지
|
||||||
|
watch(selectData, (newValue) => {
|
||||||
|
emit('update:data', newValue);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
:id="name"
|
:id="name"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:type="type"
|
:type="type"
|
||||||
|
:max="type === 'date' ? today : null"
|
||||||
@input="updateInput"
|
@input="updateInput"
|
||||||
:value="computedValue"
|
:value="computedValue"
|
||||||
:maxLength="maxlength"
|
:maxLength="maxlength"
|
||||||
|
|||||||
@ -0,0 +1,173 @@
|
|||||||
|
<template>
|
||||||
|
<div class="col-xl-12">
|
||||||
|
<UserFormInput
|
||||||
|
title="아이디"
|
||||||
|
name="id"
|
||||||
|
:is-alert="idAlert"
|
||||||
|
:is-essential="true"
|
||||||
|
:useInputGroup="true"
|
||||||
|
@update:data="handleIdChange"
|
||||||
|
:value="id"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<UserFormInput
|
||||||
|
title="생년월일"
|
||||||
|
name="birth"
|
||||||
|
:type="'date'"
|
||||||
|
:is-essential="true"
|
||||||
|
:is-alert="birthAlert"
|
||||||
|
@update:data="birth = $event"
|
||||||
|
@update:alert="birthAlert = $event"
|
||||||
|
:value="birth"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormSelect
|
||||||
|
title="비밀번호 힌트"
|
||||||
|
name="pwhint"
|
||||||
|
:is-essential="true"
|
||||||
|
:is-row="false"
|
||||||
|
:is-label="true"
|
||||||
|
:is-common="true"
|
||||||
|
:data="pwhintList"
|
||||||
|
@update:data="pwhint = $event"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<UserFormInput
|
||||||
|
title="답변"
|
||||||
|
name="pwhintRes"
|
||||||
|
:is-essential="true"
|
||||||
|
:is-alert="pwhintResAlert"
|
||||||
|
@update:data="pwhintRes = $event"
|
||||||
|
@update:alert="pwhintResAlert = $event"
|
||||||
|
:value="pwhintRes"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="d-flex mt-5">
|
||||||
|
<RouterLink type="button" class="btn btn-secondary me-2 w-50" to="/login">취소</RouterLink>
|
||||||
|
<button type="button" @click="handleSubmit" class="btn btn-primary w-50">확인</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="resetForm" class="mt-4">
|
||||||
|
<UserFormInput
|
||||||
|
title="새 비밀번호"
|
||||||
|
name="pw"
|
||||||
|
type="password"
|
||||||
|
:isEssential="true"
|
||||||
|
:is-alert="passwordAlert"
|
||||||
|
@update:data="password = $event"
|
||||||
|
@update:alert="passwordAlert = $event"
|
||||||
|
:value="password"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<UserFormInput
|
||||||
|
title="비밀번호 확인"
|
||||||
|
name="pwch"
|
||||||
|
type="password"
|
||||||
|
:isEssential="true"
|
||||||
|
:is-alert="passwordcheckAlert"
|
||||||
|
@update:data="passwordcheck = $event"
|
||||||
|
@update:alert="passwordcheckAlert = $event"
|
||||||
|
@blur="checkPw"
|
||||||
|
:value="passwordcheck"
|
||||||
|
/>
|
||||||
|
<span v-if="passwordcheckError" class="invalid-feedback d-block">{{ passwordcheckError }}</span>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2 mt-5 mb-5">
|
||||||
|
<button type="button" @click="handleNewPassword" class="btn btn-primary">확인</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import $api from '@api';
|
||||||
|
import commonApi from '@/common/commonApi';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { useToastStore } from '@s/toastStore';
|
||||||
|
import UserFormInput from '@c/input/UserFormInput.vue';
|
||||||
|
import FormSelect from '../input/FormSelect.vue';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const toastStore = useToastStore();
|
||||||
|
|
||||||
|
const id = ref('');
|
||||||
|
const birth = ref('');
|
||||||
|
const pwhint = ref('');
|
||||||
|
const pwhintRes = ref('');
|
||||||
|
|
||||||
|
const idAlert = ref(false);
|
||||||
|
const birthAlert = ref(false);
|
||||||
|
const pwhintResAlert = ref(false);
|
||||||
|
const resetForm = ref(false);
|
||||||
|
|
||||||
|
const password = ref('');
|
||||||
|
const passwordcheck = ref('');
|
||||||
|
const passwordcheckError = ref('');
|
||||||
|
|
||||||
|
const passwordAlert = ref(false);
|
||||||
|
const passwordcheckAlert = ref(false);
|
||||||
|
const passwordcheckErrorAlert = ref(false);
|
||||||
|
|
||||||
|
const { pwhintList } = commonApi();
|
||||||
|
|
||||||
|
const handleIdChange = value => {
|
||||||
|
id.value = value;
|
||||||
|
idAlert.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 아이디, 생년월일, 비밀번호 힌트, 답변이 일치하는 member 재설정 input 보이기
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
idAlert.value = id.value.trim() === '';
|
||||||
|
pwhintResAlert.value = pwhintRes.value.trim() === '';
|
||||||
|
birthAlert.value = birth.value.trim() === '';
|
||||||
|
|
||||||
|
if (idAlert.value || pwhintResAlert.value || birthAlert.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await $api.post('user/pwReset', {
|
||||||
|
id: id.value,
|
||||||
|
birth: birth.value,
|
||||||
|
pwhint: pwhint.value,
|
||||||
|
pwhintRes: pwhintRes.value,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status === 200 && response.data.data === true) {
|
||||||
|
resetForm.value = true;
|
||||||
|
} else {
|
||||||
|
toastStore.onToast('일치하는 정보가 없습니다.', 'e');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkPw = async () => {
|
||||||
|
if (password.value !== passwordcheck.value) {
|
||||||
|
passwordcheckError.value = '비밀번호가 일치하지 않습니다.';
|
||||||
|
passwordcheckErrorAlert.value = true;
|
||||||
|
} else {
|
||||||
|
passwordcheckError.value = '';
|
||||||
|
passwordcheckErrorAlert.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 비밀번호 업데이트
|
||||||
|
const handleNewPassword = async () => {
|
||||||
|
passwordAlert.value = password.value.trim() === '';
|
||||||
|
passwordcheckAlert.value = passwordcheck.value.trim() === '';
|
||||||
|
|
||||||
|
if (passwordAlert.value || passwordcheckAlert.value || passwordcheckErrorAlert.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await $api.patch('user/pwNew', {
|
||||||
|
id: id.value,
|
||||||
|
password: password.value
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status === 200 && response.data.data === true) {
|
||||||
|
toastStore.onToast('비밀번호가 재설정 되었습니다.', 's');
|
||||||
|
router.push('/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<div class="mb-3 d-flex justify-content-around">
|
<div class="mb-3 d-flex justify-content-around">
|
||||||
<div>
|
<div>
|
||||||
<input type="checkbox" class="form-check-input" id="rememberCheck" />
|
<input type="checkbox" class="form-check-input" id="rememberCheck" v-model="remember" />
|
||||||
<label class="form-check-label fw-bold" for="rememberCheck"> 자동로그인</label>
|
<label class="form-check-label fw-bold" for="rememberCheck"> 자동로그인</label>
|
||||||
</div>
|
</div>
|
||||||
<RouterLink class="text-dark fw-bold" to="/register">등록신청</RouterLink>
|
<RouterLink class="text-dark fw-bold" to="/register">등록신청</RouterLink>
|
||||||
@ -40,11 +40,17 @@
|
|||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import UserFormInput from '@c/input/UserFormInput.vue';
|
import UserFormInput from '@c/input/UserFormInput.vue';
|
||||||
|
import { useUserStore } from '@s/useUserStore';
|
||||||
|
import { useToastStore } from '@s/toastStore';
|
||||||
|
|
||||||
const id = ref('');
|
const id = ref('');
|
||||||
const password = ref('');
|
const password = ref('');
|
||||||
const idAlert = ref(false);
|
const idAlert = ref(false);
|
||||||
const passwordAlert = ref(false);
|
const passwordAlert = ref(false);
|
||||||
|
const remember = ref(false);
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const toastStore = useToastStore();
|
||||||
|
|
||||||
const handleIdChange = value => {
|
const handleIdChange = value => {
|
||||||
id.value = value;
|
id.value = value;
|
||||||
@ -57,21 +63,19 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
|
const response = await $api.post('user/login', {
|
||||||
|
loginId: id.value,
|
||||||
|
password: password.value,
|
||||||
|
remember: remember.value,
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
if (response.status === 200) {
|
||||||
const response = await $api.post('user/login', {
|
await userStore.userInfo();
|
||||||
loginId: id.value,
|
router.push('/');
|
||||||
password: password.value,
|
} else {
|
||||||
remember: false,
|
toastStore.onToast('아이디 혹은 비밀번호가 틀렸습니다.', 'e');
|
||||||
});
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
console.log('로그인 성공', response.data);
|
|
||||||
router.push('/');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('로그인 실패', error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<h2>{{ title }}</h2>
|
<h3 class="fw-bold">{{ title }}</h3>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -58,9 +58,11 @@
|
|||||||
:is-essential="true"
|
:is-essential="true"
|
||||||
:is-row="false"
|
:is-row="false"
|
||||||
:is-label="true"
|
:is-label="true"
|
||||||
|
:is-common="true"
|
||||||
:data="pwhintList"
|
:data="pwhintList"
|
||||||
@update:data="pwhint = $event"
|
@update:data="pwhint = $event"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UserFormInput
|
<UserFormInput
|
||||||
title="답변"
|
title="답변"
|
||||||
name="pwhintRes"
|
name="pwhintRes"
|
||||||
@ -152,8 +154,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref } from 'vue';
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
|
import commonApi from '@/common/commonApi'
|
||||||
import UserFormInput from '@c/input/UserFormInput.vue';
|
import UserFormInput from '@c/input/UserFormInput.vue';
|
||||||
import FormSelect from '@c/input/FormSelect.vue';
|
import FormSelect from '@c/input/FormSelect.vue';
|
||||||
import ArrInput from '@c/input/ArrInput.vue';
|
import ArrInput from '@c/input/ArrInput.vue';
|
||||||
@ -161,8 +164,6 @@
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useToastStore } from '@s/toastStore';
|
import { useToastStore } from '@s/toastStore';
|
||||||
|
|
||||||
const pwhintList = ['현재 살고 있는 동네', '가장 기억에 남는 책', '좋아하는 음식'];
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const profile = ref(null);
|
const profile = ref(null);
|
||||||
@ -173,7 +174,6 @@
|
|||||||
const password = ref('');
|
const password = ref('');
|
||||||
const passwordcheck = ref('');
|
const passwordcheck = ref('');
|
||||||
const passwordcheckError = ref('');
|
const passwordcheckError = ref('');
|
||||||
const pwhint = ref(0);
|
|
||||||
const pwhintRes = ref('');
|
const pwhintRes = ref('');
|
||||||
const name = ref('');
|
const name = ref('');
|
||||||
const birth = ref('');
|
const birth = ref('');
|
||||||
@ -181,10 +181,9 @@
|
|||||||
const detailAddress = ref('');
|
const detailAddress = ref('');
|
||||||
const postcode = ref(''); // 우편번호
|
const postcode = ref(''); // 우편번호
|
||||||
const phone = ref('');
|
const phone = ref('');
|
||||||
const colorList = ref([]);
|
|
||||||
const mbtiList = ref([]);
|
|
||||||
const color = ref(''); // 선택된 color
|
const color = ref(''); // 선택된 color
|
||||||
const mbti = ref(''); // 선택된 MBTI
|
const mbti = ref(''); // 선택된 MBTI
|
||||||
|
const pwhint = ref(''); // 선택된 pwhint
|
||||||
|
|
||||||
const profilAlert = ref(false);
|
const profilAlert = ref(false);
|
||||||
const idAlert = ref(false);
|
const idAlert = ref(false);
|
||||||
@ -252,27 +251,8 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Colors = async () => {
|
// 컬러, mbti, 비밀번호 힌트 목록 불러오기
|
||||||
const response = await $api.get('/user/color');
|
const { colorList, mbtiList, pwhintList } = commonApi();
|
||||||
colorList.value = response.data.data.map(item => ({
|
|
||||||
label: item.CMNCODNAM,
|
|
||||||
value: item.CMNCODVAL
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const Mbtis = async () => {
|
|
||||||
const response = await $api.get('/user/mbti');
|
|
||||||
mbtiList.value = response.data.data.map(item => ({
|
|
||||||
label: item.CMNCODNAM,
|
|
||||||
value: item.CMNCODVAL
|
|
||||||
}));
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
Colors();
|
|
||||||
Mbtis();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 주소 업데이트 핸들러
|
// 주소 업데이트 핸들러
|
||||||
const handleAddressUpdate = (addressData) => {
|
const handleAddressUpdate = (addressData) => {
|
||||||
@ -295,50 +275,50 @@
|
|||||||
// 회원가입
|
// 회원가입
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
|
|
||||||
idAlert.value = id.value.trim() === '';
|
idAlert.value = id.value.trim() === '';
|
||||||
passwordAlert.value = password.value.trim() === '';
|
passwordAlert.value = password.value.trim() === '';
|
||||||
passwordcheckAlert.value = passwordcheck.value.trim() === '';
|
passwordcheckAlert.value = passwordcheck.value.trim() === '';
|
||||||
pwhintResAlert.value = pwhintRes.value.trim() === '';
|
pwhintResAlert.value = pwhintRes.value.trim() === '';
|
||||||
nameAlert.value = name.value.trim() === '';
|
nameAlert.value = name.value.trim() === '';
|
||||||
birthAlert.value = birth.value.trim() === '';
|
birthAlert.value = birth.value.trim() === '';
|
||||||
addressAlert.value = address.value.trim() === '';
|
addressAlert.value = address.value.trim() === '';
|
||||||
phoneAlert.value = phone.value.trim() === '';
|
phoneAlert.value = phone.value.trim() === '';
|
||||||
|
|
||||||
// 프로필 이미지 체크
|
// 프로필 이미지 체크
|
||||||
if (!profile.value) {
|
if (!profile.value) {
|
||||||
profilerr.value = '프로필 이미지를 선택해주세요.';
|
profilerr.value = '프로필 이미지를 선택해주세요.';
|
||||||
profilAlert.value = true;
|
profilAlert.value = true;
|
||||||
} else {
|
} else {
|
||||||
profilerr.value = '';
|
profilerr.value = '';
|
||||||
profilAlert.value = false;
|
profilAlert.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profilAlert.value || idAlert.value || idErrorAlert.value || passwordAlert.value || passwordcheckAlert.value ||
|
if (profilAlert.value || idAlert.value || idErrorAlert.value || passwordAlert.value || passwordcheckAlert.value ||
|
||||||
passwordcheckErrorAlert.value || pwhintResAlert.value || nameAlert.value || birthAlert.value || addressAlert.value || phoneAlert.value) {
|
passwordcheckErrorAlert.value || pwhintResAlert.value || nameAlert.value || birthAlert.value || addressAlert.value || phoneAlert.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('memberIds', id.value);
|
formData.append('memberIds', id.value);
|
||||||
formData.append('memberPwd', password.value);
|
formData.append('memberPwd', password.value);
|
||||||
formData.append('memberPwh', pwhintList[pwhint.value]);
|
formData.append('memberPwh', pwhint.value);
|
||||||
formData.append('memberPwr', pwhintRes.value);
|
formData.append('memberPwr', pwhintRes.value);
|
||||||
formData.append('memberNam', name.value);
|
formData.append('memberNam', name.value);
|
||||||
formData.append('memberArr', address.value);
|
formData.append('memberArr', address.value);
|
||||||
formData.append('memberDtl', detailAddress.value);
|
formData.append('memberDtl', detailAddress.value);
|
||||||
formData.append('memberZip', postcode.value);
|
formData.append('memberZip', postcode.value);
|
||||||
formData.append('memberBth', birth.value);
|
formData.append('memberBth', birth.value);
|
||||||
formData.append('memberTel', phone.value);
|
formData.append('memberTel', phone.value);
|
||||||
formData.append('memberCol', color.value);
|
formData.append('memberCol', color.value);
|
||||||
formData.append('memberMbt', mbti.value);
|
formData.append('memberMbt', mbti.value);
|
||||||
formData.append('memberPrf', profile.value);
|
formData.append('memberPrf', profile.value);
|
||||||
|
|
||||||
const response = await $api.post('/user/join', formData, { isFormData : true });
|
const response = await $api.post('/user/join', formData, { isFormData : true });
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
toastStore.onToast('등록신청이 완료되었습니다. 관리자 승인 후 이용가능합니다.', 's');
|
toastStore.onToast('등록신청이 완료되었습니다. 관리자 승인 후 이용가능합니다.', 's');
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -8,161 +8,14 @@
|
|||||||
|
|
||||||
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
|
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
|
||||||
<ul class="navbar-nav flex-row align-items-center ms-auto">
|
<ul class="navbar-nav flex-row align-items-center ms-auto">
|
||||||
<!-- Language -->
|
|
||||||
<li class="nav-item dropdown-language dropdown me-2 me-xl-0">
|
|
||||||
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown">
|
|
||||||
<i class="bx bx-globe bx-md"></i>
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="javascript:void(0);" data-language="en" data-text-direction="ltr">
|
|
||||||
<span>English</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="javascript:void(0);" data-language="fr" data-text-direction="ltr">
|
|
||||||
<span>French</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="javascript:void(0);" data-language="ar" data-text-direction="rtl">
|
|
||||||
<span>Arabic</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="javascript:void(0);" data-language="de" data-text-direction="ltr">
|
|
||||||
<span>German</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<!-- /Language -->
|
|
||||||
|
|
||||||
<!-- Style Switcher -->
|
<button class="btn p-1" @click="switchToLightMode"><i class='bx bxs-sun link-warning'></i></button>
|
||||||
<li class="nav-item dropdown-style-switcher dropdown me-2 me-xl-0">
|
<button class="btn p-1" @click="switchToDarkMode"><i class='bx bxs-moon' ></i></button>
|
||||||
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown">
|
|
||||||
<i class="bx bx-md"></i>
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end dropdown-styles">
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="javascript:void(0);" data-theme="light">
|
|
||||||
<span><i class="bx bx-sun bx-md me-3"></i>Light</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="javascript:void(0);" data-theme="dark">
|
|
||||||
<span><i class="bx bx-moon bx-md me-3"></i>Dark</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="javascript:void(0);" data-theme="system">
|
|
||||||
<span><i class="bx bx-desktop bx-md me-3"></i>System</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<!-- / Style Switcher-->
|
|
||||||
|
|
||||||
<!-- Quick links -->
|
<i class="bx bx-bell bx-md bx-log-out cursor-pointer p-1" @click="handleLogout"></i>
|
||||||
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
|
|
||||||
<a
|
|
||||||
class="nav-link dropdown-toggle hide-arrow"
|
|
||||||
href="javascript:void(0);"
|
|
||||||
data-bs-toggle="dropdown"
|
|
||||||
data-bs-auto-close="outside"
|
|
||||||
aria-expanded="false"
|
|
||||||
>
|
|
||||||
<i class="bx bx-grid-alt bx-md"></i>
|
|
||||||
</a>
|
|
||||||
<div class="dropdown-menu dropdown-menu-end p-0">
|
|
||||||
<div class="dropdown-menu-header border-bottom">
|
|
||||||
<div class="dropdown-header d-flex align-items-center py-3">
|
|
||||||
<h6 class="mb-0 me-auto">Shortcuts</h6>
|
|
||||||
<a
|
|
||||||
href="javascript:void(0)"
|
|
||||||
class="dropdown-shortcuts-add py-2"
|
|
||||||
data-bs-toggle="tooltip"
|
|
||||||
data-bs-placement="top"
|
|
||||||
title="Add shortcuts"
|
|
||||||
><i class="bx bx-plus-circle text-heading"></i
|
|
||||||
></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown-shortcuts-list scrollable-container">
|
|
||||||
<div class="row row-bordered overflow-visible g-0">
|
|
||||||
<div class="dropdown-shortcuts-item col">
|
|
||||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
||||||
<i class="bx bx-calendar bx-26px text-heading"></i>
|
|
||||||
</span>
|
|
||||||
<a href="app-calendar.html" class="stretched-link">Calendar</a>
|
|
||||||
<small>Appointments</small>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown-shortcuts-item col">
|
|
||||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
||||||
<i class="bx bx-food-menu bx-26px text-heading"></i>
|
|
||||||
</span>
|
|
||||||
<a href="app-invoice-list.html" class="stretched-link">Invoice App</a>
|
|
||||||
<small>Manage Accounts</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row row-bordered overflow-visible g-0">
|
|
||||||
<div class="dropdown-shortcuts-item col">
|
|
||||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
||||||
<i class="bx bx-user bx-26px text-heading"></i>
|
|
||||||
</span>
|
|
||||||
<a href="app-user-list.html" class="stretched-link">User App</a>
|
|
||||||
<small>Manage Users</small>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown-shortcuts-item col">
|
|
||||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
||||||
<i class="bx bx-check-shield bx-26px text-heading"></i>
|
|
||||||
</span>
|
|
||||||
<a href="app-access-roles.html" class="stretched-link">Role Management</a>
|
|
||||||
<small>Permission</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row row-bordered overflow-visible g-0">
|
|
||||||
<div class="dropdown-shortcuts-item col">
|
|
||||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
||||||
<i class="bx bx-pie-chart-alt-2 bx-26px text-heading"></i>
|
|
||||||
</span>
|
|
||||||
<a href="index.html" class="stretched-link">Dashboard</a>
|
|
||||||
<small>User Dashboard</small>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown-shortcuts-item col">
|
|
||||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
||||||
<i class="bx bx-cog bx-26px text-heading"></i>
|
|
||||||
</span>
|
|
||||||
<a href="pages-account-settings-account.html" class="stretched-link">Setting</a>
|
|
||||||
<small>Account Settings</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row row-bordered overflow-visible g-0">
|
|
||||||
<div class="dropdown-shortcuts-item col">
|
|
||||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
||||||
<i class="bx bx-help-circle bx-26px text-heading"></i>
|
|
||||||
</span>
|
|
||||||
<a href="pages-faq.html" class="stretched-link">FAQs</a>
|
|
||||||
<small>FAQs & Articles</small>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown-shortcuts-item col">
|
|
||||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
|
||||||
<i class="bx bx-window-open bx-26px text-heading"></i>
|
|
||||||
</span>
|
|
||||||
<a href="modal-examples.html" class="stretched-link">Modals</a>
|
|
||||||
<small>Useful Popups</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<!-- Quick links -->
|
|
||||||
|
|
||||||
<button @click="switchToDarkMode">다크 모드</button>
|
|
||||||
<button @click="switchToLightMode">라이트 모드</button>
|
|
||||||
|
|
||||||
<!-- Notification -->
|
<!-- Notification -->
|
||||||
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-2">
|
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-2 p-1">
|
||||||
<a
|
<a
|
||||||
class="nav-link dropdown-toggle hide-arrow"
|
class="nav-link dropdown-toggle hide-arrow"
|
||||||
href="javascript:void(0);"
|
href="javascript:void(0);"
|
||||||
@ -284,120 +137,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="flex-shrink-0 me-3">
|
|
||||||
<div class="avatar">
|
|
||||||
<img src="/img/avatars/9.png" class="rounded-circle" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1">
|
|
||||||
<h6 class="small mb-0">Application has been approved 🚀</h6>
|
|
||||||
<small class="mb-1 d-block text-body">Your ABC project application has been approved.</small>
|
|
||||||
<small class="text-muted">2 days ago</small>
|
|
||||||
</div>
|
|
||||||
<div class="flex-shrink-0 dropdown-notifications-actions">
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-read"
|
|
||||||
><span class="badge badge-dot"></span
|
|
||||||
></a>
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-archive"
|
|
||||||
><span class="bx bx-x"></span
|
|
||||||
></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="flex-shrink-0 me-3">
|
|
||||||
<div class="avatar">
|
|
||||||
<span class="avatar-initial rounded-circle bg-label-success"
|
|
||||||
><i class="bx bx-pie-chart-alt"></i
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1">
|
|
||||||
<h6 class="small mb-0">Monthly report is generated</h6>
|
|
||||||
<small class="mb-1 d-block text-body">July monthly financial report is generated </small>
|
|
||||||
<small class="text-muted">3 days ago</small>
|
|
||||||
</div>
|
|
||||||
<div class="flex-shrink-0 dropdown-notifications-actions">
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-read"
|
|
||||||
><span class="badge badge-dot"></span
|
|
||||||
></a>
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-archive"
|
|
||||||
><span class="bx bx-x"></span
|
|
||||||
></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="flex-shrink-0 me-3">
|
|
||||||
<div class="avatar">
|
|
||||||
<img src="/img/avatars/5.png" class="rounded-circle" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1">
|
|
||||||
<h6 class="small mb-0">Send connection request</h6>
|
|
||||||
<small class="mb-1 d-block text-body">Peter sent you connection request</small>
|
|
||||||
<small class="text-muted">4 days ago</small>
|
|
||||||
</div>
|
|
||||||
<div class="flex-shrink-0 dropdown-notifications-actions">
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-read"
|
|
||||||
><span class="badge badge-dot"></span
|
|
||||||
></a>
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-archive"
|
|
||||||
><span class="bx bx-x"></span
|
|
||||||
></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item list-group-item-action dropdown-notifications-item">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="flex-shrink-0 me-3">
|
|
||||||
<div class="avatar">
|
|
||||||
<img src="/img/avatars/6.png" class="rounded-circle" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1">
|
|
||||||
<h6 class="small mb-0">New message from Jane</h6>
|
|
||||||
<small class="mb-1 d-block text-body">Your have new message from Jane</small>
|
|
||||||
<small class="text-muted">5 days ago</small>
|
|
||||||
</div>
|
|
||||||
<div class="flex-shrink-0 dropdown-notifications-actions">
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-read"
|
|
||||||
><span class="badge badge-dot"></span
|
|
||||||
></a>
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-archive"
|
|
||||||
><span class="bx bx-x"></span
|
|
||||||
></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="flex-shrink-0 me-3">
|
|
||||||
<div class="avatar">
|
|
||||||
<span class="avatar-initial rounded-circle bg-label-warning"
|
|
||||||
><i class="bx bx-error"></i
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1">
|
|
||||||
<h6 class="small mb-0">CPU is running high</h6>
|
|
||||||
<small class="mb-1 d-block text-body">CPU Utilization Percent is currently at 88.63%,</small>
|
|
||||||
<small class="text-muted">5 days ago</small>
|
|
||||||
</div>
|
|
||||||
<div class="flex-shrink-0 dropdown-notifications-actions">
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-read"
|
|
||||||
><span class="badge badge-dot"></span
|
|
||||||
></a>
|
|
||||||
<a href="javascript:void(0)" class="dropdown-notifications-archive"
|
|
||||||
><span class="bx bx-x"></span
|
|
||||||
></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="border-top">
|
<li class="border-top">
|
||||||
@ -413,9 +152,7 @@
|
|||||||
<!-- User -->
|
<!-- User -->
|
||||||
<li class="nav-item navbar-dropdown dropdown-user dropdown">
|
<li class="nav-item navbar-dropdown dropdown-user dropdown">
|
||||||
<a class="nav-link dropdown-toggle hide-arrow p-0" href="javascript:void(0);" data-bs-toggle="dropdown">
|
<a class="nav-link dropdown-toggle hide-arrow p-0" href="javascript:void(0);" data-bs-toggle="dropdown">
|
||||||
<div class="avatar avatar-online">
|
<img v-if="user" :src="`http://localhost:10325/upload/img/profile/${user.profile}`" alt="Profile Image" class="w-px-40 h-auto rounded-circle"/>
|
||||||
<img src="/img/avatars/1.png" class="w-px-40 h-auto rounded-circle" />
|
|
||||||
</div>
|
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
<li>
|
<li>
|
||||||
@ -490,17 +227,38 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { useAuthStore } from '@s/useAuthStore';
|
||||||
|
import { useUserStore } from '@s/useUserStore';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
import { useThemeStore } from '@s/darkmode';
|
import { useThemeStore } from '@s/darkmode';
|
||||||
import { onMounted } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
|
const user = ref(null);
|
||||||
|
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const { isDarkMode, switchToDarkMode, switchToLightMode } = useThemeStore();
|
const { isDarkMode, switchToDarkMode, switchToLightMode } = useThemeStore();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
if (isDarkMode) {
|
if (isDarkMode) {
|
||||||
switchToDarkMode();
|
switchToDarkMode();
|
||||||
} else {
|
} else {
|
||||||
switchToLightMode();
|
switchToLightMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await userStore.userInfo();
|
||||||
|
user.value = userStore.user;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleLogout = async () => {
|
||||||
|
await authStore.logout();
|
||||||
|
router.push('/login');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style></style>
|
<style></style>
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import { useAuthStore } from '@s/useAuthStore';
|
||||||
|
|
||||||
|
|
||||||
// 초기 렌더링 속도를 위해 지연 로딩 사용
|
// 초기 렌더링 속도를 위해 지연 로딩 사용
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
name: "Home",
|
||||||
component: () => import('@v/MainView.vue'),
|
component: () => import('@v/MainView.vue'),
|
||||||
// meta: { requiresAuth: true }
|
// meta: { requiresAuth: true }
|
||||||
},
|
},
|
||||||
@ -38,18 +41,26 @@ const routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
|
name: 'Login',
|
||||||
component: () => import('@v/user/TheLogin.vue'),
|
component: () => import('@v/user/TheLogin.vue'),
|
||||||
meta: { layout: 'NoLayout' },
|
meta: { layout: 'NoLayout', requiresGuest: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/register',
|
||||||
|
name: 'Register',
|
||||||
|
component: () => import('@v/user/TheRegister.vue'),
|
||||||
|
meta: { layout: 'NoLayout', requiresGuest: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pw',
|
||||||
|
name: 'Password',
|
||||||
|
component: () => import('@v/user/ThePassword.vue'),
|
||||||
|
meta: { layout: 'NoLayout', requiresGuest: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/vacation',
|
path: '/vacation',
|
||||||
component: () => import('@v/vacation/VacationManagement.vue'),
|
component: () => import('@v/vacation/VacationManagement.vue'),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/register',
|
|
||||||
component: () => import('@v/user/TheRegister.vue'),
|
|
||||||
meta: { layout: 'NoLayout' },
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/voteboard',
|
path: '/voteboard',
|
||||||
component: () => import('@v/voteboard/TheVoteBoard.vue'),
|
component: () => import('@v/voteboard/TheVoteBoard.vue'),
|
||||||
@ -80,4 +91,41 @@ const router = createRouter({
|
|||||||
routes: routes,
|
routes: routes,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
await authStore.checkAuthStatus(); // 로그인 상태 확인
|
||||||
|
|
||||||
|
if (to.meta.requiresAuth && !authStore.isAuthenticated) {
|
||||||
|
// 로그인이 필요한 페이지인데 로그인되지 않은 경우 → 로그인 페이지로 이동
|
||||||
|
next({ name: 'Login' });
|
||||||
|
} else if (to.meta.requiresGuest && authStore.isAuthenticated) {
|
||||||
|
// 비로그인 사용자만 접근 가능한 페이지인데 로그인된 경우 → 홈으로 이동
|
||||||
|
next({ name: 'Home' });
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
|
// 최초 앱 로드 시 인증 상태 체크
|
||||||
|
await authStore.checkAuthStatus()
|
||||||
|
|
||||||
|
// 현재 라우트에 인증이 필요한지 확인
|
||||||
|
const requiresAuth = to.meta.requiresAuth === true
|
||||||
|
|
||||||
|
if (requiresAuth && !authStore.isAuthenticated) {
|
||||||
|
// 인증되지 않은 사용자를 로그인 페이지로 리다이렉트
|
||||||
|
// 원래 가려던 페이지를 쿼리 파라미터로 전달
|
||||||
|
next({
|
||||||
|
name: 'Login',
|
||||||
|
query: { redirect: to.fullPath }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
50
src/stores/useAuthStore.js
Normal file
50
src/stores/useAuthStore.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
작성자 : 박지윤
|
||||||
|
작성일 : 2025-02-04
|
||||||
|
수정자 :
|
||||||
|
수정일 :
|
||||||
|
설명 : 로그인 상태, 로그아웃
|
||||||
|
*/
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import $api from "@api";
|
||||||
|
|
||||||
|
export const useAuthStore = defineStore('auth', () => {
|
||||||
|
const user = ref(null);
|
||||||
|
|
||||||
|
// 로그인 여부 확인
|
||||||
|
const isAuthenticated = computed(() => user.value !== null);
|
||||||
|
|
||||||
|
// 로그인 상태 확인
|
||||||
|
const checkAuthStatus = async () => {
|
||||||
|
const response = await $api.get('user/isLogin');
|
||||||
|
if (response.data.status === "OK" && response.data.data) {
|
||||||
|
user.value = response.data.data;
|
||||||
|
} else {
|
||||||
|
user.value = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 로그아웃
|
||||||
|
const logout = async () => {
|
||||||
|
|
||||||
|
const response = await $api.get('user/logout');
|
||||||
|
|
||||||
|
// 로그아웃 성공 시 사용자 상태 초기화
|
||||||
|
if (response.data.status === "OK") {
|
||||||
|
user.value = null;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
console.error("로그아웃 실패:", response.data.data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
user,
|
||||||
|
isAuthenticated,
|
||||||
|
checkAuthStatus,
|
||||||
|
logout
|
||||||
|
};
|
||||||
|
});
|
||||||
28
src/stores/useUserStore.js
Normal file
28
src/stores/useUserStore.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import $api from "@api";
|
||||||
|
|
||||||
|
export const useUserStore = defineStore('userInfo', () => {
|
||||||
|
const user = ref(null);
|
||||||
|
|
||||||
|
// 사용자 정보 가져오기
|
||||||
|
const userInfo = async () => {
|
||||||
|
try {
|
||||||
|
const response = await $api.get('user/userInfo');
|
||||||
|
if (response.data.status === "OK") {
|
||||||
|
user.value = response.data.data;
|
||||||
|
console.log(user.value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("사용자 정보 조회 실패:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
user,
|
||||||
|
userInfo,
|
||||||
|
};
|
||||||
|
});
|
||||||
16
src/views/user/ThePassword.vue
Normal file
16
src/views/user/ThePassword.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
|
<div class="container rounded bg-white my-10 py-10" style="max-width: 500px">
|
||||||
|
<LogoHeader title="비밀번호 재설정"/>
|
||||||
|
<FindPassword />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import FindPassword from '@/components/user/FindPassword.vue';
|
||||||
|
import LogoHeader from '@c/user/LogoHeader.vue';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
Loading…
Reference in New Issue
Block a user