Merge branch 'main' into commuters
This commit is contained in:
commit
56fc9615de
@ -2,116 +2,121 @@
|
|||||||
* Main
|
* Main
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
(function () {
|
||||||
|
// Initialize menu
|
||||||
|
//-----------------
|
||||||
|
let menu, animate;
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
var menu, animate;
|
var menu, animate;
|
||||||
(function () {
|
(function () {
|
||||||
// Initialize menu
|
// Initialize menu
|
||||||
//-----------------
|
//-----------------
|
||||||
|
=======
|
||||||
|
let layoutMenuEl = document.querySelectorAll('#layout-menu');
|
||||||
|
layoutMenuEl.forEach(function (element) {
|
||||||
|
menu = new Menu(element, {
|
||||||
|
orientation: 'vertical',
|
||||||
|
closeChildren: false,
|
||||||
|
});
|
||||||
|
// Change parameter to true if you want scroll animation
|
||||||
|
window.Helpers.scrollToActive((animate = false));
|
||||||
|
window.Helpers.mainMenu = menu;
|
||||||
|
});
|
||||||
|
>>>>>>> board-comment
|
||||||
|
|
||||||
let layoutMenuEl = document.querySelectorAll('#layout-menu')
|
// Initialize menu togglers and bind click on each
|
||||||
layoutMenuEl.forEach(function (element) {
|
let menuToggler = document.querySelectorAll('.layout-menu-toggle');
|
||||||
menu = new Menu(element, {
|
menuToggler.forEach(item => {
|
||||||
orientation: 'vertical',
|
item.addEventListener('click', event => {
|
||||||
closeChildren: false,
|
event.preventDefault();
|
||||||
})
|
window.Helpers.toggleCollapsed();
|
||||||
// Change parameter to true if you want scroll animation
|
});
|
||||||
window.Helpers.scrollToActive((animate = false))
|
});
|
||||||
window.Helpers.mainMenu = menu
|
|
||||||
})
|
|
||||||
|
|
||||||
// Initialize menu togglers and bind click on each
|
// Display menu toggle (layout-menu-toggle) on hover with delay
|
||||||
let menuToggler = document.querySelectorAll('.layout-menu-toggle')
|
let delay = function (elem, callback) {
|
||||||
menuToggler.forEach((item) => {
|
let timeout = null;
|
||||||
item.addEventListener('click', (event) => {
|
elem.onmouseenter = function () {
|
||||||
event.preventDefault()
|
// Set timeout to be a timer which will invoke callback after 300ms (not for small screen)
|
||||||
window.Helpers.toggleCollapsed()
|
if (!Helpers.isSmallScreen()) {
|
||||||
})
|
timeout = setTimeout(callback, 300);
|
||||||
})
|
} else {
|
||||||
|
timeout = setTimeout(callback, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Display menu toggle (layout-menu-toggle) on hover with delay
|
elem.onmouseleave = function () {
|
||||||
let delay = function (elem, callback) {
|
// Clear any timers set to timeout
|
||||||
let timeout = null
|
document.querySelector('.layout-menu-toggle').classList.remove('d-block');
|
||||||
elem.onmouseenter = function () {
|
clearTimeout(timeout);
|
||||||
// Set timeout to be a timer which will invoke callback after 300ms (not for small screen)
|
};
|
||||||
if (!Helpers.isSmallScreen()) {
|
};
|
||||||
timeout = setTimeout(callback, 300)
|
if (document.getElementById('layout-menu')) {
|
||||||
} else {
|
delay(document.getElementById('layout-menu'), function () {
|
||||||
timeout = setTimeout(callback, 0)
|
// not for small screen
|
||||||
}
|
if (!Helpers.isSmallScreen()) {
|
||||||
|
document.querySelector('.layout-menu-toggle').classList.add('d-block');
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
elem.onmouseleave = function () {
|
// Display in main menu when menu scrolls
|
||||||
// Clear any timers set to timeout
|
let menuInnerContainer = document.getElementsByClassName('menu-inner'),
|
||||||
document.querySelector('.layout-menu-toggle').classList.remove('d-block')
|
menuInnerShadow = document.getElementsByClassName('menu-inner-shadow')[0];
|
||||||
clearTimeout(timeout)
|
if (menuInnerContainer.length > 0 && menuInnerShadow) {
|
||||||
|
menuInnerContainer[0].addEventListener('ps-scroll-y', function () {
|
||||||
|
if (this.querySelector('.ps__thumb-y').offsetTop) {
|
||||||
|
menuInnerShadow.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
menuInnerShadow.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (document.getElementById('layout-menu')) {
|
|
||||||
delay(document.getElementById('layout-menu'), function () {
|
|
||||||
// not for small screen
|
|
||||||
if (!Helpers.isSmallScreen()) {
|
|
||||||
document.querySelector('.layout-menu-toggle').classList.add('d-block')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display in main menu when menu scrolls
|
// Init helpers & misc
|
||||||
let menuInnerContainer = document.getElementsByClassName('menu-inner'),
|
// --------------------
|
||||||
menuInnerShadow = document.getElementsByClassName('menu-inner-shadow')[0]
|
|
||||||
if (menuInnerContainer.length > 0 && menuInnerShadow) {
|
|
||||||
menuInnerContainer[0].addEventListener('ps-scroll-y', function () {
|
|
||||||
if (this.querySelector('.ps__thumb-y').offsetTop) {
|
|
||||||
menuInnerShadow.style.display = 'block'
|
|
||||||
} else {
|
|
||||||
menuInnerShadow.style.display = 'none'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init helpers & misc
|
// Init BS Tooltip
|
||||||
// --------------------
|
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||||
|
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||||
|
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||||
|
});
|
||||||
|
|
||||||
// Init BS Tooltip
|
// Accordion active class
|
||||||
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
const accordionActiveFunction = function (e) {
|
||||||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
if (e.type == 'show.bs.collapse' || e.type == 'show.bs.collapse') {
|
||||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
e.target.closest('.accordion-item').classList.add('active');
|
||||||
})
|
} else {
|
||||||
|
e.target.closest('.accordion-item').classList.remove('active');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Accordion active class
|
const accordionTriggerList = [].slice.call(document.querySelectorAll('.accordion'));
|
||||||
const accordionActiveFunction = function (e) {
|
const accordionList = accordionTriggerList.map(function (accordionTriggerEl) {
|
||||||
if (e.type == 'show.bs.collapse' || e.type == 'show.bs.collapse') {
|
accordionTriggerEl.addEventListener('show.bs.collapse', accordionActiveFunction);
|
||||||
e.target.closest('.accordion-item').classList.add('active')
|
accordionTriggerEl.addEventListener('hide.bs.collapse', accordionActiveFunction);
|
||||||
} else {
|
});
|
||||||
e.target.closest('.accordion-item').classList.remove('active')
|
|
||||||
|
// Auto update layout based on screen size
|
||||||
|
window.Helpers.setAutoUpdate(true);
|
||||||
|
|
||||||
|
// Toggle Password Visibility
|
||||||
|
window.Helpers.initPasswordToggle();
|
||||||
|
|
||||||
|
// Speech To Text
|
||||||
|
window.Helpers.initSpeechToText();
|
||||||
|
|
||||||
|
// Manage menu expanded/collapsed with templateCustomizer & local storage
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
|
// If current layout is horizontal OR current window screen is small (overlay menu) than return from here
|
||||||
|
if (window.Helpers.isSmallScreen()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const accordionTriggerList = [].slice.call(document.querySelectorAll('.accordion'))
|
// If current layout is vertical and current window screen is > small
|
||||||
const accordionList = accordionTriggerList.map(function (accordionTriggerEl) {
|
|
||||||
accordionTriggerEl.addEventListener('show.bs.collapse', accordionActiveFunction)
|
|
||||||
accordionTriggerEl.addEventListener('hide.bs.collapse', accordionActiveFunction)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Auto update layout based on screen size
|
// Auto update menu collapsed/expanded based on the themeConfig
|
||||||
window.Helpers.setAutoUpdate(true)
|
window.Helpers.setCollapsed(true, false);
|
||||||
|
})();
|
||||||
// Toggle Password Visibility
|
|
||||||
window.Helpers.initPasswordToggle()
|
|
||||||
|
|
||||||
// Speech To Text
|
|
||||||
window.Helpers.initSpeechToText()
|
|
||||||
|
|
||||||
// Manage menu expanded/collapsed with templateCustomizer & local storage
|
|
||||||
//------------------------------------------------------------------
|
|
||||||
|
|
||||||
// If current layout is horizontal OR current window screen is small (overlay menu) than return from here
|
|
||||||
if (window.Helpers.isSmallScreen()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If current layout is vertical and current window screen is > small
|
|
||||||
|
|
||||||
// Auto update menu collapsed/expanded based on the themeConfig
|
|
||||||
window.Helpers.setCollapsed(true, false)
|
|
||||||
})()
|
|
||||||
|
|||||||
@ -15,35 +15,69 @@ import Quill from 'quill';
|
|||||||
$common.변수
|
$common.변수
|
||||||
*/
|
*/
|
||||||
const common = {
|
const common = {
|
||||||
// JSON 문자열로 Delta 타입을 변환
|
// JSON 문자열로 Delta 타입을 변환
|
||||||
contentToHtml(content) {
|
contentToHtml(content) {
|
||||||
try {
|
try {
|
||||||
if (content.startsWith('{') || content.startsWith('[')) {
|
if (content.startsWith('{') || content.startsWith('[')) {
|
||||||
// Delta 형식으로 변환
|
// Delta 형식으로 변환
|
||||||
const delta = JSON.parse(content);
|
const delta = JSON.parse(content);
|
||||||
const quill = new Quill(document.createElement('div'));
|
const quill = new Quill(document.createElement('div'));
|
||||||
quill.setContents(delta);
|
quill.setContents(delta);
|
||||||
return quill.root.innerHTML; // HTML 반환
|
return quill.root.innerHTML; // HTML 반환
|
||||||
}
|
}
|
||||||
return content; // 이미 HTML일 경우 그대로 반환
|
return content; // 이미 HTML일 경우 그대로 반환
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('콘텐츠 변환 오류:', error);
|
console.error('콘텐츠 변환 오류:', error);
|
||||||
return content; // 오류 발생 시 원본 반환
|
return content; // 오류 발생 시 원본 반환
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Delta 타입을 JSON 문자열로 변환
|
// Delta 타입을 JSON 문자열로 변환
|
||||||
deltaAsJson(content) {
|
deltaAsJson(content) {
|
||||||
if (content && content.ops) {
|
if (content && content.ops) {
|
||||||
return JSON.stringify(content.ops); // Delta 객체에서 ops 속성만 JSON 문자열로 변환
|
return JSON.stringify(content.ops); // Delta 객체에서 ops 속성만 JSON 문자열로 변환
|
||||||
}
|
}
|
||||||
console.error('잘못된 Delta 객체:', content);
|
console.error('잘못된 Delta 객체:', content);
|
||||||
return null; // Delta 객체가 아니거나 ops가 없을 경우 null 반환
|
return null; // Delta 객체가 아니거나 ops가 없을 경우 null 반환
|
||||||
}
|
},
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Date 타입 문자열 포멧팅
|
||||||
|
*
|
||||||
|
* @param {string} dateStr
|
||||||
|
* @return
|
||||||
|
* 1. Date type 인 경우 예시 '25-02-24 12:02'
|
||||||
|
* 2. Date type 이 아닌 경우 입력값 리턴
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
dateFormatter(dateStr) {
|
||||||
|
const date = new Date(dateStr);
|
||||||
|
const dateCheck = date.getTime();
|
||||||
|
|
||||||
|
if (isNaN(dateCheck)) {
|
||||||
|
return dateStr;
|
||||||
|
} else {
|
||||||
|
const { year, month, day, hours, minutes } = this.formatDateTime(date);
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
formatDateTime(date) {
|
||||||
|
const zeroFormat = num => (num < 10 ? `0${num}` : num);
|
||||||
|
|
||||||
|
return {
|
||||||
|
year: date.getFullYear(),
|
||||||
|
month: zeroFormat(date.getMonth() + 1),
|
||||||
|
day: zeroFormat(date.getDate()),
|
||||||
|
hours: zeroFormat(date.getHours()),
|
||||||
|
minutes: zeroFormat(date.getMinutes()),
|
||||||
|
seconds: zeroFormat(date.getSeconds()),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(app) {
|
install(app) {
|
||||||
app.config.globalProperties.$common = common;
|
app.config.globalProperties.$common = common;
|
||||||
}
|
app.provide('common', common);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
13
src/common/formattedDate.js
Normal file
13
src/common/formattedDate.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/** 날짜 포맷1 (YYYY-MM-DD HH:MM) */
|
||||||
|
export const formattedDate = (dateString) => {
|
||||||
|
if (!dateString) return "날짜 없음";
|
||||||
|
const dateObj = new Date(dateString);
|
||||||
|
return `${dateObj.getFullYear()}-${String(dateObj.getMonth() + 1).padStart(2, '0')}-${String(dateObj.getDate()).padStart(2, '0')} ${String(dateObj.getHours()).padStart(2, '0')}:${String(dateObj.getMinutes()).padStart(2, '0')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 날짜 포맷2 (YYYY-MM-DD) */
|
||||||
|
export const formatDate = (dateString) => {
|
||||||
|
if (!dateString) return "날짜 없음";
|
||||||
|
const dateObj = new Date(dateString);
|
||||||
|
return `${dateObj.getFullYear()}-${String(dateObj.getMonth() + 1).padStart(2, '0')}-${String(dateObj.getDate()).padStart(2, '0')}`;
|
||||||
|
};
|
||||||
@ -2,18 +2,20 @@
|
|||||||
<div>
|
<div>
|
||||||
<BoardProfile
|
<BoardProfile
|
||||||
:unknown="unknown"
|
:unknown="unknown"
|
||||||
|
:isCommentAuthor="isCommentAuthor"
|
||||||
:boardId="comment.boardId"
|
:boardId="comment.boardId"
|
||||||
:profileName="comment.author"
|
:profileName="comment.author"
|
||||||
:date="comment.createdAt"
|
:date="comment.createdAt"
|
||||||
:comment="comment"
|
:comment="comment"
|
||||||
:showDetail="false"
|
:showDetail="false"
|
||||||
:author="true"
|
|
||||||
:isLike="!isLike"
|
:isLike="!isLike"
|
||||||
:isCommentPassword="comment.isCommentPassword"
|
:isCommentPassword="comment.isCommentPassword"
|
||||||
|
:isCommentProfile="true"
|
||||||
@editClick="$emit('editClick', comment)"
|
@editClick="$emit('editClick', comment)"
|
||||||
@deleteClick="$emit('deleteClick', comment)"
|
@deleteClick="$emit('deleteClick', comment)"
|
||||||
@updateReaction="handleUpdateReaction"
|
@updateReaction="handleUpdateReaction"
|
||||||
/>
|
/>
|
||||||
|
<!-- :author="true" -->
|
||||||
<!-- 댓글 비밀번호 입력창 (익명일 경우) -->
|
<!-- 댓글 비밀번호 입력창 (익명일 경우) -->
|
||||||
<div v-if="isCommentPassword && unknown" class="mt-3 w-25 ms-auto">
|
<div v-if="isCommentPassword && unknown" class="mt-3 w-25 ms-auto">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@ -27,7 +29,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<span v-if="passwordCommentAlert" class="invalid-feedback d-block text-start">{{ passwordCommentAlert }}</span>
|
<span v-if="passwordCommentAlert" class="invalid-feedback d-block text-start">{{ passwordCommentAlert }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<p>authorId:{{ comment.authorId }}</p>
|
||||||
|
<p>코멘트 비교: {{comment.isCommentAuthor}}</p>
|
||||||
|
|
||||||
|
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<template v-if="comment.isEditTextarea">
|
<template v-if="comment.isEditTextarea">
|
||||||
@ -44,7 +48,7 @@
|
|||||||
|
|
||||||
<PlusButton v-if="isPlusButton" @click="toggleComment" class="mt-6"/>
|
<PlusButton v-if="isPlusButton" @click="toggleComment" class="mt-6"/>
|
||||||
<BoardCommentArea v-if="isComment" @submitComment="submitComment"/>
|
<BoardCommentArea v-if="isComment" @submitComment="submitComment"/>
|
||||||
|
|
||||||
<!-- 대댓글 -->
|
<!-- 대댓글 -->
|
||||||
<ul v-if="comment.children && comment.children.length" class="list-unstyled">
|
<ul v-if="comment.children && comment.children.length" class="list-unstyled">
|
||||||
<li
|
<li
|
||||||
@ -52,12 +56,12 @@
|
|||||||
:key="child.commentId"
|
:key="child.commentId"
|
||||||
class="mt-8 pt-6 ps-10 border-top"
|
class="mt-8 pt-6 ps-10 border-top"
|
||||||
>
|
>
|
||||||
<BoardComment
|
<BoardComment
|
||||||
:comment="child"
|
:comment="child"
|
||||||
:unknown="unknown"
|
:unknown="unknown"
|
||||||
:isPlusButton="false"
|
:isPlusButton="false"
|
||||||
:isLike="true"
|
:isLike="true"
|
||||||
@submitComment="submitComment"
|
@submitComment="submitComment"
|
||||||
@updateReaction="handleUpdateReaction"
|
@updateReaction="handleUpdateReaction"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
@ -77,9 +81,13 @@ const props = defineProps({
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
unknown: {
|
unknown: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
isCommentAuthor: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
isPlusButton: {
|
isPlusButton: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
@ -133,7 +141,7 @@ const handleUpdateReaction = (reactionData) => {
|
|||||||
// 비밀번호 확인
|
// 비밀번호 확인
|
||||||
const logPasswordAndEmit = () => {
|
const logPasswordAndEmit = () => {
|
||||||
emit('submitPassword', props.comment, password.value);
|
emit('submitPassword', props.comment, password.value);
|
||||||
password.value = "";
|
password.value = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(() => props.comment.isEditTextarea, (newVal) => {
|
watch(() => props.comment.isEditTextarea, (newVal) => {
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
class="form-control flex-grow-1"
|
class="form-control flex-grow-1"
|
||||||
v-model="password"
|
v-model="password"
|
||||||
/>
|
/>
|
||||||
<!-- <span v-if="passwordAlert" class="invalid-feedback d-block text-start">{{ passwordAlert }}</span> -->
|
<span v-if="passwordAlert" class="invalid-feedback d-block text-start ms-2">{{ passwordAlert }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -70,6 +70,10 @@ const props = defineProps({
|
|||||||
parentId: {
|
parentId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
|
},
|
||||||
|
passwordAlert: {
|
||||||
|
type: String,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
<BoardComment
|
<BoardComment
|
||||||
:unknown="unknown"
|
:unknown="unknown"
|
||||||
:comment="comment"
|
:comment="comment"
|
||||||
|
:isCommentAuthor="comment.isCommentAuthor"
|
||||||
:isCommentPassword="comment.isCommentPassword"
|
:isCommentPassword="comment.isCommentPassword"
|
||||||
:isEditTextarea="comment.isEditTextarea"
|
:isEditTextarea="comment.isEditTextarea"
|
||||||
:passwordCommentAlert="passwordCommentAlert"
|
:passwordCommentAlert="passwordCommentAlert"
|
||||||
@ -38,6 +39,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
isCommentAuthor: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
isCommentPassword: {
|
isCommentPassword: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
@ -52,7 +57,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['submitComment', 'updateReaction', 'editClick', 'submitPassword', 'clearPassword']);
|
const emit = defineEmits(['submitComment', 'updateReaction', 'editClick', 'deleteClick', 'submitPassword', 'clearPassword']);
|
||||||
|
|
||||||
const submitComment = (replyData) => {
|
const submitComment = (replyData) => {
|
||||||
emit('submitComment', replyData);
|
emit('submitComment', replyData);
|
||||||
|
|||||||
@ -22,7 +22,8 @@
|
|||||||
<!-- 버튼 영역 -->
|
<!-- 버튼 영역 -->
|
||||||
<div class="ms-auto text-end">
|
<div class="ms-auto text-end">
|
||||||
<!-- 수정, 삭제 버튼 -->
|
<!-- 수정, 삭제 버튼 -->
|
||||||
<template v-if="author || showDetail">
|
<!-- <template v-if="isAuthor || showDetail"> -->
|
||||||
|
<template v-if="isCommentProfile ? isCommentAuthor : isAuthor">
|
||||||
<EditButton @click.stop="editClick" />
|
<EditButton @click.stop="editClick" />
|
||||||
<DeleteButton @click.stop="deleteClick" />
|
<DeleteButton @click.stop="deleteClick" />
|
||||||
</template>
|
</template>
|
||||||
@ -49,7 +50,7 @@ import BoardRecommendBtn from '../button/BoardRecommendBtn.vue';
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
comment: {
|
comment: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: false,
|
||||||
},
|
},
|
||||||
boardId: {
|
boardId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@ -61,7 +62,11 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
profileName: {
|
profileName: {
|
||||||
type: String,
|
type: String,
|
||||||
|
<<<<<<< HEAD
|
||||||
default: '익명',
|
default: '익명',
|
||||||
|
=======
|
||||||
|
default: '',
|
||||||
|
>>>>>>> board-comment
|
||||||
},
|
},
|
||||||
unknown: {
|
unknown: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -72,10 +77,12 @@ const props = defineProps({
|
|||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
// 게시글의 작성자 여부를 확인 : 현재 로그인한 사용자가 이 게시글의 작성자인지 여부
|
// 게시글의 작성자 여부를 확인 : 현재 로그인한 사용자가 이 게시글의 작성자인지 여부
|
||||||
author: {
|
isAuthor: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
isCommentAuthor: Boolean, // 댓글 작성자인지 여부
|
||||||
|
isCommentProfile: Boolean, // 현재 컴포넌트가 댓글용인지 여부
|
||||||
date: {
|
date: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
@ -98,6 +105,7 @@ const emit = defineEmits(['updateReaction', 'editClick', 'deleteClick']);
|
|||||||
|
|
||||||
// 수정
|
// 수정
|
||||||
const editClick = () => {
|
const editClick = () => {
|
||||||
|
console.log('클릭 확인')
|
||||||
emit('editClick', props.unknown);
|
emit('editClick', props.unknown);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -14,10 +14,15 @@
|
|||||||
:placeholder="title"
|
:placeholder="title"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:min="min"
|
:min="min"
|
||||||
|
@focusout="$emit('focusout', modelValue)"
|
||||||
/>
|
/>
|
||||||
<div class="invalid-feedback" :class="isAlert ? 'display-block' : ''">
|
<div class="invalid-feedback" :class="isAlert ? 'display-block' : ''">
|
||||||
{{ title }}을 확인해주세요.
|
{{ title }}을 확인해주세요.
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 카테고리 중복 -->
|
||||||
|
<div class="invalid-feedback" :class="isCateAlert ? 'display-block' : ''">
|
||||||
|
카테고리 중복입니다.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -57,6 +62,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
isCateAlert : {
|
||||||
|
type :Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
isLabel : {
|
isLabel : {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
@ -73,7 +82,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Emits 정의
|
// Emits 정의
|
||||||
const emits = defineEmits(['update:modelValue']);
|
const emits = defineEmits(['update:modelValue', 'focusout']);
|
||||||
|
|
||||||
// 로컬 상태로 사용하기 위한 `inputValue`
|
// 로컬 상태로 사용하기 위한 `inputValue`
|
||||||
const inputValue = ref(props.modelValue);
|
const inputValue = ref(props.modelValue);
|
||||||
|
|||||||
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, defineEmits, computed } from "vue";
|
import { defineProps, defineEmits, computed } from "vue";
|
||||||
|
import { formatDate } from '@/common/formattedDate.js';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isOpen: Boolean,
|
isOpen: Boolean,
|
||||||
@ -130,14 +131,6 @@ const mergedVacations = computed(() => {
|
|||||||
return all;
|
return all;
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 날짜 포맷 (YYYY-MM-DD) */
|
|
||||||
const formatDate = (dateString) => {
|
|
||||||
if (!dateString) return "";
|
|
||||||
// 만약 dateString이 "YYYY-MM-DD" 형식이라면 그대로 반환
|
|
||||||
// 혹은 "YYYY-MM-DD..." 라면 앞 10자만 잘라 반환
|
|
||||||
return dateString.substring(0, 10);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** 모달 닫기 */
|
/** 모달 닫기 */
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card-body d-flex justify-content-center">
|
<div class="card-body d-flex justify-content-center m-n5">
|
||||||
<ul class="list-unstyled d-flex flex-wrap align-items-center gap-2 mb-0 mt-2">
|
<ul class="list-unstyled d-flex flex-wrap align-items-center gap-2 mb-0 mt-2">
|
||||||
<li
|
<li
|
||||||
v-for="(user, index) in sortedUserList"
|
v-for="(user, index) in sortedUserList"
|
||||||
|
|||||||
@ -4,12 +4,12 @@
|
|||||||
v-if="isWriteVisible"
|
v-if="isWriteVisible"
|
||||||
@close="isWriteVisible = false"
|
@close="isWriteVisible = false"
|
||||||
:dataList="cateList"
|
:dataList="cateList"
|
||||||
@addCategory="addCategory"
|
|
||||||
@addWord="editWord"
|
@addWord="editWord"
|
||||||
:NumValue="item.WRDDICSEQ"
|
:NumValue="item.WRDDICSEQ"
|
||||||
:formValue="item.WRDDICCAT"
|
:formValue="item.WRDDICCAT"
|
||||||
:titleValue="item.WRDDICTTL"
|
:titleValue="item.WRDDICTTL"
|
||||||
:contentValue="item.WRDDICCON"
|
:contentValue="item.WRDDICCON"
|
||||||
|
:isDisabled="userStore.user.role !== 'ROLE_ADMIN'"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
@ -38,7 +38,7 @@
|
|||||||
:style="{ borderColor: item.author.color}"/>
|
:style="{ borderColor: item.author.color}"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="mb-0 small fw-medium">{{ formatDate(item.author.createdAt) }}</p>
|
<p class="mb-0 small fw-medium">{{ formattedDate(item.author.createdAt) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -55,13 +55,13 @@
|
|||||||
:style="{ borderColor: item.lastEditor.color}"/>
|
:style="{ borderColor: item.lastEditor.color}"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="mb-0 small fw-medium">{{ formatDate(item.lastEditor.updatedAt) }}</p>
|
<p class="mb-0 small fw-medium">{{ formattedDate(item.lastEditor.updatedAt) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="edit-btn">
|
<div class="edit-btn" v-if="userStore.user.role !== 'ROLE_ADMIN'">
|
||||||
<EditBtn @click="toggleWriteVisible" />
|
<EditBtn @click="toggleWriteVisible" />
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -74,6 +74,7 @@ import { ref, toRefs, getCurrentInstance, } from 'vue';
|
|||||||
import EditBtn from '@/components/button/EditBtn.vue';
|
import EditBtn from '@/components/button/EditBtn.vue';
|
||||||
import $api from '@api';
|
import $api from '@api';
|
||||||
import DictWrite from './DictWrite.vue';
|
import DictWrite from './DictWrite.vue';
|
||||||
|
import { formattedDate } from "@/common/formattedDate";
|
||||||
|
|
||||||
import { useUserInfoStore } from '@s/useUserInfoStore';
|
import { useUserInfoStore } from '@s/useUserInfoStore';
|
||||||
|
|
||||||
@ -98,9 +99,9 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 카테고리
|
// 카테고리
|
||||||
const localCateList = ref([...props.cateList]);
|
// const localCateList = ref([...props.cateList]);
|
||||||
// 선택 카테고리
|
// 선택 카테고리
|
||||||
const selectedCategory = ref('');
|
// const selectedCategory = ref('');
|
||||||
|
|
||||||
// cateList emit
|
// cateList emit
|
||||||
const emit = defineEmits(['update:cateList','refreshWordList', 'updateChecked']);
|
const emit = defineEmits(['update:cateList','refreshWordList', 'updateChecked']);
|
||||||
@ -115,41 +116,41 @@ const toggleWriteVisible = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//카테고리 등록 수정
|
//카테고리 등록 수정
|
||||||
const addCategory = (data) => {
|
// const addCategory = (data) => {
|
||||||
try {
|
// try {
|
||||||
const lastCategory = localCateList.value.length > 0
|
// const lastCategory = localCateList.value.length > 0
|
||||||
? localCateList.value[localCateList.value.length - 1]
|
// ? localCateList.value[localCateList.value.length - 1]
|
||||||
: null;
|
// : null;
|
||||||
const newValue = lastCategory ? lastCategory.value + 1 : 600101;
|
// const newValue = lastCategory ? lastCategory.value + 1 : 600101;
|
||||||
|
|
||||||
// console.log('lastCategory', lastCategory);
|
// // // console.log('lastCategory', lastCategory);
|
||||||
// console.log('newValue', newValue);
|
// // // console.log('newValue', newValue);
|
||||||
|
|
||||||
axios.post('worddict/insertCategory', {
|
// axios.post('worddict/insertCategory', {
|
||||||
CMNCODNAM: data
|
// CMNCODNAM: data
|
||||||
}).then(res => {
|
// }).then(res => {
|
||||||
if(res.data.data === 1){
|
// if(res.data.data === 1){
|
||||||
toastStore.onToast('카테고리가 추가 등록 되었습니다.', 's');
|
// toastStore.onToast('카테고리가 추가 등록 되었습니다.', 's');
|
||||||
const newCategory = { label: data, value: newValue };
|
// const newCategory = { label: data, value: newValue };
|
||||||
localCateList.value = [newCategory, ...localCateList.value];
|
// localCateList.value = [newCategory, ...localCateList.value];
|
||||||
selectedCategory.value = newCategory.value;
|
// selectedCategory.value = newCategory.value;
|
||||||
|
|
||||||
// console.log('newCategory', newCategory);
|
// // // console.log('newCategory', newCategory);
|
||||||
// console.log('localCateList.value', localCateList.value);
|
// // // console.log('localCateList.value', localCateList.value);
|
||||||
// console.log('selectedCategory.value', selectedCategory.value);
|
// // // console.log('selectedCategory.value', selectedCategory.value);
|
||||||
|
|
||||||
// 부모에게 전달
|
// // // 부모에게 전달
|
||||||
emit('update:cateList', localCateList.value);
|
// emit('update:cateList', localCateList.value);
|
||||||
} else if(res.data.message == '이미 존재하는 카테고리명입니다.') {
|
// } else if(res.data.message == '이미 존재하는 카테고리명입니다.') {
|
||||||
toastStore.onToast(res.data.message, 'e');
|
// toastStore.onToast(res.data.message, 'e');
|
||||||
}
|
// }
|
||||||
}).catch(err => {
|
// }).catch(err => {
|
||||||
console.error('카테고리 추가 중 오류:', err);
|
// console.error('카테고리 추가 중 오류:', err);
|
||||||
});
|
// });
|
||||||
} catch (err) {
|
// } catch (err) {
|
||||||
console.error('카테고리 추가 함수 오류:', err);
|
// console.error('카테고리 추가 함수 오류:', err);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
// 용어집 수정
|
// 용어집 수정
|
||||||
@ -191,11 +192,14 @@ const editWord = (data) => {
|
|||||||
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
const baseUrl = $api.defaults.baseURL.replace(/api\/$/, '');
|
||||||
|
|
||||||
// 날짜 포맷
|
// 날짜 포맷
|
||||||
const formatDate = (dateString) => new Date(dateString).toLocaleString();
|
// const formatDate = (dateString) => new Date(dateString).toLocaleString();
|
||||||
|
|
||||||
// 프로필 이미지
|
// 프로필 이미지
|
||||||
const getProfileImage = (imagePath) =>
|
const defaultProfile = "/img/icons/icon.png";
|
||||||
imagePath ? `${baseUrl}upload/img/profile/${imagePath}` : '/img/avatars/default-Profile.jpg';
|
|
||||||
|
const getProfileImage = (profilePath) => {
|
||||||
|
return profilePath && profilePath.trim() ? `${baseUrl}upload/img/profile/${profilePath}` : defaultProfile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// 체크 상태 변경 시 부모로 전달
|
// 체크 상태 변경 시 부모로 전달
|
||||||
|
|||||||
@ -13,20 +13,27 @@
|
|||||||
:disabled="isDisabled"
|
:disabled="isDisabled"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2 btn-margin">
|
<div class="col-2 btn-margin" v-if="!isDisabled">
|
||||||
<PlusBtn v-if="userStore.user.role == 'ROLE_ADMIN'" @click="toggleInput"/>
|
<PlusBtn @click="toggleInput"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" v-if="showInput">
|
<div class="row" v-if="showInput">
|
||||||
<div class="col-10">
|
<div class="col-10">
|
||||||
<FormInput title="카테고리 입력" name="카테고리" @update:modelValue="addCategory = $event" :is-alert="addCategoryAlert"/>
|
<FormInput
|
||||||
|
ref="categoryInputRef"
|
||||||
|
title="카테고리 입력"
|
||||||
|
name="카테고리"
|
||||||
|
@update:modelValue="addCategory = $event"
|
||||||
|
:is-cate-alert="addCategoryAlert"
|
||||||
|
@focusout="handleCategoryFocusout(addCategory)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2 btn-margin">
|
<!-- <div class="col-2 btn-margin">
|
||||||
<button class="btn btn-primary btn-icon" @click="saveInput">
|
<button class="btn btn-primary btn-icon" @click="saveInput">
|
||||||
<i class="bx bx-check"></i>
|
<i class="bx bx-check"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dict-w">
|
<div class="dict-w">
|
||||||
@ -58,13 +65,13 @@ import QEditor from '@/components/editor/QEditor.vue';
|
|||||||
import FormInput from '@/components/input/FormInput.vue';
|
import FormInput from '@/components/input/FormInput.vue';
|
||||||
import FormSelect from '@/components/input/FormSelect.vue';
|
import FormSelect from '@/components/input/FormSelect.vue';
|
||||||
import PlusBtn from '../button/PlusBtn.vue';
|
import PlusBtn from '../button/PlusBtn.vue';
|
||||||
import { useUserInfoStore } from '@s/useUserInfoStore';
|
// import { useUserInfoStore } from '@s/useUserInfoStore';
|
||||||
|
|
||||||
// 유저 구분
|
// 유저 구분
|
||||||
const userStore = useUserInfoStore();
|
// const userStore = useUserInfoStore();
|
||||||
|
|
||||||
// 유저 상태에 따른 disabled
|
// 유저 상태에 따른 disabled
|
||||||
const isDisabled = computed(() => userStore.user.role !== 'ROLE_ADMIN');
|
// const isDisabled = computed(() => userStore.user.role !== 'ROLE_ADMIN');
|
||||||
|
|
||||||
const emit = defineEmits(['close','addCategory','addWord']);
|
const emit = defineEmits(['close','addCategory','addWord']);
|
||||||
|
|
||||||
@ -83,15 +90,18 @@ const addCategoryAlert = ref(false);
|
|||||||
const selectCategory = ref('');
|
const selectCategory = ref('');
|
||||||
|
|
||||||
// 제목 상태
|
// 제목 상태
|
||||||
const computedTitle = computed(() =>
|
const computedTitle = computed(() =>
|
||||||
wordTitle.value === '' ? props.titleValue : wordTitle.value
|
wordTitle.value === '' ? props.titleValue : wordTitle.value
|
||||||
);
|
);
|
||||||
|
|
||||||
// 카테고리 상태
|
// 카테고리 상태
|
||||||
const selectedCategory = computed(() =>
|
const selectedCategory = computed(() =>
|
||||||
selectCategory.value === '' ? props.formValue : selectCategory.value
|
selectCategory.value === '' ? props.formValue : selectCategory.value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 카테고리 입력 중복 ref
|
||||||
|
const categoryInputRef = ref(null);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dataList: {
|
dataList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@ -106,7 +116,11 @@ const props = defineProps({
|
|||||||
titleValue : {
|
titleValue : {
|
||||||
type:String,
|
type:String,
|
||||||
},contentValue : {
|
},contentValue : {
|
||||||
type:String
|
type:String,
|
||||||
|
},
|
||||||
|
isDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -120,17 +134,17 @@ const toggleInput = () => {
|
|||||||
|
|
||||||
|
|
||||||
// 카테고리 저장
|
// 카테고리 저장
|
||||||
const saveInput = () => {
|
// const saveInput = () => {
|
||||||
if(addCategory.value == ''){
|
// if(addCategory.value == ''){
|
||||||
addCategoryAlert.value = true;
|
// addCategoryAlert.value = true;
|
||||||
return;
|
// return;
|
||||||
}else {
|
// }else {
|
||||||
addCategoryAlert.value = false;
|
// addCategoryAlert.value = false;
|
||||||
}
|
// }
|
||||||
// console.log('입력값 저장됨!',addCategory.value);
|
// console.log('입력값 저장됨!',addCategory.value);
|
||||||
emit('addCategory', addCategory.value);
|
// emit('addCategory', addCategory.value);
|
||||||
// showInput.value = false;
|
// showInput.value = false;
|
||||||
};
|
// };
|
||||||
|
|
||||||
const onChange = (newValue) => {
|
const onChange = (newValue) => {
|
||||||
selectCategory.value = newValue.target.value;
|
selectCategory.value = newValue.target.value;
|
||||||
@ -138,18 +152,12 @@ const onChange = (newValue) => {
|
|||||||
|
|
||||||
//용어 등록
|
//용어 등록
|
||||||
const saveWord = () => {
|
const saveWord = () => {
|
||||||
|
|
||||||
// if(addCategory.value == ''){
|
|
||||||
// addCategoryAlert.value = true;
|
|
||||||
// return;
|
|
||||||
// }else {
|
|
||||||
// addCategoryAlert.value = false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//validation
|
//validation
|
||||||
|
console.log('computedTitle.value', computedTitle.value);
|
||||||
|
|
||||||
|
|
||||||
// 용어 체크
|
// 용어 체크
|
||||||
if(computedTitle.value == '' || computedTitle.length == 0){
|
if(computedTitle.value == undefined){
|
||||||
wordTitleAlert.value = true;
|
wordTitleAlert.value = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -166,8 +174,35 @@ const saveWord = () => {
|
|||||||
category: selectedCategory.value,
|
category: selectedCategory.value,
|
||||||
content: content.value,
|
content: content.value,
|
||||||
};
|
};
|
||||||
emit('addWord', wordData ,addCategory.value );
|
|
||||||
|
emit('addWord', wordData, addCategory.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 카테고리 focusout 이벤트 핸들러 추가
|
||||||
|
const handleCategoryFocusout = (value) => {
|
||||||
|
|
||||||
|
const existingCategory = props.dataList.find(item => item.label === value);
|
||||||
|
// console.log('existingCategory', existingCategory);
|
||||||
|
|
||||||
|
if (existingCategory) {
|
||||||
|
// console.log('이미 존재하는 카테고리입니다:', value);
|
||||||
|
addCategoryAlert.value = true;
|
||||||
|
|
||||||
|
// 중복시 강제 focus
|
||||||
|
setTimeout(() => {
|
||||||
|
const inputElement = categoryInputRef.value?.$el?.querySelector('input');
|
||||||
|
if (inputElement) {
|
||||||
|
inputElement.focus();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
addCategoryAlert.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -180,4 +215,4 @@ const saveWord = () => {
|
|||||||
margin-top: 2.5rem
|
margin-top: 2.5rem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -24,14 +24,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import TheTop from './TheTop.vue';
|
import TheTop from './TheTop.vue';
|
||||||
import TheFooter from './TheFooter.vue';
|
import TheFooter from './TheFooter.vue';
|
||||||
import TheMenu from './TheMenu.vue';
|
import TheMenu from './TheMenu.vue';
|
||||||
import { nextTick } from 'vue';
|
import { nextTick } from 'vue';
|
||||||
import { wait } from '@/common/utils';
|
import { wait } from '@/common/utils';
|
||||||
|
|
||||||
window.isDarkStyle = window.Helpers.isDarkStyle();
|
window.isDarkStyle = window.Helpers.isDarkStyle();
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
const loadScript = src => {
|
const loadScript = src => {
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
script.src = src;
|
script.src = src;
|
||||||
@ -44,6 +45,25 @@ nextTick(async () => {
|
|||||||
loadScript('/vendor/js/menu.js');
|
loadScript('/vendor/js/menu.js');
|
||||||
// loadScript('/js/main.js');
|
// loadScript('/js/main.js');
|
||||||
});
|
});
|
||||||
|
=======
|
||||||
|
const loadScript = src => {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = src;
|
||||||
|
script.type = 'text/javascript';
|
||||||
|
script.async = true;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
// script.onload = () => {
|
||||||
|
// console.log(`${src} loaded successfully.`);
|
||||||
|
// };
|
||||||
|
script.onerror = () => {
|
||||||
|
console.error(`Failed to load script: ${src}`);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nextTick(async () => {
|
||||||
|
await wait(200);
|
||||||
|
loadScript('/vendor/js/menu.js');
|
||||||
|
loadScript('/js/main.js');
|
||||||
|
});
|
||||||
|
>>>>>>> board-comment
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style></style>
|
||||||
</style>
|
|
||||||
|
|||||||
@ -152,7 +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">
|
||||||
<img v-if="user" :src="`${baseUrl}upload/img/profile/${user.profile}`" alt="Profile Image" class="w-px-40 h-auto 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>
|
</a>
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@ -10,14 +10,14 @@
|
|||||||
:boardId="currentBoardId"
|
:boardId="currentBoardId"
|
||||||
:profileName="profileName"
|
:profileName="profileName"
|
||||||
:unknown="unknown"
|
:unknown="unknown"
|
||||||
:author="isAuthor"
|
|
||||||
:views="views"
|
:views="views"
|
||||||
:commentNum="commentNum"
|
:commentNum="commentNum"
|
||||||
:date="formattedBoardDate"
|
:date="formattedBoardDate"
|
||||||
:isLike="false"
|
:isLike="false"
|
||||||
|
:isAuthor="isAuthor"
|
||||||
@editClick="editClick"
|
@editClick="editClick"
|
||||||
@deleteClick="deleteClick"
|
@deleteClick="deleteClick"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 비밀번호 입력창 (익명일 경우) -->
|
<!-- 비밀번호 입력창 (익명일 경우) -->
|
||||||
<div v-if="isPassword && unknown" class="mt-3 w-25 ms-auto">
|
<div v-if="isPassword && unknown" class="mt-3 w-25 ms-auto">
|
||||||
@ -74,8 +74,14 @@
|
|||||||
:likeClicked="likeClicked"
|
:likeClicked="likeClicked"
|
||||||
:dislikeClicked="dislikeClicked"
|
:dislikeClicked="dislikeClicked"
|
||||||
@updateReaction="handleUpdateReaction"
|
@updateReaction="handleUpdateReaction"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<p>현재 로그인한 사용자 ID: {{ currentUserId }}</p>
|
||||||
|
<p>게시글 작성자: {{ authorId }}</p>
|
||||||
|
<p>isAuthor 값: {{ isAuthor }}</p>
|
||||||
|
<!-- <p>use이미지:{{userStore.user.img}}</p> -->
|
||||||
|
<!-- <img :src="`http://localhost:10325/upload/img/profile/${userStore.user.profile}`" alt="Profile Image" class="w-px-40 h-auto rounded-circle"/> -->
|
||||||
|
|
||||||
|
|
||||||
<!-- 첨부파일 목록 -->
|
<!-- 첨부파일 목록 -->
|
||||||
<!-- <ul v-if="attachments.length" class="attachments mt-4 list-unstyled">
|
<!-- <ul v-if="attachments.length" class="attachments mt-4 list-unstyled">
|
||||||
@ -88,6 +94,7 @@
|
|||||||
<BoardCommentArea
|
<BoardCommentArea
|
||||||
:profileName="profileName"
|
:profileName="profileName"
|
||||||
:unknown="unknown"
|
:unknown="unknown"
|
||||||
|
:passwordAlert="passwordAlert"
|
||||||
@submitComment="handleCommentSubmit"
|
@submitComment="handleCommentSubmit"
|
||||||
/>
|
/>
|
||||||
<!-- <BoardCommentArea :profileName="profileName" :unknown="unknown" /> -->
|
<!-- <BoardCommentArea :profileName="profileName" :unknown="unknown" /> -->
|
||||||
@ -97,7 +104,7 @@
|
|||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<BoardCommentList
|
<BoardCommentList
|
||||||
:unknown="unknown"
|
:unknown="unknown"
|
||||||
:comments="comments"
|
:comments="commentsWithAuthStatus"
|
||||||
:isCommentPassword="isCommentPassword"
|
:isCommentPassword="isCommentPassword"
|
||||||
:isEditTextarea="isEditTextarea"
|
:isEditTextarea="isEditTextarea"
|
||||||
:passwordCommentAlert="passwordCommentAlert"
|
:passwordCommentAlert="passwordCommentAlert"
|
||||||
@ -130,6 +137,7 @@ import BoardRecommendBtn from '@c/button/BoardRecommendBtn.vue';
|
|||||||
import Pagination from '@c/pagination/Pagination.vue';
|
import Pagination from '@c/pagination/Pagination.vue';
|
||||||
import { ref, onMounted, computed } from 'vue';
|
import { ref, onMounted, computed } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||||
import axios from '@api';
|
import axios from '@api';
|
||||||
|
|
||||||
// 게시물 데이터 상태
|
// 게시물 데이터 상태
|
||||||
@ -148,12 +156,28 @@ const comments = ref([]);
|
|||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const userStore = useUserInfoStore();
|
||||||
const currentBoardId = ref(Number(route.params.id));
|
const currentBoardId = ref(Number(route.params.id));
|
||||||
|
<<<<<<< HEAD
|
||||||
const unknown = computed(() => profileName.value === '익명');
|
const unknown = computed(() => profileName.value === '익명');
|
||||||
const currentUserId = ref('김자바'); // 현재 로그인한 사용자 id
|
const currentUserId = ref('김자바'); // 현재 로그인한 사용자 id
|
||||||
const authorId = ref(null); // 작성자 id
|
const authorId = ref(null); // 작성자 id
|
||||||
|
=======
|
||||||
|
// const unknown = computed(() => profileName.value === '익명');
|
||||||
|
const currentUserId = computed(() => userStore.user.id); // 현재 로그인한 사용자 id
|
||||||
|
const authorId = ref(''); // 작성자 id
|
||||||
|
>>>>>>> board-comment
|
||||||
|
|
||||||
const isAuthor = computed(() => currentUserId.value === authorId.value);
|
const isAuthor = computed(() => currentUserId.value === authorId.value);
|
||||||
|
// const isCommentAuthor =
|
||||||
|
const commentsWithAuthStatus = computed(() => {
|
||||||
|
const updatedComments = comments.value.map(comment => ({
|
||||||
|
...comment,
|
||||||
|
isCommentAuthor: comment.authorId === currentUserId.value
|
||||||
|
}));
|
||||||
|
// console.log("✅ commentsWithAuthStatus 업데이트됨:", updatedComments);
|
||||||
|
return updatedComments;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
const password = ref('');
|
const password = ref('');
|
||||||
@ -187,9 +211,12 @@ const fetchBoardDetails = async () => {
|
|||||||
const response = await axios.get(`board/${currentBoardId.value}`);
|
const response = await axios.get(`board/${currentBoardId.value}`);
|
||||||
const data = response.data.data;
|
const data = response.data.data;
|
||||||
|
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
// API 응답 데이터 반영
|
// API 응답 데이터 반영
|
||||||
// const boardDetail = data.boardDetail || {};
|
// const boardDetail = data.boardDetail || {};
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
profileName.value = data.author || '익명';
|
profileName.value = data.author || '익명';
|
||||||
|
|
||||||
// 익명확인하고 싶을때
|
// 익명확인하고 싶을때
|
||||||
@ -198,6 +225,15 @@ const fetchBoardDetails = async () => {
|
|||||||
// 게시글의 작성자 여부를 확인 : 현재 로그인한 사용자가 이 게시글의 작성자인지 여부
|
// 게시글의 작성자 여부를 확인 : 현재 로그인한 사용자가 이 게시글의 작성자인지 여부
|
||||||
authorId.value = data.author;
|
authorId.value = data.author;
|
||||||
|
|
||||||
|
=======
|
||||||
|
profileName.value = data.author;
|
||||||
|
|
||||||
|
// 익명확인하고 싶을때
|
||||||
|
// profileName.value = '익명';
|
||||||
|
|
||||||
|
|
||||||
|
authorId.value = data.authorId; //게시글 작성자 id
|
||||||
|
>>>>>>> board-comment
|
||||||
boardTitle.value = data.title || '제목 없음';
|
boardTitle.value = data.title || '제목 없음';
|
||||||
boardContent.value = data.content || '';
|
boardContent.value = data.content || '';
|
||||||
date.value = data.date || '';
|
date.value = data.date || '';
|
||||||
@ -262,7 +298,7 @@ const handleCommentReaction = async ({ boardId, commentId, isLike, isDislike })
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 댓글 목록 조회 (대댓글 포함)
|
// 댓글 목록 조회
|
||||||
const fetchComments = async (page = 1) => {
|
const fetchComments = async (page = 1) => {
|
||||||
try {
|
try {
|
||||||
// 댓글
|
// 댓글
|
||||||
@ -273,11 +309,20 @@ const fetchComments = async (page = 1) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
console.log(response.data.data)
|
||||||
|
|
||||||
|
>>>>>>> board-comment
|
||||||
const commentsList = response.data.data.list.map(comment => ({
|
const commentsList = response.data.data.list.map(comment => ({
|
||||||
commentId: comment.LOCCMTSEQ, // 댓글 ID
|
commentId: comment.LOCCMTSEQ, // 댓글 ID
|
||||||
boardId: comment.LOCBRDSEQ,
|
boardId: comment.LOCBRDSEQ,
|
||||||
parentId: comment.LOCCMTPNT, // 부모 ID
|
parentId: comment.LOCCMTPNT, // 부모 ID
|
||||||
author: comment.author || '익명',
|
author: comment.author || '익명',
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
authorId: comment.authorId,
|
||||||
|
>>>>>>> board-comment
|
||||||
content: comment.LOCCMTRPY,
|
content: comment.LOCCMTRPY,
|
||||||
likeCount: comment.likeCount || 0,
|
likeCount: comment.likeCount || 0,
|
||||||
dislikeCount: comment.dislikeCount || 0,
|
dislikeCount: comment.dislikeCount || 0,
|
||||||
@ -286,8 +331,6 @@ const fetchComments = async (page = 1) => {
|
|||||||
createdAtRaw: new Date(comment.LOCCMTRDT), // 정렬용
|
createdAtRaw: new Date(comment.LOCCMTRDT), // 정렬용
|
||||||
createdAt: formattedDate(comment.LOCCMTRDT), // 표시용
|
createdAt: formattedDate(comment.LOCCMTRDT), // 표시용
|
||||||
children: [], // 대댓글을 담을 배열
|
children: [], // 대댓글을 담을 배열
|
||||||
// isCommentPassword: false, // 개별 댓글 비밀번호 입력 상태
|
|
||||||
// isEditTextarea: false // 개별 댓글 수정 상태
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for (const comment of commentsList) {
|
for (const comment of commentsList) {
|
||||||
@ -297,7 +340,7 @@ const fetchComments = async (page = 1) => {
|
|||||||
params: { LOCCMTPNT: comment.commentId }
|
params: { LOCCMTPNT: comment.commentId }
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log(`대댓글 데이터 (${comment.commentId}의 대댓글):`, replyResponse.data);
|
console.log(`대댓글 데이터 (${comment.commentId}의 대댓글):`, replyResponse.data);
|
||||||
|
|
||||||
if (replyResponse.data.data) {
|
if (replyResponse.data.data) {
|
||||||
comment.children = replyResponse.data.data.map(reply => ({
|
comment.children = replyResponse.data.data.map(reply => ({
|
||||||
@ -343,21 +386,22 @@ const fetchComments = async (page = 1) => {
|
|||||||
console.log('댓글 목록 불러오기 오류:', error);
|
console.log('댓글 목록 불러오기 오류:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const isSubmitting = ref(false);
|
// const isSubmitting = ref(false);
|
||||||
|
|
||||||
// 댓글 작성
|
// 댓글 작성
|
||||||
const handleCommentSubmit = async ({ comment, password }) => {
|
const handleCommentSubmit = async ({ comment, password }) => {
|
||||||
// if (unknown.value && !password) {
|
console.log('댓글')
|
||||||
// passwordAlert.value = "익명 사용자는 비밀번호를 입력해야 합니다."; // UI에 메시지 표시
|
//비밀번호 입력 안했을시
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (!password) {
|
// if (!password) {
|
||||||
// passwordAlert.value = "비밀번호를 입력해야 합니다."; // UI에서 경고 표시
|
// passwordAlert.value = "비밀번호를 입력해야 합니다.";
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// console.log('비밀번호 눌렀음')
|
||||||
|
|
||||||
// 중복 실행 방지
|
// 중복 실행 방지
|
||||||
if (isSubmitting.value) return;
|
// if (isSubmitting.value) return;
|
||||||
isSubmitting.value = true;
|
// isSubmitting.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(`board/${currentBoardId.value}/comment`, {
|
const response = await axios.post(`board/${currentBoardId.value}/comment`, {
|
||||||
@ -368,7 +412,7 @@ const handleCommentSubmit = async ({ comment, password }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
// console.log('댓글 작성 성공:', response.data.message);
|
console.log('댓글 작성 성공:', response.data.message);
|
||||||
await fetchComments();
|
await fetchComments();
|
||||||
} else {
|
} else {
|
||||||
console.log('댓글 작성 실패:', response.data.message);
|
console.log('댓글 작성 실패:', response.data.message);
|
||||||
@ -439,19 +483,28 @@ const deleteClick = (unknown) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 댓글 수정 버튼 클릭(대댓글 포함)
|
// 댓글 수정 버튼 클릭
|
||||||
const editComment = (comment) => {
|
const editComment = (comment) => {
|
||||||
if (comment.isEditTextarea) {
|
const targetComment = comments.value.find(c => c.commentId === comment.commentId);
|
||||||
// 이미 수정창이 열려 있으면 닫기
|
|
||||||
comment.isEditTextarea = false;
|
if (!targetComment) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 수정 text창 열림, 닫힘 유무
|
||||||
|
if (targetComment.isEditTextarea) {
|
||||||
|
targetComment.isEditTextarea = false;
|
||||||
|
} else {
|
||||||
|
targetComment.isEditTextarea = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 익명일때
|
||||||
if (unknown.value) {
|
if (unknown.value) {
|
||||||
toggleCommentPassword(comment, "edit");
|
toggleCommentPassword(comment, "edit");
|
||||||
} else {
|
} else {
|
||||||
comment.isEditTextarea = true;
|
comment.isEditTextarea = true;
|
||||||
}
|
}
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
// comments.value.forEach(c => {
|
// comments.value.forEach(c => {
|
||||||
// c.isEditTextarea = false;
|
// c.isEditTextarea = false;
|
||||||
@ -463,10 +516,13 @@ const editComment = (comment) => {
|
|||||||
// } else {
|
// } else {
|
||||||
// comment.isEditTextarea = true;
|
// comment.isEditTextarea = true;
|
||||||
// }
|
// }
|
||||||
|
=======
|
||||||
|
>>>>>>> board-comment
|
||||||
}
|
}
|
||||||
|
|
||||||
// 댓글 삭제 버튼 클릭(대댓글 포함)
|
// 댓글 삭제 버튼 클릭
|
||||||
const deleteComment = (comment) => {
|
const deleteComment = async (comment) => {
|
||||||
|
// 익명 사용자인 경우
|
||||||
if (unknown.value) {
|
if (unknown.value) {
|
||||||
if (comment.isEditTextarea) {
|
if (comment.isEditTextarea) {
|
||||||
// 현재 수정 중이라면 수정 모드를 끄고, 삭제 비밀번호 입력창을 띄움
|
// 현재 수정 중이라면 수정 모드를 끄고, 삭제 비밀번호 입력창을 띄움
|
||||||
@ -477,8 +533,8 @@ const deleteComment = (comment) => {
|
|||||||
toggleCommentPassword(comment, "delete");
|
toggleCommentPassword(comment, "delete");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 로그인 사용자 바로 삭제
|
// 로그인 사용자인 경우 (바로 삭제)
|
||||||
comments.value = comments.value.filter(c => c.commentId !== comment.commentId);
|
deleteReplyComment(comment)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -531,7 +587,7 @@ const submitPassword = async () => {
|
|||||||
}
|
}
|
||||||
lastClickedButton.value = null;
|
lastClickedButton.value = null;
|
||||||
} else {
|
} else {
|
||||||
passwordAlert.value = "비밀번호가 일치하지 않습니다.????";
|
passwordAlert.value = "비밀번호가 일치하지 않습니다.";
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.log("📌 전체 오류:", error);
|
// console.log("📌 전체 오류:", error);
|
||||||
@ -552,6 +608,7 @@ const submitPassword = async () => {
|
|||||||
|
|
||||||
// 댓글 삭제 (비밀번호 확인 후)
|
// 댓글 삭제 (비밀번호 확인 후)
|
||||||
const submitCommentPassword = async (comment, password) => {
|
const submitCommentPassword = async (comment, password) => {
|
||||||
|
|
||||||
if (!password) {
|
if (!password) {
|
||||||
passwordCommentAlert.value = "비밀번호를 입력해주세요.";
|
passwordCommentAlert.value = "비밀번호를 입력해주세요.";
|
||||||
return;
|
return;
|
||||||
@ -564,12 +621,19 @@ const submitCommentPassword = async (comment, password) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.data.code === 200 && response.data.data === true) {
|
if (response.data.code === 200 && response.data.data === true) {
|
||||||
|
passwordCommentAlert.value = "";
|
||||||
comment.isCommentPassword = false;
|
comment.isCommentPassword = false;
|
||||||
|
|
||||||
if (lastCommentClickedButton.value === "edit") {
|
if (lastCommentClickedButton.value === "edit") {
|
||||||
comment.isEditTextarea = true;
|
comment.isEditTextarea = true;
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
passwordCommentAlert.value = "";
|
||||||
|
|
||||||
|
>>>>>>> board-comment
|
||||||
// handleSubmitEdit(comment, comment.content);
|
// handleSubmitEdit(comment, comment.content);
|
||||||
} else if (lastCommentClickedButton.value === "delete") {
|
} else if (lastCommentClickedButton.value === "delete") {
|
||||||
|
passwordCommentAlert.value = "";
|
||||||
|
|
||||||
deleteReplyComment(comment)
|
deleteReplyComment(comment)
|
||||||
}
|
}
|
||||||
@ -631,7 +695,7 @@ const deleteReplyComment = async (comment) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 댓글 수정 확인 (대댓글 포함)
|
// 댓글 수정 확인
|
||||||
const handleSubmitEdit = async (comment, editedContent) => {
|
const handleSubmitEdit = async (comment, editedContent) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.put(`board/comment/${comment.commentId}`, {
|
const response = await axios.put(`board/comment/${comment.commentId}`, {
|
||||||
@ -640,8 +704,19 @@ const handleSubmitEdit = async (comment, editedContent) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 수정 성공 시 업데이트
|
// 수정 성공 시 업데이트
|
||||||
|
<<<<<<< HEAD
|
||||||
comment.content = editedContent;
|
comment.content = editedContent;
|
||||||
comment.isEditTextarea = false;
|
comment.isEditTextarea = false;
|
||||||
|
=======
|
||||||
|
// comment.content = editedContent;
|
||||||
|
// comment.isEditTextarea = false;
|
||||||
|
if (response.status === 200) {
|
||||||
|
// 댓글 목록 새로고침
|
||||||
|
await fetchComments();
|
||||||
|
} else {
|
||||||
|
console.log("❌ 댓글 수정 실패:", response.data);
|
||||||
|
}
|
||||||
|
>>>>>>> board-comment
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("댓글 수정 중 오류 발생:", error);
|
console.error("댓글 수정 중 오류 발생:", error);
|
||||||
}
|
}
|
||||||
@ -650,7 +725,16 @@ const handleSubmitEdit = async (comment, editedContent) => {
|
|||||||
// 댓글 수정 취소 (대댓글 포함)
|
// 댓글 수정 취소 (대댓글 포함)
|
||||||
const handleCancelEdit = (comment) => {
|
const handleCancelEdit = (comment) => {
|
||||||
console.log("BoardView.vue - 댓글 수정 취소:", comment);
|
console.log("BoardView.vue - 댓글 수정 취소:", comment);
|
||||||
comment.isEditTextarea = false;
|
|
||||||
|
// 원본 comments 배열에서 동일한 comment 찾기
|
||||||
|
const targetComment = comments.value.find(c => c.commentId === comment.commentId);
|
||||||
|
|
||||||
|
if (targetComment) {
|
||||||
|
console.log("✅ 원본 데이터 찾음, 수정 취소 처리 가능");
|
||||||
|
targetComment.isEditTextarea = false;
|
||||||
|
} else {
|
||||||
|
console.error("❌ 원본 데이터 찾을 수 없음, 수정 취소 실패");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 페이지 변경
|
// 페이지 변경
|
||||||
|
|||||||
@ -5,12 +5,16 @@
|
|||||||
<!-- Sidebar: 사이드바 영역 -->
|
<!-- Sidebar: 사이드바 영역 -->
|
||||||
<div class="col-3 app-calendar-sidebar border-end" id="app-calendar-sidebar">
|
<div class="col-3 app-calendar-sidebar border-end" id="app-calendar-sidebar">
|
||||||
<div class="sidebar-content">
|
<div class="sidebar-content">
|
||||||
<!-- 사원 프로필 리스트 -->
|
<div class="sidebar-actions text-center my-3">
|
||||||
|
<HalfDayButtons
|
||||||
|
@toggleHalfDay="toggleHalfDay"
|
||||||
|
@addVacationRequests="saveVacationChanges"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<ProfileList
|
<ProfileList
|
||||||
@profileClick="handleProfileClick"
|
@profileClick="handleProfileClick"
|
||||||
:remainingVacationData="remainingVacationData"
|
:remainingVacationData="remainingVacationData"
|
||||||
/>
|
/>
|
||||||
<!-- 모달들은 화면 오버레이로 동작하므로 사이드바 내부에 두어도 무방 -->
|
|
||||||
<VacationModal
|
<VacationModal
|
||||||
v-if="isModalOpen"
|
v-if="isModalOpen"
|
||||||
:isOpen="isModalOpen"
|
:isOpen="isModalOpen"
|
||||||
@ -28,24 +32,23 @@
|
|||||||
@updateVacation="fetchRemainingVacation"
|
@updateVacation="fetchRemainingVacation"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-actions text-center my-3">
|
|
||||||
<!-- 액션 버튼 -->
|
|
||||||
<HalfDayButtons
|
|
||||||
@toggleHalfDay="toggleHalfDay"
|
|
||||||
@addVacationRequests="saveVacationChanges"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Content: 캘린더 영역 -->
|
<!-- Main Content: 캘린더 영역 -->
|
||||||
<div class="col app-calendar-content">
|
<div class="col app-calendar-content">
|
||||||
<div class="card shadow-none border-0">
|
<div class="card shadow-none border-0">
|
||||||
<div class="card-body pb-0">
|
<div class="card-body pb-0" style="position: relative;">
|
||||||
<full-calendar
|
<full-calendar
|
||||||
ref="fullCalendarRef"
|
ref="fullCalendarRef"
|
||||||
:options="calendarOptions"
|
:options="calendarOptions"
|
||||||
class="flatpickr-calendar-only"
|
class="flatpickr-calendar-only"
|
||||||
/>
|
/>
|
||||||
|
<!-- 숨겨진 데이트피커 인풋 -->
|
||||||
|
<input
|
||||||
|
ref="calendarDatepicker"
|
||||||
|
type="text"
|
||||||
|
style="display: none; position: absolute;"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -60,7 +63,12 @@
|
|||||||
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";
|
||||||
|
// Flatpickr 및 MonthSelect 플러그인 임포트
|
||||||
|
import flatpickr from "flatpickr";
|
||||||
|
import monthSelectPlugin from "flatpickr/dist/plugins/monthSelect/index";
|
||||||
import "flatpickr/dist/flatpickr.min.css";
|
import "flatpickr/dist/flatpickr.min.css";
|
||||||
|
import "flatpickr/dist/plugins/monthSelect/style.css";
|
||||||
|
|
||||||
import "@/assets/css/app-calendar.css";
|
import "@/assets/css/app-calendar.css";
|
||||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||||
import HalfDayButtons from "@c/button/HalfDayButtons.vue";
|
import HalfDayButtons from "@c/button/HalfDayButtons.vue";
|
||||||
@ -75,11 +83,11 @@
|
|||||||
const userListStore = useUserStore();
|
const userListStore = useUserStore();
|
||||||
const userList = ref([]);
|
const userList = ref([]);
|
||||||
const userColors = ref({});
|
const userColors = ref({});
|
||||||
const myVacations = ref([]); // 전체 "사용한 연차" 목록 (로그인한 사원의 휴가만)
|
const myVacations = ref([]); // 로그인한 사원의 휴가
|
||||||
const receivedVacations = ref([]); // 전체 "받은 연차" 목록
|
const receivedVacations = ref([]);
|
||||||
const isModalOpen = ref(false);
|
const isModalOpen = ref(false);
|
||||||
const remainingVacationData = ref({});
|
const remainingVacationData = ref({});
|
||||||
const modalYear = ref(new Date().getFullYear());
|
|
||||||
const lastRemainingYear = ref(new Date().getFullYear());
|
const lastRemainingYear = ref(new Date().getFullYear());
|
||||||
const lastRemainingMonth = ref(String(new Date().getMonth() + 1).padStart(2, "0"));
|
const lastRemainingMonth = ref(String(new Date().getMonth() + 1).padStart(2, "0"));
|
||||||
const isGrantModalOpen = ref(false);
|
const isGrantModalOpen = ref(false);
|
||||||
@ -94,8 +102,9 @@
|
|||||||
const holidayDates = ref(new Set());
|
const holidayDates = ref(new Set());
|
||||||
const fetchedEvents = ref([]);
|
const fetchedEvents = ref([]);
|
||||||
|
|
||||||
// 추가: 토글 상태 변수 (필요 시 사용 가능)
|
// 데이트피커 인풋 ref
|
||||||
const toggledDates = ref(new Set());
|
const calendarDatepicker = ref(null);
|
||||||
|
let fpInstance = null;
|
||||||
|
|
||||||
const calendarOptions = reactive({
|
const calendarOptions = reactive({
|
||||||
plugins: [dayGridPlugin, interactionPlugin],
|
plugins: [dayGridPlugin, interactionPlugin],
|
||||||
@ -115,9 +124,42 @@
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await userStore.userInfo();
|
await userStore.userInfo();
|
||||||
await fetchRemainingVacation();
|
await fetchRemainingVacation();
|
||||||
// 초기 vacation history도 가져오기
|
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
await fetchVacationHistory(currentYear);
|
await fetchVacationHistory(currentYear);
|
||||||
|
|
||||||
|
// Flatpickr 초기화 (달 선택 모드)
|
||||||
|
fpInstance = flatpickr(calendarDatepicker.value, {
|
||||||
|
dateFormat: "Y-m",
|
||||||
|
plugins: [
|
||||||
|
new monthSelectPlugin({
|
||||||
|
shorthand: true,
|
||||||
|
dateFormat: "Y-m",
|
||||||
|
altFormat: "F Y"
|
||||||
|
})
|
||||||
|
],
|
||||||
|
onChange: function(selectedDatesArr, dateStr) {
|
||||||
|
// 선택한 달의 첫날로 달력을 이동
|
||||||
|
fullCalendarRef.value.getApi().gotoDate(dateStr + "-01");
|
||||||
|
const [year, month] = dateStr.split("-");
|
||||||
|
lastRemainingYear.value = parseInt(year, 10);
|
||||||
|
lastRemainingMonth.value = month;
|
||||||
|
loadCalendarData(lastRemainingYear.value, lastRemainingMonth.value);
|
||||||
|
},
|
||||||
|
onClose: function() {
|
||||||
|
calendarDatepicker.value.style.display = "none";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// FullCalendar 헤더 제목(.fc-toolbar-title) 클릭 시 데이트피커 열기
|
||||||
|
nextTick(() => {
|
||||||
|
const titleEl = document.querySelector('.fc-toolbar-title');
|
||||||
|
if (titleEl) {
|
||||||
|
titleEl.style.cursor = 'pointer';
|
||||||
|
titleEl.addEventListener('click', () => {
|
||||||
|
fpInstance.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 연차 내역 API (초기 호출용)
|
// 연차 내역 API (초기 호출용)
|
||||||
@ -137,7 +179,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// lastRemainingYear 값이 변경될 때마다 해당 연도의 연차 내역 재조회
|
|
||||||
watch(lastRemainingYear, async (newYear, oldYear) => {
|
watch(lastRemainingYear, async (newYear, oldYear) => {
|
||||||
await fetchVacationHistory(newYear);
|
await fetchVacationHistory(newYear);
|
||||||
});
|
});
|
||||||
@ -156,27 +197,18 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 프로필 클릭 시 연차 내역 가져오기
|
|
||||||
const handleProfileClick = async (user) => {
|
const handleProfileClick = async (user) => {
|
||||||
try {
|
try {
|
||||||
if (isModalOpen.value) {
|
// 열린 모달이 있으면 모두 닫음 후 새 모달 열기
|
||||||
isModalOpen.value = false;
|
isModalOpen.value = false;
|
||||||
return;
|
isGrantModalOpen.value = false;
|
||||||
}
|
|
||||||
if (isGrantModalOpen.value) {
|
|
||||||
isGrantModalOpen.value = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (user.MEMBERSEQ === userStore.user.id) {
|
if (user.MEMBERSEQ === userStore.user.id) {
|
||||||
const year = new Date().getFullYear();
|
const displayedYear = lastRemainingYear.value;
|
||||||
await fetchVacationHistory(year);
|
await fetchVacationHistory(displayedYear);
|
||||||
isModalOpen.value = true;
|
isModalOpen.value = true;
|
||||||
lastRemainingYear.value = year;
|
|
||||||
isGrantModalOpen.value = false;
|
|
||||||
} else {
|
} else {
|
||||||
selectedUser.value = user;
|
selectedUser.value = user;
|
||||||
isGrantModalOpen.value = true;
|
isGrantModalOpen.value = true;
|
||||||
isModalOpen.value = false;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("🚨 연차 데이터 불러오기 실패:", error);
|
console.error("🚨 연차 데이터 불러오기 실패:", error);
|
||||||
@ -220,29 +252,23 @@
|
|||||||
return vacationCodeMap.value[typeCode] || "기타";
|
return vacationCodeMap.value[typeCode] || "기타";
|
||||||
};
|
};
|
||||||
|
|
||||||
// computed: lastRemainingYear과 일치하는 항목만 필터링
|
|
||||||
const filteredMyVacations = computed(() => {
|
const filteredMyVacations = computed(() => {
|
||||||
const filtered = myVacations.value.filter(vac => {
|
return myVacations.value.filter(vac => {
|
||||||
const dateStr = vac.date || vac.LOCVACUDT;
|
const dateStr = vac.date;
|
||||||
const year = dateStr ? dateStr.split("T")[0].substring(0, 4) : null;
|
const year = dateStr ? dateStr.split("T")[0].substring(0, 4) : null;
|
||||||
console.log("vacation year:", year, "lastRemainingYear:", lastRemainingYear.value);
|
|
||||||
return year === String(lastRemainingYear.value);
|
return year === String(lastRemainingYear.value);
|
||||||
});
|
});
|
||||||
console.log("filteredMyVacations:", filtered);
|
|
||||||
return filtered;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredReceivedVacations = computed(() => {
|
const filteredReceivedVacations = computed(() => {
|
||||||
return receivedVacations.value.filter(vac => {
|
return receivedVacations.value.filter(vac => {
|
||||||
const dateStr = vac.date || vac.LOCVACUDT;
|
const dateStr = vac.date;
|
||||||
const year = dateStr ? dateStr.split("T")[0].substring(0, 4) : null;
|
const year = dateStr ? dateStr.split("T")[0].substring(0, 4) : null;
|
||||||
console.log("vacation year:", year, "lastRemainingYear:", lastRemainingYear.value);
|
|
||||||
return dateStr && year === String(lastRemainingYear.value);
|
return dateStr && year === String(lastRemainingYear.value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateCalendarEvents() {
|
function updateCalendarEvents() {
|
||||||
// selectedDates에서 "delete"가 아닌 경우에 대해 이벤트 생성
|
|
||||||
const selectedEvents = Array.from(selectedDates.value)
|
const selectedEvents = Array.from(selectedDates.value)
|
||||||
.filter(([date, type]) => type !== "delete")
|
.filter(([date, type]) => type !== "delete")
|
||||||
.map(([date, type]) => ({
|
.map(([date, type]) => ({
|
||||||
@ -254,8 +280,6 @@
|
|||||||
classNames: [getVacationTypeClass(type), "selected-event"]
|
classNames: [getVacationTypeClass(type), "selected-event"]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// fetchedEvents에서, 만약 해당 날짜가 "delete" 상태라면
|
|
||||||
// 로그인한 사용자의(내) 이벤트만 제거하고, 다른 사용자의 이벤트는 그대로 둠.
|
|
||||||
const filteredFetchedEvents = fetchedEvents.value.filter(event => {
|
const filteredFetchedEvents = fetchedEvents.value.filter(event => {
|
||||||
if (event.saved && selectedDates.value.get(event.start) === "delete") {
|
if (event.saved && selectedDates.value.get(event.start) === "delete") {
|
||||||
if (event.memberSeq === userStore.user.id) {
|
if (event.memberSeq === userStore.user.id) {
|
||||||
@ -287,15 +311,12 @@
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 내 휴가 여부: LOCVACUDT의 앞 10자가 clickedDateStr과 같고, LOCVACRMM가 없거나 빈 문자열인 경우
|
|
||||||
const isMyVacation = myVacations.value.some(vac => {
|
const isMyVacation = myVacations.value.some(vac => {
|
||||||
const vacDate = vac.date ? String(vac.date).substring(0, 10) : "";
|
const vacDate = vac.date ? String(vac.date).substring(0, 10) : "";
|
||||||
return vacDate === clickedDateStr &&
|
return vacDate === clickedDateStr && !vac.receiverId;
|
||||||
(!vac.LOCVACRMM || String(vac.LOCVACRMM).trim() === "");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isMyVacation) {
|
if (isMyVacation) {
|
||||||
// 내 휴가인 경우: selectedDates에 "delete" 상태를 토글 (내 이벤트만 영향을 줌)
|
|
||||||
if (selectedDates.value.get(clickedDateStr) === "delete") {
|
if (selectedDates.value.get(clickedDateStr) === "delete") {
|
||||||
selectedDates.value.delete(clickedDateStr);
|
selectedDates.value.delete(clickedDateStr);
|
||||||
} else {
|
} else {
|
||||||
@ -305,9 +326,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 내 휴가가 없는 날짜: 일반 선택/토글 처리
|
|
||||||
if (selectedDates.value.has(clickedDateStr)) {
|
if (selectedDates.value.has(clickedDateStr)) {
|
||||||
console.log("일반 날짜 토글 off: 기존 선택 해제");
|
|
||||||
selectedDates.value.delete(clickedDateStr);
|
selectedDates.value.delete(clickedDateStr);
|
||||||
updateCalendarEvents();
|
updateCalendarEvents();
|
||||||
return;
|
return;
|
||||||
@ -315,7 +334,6 @@
|
|||||||
const type = halfDayType.value
|
const type = halfDayType.value
|
||||||
? (halfDayType.value === "AM" ? "700101" : "700102")
|
? (halfDayType.value === "AM" ? "700101" : "700102")
|
||||||
: "700103";
|
: "700103";
|
||||||
console.log("일반 날짜 토글 on: 선택 및 타입", type);
|
|
||||||
selectedDates.value.set(clickedDateStr, type);
|
selectedDates.value.set(clickedDateStr, type);
|
||||||
halfDayType.value = null;
|
halfDayType.value = null;
|
||||||
updateCalendarEvents();
|
updateCalendarEvents();
|
||||||
@ -331,7 +349,6 @@
|
|||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const vacationList = response.data;
|
const vacationList = response.data;
|
||||||
if (lastRemainingYear.value !== year) {
|
if (lastRemainingYear.value !== year) {
|
||||||
// 로그인한 사원의 휴가만 저장
|
|
||||||
myVacations.value = vacationList.filter(
|
myVacations.value = vacationList.filter(
|
||||||
(vac) => vac.MEMBERSEQ === userStore.user.id
|
(vac) => vac.MEMBERSEQ === userStore.user.id
|
||||||
);
|
);
|
||||||
@ -348,7 +365,7 @@
|
|||||||
backgroundColor,
|
backgroundColor,
|
||||||
classNames: [getVacationTypeClass(vac.LOCVACTYP)],
|
classNames: [getVacationTypeClass(vac.LOCVACTYP)],
|
||||||
saved: true,
|
saved: true,
|
||||||
memberSeq: vac.MEMBERSEQ, // 이벤트 소유자 정보
|
memberSeq: vac.MEMBERSEQ,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((event) => event.start);
|
.filter((event) => event.start);
|
||||||
@ -368,18 +385,18 @@
|
|||||||
const vacationsToAdd = selectedDatesArray
|
const vacationsToAdd = selectedDatesArray
|
||||||
.filter(([date, type]) => type !== "delete")
|
.filter(([date, type]) => type !== "delete")
|
||||||
.filter(([date, type]) =>
|
.filter(([date, type]) =>
|
||||||
!myVacations.value.some(vac => vac.LOCVACUDT && vac.LOCVACUDT.startsWith(date)) ||
|
!myVacations.value.some(vac => vac.date && vac.date.startsWith(date)) ||
|
||||||
myVacations.value.some(vac => vac.LOCVACUDT && vac.LOCVACUDT.startsWith(date) && vac.LOCVACRMM)
|
myVacations.value.some(vac => vac.date && vac.date.startsWith(date) && vac.receiverId)
|
||||||
)
|
)
|
||||||
.map(([date, type]) => ({ date, type }));
|
.map(([date, type]) => ({ date, type }));
|
||||||
const vacationsToDelete = myVacations.value
|
const vacationsToDelete = myVacations.value
|
||||||
.filter(vac => {
|
.filter(vac => {
|
||||||
if (!vac.LOCVACUDT) return false;
|
if (!vac.date) return false;
|
||||||
const date = vac.LOCVACUDT.split("T")[0];
|
const date = vac.date.split("T")[0];
|
||||||
return selectedDates.value.get(date) === "delete" && !vac.LOCVACRMM;
|
return selectedDates.value.get(date) === "delete" && !vac.receiverId;
|
||||||
})
|
})
|
||||||
.map(vac => {
|
.map(vac => {
|
||||||
const id = vac.LOCVACSEQ;
|
const id = vac.id;
|
||||||
return typeof id === "number" ? Number(id) : id;
|
return typeof id === "number" ? Number(id) : id;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
@ -390,6 +407,9 @@
|
|||||||
if (response.data && response.data.status === "OK") {
|
if (response.data && response.data.status === "OK") {
|
||||||
alert("✅ 휴가 변경 사항이 저장되었습니다.");
|
alert("✅ 휴가 변경 사항이 저장되었습니다.");
|
||||||
await fetchRemainingVacation();
|
await fetchRemainingVacation();
|
||||||
|
if (isModalOpen.value) {
|
||||||
|
await fetchVacationHistory(lastRemainingYear.value);
|
||||||
|
}
|
||||||
const currentDate = fullCalendarRef.value.getApi().getDate();
|
const currentDate = fullCalendarRef.value.getApi().getDate();
|
||||||
await loadCalendarData(currentDate.getFullYear(), currentDate.getMonth() + 1);
|
await loadCalendarData(currentDate.getFullYear(), currentDate.getMonth() + 1);
|
||||||
selectedDates.value.clear();
|
selectedDates.value.clear();
|
||||||
@ -440,5 +460,10 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* 스타일 정의 */
|
/* 기본 스타일은 그대로 두고, 데이트피커 인풋의 추가 스타일 정의 */
|
||||||
|
.fc-toolbar-title {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 데이트피커 인풋은 Flatpickr에서 동적으로 스타일 적용됨 */
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container-xxl flex-grow-1 container-p-y">
|
<div class="container-xxl flex-grow-1 container-p-y">
|
||||||
<!-- {{ userStore.user.role == 'ROLE_ADMIN' ? '관리자' : '일반인'}} -->
|
|
||||||
<div class="card p-5">
|
<div class="card p-5">
|
||||||
<!-- 타이틀, 검색 -->
|
<!-- 타이틀, 검색 -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -30,7 +29,7 @@
|
|||||||
|
|
||||||
<!-- 작성 -->
|
<!-- 작성 -->
|
||||||
<div v-if="isWriteVisible" class="mt-5">
|
<div v-if="isWriteVisible" class="mt-5">
|
||||||
<DictWrite @close="isWriteVisible = false" :dataList="cateList" @addCategory="addCategory" @addWord="addWord"/>
|
<DictWrite @close="isWriteVisible = false" :dataList="cateList" @addWord="addWord"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -174,30 +173,34 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
//카테고리 등록
|
//카테고리 등록
|
||||||
const addCategory = (data) =>{
|
// const addCategory = (data) =>{
|
||||||
const lastCategory = cateList.value[cateList.value.length - 1];
|
// const lastCategory = cateList.value[cateList.value.length - 1];
|
||||||
const newValue = lastCategory ? lastCategory.value + 1 : 600101;
|
// const newValue = lastCategory ? lastCategory.value + 1 : 600101;
|
||||||
const newCategory = { label: data, value: newValue };
|
// const newCategory = { label: data, value: newValue };
|
||||||
cateList.value = [newCategory, ...cateList.value];
|
|
||||||
selectedCategory.value = newCategory.value;
|
|
||||||
// axios.post('worddict/insertCategory',{
|
|
||||||
// CMNCODNAM: data
|
|
||||||
// }).then(res => {
|
|
||||||
// if(res.data.data == '1'){
|
|
||||||
// toastStore.onToast('카테고리가 추가 등록 되었습니다.', 's');
|
|
||||||
// const newCategory = { label: data, value: newValue };
|
|
||||||
// cateList.value = [newCategory, ...cateList.value];
|
// cateList.value = [newCategory, ...cateList.value];
|
||||||
// selectedCategory.value = newCategory.value;
|
// selectedCategory.value = newCategory.value;
|
||||||
// } else if(res.data.message == '이미 존재하는 카테고리명입니다.') {
|
//// axios.post('worddict/insertCategory',{
|
||||||
// toastStore.onToast(res.data.message, 'e');
|
//// CMNCODNAM: data
|
||||||
// }
|
//// }).then(res => {
|
||||||
// })
|
//// if(res.data.data == '1'){
|
||||||
}
|
//// toastStore.onToast('카테고리가 추가 등록 되었습니다.', 's');
|
||||||
|
//// const newCategory = { label: data, value: newValue };
|
||||||
|
//// cateList.value = [newCategory, ...cateList.value];
|
||||||
|
//// selectedCategory.value = newCategory.value;
|
||||||
|
//// } else if(res.data.message == '이미 존재하는 카테고리명입니다.') {
|
||||||
|
//// toastStore.onToast(res.data.message, 'e');
|
||||||
|
//// }
|
||||||
|
//// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 용어집 등록
|
||||||
const addWord = (wordData, data) => {
|
const addWord = (wordData, data) => {
|
||||||
let category = null;
|
let category = null;
|
||||||
// 카테고리 체크
|
// 카테고리 체크
|
||||||
const existingCategory = cateList.value.find(item => item.label === data);
|
const existingCategory = cateList.value.find(item => item.label === data);
|
||||||
if (existingCategory) {
|
if (existingCategory) {
|
||||||
|
console.log('카테고리 중복');
|
||||||
|
|
||||||
//카테고리 있을시 그냥 저장
|
//카테고리 있을시 그냥 저장
|
||||||
category = existingCategory.label == '' ? wordData.category : existingCategory.value;
|
category = existingCategory.label == '' ? wordData.category : existingCategory.value;
|
||||||
} else {
|
} else {
|
||||||
@ -208,6 +211,7 @@
|
|||||||
}
|
}
|
||||||
sendWordRequest(category, wordData, data, !existingCategory);
|
sendWordRequest(category, wordData, data, !existingCategory);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendWordRequest = (category, wordData, data, isNewCategory) => {
|
const sendWordRequest = (category, wordData, data, isNewCategory) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
WRDDICCAT: category,
|
WRDDICCAT: category,
|
||||||
@ -216,17 +220,26 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isNewCategory) {
|
if (isNewCategory) {
|
||||||
payload.CMNCODNAM = data; // 새로운 카테고리 추가 시 포함
|
payload.CMNCODNAM = data;
|
||||||
|
axios.post('worddict/insertWord', payload).then(res => {
|
||||||
|
if (res.data.status === 'OK') {
|
||||||
|
toastStore.onToast('용어가 등록 되었습니다.', 's');
|
||||||
|
isWriteVisible.value = false;
|
||||||
|
getwordList();
|
||||||
|
const newCategory = { label: data, value: category }; // 여기서 data 사용
|
||||||
|
cateList.value = [newCategory, ...cateList.value];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
axios.post('worddict/insertWord', payload).then(res => {
|
||||||
|
if (res.data.status === 'OK') {
|
||||||
|
toastStore.onToast('용어가 등록 되었습니다.', 's');
|
||||||
|
isWriteVisible.value = false;
|
||||||
|
getwordList();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
axios.post('worddict/insertWord', payload).then(res => {
|
};
|
||||||
if (res.data.status === 'OK') {
|
|
||||||
toastStore.onToast('용어가 등록 되었습니다.', 's');
|
|
||||||
isWriteVisible.value = false;
|
|
||||||
getwordList();
|
|
||||||
//카테고리 리스트 다시 조회 해야야함
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// 체크 상태 업데이트
|
// 체크 상태 업데이트
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user