thainv-dev: tạo lại cấu trúc folder và làm UI
This commit is contained in:
@@ -2,10 +2,10 @@
|
|||||||
body
|
body
|
||||||
font-family: 'Nunito', sans-serif
|
font-family: 'Nunito', sans-serif
|
||||||
|
|
||||||
video
|
// video
|
||||||
max-width: 100% !important
|
// max-width: 100% !important
|
||||||
width: unset !important
|
// width: unset !important
|
||||||
height: unset !important
|
// height: unset !important
|
||||||
|
|
||||||
iframe
|
iframe
|
||||||
width: 100% !important
|
width: 100% !important
|
||||||
|
|||||||
@@ -20,17 +20,13 @@ figure {
|
|||||||
@apply w-full;
|
@apply w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
& a {
|
& document, & a, & custom-figure, & author {
|
||||||
@apply text-primary-600 underline;
|
@apply cursor-pointer text-primary-600;
|
||||||
}
|
|
||||||
|
|
||||||
& document {
|
|
||||||
@apply cursor-pointer text-primary-600 underline;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div[layout="ARTICLE_DETAIL_EMAGAZINE"] {
|
div[layout="TYPE:Detail-LAYOUT:image"] {
|
||||||
& p,& figure.align-center-image, & #sub, & #title, & #intro {
|
& p,& figure.align-center-image, & #sub, & #title, & #intro, & #breakcrumb, & #navigation__bottom {
|
||||||
@apply lg:max-w-640px mx-auto;
|
@apply lg:max-w-640px mx-auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,110 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { usePollStore } from '~/stores/poll'
|
import { usePollStore } from "~/stores/poll";
|
||||||
import { usePollOptionStore } from '~/stores/poll-option'
|
import { usePollOptionStore } from "~/stores/poll-option";
|
||||||
import type { Poll } from '~/server/models/poll';
|
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";
|
||||||
const props = defineProps<{ dataId?: string }>();
|
const props = defineProps<{ dataId?: string }>();
|
||||||
|
|
||||||
const store = reactive({
|
const store = reactive({
|
||||||
poll: usePollStore(),
|
poll: usePollStore(),
|
||||||
pollOptions: usePollOptionStore()
|
pollOptions: usePollOptionStore(),
|
||||||
})
|
pollResponse: usePollResponseStore(),
|
||||||
|
});
|
||||||
|
const { currentPoll } = storeToRefs(store.poll);
|
||||||
|
const { currentPollOptions } = storeToRefs(store.pollOptions);
|
||||||
|
const { currentPollResponses } = storeToRefs(store.pollResponse);
|
||||||
|
const poll = reactive<Poll | any>({});
|
||||||
|
const options = ref<PollOption[]>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
const poll = reactive<Poll>(await store.poll.fetchById((String(props.dataId))))
|
function assignData() {
|
||||||
const options = ref<any []>(await store.pollOptions.fetchByPollId((String(props.dataId))))
|
Object.assign(poll, currentPoll.value);
|
||||||
|
options.value = currentPollOptions.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
|
||||||
const selectedOption = ref<any>(null);
|
const selectedOption = ref<any>(null);
|
||||||
|
const showResult = ref(false);
|
||||||
|
const alreadyVoted = ref(false);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function submitVote () {
|
async function submitVote() {
|
||||||
console.log(selectedOption, 'id')
|
if (selectedOption.value) {
|
||||||
|
let option = options.value?.find((option: PollOption) => option.id === selectedOption.value);
|
||||||
|
if(option) {
|
||||||
|
option.responsesCount = Number(option.responsesCount) + 1
|
||||||
|
|
||||||
|
}
|
||||||
|
const totalResponses = options.value?.reduce((sum, option) => sum + Number(option.responsesCount ?? 0), 0);
|
||||||
|
// const result = await store.pollResponse.create({ optionId: selectedOption.value });
|
||||||
|
// if (result) {
|
||||||
|
// alreadyVoted.value = true;
|
||||||
|
// if (options.value) {
|
||||||
|
// let option = options.value.find((option: PollOption) => option.id === selectedOption.value);
|
||||||
|
// // if (option) option?.responsesCount += 1;
|
||||||
|
// // options.value.filter((option) => {
|
||||||
|
// // option.votePercentage = (option.responsesCount / currentPollResponses.value.length) * 100;
|
||||||
|
// // });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleResults = () => {
|
||||||
|
if (canShowResult.value) showResult.value = !showResult.value;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<span class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5]">
|
<span class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5]">
|
||||||
<span class="block">
|
<span class="block">
|
||||||
<span class="underline decoration-gray-500 font-bold">
|
<span class="underline decoration-gray-500 font-bold">
|
||||||
{{ poll?.title }}
|
{{ poll?.title }}
|
||||||
</span>
|
</span>
|
||||||
<!-- <button v-if="showResult && canShowResult" type="button" class="underline text-blue-400" @click="toggleResults">
|
<button v-if="showResult && canShowResult" type="button" class="underline text-blue-400" @click="toggleResults">Câu hỏi</button>
|
||||||
Câu hỏi
|
<button class="underline text-blue-400" v-if="!showResult && canShowResult" type="button" @click="toggleResults">Kết quả</button>
|
||||||
</button>
|
|
||||||
<button class="underline text-blue-400" v-if="!showResult && canShowResult" type="button" @click="toggleResults">
|
|
||||||
Kết quả
|
|
||||||
</button> -->
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="p-1 block">
|
<span v-if="!showResult" class="p-1 block">
|
||||||
<span v-for="(option, index) in options" :key="index" class="block">
|
<span v-for="(option, index) in options" :key="index" class="block">
|
||||||
<label class="flex gap-2 m-2">
|
<label class="flex gap-2 m-2">
|
||||||
<input type="radio" :value="option.id" v-model="selectedOption" />
|
<input type="radio" :value="option.id" v-model="selectedOption" />
|
||||||
<span class="font-semibold">{{ option?.title }}</span>
|
<span class="font-semibold">{{ option?.title }}</span>
|
||||||
</label>
|
</label>
|
||||||
</span>
|
</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>
|
<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>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- <span v-else class="block">
|
<span v-else class="block">
|
||||||
<span v-for="(answer, index) in options" :key="index" class="block poll-result relative rounded-3xl overflow-hidden my-3">
|
hoàn thành
|
||||||
|
<!-- <span v-for="(answer, index) in options" :key="index" class="block poll-result relative rounded-3xl overflow-hidden my-3">
|
||||||
<span class="absolute top-0 start-0 bottom-0 bg-gradient-to-r from-sky-500 to-indigo-500"
|
<span class="absolute top-0 start-0 bottom-0 bg-gradient-to-r from-sky-500 to-indigo-500"
|
||||||
:style="{ width: `${calculatePercentage(answer?.voteCount)}%` }"></span>
|
:style="{ width: `${calculatePercentage(answer?.voteCount)}%` }"></span>
|
||||||
<span class="block relative z-0 ps-1">
|
<span class="block relative z-0 ps-1">
|
||||||
<span>{{ calculatePercentage(answer?.voteCount).toFixed(2) }}%</span>
|
<span>{{ calculatePercentage(answer?.voteCount).toFixed(2) }}%</span>
|
||||||
<span class="">({{ answer?.voteCount }})</span>
|
<span class="">({{ answer?.voteCount }})</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span> -->
|
||||||
</span> -->
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,310 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useQuizStore } from "~/stores/quiz";
|
||||||
|
import type { Quiz } from "~/server/models/quiz";
|
||||||
|
|
||||||
|
const props = defineProps<{ dataId?: string }>();
|
||||||
|
|
||||||
|
const store = reactive({
|
||||||
|
quiz: useQuizStore(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { currentQuiz } = storeToRefs(store.quiz);
|
||||||
|
|
||||||
|
const quiz = reactive<Quiz>({});
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
await store.quiz.fetchById(Number(props.dataId));
|
||||||
|
|
||||||
|
assignData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function assignData() {
|
||||||
|
Object.assign(quiz, currentQuiz.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
const prevQuestion = () => {
|
||||||
|
if (step.value) {
|
||||||
|
step.value--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextQuestion = () => {
|
||||||
|
if (step.value < 3) {
|
||||||
|
step.value++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
articles: null,
|
||||||
|
questionGeneral: [
|
||||||
|
{
|
||||||
|
answers: [
|
||||||
|
{
|
||||||
|
id: 260,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
questionId: 511,
|
||||||
|
title: "Con ếch 1",
|
||||||
|
thumbnail: "",
|
||||||
|
description: "Con ếch 1",
|
||||||
|
type: 0,
|
||||||
|
isCorrect: true,
|
||||||
|
order: 1,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 259,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
questionId: 511,
|
||||||
|
title: "Con ếch 2",
|
||||||
|
thumbnail: "",
|
||||||
|
description: "Con ếch 2",
|
||||||
|
type: 0,
|
||||||
|
isCorrect: false,
|
||||||
|
order: 1,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 258,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
questionId: 511,
|
||||||
|
title: "Con ếch 3",
|
||||||
|
thumbnail: "",
|
||||||
|
description: "Con ếch 3",
|
||||||
|
type: 0,
|
||||||
|
isCorrect: false,
|
||||||
|
order: 3,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: null,
|
||||||
|
id: 511,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
title: "Con ếch bạn chọn sẽ tiết lộ bí quyết làm giàu",
|
||||||
|
thumbnail: "https://resource.vpress.vn/resources/1/private/13cee27a2bd93915479f049378cffdd3/caudo1-1717486185.jpg",
|
||||||
|
description: "Con ếch bạn chọn sẽ tiết lộ bí quyết làm giàu",
|
||||||
|
type: 1,
|
||||||
|
order: 1,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
answers: [
|
||||||
|
{
|
||||||
|
id: 257,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
questionId: 510,
|
||||||
|
title: "Băng zôn",
|
||||||
|
thumbnail: "",
|
||||||
|
description: "Băng zôn",
|
||||||
|
type: 1,
|
||||||
|
isCorrect: true,
|
||||||
|
order: 1,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 256,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
questionId: 510,
|
||||||
|
title: "Người đàn ông",
|
||||||
|
thumbnail: "",
|
||||||
|
description: "Người đàn ông",
|
||||||
|
type: 1,
|
||||||
|
isCorrect: true,
|
||||||
|
order: 2,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 255,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
questionId: 510,
|
||||||
|
title: "Bánh sinh nhật",
|
||||||
|
thumbnail: "",
|
||||||
|
description: "Bánh sinh nhật",
|
||||||
|
type: 1,
|
||||||
|
isCorrect: false,
|
||||||
|
order: 3,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 254,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
questionId: 510,
|
||||||
|
title: "Khác",
|
||||||
|
thumbnail: "",
|
||||||
|
description: "Khác",
|
||||||
|
type: 2,
|
||||||
|
isCorrect: false,
|
||||||
|
order: 4,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: null,
|
||||||
|
id: 510,
|
||||||
|
siteId: 1,
|
||||||
|
quizId: 4,
|
||||||
|
title: "Những điều khả nghi nào trong bức hình này?",
|
||||||
|
thumbnail: "https://resource.vpress.vn/resources/1/private/13cee27a2bd93915479f049378cffdd3/câu-đố-2-1717486529.jpg",
|
||||||
|
description: "Đâu là điều khả nghi nhất trong bức hình này",
|
||||||
|
type: 2,
|
||||||
|
order: 2,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T15:27:05.641243",
|
||||||
|
updatedBy: null,
|
||||||
|
updatedOn: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: null,
|
||||||
|
id: 4,
|
||||||
|
siteId: 1,
|
||||||
|
title: "câu đố tháng 6",
|
||||||
|
code: "cau-do-thang-6",
|
||||||
|
type: 0,
|
||||||
|
startTime: "2024-06-04T15:00:00",
|
||||||
|
endTime: "2024-06-10T00:00:00",
|
||||||
|
settings: {
|
||||||
|
participantType: 3,
|
||||||
|
resultPublication: 1,
|
||||||
|
},
|
||||||
|
features: "Important;Feature",
|
||||||
|
taxonomy: "Biên tập",
|
||||||
|
keywords: "câu đố;tháng 6;e",
|
||||||
|
thumbnail: "https://resource.vpress.vn/resources/1/private/13cee27a2bd93915479f049378cffdd3/ret-20240603042609106.jpg",
|
||||||
|
description: "câu đố tháng 6 e",
|
||||||
|
order: 1,
|
||||||
|
status: 6,
|
||||||
|
createdBy: 3,
|
||||||
|
createdOn: "2024-06-04T14:40:08.617253",
|
||||||
|
updatedBy: 3,
|
||||||
|
updatedOn: "2024-06-04T15:23:59.964931",
|
||||||
|
};
|
||||||
|
|
||||||
|
const step = ref(0);
|
||||||
|
const beforeWidth = computed(() => (100 / Number(data.questionGeneral.length - 1)) * step.value);
|
||||||
|
|
||||||
|
const selectQuizAnswer = ref<any>([]);
|
||||||
|
|
||||||
|
data.questionGeneral.forEach((question) => {
|
||||||
|
switch (question.type) {
|
||||||
|
case 0:
|
||||||
|
selectQuizAnswer.value.push([]);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
selectQuizAnswer.value.push(0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
selectQuizAnswer.value.push([]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function submitSend() {}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
quiz
|
<div class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5] !text-black">
|
||||||
</template>
|
<h5 class="underline decoration-gray-500 font-bold mb-2">Câu đố: {{ data?.title }}</h5>
|
||||||
|
|
||||||
|
<ul class="px-3">
|
||||||
|
<li v-for="(question, questionIndex) in data.questionGeneral" :key="questionIndex" class="mb-2">
|
||||||
|
<h5 class="mb-1 font-700 text-black">{{ `${questionIndex + 1}. ${question.title}` }}</h5>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1">
|
||||||
|
<input :id="`answer-${questionIndex}-${answerIndex}`" :type="question.type === 1 ? 'radio' : 'checkbox'" :value="answerIndex" v-model="selectQuizAnswer[questionIndex]" />
|
||||||
|
<label :for="`answer-${questionIndex}-${answerIndex}`" class="font-semibold">{{ answer.title }}</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button @click="submitSend" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Gửi câu trả lời</button>
|
||||||
|
</div>
|
||||||
|
<!-- <div>
|
||||||
|
<h5 class="text-black text-18px font-700">{{ data?.title }}</h5>
|
||||||
|
<template v-if="data.questionGeneral.length > 1">
|
||||||
|
<ul
|
||||||
|
:style="{ '--before-width': beforeWidth + '%' }"
|
||||||
|
class="progress flex items-center justify-between relative after:content-[''] after:absolute after:top-50% after:translate-y--50% after:w-full after:h-1 after:bg-gray-200 before:content-[''] before:absolute before:top-50% before:translate-y--50% before:h-1 before:bg-primary-500 before:z-2 before:transition-all before:ease-linear before:duration-300"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="(index, item) in data.questionGeneral.length"
|
||||||
|
:key="index"
|
||||||
|
:class="step >= index - 1 ? 'bg-primary-500 text-white transition-all delay-300' : 'bg-white text-primary-500'"
|
||||||
|
class="relative z-3 w-7 h-7 rounded-full flex items-center justify-center border-2 border-solid border-primary-500"
|
||||||
|
>
|
||||||
|
<template template v-if="step > index - 1"><Icon name="material-symbols:check-rounded" class="text-22px" /></template>
|
||||||
|
<template v-else>{{ item }}</template>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<template v-for="(item, index) in data.questionGeneral" :key="index">
|
||||||
|
<div v-show="step === index">
|
||||||
|
{{ item.title }} => {{ index }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="bg-primary-500 text-white px-2 py-2 rounded-4px" @click="prevQuestion()">Câu trước</button>
|
||||||
|
<button class="bg-primary-500 text-white px-2 py-2 rounded-4px" @click="nextQuestion()">Câu tiếp theo</button>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:root {
|
||||||
|
--before-width: 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
&::before {
|
||||||
|
width: var(--before-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,299 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useSurveyStore } from "~/stores/survey";
|
||||||
|
import type { Survey } from "~/server/models/survey";
|
||||||
|
|
||||||
|
const props = defineProps<{ dataId?: string }>();
|
||||||
|
|
||||||
|
const store = reactive({
|
||||||
|
survey: useSurveyStore(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { currentSurvey } = storeToRefs(store.survey);
|
||||||
|
|
||||||
|
const survey = reactive<Survey>({});
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
await store.survey.fetchById(Number(props.dataId));
|
||||||
|
|
||||||
|
assignData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function assignData() {
|
||||||
|
Object.assign(survey, currentSurvey.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
const dataSurvey = {
|
||||||
|
"articles": null,
|
||||||
|
"questionGeneral": [
|
||||||
|
{
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"id": 85,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"questionId": 84,
|
||||||
|
"title": "Không",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"isCorrect": false,
|
||||||
|
"order": 2,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 84,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"questionId": 84,
|
||||||
|
"title": "Có",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"isCorrect": true,
|
||||||
|
"order": 1,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": null,
|
||||||
|
"id": 84,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"title": "Bạn có chọn xe công nghệ để di chuyển trong giờ cao điểm không?",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 0,
|
||||||
|
"order": 3,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"id": 83,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"questionId": 83,
|
||||||
|
"title": "Xe bus",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"isCorrect": false,
|
||||||
|
"order": 3,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 82,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"questionId": 83,
|
||||||
|
"title": "Xe đạp",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"isCorrect": false,
|
||||||
|
"order": 2,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 81,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"questionId": 83,
|
||||||
|
"title": "Xe máy",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"isCorrect": true,
|
||||||
|
"order": 1,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": null,
|
||||||
|
"id": 83,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"title": "Bạn thường di chuyển bằng phương tiện gì?",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"order": 2,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"id": 80,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"questionId": 82,
|
||||||
|
"title": "21 lần trở lên",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"isCorrect": false,
|
||||||
|
"order": 3,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 79,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"questionId": 82,
|
||||||
|
"title": "14 - 21 lần",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"isCorrect": false,
|
||||||
|
"order": 0,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 78,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"questionId": 82,
|
||||||
|
"title": "7 lần",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "",
|
||||||
|
"type": 1,
|
||||||
|
"isCorrect": true,
|
||||||
|
"order": 1,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": null,
|
||||||
|
"id": 82,
|
||||||
|
"siteId": 1,
|
||||||
|
"surveyId": 10,
|
||||||
|
"title": "Mỗi tuần bạn di chuyển với tần suất bao nhiêu lần?",
|
||||||
|
"thumbnail": "",
|
||||||
|
"description": "Mỗi tuần bạn di chuyển với tần suất bao nhiêu lần?",
|
||||||
|
"type": 1,
|
||||||
|
"order": 1,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.794056",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": null,
|
||||||
|
"id": 10,
|
||||||
|
"siteId": 1,
|
||||||
|
"title": "Thói quen di chuyển trong giờ cao điểm",
|
||||||
|
"code": "thoi-quen-di-chuyen-trong-gio-cao-diem",
|
||||||
|
"type": 0,
|
||||||
|
"startTime": "2024-06-04T17:18:00",
|
||||||
|
"endTime": "2024-06-20T00:00:00",
|
||||||
|
"settings": {
|
||||||
|
"participantType": 3,
|
||||||
|
"resultPublication": 2
|
||||||
|
},
|
||||||
|
"features": "Feature",
|
||||||
|
"taxonomy": "Biên tập",
|
||||||
|
"keywords": "thoiquendichuyen;giocaodiem",
|
||||||
|
"thumbnail": "https://resource.vpress.vn/resources/1/private/13cee27a2bd93915479f049378cffdd3/thoiquendichuyentronggiocaodiem-20240604100659862.png",
|
||||||
|
"description": "Thói quen di chuyển trong giờ cao điểm",
|
||||||
|
"order": 1,
|
||||||
|
"status": 6,
|
||||||
|
"createdBy": 3,
|
||||||
|
"createdOn": "2024-06-04T17:13:45.653177",
|
||||||
|
"updatedBy": null,
|
||||||
|
"updatedOn": null
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const selectSurveyAnswer = ref<any>([])
|
||||||
|
|
||||||
|
dataSurvey.questionGeneral.forEach((question) => {
|
||||||
|
switch (question.type) {
|
||||||
|
case 0:
|
||||||
|
selectSurveyAnswer.value.push([])
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
selectSurveyAnswer.value.push(0)
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
selectSurveyAnswer.value.push([])
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
async function submitSend() {
|
||||||
|
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
Survey
|
|
||||||
</template>
|
<div class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5] !text-black">
|
||||||
|
<h5 class="underline decoration-gray-500 font-bold mb-2">Khảo sát: {{ dataSurvey?.title }}</h5>
|
||||||
|
|
||||||
|
<ul class="px-3">
|
||||||
|
<li v-for="(question, questionIndex) in dataSurvey.questionGeneral" :key="questionIndex" class="mb-2">
|
||||||
|
<h5 class="mb-1 font-700 text-black">{{ `${questionIndex + 1}. ${question.title}` }}</h5>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li v-for="(answer, answerIndex) in question.answers" :key="answerIndex" class="flex items-center gap-1 py-1">
|
||||||
|
<input :id="`answer-survey-${questionIndex}-${answerIndex}`" :type="question.type === 1 ? 'radio' : 'checkbox'" :value="answerIndex" v-model="selectSurveyAnswer[questionIndex]">
|
||||||
|
<label :for="`answer-survey-${questionIndex}-${answerIndex}`" class="font-semibold">{{ answer.title }}</label>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button @click="submitSend" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Gửi câu trả lời</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:root {
|
||||||
|
--before-width: 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as ADS_Default } from './layouts/Default.vue';
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { enumPageComponentTemplates } from "@/definitions/enum";
|
||||||
|
import { ADS_Default
|
||||||
|
} from "./index";
|
||||||
|
const _props = defineProps<{
|
||||||
|
settings: any;
|
||||||
|
component?: any;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const definedDynamicComponent: Record<string, any> = {
|
||||||
|
'DEFAULT': ADS_Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentComponent = computed(() => `${_props.settings.layout}`);
|
||||||
|
const GET_PROPS = computed(() => {
|
||||||
|
return () => {
|
||||||
|
let props: any = {};
|
||||||
|
if (_props.settings) {
|
||||||
|
for (const [key, value] of Object.entries(_props.settings)) {
|
||||||
|
props = {
|
||||||
|
...props,
|
||||||
|
[key]: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="GET_PROPS()" />
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import ADSDefault from '@/assets/images/ads.jpg'
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="shadow">
|
||||||
|
<img :src="ADSDefault" alt="quảng cáo" class=" object-cover">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.content {
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export { default as Article_Card } from './layouts/Card.vue'
|
||||||
|
export { default as Article_Detail_General } from './layouts/details/General.vue'
|
||||||
|
export { default as Article_Detail_Podcast } from './layouts/details/Podcast.vue'
|
||||||
|
export { default as Article_Detail_Video } from './layouts/details/Video.vue'
|
||||||
|
export { default as Article_Detail_Image } from './layouts/details/Image.vue'
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { enumPageComponentTemplates } from "@/definitions/enum";
|
||||||
|
import {
|
||||||
|
Article_Card,
|
||||||
|
Article_Detail_General,
|
||||||
|
Article_Detail_Podcast,
|
||||||
|
Article_Detail_Video,
|
||||||
|
Article_Detail_Image
|
||||||
|
} from "./index";
|
||||||
|
const _props = defineProps<{
|
||||||
|
settings: any;
|
||||||
|
component?: any;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const definedDynamicComponent: Record<string, any> = {
|
||||||
|
'TYPE:Detail-LAYOUT:default': Article_Detail_General,
|
||||||
|
'TYPE:Detail-LAYOUT:image': Article_Detail_Image,
|
||||||
|
'TYPE:Detail-LAYOUT:video': Article_Detail_Video,
|
||||||
|
'TYPE:Detail-LAYOUT:podcast': Article_Detail_Podcast,
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentComponent = computed(() => `${_props.settings.layout}`);
|
||||||
|
const GET_PROPS = computed(() => {
|
||||||
|
return () => {
|
||||||
|
let props: any = {};
|
||||||
|
if (_props.settings) {
|
||||||
|
for (const [key, value] of Object.entries(_props.settings)) {
|
||||||
|
props = {
|
||||||
|
...props,
|
||||||
|
[key]: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="GET_PROPS()" />
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
dataResult?: any;
|
||||||
|
dataType?: any;
|
||||||
|
dataQuery?: any;
|
||||||
|
layout?: string;
|
||||||
|
design?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
vào r</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.basic-article {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&.no-data {
|
||||||
|
gap: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vertical {
|
||||||
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
&.border-custom {
|
||||||
|
border-color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
&.borderLeft {
|
||||||
|
border-left: 2px solid;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
&.borderRight {
|
||||||
|
border-right: 2px solid;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
&.borderTop {
|
||||||
|
border-top: 2px solid;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
&.borderBottom {
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
&.horizontal {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
|
||||||
|
&.reverse {
|
||||||
|
.basic-article_thumbnail {
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.basic-article_content {
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_thumbnail {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 6px;
|
||||||
|
aspect-ratio: 16/10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_content {
|
||||||
|
padding: 10px 0px;
|
||||||
|
|
||||||
|
&.no-data {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-block {
|
||||||
|
background-color: #409eff;
|
||||||
|
height: 100px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+168
@@ -0,0 +1,168 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useArticleStore } from "~/stores/articles";
|
||||||
|
import Poll from "~/components/article/immerse/Poll.vue";
|
||||||
|
import Quiz from "~/components/article/immerse/Quiz.vue";
|
||||||
|
import Survey from "~/components/article/immerse/Survey.vue";
|
||||||
|
import Document from "~/components/article/immerse/Document.vue";
|
||||||
|
import Attachment from "@/components/article/immerse/Attachment.vue";
|
||||||
|
import Tag from "@/components/article/immerse/Tag.vue";
|
||||||
|
const { currentArticle } = storeToRefs(useArticleStore());
|
||||||
|
import { useDynamicPageStore } from "~/stores/dynamic-page";
|
||||||
|
import { useCategoryStore } from "~/stores/category";
|
||||||
|
|
||||||
|
const store = reactive({
|
||||||
|
dynamicPage: useDynamicPageStore(),
|
||||||
|
article: useArticleStore(),
|
||||||
|
category: useCategoryStore(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { categoryTree } = storeToRefs(store.category);
|
||||||
|
|
||||||
|
|
||||||
|
function increase() {
|
||||||
|
const step = ref(Number(getComputedStyle(document.documentElement).getPropertyValue("--step").trim()));
|
||||||
|
step.value += 2;
|
||||||
|
document.documentElement.style.setProperty("--step", step.value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrease() {
|
||||||
|
const step = ref(Number(getComputedStyle(document.documentElement).getPropertyValue("--step").trim()));
|
||||||
|
step.value -= 2;
|
||||||
|
document.documentElement.style.setProperty("--step", step.value.toString());
|
||||||
|
}
|
||||||
|
await store.category.fetchBySiteId();
|
||||||
|
const currentCategoryTree = (store.category.currentCategoryTree = findElementPathById(categoryTree.value, currentArticle.value.categoryId));
|
||||||
|
function findElementPathById(categories: any[], targetId: number, path: any[] = []) {
|
||||||
|
for (const category of categories) {
|
||||||
|
const currentPath = [...path, { title: category.title, code: category.code }];
|
||||||
|
if (category.id === targetId) {
|
||||||
|
return currentPath;
|
||||||
|
}
|
||||||
|
if (category.children) {
|
||||||
|
const result: any = findElementPathById(category.children, targetId, currentPath);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
|
||||||
|
clickElement("figure", "custom-figure", "data-code");
|
||||||
|
clickElement("author", "author", "data-code");
|
||||||
|
|
||||||
|
let detailEmagazine = document.querySelector('div[layout="ARTICLE_DETAIL_EMAGAZINE"]');
|
||||||
|
let breakcrumb = document.querySelector('div[layout="BREADCRUM_DEFAULT"]');
|
||||||
|
if (detailEmagazine && breakcrumb) {
|
||||||
|
breakcrumb.classList.add("lg:max-w-640px", "mx-auto");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function clickElement(type: string, selector: string, attribute: string) {
|
||||||
|
const elements = document.querySelectorAll(selector);
|
||||||
|
elements.forEach((element) => {
|
||||||
|
element.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const url = `${window.location.protocol}//${window.location.host}/${type}/${element.getAttribute(attribute)}`;
|
||||||
|
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isBookmark = ref(false)
|
||||||
|
const onClickBookmark = () => {
|
||||||
|
isBookmark.value = !isBookmark.value
|
||||||
|
}
|
||||||
|
async function copyLink() {
|
||||||
|
try {
|
||||||
|
const url = window.location.href
|
||||||
|
await navigator.clipboard.writeText(url)
|
||||||
|
alert('copy link thành công')
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div id="breakcrumb" class="flex justify-between items-center my-3">
|
||||||
|
<ul class="flex gap-6 items-center text-md">
|
||||||
|
<template v-for="(category, index) in currentCategoryTree" :key="index">
|
||||||
|
<li class="first:text-primary-600 hover:text-primary-600 font-semibold relative after:absolute after:content-['\003E'] last:after:content-[''] after:right--4 after:text-gray-3">
|
||||||
|
<nuxt-link :to="{ name: 'categories', params: { categories: category.code ?? '/' } }">{{ category.title }}</nuxt-link>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<div @click="increase()" class="w-10 h-10 border-1px border-solid shadow rounded-full relative cursor-pointer hover:bg-primary-100 hover:text-primary-600">
|
||||||
|
<svg class="absolute top-50% left-50% translate-y--50% translate-x--55%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
|
||||||
|
<path fill="none" d="M0 0h24v24H0z"></path>
|
||||||
|
<path
|
||||||
|
d="M11.246 15H4.75416L2.75416 20H0.600098L7.0001 4H9.0001L15.4001 20H13.246L11.246 15ZM10.446 13L8.0001 6.88516L5.55416 13H10.446ZM21.0001 12.5351V12H23.0001V20H21.0001V19.4649C20.4118 19.8052 19.7287 20 19.0001 20C16.791 20 15.0001 18.2091 15.0001 16C15.0001 13.7909 16.791 12 19.0001 12C19.7287 12 20.4118 12.1948 21.0001 12.5351ZM19.0001 18C20.1047 18 21.0001 17.1046 21.0001 16C21.0001 14.8954 20.1047 14 19.0001 14C17.8955 14 17.0001 14.8954 17.0001 16C17.0001 17.1046 17.8955 18 19.0001 18Z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<svg class="absolute right-1.5 top-2 w-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M11 11V5H13V11H19V13H13V19H11V13H5V11H11Z"></path></svg>
|
||||||
|
</div>
|
||||||
|
<div @click="decrease()" class="w-10 h-10 border-1px border-solid shadow rounded-full relative cursor-pointer hover:bg-primary-100 hover:text-primary-600">
|
||||||
|
<svg class="absolute top-50% left-50% translate-y--50% translate-x--55%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
|
||||||
|
<path fill="none" d="M0 0h24v24H0z"></path>
|
||||||
|
<path
|
||||||
|
d="M11.246 15H4.75416L2.75416 20H0.600098L7.0001 4H9.0001L15.4001 20H13.246L11.246 15ZM10.446 13L8.0001 6.88516L5.55416 13H10.446ZM21.0001 12.5351V12H23.0001V20H21.0001V19.4649C20.4118 19.8052 19.7287 20 19.0001 20C16.791 20 15.0001 18.2091 15.0001 16C15.0001 13.7909 16.791 12 19.0001 12C19.7287 12 20.4118 12.1948 21.0001 12.5351ZM19.0001 18C20.1047 18 21.0001 17.1046 21.0001 16C21.0001 14.8954 20.1047 14 19.0001 14C17.8955 14 17.0001 14.8954 17.0001 16C17.0001 17.1046 17.8955 18 19.0001 18Z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<svg class="absolute right-1.5 top-2 w-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M5 11V13H19V11H5Z"></path></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content" v-if="currentArticle">
|
||||||
|
<h1 id="sub" v-html="currentArticle?.sub" class="font-bold opacity-60 pb-1"></h1>
|
||||||
|
<h3 id="title" class="font-bold pb-1" v-html="currentArticle?.title"></h3>
|
||||||
|
<p id="published-on" class="text-gray-600 mb-3">{{ utils.dateFormat(currentArticle?.publishedOn, "dddd, DD/MM/YYYY - HH:mm") }}</p>
|
||||||
|
<div id="intro" v-if="currentArticle?.intro" v-html="currentArticle?.intro" class="font-semibold tracking-widest pb-1 mb-3"></div>
|
||||||
|
<component :is="{ template: currentArticle.detail, components: { Poll, Quiz, Survey, Document, Attachment, Tag } }" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-5 flex flex-wrap justify-between items-center">
|
||||||
|
<div class="flex gap-4 items-center">
|
||||||
|
<nuxt-link :to="{ name: 'categories', params: { categories: `${currentCategoryTree[currentCategoryTree.length - 1]?.code}` } }" title="Quay trở lại" class="w-12 h-3rem rounded-full flex items-center justify-center bg-white border-1px shadow hover:bg-primary-100 hover:text-primary-600 cursor-pointer">
|
||||||
|
<Icon name="fa6-solid:arrow-left" />
|
||||||
|
</nuxt-link>
|
||||||
|
<button @click="onClickBookmark()" class="w-8 h-8 rounded-full bg-white hover:bg-primary-100 hover:text-primary-600">
|
||||||
|
<Icon v-show="isBookmark === false" name="fa6-regular:bookmark" />
|
||||||
|
<Icon v-show="isBookmark === true" name="fa6-solid:bookmark" class="text-primary-600" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-4 items-center">
|
||||||
|
<button @click="copyLink()" title="Copy link" class="w-12 h-3rem rounded-full flex items-center justify-center bg-white border-1px shadow hover:bg-primary-100 hover:text-primary-600 cursor-pointer text-2xl">
|
||||||
|
<Icon name="bi:link-45deg" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#sub,
|
||||||
|
#intro,
|
||||||
|
#intro + div {
|
||||||
|
font-size: calc(16px + var(--step) * 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
font-size: calc(28px + var(--step) * 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#published-on {
|
||||||
|
font-size: calc(14px + var(--step) * 1px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useArticleStore } from "~/stores/articles";
|
||||||
|
import Poll from "~/components/article/immerse/Poll.vue";
|
||||||
|
import Quiz from "~/components/article/immerse/Quiz.vue";
|
||||||
|
import Survey from "~/components/article/immerse/Survey.vue";
|
||||||
|
import Document from "~/components/article/immerse/Document.vue";
|
||||||
|
import Attachment from "@/components/article/immerse/Attachment.vue";
|
||||||
|
import Tag from "@/components/article/immerse/Tag.vue";
|
||||||
|
const { currentArticle } = storeToRefs(useArticleStore());
|
||||||
|
import { useDynamicPageStore } from "~/stores/dynamic-page";
|
||||||
|
import { useCategoryStore } from "~/stores/category";
|
||||||
|
|
||||||
|
const store = reactive({
|
||||||
|
dynamicPage: useDynamicPageStore(),
|
||||||
|
article: useArticleStore(),
|
||||||
|
category: useCategoryStore(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { categoryTree } = storeToRefs(store.category);
|
||||||
|
|
||||||
|
await store.category.fetchBySiteId();
|
||||||
|
const currentCategoryTree = (store.category.currentCategoryTree = findElementPathById(categoryTree.value, currentArticle.value.categoryId));
|
||||||
|
function findElementPathById(categories: any[], targetId: number, path: any[] = []) {
|
||||||
|
for (const category of categories) {
|
||||||
|
const currentPath = [...path, { title: category.title, code: category.code }];
|
||||||
|
if (category.id === targetId) {
|
||||||
|
return currentPath;
|
||||||
|
}
|
||||||
|
if (category.children) {
|
||||||
|
const result: any = findElementPathById(category.children, targetId, currentPath);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
clickElement("figure", "custom-figure", "data-code");
|
||||||
|
clickElement("author", "author", "data-code");
|
||||||
|
|
||||||
|
let detailEmagazine = document.querySelector('div[layout="ARTICLE_DETAIL_EMAGAZINE"]');
|
||||||
|
let breakcrumb = document.querySelector('div[layout="BREADCRUM_DEFAULT"]');
|
||||||
|
if (detailEmagazine && breakcrumb) {
|
||||||
|
breakcrumb.classList.add("lg:max-w-640px", "mx-auto");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function clickElement(type: string, selector: string, attribute: string) {
|
||||||
|
const elements = document.querySelectorAll(selector);
|
||||||
|
elements.forEach((element) => {
|
||||||
|
element.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const url = `${window.location.protocol}//${window.location.host}/${type}/${element.getAttribute(attribute)}`;
|
||||||
|
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isBookmark = ref(false);
|
||||||
|
const onClickBookmark = () => {
|
||||||
|
isBookmark.value = !isBookmark.value;
|
||||||
|
};
|
||||||
|
async function copyLink() {
|
||||||
|
try {
|
||||||
|
const url = window.location.href;
|
||||||
|
await navigator.clipboard.writeText(url);
|
||||||
|
alert("copy link thành công");
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(currentArticle, "curetna");
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="content" v-if="currentArticle">
|
||||||
|
<div id="breakcrumb" class="flex justify-between items-center my-3">
|
||||||
|
<ul class="flex gap-6 items-center text-md">
|
||||||
|
<template v-for="(category, index) in currentCategoryTree" :key="index">
|
||||||
|
<li class="font-semibold relative after:absolute after:content-['\003E'] last:after:content-[''] after:right--4 after:text-gray-3">
|
||||||
|
<nuxt-link :class="index !== 0 ? '!text-black' : ''" class="hover:!text-primary-600" :to="{ name: 'categories', params: { categories: category.code ?? '/' } }">{{ category.title }}</nuxt-link>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<span id="published-on" class="text-gray-600 mb-3">{{ utils.dateFormat(currentArticle?.publishedOn, "dddd, DD/MM/YYYY - HH:mm") }}</span>
|
||||||
|
</div>
|
||||||
|
<h1 id="sub" v-html="currentArticle?.sub" class="font-bold opacity-60 pb-1"></h1>
|
||||||
|
<h3 id="title" class="font-bold pb-1" v-html="currentArticle?.title"></h3>
|
||||||
|
|
||||||
|
<div id="intro" v-if="currentArticle?.intro" v-html="currentArticle?.intro" class="font-semibold tracking-widest pb-1 mb-3"></div>
|
||||||
|
<component :is="{ template: currentArticle.detail, components: { Poll, Quiz, Survey, Document, Attachment, Tag } }" />
|
||||||
|
|
||||||
|
<div id="navigation__bottom" class="py-5 flex flex-wrap justify-between items-center">
|
||||||
|
<div class="flex gap-4 items-center">
|
||||||
|
<nuxt-link
|
||||||
|
:to="{ name: 'categories', params: { categories: `${currentCategoryTree[currentCategoryTree.length - 1]?.code}` } }"
|
||||||
|
title="Quay trở lại"
|
||||||
|
class="w-10 h-10 rounded-8px flex items-center justify-center bg-white border-1px shadow hover:bg-primary-100 hover:text-primary-600 cursor-pointer"
|
||||||
|
>
|
||||||
|
<Icon name="fa6-solid:arrow-left" />
|
||||||
|
</nuxt-link>
|
||||||
|
<button @click="onClickBookmark()" class="w-10 h-10 rounded-8px border-1px bg-white hover:bg-primary-100 hover:text-primary-600">
|
||||||
|
<Icon v-show="isBookmark === false" name="fa6-regular:bookmark" />
|
||||||
|
<Icon v-show="isBookmark === true" name="fa6-solid:bookmark" class="text-primary-600" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-4 items-center">
|
||||||
|
<button @click="copyLink()" title="Copy link" class="w-10 h-10 rounded-8px flex items-center justify-center bg-white border-1px shadow hover:bg-primary-100 hover:text-primary-600 cursor-pointer text-2xl">
|
||||||
|
<Icon name="bi:link-45deg" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#sub,
|
||||||
|
#intro,
|
||||||
|
#intro + div {
|
||||||
|
font-size: calc(16px + var(--step) * 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
font-size: calc(28px + var(--step) * 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#published-on {
|
||||||
|
font-size: calc(14px + var(--step) * 1px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<script setup lang="ts"></script>
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
postcart</div>
|
||||||
|
</template>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
div {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Comment from "@/components/dynamic-page/page-component/templates/other/comments/default.vue";
|
||||||
|
import { useArticleStore } from "~/stores/articles";
|
||||||
|
import Poll from "~/components/article/immerse/Poll.vue";
|
||||||
|
import Quiz from "~/components/article/immerse/Quiz.vue";
|
||||||
|
import Survey from "~/components/article/immerse/Survey.vue";
|
||||||
|
import Document from "~/components/article/immerse/Document.vue";
|
||||||
|
import Attachment from "@/components/article/immerse/Attachment.vue";
|
||||||
|
import Tag from "@/components/article/immerse/Tag.vue";
|
||||||
|
const { currentArticle } = storeToRefs(useArticleStore());
|
||||||
|
import { useDynamicPageStore } from "~/stores/dynamic-page";
|
||||||
|
import { useCategoryStore } from "~/stores/category";
|
||||||
|
|
||||||
|
const store = reactive({
|
||||||
|
dynamicPage: useDynamicPageStore(),
|
||||||
|
article: useArticleStore(),
|
||||||
|
category: useCategoryStore(),
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(currentArticle.value ,'curenta')
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3">
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<video class="w-full h-full" controls="controls" width="100%" height="100%" data-file-id="149" data-resource="https://acp-api.vpress.vn/Resources/Video/983d2f57-7743-472f-b22d-fc73085af6d5.mp4" data-title="Download.mp4">
|
||||||
|
<source src="" type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-4 pt-2 bg-[rgb(248,249,250)]">
|
||||||
|
<h1 class="text-2rem text-#495057 font-700" v-html="currentArticle.title"></h1>
|
||||||
|
<p class="line-clamp-3 font-400" v-html="currentArticle.intro"></p>
|
||||||
|
<h5 class="text-end font-600 opacity-75">Tác giả</h5>
|
||||||
|
|
||||||
|
<p><b class="text-primary-600 fw-bold">Danh mục</b> <span class="ms-2 opacity-25 fw-semibold">{{ utils.dateFormat(currentArticle?.publishedOn, "dddd, DD/MM/YYYY - HH:mm") }}</span></p>
|
||||||
|
<Comment />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.line-clamp-3 {
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as Collection_Article } from './layouts/Article.vue'
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
Collection_Article
|
||||||
|
} from "./index";
|
||||||
|
const _props = defineProps<{
|
||||||
|
settings: any;
|
||||||
|
component?: any;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const definedDynamicComponent: Record<string, any> = {
|
||||||
|
'TYPE:Article-LAYOUT:vertical-DATA:HORIZONTAL': Collection_Article,
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentComponent = computed(() => `${_props.settings.layout}`);
|
||||||
|
const GET_PROPS = computed(() => {
|
||||||
|
return () => {
|
||||||
|
let props: any = {};
|
||||||
|
if (_props.settings) {
|
||||||
|
for (const [key, value] of Object.entries(_props.settings)) {
|
||||||
|
props = {
|
||||||
|
...props,
|
||||||
|
[key]: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="GET_PROPS()" />
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<script setup lang="ts"></script>
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
collection
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
// Article
|
// Article
|
||||||
export { default as Article_BasicCard } from './articles/individuals/Card.vue'
|
export { default as Article_BasicCard } from './articles/individuals/Card.vue'
|
||||||
|
|
||||||
export { default as Article_BasicCollection } from './articles/collections/BasicCollection.vue'
|
export { default as Article_BasicCollection } from './articles/collections/BasicCollection.vue'
|
||||||
|
|
||||||
// Category
|
// Category
|
||||||
@@ -7,4 +8,8 @@ export { default as BasicCategories } from './categories/BasicCategories.vue'
|
|||||||
export { default as CollectionPaging } from './pageCategories/collection_page.vue'
|
export { default as CollectionPaging } from './pageCategories/collection_page.vue'
|
||||||
|
|
||||||
|
|
||||||
export { default as Dynamic_Other } from './other/index.vue'
|
export { default as Dynamic_Other } from './other/index.vue'
|
||||||
|
|
||||||
|
export { default as Dynamic_Advertising } from './advertising/index.vue'
|
||||||
|
export { default as Dynamic_Article } from './articles/index.vue'
|
||||||
|
export { default as Dynamic_Collection } from './collections/index.vue'
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { enumPageComponentTemplates } from "@/definitions/enum";
|
import { enumPageComponentTemplates } from "@/definitions/enum";
|
||||||
import { Article_BasicCard, BasicCategories, Article_BasicCollection, CollectionPaging, Dynamic_Other } from "./index";
|
import { BasicCategories, Dynamic_Collection, CollectionPaging, Dynamic_Other, Dynamic_Advertising, Dynamic_Article } from "./index";
|
||||||
|
|
||||||
const _props = defineProps<{
|
const _props = defineProps<{
|
||||||
settings: any;
|
settings: any;
|
||||||
component?: any;
|
component?: any;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const definedDynamicComponent: Record<string, any> = {
|
const definedDynamicComponent: Record<string, any> = {
|
||||||
[enumPageComponentTemplates.ARTICLE]: Article_BasicCard,
|
[enumPageComponentTemplates.ARTICLE]: Dynamic_Article,
|
||||||
[enumPageComponentTemplates.CATEGORY]: BasicCategories,
|
[enumPageComponentTemplates.CATEGORY]: BasicCategories,
|
||||||
[enumPageComponentTemplates.COLLECTION]: Article_BasicCollection,
|
[enumPageComponentTemplates.COLLECTION]: Dynamic_Collection,
|
||||||
[enumPageComponentTemplates.SECTION]: CollectionPaging,
|
[enumPageComponentTemplates.SECTION]: CollectionPaging,
|
||||||
[enumPageComponentTemplates.OTHER]: Dynamic_Other
|
[enumPageComponentTemplates.OTHER]: Dynamic_Other,
|
||||||
|
[enumPageComponentTemplates.ADVERTISING]: Dynamic_Advertising
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCurrentComponent = computed(() => `${_props.settings.template}`);
|
const getCurrentComponent = computed(() => `${_props.settings.template}`);
|
||||||
|
|
||||||
|
|
||||||
const GET_PROPS = computed(() => {
|
const GET_PROPS = computed(() => {
|
||||||
return () => {
|
return () => {
|
||||||
let props: any = {};
|
let props: any = {};
|
||||||
|
|||||||
@@ -1,38 +1,73 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import { useDynamicPageStore } from "~/stores/dynamic-page";
|
import { useDynamicPageStore } from "~/stores/dynamic-page";
|
||||||
|
import { useCategoryStore } from "~/stores/category";
|
||||||
|
import { useArticleStore } from "~/stores/articles";
|
||||||
|
|
||||||
|
const store = reactive({
|
||||||
|
dynamicPage: useDynamicPageStore(),
|
||||||
|
article: useArticleStore(),
|
||||||
|
category: useCategoryStore()
|
||||||
|
})
|
||||||
|
|
||||||
|
const { currentArticle } = storeToRefs(store.article)
|
||||||
|
const { categoryTree } = storeToRefs(store.category)
|
||||||
if(!localStorage.getItem('step')) {
|
if(!localStorage.getItem('step')) {
|
||||||
localStorage.setItem('step', '0')
|
localStorage.setItem('step', '0')
|
||||||
}
|
}
|
||||||
useDynamicPageStore().step = Number(localStorage.getItem('step')) ?? 0
|
|
||||||
function increase() {
|
function increase() {
|
||||||
useDynamicPageStore().step = Number(useDynamicPageStore().step) + 2
|
|
||||||
localStorage.setItem('step', useDynamicPageStore().step.toString())
|
const step = ref(Number(getComputedStyle(document.documentElement).getPropertyValue('--step').trim()))
|
||||||
|
step.value += 2
|
||||||
|
document.documentElement.style.setProperty('--step', step.value.toString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function decrease() {
|
function decrease() {
|
||||||
useDynamicPageStore().step = Number(useDynamicPageStore().step) - 2
|
const step = ref(Number(getComputedStyle(document.documentElement).getPropertyValue('--step').trim()))
|
||||||
localStorage.setItem('step', useDynamicPageStore().step.toString())
|
step.value -= 2
|
||||||
|
document.documentElement.style.setProperty('--step', step.value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findElementPathById(categories: any[], targetId: number, path = []) {
|
||||||
|
for (const category of categories) {
|
||||||
|
const currentPath = [...path, { title: category.title, code: category.code }];
|
||||||
|
if (category.id === targetId) {
|
||||||
|
return currentPath;
|
||||||
|
}
|
||||||
|
if (category.children) {
|
||||||
|
const result: any = findElementPathById(category.children, targetId, currentPath);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
await store.category.fetchBySiteId()
|
||||||
|
console.log(store.category.categoryTree, 'tree')
|
||||||
|
if(!categoryTree.value?.length) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentCategoryTree = store.category.currentCategoryTree = findElementPathById(categoryTree.value, currentArticle.value.categoryId)
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let detailEmagazine = document.querySelector('div[layout="ARTICLE_DETAIL_EMAGAZINE"]')
|
let detailEmagazine = document.querySelector('div[layout="ARTICLE_DETAIL_EMAGAZINE"]')
|
||||||
let breakcrumb = document.querySelector('div[layout="BREADCRUM_DEFAULT"]')
|
let breakcrumb = document.querySelector('div[layout="BREADCRUM_DEFAULT"]')
|
||||||
if( detailEmagazine && breakcrumb) {
|
if( detailEmagazine && breakcrumb) {
|
||||||
breakcrumb.classList.add('lg:max-w-640px','mx-auto')
|
breakcrumb.classList.add('lg:max-w-640px','mx-auto')
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('b')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="flex justify-between items-center my-3">
|
<div class="flex justify-between items-center my-3">
|
||||||
<ul class="flex gap-6 items-center text-md">
|
<ul class="flex gap-6 items-center text-md">
|
||||||
<li class="first:text-primary-600 font-semibold">
|
<template v-for="(category, index) in currentCategoryTree" :key="index">
|
||||||
<nuxt-link to="/">Trang chủ</nuxt-link>
|
<li class="first:text-primary-600 hover:text-primary-600 font-semibold relative after:absolute after:content-['\003E'] last:after:content-[''] after:right--4 after:text-gray-3">
|
||||||
</li>
|
<nuxt-link :to="{ name: 'categories', params: { categories: category.code ?? '/' } }">{{ category.title }}</nuxt-link>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@@ -47,12 +82,9 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss">
|
||||||
.empty {
|
:root {
|
||||||
border-radius: 6px;
|
--step: 0;
|
||||||
background: #409eff;
|
|
||||||
width: 40px;
|
|
||||||
min-height: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useCategoryStore } from '@/stores/category';
|
||||||
|
const store = {
|
||||||
|
category: useCategoryStore()
|
||||||
|
}
|
||||||
|
|
||||||
|
const { currentCategoryTree } = storeToRefs(store.category)
|
||||||
const isBookmark = ref(false)
|
const isBookmark = ref(false)
|
||||||
const onClickBookmark = () => {
|
const onClickBookmark = () => {
|
||||||
isBookmark.value = !isBookmark.value
|
isBookmark.value = !isBookmark.value
|
||||||
@@ -14,11 +20,12 @@ async function copyLink() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="py-5 flex flex-wrap justify-between items-center">
|
<div class="py-5 flex flex-wrap justify-between items-center">
|
||||||
<div class="flex gap-4 items-center">
|
<div class="flex gap-4 items-center">
|
||||||
<nuxt-link to="/" title="Quay trở lại" class="w-12 h-3rem rounded-full flex items-center justify-center bg-white border-1px shadow hover:bg-primary-100 hover:text-primary-600 cursor-pointer">
|
<nuxt-link :to="{ name: 'categories', params: { categories: `${currentCategoryTree[currentCategoryTree.length - 1]?.code}` } }" title="Quay trở lại" class="w-12 h-3rem rounded-full flex items-center justify-center bg-white border-1px shadow hover:bg-primary-100 hover:text-primary-600 cursor-pointer">
|
||||||
<Icon name="fa6-solid:arrow-left" />
|
<Icon name="fa6-solid:arrow-left" />
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
<button @click="onClickBookmark()" class="w-8 h-8 rounded-full bg-white hover:bg-primary-100 hover:text-primary-600">
|
<button @click="onClickBookmark()" class="w-8 h-8 rounded-full bg-white hover:bg-primary-100 hover:text-primary-600">
|
||||||
|
|||||||
@@ -11,17 +11,57 @@ import Document from '~/components/article/immerse/Document.vue'
|
|||||||
import Attachment from '@/components/article/immerse/Attachment.vue'
|
import Attachment from '@/components/article/immerse/Attachment.vue'
|
||||||
import Tag from '@/components/article/immerse/Tag.vue'
|
import Tag from '@/components/article/immerse/Tag.vue'
|
||||||
import Articlerelation from '~/components/article/immerse/ArticleRelation.vue'
|
import Articlerelation from '~/components/article/immerse/ArticleRelation.vue'
|
||||||
|
|
||||||
const { currentArticle } = storeToRefs(useArticleStore());
|
const { currentArticle } = storeToRefs(useArticleStore());
|
||||||
const { step } = storeToRefs(useDynamicPageStore());
|
const { step } = storeToRefs(useDynamicPageStore());
|
||||||
import * as cherrio from 'cheerio'
|
|
||||||
|
|
||||||
const $ = cherrio.load(currentArticle.value.detail)
|
const router = useRouter()
|
||||||
// console.log($, 'cherrip')
|
// import * as cherrio from 'cheerio'
|
||||||
|
|
||||||
|
// const $ = cherrio.load(currentArticle.value.detail)
|
||||||
|
// for(let index = 0; index < $('articlerelation').length, index++) {
|
||||||
|
// $('articlerelation')[index]
|
||||||
|
// }
|
||||||
|
// console.log($('articlerelation').length, 'cherrip')
|
||||||
// onBeforeMount(async () => {
|
// onBeforeMount(async () => {
|
||||||
// await useArticleStore().getArticleCondition({ids: [1, 2, 3]})
|
// await useArticleStore().getArticleCondition({ids: [1, 2, 3]})
|
||||||
// })
|
// })
|
||||||
|
// console.log(router,'route')
|
||||||
|
onMounted(() => {
|
||||||
|
// const elements = document.querySelectorAll('custom-figure')
|
||||||
|
// elements.forEach((element) => {
|
||||||
|
// element.addEventListener('click', (event) => {
|
||||||
|
// event.preventDefault();
|
||||||
|
// console.log(element, 'element')
|
||||||
|
// const url = `figure/${element.getAttribute('data-code')}`;
|
||||||
|
|
||||||
|
// const a = document.createElement('a')
|
||||||
|
// a.href = url;
|
||||||
|
// document.body.appendChild(a)
|
||||||
|
// a.click();
|
||||||
|
// document.body.removeChild(a);
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
|
||||||
|
clickElement('figure', 'custom-figure', 'data-code')
|
||||||
|
clickElement('author', 'author', 'data-code')
|
||||||
|
})
|
||||||
|
|
||||||
|
function clickElement(type: string, selector: string, attribute: string) {
|
||||||
|
const elements = document.querySelectorAll(selector)
|
||||||
|
elements.forEach((element) => {
|
||||||
|
element.addEventListener('click', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const url = `${window.location.protocol}//${window.location.host}/${type}/${element.getAttribute(attribute)}`;
|
||||||
|
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.href = url;
|
||||||
|
document.body.appendChild(a)
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// const fileName = ref('')
|
||||||
// onMounted(() => {
|
// onMounted(() => {
|
||||||
// const documentElements = document.querySelectorAll('document, attachment')
|
// const documentElements = document.querySelectorAll('document, attachment')
|
||||||
|
|
||||||
@@ -50,15 +90,24 @@ const $ = cherrio.load(currentArticle.value.detail)
|
|||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="content" v-if="currentArticle">
|
<div class="content" v-if="currentArticle">
|
||||||
<h1 id="sub" v-html="currentArticle?.sub" class=" font-bold opacity-60 pb-1" :style="{ 'font-size': `${16 + Number(step)}px`}"></h1>
|
<h1 id="sub" v-html="currentArticle?.sub" class=" font-bold opacity-60 pb-1"></h1>
|
||||||
<h3 id="title" :style="{ 'font-size': width > breakpoint.lg ? `${32 + Number(step)}px` : `${20 + Number(step)}px`}" class="font-bold pb-1" v-html="currentArticle?.title"></h3>
|
<h3 id="title" class="font-bold pb-1" v-html="currentArticle?.title"></h3>
|
||||||
<p id="published-on" class="text-gray-600 mb-3" :style="{ 'font-size': `${14 + Number(step)}px` }">{{ utils.dateFormat(currentArticle?.publishedOn, "dddd, DD/MM/YYYY - HH:mm") }}</p>
|
<p id="published-on" class="text-gray-600 mb-3">{{ utils.dateFormat(currentArticle?.publishedOn, "dddd, DD/MM/YYYY - HH:mm") }}</p>
|
||||||
<div id="intro" v-if="currentArticle?.intro" v-html="currentArticle?.intro" class="font-semibold tracking-widest pb-1 mb-3" :style="{'font-size': `${16 + Number(step)}px`}"></div>
|
<div id="intro" v-if="currentArticle?.intro" v-html="currentArticle?.intro" class="font-semibold tracking-widest pb-1 mb-3"></div>
|
||||||
<!-- <div id="article-detail" :class="'tracking-wider'" v-html="currentArticle.detail" class="[&_img]:mx-auto" :style="{ 'font-size': `${16 + Number(step)}px`}"> </div> -->
|
<component :is="{template: currentArticle.detail, components: { Poll, Quiz, Survey, Document, Attachment, Tag} }" />
|
||||||
<component :is="{template: currentArticle.detail, components: { Poll, Document, Attachment, Tag} }" />
|
|
||||||
<!-- <component :is="{template: currentArticle.detail, components: { Poll, Quiz, Survey, Document, Attachment, Tag} }" /> -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
|
#sub, #intro, #intro + div {
|
||||||
|
font-size: calc(16px + var(--step) * 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
font-size: calc(28px + var(--step) * 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#published-on {
|
||||||
|
font-size: calc(14px + var(--step) * 1px);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -15,7 +15,7 @@ const definedDynamicComponent: Record<string, any> = {
|
|||||||
'ARTICLE_DETAIL_EMAGAZINE': Article_Detail_Emagazine,
|
'ARTICLE_DETAIL_EMAGAZINE': Article_Detail_Emagazine,
|
||||||
'ADS_DEFAULT': ADS_Default,
|
'ADS_DEFAULT': ADS_Default,
|
||||||
'ARTICLE_BUTTON': Article_Button,
|
'ARTICLE_BUTTON': Article_Button,
|
||||||
COMMENT: Comment,
|
'COMMENT_DEFAULT': Comment,
|
||||||
PODCAST: Article_Detail_Podcast,
|
PODCAST: Article_Detail_Podcast,
|
||||||
VIDEO: Article_Detail_Video
|
VIDEO: Article_Detail_Video
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const CLASS_FOR_LAYOUT = computed(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[CLASS_FOR_LAYOUT.page_container]">
|
<div :class="[CLASS_FOR_LAYOUT.page_container]">
|
||||||
<div :class="[CLASS_FOR_LAYOUT.layout_container]" class="grid-container grid grid-cols-1 gap-20 py-20 style_layout">
|
<div :class="[CLASS_FOR_LAYOUT.layout_container]" class="grid-container grid grid-cols-1 gap-20 py-10 style_layout">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="page_container full-size-page">
|
<div class="page_container full-size-page">
|
||||||
<div class="layout_container center-layout grid-container">
|
<div class="container-long my-5">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -164,11 +164,16 @@ export const pageComponentLayouts = {
|
|||||||
{ title: "Dọc và ẩn Hình ảnh", value: enumPageComponentLayouts[enumPageComponentTemplates.ARTICLE]['VERTICAL-HIDE_THUMBNAIL'] },
|
{ title: "Dọc và ẩn Hình ảnh", value: enumPageComponentLayouts[enumPageComponentTemplates.ARTICLE]['VERTICAL-HIDE_THUMBNAIL'] },
|
||||||
{ title: "Dọc và ẩn Giới thiệu", value: enumPageComponentLayouts[enumPageComponentTemplates.ARTICLE]['VERTICAL-HIDE_PARAGRAPH'] },
|
{ title: "Dọc và ẩn Giới thiệu", value: enumPageComponentLayouts[enumPageComponentTemplates.ARTICLE]['VERTICAL-HIDE_PARAGRAPH'] },
|
||||||
{ title: "Dọc và ẩn Giới thiệu, ngược", value: enumPageComponentLayouts[enumPageComponentTemplates.ARTICLE]['VERTICAL-HIDE_PARAGRAPH-REVERSE'] },
|
{ title: "Dọc và ẩn Giới thiệu, ngược", value: enumPageComponentLayouts[enumPageComponentTemplates.ARTICLE]['VERTICAL-HIDE_PARAGRAPH-REVERSE'] },
|
||||||
|
{ title: "mặc định", value: enumPageComponentLayouts[enumPageComponentTemplates.ARTICLE]['DEFAULT'] },
|
||||||
],
|
],
|
||||||
[`${enumPageComponentTemplates.CATEGORY}`]: [
|
[`${enumPageComponentTemplates.CATEGORY}`]: [
|
||||||
{ title: "Danh mục", value: enumPageComponentLayouts[enumPageComponentTemplates.CATEGORY]['DEFAULT'] }
|
{ title: "Danh mục", value: enumPageComponentLayouts[enumPageComponentTemplates.CATEGORY]['DEFAULT'] }
|
||||||
],
|
],
|
||||||
[`${enumPageComponentTemplates.COLLECTION}`]: [
|
[`${enumPageComponentTemplates.COLLECTION}`]: [
|
||||||
{ title: "Cụm Bài viết 5 phần tử, Bài viết ngang", value: enumPageComponentLayouts[enumPageComponentTemplates.COLLECTION]['ARTICLE-VERTICAL-|HORIZONTAL|-MAX_5'] },
|
{ title: "Cụm Bài viết 5 phần tử, Bài viết ngang", value: enumPageComponentLayouts[enumPageComponentTemplates.COLLECTION]['ARTICLE-VERTICAL-|HORIZONTAL|-MAX_5'] },
|
||||||
|
{ title: "Cụm Bài viết Mặc định", value: enumPageComponentLayouts[enumPageComponentTemplates.COLLECTION]['DEFAULT'] },
|
||||||
|
],
|
||||||
|
[`${enumPageComponentTemplates.ADVERTISING}`]: [
|
||||||
|
{ title: "Quảng cáo mặc định", value: enumPageComponentLayouts[enumPageComponentTemplates.ADVERTISING]['DEFAULT'] },
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export const enumPageComponentLayouts = {
|
|||||||
'VERTICAL-HIDE_THUMBNAIL': "LAYOUT:vertical-HIDE:thumbnail",
|
'VERTICAL-HIDE_THUMBNAIL': "LAYOUT:vertical-HIDE:thumbnail",
|
||||||
'VERTICAL-HIDE_PARAGRAPH': "LAYOUT:vertical-HIDE:paragraph",
|
'VERTICAL-HIDE_PARAGRAPH': "LAYOUT:vertical-HIDE:paragraph",
|
||||||
'VERTICAL-HIDE_PARAGRAPH-REVERSE': "LAYOUT:vertical-HIDE:paragraph-REVERSE:true",
|
'VERTICAL-HIDE_PARAGRAPH-REVERSE': "LAYOUT:vertical-HIDE:paragraph-REVERSE:true",
|
||||||
|
"DEFAULT": "TYPE:Detail-LAYOUT:default"
|
||||||
},
|
},
|
||||||
[`${enumPageComponentTemplates.CATEGORY}`]: {
|
[`${enumPageComponentTemplates.CATEGORY}`]: {
|
||||||
NONE: "None",
|
NONE: "None",
|
||||||
@@ -141,6 +142,9 @@ export const enumPageComponentLayouts = {
|
|||||||
},
|
},
|
||||||
[`${enumPageComponentTemplates.OTHER}`]: {
|
[`${enumPageComponentTemplates.OTHER}`]: {
|
||||||
'"ARTICLE_BUTTON"': '"ARTICLE_BUTTON"'
|
'"ARTICLE_BUTTON"': '"ARTICLE_BUTTON"'
|
||||||
|
},
|
||||||
|
[`${enumPageComponentTemplates.ADVERTISING}`]: {
|
||||||
|
'DEFAULT': 'DEFAULT'
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,35 +40,31 @@ watch(currentArticle, async () => {
|
|||||||
let isContentType : string = '';
|
let isContentType : string = '';
|
||||||
switch (currentArticle.value?.contentType) {
|
switch (currentArticle.value?.contentType) {
|
||||||
case 1:
|
case 1:
|
||||||
isContentType = 'trang-doi-song'
|
isContentType = 'trang-chi-tiet-bai-viet-general'
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
isContentType = 'ArticleLayoutImage'
|
isContentType = 'trang-chi-tiet-bai-viet-image'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
isContentType = 'trang-chi-tiet-podcast'
|
isContentType = 'trang-chi-tiet-bai-viet-postcart'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
isContentType = 'trang-chi-tiet-video-clip'
|
isContentType = 'trang-chi-tiet-bai-viet-video'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
if (currentArticle.value?.layoutType === 4) {
|
if (currentArticle.value?.layoutType === 4) {
|
||||||
isContentType = 'trang-chi-tiet-emagazine'
|
isContentType = 'trang-chi-tiet-bai-viet-emagazine'
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (currentArticle.value?.layoutType === 3) {
|
if (currentArticle.value?.layoutType === 3) {
|
||||||
isContentType = 'trang-chi-tiet-infographics'
|
isContentType = 'trang-chi-tiet-bai-viet-infographics'
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// else {
|
|
||||||
// isContentType = 'trang-chi-tiet-emagazine'
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
default:
|
default:
|
||||||
isContentType = 'trang-chi-tiet-emagazine'
|
isContentType = 'trang-chi-tiet-bai-viet-general'
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
await loadPage(isContentType);
|
await loadPage(isContentType);
|
||||||
@@ -83,9 +79,6 @@ useSeoMeta({
|
|||||||
twitterCard: 'summary_large_image',
|
twitterCard: 'summary_large_image',
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
console.log(document.querySelectorAll('document'), '12')
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import * as topicCtrl from '~/server/models/topic'
|
|||||||
import * as pollCtrl from '~/server/models/poll'
|
import * as pollCtrl from '~/server/models/poll'
|
||||||
import * as pollOptionCtrl from '~/server/models/poll-option'
|
import * as pollOptionCtrl from '~/server/models/poll-option'
|
||||||
import * as pollResponseCtrl from '~/server/models/poll-response'
|
import * as pollResponseCtrl from '~/server/models/poll-response'
|
||||||
|
import * as CategoryCtrl from '~/server/models/category'
|
||||||
|
import * as quizCtrl from '~/server/models/quiz'
|
||||||
|
import * as survetCtrl from '~/server/models/survey'
|
||||||
|
|
||||||
const router = createRouter()
|
const router = createRouter()
|
||||||
|
|
||||||
@@ -16,4 +19,8 @@ router.get('/event', defineEventHandler(eventCtrl.fetchById))
|
|||||||
router.get('/poll-by-id', defineEventHandler(pollCtrl.fetchById))
|
router.get('/poll-by-id', defineEventHandler(pollCtrl.fetchById))
|
||||||
router.get('/poll-option/pollId', defineEventHandler(pollOptionCtrl.fetchByPollId))
|
router.get('/poll-option/pollId', defineEventHandler(pollOptionCtrl.fetchByPollId))
|
||||||
router.post('/poll-response', defineEventHandler(pollResponseCtrl.create))
|
router.post('/poll-response', defineEventHandler(pollResponseCtrl.create))
|
||||||
|
router.get('/poll-response/pollId', defineEventHandler(pollResponseCtrl.fetchByPollId))
|
||||||
|
router.get('/quiz/get-by-id', defineEventHandler(quizCtrl.fetchById))
|
||||||
|
router.get('/survey/get-by-id', defineEventHandler(survetCtrl.fetchById))
|
||||||
|
router.get('/category-tree', defineEventHandler(CategoryCtrl.list))
|
||||||
export default useBase('/api/services', router.handler)
|
export default useBase('/api/services', router.handler)
|
||||||
|
|||||||
@@ -24,20 +24,22 @@ export type Category = {
|
|||||||
status: number;
|
status: number;
|
||||||
} & Base;
|
} & Base;
|
||||||
|
|
||||||
|
export type CategoryTree = Category & {
|
||||||
|
children?: Category[]
|
||||||
|
}
|
||||||
|
|
||||||
export const list = async () => {
|
export const list = async () => {
|
||||||
|
console.log('vào category service')
|
||||||
try {
|
try {
|
||||||
const { site, apiUrl } = useRuntimeConfig().public;
|
const { site, apiUrl } = useRuntimeConfig().public;
|
||||||
|
|
||||||
const {items}:any = await $fetch(`${apiUrl}/cms/category/site`, {
|
const { items }: CategoryTree[] | any = await $fetch(`${apiUrl}/cms/category/tree/site:1`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
site: 1,
|
||||||
Accept: "application/json",
|
|
||||||
site: site,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
return { items } ;
|
||||||
return items;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,25 @@
|
|||||||
import { H3Event } from 'h3';
|
import { H3Event } from 'h3';
|
||||||
import Base from './base'
|
import Base from './base'
|
||||||
|
|
||||||
|
export type PollOption = {
|
||||||
|
id?: number; // Mã định danh
|
||||||
|
siteId?: number; // Mã hệ thống
|
||||||
|
pollId?: number; // Mã bình chọn
|
||||||
|
title?: string; // Tiêu đề
|
||||||
|
thumbnail?: string; // Ảnh đại diện
|
||||||
|
description?: string; // Mô tả
|
||||||
|
type?: number; // Phân loại
|
||||||
|
order?: number; // Sắp xếp
|
||||||
|
status?: number; // Trạng thái
|
||||||
|
responsesCount?: number //số lượng response của option
|
||||||
|
}
|
||||||
|
|
||||||
export const fetchByPollId = async (event: H3Event) => {
|
export const fetchByPollId = async (event: H3Event) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const { apiUrl } = useRuntimeConfig().public
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
const { pollId}: any = getQuery(event)
|
const { pollId }: any = getQuery(event)
|
||||||
const { items }: any = await $fetch(`${apiUrl}/cms/poll-option/poll:${pollId}`, {
|
const { items }: PollOption[] | any = await $fetch(`${apiUrl}/cms/poll-option/poll:${pollId}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
site: 1
|
site: 1
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
import { H3Event } from 'h3';
|
import { H3Event } from 'h3';
|
||||||
import Base from './base'
|
import Base from './base'
|
||||||
|
|
||||||
|
export type PollResponse = {
|
||||||
|
id?: number; // Mã định danh
|
||||||
|
siteId?: number; // Mã hệ thống
|
||||||
|
pollId?: number; // Mã bình chọn
|
||||||
|
optionId?: number; // Mã tùy chọn
|
||||||
|
responderId?: number; // Mã người phản hồi
|
||||||
|
responderInfo?: string; // Thông tin người phản hồi
|
||||||
|
status?: number; // Trạng thái
|
||||||
|
}
|
||||||
|
|
||||||
export const create = async (event: H3Event) => {
|
export const create = async (event: H3Event) => {
|
||||||
try {
|
try {
|
||||||
const { apiUrl } = useRuntimeConfig().public
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
const payload = await readBody<any>(event)
|
const payload = await readBody<any>(event)
|
||||||
@@ -11,14 +20,31 @@ import Base from './base'
|
|||||||
headers: {
|
headers: {
|
||||||
site: 1
|
site: 1
|
||||||
},
|
},
|
||||||
body: {
|
body: payload
|
||||||
payload
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
console.log(payload, 'payload')
|
||||||
return item
|
return item
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fetchByPollId = async (event: H3Event) => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
|
const { pollId }: any = getQuery(event)
|
||||||
|
const { items }: PollResponse[] | any = await $fetch(`${apiUrl}/cms/poll-response/poll:${pollId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
site: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
import { H3Event } from 'h3';
|
import { H3Event } from 'h3';
|
||||||
import Base from './base'
|
import Base from './base'
|
||||||
|
|
||||||
|
export type PollSetting = {
|
||||||
|
participantType?: number; // Loại thành phần tham gia
|
||||||
|
resultPublication?: number; // Nguyên tắc công bố kết quả
|
||||||
|
}
|
||||||
|
|
||||||
export type Poll = {
|
export type Poll = {
|
||||||
id?: number; // Mã định danh
|
id?: number; // Mã định danh
|
||||||
siteId?: number; // Mã hệ thống
|
siteId?: number; // Mã hệ thống
|
||||||
@@ -12,7 +17,7 @@ export type Poll = {
|
|||||||
startTime?: string; // Bắt đầu (string)
|
startTime?: string; // Bắt đầu (string)
|
||||||
endTime?: string; // Kết thúc (string)
|
endTime?: string; // Kết thúc (string)
|
||||||
type?: number; // Phân loại
|
type?: number; // Phân loại
|
||||||
settings?: object; // Thiết lập: PollSettings (Json)
|
settings?: PollSetting; // Thiết lập: PollSettings (Json)
|
||||||
features?: string; // Đặc trưng: Featured (nổi bật)
|
features?: string; // Đặc trưng: Featured (nổi bật)
|
||||||
taxonomy?: string; // Phân nhóm
|
taxonomy?: string; // Phân nhóm
|
||||||
isPublished?: boolean; // Đã xuất bản
|
isPublished?: boolean; // Đã xuất bản
|
||||||
@@ -25,10 +30,9 @@ export type Poll = {
|
|||||||
|
|
||||||
export const fetchById = async (event: H3Event) => {
|
export const fetchById = async (event: H3Event) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const { apiUrl } = useRuntimeConfig().public
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
const { pollId}: any = getQuery(event)
|
const { pollId}: any = getQuery(event)
|
||||||
const { item }: any = await $fetch(`${apiUrl}/cms/poll/${pollId}`, {
|
const { item }: Poll | any = await $fetch(`${apiUrl}/cms/poll/${pollId}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
site: 1
|
site: 1
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { H3Event } from 'h3';
|
||||||
|
export type QuizSetting = {
|
||||||
|
participantType?: number; // Loại thành phần tham gia
|
||||||
|
resultPublication?: number; // Nguyên tắc công bố kết quả
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Quiz = {
|
||||||
|
id?: number; // Mã định danh
|
||||||
|
siteId?: number; // Mã hệ thống
|
||||||
|
title?: string; // Tiêu đề
|
||||||
|
code?: string; // Nhận diện
|
||||||
|
keywords?: string; // Từ khóa
|
||||||
|
thumbnail?: string; // Ảnh nhỏ
|
||||||
|
description?: string; // Mô tả
|
||||||
|
startTime?: string; // Bắt đầu
|
||||||
|
endTime?: string; // Kết thúc
|
||||||
|
type?: number; // Phân loại
|
||||||
|
settings?: object; // Thiết lập
|
||||||
|
features?: string; // Đặc trưng
|
||||||
|
taxonomy?: string; // Phân nhóm
|
||||||
|
isPublished?: boolean; // Đã xuất bản
|
||||||
|
publishedBy?: number; // Xuất bản bởi
|
||||||
|
publishedOn?: string; // Xuất bản vào lúc
|
||||||
|
expiresOn?: string; // Đã hết hạn vào lúc
|
||||||
|
order?: number; // Thứ tự sắp xếp
|
||||||
|
status?: number; // Trạng thái
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchById = async (event: H3Event) => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
|
const { quizId }: any = getQuery(event)
|
||||||
|
const { item }: Quiz | any = await $fetch(`${apiUrl}/cms/quiz/${quizId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
site: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return item
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { H3Event } from 'h3';
|
||||||
|
export type SurveySetting = {
|
||||||
|
participantType?: number; // Loại thành phần tham gia
|
||||||
|
resultPublication?: number; // Nguyên tắc công bố kết quả
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Survey = {
|
||||||
|
id?: number; // Mã định danh
|
||||||
|
siteId?: number; // Mã hệ thống
|
||||||
|
title?: string; // Tiêu đề
|
||||||
|
code?: string; // Nhận diện
|
||||||
|
keywords?: string; // Từ khóa
|
||||||
|
thumbnail?: string; // Ảnh nhỏ
|
||||||
|
description?: string; // Mô tả
|
||||||
|
startTime?: string; // Bắt đầu, assuming date is handled as ISO string
|
||||||
|
endTime?: string; // Kết thúc, assuming date is handled as ISO string
|
||||||
|
type?: number; // Phân loại
|
||||||
|
settings?: SurveySetting; // Thiết lập, as a JSON string
|
||||||
|
features?: string; // Đặc trưng
|
||||||
|
taxonomy?: string; // Phân nhóm
|
||||||
|
isPublished?: boolean; // Đã xuất bản
|
||||||
|
publishedBy?: number; // Xuất bản bởi
|
||||||
|
publishedOn?: string; // Xuất bản vào lúc, assuming date is handled as ISO string
|
||||||
|
expiresOn?: string; // Đã hết hạn vào lúc, assuming date is handled as ISO string
|
||||||
|
order?: number; // Thứ tự sắp xếp
|
||||||
|
status?: number; // Trạng thái
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchById = async (event: H3Event) => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
|
const { surveyId }: any = getQuery(event)
|
||||||
|
const { item }: Survey | any = await $fetch(`${apiUrl}/cms/survey/${surveyId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
site: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return item
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
+92
-62
@@ -1,72 +1,102 @@
|
|||||||
import type { Category } from "~/server/models/category";
|
import type { Category, CategoryTree } from "~/server/models/category";
|
||||||
|
|
||||||
export const useCategoryStore = defineStore("category-v2", () => {
|
// export const useCategoryStore = defineStore("category-v2", () => {
|
||||||
const categories = ref<Category[]>([]);
|
// const categories = ref<Category[]>([]);
|
||||||
|
// const categoryTree = ref<any[]>([]);
|
||||||
|
// const currentCategoryTree = ref<any[]>([])
|
||||||
|
|
||||||
async function fetchCategories() {
|
// const findBySiteId = async () => {
|
||||||
const { data, error } = await useFetch<Category[]>("/api/v2/categories");
|
// try {
|
||||||
if (error.value) {
|
// const { data } = await useFetch(`/api/services/category-tree`)
|
||||||
return [] as Category[];
|
// categoryTree.value = data.value
|
||||||
}
|
// return categoryTree.value
|
||||||
|
// } catch (error) {}
|
||||||
|
// }
|
||||||
|
|
||||||
categories.value = Object.assign([], data.value);
|
// async function fetchCategories() {
|
||||||
|
// const { data, error } = await useFetch<Category[]>("/api/v2/categories");
|
||||||
|
// if (error.value) {
|
||||||
|
// return [] as Category[];
|
||||||
|
// }
|
||||||
|
|
||||||
return categories.value;
|
// categories.value = Object.assign([], data.value);
|
||||||
|
|
||||||
|
// return categories.value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function findByCode(code?: string) {
|
||||||
|
// if (code) return categories.value.find((c) => c.code === code);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function findById(id?: number) {
|
||||||
|
// return categories.value.find((c) => c.id === id);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function findParents(category?: Category) {
|
||||||
|
// if (!category) return [];
|
||||||
|
|
||||||
|
// const parents = [];
|
||||||
|
// let parent = findById(category.parentId);
|
||||||
|
// while (parent) {
|
||||||
|
// parents.push(parent);
|
||||||
|
// parent = findById(parent.parentId);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return parents.reverse().concat(category);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function findSubTree(category?: Category) {
|
||||||
|
// if (!category) return [];
|
||||||
|
|
||||||
|
// let subTree = [] as Category[];
|
||||||
|
|
||||||
|
// function findChildren(category: Category) {
|
||||||
|
// const children = categories.value.filter((c:Category) => c.parentId === category.id);
|
||||||
|
// if (children.length === 0) return;
|
||||||
|
|
||||||
|
// subTree.push(...children,category);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if(category.parentId === 41){
|
||||||
|
// findChildren(category);
|
||||||
|
// }else{
|
||||||
|
// const parent = findById(category.parentId);
|
||||||
|
// if(parent){
|
||||||
|
// findChildren(parent);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return subTree.reverse();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function findChildren(category: Category) {
|
||||||
|
// const children = categories.value.filter((c:Category) => c.parentId === category.id);
|
||||||
|
// if (children.length === 0) return;
|
||||||
|
// else return [...children]
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// return { categories, categoryTree, currentCategoryTree, findBySiteId, fetchCategories, findByCode, findById, findParents,findSubTree, findChildren };
|
||||||
|
// });
|
||||||
|
|
||||||
|
export const useCategoryStore = defineStore('usecategorystore', () => {
|
||||||
|
const categoryTree = shallowRef<CategoryTree[]>([])
|
||||||
|
const currentCategoryTree = shallowRef<any[]>([])
|
||||||
|
|
||||||
|
async function fetchBySiteId() {
|
||||||
|
const { data }: any = await useFetch(`/api/services/category-tree`)
|
||||||
|
categoryTree.value = data.value.items
|
||||||
|
return categoryTree.value
|
||||||
}
|
}
|
||||||
|
|
||||||
function findByCode(code?: string) {
|
return {
|
||||||
if (code) return categories.value.find((c) => c.code === code);
|
categoryTree,
|
||||||
|
currentCategoryTree,
|
||||||
|
|
||||||
|
fetchBySiteId
|
||||||
}
|
}
|
||||||
|
})
|
||||||
function findById(id?: number) {
|
|
||||||
return categories.value.find((c) => c.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function findParents(category?: Category) {
|
|
||||||
if (!category) return [];
|
|
||||||
|
|
||||||
const parents = [];
|
|
||||||
let parent = findById(category.parentId);
|
|
||||||
while (parent) {
|
|
||||||
parents.push(parent);
|
|
||||||
parent = findById(parent.parentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parents.reverse().concat(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
function findSubTree(category?: Category) {
|
|
||||||
if (!category) return [];
|
|
||||||
|
|
||||||
let subTree = [] as Category[];
|
|
||||||
|
|
||||||
function findChildren(category: Category) {
|
|
||||||
const children = categories.value.filter((c:Category) => c.parentId === category.id);
|
|
||||||
if (children.length === 0) return;
|
|
||||||
|
|
||||||
subTree.push(...children,category);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(category.parentId === 41){
|
|
||||||
findChildren(category);
|
|
||||||
}else{
|
|
||||||
const parent = findById(category.parentId);
|
|
||||||
if(parent){
|
|
||||||
findChildren(parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return subTree.reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
function findChildren(category: Category) {
|
|
||||||
const children = categories.value.filter((c:Category) => c.parentId === category.id);
|
|
||||||
if (children.length === 0) return;
|
|
||||||
else return [...children]
|
|
||||||
}
|
|
||||||
|
|
||||||
return { categories, fetchCategories, findByCode, findById, findParents,findSubTree, findChildren };
|
|
||||||
});
|
|
||||||
|
|
||||||
if (import.meta.hot) {
|
if (import.meta.hot) {
|
||||||
import.meta.hot.accept(acceptHMRUpdate(useCategoryStore, import.meta.hot));
|
import.meta.hot.accept(acceptHMRUpdate(useCategoryStore, import.meta.hot));
|
||||||
|
|||||||
+863
-15
@@ -10,6 +10,866 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
|
|||||||
async function fetchPageByCode(slug: any) {
|
async function fetchPageByCode(slug: any) {
|
||||||
try {
|
try {
|
||||||
const { data } = await useFetch(`/api/dynamic-page/get-by-code/${slug}`)
|
const { data } = await useFetch(`/api/dynamic-page/get-by-code/${slug}`)
|
||||||
|
// const data = ref({
|
||||||
|
// "sections": [
|
||||||
|
// {
|
||||||
|
// "id": 42,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section5hang",
|
||||||
|
// "slug": "section5hang",
|
||||||
|
// "code": "section5hang",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": "[{\"type\":\"component\",\"data\":57},{\"type\":\"component\",\"data\":68},{\"type\":\"component\",\"data\":69},{\"type\":\"component\",\"data\":44},{\"type\":\"component\",\"data\":50}]",
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:horizontal-TYPE:Default-MAX:5",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T16:17:57.386059",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:18:56.082485"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 32,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section2hang",
|
||||||
|
// "slug": "section2hang",
|
||||||
|
// "code": "section2hang_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": "[{\"type\":\"component\",\"data\":58},{\"type\":\"component\",\"data\":101}]",
|
||||||
|
// "keywords": null,
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:horizontal-TYPE:Default-MAX:2",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T10:33:59.071404",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:18:56.493553"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 31,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section2left3",
|
||||||
|
// "slug": "section2left3",
|
||||||
|
// "code": "section2left3_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": "[{\"type\":\"section\",\"data\":42},{\"type\":\"section\",\"data\":32}]",
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical-TYPE:LEFT-MAX:2",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": "",
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:02:35.828188",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T09:36:43.623068"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 30,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section2left2",
|
||||||
|
// "slug": "section2left2",
|
||||||
|
// "code": "section2left2_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical-TYPE:LEFT-MAX:2",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": "",
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:02:09.626405",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T09:37:17.837094"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 29,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section2left1",
|
||||||
|
// "slug": "section2left1",
|
||||||
|
// "code": "section2left1_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical-TYPE:LEFT-MAX:2",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": "",
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:01:11.78265",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T09:01:40.494573"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 28,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section3cot",
|
||||||
|
// "slug": "section3cot",
|
||||||
|
// "code": "section3cot_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical-TYPE:Default-MAX:3",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": "",
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:00:32.765855",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T09:37:50.127734"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 27,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section2left",
|
||||||
|
// "slug": "section2left",
|
||||||
|
// "code": "section2left_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical-TYPE:LEFT-MAX:2",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": "",
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:00:05.873579",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T09:38:06.600079"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 26,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section3hang",
|
||||||
|
// "slug": "section3hang",
|
||||||
|
// "code": "section3hang_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": null,
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:horizontal-TYPE:Default-MAX:3",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T08:59:19.411836",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T09:38:29.410238"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 25,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section1hang1",
|
||||||
|
// "slug": "section1hang1",
|
||||||
|
// "code": "section1hang1_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": "",
|
||||||
|
// "keywords": null,
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:horizontal-TYPE:Default-MAX:1",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T08:53:59.364384",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T08:57:34.1155"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 24,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "section1hang",
|
||||||
|
// "slug": "section1hang",
|
||||||
|
// "code": "section1hang_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": null,
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:horizontal-TYPE:Default-MAX:1",
|
||||||
|
// "template": "Article",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T08:53:52.871306",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T09:39:00.332127"
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// "components": [
|
||||||
|
// {
|
||||||
|
// "id": 101,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "ads2_doisong",
|
||||||
|
// "code": "ads2_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "ADS_DEFAULT",
|
||||||
|
// "template": "Other",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-06-04T15:44:49.728501",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-06-04T15:45:02.192997"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 69,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "coppy_link_2",
|
||||||
|
// "code": "coppy_link_2",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "ARTICLE_BUTTON",
|
||||||
|
// "template": "Other",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T15:51:28.699877",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:00.334897"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 68,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "article_detail_1",
|
||||||
|
// "code": "article_detail_1",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "ARTICLE_DETAIL_DEFAULT",
|
||||||
|
// "template": "Other",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T15:37:58.099224",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:00.742949"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 62,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "coppy_link_1",
|
||||||
|
// "code": "coppy_link_1",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "ARTICLE_DETAIL_DEFAULT",
|
||||||
|
// "template": "Other",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": -1,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T15:24:08.987936",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T15:25:38.566902"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 58,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "ads_1",
|
||||||
|
// "code": "ads_1",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "ADS_DEFAULT",
|
||||||
|
// "template": "Other",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T15:09:08.953513",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:01.56169"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 57,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "breadcrumb_1",
|
||||||
|
// "code": "breadcrumb_1",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "BREADCRUM_DEFAULT",
|
||||||
|
// "template": "Other",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T15:01:25.190114",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:01.972624"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 50,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "comment",
|
||||||
|
// "code": "comment_default1",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "COMMENT",
|
||||||
|
// "template": "Other",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T11:37:42.957585",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T11:38:23.481239"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 47,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "collection_paging",
|
||||||
|
// "code": "collection_paging_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "DEFAULT",
|
||||||
|
// "template": "Section",
|
||||||
|
// "dataQuery": "Get[Article] Top[10] With[Categories:81]",
|
||||||
|
// "dataResult": "[]",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:49:48.945226",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:02.788055"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 44,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "collection5item2",
|
||||||
|
// "code": "collection5item2_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "TYPE:Article-LAYOUT:vertical-DATA:HORIZONTAL-MAX:5",
|
||||||
|
// "template": "Collection",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": true,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:18:53.361283",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:03.20532"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 43,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "article_doc",
|
||||||
|
// "code": "article_doc_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical",
|
||||||
|
// "template": "Article",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:18:26.503605",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:03.613773"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 42,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "collection5item",
|
||||||
|
// "code": "collection5item_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "TYPE:Article-LAYOUT:vertical-DATA:HORIZONTAL-MAX:5",
|
||||||
|
// "template": "Collection",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:17:57.798722",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:04.026497"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 41,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "article_doc_intro3",
|
||||||
|
// "code": "article_doc_intro3_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical-HIDE:paragraph",
|
||||||
|
// "template": "Article",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:17:21.675354",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:04.431454"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 40,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "article_doc_intro2",
|
||||||
|
// "code": "article_doc_intro2_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical-HIDE:paragraph",
|
||||||
|
// "template": "Article",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:16:56.07848",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:04.842294"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 39,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "article_doc_intro1",
|
||||||
|
// "code": "article_doc_intro1_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:vertical-HIDE:paragraph",
|
||||||
|
// "template": "Article",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:16:39.074945",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:05.246938"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 38,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "article_ngang",
|
||||||
|
// "code": "article_ngang_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "LAYOUT:horizontal",
|
||||||
|
// "template": "Article",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:15:38.638781",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:05.664736"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 37,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "pageId": 4,
|
||||||
|
// "sectionId": null,
|
||||||
|
// "title": "category",
|
||||||
|
// "code": "category_doisong",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "keywords": "",
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "DEFAULT",
|
||||||
|
// "template": "Category",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": "",
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": null,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T09:14:11.978206",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:19:06.0724"
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// "id": 4,
|
||||||
|
// "siteId": 1,
|
||||||
|
// "parentId": null,
|
||||||
|
// "title": "Trang đời sống",
|
||||||
|
// "slug": "trang-doi-song",
|
||||||
|
// "code": "page-doi-song",
|
||||||
|
// "type": 1,
|
||||||
|
// "content": null,
|
||||||
|
// "favicon": null,
|
||||||
|
// "keywords": null,
|
||||||
|
// "thumbnail": null,
|
||||||
|
// "settings": {
|
||||||
|
// "label": "",
|
||||||
|
// "layout": "Center_Page",
|
||||||
|
// "template": "Home",
|
||||||
|
// "dataQuery": null,
|
||||||
|
// "dataResult": null,
|
||||||
|
// "pinned": null
|
||||||
|
// },
|
||||||
|
// "features": "Navigation",
|
||||||
|
// "taxonomy": "Navigation",
|
||||||
|
// "description": null,
|
||||||
|
// "isPublished": false,
|
||||||
|
// "publishedBy": null,
|
||||||
|
// "publishedOn": null,
|
||||||
|
// "expiresOn": null,
|
||||||
|
// "order": 0,
|
||||||
|
// "status": 6,
|
||||||
|
// "createdBy": 1,
|
||||||
|
// "createdOn": "2024-05-30T08:42:10.319911",
|
||||||
|
// "updatedBy": 1,
|
||||||
|
// "updatedOn": "2024-05-30T16:18:55.254121"
|
||||||
|
// })
|
||||||
currentPage.value = {}
|
currentPage.value = {}
|
||||||
currentPage.value = data.value
|
currentPage.value = data.value
|
||||||
} catch (error: any) {}
|
} catch (error: any) {}
|
||||||
@@ -35,6 +895,8 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
|
|||||||
(section: any) => section.isPublished && !contentArr.flat().some((_section: any) => _section && _section.data && _section.type === "section" && section.id === _section.data)
|
(section: any) => section.isPublished && !contentArr.flat().some((_section: any) => _section && _section.data && _section.type === "section" && section.id === _section.data)
|
||||||
).sort((a: any, b: any) => a.order - b.order);
|
).sort((a: any, b: any) => a.order - b.order);
|
||||||
|
|
||||||
|
console.log(sectionPublished.value, 'section');
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const setComponentPublished = () => {
|
const setComponentPublished = () => {
|
||||||
@@ -44,7 +906,7 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
|
|||||||
return section;
|
return section;
|
||||||
});
|
});
|
||||||
componentPublished.value = currentPage.value.components && currentPage.value.components.filter((section: any) => section.isPublished);
|
componentPublished.value = currentPage.value.components && currentPage.value.components.filter((section: any) => section.isPublished);
|
||||||
|
console.log(componentPublished.value ,'123123')
|
||||||
};
|
};
|
||||||
|
|
||||||
const setDataQuery = (query: any, componentId: number | string) => {
|
const setDataQuery = (query: any, componentId: number | string) => {
|
||||||
@@ -63,30 +925,16 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
|
|||||||
setComponentPublished();
|
setComponentPublished();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function increaseStep(increase: number) {
|
|
||||||
step.value += increase
|
|
||||||
return step.value
|
|
||||||
}
|
|
||||||
|
|
||||||
function decreaseStep(decrease: number) {
|
|
||||||
step.value -= decrease
|
|
||||||
return step.value
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
currentPage,
|
currentPage,
|
||||||
sectionPublished,
|
sectionPublished,
|
||||||
componentPublished,
|
componentPublished,
|
||||||
step,
|
|
||||||
|
|
||||||
fetchPageByCode,
|
fetchPageByCode,
|
||||||
fetchPageById,
|
fetchPageById,
|
||||||
setSectionPublished,
|
setSectionPublished,
|
||||||
setComponentPublished,
|
setComponentPublished,
|
||||||
setDataQuery,
|
setDataQuery,
|
||||||
|
|
||||||
increaseStep,
|
|
||||||
decreaseStep,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+17
-12
@@ -1,20 +1,25 @@
|
|||||||
export const usePollOptionStore = defineStore('usepollOptionStore', () => {
|
import type { PollOption } from "~/server/models/poll-option"
|
||||||
|
export const usePollOptionStore = defineStore('usePollOptionStore', () => {
|
||||||
|
const currentPollOption = shallowReactive<PollOption>({})
|
||||||
|
const currentPollOptions = shallowRef<PollOption[] | any[]>([])
|
||||||
async function fetchByPollId(id: string) {
|
async function fetchByPollId(id: string) {
|
||||||
const { data, error } = await useFetch<any>(`/api/services/poll-option/pollId`, {
|
try {
|
||||||
query: {
|
const { data } = await useFetch<any>(`/api/services/poll-option/pollId`, {
|
||||||
pollId: id
|
query: {
|
||||||
}
|
pollId: id
|
||||||
})
|
}
|
||||||
if(error.value) {
|
})
|
||||||
return null
|
|
||||||
}
|
data.value && (currentPollOptions.value = data.value)
|
||||||
|
return currentPollOptions.value
|
||||||
|
} catch(error) {}
|
||||||
|
|
||||||
|
|
||||||
return data.value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { fetchByPollId }
|
return { currentPollOptions, fetchByPollId }
|
||||||
})
|
})
|
||||||
|
|
||||||
if(import.meta.hot) {
|
if(import.meta.hot) {
|
||||||
import.meta.hot.accept(acceptHMRUpdate(useTagStore, import.meta.hot))
|
import.meta.hot.accept(acceptHMRUpdate(usePollOptionStore, import.meta.hot))
|
||||||
}
|
}
|
||||||
+33
-12
@@ -1,19 +1,40 @@
|
|||||||
export const usePollResponseStore = defineStore('usepollResponseStore', () => {
|
import type { PollResponse } from "~/server/models/poll-response"
|
||||||
async function create(pollResponse: any) {
|
export const usePollResponseStore = defineStore('usePollResponseStore', () => {
|
||||||
const { data, error } = await useFetch<any>(`/api/services/poll-response`, {
|
const currentPollResponse = shallowReactive<PollResponse>({})
|
||||||
method: 'POST',
|
const currentPollResponses = shallowRef<PollResponse[]>([])
|
||||||
body: pollResponse
|
const create = async (pollResponse: any) => {
|
||||||
})
|
|
||||||
if(error.value) {
|
try {
|
||||||
return null
|
const { data } = await useFetch<any>(`/api/services/poll-response`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: pollResponse
|
||||||
|
})
|
||||||
|
data.value && (Object.assign(currentPollResponse, data.value))
|
||||||
|
return currentPollResponse
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { create }
|
async function fetchByPollId(id: string) {
|
||||||
|
try {
|
||||||
|
const { data } = await useFetch<any>(`/api/services/poll-response/pollId`, {
|
||||||
|
query: {
|
||||||
|
pollId: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
data.value && (currentPollResponses.value = data.value)
|
||||||
|
return currentPollResponses.value
|
||||||
|
} catch (error) { }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return { currentPollResponse, currentPollResponses, create, fetchByPollId }
|
||||||
})
|
})
|
||||||
|
|
||||||
if(import.meta.hot) {
|
if (import.meta.hot) {
|
||||||
import.meta.hot.accept(acceptHMRUpdate(useTagStore, import.meta.hot))
|
import.meta.hot.accept(acceptHMRUpdate(usePollResponseStore, import.meta.hot))
|
||||||
}
|
}
|
||||||
+25
-12
@@ -1,20 +1,33 @@
|
|||||||
export const usePollStore = defineStore('usepollStore', () => {
|
import type { Poll } from "~/server/models/poll"
|
||||||
|
export const usePollStore = defineStore('usePollStore', () => {
|
||||||
|
const currentPoll = shallowReactive<Poll>({})
|
||||||
async function fetchById(id: string) {
|
async function fetchById(id: string) {
|
||||||
const { data, error } = await useFetch<any>(`/api/services/poll-by-id`, {
|
|
||||||
query: {
|
|
||||||
pollId: id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if(error.value) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.value
|
try {
|
||||||
|
const { data } = await useFetch<any>(`/api/services/poll-by-id`, {
|
||||||
|
query: {
|
||||||
|
pollId: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
data.value && (Object.assign(currentPoll, data.value))
|
||||||
|
return currentPoll
|
||||||
|
} catch(error) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { fetchById }
|
async function categoryId() {
|
||||||
|
try {
|
||||||
|
const { data } = await useFetch(`/api/services/category-tree`)
|
||||||
|
return data.value
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fetchById, currentPoll, categoryId }
|
||||||
})
|
})
|
||||||
|
|
||||||
if(import.meta.hot) {
|
if(import.meta.hot) {
|
||||||
import.meta.hot.accept(acceptHMRUpdate(useTagStore, import.meta.hot))
|
import.meta.hot.accept(acceptHMRUpdate(usePollStore, import.meta.hot))
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import type { Quiz } from '~/server/models/quiz';
|
||||||
|
export const useQuizStore = defineStore('useQuizStore', () => {
|
||||||
|
const currentQuiz = shallowReactive<Quiz>({})
|
||||||
|
async function fetchById(id: number) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data } = await useFetch<any>(`/api/services/quiz/get-by-id`, {
|
||||||
|
query: {
|
||||||
|
quizId: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
data.value && (Object.assign(currentQuiz, data.value))
|
||||||
|
return currentQuiz
|
||||||
|
} catch(error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fetchById, currentQuiz }
|
||||||
|
})
|
||||||
|
|
||||||
|
if(import.meta.hot) {
|
||||||
|
import.meta.hot.accept(acceptHMRUpdate(useQuizStore, import.meta.hot))
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import type { Survey } from '~/server/models/survey';
|
||||||
|
export const useSurveyStore = defineStore('useSurveyStore', () => {
|
||||||
|
const currentSurvey = shallowReactive<Survey>({})
|
||||||
|
async function fetchById(id: number) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data } = await useFetch<any>(`/api/services/survey/get-by-id`, {
|
||||||
|
query: {
|
||||||
|
surveyId: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
data.value && (Object.assign(currentSurvey, data.value))
|
||||||
|
return currentSurvey
|
||||||
|
} catch(error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fetchById, currentSurvey }
|
||||||
|
})
|
||||||
|
|
||||||
|
if(import.meta.hot) {
|
||||||
|
import.meta.hot.accept(acceptHMRUpdate(useSurveyStore, import.meta.hot))
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ export default defineConfig({
|
|||||||
"after:no-content": "after:content-['']",
|
"after:no-content": "after:content-['']",
|
||||||
"before:no-content": "before:content-['']",
|
"before:no-content": "before:content-['']",
|
||||||
'container-xxl': 'px-[8px] mx-auto w-full sm:w-620px md:w-760px lg:w-980px xl:w-1100px 2xl:w-1200px',
|
'container-xxl': 'px-[8px] mx-auto w-full sm:w-620px md:w-760px lg:w-980px xl:w-1100px 2xl:w-1200px',
|
||||||
|
'container-long': 'px-2 mx-auto w-full sm:w-620px md:w-760px lg:w-980px xl:w-1100px 2xl:w-1200px'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
rules: [
|
rules: [
|
||||||
|
|||||||
Reference in New Issue
Block a user