Merge remote-tracking branch 'origin/main' into board-view-content
This commit is contained in:
commit
5888bd51b2
@ -3,4 +3,94 @@
|
||||
|
||||
.display-block {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
.notice-row td {
|
||||
color: #DC3545 !important;
|
||||
}
|
||||
.notice-row {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.general-row {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
.clickable-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
.clickable-row:hover {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
.new-badge {
|
||||
font-size: 0.65rem;
|
||||
padding: 0.2em 0.4em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
/* 휴가*/
|
||||
|
||||
.half-day-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.half-day-buttons .btn.active {
|
||||
border: 2px solid black;
|
||||
}
|
||||
.fc-daygrid-day-frame {
|
||||
min-height: 80px !important;
|
||||
max-height: 120px !important;
|
||||
overflow: hidden !important;
|
||||
padding-top: 25px !important;
|
||||
}
|
||||
.fc-daygrid-day-events {
|
||||
max-height: 100px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
.fc-daygrid-event {
|
||||
position: absolute !important;
|
||||
height: 20px !important;
|
||||
width: 100% !important;
|
||||
left: 0 !important;
|
||||
margin: 2px 0 !important;
|
||||
padding: 0 !important;
|
||||
border-radius: 2px !important;
|
||||
border: none !important;
|
||||
}
|
||||
.fc-daygrid-event-harness {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
gap: 22px;
|
||||
}
|
||||
.fc-daygrid-event.half-day-am {
|
||||
width: 45% !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
.fc-daygrid-event.half-day-pm {
|
||||
width: 45% !important;
|
||||
left: auto !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
.fc-daygrid-event.full-day {
|
||||
width: 100% !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
.fc-day-sun .fc-daygrid-day-number,
|
||||
.fc-col-header-cell:first-child .fc-col-header-cell-cushion {
|
||||
color: #ff4500 !important;
|
||||
}
|
||||
.fc-day-sat .fc-daygrid-day-number,
|
||||
.fc-col-header-cell:last-child .fc-col-header-cell-cushion {
|
||||
color: #6076e0 !important;
|
||||
}
|
||||
.fc-daygrid-day-number {
|
||||
position: absolute !important;
|
||||
top: 0px !important;
|
||||
left: 5px !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import axios from "axios";
|
||||
import router from "@/router/index";
|
||||
import { useToastStore } from '@s/toastStore';
|
||||
|
||||
const $api = axios.create({
|
||||
baseURL: 'http://localhost:10325/api/',
|
||||
@ -30,13 +30,41 @@ $api.interceptors.request.use(
|
||||
|
||||
// 응답 인터셉터 추가하기
|
||||
$api.interceptors.response.use(
|
||||
|
||||
function (response) {
|
||||
// 2xx 범위에 있는 상태 코드는 이 함수를 트리거 합니다.
|
||||
// 응답 데이터가 있는 작업 수행
|
||||
// 2xx 범위의 응답 처리
|
||||
return response;
|
||||
}, function (error) {
|
||||
// 2xx 외의 범위에 있는 상태 코드는 이 함수를 트리거 합니다.
|
||||
// 응답 오류가 있는 작업 수행
|
||||
},
|
||||
function (error) {
|
||||
const toastStore = useToastStore()
|
||||
// 오류 응답 처리
|
||||
if (error.response) {
|
||||
switch (error.response.status) {
|
||||
case 401:
|
||||
toastStore.onToast('아이디 혹은 비밀번호가 틀렸습니다.', 'e');
|
||||
break;
|
||||
case 403:
|
||||
toastStore.onToast('접근 권한이 없습니다.', 'e');
|
||||
break;
|
||||
case 404:
|
||||
toastStore.onToast('요청한 페이지를 찾을 수 없습니다.', 'e');
|
||||
break;
|
||||
case 500:
|
||||
toastStore.onToast('서버 오류가 발생했습니다.', 'e');
|
||||
break;
|
||||
default:
|
||||
toastStore.onToast('알 수 없는 오류가 발생했습니다.', 'e');
|
||||
}
|
||||
} else if (error.request) {
|
||||
// 요청이 전송되었으나 응답을 받지 못한 경우
|
||||
toastStore.onToast('서버와 통신할 수 없습니다.', 'e');
|
||||
} else {
|
||||
// 요청 설정 중에 오류가 발생한 경우
|
||||
toastStore.onToast('요청 중 오류가 발생했습니다.', 'e');
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export default $api;
|
||||
|
||||
@ -12,27 +12,28 @@ const commonApi = () => {
|
||||
const colorList = ref([]);
|
||||
const mbtiList = ref([]);
|
||||
const pwhintList = ref([]);
|
||||
const yearCategory = ref([]);
|
||||
const cateList = ref([]);
|
||||
|
||||
const CommonCode = async (path, endpoint, targetList) => {
|
||||
|
||||
const response = await $api.get(`${path}/${endpoint}`);
|
||||
targetList.value = response.data.data.map(item => ({
|
||||
label: item.CMNCODNAM,
|
||||
value: item.CMNCODVAL,
|
||||
}));
|
||||
|
||||
const CommonCode = async (endpoint, targetList) => {
|
||||
try {
|
||||
const response = await $api.get(`/user/${endpoint}`);
|
||||
targetList.value = response.data.data.map(item => ({
|
||||
label: item.CMNCODNAM,
|
||||
value: item.CMNCODVAL
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error(`Error fetching ${endpoint}:`, error);
|
||||
targetList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await CommonCode("color", colorList);
|
||||
await CommonCode("mbti", mbtiList);
|
||||
await CommonCode("pwhint", pwhintList);
|
||||
await CommonCode("user", "color", colorList);
|
||||
await CommonCode("user", "mbti", mbtiList);
|
||||
await CommonCode("user", "pwhint", pwhintList);
|
||||
await CommonCode("project", "yearCategory", yearCategory);
|
||||
await CommonCode("worddict", "getWordCategory", cateList);
|
||||
});
|
||||
|
||||
return { colorList, mbtiList, pwhintList };
|
||||
return { colorList, mbtiList, pwhintList, yearCategory, cateList };
|
||||
};
|
||||
|
||||
export default commonApi;
|
||||
|
||||
@ -74,9 +74,9 @@ const router = useRouter();
|
||||
|
||||
// Props 정의
|
||||
const props = defineProps({
|
||||
boardId: {
|
||||
type: Number,
|
||||
required: true
|
||||
boardId: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
profileName: {
|
||||
type: String,
|
||||
@ -125,7 +125,7 @@ const handleEdit = () => {
|
||||
// router.push({ name: 'BoardEdit', params: { id: boardId } });
|
||||
|
||||
if (props.unknown) {
|
||||
togglePassword('edit');
|
||||
togglePassword('edit');
|
||||
} else {
|
||||
router.push({ name: 'BoardEdit', params: { id: 100 } }); // 로그인한 경우 바로 편집
|
||||
}
|
||||
@ -154,14 +154,14 @@ const togglePassword = (button) => {
|
||||
const handlePasswordSubmit = async () => {
|
||||
isPassword.value = false;
|
||||
lastClickedButton.value = null;
|
||||
|
||||
|
||||
console.log('비밀번호:', password.value);
|
||||
console.log(props.boardId)
|
||||
console.log(props.boardId)
|
||||
|
||||
try {
|
||||
const requestData = {
|
||||
MEMBERSEQ: 288,
|
||||
LOCBRDPWD: 1234
|
||||
LOCBRDPWD: password.value,
|
||||
LOCBRDSEQ: 288
|
||||
}
|
||||
|
||||
console.log(requestData)
|
||||
|
||||
@ -1,21 +1,20 @@
|
||||
<template>
|
||||
<ul class="cate-list list-unstyled d-flex flex-wrap mb-0">
|
||||
<li
|
||||
v-for="category in lists"
|
||||
:key="category.CMNCODVAL"
|
||||
class="mt-2 mx-1"
|
||||
>
|
||||
<button
|
||||
<li v-for="category in lists" :key="category.value" class="mt-2 mx-1">
|
||||
<button
|
||||
type="button"
|
||||
class="btn"
|
||||
:class="{
|
||||
'btn-outline-primary': category.CMNCODVAL !== selectedCategory,
|
||||
'btn-primary': category.CMNCODVAL === selectedCategory
|
||||
'btn-outline-primary': category.value !== selectedCategory,
|
||||
'btn-primary': category.value === selectedCategory
|
||||
}"
|
||||
@click="selectCategory(category.CMNCODVAL)"
|
||||
>{{ category.CMNCODNAM }}</button>
|
||||
@click="selectCategory(category.value)"
|
||||
>
|
||||
{{ category.label }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -48,10 +47,10 @@ const selectCategory = (cate) => {
|
||||
.cate-list {
|
||||
overflow-x: scroll;
|
||||
flex-wrap: nowrap !important;
|
||||
|
||||
|
||||
li {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
:type="type"
|
||||
@input="updateInput"
|
||||
:value="computedValue"
|
||||
:disabled="disabled"
|
||||
:maxLength="maxlength"
|
||||
:placeholder="title"
|
||||
@blur="$emit('blur')"
|
||||
@ -26,6 +27,7 @@
|
||||
:max="type === 'date' ? today : null"
|
||||
@input="updateInput"
|
||||
:value="computedValue"
|
||||
:disabled="disabled"
|
||||
:maxLength="maxlength"
|
||||
:placeholder="title"
|
||||
@blur="$emit('blur')"
|
||||
@ -65,6 +67,11 @@
|
||||
default: '',
|
||||
required: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: 30,
|
||||
|
||||
63
src/components/list/ProjectCard.vue
Normal file
63
src/components/list/ProjectCard.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="card mb-3 shadow-sm border">
|
||||
<div class="row g-0">
|
||||
<!-- 게시물 내용 섹션 -->
|
||||
<div>
|
||||
<div class="card-body">
|
||||
<!-- 제목 -->
|
||||
<h5 class="card-title">
|
||||
{{ title }}
|
||||
<span class="text-muted me-3" v-if="attachment">
|
||||
<i class="fa-solid fa-paperclip"></i>
|
||||
</span>
|
||||
</h5>
|
||||
<!-- 본문 -->
|
||||
<div class="card-text line-clamp-2 my-5">{{ content }}</div>
|
||||
<!-- 날짜 -->
|
||||
<div class="d-flex flex-column flex-sm-row justify-content-between align-items-start">
|
||||
<small class="text-muted">{{ formattedDate }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
// Props 정의
|
||||
const props = defineProps({
|
||||
category: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
date: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
attachment: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
});
|
||||
|
||||
// formattedDate을 computed로 정의
|
||||
const formattedDate = computed(() => {
|
||||
const date = new Date(props.date);
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(
|
||||
date.getDate()
|
||||
).padStart(2, "0")} ${String(date.getHours()).padStart(2, "0")}:${String(
|
||||
date.getMinutes()
|
||||
).padStart(2, "0")}`;
|
||||
});
|
||||
</script>
|
||||
49
src/components/list/ProjectCardList.vue
Normal file
49
src/components/list/ProjectCardList.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div class="mt-4">
|
||||
<div v-if="posts.length === 0" class="text-center">
|
||||
<p class="text-muted mt-4">게시물이 없습니다.</p>
|
||||
</div>
|
||||
|
||||
<div v-for="post in posts" :key="post.id" @click="goDetail(post.id)">
|
||||
<ProjectCard
|
||||
:title="post.title"
|
||||
:content="post.content"
|
||||
:date="post.date"
|
||||
:attachment="post.attachment || false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineEmits } from 'vue';
|
||||
import ProjectCard from './ProjectCard.vue';
|
||||
|
||||
// 테스트용 데이터
|
||||
const posts = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: 'Vue 3 Composition API 소개',
|
||||
content: 'Composition API를 사용하여 Vue 3에서 효율적으로 개발하는 방법을 알아봅니다. Composition API를 사용하여 Vue 3에서 효율적으로 개발하는 방법을 알아봅니다. Composition API를 사용하여 Vue 3에서 효율적으로 개발하는 방법을 알아봅니다. Composition API를 사용하여 Vue 3에서 효율적으로 개발하는 방법을 알아봅니다. Composition API를 사용하여 Vue 3에서 효율적으로 개발하는 방법을 알아봅니다. Composition API를 사용하여 Vue 3에서 효율적으로 개발하는 방법을 알아봅니다.',
|
||||
date: '2025-02-10',
|
||||
comments: 4,
|
||||
attachment: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Spring Boot로 REST API 만들기',
|
||||
content: 'Spring Boot를 사용하여 간단한 RESTful API를 구현하는 방법을 다룹니다.',
|
||||
date: '2025-02-09',
|
||||
comments: 2,
|
||||
attachment: false
|
||||
}
|
||||
]);
|
||||
|
||||
const emit = defineEmits(['click']);
|
||||
|
||||
// 상세 페이지 이동
|
||||
const goDetail = (id) => {
|
||||
emit('click', id);
|
||||
};
|
||||
|
||||
</script>
|
||||
19
src/components/projectlist/ProjectList.vue
Normal file
19
src/components/projectlist/ProjectList.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<SearchBar />
|
||||
<CategoryBtn :lists="yearCategory" />
|
||||
<ProjectCardList :category="selectedCategory" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import SearchBar from '@c/search/SearchBar.vue';
|
||||
import ProjectCardList from '@c/list/ProjectCardList.vue';
|
||||
import CategoryBtn from '@c/category/CategoryBtn.vue';
|
||||
import commonApi from '@/common/commonApi'
|
||||
import { ref } from 'vue';
|
||||
|
||||
const selectedCategory = ref(null);
|
||||
|
||||
const { yearCategory } = commonApi();
|
||||
|
||||
|
||||
</script>
|
||||
@ -8,44 +8,43 @@
|
||||
:useInputGroup="true"
|
||||
@update:data="handleIdChange"
|
||||
:value="id"
|
||||
:disabled="resetForm"
|
||||
/>
|
||||
|
||||
<UserFormInput
|
||||
title="생년월일"
|
||||
name="birth"
|
||||
:type="'date'"
|
||||
:is-essential="true"
|
||||
:is-alert="birthAlert"
|
||||
@update:data="birth = $event"
|
||||
@update:alert="birthAlert = $event"
|
||||
:value="birth"
|
||||
/>
|
||||
|
||||
<FormSelect
|
||||
title="비밀번호 힌트"
|
||||
name="pwhint"
|
||||
:is-essential="true"
|
||||
:is-row="false"
|
||||
:is-label="true"
|
||||
:is-common="true"
|
||||
:data="pwhintList"
|
||||
@update:data="pwhint = $event"
|
||||
/>
|
||||
|
||||
<UserFormInput
|
||||
title="답변"
|
||||
name="pwhintRes"
|
||||
:is-essential="true"
|
||||
:is-alert="pwhintResAlert"
|
||||
@update:data="pwhintRes = $event"
|
||||
@update:alert="pwhintResAlert = $event"
|
||||
:value="pwhintRes"
|
||||
/>
|
||||
|
||||
<div class="d-flex mt-5">
|
||||
<RouterLink type="button" class="btn btn-secondary me-2 w-50" to="/login">취소</RouterLink>
|
||||
<button type="button" @click="handleSubmit" class="btn btn-primary w-50">확인</button>
|
||||
</div>
|
||||
<template v-if="!resetForm">
|
||||
<UserFormInput
|
||||
title="생년월일"
|
||||
name="birth"
|
||||
:type="'date'"
|
||||
:is-essential="true"
|
||||
:is-alert="birthAlert"
|
||||
@update:data="birth = $event"
|
||||
@update:alert="birthAlert = $event"
|
||||
:value="birth"
|
||||
/>
|
||||
<FormSelect
|
||||
title="비밀번호 힌트"
|
||||
name="pwhint"
|
||||
:is-essential="true"
|
||||
:is-row="false"
|
||||
:is-label="true"
|
||||
:is-common="true"
|
||||
:data="pwhintList"
|
||||
@update:data="pwhint = $event"
|
||||
/>
|
||||
<UserFormInput
|
||||
title="답변"
|
||||
name="pwhintRes"
|
||||
:is-essential="true"
|
||||
:is-alert="pwhintResAlert"
|
||||
@update:data="pwhintRes = $event"
|
||||
@update:alert="pwhintResAlert = $event"
|
||||
:value="pwhintRes"
|
||||
/>
|
||||
<div class="d-flex mt-5">
|
||||
<RouterLink type="button" class="btn btn-secondary me-2 w-50" to="/login">취소</RouterLink>
|
||||
<button type="button" @click="handleSubmit" class="btn btn-primary w-50">확인</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="resetForm" class="mt-4">
|
||||
@ -159,6 +158,16 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const checkResponse = await $api.post('user/checkPassword', {
|
||||
id: id.value,
|
||||
password: password.value
|
||||
});
|
||||
|
||||
if (checkResponse.data.data === false) {
|
||||
toastStore.onToast('기존 비밀번호와 동일한 비밀번호로 변경할 수 없습니다.', 'e');
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await $api.patch('user/pwNew', {
|
||||
id: id.value,
|
||||
password: password.value
|
||||
|
||||
@ -63,20 +63,17 @@
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
const response = await $api.post('user/login', {
|
||||
$api.post('user/login', {
|
||||
loginId: id.value,
|
||||
password: password.value,
|
||||
remember: remember.value,
|
||||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
await userStore.userInfo();
|
||||
router.push('/');
|
||||
} else {
|
||||
toastStore.onToast('아이디 혹은 비밀번호가 틀렸습니다.', 'e');
|
||||
}
|
||||
|
||||
})
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
userStore.userInfo();
|
||||
router.push('/');
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@ -1,39 +1,49 @@
|
||||
<template>
|
||||
<div class="d-flex">
|
||||
<FormSelect
|
||||
name="cate"
|
||||
title="카테고리"
|
||||
:data="formattedDataList"
|
||||
:is-common="true"
|
||||
@update:data="selectCategory = $event"
|
||||
@change="onChange"
|
||||
/>
|
||||
|
||||
<PlusBtn @click="toggleInput"/>
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col-10">
|
||||
<FormSelect
|
||||
name="cate"
|
||||
title="카테고리 선택"
|
||||
:data="formattedDataList"
|
||||
:is-common="true"
|
||||
@update:data="selectCategory = $event"
|
||||
@change="onChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-2 btn-margin">
|
||||
<PlusBtn @click="toggleInput"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex" v-if="showInput">
|
||||
<FormInput :isLabel="false" title="카테고리" name="카테고리" @update:modelValue="addCategory = $event" :is-alert="addCategoryAlert"/>
|
||||
<button class="btn btn-primary" @click="saveInput">
|
||||
<i class="bx bx-check"></i>
|
||||
</button>
|
||||
<div class="row" v-if="showInput">
|
||||
<div class="col-10">
|
||||
<FormInput title="카테고리 입력" name="카테고리" @update:modelValue="addCategory = $event" :is-alert="addCategoryAlert"/>
|
||||
</div>
|
||||
<div class="col-2 btn-margin">
|
||||
<button class="btn btn-primary btn-icon" @click="saveInput">
|
||||
<i class="bx bx-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="dict-w">
|
||||
<FormInput
|
||||
title="용어"
|
||||
type="text"
|
||||
name="word"
|
||||
:is-essential="true"
|
||||
:is-alert="wordTitleAlert"
|
||||
@update:modelValue="wordTitle = $event"
|
||||
/>
|
||||
title="용어"
|
||||
type="text"
|
||||
name="word"
|
||||
:is-essential="true"
|
||||
:is-alert="wordTitleAlert"
|
||||
@update:modelValue="wordTitle = $event"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<QEditor @update:data="content = $event" @update:imageUrls="imageUrls = $event" :is-alert="wordContentAlert" />
|
||||
<button class="btn btn-primary" @click="saveWord">
|
||||
<i class="bx bx-check"></i>
|
||||
</button>
|
||||
<button @click="$emit('close')">취소</button>
|
||||
<div class="text-end mt-5">
|
||||
<button class="btn btn-primary" @click="saveWord">
|
||||
<i class="bx bx-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -124,3 +134,15 @@ const saveWord = () => {
|
||||
emit('addWord', wordData);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dict-w {
|
||||
width: 83%;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.btn-margin {
|
||||
margin-top: 2.5rem
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -46,19 +46,25 @@
|
||||
<li class="menu-item" :class="$route.path.includes('/wordDict') ? 'active' : ''">
|
||||
<RouterLink class="menu-link" to="/wordDict">
|
||||
<i class="menu-icon icon-base bx bx-book-open"></i>
|
||||
<div class="text-truncate">wordDict</div>
|
||||
<div class="text-truncate">WordDict</div>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li class="menu-item" :class="$route.path.includes('/voteboard') ? 'active' : ''">
|
||||
<RouterLink class="menu-link" to="/voteboard">
|
||||
<i class="menu-icon icon-base bx bx-box"></i>
|
||||
<div class="text-truncate">voteboard</div>
|
||||
<div class="text-truncate">Voteboard</div>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li class="menu-item" :class="$route.path.includes('/vacation') ? 'active' : ''">
|
||||
<RouterLink class="menu-link" to="/vacation">
|
||||
<i class="menu-icon tf-icons bx bx-calendar"></i>
|
||||
<div class="text-truncate">vacation</div>
|
||||
<div class="text-truncate">Vacation</div>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li class="menu-item" :class="$route.path.includes('/projectlist') ? 'active' : ''">
|
||||
<RouterLink class="menu-link" to="/projectlist">
|
||||
<i class="menu-icon icon-base bx bx-list-ul"></i>
|
||||
<div class="text-truncate">Project</div>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li class="menu-item" :class="$route.path.includes('/sample') ? 'active' : ''">
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<!-- Notification -->
|
||||
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-2 p-1">
|
||||
<a
|
||||
class="nav-link dropdown-toggle hide-arrow"
|
||||
class="nav-link dropdown-toggle hide-arrow p-0"
|
||||
href="javascript:void(0);"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
|
||||
@ -76,6 +76,10 @@ const routes = [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/projectlist',
|
||||
component: () => import('@v/projectlist/TheProjectList.vue'),
|
||||
},
|
||||
{
|
||||
path: '/sample',
|
||||
component: () => import('@c/calendar/SampleCalendar.vue'),
|
||||
|
||||
@ -7,18 +7,12 @@ export const useUserStore = defineStore('userInfo', () => {
|
||||
|
||||
// 사용자 정보 가져오기
|
||||
const userInfo = async () => {
|
||||
try {
|
||||
const response = await $api.get('user/userInfo');
|
||||
if (response.data.status === "OK") {
|
||||
user.value = response.data.data;
|
||||
console.log(user.value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error("사용자 정보 조회 실패:", error);
|
||||
return false;
|
||||
const response = await $api.get('user/userInfo');
|
||||
if (response.data.status === "OK") {
|
||||
user.value = response.data.data;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@ -139,8 +139,4 @@ onMounted(() => {
|
||||
color: red;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.display-block {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
<tr v-for="(post, index) in generalList"
|
||||
:key="'post-' + index"
|
||||
class="general-row clickable-row"
|
||||
@click="goDetail(post.id)">
|
||||
@click="goDetail(post.realId)">
|
||||
<td>{{ post.id }}</td>
|
||||
<td>
|
||||
{{ post.title }}
|
||||
@ -93,6 +93,7 @@
|
||||
<div class="row g-3">
|
||||
<div class="mt-8">
|
||||
<Pagination
|
||||
v-if="pagination.pages"
|
||||
v-bind="pagination"
|
||||
@update:currentPage="handlePageChange"
|
||||
/>
|
||||
@ -102,7 +103,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import Pagination from '@c/pagination/Pagination.vue';
|
||||
import SearchBar from '@c/search/SearchBar.vue';
|
||||
import router from '@/router';
|
||||
@ -142,7 +143,7 @@ const pagination = ref({
|
||||
|
||||
// 상세 페이지 이동
|
||||
const goDetail = (id) => {
|
||||
router.push({ name: 'BoardDetail', params: { id } });
|
||||
router.push({ name: 'BoardDetail', params: { id: id } });
|
||||
};
|
||||
|
||||
// 날짜 포맷 변환 함수 (오늘이면 HH:mm, 아니면 YYYY-MM-DD)
|
||||
@ -187,9 +188,10 @@ const fetchGeneralPosts = async (page = 1) => {
|
||||
|
||||
if (data?.data) {
|
||||
console.log(data)
|
||||
const totalPosts = data.data.total; // 전체 게시물 개수 받아오기 (API가 제공해야 함)
|
||||
const totalPosts = data.data.total; // 전체 게시물 개수 받아오기
|
||||
|
||||
generalList.value = data.data.list.map((post, index) => ({
|
||||
realId: post.id,
|
||||
id: totalPosts - ((page - 1) * selectedSize.value) - index,
|
||||
title: post.title,
|
||||
author: post.author || '익명',
|
||||
@ -258,33 +260,4 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 공지사항 스타일 */
|
||||
.notice-row {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.notice-row td {
|
||||
color: #DC3545 !important;
|
||||
}
|
||||
|
||||
/* 일반 게시물 스타일 */
|
||||
.general-row {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* 행 전체 클릭 가능 */
|
||||
.clickable-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
.clickable-row:hover {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
/* 새 글 아이콘 크기 조정 */
|
||||
.new-badge {
|
||||
font-size: 0.65rem; /* 원래 크기의 약 절반 */
|
||||
padding: 0.2em 0.4em; /* 배지 크기 조정 */
|
||||
vertical-align: middle; /* 텍스트 정렬 */
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
10
src/views/projectlist/TheProjectList.vue
Normal file
10
src/views/projectlist/TheProjectList.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<ProjectList />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ProjectList from '@c/projectlist/ProjectList.vue';
|
||||
|
||||
</script>
|
||||
@ -34,22 +34,4 @@
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.modal-content {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
width: 300px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@ -297,81 +297,6 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 버튼 스타일 */
|
||||
.half-day-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.half-day-buttons .btn.active {
|
||||
border: 2px solid black;
|
||||
}
|
||||
<style>
|
||||
|
||||
/* 날짜 칸 높이 고정 */
|
||||
.fc-daygrid-day-frame {
|
||||
min-height: 80px !important;
|
||||
max-height: 120px !important;
|
||||
overflow: hidden !important;
|
||||
padding-top: 25px !important;
|
||||
}
|
||||
|
||||
/* 날짜 칸 내부의 이벤트 목록 */
|
||||
.fc-daygrid-day-events {
|
||||
max-height: 100px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.fc-daygrid-event {
|
||||
position: absolute !important;
|
||||
height: 20px !important;
|
||||
width: 100% !important;
|
||||
left: 0 !important;
|
||||
margin: 2px 0 !important;
|
||||
padding: 0 !important;
|
||||
border-radius: 2px !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
/* 여러 이벤트가 같은 날짜에 있을 때 정렬 */
|
||||
.fc-daygrid-event-harness {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
/* 기본 휴가/반차 이벤트 (API에서 받은 이벤트) */
|
||||
.fc-daygrid-event.half-day-am {
|
||||
width: 45% !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
.fc-daygrid-event.half-day-pm {
|
||||
width: 45% !important;
|
||||
left: auto !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
.fc-daygrid-event.full-day {
|
||||
width: 100% !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
/* 요일별 날짜 칸 스타일 */
|
||||
.fc-day-sun .fc-daygrid-day-number,
|
||||
.fc-col-header-cell:first-child .fc-col-header-cell-cushion {
|
||||
color: #ff4500 !important;
|
||||
}
|
||||
.fc-day-sat .fc-daygrid-day-number,
|
||||
.fc-col-header-cell:last-child .fc-col-header-cell-cushion {
|
||||
color: #324fde !important;
|
||||
}
|
||||
.fc-daygrid-day-number {
|
||||
position: absolute !important;
|
||||
top: 0px !important;
|
||||
left: 5px !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -69,6 +69,7 @@
|
||||
import DictCard from '@/components/wordDict/DictCard.vue';
|
||||
import DictWrite from '@/components/wordDict/DictWrite.vue';
|
||||
import DictAlphabetFilter from '@/components/wordDict/DictAlphabetFilter.vue';
|
||||
import commonApi from '@/common/commonApi'
|
||||
import { useToastStore } from '@s/toastStore';
|
||||
|
||||
const { appContext } = getCurrentInstance();
|
||||
@ -87,7 +88,7 @@
|
||||
const total = ref(0);
|
||||
|
||||
// 카테고리
|
||||
const cateList = ref([]);
|
||||
const { cateList } = commonApi();
|
||||
const selectedCategory = ref('');
|
||||
|
||||
//선택된 알파벳
|
||||
@ -102,7 +103,6 @@
|
||||
// 데이터 로드
|
||||
onMounted(() => {
|
||||
getwordList();
|
||||
getwordCategory();
|
||||
});
|
||||
|
||||
//용어 목록
|
||||
@ -128,17 +128,7 @@
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
// 카테고리 목록
|
||||
const getwordCategory = () => {
|
||||
axios.get('worddict/getWordCategory')
|
||||
.then(res => {
|
||||
cateList.value = res.data.data;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('카테고리 로드 오류:', err);
|
||||
error.value = '카테고리 데이터를 가져오는 중 문제가 발생했습니다.';
|
||||
});
|
||||
};
|
||||
|
||||
// 검색
|
||||
const search = (e) => {
|
||||
searchText.value = e.trim();
|
||||
@ -172,7 +162,7 @@
|
||||
}).then(res => {
|
||||
if(res.data.data == '1'){
|
||||
toastStore.onToast('카테고리가 추가 등록 되었습니다.', 's');
|
||||
const newCategory = { CMNCODNAM: data, CMNCODVAL: newValue.toString() }; // Assuming CMNCODVAL is the same as CMNCODNAM
|
||||
const newCategory = { CMNCODNAM: data, CMNCODVAL: newValue.toString() };
|
||||
cateList.value.unshift(newCategory);
|
||||
selectCategory.value = newCategory.CMNCODVAL;
|
||||
}
|
||||
@ -181,10 +171,6 @@
|
||||
//용어 등록
|
||||
const addWord = (wordData) => {
|
||||
|
||||
// console.log('단어 추가됨:', wordData.category); // WRDDICCAT
|
||||
// console.log('단어 추가됨:', wordData.content); // WRDDICCON
|
||||
// console.log('단어 추가됨:', wordData.title); // WRDDICTTL
|
||||
|
||||
axios.post('worddict/insertWord',{
|
||||
WRDDICCAT : wordData.category,
|
||||
WRDDICTTL : wordData.title,
|
||||
@ -192,10 +178,8 @@
|
||||
}).then(res => {
|
||||
if(res.data.data == '1'){
|
||||
toastStore.onToast('용어가 등록 되었습니다.', 's');
|
||||
isWriteVisible.value = false
|
||||
// const newCategory = { CMNCODNAM: data, CMNCODVAL: newValue.toString() };
|
||||
// cateList.value.unshift(newCategory);
|
||||
// selectCategory.value = newCategory.CMNCODVAL;
|
||||
isWriteVisible.value = false;
|
||||
getwordList();
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user