종료된 프로젝트 관련

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>
<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="card-body">
<!-- 제목 -->
<h5 class="card-title d-flex justify-content-between">
<div class="d-flex justify-content-between ">
<h5 class="card-title fw-bold">
{{ title }}
<div>
<EditBtn @click.stop="openEditModal" />
<DeleteBtn @click.stop="handleDelete" class="ms-1"/>
</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" />
<DeleteBtn v-if="isProjectCreator" @click.stop="handleDelete" class="ms-1"/>
</div>
</div>
<!-- 날짜 -->
<div class="d-flex flex-column flex-sm-row align-items-center pb-2">
<i class="bx bx-calendar"></i>
@ -21,7 +23,7 @@
<div class="d-flex flex-column flex-sm-row align-items-center pb-2">
<i class="bx bxs-user"></i>
<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 class="d-flex flex-column flex-sm-row align-items-center pb-2">
@ -46,13 +48,18 @@
v-if="coordinates"
:lat="coordinates.lat"
:lng="coordinates.lng"
class="w-px-200 h-px-200"
class="w-px-250 h-px-200"
@onLoadKakaoMap="onLoadKakaoMap"
>
<KakaoMapMarker
:lat="coordinates.lat"
:lng="coordinates.lng"
/>
</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>
@ -153,7 +160,7 @@
</template>
<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 CenterModal from '@c/modal/CenterModal.vue';
import $api from '@api';
@ -217,6 +224,10 @@ const props = defineProps({
type: String,
required: false
},
projctCreatorId: {
type: Number,
required: false
}
});
// Emit
@ -228,6 +239,7 @@ const logData = ref([]);
//
const isPopoverVisible = ref(false);
const map = ref();
const mapIconRef = ref(null);
const coordinates = ref(null);
@ -237,6 +249,23 @@ const originalColor = ref('');
const nameAlert = ref(false);
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({
PROJCTSEQ: props.projctSeq,
@ -273,6 +302,7 @@ const updateAddress = addressData => {
};
};
//
const getLogData = async () => {
const res = await $api.get(`project/log/${props.projctSeq}`);
@ -295,17 +325,23 @@ const closeModal = () => {
const openEditModal = () => {
isEditModalOpen.value = true;
originalColor.value = props.projctCol;
// ( )
if (!user.value) {
userStore.userInfo().then(() => {
user.value = userStore.user;
});
}
};
//
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;
};
@ -320,6 +356,19 @@ const hasChanges = computed(() => {
selectedProject.value.PROJCTDES !== props.description ||
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 = () => {
@ -344,7 +393,7 @@ const handleUpdate = () => {
projctStr: selectedProject.value.PROJCTSTR,
projctEnd: selectedProject.value.PROJCTEND || null,
projctDes: selectedProject.value.PROJCTDES || null,
projctUmb: user.value?.name,
projctUmb: user.value?.id,
originalColor: originalColor.value === selectedProject.value.PROJCTCOL ? null : originalColor.value,
}).then(res => {
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 = () => {
$api.patch('project/delete', {
@ -388,15 +457,16 @@ const handleDelete = () => {
location.reload()
}
})
};
//
onMounted(async () => {
convertAddressToCoordinates();
//
await userStore.userInfo();
user.value = userStore.user;
convertAddressToCoordinates();
});
</script>

View File

@ -23,6 +23,7 @@
:projctSeq="post.PROJCTSEQ"
:projctCol="post.PROJCTCOL"
:projctColor="post.projctcolor"
:projctCreatorId="post.PROJCTCMB"
@update="getProjectList"
/>
</div>
@ -207,18 +208,17 @@
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;
}
}
});
}, { flush: 'post' });
//
const handleCreate = async () => {
@ -240,7 +240,7 @@
projctArr: addressData.value.address,
projctDtl: addressData.value.detailAddress,
projctZip: addressData.value.postcode,
projctCmb: user.value.name,
projctCmb: user.value.id,
}).then(res => {
if (res.status === 200) {
toastStore.onToast('프로젝트가 등록되었습니다.', 's');

View File

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