251 lines
9.6 KiB
Vue
251 lines
9.6 KiB
Vue
<template>
|
|
<div class="container-xxl flex-grow-1 container-p-y">
|
|
<div class="card mb-6">
|
|
<div class="card-body">
|
|
<div class="user-list-container">
|
|
<ul class="timeline mb-1">
|
|
<li class="timeline-item timeline-item-transparent">
|
|
<span class="timeline-point timeline-point-info"></span>
|
|
<div class="timeline-event">
|
|
<div class="timeline-header mb-2">
|
|
<h6 class="mb-0">투표 인원</h6>
|
|
</div>
|
|
<UserList :role="'vote'" @userListInfo="userSet" @user-list-update="handleUserListUpdate" class="mb-3" />
|
|
<div v-if="UserListAlert" class="invalid-feedback d-block">2명이상 선택해주세요.</div>
|
|
<form-input
|
|
title="제목"
|
|
name="title"
|
|
:is-essential="true"
|
|
:is-alert="titleAlert"
|
|
v-model="title"
|
|
@keyup="ValidHandler('title')"
|
|
/>
|
|
<div class="date-picker-container" @click="focusDateInput">
|
|
<form-input
|
|
title="종료날짜"
|
|
name="endDate"
|
|
type="datetime-local"
|
|
:is-essential="true"
|
|
:is-alert="endDateAlert"
|
|
v-model="endDate"
|
|
:min="minDate"
|
|
@input="ValidHandlerendDate"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 숨겨진 input 태그를 사용하여 강제로 포커스 -->
|
|
<input ref="dateInput" type="datetime-local" v-model="endDate" class="hidden-date-input">
|
|
|
|
<!-- 항목 입력 반복 -->
|
|
<div v-for="(item, index) in itemList" :key="index">
|
|
<form-input
|
|
:title="'항목 ' + (index + 1)"
|
|
:name="'content' + index"
|
|
:is-essential="index < 2"
|
|
:is-alert="contentAlerts[index]"
|
|
v-model="item.content"
|
|
@keyup="ValidHandler('content' + (index + 1))"
|
|
:is-btn="true"
|
|
>
|
|
<template v-slot:append>
|
|
<delete-btn @click="removeItem(index)" :disabled="index < 2" />
|
|
</template>
|
|
</form-input>
|
|
<form-input
|
|
:title="'URL ' + (index + 1)"
|
|
:name="'url' + index"
|
|
v-model="item.url"
|
|
:is-essential="false"
|
|
class="mb-1"
|
|
/>
|
|
<!-- <link-input v-model="item.url" class="mb-1"/> -->
|
|
</div>
|
|
|
|
<plus-btn @click="addItem" :disabled="itemList.length >= 10" class="mb-3" />
|
|
<div>
|
|
<label>
|
|
<input
|
|
class="form-check-input me-1"
|
|
type="checkbox"
|
|
id="addvoteitem"
|
|
v-model="addvoteitem"
|
|
/>
|
|
항목 추가여부
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label >
|
|
<input
|
|
class="form-check-input me-1"
|
|
type="checkbox"
|
|
id="addvotemulti"
|
|
v-model="addvotemulti"
|
|
/>
|
|
다중투표 허용여부
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
<div class="mb-4 d-flex justify-content-end">
|
|
<button type="button" class="btn btn-info" @click="goList">
|
|
<i class="bx bx-left-arrow-alt"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-primary ms-1" @click="saveValid">
|
|
<i class="bx bx-check"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { nextTick, onMounted, ref, toRaw } from "vue";
|
|
import UserList from "@c/user/UserList.vue";
|
|
import formInput from "@c/input/FormInput.vue";
|
|
import { useToastStore } from "@s/toastStore";
|
|
import PlusBtn from "@c/button/PlusBtn.vue";
|
|
import DeleteBtn from "@c/button/DeleteBtn.vue";
|
|
import $api from "@api";
|
|
import router from "@/router";
|
|
import { voteCommon } from '@s/voteCommon';
|
|
import { useUserStore } from '@s/userList';
|
|
import { useRoute } from "vue-router";
|
|
|
|
const userStore = useUserStore();
|
|
// const offset = new Date().getTimezoneOffset() * 60000
|
|
// const today = new Date(Date.now() - offset);
|
|
// today.setDate(today.getDate() + 1);
|
|
// const minDate = today.toISOString().substring(0, 16);
|
|
const toastStore = useToastStore();
|
|
const activeUserList = ref([]);
|
|
const disabledUsers = ref([]);
|
|
const titleAlert = ref(false);
|
|
const endDateAlert = ref(false);
|
|
const contentAlerts = ref([false, false]);
|
|
const UserListAlert = ref(false);
|
|
const title = ref("");
|
|
const endDate = ref("");
|
|
const { itemList, addItem, removeItem } = voteCommon();
|
|
const userListTotal = ref(0);
|
|
const addvoteitem = ref(false);
|
|
const addvotemulti= ref(false);
|
|
|
|
const dateInput = ref(null);
|
|
|
|
const focusDateInput = () => {
|
|
if (dateInput.value) {
|
|
dateInput.value.showPicker(); // 달력 자동 열기 (일부 브라우저에서 지원)
|
|
dateInput.value.focus(); // 포커스 이동
|
|
}
|
|
};
|
|
|
|
const minDate = ref('');
|
|
onMounted(() => {
|
|
nextTick(() => {
|
|
const offset = new Date().getTimezoneOffset() * 60000;
|
|
const today = new Date(Date.now() - offset);
|
|
today.setDate(today.getDate() + 1);
|
|
minDate.value = today.toISOString().substring(0, 16);
|
|
});
|
|
});
|
|
|
|
const userSet = ({ userList, userTotal }) => {
|
|
activeUserList.value = userList;
|
|
userListTotal.value = userTotal;
|
|
};
|
|
const handleUserListUpdate = ({ activeUsers, disabledUsers: updatedDisabledUsers }) => {
|
|
activeUserList.value = activeUsers;
|
|
disabledUsers.value = updatedDisabledUsers;
|
|
userListTotal.value = activeUsers.length;
|
|
if(activeUserList.value.length<2){
|
|
UserListAlert.value = true;
|
|
}else{
|
|
UserListAlert.value = false;
|
|
}
|
|
};
|
|
const saveValid = () => {
|
|
let valid = true;
|
|
if (disabledUsers.value.length === 0) {
|
|
activeUserList.value = [...userStore.userList];
|
|
}
|
|
if (title.value.trim() === '') {
|
|
titleAlert.value = true;
|
|
valid = false;
|
|
} else {
|
|
titleAlert.value = false;
|
|
}
|
|
if (endDate.value === '') {
|
|
endDateAlert.value = true;
|
|
valid = false;
|
|
} else {
|
|
endDateAlert.value = false;
|
|
}
|
|
itemList.value.forEach((item, index) => {
|
|
if (index < 2 && item.content.trim() === '') {
|
|
contentAlerts.value[index] = true;
|
|
valid = false;
|
|
} else if (index >= 2 && item.content.trim() === '' && item.url.trim() !== '') {
|
|
contentAlerts.value[index] = true;
|
|
valid = false;
|
|
} else {
|
|
contentAlerts.value[index] = false;
|
|
}
|
|
});
|
|
if (activeUserList.value.length < 2) {
|
|
UserListAlert.value = true;
|
|
valid = false;
|
|
} else {
|
|
UserListAlert.value = false;
|
|
}
|
|
if (valid) {
|
|
saveVote();
|
|
}
|
|
};
|
|
const saveVote = () => {
|
|
const filteredItemList = itemList.value.filter(item => item.content && item.content.trim() !== '');
|
|
const unwrappedUserList = toRaw(activeUserList.value);
|
|
const listId = unwrappedUserList.map(item => ({
|
|
id: item.MEMBERSEQ,
|
|
}));
|
|
$api.post('vote/insertWord',{
|
|
addvoteIs :addvoteitem.value === false ? '0' :'1'
|
|
,votemMltiIs :addvotemulti.value === false ? '0' : '1'
|
|
,title :title.value.trim()
|
|
,endDate :endDate.value
|
|
,itemList :filteredItemList
|
|
,activeUserList :listId
|
|
}).then((res)=>{
|
|
if(res.data.status == 'OK'){
|
|
toastStore.onToast('투표가 등록되었습니다.', 's');
|
|
goList();
|
|
}
|
|
})
|
|
};
|
|
const ValidHandler = (field) => {
|
|
if (field === 'title') {
|
|
titleAlert.value = false;
|
|
}
|
|
if (field.startsWith('content')) {
|
|
const index = parseInt(field.replace('content', '')) - 1;
|
|
if (!isNaN(index)) {
|
|
contentAlerts.value[index] = false;
|
|
}
|
|
}
|
|
};
|
|
const ValidHandlerendDate = () =>{
|
|
endDateAlert.value = false;
|
|
}
|
|
const goList = () => {
|
|
router.push('/voteboard');
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.item-input {
|
|
max-width: 200px;
|
|
}
|
|
</style>
|