Merge branch 'main' into vacation
This commit is contained in:
commit
9af35ff2d8
@ -819,3 +819,7 @@ input:checked + .slider:before {
|
|||||||
.font-bold {
|
.font-bold {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|||||||
@ -27,10 +27,16 @@
|
|||||||
<!-- 수정, 삭제 버튼 -->
|
<!-- 수정, 삭제 버튼 -->
|
||||||
<template v-if="!isDeletedComment && (unknown || isCommentAuthor || isAuthor)">
|
<template v-if="!isDeletedComment && (unknown || isCommentAuthor || isAuthor)">
|
||||||
<div class="float-end ms-1">
|
<div class="float-end ms-1">
|
||||||
|
<slot name="gobackBtn"></slot>
|
||||||
<EditButton @click.stop="editClick" :is-pushed="isEditPushed" />
|
<EditButton @click.stop="editClick" :is-pushed="isEditPushed" />
|
||||||
<DeleteButton :class="'ms-1'" @click.stop="deleteClick" :is-pushed="isDeletePushed" />
|
<DeleteButton :class="'ms-1'" @click.stop="deleteClick" :is-pushed="isDeletePushed" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="float-end ms-1">
|
||||||
|
<slot name="gobackBtn"></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- 좋아요, 싫어요 버튼 (댓글에서만 표시) -->
|
<!-- 좋아요, 싫어요 버튼 (댓글에서만 표시) -->
|
||||||
<BoardRecommendBtn
|
<BoardRecommendBtn
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
<div class="row g-0">
|
<div class="row g-0">
|
||||||
<div class="col-3 border-end text-center" id="app-calendar-sidebar">
|
<div class="col-3 border-end text-center" id="app-calendar-sidebar">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<img v-if="user" :src="`${baseUrl}upload/img/profile/${user.profile}`" alt="Profile Image" class="w-px-50 h-px-50 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-50 h-px-50 rounded-circle object-fit-contain" @error="$event.target.src = '/img/icons/icon.png'"/>
|
||||||
<p class="mt-2 fw-bold">
|
<p class="mt-2 fw-bold">
|
||||||
{{ user.name }}
|
{{ user.name }}
|
||||||
</p>
|
</p>
|
||||||
@ -60,7 +60,7 @@
|
|||||||
<div class="row my-2 d-flex align-items-center">
|
<div class="row my-2 d-flex align-items-center">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<img :src="`${baseUrl}upload/img/profile/${commuter.profile}`"
|
<img :src="`${baseUrl}upload/img/profile/${commuter.profile}`"
|
||||||
class="rounded-circle me-2 w-px-50 h-px-50"
|
class="me-2 w-px-50 h-px-50 rounded-circle object-fit-contain"
|
||||||
@error="$event.target.src = '/img/icons/icon.png'">
|
@error="$event.target.src = '/img/icons/icon.png'">
|
||||||
|
|
||||||
<span class="fw-bold">{{ commuter.memberName }}</span>
|
<span class="fw-bold">{{ commuter.memberName }}</span>
|
||||||
@ -399,7 +399,7 @@ const loadCommuters = async () => {
|
|||||||
// 프로필 이미지 생성
|
// 프로필 이미지 생성
|
||||||
const profileImg = document.createElement('img');
|
const profileImg = document.createElement('img');
|
||||||
profileImg.src = `${baseUrl}upload/img/profile/${commuter.profile}`;
|
profileImg.src = `${baseUrl}upload/img/profile/${commuter.profile}`;
|
||||||
profileImg.className = 'rounded-circle w-px-20 h-px-20 mx-1 mb-1 position-relative z-5 m-auto';
|
profileImg.className = 'rounded-circle w-px-20 h-px-20 mx-1 mb-1 position-relative z-5 m-auto object-fit-contain';
|
||||||
profileImg.style.border = `2px solid ${commuter.projctcolor}`;
|
profileImg.style.border = `2px solid ${commuter.projctcolor}`;
|
||||||
profileImg.onerror = () => { profileImg.src = '/img/icons/icon.png'; };
|
profileImg.onerror = () => { profileImg.src = '/img/icons/icon.png'; };
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
<img
|
<img
|
||||||
:src="`${baseUrl}upload/img/profile/${commuter.profile}`"
|
:src="`${baseUrl}upload/img/profile/${commuter.profile}`"
|
||||||
alt="User Profile"
|
alt="User Profile"
|
||||||
class="rounded-circle"
|
class="rounded-circle object-fit-contain"
|
||||||
:class="isCurrentUser(commuter) ? 'cursor-pointer' : ''"
|
:class="isCurrentUser(commuter) ? 'cursor-pointer' : ''"
|
||||||
:draggable="isCurrentUser(commuter)"
|
:draggable="isCurrentUser(commuter)"
|
||||||
@dragstart="isCurrentUser(commuter) ? dragStart($event, post) : null"
|
@dragstart="isCurrentUser(commuter) ? dragStart($event, post) : null"
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
:dinnerList="dinnerList"
|
:dinnerList="dinnerList"
|
||||||
:teaTimeList="teaTimeList"
|
:teaTimeList="teaTimeList"
|
||||||
:workShopList="workShopList"
|
:workShopList="workShopList"
|
||||||
|
@handle-click-vacation="handleClickVacation"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -60,13 +61,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { inject, onMounted, reactive, ref, watch } from 'vue';
|
import { inject, onMounted, reactive, ref, watch, nextTick } from 'vue';
|
||||||
import { fetchHolidays } from '@c/calendar/holiday';
|
import { fetchHolidays } from '@c/calendar/holiday';
|
||||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||||
import { useProjectStore } from '@/stores/useProjectStore';
|
import { useProjectStore } from '@/stores/useProjectStore';
|
||||||
import { useToastStore } from '@s/toastStore';
|
import { useToastStore } from '@s/toastStore';
|
||||||
import { useWeatherStore } from '@/stores/useWeatherStore';
|
import { useWeatherStore } from '@/stores/useWeatherStore';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
import router from '@/router';
|
||||||
import FullCalendar from '@fullcalendar/vue3';
|
import FullCalendar from '@fullcalendar/vue3';
|
||||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||||
import interactionPlugin from '@fullcalendar/interaction';
|
import interactionPlugin from '@fullcalendar/interaction';
|
||||||
@ -342,7 +344,7 @@
|
|||||||
useFilterEventList(month, day);
|
useFilterEventList(month, day);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 오늘 날짜 노란색 복구
|
// 오늘 날짜 노란색 배경 복구
|
||||||
const colorToday = e => {
|
const colorToday = e => {
|
||||||
if (todayEL != null && !todayEL.classList.contains('fc-day-today')) todayEL.classList.add('fc-day-today');
|
if (todayEL != null && !todayEL.classList.contains('fc-day-today')) todayEL.classList.add('fc-day-today');
|
||||||
};
|
};
|
||||||
@ -504,6 +506,8 @@
|
|||||||
selectAllow: selectInfo => isSelectableDate(selectInfo.start),
|
selectAllow: selectInfo => isSelectableDate(selectInfo.start),
|
||||||
dateClick: handleDateClick,
|
dateClick: handleDateClick,
|
||||||
dayCellDidMount: arg => {
|
dayCellDidMount: arg => {
|
||||||
|
// 날씨 정보 업데이트
|
||||||
|
addWeatherInfo(arg);
|
||||||
const dateCell = arg.el;
|
const dateCell = arg.el;
|
||||||
|
|
||||||
// 마우스 홀드시 이벤트 모달
|
// 마우스 홀드시 이벤트 모달
|
||||||
@ -534,10 +538,51 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 날짜 정보 업데이트
|
||||||
|
const addWeatherInfo = arg => {
|
||||||
|
const dateStr = $common.dateFormatter(arg.date, 'YMD');
|
||||||
|
// 해당 셀의 날짜와 일치하는 데이터
|
||||||
|
const theDayWeatherInfo = dailyWeatherList.value.find(weather => weather.date === dateStr);
|
||||||
|
|
||||||
|
if (theDayWeatherInfo) {
|
||||||
|
let weatherIconUrl = `https://openweathermap.org/img/wn/${theDayWeatherInfo.icon}.png`;
|
||||||
|
if (theDayWeatherInfo.icon === '01d' || theDayWeatherInfo.icon === '01n') {
|
||||||
|
weatherIconUrl = '/img/icons/sunny-custom.png';
|
||||||
|
}
|
||||||
|
// 날씨 이미지 세팅
|
||||||
|
const weatherEl = document.createElement('img');
|
||||||
|
weatherEl.src = weatherIconUrl;
|
||||||
|
weatherEl.alt = theDayWeatherInfo.description;
|
||||||
|
weatherEl.className = 'weather-icon';
|
||||||
|
weatherEl.style.width = '28px';
|
||||||
|
weatherEl.style.height = '28px';
|
||||||
|
|
||||||
|
// 해당 셀에 이미지 넣기
|
||||||
|
const dayTopEl = arg.el.querySelector('.fc-daygrid-day-top');
|
||||||
|
dayTopEl.classList.add('align-items-center');
|
||||||
|
dayTopEl.prepend(weatherEl); // 이상하게 가장 앞에 넣어야 일자 뒤에 나옴
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 날씨 데이터 변경 감지하여 날씨 정보 업데이트
|
||||||
|
watch(dailyWeatherList, async () => {
|
||||||
|
await nextTick(); // DOM이 업데이트된 후 실행
|
||||||
|
document.querySelectorAll('.fc-daygrid-day').forEach(dayCell => {
|
||||||
|
addWeatherInfo({
|
||||||
|
el: dayCell,
|
||||||
|
date: dayCell.dataset.date,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const handleWheelEvent = e => {
|
const handleWheelEvent = e => {
|
||||||
handleCloseModal();
|
handleCloseModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClickVacation = () => {
|
||||||
|
router.push({ path: 'Vacation' });
|
||||||
|
};
|
||||||
|
|
||||||
// 달력 뷰 변경 감지 (월 변경 시 데이터 다시 가져오기)
|
// 달력 뷰 변경 감지 (월 변경 시 데이터 다시 가져오기)
|
||||||
watch(
|
watch(
|
||||||
() => fullCalendarRef.value?.getApi().currentData.viewTitle,
|
() => fullCalendarRef.value?.getApi().currentData.viewTitle,
|
||||||
@ -564,12 +609,6 @@
|
|||||||
param.append('month', month);
|
param.append('month', month);
|
||||||
param.append('day', day);
|
param.append('day', day);
|
||||||
|
|
||||||
// if (!weatherStore.dailyWeatherList?.length) {
|
|
||||||
// await weatherStore.getWeatherInfo();
|
|
||||||
// //dailyWeatherList.value = weatherStore.dailyWeatherList;
|
|
||||||
// console.log('dailyWeatherList.value: ', dailyWeatherList.value);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 이벤트 카테고리 호출
|
// 이벤트 카테고리 호출
|
||||||
await fetchCategoryList();
|
await fetchCategoryList();
|
||||||
await fetchEventList(param);
|
await fetchEventList(param);
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
(category.CMNCODVAL === 300205 && teaTimeList?.length) ||
|
(category.CMNCODVAL === 300205 && teaTimeList?.length) ||
|
||||||
(category.CMNCODVAL === 300206 && workShopList?.length)
|
(category.CMNCODVAL === 300206 && workShopList?.length)
|
||||||
"
|
"
|
||||||
|
@click="category.CMNCODVAL == 300202 ? $emit('handleClickVacation') : ''"
|
||||||
|
:class="category.CMNCODVAL == 300202 ? 'pointer' : ''"
|
||||||
class="border border-2 mt-3 card p-2"
|
class="border border-2 mt-3 card p-2"
|
||||||
>
|
>
|
||||||
<div class="row g-2 position-relative">
|
<div class="row g-2 position-relative">
|
||||||
@ -100,6 +102,8 @@
|
|||||||
type: Array,
|
type: Array,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
defineEmits(['handleClickVacation']);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
:data-bs-original-title="getTooltipTitle(user)"
|
:data-bs-original-title="getTooltipTitle(user)"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
class="rounded-circle user-avatar border border-3"
|
class="user-avatar border border-3 rounded-circle object-fit-contain"
|
||||||
:class="{ 'grayscaleImg': isUserDisabled(user) }"
|
:class="{ 'grayscaleImg': isUserDisabled(user) }"
|
||||||
:src="`${baseUrl}upload/img/profile/${user.MEMBERPRF}`"
|
:src="`${baseUrl}upload/img/profile/${user.MEMBERPRF}`"
|
||||||
:style="`border-color: ${user.usercolor} !important;`"
|
:style="`border-color: ${user.usercolor} !important;`"
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</h5>
|
</h5>
|
||||||
<h5 class="mb-1">{{ data.localVote.LOCVOTTTL }}
|
<h5 class="mb-0">{{ data.localVote.LOCVOTTTL }}
|
||||||
<i v-if="yesVotetotal != '0'" class="bx bxs-check-circle link-success"></i>
|
<i v-if="yesVotetotal != '0'" class="bx bxs-check-circle link-success"></i>
|
||||||
</h5>
|
</h5>
|
||||||
<small >{{ data.localVote.formatted_LOCVOTRDT }} ~ {{ data.localVote.formatted_LOCVOTEDT }}</small>
|
<small >{{ data.localVote.formatted_LOCVOTRDT }} ~ {{ data.localVote.formatted_LOCVOTEDT }}</small>
|
||||||
|
|||||||
@ -49,7 +49,7 @@
|
|||||||
@keyup="ValidHandler('title')"
|
@keyup="ValidHandler('title')"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<QEditor class="" @keyup="ValidHandler('content')" @update:data="handleContentUpdate" @update:imageUrls="imageUrls = $event" :is-alert="wordContentAlert" :initialData="contentValue"/>
|
<QEditor class="q-editor-container" @keyup="ValidHandler('content')" @update:data="handleContentUpdate" @update:imageUrls="imageUrls = $event" :is-alert="wordContentAlert" :initialData="contentValue"/>
|
||||||
<div class="text-end mt-5">
|
<div class="text-end mt-5">
|
||||||
<button class="btn btn-primary" @click="saveWord" :disabled="titleValue ? !changed : false">
|
<button class="btn btn-primary" @click="saveWord" :disabled="titleValue ? !changed : false">
|
||||||
<i class="bx bx-check"></i>
|
<i class="bx bx-check"></i>
|
||||||
@ -232,3 +232,11 @@ const handleCategoryFocusout = (value) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
.q-editor-container {
|
||||||
|
max-width: 100%; /* 영역이 넘치지 않게 */
|
||||||
|
overflow: auto; /* 넘치는 내용은 스크롤로 처리 */
|
||||||
|
word-wrap: break-word; /* 긴 단어는 자동으로 줄바꿈 */
|
||||||
|
white-space: normal; /* 내용이 길어지면 자동으로 줄바꿈 */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -177,7 +177,7 @@
|
|||||||
v-if="user"
|
v-if="user"
|
||||||
:src="`${baseUrl}upload/img/profile/${user.profile}`"
|
:src="`${baseUrl}upload/img/profile/${user.profile}`"
|
||||||
alt="Profile Image"
|
alt="Profile Image"
|
||||||
class="w-px-40 h-px-40 rounded-circle border border-3"
|
class="w-px-40 h-px-40 rounded-circle border border-3 object-fit-contain"
|
||||||
:style="`border-color: ${user.usercolor} !important;`"
|
:style="`border-color: ${user.usercolor} !important;`"
|
||||||
@error="$event.target.src = '/img/icons/icon.png'"
|
@error="$event.target.src = '/img/icons/icon.png'"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const routes = [
|
|||||||
path: '/',
|
path: '/',
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: () => import('@v/MainView.vue'),
|
component: () => import('@v/MainView.vue'),
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/board',
|
path: '/board',
|
||||||
@ -22,6 +22,7 @@ const routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'write',
|
path: 'write',
|
||||||
|
name: 'BoardWrite',
|
||||||
component: () => import('@v/board/BoardWrite.vue'),
|
component: () => import('@v/board/BoardWrite.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -40,12 +41,13 @@ const routes = [
|
|||||||
path: '/mypage',
|
path: '/mypage',
|
||||||
name: 'MyPage',
|
name: 'MyPage',
|
||||||
component: () => import('@v/mypage/MyPage.vue'),
|
component: () => import('@v/mypage/MyPage.vue'),
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/wordDict',
|
path: '/wordDict',
|
||||||
|
name: 'WordDict',
|
||||||
component: () => import('@v/wordDict/wordDict.vue'),
|
component: () => import('@v/wordDict/wordDict.vue'),
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
@ -67,36 +69,43 @@ const routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/vacation',
|
path: '/vacation',
|
||||||
|
name: 'Vacation',
|
||||||
component: () => import('@v/vacation/VacationManagement.vue'),
|
component: () => import('@v/vacation/VacationManagement.vue'),
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/voteboard',
|
path: '/voteboard',
|
||||||
|
name: 'VoteBoard',
|
||||||
component: () => import('@v/voteboard/TheVoteBoard.vue'),
|
component: () => import('@v/voteboard/TheVoteBoard.vue'),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
|
name: 'VoteBoardList',
|
||||||
component: () => import('@v/voteboard/voteBoardList.vue'),
|
component: () => import('@v/voteboard/voteBoardList.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'write',
|
path: 'write',
|
||||||
|
name: 'VoteboardWrite',
|
||||||
component: () => import('@v/voteboard/voteboardWrite.vue'),
|
component: () => import('@v/voteboard/voteboardWrite.vue'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/projectlist',
|
path: '/projectlist',
|
||||||
|
name: 'Projectlist',
|
||||||
component: () => import('@v/projectlist/TheProjectList.vue'),
|
component: () => import('@v/projectlist/TheProjectList.vue'),
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/commuters',
|
path: '/commuters',
|
||||||
|
name: 'Commuters',
|
||||||
component: () => import('@v/commuters/TheCommuters.vue'),
|
component: () => import('@v/commuters/TheCommuters.vue'),
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/authorization',
|
path: '/authorization',
|
||||||
|
name: 'Authorization',
|
||||||
component: () => import('@v/admin/TheAuthorization.vue'),
|
component: () => import('@v/admin/TheAuthorization.vue'),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
|
|||||||
@ -72,7 +72,6 @@ export const useWeatherStore = defineStore('weather', () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 로컬스토리지 캐시 포함한 로직
|
|
||||||
const getWeatherInfoWithCache = async () => {
|
const getWeatherInfoWithCache = async () => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const pad = n => String(n).padStart(2, '0');
|
const pad = n => String(n).padStart(2, '0');
|
||||||
@ -86,17 +85,21 @@ export const useWeatherStore = defineStore('weather', () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 캐시 삭제
|
try {
|
||||||
|
const { weather: w, dailyWeatherList: d } = await getWeatherInfo();
|
||||||
|
|
||||||
|
// 기존 캐시 삭제
|
||||||
Object.keys(localStorage).forEach(k => {
|
Object.keys(localStorage).forEach(k => {
|
||||||
if (k.startsWith('weather_')) localStorage.removeItem(k);
|
if (k.startsWith('weather_')) localStorage.removeItem(k);
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
|
||||||
const { weather: w, dailyWeatherList: d } = await getWeatherInfo();
|
|
||||||
localStorage.setItem(key, JSON.stringify({ weather: w, dailyWeatherList: d }));
|
localStorage.setItem(key, JSON.stringify({ weather: w, dailyWeatherList: d }));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 오류 시 기존 로컬스토리지 값 중 가장 최신 값 사용
|
console.error('날씨 API 호출 실패, 캐시 fallback 시도 중...');
|
||||||
const oldKey = Object.keys(localStorage).filter(k => k.startsWith('weather_')).sort().pop();
|
const oldKey = Object.keys(localStorage)
|
||||||
|
.filter(k => k.startsWith('weather_'))
|
||||||
|
.sort()
|
||||||
|
.pop();
|
||||||
if (oldKey) {
|
if (oldKey) {
|
||||||
const fallback = JSON.parse(localStorage.getItem(oldKey));
|
const fallback = JSON.parse(localStorage.getItem(oldKey));
|
||||||
weather.value = fallback.weather;
|
weather.value = fallback.weather;
|
||||||
|
|||||||
@ -190,9 +190,9 @@
|
|||||||
searchText: searchText.value,
|
searchText: searchText.value,
|
||||||
showNotice: showNotices.value,
|
showNotice: showNotices.value,
|
||||||
};
|
};
|
||||||
|
//localStorage.removeItem
|
||||||
// 목록으로 바로 보낼때 필터 유지값
|
// 목록으로 바로 보낼때 필터 유지값
|
||||||
//localStorage.setItem(`boardList_${seq}`, JSON.stringify(query));
|
localStorage.setItem(`boardList_${seq}`, JSON.stringify(query));
|
||||||
};
|
};
|
||||||
|
|
||||||
// 스토리지 초기화
|
// 스토리지 초기화
|
||||||
@ -384,5 +384,4 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
top: -1px;
|
top: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -21,7 +21,14 @@
|
|||||||
:is-delete-pushed="isDeletePushed"
|
:is-delete-pushed="isDeletePushed"
|
||||||
@editClick="editClick"
|
@editClick="editClick"
|
||||||
@deleteClick="deleteClick"
|
@deleteClick="deleteClick"
|
||||||
/>
|
>
|
||||||
|
<!-- 목록으로 버튼 -->
|
||||||
|
<template #gobackBtn>
|
||||||
|
<button class="btn btn-label-primary btn-icon me-1" @click="goList">
|
||||||
|
<i class="bx bx-left-arrow-alt"></i>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</BoardProfile>
|
||||||
|
|
||||||
<!-- 비밀번호 입력창 (익명일 경우) -->
|
<!-- 비밀번호 입력창 (익명일 경우) -->
|
||||||
<div v-if="isPassword && unknown" class="mt-3 w-px-200 ms-auto">
|
<div v-if="isPassword && unknown" class="mt-3 w-px-200 ms-auto">
|
||||||
@ -451,6 +458,7 @@
|
|||||||
passwordAlert.value = '';
|
passwordAlert.value = '';
|
||||||
commentAlert.value = '';
|
commentAlert.value = '';
|
||||||
await fetchComments();
|
await fetchComments();
|
||||||
|
activeCommentBtnClass();
|
||||||
} else {
|
} else {
|
||||||
alert('댓글 작성을 실패했습니다.');
|
alert('댓글 작성을 실패했습니다.');
|
||||||
}
|
}
|
||||||
@ -496,6 +504,9 @@
|
|||||||
const isUnknown = unknown?.unknown ?? false;
|
const isUnknown = unknown?.unknown ?? false;
|
||||||
|
|
||||||
if (isUnknown) {
|
if (isUnknown) {
|
||||||
|
closeAllEditTextareas();
|
||||||
|
closeAllPasswordAreas();
|
||||||
|
activeCommentBtnClass();
|
||||||
togglePassword('delete');
|
togglePassword('delete');
|
||||||
} else {
|
} else {
|
||||||
deletePost();
|
deletePost();
|
||||||
@ -581,6 +592,8 @@
|
|||||||
|
|
||||||
// 댓글 삭제 버튼 클릭
|
// 댓글 삭제 버튼 클릭
|
||||||
const deleteComment = async comment => {
|
const deleteComment = async comment => {
|
||||||
|
acitveButtonType(); //게시글 버튼 클릭 클래스 제거
|
||||||
|
closeAllEditTextareas();
|
||||||
const isMyComment = comment.authorId === currentUserId.value;
|
const isMyComment = comment.authorId === currentUserId.value;
|
||||||
|
|
||||||
// 익명인 경우
|
// 익명인 경우
|
||||||
@ -686,6 +699,7 @@
|
|||||||
isEditPushed.value = false;
|
isEditPushed.value = false;
|
||||||
isDeletePushed.value = false;
|
isDeletePushed.value = false;
|
||||||
lastClickedButton.value = '';
|
lastClickedButton.value = '';
|
||||||
|
isPassword.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -877,6 +891,16 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 게시글 목록 이동 버튼
|
||||||
|
const goList = () => {
|
||||||
|
// 목록으로 바로 이동시 필터 유지
|
||||||
|
const getFilter = localStorage.getItem(`boardList_${currentBoardId.value}`);
|
||||||
|
router.push({
|
||||||
|
name: 'BoardList',
|
||||||
|
query: getFilter ? JSON.parse(getFilter) : '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 댓글 삭제 (대댓글 포함)
|
// 댓글 삭제 (대댓글 포함)
|
||||||
const handleCommentDeleted = deletedCommentId => {
|
const handleCommentDeleted = deletedCommentId => {
|
||||||
// 댓글 삭제
|
// 댓글 삭제
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
<!-- 단어 목록 -->
|
<!-- 단어 목록 -->
|
||||||
<ul v-if="total > 0" class="ms-3 list-unstyled" style="overflow-x: hidden; word-wrap: break-word;">
|
<ul v-if="total > 0" class="ms-3 list-unstyled" style="overflow-x: hidden; word-wrap: break-word;">
|
||||||
<DictCard
|
<DictCard
|
||||||
|
class="DictCard q-editor-container"
|
||||||
v-for="item in wordList"
|
v-for="item in wordList"
|
||||||
:key="item.WRDDICSEQ"
|
:key="item.WRDDICSEQ"
|
||||||
:item="item"
|
:item="item"
|
||||||
@ -330,5 +331,15 @@ import { useRoute } from 'vue-router';
|
|||||||
top: 5px;
|
top: 5px;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
}
|
}
|
||||||
|
.DictCard {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
.q-editor-container {
|
||||||
|
max-width: 100%; /* 영역이 넘치지 않게 */
|
||||||
|
overflow: auto; /* 넘치는 내용은 스크롤로 처리 */
|
||||||
|
word-wrap: break-word; /* 긴 단어는 자동으로 줄바꿈 */
|
||||||
|
white-space: normal; /* 내용이 길어지면 자동으로 줄바꿈 */
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user