Merge branch 'main' of http://192.168.0.251:3000/localnet/localhost-front
This commit is contained in:
commit
722df90b4d
6
.env.dev
6
.env.dev
@ -1,6 +1,6 @@
|
||||
VITE_DOMAIN = http://localhost:5173/
|
||||
VITE_DOMAIN = https://192.168.0.251:5173/
|
||||
# VITE_LOGIN_URL = http://localhost:10325/ms/
|
||||
# VITE_FILE_URL = http://localhost:10325/ms/
|
||||
# VITE_API_URL = http://localhost:10325/api/
|
||||
VITE_API_URL = http://localhost:10325/test/
|
||||
VITE_API_URL = https://192.168.0.251:10325/api/
|
||||
VITE_TEST_URL = https://192.168.0.251:10325/test/
|
||||
VITE_KAKAO_MAP_KEY=6f092e8f45ee81186bb6d8408f66a492
|
||||
6
.env.mine
Normal file
6
.env.mine
Normal file
@ -0,0 +1,6 @@
|
||||
VITE_DOMAIN = http://localhost:5173/
|
||||
# VITE_LOGIN_URL = http://localhost:10325/ms/
|
||||
# VITE_FILE_URL = http://localhost:10325/ms/
|
||||
VITE_API_URL = http://localhost:10325/api/
|
||||
VITE_TEST_URL = http://localhost:10325/test/
|
||||
VITE_KAKAO_MAP_KEY=6f092e8f45ee81186bb6d8408f66a492
|
||||
97
package.json
97
package.json
@ -1,50 +1,51 @@
|
||||
{
|
||||
"name": "front",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host 0.0.0.0 --mode dev",
|
||||
"build": "vite build --mode prod",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --fix",
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fullcalendar/core": "^6.1.15",
|
||||
"@fullcalendar/daygrid": "^6.1.15",
|
||||
"@fullcalendar/interaction": "^6.1.15",
|
||||
"@fullcalendar/vue3": "^6.1.15",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@tinymce/tinymce-vue": "^5.1.1",
|
||||
"@vueup/vue-quill": "^1.2.0",
|
||||
"axios": "^1.7.9",
|
||||
"bootstrap": "^5.3.3",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"dayjs": "^1.11.13",
|
||||
"dompurify": "^3.2.3",
|
||||
"flatpickr": "^4.6.13",
|
||||
"front": "file:",
|
||||
"heic2any": "^0.0.4",
|
||||
"pinia": "^2.2.6",
|
||||
"pinia-plugin-persist": "^1.0.0",
|
||||
"quill": "^2.0.3",
|
||||
"upload-images-converter": "^2.0.2",
|
||||
"vite-plugin-mkcert": "^1.17.6",
|
||||
"vue": "^3.5.13",
|
||||
"vue-flatpickr-component": "^11.0.5",
|
||||
"vue-router": "^4.4.5",
|
||||
"vue3-kakao-maps": "^2.3.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vue/eslint-config-prettier": "^10.1.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"prettier": "^3.3.3",
|
||||
"vite": "^5.4.10",
|
||||
"vite-plugin-inspect": "^0.8.9",
|
||||
"vite-plugin-vue-devtools": "^7.6.5"
|
||||
}
|
||||
"name": "front",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host 0.0.0.0 --mode dev",
|
||||
"mine": "vite --host 0.0.0.0 --mode mine",
|
||||
"build": "vite build --mode prod",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --fix",
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fullcalendar/core": "^6.1.15",
|
||||
"@fullcalendar/daygrid": "^6.1.15",
|
||||
"@fullcalendar/interaction": "^6.1.15",
|
||||
"@fullcalendar/vue3": "^6.1.15",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@tinymce/tinymce-vue": "^5.1.1",
|
||||
"@vueup/vue-quill": "^1.2.0",
|
||||
"axios": "^1.7.9",
|
||||
"bootstrap": "^5.3.3",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"dayjs": "^1.11.13",
|
||||
"dompurify": "^3.2.3",
|
||||
"flatpickr": "^4.6.13",
|
||||
"front": "file:",
|
||||
"heic2any": "^0.0.4",
|
||||
"pinia": "^2.2.6",
|
||||
"pinia-plugin-persist": "^1.0.0",
|
||||
"quill": "^2.0.3",
|
||||
"upload-images-converter": "^2.0.2",
|
||||
"vite-plugin-mkcert": "^1.17.6",
|
||||
"vue": "^3.5.13",
|
||||
"vue-flatpickr-component": "^11.0.5",
|
||||
"vue-router": "^4.4.5",
|
||||
"vue3-kakao-maps": "^2.3.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vue/eslint-config-prettier": "^10.1.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"prettier": "^3.3.3",
|
||||
"vite": "^5.4.10",
|
||||
"vite-plugin-inspect": "^0.8.9",
|
||||
"vite-plugin-vue-devtools": "^7.6.5"
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,42 +7,184 @@
|
||||
|
||||
|
||||
/* 휴가 */
|
||||
.half-day-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.half-day-buttons .btn.active {
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
.fc-daygrid-day-events {
|
||||
max-height: 100px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
/* 이벤트 선 없게 */
|
||||
.fc-event {
|
||||
border: none;
|
||||
}
|
||||
/* 오전전반차 그래프 */
|
||||
.fc-daygrid-event.half-day-am {
|
||||
width: calc(50% - 4px) !important;
|
||||
}
|
||||
/* 오후반차 그래프프 */
|
||||
.fc-daygrid-event.half-day-pm {
|
||||
width: calc(50% - 4px) !important;
|
||||
margin-left: auto !important
|
||||
}
|
||||
/* 공휴일,일요일 색상 */
|
||||
.fc-day-sun .fc-daygrid-day-number,
|
||||
.fc-col-header-cell:first-child .fc-col-header-cell-cushion {
|
||||
color: #ff4500 !important;
|
||||
}
|
||||
/* 토요일 색상 */
|
||||
.fc-day-sat .fc-daygrid-day-number,
|
||||
.fc-col-header-cell:last-child .fc-col-header-cell-cushion {
|
||||
color: #6076e0 !important;
|
||||
}
|
||||
/* 캘린더 날짜 왼쪽 상단 위치하게 */
|
||||
.fc-daygrid-day-number {
|
||||
margin-right: auto;
|
||||
}
|
||||
/* 데이트피커 뾰족없게게 */
|
||||
.flatpickr-calendar:before,
|
||||
.flatpickr-calendar:after {
|
||||
display: none !important;
|
||||
}
|
||||
/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */
|
||||
.fc-toolbar-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
/* 클릭 가능한 날짜 (오늘 + 미래) */
|
||||
.fc-daygrid-day.clickable {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
}
|
||||
/* 마우스를 올렸을 때 효과 */
|
||||
.fc-daygrid-day.clickable:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05); /* 연한 배경 효과 */
|
||||
}
|
||||
/* 주말 (토요일, 일요일) 및 공휴일 */
|
||||
.fc-day-sat-sun {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.6; /* 흐려 보이게 */
|
||||
}
|
||||
/* 과거 날짜 (오늘 이전) */
|
||||
.fc-daygrid-day.past {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.6; /* 흐려 보이게 */
|
||||
}
|
||||
/* 기본 이벤트 스타일 */
|
||||
.fc-daygrid-event {
|
||||
border: none !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* 오전 반차 (왼쪽 절반) */
|
||||
.selected-event.half-day-am {
|
||||
width: 50% !important;
|
||||
left: 0 !important;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
/* 오후 반차 (오른쪽 절반) */
|
||||
.selected-event.half-day-pm {
|
||||
width: 50% !important;
|
||||
margin-left: auto !important;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
|
||||
/* 본인 모달 */
|
||||
|
||||
/* 닫기 버튼 */
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
/* 리스트 아이템 */
|
||||
.vacation-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
/* 모달 본문 스크롤 */
|
||||
.modal-body {
|
||||
max-height: 130px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 선물하기 모달 */
|
||||
|
||||
/* 연차 개수 버튼 */
|
||||
.count-btn {
|
||||
font-size: 18px;
|
||||
padding: 2px 10px;
|
||||
border: none;
|
||||
background: #2C3E50;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.count-btn:hover {
|
||||
background: #1d2c44;
|
||||
}
|
||||
.count-btn:disabled {
|
||||
background: #cccccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* 버튼 컨테이너 (우측 정렬) */
|
||||
.custom-button-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
/* 버튼 기본 스타일 */
|
||||
.custom-button {
|
||||
background: none; /* 배경색 없음 */
|
||||
border: none; /* 테두리 없음 */
|
||||
padding: 10px; /* 크기 조정 */
|
||||
cursor: pointer; /* 클릭 가능하도록 변경 */
|
||||
}
|
||||
|
||||
/* 아이콘 색상 변경 (기본) */
|
||||
.custom-button i {
|
||||
color: #282538; /* 기본 아이콘 색상 */
|
||||
font-size: 25px; /* 아이콘 크기 */
|
||||
}
|
||||
|
||||
/* 버튼 호버 효과 */
|
||||
.custom-button:hover i {
|
||||
color: #ff0800; /* 호버 시 아이콘 색상 변경 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 모달 배경 투명하게 */
|
||||
.modal-dialog {
|
||||
background: none !important; /* 배경 제거 */
|
||||
box-shadow: none !important; /* 음영 제거 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 모달 내용 스타일 */
|
||||
.modal-content {
|
||||
background: #fff; /* 기존 흰색 배경 유지 */
|
||||
border-radius: 8px;
|
||||
box-shadow: none !important; /* 내부 음영 제거 */
|
||||
padding: 20px;
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.grayscaleImg {
|
||||
filter: grayscale(100%);
|
||||
|
||||
@ -3,7 +3,7 @@ import { useRoute } from 'vue-router';
|
||||
import { useToastStore } from '@s/toastStore';
|
||||
|
||||
const $api = axios.create({
|
||||
baseURL: 'https://192.168.0.251:10325/api/',
|
||||
baseURL: import.meta.env.VITE_API_URL,
|
||||
timeout: 300000,
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
@ -1,43 +1,133 @@
|
||||
<template>
|
||||
<div class="half-day-buttons">
|
||||
<div class="menu gap-4 justify-content-center mt-5">
|
||||
<!-- 오전 반차 버튼 -->
|
||||
<button
|
||||
class="btn btn-info"
|
||||
class="btn btn-warning"
|
||||
:class="{ active: halfDayType === 'AM' }"
|
||||
@click="toggleHalfDay('AM')"
|
||||
>
|
||||
<i class="bi bi-sun"></i>
|
||||
</button>
|
||||
|
||||
<!-- 오후 반차 버튼 -->
|
||||
<button
|
||||
class="btn btn-warning"
|
||||
class="btn btn-info"
|
||||
:class="{ active: halfDayType === 'PM' }"
|
||||
@click="toggleHalfDay('PM')"
|
||||
>
|
||||
<i class="bi bi-moon"></i>
|
||||
</button>
|
||||
|
||||
<!-- 저장 버튼 -->
|
||||
<div class="save-button-container">
|
||||
<button class="btn btn-success" @click="addVacationRequests">
|
||||
<button class="btn btn-success" @click="addVacationRequests" :disabled="isDisabled">
|
||||
✔
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineEmits, ref } from "vue";
|
||||
import { defineEmits, ref, defineProps } from "vue";
|
||||
|
||||
const emit = defineEmits(["toggleHalfDay", "addVacationRequests"]);
|
||||
const props = defineProps({
|
||||
isDisabled: Boolean
|
||||
});
|
||||
|
||||
const emit = defineEmits(["toggleHalfDay", "addVacationRequests", "resetHalfDay"]);
|
||||
const halfDayType = ref(null);
|
||||
|
||||
const toggleHalfDay = (type) => {
|
||||
halfDayType.value = halfDayType.value === type ? null : type;
|
||||
halfDayType.value = type;
|
||||
|
||||
emit("toggleHalfDay", halfDayType.value);
|
||||
|
||||
// ✅ 버튼 클릭 후 1초 후 자동 비활성화
|
||||
setTimeout(() => {
|
||||
halfDayType.value = null;
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// 날짜 선택 후 반차 버튼 상태 초기화
|
||||
const resetHalfDay = () => {
|
||||
halfDayType.value = null;
|
||||
emit("resetHalfDay");
|
||||
};
|
||||
|
||||
const addVacationRequests = () => {
|
||||
emit("addVacationRequests");
|
||||
};
|
||||
|
||||
defineExpose({ resetHalfDay });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped>
|
||||
/* 버튼 기본 스타일 */
|
||||
.btn {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
</style>
|
||||
/* 마우스를 올렸을 때 */
|
||||
.btn:hover {
|
||||
filter: brightness(90%);
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* 버튼이 눌렸을 때 */
|
||||
.btn:active {
|
||||
transform: scale(0.9);
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 선택된 (눌린) 버튼 */
|
||||
.btn.active {
|
||||
border: 3px solid #fff; /* 흰색 테두리 강조 */
|
||||
box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.3);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* AM 버튼 (선택된 상태) */
|
||||
.btn-warning.active {
|
||||
background-color: #ffca2c !important; /* 진한 노란색 */
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* PM 버튼 (선택된 상태) */
|
||||
.btn-info.active {
|
||||
background-color: #0b5ed7 !important; /* 진한 파란색 */
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* ✔ 버튼 */
|
||||
.btn-success {
|
||||
font-size: 24px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
/* ✔ 버튼 마우스 오버 */
|
||||
.btn-success:hover {
|
||||
background-color: #198754;
|
||||
box-shadow: 0px 4px 10px rgba(25, 135, 84, 0.4);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* ✔ 버튼 클릭 */
|
||||
.btn-success:active {
|
||||
transform: scale(0.95);
|
||||
box-shadow: 0px 2px 5px rgba(25, 135, 84, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,21 +1,22 @@
|
||||
<template>
|
||||
<div v-if="isOpen" class="modal-dialog" @click.self="closeModal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-content p-5">
|
||||
<h5 class="modal-title">To. {{ targetUser.MEMBERNAM }} 🎁</h5>
|
||||
<button class="close-btn" @click="closeModal">✖</button>
|
||||
|
||||
<div class="modal-body">
|
||||
<p>선물할 연차 개수를 선택하세요.</p>
|
||||
|
||||
<div class="vacation-control">
|
||||
<div class="justify-content-center d-sm-flex gap-sm-3 align-items-md-center mt-8">
|
||||
<button @click="decreaseCount" :disabled="grantCount < 2" class="count-btn">-</button>
|
||||
<span class="grant-count">{{ grantCount }}</span>
|
||||
<span class="text-dark fw-bold fs-4">{{ grantCount }}</span>
|
||||
<button @click="increaseCount" :disabled="grantCount >= availableQuota" class="count-btn">+</button>
|
||||
</div>
|
||||
|
||||
<button class="gift-btn" @click="saveVacationGrant" :disabled="grantCount === 0">
|
||||
<div class="custom-button-container">
|
||||
<button class="custom-button" @click="saveVacationGrant" :disabled="grantCount === 0">
|
||||
<i class="bx bx-gift"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -24,7 +25,9 @@
|
||||
<script setup>
|
||||
import { ref, defineProps, defineEmits, watch, onMounted } from "vue";
|
||||
import axios from "@api";
|
||||
import { useToastStore } from '@s/toastStore';
|
||||
|
||||
const toastStore = useToastStore();
|
||||
const props = defineProps({
|
||||
isOpen: Boolean,
|
||||
targetUser: Object,
|
||||
@ -72,21 +75,18 @@
|
||||
count: grantCount.value,
|
||||
},
|
||||
];
|
||||
console.log(props.targetUser)
|
||||
console.log(payload)
|
||||
const response = await axios.post("vacation", payload);
|
||||
console.log(response)
|
||||
if (response.data && response.data.status === "OK") {
|
||||
alert("✅ 연차가 부여되었습니다.");
|
||||
toastStore.onToast('연차가 선물되었습니다.', 's');
|
||||
await fetchSentVacationCount();
|
||||
emit("updateVacation");
|
||||
closeModal();
|
||||
} else {
|
||||
alert("🚨 연차 추가 중 오류가 발생했습니다.");
|
||||
toastStore.onToast(' 연차 선물 중 오류가 발생했습니다.', 'e');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("🚨 연차 추가 실패:", error);
|
||||
alert("연차 추가에 실패했습니다.");
|
||||
toastStore.onToast(' 연차 선물 실패!!.', 'e');
|
||||
}
|
||||
};
|
||||
|
||||
@ -98,7 +98,6 @@
|
||||
() => props.isOpen,
|
||||
async (newVal) => {
|
||||
if (newVal && props.targetUser && props.targetUser.MEMBERSEQ) {
|
||||
console.log("🟢 모달이 열렸습니다. 데이터를 로드합니다.");
|
||||
await fetchSentVacationCount();
|
||||
}
|
||||
}
|
||||
@ -124,81 +123,4 @@
|
||||
|
||||
<style scoped>
|
||||
|
||||
/* 모달 본문 */
|
||||
.modal-content {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
width: 300px;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.15);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 닫기 버튼 */
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 연차 개수 조정 버튼 */
|
||||
.vacation-control {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.count-btn {
|
||||
font-size: 18px;
|
||||
padding: 6px 12px;
|
||||
border: none;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.count-btn:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* 개수 표시 */
|
||||
.grant-count {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 선물 아이콘 버튼 */
|
||||
.gift-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
background: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 10px 15px;
|
||||
margin-top: 15px;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.gift-btn:hover {
|
||||
background: #218838;
|
||||
}
|
||||
|
||||
.gift-btn:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,29 +1,28 @@
|
||||
<template>
|
||||
<div v-if="isOpen" class="modal-dialog" @click.self="closeModal">
|
||||
<div class="modal-content modal-scroll">
|
||||
<div class="modal-content p-5 modal-scroll">
|
||||
<h5 class="modal-title">📅 내 연차 사용 내역</h5>
|
||||
<button class="close-btn" @click="closeModal">✖</button>
|
||||
|
||||
<!-- 연차 목록 -->
|
||||
<div class="modal-body" v-if="mergedVacations.length > 0">
|
||||
<ol class="vacation-list">
|
||||
<ol class="list-group-numbered px-0 mt-4">
|
||||
<li
|
||||
v-for="(vac, index) in mergedVacations"
|
||||
:key="vac._expandIndex"
|
||||
class="vacation-item"
|
||||
>
|
||||
<!-- Used 항목만 인덱스 표시 -->
|
||||
<span v-if="vac.category === 'used'" class="vacation-index">
|
||||
<span v-if="vac.category === 'used'" class="fw-bold text-dark me-2">
|
||||
{{ usedVacationIndexMap[vac._expandIndex] }})
|
||||
</span>
|
||||
|
||||
<span :class="vac.category === 'used' ? 'minus-symbol' : 'plus-symbol'">
|
||||
<span :class="vac.category === 'used' ? 'fw-bold text-danger me-2' : 'fw-bold text-primary me-2'">
|
||||
{{ vac.category === 'used' ? '-' : '+' }}
|
||||
</span>
|
||||
|
||||
<span
|
||||
:style="{ color: userColors[vac.senderId || vac.receiverId] || '#000' }"
|
||||
class="vacation-date"
|
||||
>
|
||||
{{ formatDate(vac.date) }}
|
||||
</span>
|
||||
@ -32,7 +31,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 연차 데이터 없음 -->
|
||||
<p v-else class="no-data">
|
||||
<p v-else class="text-sm-center mt-10 text-gray">
|
||||
🚫 사용한 연차가 없습니다.
|
||||
</p>
|
||||
</div>
|
||||
@ -139,86 +138,4 @@ const closeModal = () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 모달 본문 */
|
||||
.modal-content {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
width: 300px;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.15);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 닫기 버튼 */
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 리스트 기본 스타일 */
|
||||
.vacation-list {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
/* 리스트 아이템 */
|
||||
.vacation-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
/* 인덱스 (연차 사용 개수) */
|
||||
.vacation-index {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
margin-right: 8px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* "-" 빨간색 */
|
||||
.minus-symbol {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* "+" 파란색 */
|
||||
.plus-symbol {
|
||||
color: blue;
|
||||
font-weight: bold;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* 날짜 스타일 */
|
||||
.vacation-date {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 연차 데이터 없음 */
|
||||
.no-data {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: gray;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 모달 본문 스크롤: 높이가 300px 이상이면 스크롤바 표시 */
|
||||
.modal-body {
|
||||
max-height: 130px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -8,9 +8,8 @@
|
||||
|
||||
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
|
||||
<ul class="navbar-nav flex-row align-items-center ms-auto">
|
||||
|
||||
<button class="btn p-1" @click="switchToLightMode"><i class='bx bxs-sun link-warning'></i></button>
|
||||
<button class="btn p-1" @click="switchToDarkMode"><i class='bx bxs-moon' ></i></button>
|
||||
<button class="btn p-1" @click="switchToLightMode"><i class="bx bxs-sun link-warning"></i></button>
|
||||
<button class="btn p-1" @click="switchToDarkMode"><i class="bx bxs-moon"></i></button>
|
||||
|
||||
<i class="bx bx-bell bx-md bx-log-out cursor-pointer p-1" @click="handleLogout"></i>
|
||||
|
||||
@ -152,7 +151,13 @@
|
||||
<!-- User -->
|
||||
<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">
|
||||
<img v-if="user" :src="`${baseUrl}upload/img/profile/${user.profile}`" alt="Profile Image" class="w-px-40 h-px-40 rounded-circle" @error="$event.target.src = '/img/icons/icon.png'"/>
|
||||
<img
|
||||
v-if="user"
|
||||
:src="`${baseUrl}upload/img/profile/${user.profile}`"
|
||||
alt="Profile Image"
|
||||
class="w-px-40 h-px-40 rounded-circle"
|
||||
@error="$event.target.src = '/img/icons/icon.png'"
|
||||
/>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
@ -227,40 +232,37 @@
|
||||
</nav>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useAuthStore } from '@s/useAuthStore';
|
||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useThemeStore } from '@s/darkmode';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import $api from '@api';
|
||||
import { useAuthStore } from '@s/useAuthStore';
|
||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useThemeStore } from '@s/darkmode';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import $api from '@api';
|
||||
|
||||
const user = ref(null);
|
||||
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
||||
const user = ref(null);
|
||||
//const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
||||
const baseUrl = import.meta.env.BASE_URL;
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const userStore = useUserInfoStore();
|
||||
const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
const userStore = useUserInfoStore();
|
||||
const router = useRouter();
|
||||
|
||||
const { isDarkMode, switchToDarkMode, switchToLightMode } = useThemeStore();
|
||||
const { isDarkMode, switchToDarkMode, switchToLightMode } = useThemeStore();
|
||||
|
||||
onMounted(async () => {
|
||||
if (isDarkMode) {
|
||||
switchToDarkMode();
|
||||
} else {
|
||||
switchToLightMode();
|
||||
}
|
||||
|
||||
await userStore.userInfo();
|
||||
user.value = userStore.user;
|
||||
});
|
||||
|
||||
|
||||
|
||||
const handleLogout = async () => {
|
||||
await authStore.logout();
|
||||
router.push('/login');
|
||||
};
|
||||
onMounted(async () => {
|
||||
if (isDarkMode) {
|
||||
switchToDarkMode();
|
||||
} else {
|
||||
switchToLightMode();
|
||||
}
|
||||
|
||||
await userStore.userInfo();
|
||||
user.value = userStore.user;
|
||||
});
|
||||
|
||||
const handleLogout = async () => {
|
||||
await authStore.logout();
|
||||
router.push('/login');
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
||||
|
||||
@ -91,7 +91,9 @@ import router from '@/router';
|
||||
import axios from '@api';
|
||||
import SaveButton from '@c/button/SaveBtn.vue';
|
||||
import BackButton from '@c/button/BackBtn.vue'
|
||||
import { useToastStore } from '@s/toastStore';
|
||||
|
||||
const toastStore = useToastStore();
|
||||
const categoryList = ref([]);
|
||||
const title = ref('');
|
||||
const password = ref('');
|
||||
@ -113,6 +115,11 @@ const fetchCategories = async () => {
|
||||
try {
|
||||
const response = await axios.get('board/categories');
|
||||
categoryList.value = response.data.data;
|
||||
// "자유" 카테고리 찾기 (CMNCODNAM이 '자유'인 것 선택)
|
||||
const freeCategory = categoryList.value.find(category => category.CMNCODNAM === '자유');
|
||||
if (freeCategory) {
|
||||
categoryValue.value = freeCategory.CMNCODVAL; // 기본 선택값 설정
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('카테고리 불러오기 오류:', error);
|
||||
}
|
||||
@ -167,11 +174,11 @@ const write = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
alert('게시물이 작성되었습니다.');
|
||||
toastStore.onToast('게시물이 작성되었습니다.', 's');
|
||||
goList();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert('게시물 작성 중 오류가 발생했습니다.');
|
||||
toastStore.onToast('게시물 작성 중 오류가 발생했습니다.', 'e');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
<HalfDayButtons
|
||||
@toggleHalfDay="toggleHalfDay"
|
||||
@addVacationRequests="saveVacationChanges"
|
||||
:isDisabled="!hasChanges"
|
||||
/>
|
||||
</div>
|
||||
<ProfileList
|
||||
@ -78,7 +79,9 @@
|
||||
import { useUserStore } from "@s/userList";
|
||||
import { useUserInfoStore } from "@s/useUserInfoStore";
|
||||
import { fetchHolidays } from "@c/calendar/holiday.js";
|
||||
import { useToastStore } from '@s/toastStore';
|
||||
|
||||
const toastStore = useToastStore();
|
||||
const userStore = useUserInfoStore();
|
||||
const userListStore = useUserStore();
|
||||
const userList = ref([]);
|
||||
@ -101,11 +104,74 @@
|
||||
const vacationCodeMap = ref({});
|
||||
const holidayDates = ref(new Set());
|
||||
const fetchedEvents = ref([]);
|
||||
const halfDayButtonsRef = ref(null);
|
||||
|
||||
// 데이트피커 인풋 ref
|
||||
const calendarDatepicker = ref(null);
|
||||
let fpInstance = null;
|
||||
|
||||
/** ✅ 변경사항 여부 확인 */
|
||||
const hasChanges = computed(() => {
|
||||
return (
|
||||
selectedDates.value.size > 0 ||
|
||||
myVacations.value.some(vac => selectedDates.value.has(vac.date.split("T")[0]))
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
/** ✅ selectedDates가 변경될 때 버튼 상태 즉시 업데이트 */
|
||||
watch(
|
||||
() => Array.from(selectedDates.value.keys()), // keys()를 Array로 변환해서 감시
|
||||
(newKeys) => {
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
function handleDateClick(info) {
|
||||
const clickedDateStr = info.dateStr;
|
||||
const clickedDate = info.date;
|
||||
const todayStr = new Date().toISOString().split("T")[0];
|
||||
|
||||
if (
|
||||
clickedDate.getDay() === 0 ||
|
||||
clickedDate.getDay() === 6 ||
|
||||
holidayDates.value.has(clickedDateStr) ||
|
||||
clickedDateStr < todayStr
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const isMyVacation = myVacations.value.some(vac => {
|
||||
const vacDate = vac.date ? String(vac.date).substring(0, 10) : "";
|
||||
return vacDate === clickedDateStr && !vac.receiverId;
|
||||
});
|
||||
|
||||
if (isMyVacation) {
|
||||
if (selectedDates.value.get(clickedDateStr) === "delete") {
|
||||
selectedDates.value.delete(clickedDateStr);
|
||||
} else {
|
||||
selectedDates.value.set(clickedDateStr, "delete");
|
||||
}
|
||||
updateCalendarEvents();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedDates.value.has(clickedDateStr)) {
|
||||
selectedDates.value.delete(clickedDateStr);
|
||||
updateCalendarEvents();
|
||||
return;
|
||||
}
|
||||
const type = halfDayType.value
|
||||
? (halfDayType.value === "AM" ? "700101" : "700102")
|
||||
: "700103";
|
||||
selectedDates.value.set(clickedDateStr, type);
|
||||
halfDayType.value = null;
|
||||
updateCalendarEvents();
|
||||
// ✅ 날짜 선택 후 버튼 초기화
|
||||
if (halfDayButtonsRef.value) {
|
||||
halfDayButtonsRef.value.resetHalfDay();
|
||||
}
|
||||
}
|
||||
|
||||
const calendarOptions = reactive({
|
||||
plugins: [dayGridPlugin, interactionPlugin],
|
||||
initialView: "dayGridMonth",
|
||||
@ -150,17 +216,28 @@
|
||||
}
|
||||
});
|
||||
|
||||
// FullCalendar 헤더 제목(.fc-toolbar-title) 클릭 시 데이트피커 열기
|
||||
// FullCalendar 헤더 제목(.fc-toolbar-title) 클릭 시 데이트피커 열기
|
||||
nextTick(() => {
|
||||
const titleEl = document.querySelector('.fc-toolbar-title');
|
||||
if (titleEl) {
|
||||
const titleEl = document.querySelector('.fc-toolbar-title');
|
||||
if (titleEl) {
|
||||
titleEl.style.cursor = 'pointer';
|
||||
titleEl.addEventListener('click', () => {
|
||||
fpInstance.open();
|
||||
// 화면 중앙 정렬을 위한 스타일 조정
|
||||
const dpEl = calendarDatepicker.value;
|
||||
dpEl.style.display = 'block';
|
||||
dpEl.style.position = 'fixed';
|
||||
dpEl.style.top = '22%';
|
||||
dpEl.style.left = '66%';
|
||||
dpEl.style.transform = 'translate(-50%, -50%)';
|
||||
dpEl.style.zIndex = '9999';
|
||||
dpEl.style.border = 'none';
|
||||
dpEl.style.outline = 'none';
|
||||
dpEl.style.backgroundColor = 'transparent';
|
||||
fpInstance.open();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
// 연차 내역 API (초기 호출용)
|
||||
async function fetchVacationHistory(year) {
|
||||
@ -272,7 +349,6 @@
|
||||
const selectedEvents = Array.from(selectedDates.value)
|
||||
.filter(([date, type]) => type !== "delete")
|
||||
.map(([date, type]) => ({
|
||||
title: getVacationType(type),
|
||||
start: date,
|
||||
backgroundColor: "rgb(113 212 243 / 76%)",
|
||||
textColor: "#fff",
|
||||
@ -298,47 +374,6 @@
|
||||
return "full-day";
|
||||
};
|
||||
|
||||
function handleDateClick(info) {
|
||||
const clickedDateStr = info.dateStr;
|
||||
const clickedDate = info.date;
|
||||
const todayStr = new Date().toISOString().split("T")[0];
|
||||
|
||||
if (
|
||||
clickedDate.getDay() === 0 ||
|
||||
clickedDate.getDay() === 6 ||
|
||||
holidayDates.value.has(clickedDateStr) ||
|
||||
clickedDateStr < todayStr
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const isMyVacation = myVacations.value.some(vac => {
|
||||
const vacDate = vac.date ? String(vac.date).substring(0, 10) : "";
|
||||
return vacDate === clickedDateStr && !vac.receiverId;
|
||||
});
|
||||
|
||||
if (isMyVacation) {
|
||||
if (selectedDates.value.get(clickedDateStr) === "delete") {
|
||||
selectedDates.value.delete(clickedDateStr);
|
||||
} else {
|
||||
selectedDates.value.set(clickedDateStr, "delete");
|
||||
}
|
||||
updateCalendarEvents();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedDates.value.has(clickedDateStr)) {
|
||||
selectedDates.value.delete(clickedDateStr);
|
||||
updateCalendarEvents();
|
||||
return;
|
||||
}
|
||||
const type = halfDayType.value
|
||||
? (halfDayType.value === "AM" ? "700101" : "700102")
|
||||
: "700103";
|
||||
selectedDates.value.set(clickedDateStr, type);
|
||||
halfDayType.value = null;
|
||||
updateCalendarEvents();
|
||||
}
|
||||
|
||||
function toggleHalfDay(type) {
|
||||
halfDayType.value = halfDayType.value === type ? null : type;
|
||||
}
|
||||
@ -381,6 +416,7 @@
|
||||
}
|
||||
|
||||
async function saveVacationChanges() {
|
||||
if (!hasChanges.value) return;
|
||||
const selectedDatesArray = Array.from(selectedDates.value);
|
||||
const vacationsToAdd = selectedDatesArray
|
||||
.filter(([date, type]) => type !== "delete")
|
||||
@ -405,7 +441,7 @@
|
||||
delete: vacationsToDelete
|
||||
});
|
||||
if (response.data && response.data.status === "OK") {
|
||||
alert("✅ 휴가 변경 사항이 저장되었습니다.");
|
||||
toastStore.onToast('휴가 변경 사항이 저장되었습니다.', 's');
|
||||
await fetchRemainingVacation();
|
||||
if (isModalOpen.value) {
|
||||
await fetchVacationHistory(lastRemainingYear.value);
|
||||
@ -415,11 +451,11 @@
|
||||
selectedDates.value.clear();
|
||||
updateCalendarEvents();
|
||||
} else {
|
||||
alert("❌ 휴가 저장 중 오류가 발생했습니다.");
|
||||
toastStore.onToast('휴가 저장 중 오류가 발생했습니다.', 'e');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("🚨 휴가 변경 저장 실패:", error);
|
||||
alert("❌ 휴가 저장 요청에 실패했습니다.");
|
||||
toastStore.onToast('휴가 저장 요청에 실패했습니다.', 'e');
|
||||
}
|
||||
}
|
||||
|
||||
@ -447,6 +483,46 @@
|
||||
await nextTick();
|
||||
fullCalendarRef.value.getApi().refetchEvents();
|
||||
}
|
||||
/** ✅ 오늘 이후의 날짜만 클릭 가능하도록 설정 */
|
||||
function markClickableDates() {
|
||||
nextTick(() => {
|
||||
const todayStr = new Date().toISOString().split("T")[0]; // 오늘 날짜 YYYY-MM-DD
|
||||
const todayObj = new Date(todayStr);
|
||||
|
||||
document.querySelectorAll(".fc-daygrid-day").forEach((cell) => {
|
||||
const dateStr = cell.getAttribute("data-date");
|
||||
if (!dateStr) return; // 날짜가 없으면 스킵
|
||||
|
||||
const dateObj = new Date(dateStr);
|
||||
|
||||
// 주말 (토요일, 일요일)
|
||||
if (dateObj.getDay() === 0 || dateObj.getDay() === 6 || holidayDates.value.has(dateStr)) {
|
||||
cell.classList.remove("clickable");
|
||||
cell.classList.add("fc-day-sat-sun");
|
||||
}
|
||||
// 과거 날짜 (오늘 이전)
|
||||
else if (dateObj < todayObj) {
|
||||
cell.classList.remove("clickable");
|
||||
cell.classList.add("past"); // 과거 날짜 비활성화
|
||||
}
|
||||
// 오늘 & 미래 날짜 (클릭 가능)
|
||||
else {
|
||||
cell.classList.add("clickable");
|
||||
cell.classList.remove("past", "fc-day-sat-sun");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** ✅ onMounted 및 달력 변경 시 실행 */
|
||||
onMounted(() => {
|
||||
markClickableDates();
|
||||
});
|
||||
|
||||
watch([holidayDates, lastRemainingYear, lastRemainingMonth], () => {
|
||||
markClickableDates();
|
||||
});
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchUserList();
|
||||
@ -460,10 +536,5 @@
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */
|
||||
.fc-toolbar-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 데이트피커 인풋은 Flatpickr에서 동적으로 스타일 적용됨 */
|
||||
</style>
|
||||
|
||||
@ -5,27 +5,33 @@ import vueDevTools from 'vite-plugin-vue-devtools';
|
||||
import mkcert from 'vite-plugin-mkcert';
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueDevTools(),
|
||||
// 자신의 로컬 서버에 연결하려면 이부분 주석처리
|
||||
mkcert({
|
||||
// SSL 키 등록
|
||||
keyFile: '/localhost-key.pem',
|
||||
certFile: '/localhost.pem',
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
'@a': fileURLToPath(new URL('./src/assets/', import.meta.url)),
|
||||
'@c': fileURLToPath(new URL('./src/components/', import.meta.url)),
|
||||
'@v': fileURLToPath(new URL('./src/views/', import.meta.url)),
|
||||
'@l': fileURLToPath(new URL('./src/layout/', import.meta.url)),
|
||||
'@s': fileURLToPath(new URL('./src/stores/', import.meta.url)),
|
||||
'@p': fileURLToPath(new URL('./src/common/plugin/', import.meta.url)),
|
||||
'@api': fileURLToPath(new URL('./src/common/axios-interceptor.js', import.meta.url)),
|
||||
export default defineConfig(({ mode }) => {
|
||||
const plugins = [vue(), vueDevTools()];
|
||||
|
||||
// dev: https, mine: http
|
||||
if (mode === 'dev') {
|
||||
plugins.push(
|
||||
mkcert({
|
||||
// SSL 키 등록
|
||||
keyFile: '/localhost-key.pem',
|
||||
certFile: '/localhost.pem',
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
plugins,
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
'@a': fileURLToPath(new URL('./src/assets/', import.meta.url)),
|
||||
'@c': fileURLToPath(new URL('./src/components/', import.meta.url)),
|
||||
'@v': fileURLToPath(new URL('./src/views/', import.meta.url)),
|
||||
'@l': fileURLToPath(new URL('./src/layout/', import.meta.url)),
|
||||
'@s': fileURLToPath(new URL('./src/stores/', import.meta.url)),
|
||||
'@p': fileURLToPath(new URL('./src/common/plugin/', import.meta.url)),
|
||||
'@api': fileURLToPath(new URL('./src/common/axios-interceptor.js', import.meta.url)),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user