2024-06-17 11:48:00 +07:00
|
|
|
span
|
2024-06-06 13:29:22 +07:00
|
|
|
<script setup lang="ts">
|
2024-06-12 17:17:49 +07:00
|
|
|
import { usePollStore } from "~/stores/poll";
|
|
|
|
|
import { usePollOptionStore } from "~/stores/poll-option";
|
|
|
|
|
import { usePollResponseStore } from "~/stores/poll-response";
|
|
|
|
|
import type { Poll } from "~/server/models/poll";
|
|
|
|
|
import type { PollResponse } from "~/server/models/poll-response";
|
|
|
|
|
import type { PollOption } from "~/server/models/poll-option";
|
2024-06-06 13:29:22 +07:00
|
|
|
const props = defineProps<{ dataId?: string }>();
|
|
|
|
|
|
|
|
|
|
const store = reactive({
|
|
|
|
|
poll: usePollStore(),
|
2024-06-12 17:17:49 +07:00
|
|
|
pollOptions: usePollOptionStore(),
|
|
|
|
|
pollResponse: usePollResponseStore(),
|
|
|
|
|
});
|
|
|
|
|
const { currentPoll } = storeToRefs(store.poll);
|
|
|
|
|
const { currentPollOptions } = storeToRefs(store.pollOptions);
|
|
|
|
|
const { currentPollResponses } = storeToRefs(store.pollResponse);
|
|
|
|
|
const poll = reactive<Poll | any>({});
|
2024-06-17 11:48:00 +07:00
|
|
|
const options = ref<PollOption[] | any[]>([]);
|
2024-07-06 16:28:45 +07:00
|
|
|
|
2024-06-12 17:17:49 +07:00
|
|
|
async function loadData() {
|
|
|
|
|
await store.poll.fetchById(String(props.dataId));
|
|
|
|
|
await store.pollOptions.fetchByPollId(String(props.dataId));
|
|
|
|
|
await store.pollResponse.fetchByPollId(String(props.dataId));
|
|
|
|
|
assignData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function assignData() {
|
|
|
|
|
Object.assign(poll, currentPoll.value);
|
|
|
|
|
options.value = currentPollOptions.value;
|
|
|
|
|
}
|
2024-06-06 13:29:22 +07:00
|
|
|
|
2024-07-06 16:28:45 +07:00
|
|
|
await loadData();
|
|
|
|
|
// onBeforeMount(async () => {
|
|
|
|
|
// });
|
2024-06-06 13:29:22 +07:00
|
|
|
|
2024-07-06 16:28:45 +07:00
|
|
|
// const selectedOption = ref<any>(-1);
|
|
|
|
|
// const showResult = ref(false);
|
2024-06-12 17:17:49 +07:00
|
|
|
const alreadyVoted = ref(false);
|
2024-07-06 16:28:45 +07:00
|
|
|
const showResult = ref(false)
|
2024-06-12 17:17:49 +07:00
|
|
|
const canShowResult = computed(() => {
|
|
|
|
|
switch (poll.settings?.resultPublication) {
|
|
|
|
|
case 0:
|
|
|
|
|
return false;
|
|
|
|
|
case 1:
|
|
|
|
|
return true;
|
|
|
|
|
case 2:
|
|
|
|
|
return alreadyVoted.value;
|
|
|
|
|
case 3:
|
|
|
|
|
return alreadyVoted.value && (!poll.endTime || new Date() > new Date(poll.endTime));
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-07-06 16:28:45 +07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// const toggleResults = () => {
|
|
|
|
|
// if (canShowResult.value) showResult.value = !showResult.value;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
const singleSelect = ref<number>(-1)
|
|
|
|
|
const multipleSelect = ref<number []>([])
|
|
|
|
|
|
2024-06-17 11:48:00 +07:00
|
|
|
const totalResponses = ref(0);
|
2024-06-12 17:17:49 +07:00
|
|
|
async function submitVote() {
|
2024-07-06 16:28:45 +07:00
|
|
|
// if (selectedOption.value >= 0 && !alreadyVoted.value) {
|
|
|
|
|
// const result = await store.pollResponse.create({ optionId: selectedOption.value });
|
|
|
|
|
// if (result?.id) {
|
|
|
|
|
// totalResponses.value = options.value?.reduce((sum, option) => sum + Number(option.responseCount ?? 0), 1);
|
|
|
|
|
// options?.value?.forEach((option: PollOption | any) => {
|
|
|
|
|
// if (option.id === selectedOption.value) {
|
|
|
|
|
// option.responseCount = (option.responseCount ?? 0) + 1;
|
|
|
|
|
// }
|
|
|
|
|
// option.percentage = Number(((option.responseCount / totalResponses.value) * 100).toFixed(1));
|
|
|
|
|
// });
|
|
|
|
|
// alreadyVoted.value = true;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
switch (poll.type) {
|
|
|
|
|
case 1:
|
|
|
|
|
if(singleSelect.value >= 0) {
|
|
|
|
|
totalResponses.value = options.value?.reduce((sum, option) => sum + Number(option.responseCount ?? 0), 1);
|
|
|
|
|
options?.value?.forEach((option: PollOption | any) => {
|
|
|
|
|
if (option.id === singleSelect.value) {
|
2024-06-17 11:48:00 +07:00
|
|
|
option.responseCount = (option.responseCount ?? 0) + 1;
|
|
|
|
|
}
|
|
|
|
|
option.percentage = Number(((option.responseCount / totalResponses.value) * 100).toFixed(1));
|
2024-07-06 16:28:45 +07:00
|
|
|
alreadyVoted.value = true
|
2024-06-17 11:48:00 +07:00
|
|
|
});
|
2024-07-06 16:28:45 +07:00
|
|
|
}
|
2024-06-12 17:17:49 +07:00
|
|
|
}
|
2024-06-06 13:29:22 +07:00
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
<template>
|
2024-07-06 16:28:45 +07:00
|
|
|
|
|
|
|
|
<div class="inline-block px-4 py-2 mb-5">
|
|
|
|
|
<h3 class="text-#000 font-raleway font-italic text-16px font-500 leading-140% mb-2">{{ poll?.title }}</h3>
|
|
|
|
|
<ul class="flex flex-col gap-3">
|
|
|
|
|
<template v-if="poll.type === 1">
|
|
|
|
|
<li v-for="(option, index) in options" :key="index">
|
|
|
|
|
<input :id="`option-${index}`" :disabled="singleSelect >= 0 && alreadyVoted ? true : false" type="radio" class="peer opacity-0" :value="option.id" v-model="singleSelect">
|
|
|
|
|
<label :for="`option-${index}`" class="font-raleway text-16px relative text-#000 font-400 leading-140% pl-16px before:content-[''] before:inline-block before:w-14px before:h-14px before:rounded-50% before:border-1 before:absolute before:left--3 before:top-10px before:border-1px before:border-#000 before:translate-y--50% after:absolute after:left--10px after:top-10px after:translate-y--50% after:border-#000 after:content-[''] after:inline-block after:w-10px after:h-10px after:rounded-full peer-checked:after:bg-primary peer-checked:before:border-primary ">{{ option?.title }}</label>
|
|
|
|
|
</li>
|
|
|
|
|
</template>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<div class="flex items-center justify-center mt-3">
|
|
|
|
|
<button @click="submitVote()" v-if="!alreadyVoted" :disabled="alreadyVoted && singleSelect >= 0 ? true : false" class="px-5 py-10px rounded-6px bg-primary text-#fff font-raleway text-14px font-400">Gửi kết quả</button>
|
|
|
|
|
<button @click="showResult = true" v-if="alreadyVoted" class="px-5 py-10px rounded-6px bg-primary text-#fff font-raleway text-14px font-400">Xem kết quả</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="mt-5" v-if="showResult && canShowResult">
|
|
|
|
|
<h3 class="text-#000 font-raleway font-italic text-16px font-500 leading-140% mb-2">{{ poll?.title }}</h3>
|
|
|
|
|
<ul>
|
|
|
|
|
<li v-for="(answer, index) in options" :key="index" class="flex gap-4 items-center text-#000 font-raleway text-12px leading-140%">
|
|
|
|
|
{{ answer.percentage}}%
|
|
|
|
|
<div :style="{ width: `${answer.percentage}%` }" :class="answer.id === singleSelect ? 'bg-primary' : 'bg-#AEAEAE'" class="h-1.5 rounded-full"></div>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- <span class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5]">
|
2024-06-06 13:29:22 +07:00
|
|
|
<span class="block">
|
|
|
|
|
<span class="underline decoration-gray-500 font-bold">
|
|
|
|
|
{{ poll?.title }}
|
|
|
|
|
</span>
|
2024-06-12 17:17:49 +07:00
|
|
|
<button v-if="showResult && canShowResult" type="button" class="underline text-blue-400" @click="toggleResults">Câu hỏi</button>
|
|
|
|
|
<button class="underline text-blue-400" v-if="!showResult && canShowResult" type="button" @click="toggleResults">Kết quả</button>
|
2024-06-06 13:29:22 +07:00
|
|
|
</span>
|
|
|
|
|
|
2024-06-12 17:17:49 +07:00
|
|
|
<span v-if="!showResult" class="p-1 block">
|
|
|
|
|
<span v-for="(option, index) in options" :key="index" class="block">
|
|
|
|
|
<label class="flex gap-2 m-2">
|
2024-06-17 11:48:00 +07:00
|
|
|
<input type="radio" :value="option.id" v-model="selectedOption" :disabled="selectedOption >= 0 && alreadyVoted ? true : false" />
|
2024-06-12 17:17:49 +07:00
|
|
|
<span class="font-semibold">{{ option?.title }}</span>
|
|
|
|
|
</label>
|
|
|
|
|
</span>
|
|
|
|
|
<button @click="submitVote" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Bình chọn</button>
|
2024-06-06 13:29:22 +07:00
|
|
|
</span>
|
|
|
|
|
|
2024-06-17 11:48:00 +07:00
|
|
|
<span v-else class="flex flex-col my-5 gap-4">
|
|
|
|
|
<span v-for="(answer, index) in options" :key="index" class="flex gap-2">
|
|
|
|
|
<span class="w-50px">{{ answer.percentage }}%</span>
|
|
|
|
|
<div class="w-full">
|
|
|
|
|
<b class="mb-0.5 block">{{ answer.title }}</b>
|
|
|
|
|
<div :style="{ width: `${answer.percentage}%` }" :class="answer.id === selectedOption ? 'bg-green-600' : 'bg-primary-500'" class="h-1.5 rounded-full"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</span>
|
|
|
|
|
<b>Tổng số lượt binh chọn: {{ totalResponses }}</b>
|
2024-06-12 17:17:49 +07:00
|
|
|
</span>
|
2024-07-06 16:28:45 +07:00
|
|
|
</span> -->
|
2024-06-12 17:17:49 +07:00
|
|
|
</template>
|