종료된 프로젝트 관련

This commit is contained in:
yoon 2025-03-07 12:09:37 +09:00
parent 292b479523
commit cbc3c9dda5
3 changed files with 122 additions and 36 deletions

View File

@ -1,16 +1,18 @@
<template> <template>
<div class="card mb-3 shadow-sm border"> <div class="card mb-3 shadow-sm border" :class="isProjectExpired ? 'end-project' : ''">
<div class="row g-0"> <div class="row g-0">
<div class="card-body"> <div class="card-body">
<!-- 제목 --> <!-- 제목 -->
<h5 class="card-title d-flex justify-content-between"> <div class="d-flex justify-content-between ">
{{ title }} <h5 class="card-title fw-bold">
{{ title }}
<div> </h5>
<p v-if="isProjectExpired" class="btn-icon btn-danger rounded-2"><i class='bx bx-power-off'></i></p>
<div v-if="!isProjectExpired">
<EditBtn @click.stop="openEditModal" /> <EditBtn @click.stop="openEditModal" />
<DeleteBtn @click.stop="handleDelete" class="ms-1"/> <DeleteBtn v-if="isProjectCreator" @click.stop="handleDelete" class="ms-1"/>
</div> </div>
</h5> </div>
<!-- 날짜 --> <!-- 날짜 -->
<div class="d-flex flex-column flex-sm-row align-items-center pb-2"> <div class="d-flex flex-column flex-sm-row align-items-center pb-2">
<i class="bx bx-calendar"></i> <i class="bx bx-calendar"></i>
@ -21,7 +23,7 @@
<div class="d-flex flex-column flex-sm-row align-items-center pb-2"> <div class="d-flex flex-column flex-sm-row align-items-center pb-2">
<i class="bx bxs-user"></i> <i class="bx bxs-user"></i>
<div class="ms-2">참여자</div> <div class="ms-2">참여자</div>
<UserList :projctSeq="projctSeq" class="ms-8 mb-0" /> <UserList :projctSeq="projctSeq" :showOnlyActive="isProjectExpired" class="ms-8 mb-0" />
</div> </div>
<!-- 설명 --> <!-- 설명 -->
<div class="d-flex flex-column flex-sm-row align-items-center pb-2"> <div class="d-flex flex-column flex-sm-row align-items-center pb-2">
@ -46,13 +48,18 @@
v-if="coordinates" v-if="coordinates"
:lat="coordinates.lat" :lat="coordinates.lat"
:lng="coordinates.lng" :lng="coordinates.lng"
class="w-px-200 h-px-200" class="w-px-250 h-px-200"
@onLoadKakaoMap="onLoadKakaoMap"
> >
<KakaoMapMarker <KakaoMapMarker
:lat="coordinates.lat" :lat="coordinates.lat"
:lng="coordinates.lng" :lng="coordinates.lng"
/> />
</KakaoMap> </KakaoMap>
<div class="position-absolute top-50 translate-middle-y end-0 me-3 z-1 d-flex flex-column gap-1">
<button class="btn-secondary border-none" @click="zoomOut">+</button>
<button class="btn-secondary border-none" @click="zoomIn">-</button>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -153,7 +160,7 @@
</template> </template>
<script setup> <script setup>
import { defineProps, onMounted, ref, computed, inject } from 'vue'; import { defineProps, onMounted, ref, computed, watch } from 'vue';
import UserList from '@c/user/UserList.vue'; import UserList from '@c/user/UserList.vue';
import CenterModal from '@c/modal/CenterModal.vue'; import CenterModal from '@c/modal/CenterModal.vue';
import $api from '@api'; import $api from '@api';
@ -217,6 +224,10 @@ const props = defineProps({
type: String, type: String,
required: false required: false
}, },
projctCreatorId: {
type: Number,
required: false
}
}); });
// Emit // Emit
@ -228,6 +239,7 @@ const logData = ref([]);
// //
const isPopoverVisible = ref(false); const isPopoverVisible = ref(false);
const map = ref();
const mapIconRef = ref(null); const mapIconRef = ref(null);
const coordinates = ref(null); const coordinates = ref(null);
@ -237,6 +249,23 @@ const originalColor = ref('');
const nameAlert = ref(false); const nameAlert = ref(false);
const user = ref(null); const user = ref(null);
const isProjectCreator = computed(() => {
return user.value?.id === props.projctCreatorId;
});
// ( )
const isProjectExpired = computed(() => {
if (!props.enddate) return false;
const today = new Date();
today.setHours(0, 0, 0, 0); //
const endDate = new Date(props.enddate);
endDate.setHours(0, 0, 0, 0); //
return endDate < today;
});
// //
const selectedProject = ref({ const selectedProject = ref({
PROJCTSEQ: props.projctSeq, PROJCTSEQ: props.projctSeq,
@ -273,6 +302,7 @@ const updateAddress = addressData => {
}; };
}; };
// //
const getLogData = async () => { const getLogData = async () => {
const res = await $api.get(`project/log/${props.projctSeq}`); const res = await $api.get(`project/log/${props.projctSeq}`);
@ -295,17 +325,23 @@ const closeModal = () => {
const openEditModal = () => { const openEditModal = () => {
isEditModalOpen.value = true; isEditModalOpen.value = true;
originalColor.value = props.projctCol; originalColor.value = props.projctCol;
// ( )
if (!user.value) {
userStore.userInfo().then(() => {
user.value = userStore.user;
});
}
}; };
// //
const closeEditModal = () => { const closeEditModal = () => {
selectedProject.value = {
PROJCTSEQ: props.projctSeq,
PROJCTNAM: props.title,
PROJCTSTR: props.strdate,
PROJCTEND: props.enddate,
PROJCTZIP: props.addressZip,
PROJCTARR: props.address,
PROJCTDTL: props.addressdtail,
PROJCTDES: props.description,
PROJCTCOL: props.projctCol,
projctcolor: props.projctColor,
};
isEditModalOpen.value = false; isEditModalOpen.value = false;
}; };
@ -320,6 +356,19 @@ const hasChanges = computed(() => {
selectedProject.value.PROJCTDES !== props.description || selectedProject.value.PROJCTDES !== props.description ||
selectedProject.value.PROJCTCOL !== props.projctCol; selectedProject.value.PROJCTCOL !== props.projctCol;
}); });
//
watch(
() => selectedProject.value,
() => {
const start = new Date(selectedProject.value.PROJCTSTR);
const end = new Date(selectedProject.value.PROJCTEND);
if (end < start) {
selectedProject.value.PROJCTEND = selectedProject.value.PROJCTSTR;
}
},
{ deep: true, flush: 'post' }
);
// //
const handleUpdate = () => { const handleUpdate = () => {
@ -344,7 +393,7 @@ const handleUpdate = () => {
projctStr: selectedProject.value.PROJCTSTR, projctStr: selectedProject.value.PROJCTSTR,
projctEnd: selectedProject.value.PROJCTEND || null, projctEnd: selectedProject.value.PROJCTEND || null,
projctDes: selectedProject.value.PROJCTDES || null, projctDes: selectedProject.value.PROJCTDES || null,
projctUmb: user.value?.name, projctUmb: user.value?.id,
originalColor: originalColor.value === selectedProject.value.PROJCTCOL ? null : originalColor.value, originalColor: originalColor.value === selectedProject.value.PROJCTCOL ? null : originalColor.value,
}).then(res => { }).then(res => {
if (res.status === 200) { if (res.status === 200) {
@ -376,6 +425,26 @@ const convertAddressToCoordinates = () => {
}); });
}; };
const onLoadKakaoMap = (mapRef) => {
map.value = mapRef;
};
//
const zoomIn = () => {
if (map.value) {
const level = map.value.getLevel();
map.value.setLevel(level + 1);
}
};
//
const zoomOut = () => {
if (map.value) {
const level = map.value.getLevel();
map.value.setLevel(level - 1);
}
};
// //
const handleDelete = () => { const handleDelete = () => {
$api.patch('project/delete', { $api.patch('project/delete', {
@ -388,15 +457,16 @@ const handleDelete = () => {
location.reload() location.reload()
} }
}) })
}; };
// //
onMounted(async () => { onMounted(async () => {
convertAddressToCoordinates();
// //
await userStore.userInfo(); await userStore.userInfo();
user.value = userStore.user; user.value = userStore.user;
convertAddressToCoordinates();
}); });
</script> </script>

View File

@ -23,6 +23,7 @@
:projctSeq="post.PROJCTSEQ" :projctSeq="post.PROJCTSEQ"
:projctCol="post.PROJCTCOL" :projctCol="post.PROJCTCOL"
:projctColor="post.projctcolor" :projctColor="post.projctcolor"
:projctCreatorId="post.PROJCTCMB"
@update="getProjectList" @update="getProjectList"
/> />
</div> </div>
@ -204,21 +205,20 @@
// :: // ::
const handleAddressUpdate = (data) => { const handleAddressUpdate = (data) => {
addressData.value = data; addressData.value = data;
}; };
// //
watch([startDay, endDay], () => { watch([startDay, endDay], () => {
if (startDay.value && endDay.value) { if (startDay.value && endDay.value) {
const start = new Date(startDay.value); const start = new Date(startDay.value);
const end = new Date(endDay.value); const end = new Date(endDay.value);
// if (end < start) {
if (end < start) { endDay.value = startDay.value;
endDay.value = startDay.value; }
} }
} }, { flush: 'post' });
});
// //
const handleCreate = async () => { const handleCreate = async () => {
@ -240,7 +240,7 @@
projctArr: addressData.value.address, projctArr: addressData.value.address,
projctDtl: addressData.value.detailAddress, projctDtl: addressData.value.detailAddress,
projctZip: addressData.value.postcode, projctZip: addressData.value.postcode,
projctCmb: user.value.name, projctCmb: user.value.id,
}).then(res => { }).then(res => {
if (res.status === 200) { if (res.status === 200) {
toastStore.onToast('프로젝트가 등록되었습니다.', 's'); toastStore.onToast('프로젝트가 등록되었습니다.', 's');

View File

@ -1,11 +1,12 @@
<template> <template>
<ul class="list-unstyled users-list d-flex align-items-center gap-1"> <ul class="list-unstyled users-list d-flex align-items-center gap-1">
<li <li
v-for="(user, index) in sortedUserList" v-for="(user, index) in displayedUserList"
:key="index" :key="index"
class="avatar pull-up" class="avatar pull-up"
:class="{ 'opacity-100': isUserDisabled(user) }" :class="{ 'opacity-100': isUserDisabled(user) }"
@click.stop="toggleDisable(index)" @click.stop="showOnlyActive ? null : toggleDisable(index)"
:style="showOnlyActive ? 'cursor: default' : ''"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-popup="tooltip-custom" data-popup="tooltip-custom"
data-bs-placement="top" data-bs-placement="top"
@ -38,6 +39,10 @@ const props = defineProps({
projctSeq: { projctSeq: {
type: Number, type: Number,
required: false, required: false,
},
showOnlyActive: {
type: Boolean,
default: false
} }
}); });
@ -54,6 +59,14 @@ const sortedUserList = computed(() => {
}); });
}); });
// showOnlyActive true ,
const displayedUserList = computed(() => {
if (props.showOnlyActive) {
return sortedUserList.value.filter(user => !isUserDisabled(user));
}
return sortedUserList.value;
});
// //
const fetchProjectParticipation = async () => { const fetchProjectParticipation = async () => {
if (props.projctSeq) { if (props.projctSeq) {
@ -91,8 +104,11 @@ const isUserDisabled = (user) => {
}; };
// / DB // / DB
// showOnlyActive true toggleDisable
const toggleDisable = async (index) => { const toggleDisable = async (index) => {
const user = sortedUserList.value[index]; if (props.showOnlyActive) return; // showOnlyActive true
const user = displayedUserList.value[index];
if (user) { if (user) {
const newParticipationStatus = props.projctSeq const newParticipationStatus = props.projctSeq
? user.PROJCTYON === '1' ? user.PROJCTYON === '1'