localhost-front/src/components/projectlist/ProjectList.vue

258 lines
8.1 KiB
Vue

<template>
<SearchBar @update:data="search" />
<div class="d-flex align-items-center">
<CategoryBtn :lists="yearCategory" @update:data="selectedCategory = $event" />
<WriteBtn class="mt-2 ms-auto" @click="openCreateModal" />
</div>
<!-- 프로젝트 목록 -->
<div class="mt-4">
<div v-if="projectStore.projectList.length === 0" class="text-center">
<p class="text-muted mt-4">등록된 프로젝트가 없습니다.</p>
</div>
<div v-for="post in projectStore.projectList" :key="post.PROJCTSEQ">
<ProjectCard
:title="post.PROJCTNAM"
:description="post.PROJCTDES"
:strdate="post.PROJCTSTR"
:enddate="post.PROJCTEND"
:address="post.PROJCTARR"
:addressdtail="post.PROJCTDTL"
:addressZip="post.PROJCTZIP"
:projctSeq="post.PROJCTSEQ"
:projctCol="post.PROJCTCOL"
:projctColor="post.projctcolor"
@update="getProjectList"
/>
</div>
</div>
<!-- 등록 모달 -->
<form @reset.prevent="formReset">
<CenterModal :display="isCreateModalOpen" @close="closeCreateModal" :create="true" @reset="formReset">
<template #title> 프로젝트 등록 </template>
<template #body>
<FormInput
title="이름"
name="name"
:is-essential="true"
:is-alert="nameAlert"
:modelValue="name"
@update:alert="nameAlert = $event"
@update:modelValue="name = $event"
/>
<FormSelect
title="컬러"
name="color"
:is-essential="true"
:is-label="true"
:is-common="true"
:data="colorList"
@update:data="color = $event"
/>
<FormInput
title="시작 일"
name="startDay"
:type="'date'"
:is-essential="true"
:modelValue="startDay"
v-model="startDay"
/>
<FormInput
title="종료 일"
:type="'date'"
name="endDay"
:modelValue="endDay"
@update:modelValue="endDay = $event"
/>
<FormInput
title="설명"
name="description"
:modelValue="description"
@update:modelValue="description = $event"
/>
<ArrInput
title="주소"
name="address"
:isEssential="true"
:is-row="true"
:is-alert="addressAlert"
:modelValue="addressData"
@update:data="handleAddressUpdate"
@update:alert="addressAlert = $event"
/>
</template>
<template #footer>
<BackButton type="reset" @click="closeCreateModal" />
<SaveButton @click="handleCreate" />
</template>
</CenterModal>
</form>
</template>
<script setup>
import { computed, ref, watch, onMounted, inject } from 'vue';
import SearchBar from '@c/search/SearchBar.vue';
import ProjectCard from '@c/list/ProjectCard.vue';
import CategoryBtn from '@c/category/CategoryBtn.vue';
import WriteBtn from '@c/button/WriteBtn.vue';
import CenterModal from '@c/modal/CenterModal.vue';
import FormSelect from '@c/input/FormSelect.vue';
import FormInput from '@c/input/FormInput.vue';
import ArrInput from '@c/input/ArrInput.vue';
import commonApi from '@/common/commonApi';
import { useToastStore } from '@s/toastStore';
import { useUserInfoStore } from '@/stores/useUserInfoStore';
import { useProjectStore } from '@/stores/useProjectStore';
import $api from '@api';
import SaveButton from '@c/button/SaveBtn.vue';
import BackButton from '@c/button/BackBtn.vue';
const toastStore = useToastStore();
const userStore = useUserInfoStore();
const projectStore = useProjectStore();
// 상태 관리
const user = ref(null);
const selectedCategory = ref(null);
const searchText = ref('');
// dayjs 인스턴스 가져오기
const dayjs = inject('dayjs');
// 오늘 날짜를 YYYY-MM-DD 형식으로 변환
const today = dayjs().format('YYYY-MM-DD');
// 등록 모달 상태
const isCreateModalOpen = ref(false);
const name = ref('');
const color = ref('');
const startDay = ref(today);
const endDay = ref('');
const description = ref('');
const nameAlert = ref(false);
const addressAlert = ref(false);
const addressData = ref({
postcode: '',
address: '',
detailAddress: ''
});
// API 호출
const { yearCategory, colorList } = commonApi({
loadColor: true,
colorType: 'YNP',
loadYearCategory: true,
});
// 검색 처리
const search = async searchKeyword => {
searchText.value = searchKeyword.trim();
await getProjectList();
};
const selectedYear = computed(() => {
if (!selectedCategory.value || selectedCategory.value === 900101) {
return null;
}
// 선택된 category 값 label 값으로 변환
return yearCategory.value.find(item => item.value === selectedCategory.value)?.label || null;
});
// 프로젝트 목록 조회
const getProjectList = async () => {
await projectStore.getProjectList(searchText.value, selectedYear.value);
};
// 카테고리 변경 감지
watch(selectedCategory, async () => {
await getProjectList();
});
// 등록 모달 관리
const openCreateModal = () => {
isCreateModalOpen.value = true;
};
const closeCreateModal = () => {
isCreateModalOpen.value = false;
};
const formReset = () => {
name.value = '';
color.value = '';
addressData.value = {
postcode: '',
address: '',
detailAddress: ''
};
startDay.value = today;
endDay.value = '';
description.value = '';
nameAlert.value = false;
addressAlert.value = false;
}
// 등록 :: 주소 업데이트 핸들러
const handleAddressUpdate = (data) => {
addressData.value = data;
};
// 시작일이나 종료일이 변경될 때마다 종료일을 유효성 검사
watch([startDay, endDay], () => {
if (startDay.value && endDay.value) {
const start = new Date(startDay.value);
const end = new Date(endDay.value);
// 종료일이 시작일보다 이전 날짜라면 종료일을 시작일로 맞추기
if (end < start) {
endDay.value = startDay.value;
}
}
});
// 프로젝트 등록
const handleCreate = async () => {
nameAlert.value = name.value.trim() === '';
addressAlert.value = addressData.value.address.trim() === '';
if (nameAlert.value || addressAlert.value) {
return;
}
$api.post('project/insert', {
projctNam: name.value,
projctCol: color.value,
projctStr: startDay.value,
projctEnd: endDay.value || null,
projctDes: description.value || null,
projctArr: addressData.value.address,
projctDtl: addressData.value.detailAddress,
projctZip: addressData.value.postcode,
projctCmb: user.value.name,
}).then(res => {
if (res.status === 200) {
toastStore.onToast('프로젝트가 등록되었습니다.', 's');
closeCreateModal();
getProjectList();
}
});
};
onMounted(async () => {
await getProjectList();
await userStore.userInfo();
user.value = userStore.user;
});
</script>