thainv-dev: tạo lại cấu trúc folder và làm UI

This commit is contained in:
nguyen van thai
2024-06-12 17:17:49 +07:00
parent c217ed82c9
commit 5b1e0af397
44 changed files with 2674 additions and 228 deletions
+4 -4
View File
@@ -2,10 +2,10 @@
body
font-family: 'Nunito', sans-serif
video
max-width: 100% !important
width: unset !important
height: unset !important
// video
// max-width: 100% !important
// width: unset !important
// height: unset !important
iframe
width: 100% !important
+4 -8
View File
@@ -20,17 +20,13 @@ figure {
@apply w-full;
}
& a {
@apply text-primary-600 underline;
}
& document {
@apply cursor-pointer text-primary-600 underline;
& document, & a, & custom-figure, & author {
@apply cursor-pointer text-primary-600;
}
}
div[layout="ARTICLE_DETAIL_EMAGAZINE"] {
& p,& figure.align-center-image, & #sub, & #title, & #intro {
div[layout="TYPE:Detail-LAYOUT:image"] {
& p,& figure.align-center-image, & #sub, & #title, & #intro, & #breakcrumb, & #navigation__bottom {
@apply lg:max-w-640px mx-auto;
}
}
+74 -20
View File
@@ -1,22 +1,79 @@
<script setup lang="ts">
import { usePollStore } from '~/stores/poll'
import { usePollOptionStore } from '~/stores/poll-option'
import type { Poll } from '~/server/models/poll';
import { usePollStore } from "~/stores/poll";
import { usePollOptionStore } from "~/stores/poll-option";
import { usePollResponseStore } from "~/stores/poll-response";
import type { Poll } from "~/server/models/poll";
import type { PollResponse } from "~/server/models/poll-response";
import type { PollOption } from "~/server/models/poll-option";
const props = defineProps<{ dataId?: string }>();
const store = reactive({
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))))
const options = ref<any []>(await store.pollOptions.fetchByPollId((String(props.dataId))))
function assignData() {
Object.assign(poll, currentPoll.value);
options.value = currentPollOptions.value;
}
onBeforeMount(async () => {
await loadData();
});
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 () {
console.log(selectedOption, 'id')
async function submitVote() {
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>
<template>
<span class="inline-block px-4 py-2 shadow-xl rounded-lg bg-[#f5f5f5]">
@@ -24,33 +81,30 @@ function submitVote () {
<span class="underline decoration-gray-500 font-bold">
{{ poll?.title }}
</span>
<!-- <button v-if="showResult && canShowResult" type="button" class="underline text-blue-400" @click="toggleResults">
Câu hỏi
</button>
<button class="underline text-blue-400" v-if="!showResult && canShowResult" type="button" @click="toggleResults">
Kết quả
</button> -->
<button v-if="showResult && canShowResult" type="button" class="underline text-blue-400" @click="toggleResults">Câu hỏi</button>
<button class="underline text-blue-400" v-if="!showResult && canShowResult" type="button" @click="toggleResults">Kết quả</button>
</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">
<label class="flex gap-2 m-2">
<input type="radio" :value="option.id" v-model="selectedOption" />
<span class="font-semibold">{{ option?.title }}</span>
</label>
</span>
<button @click="submitVote" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Bình chọn </button>
<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 v-else class="block">
<span v-for="(answer, index) in options" :key="index" class="block poll-result relative rounded-3xl overflow-hidden my-3">
<span v-else class="block">
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"
:style="{ width: `${calculatePercentage(answer?.voteCount)}%` }"></span>
<span class="block relative z-0 ps-1">
<span>{{ calculatePercentage(answer?.voteCount).toFixed(2) }}%</span>
<span class="">({{ answer?.voteCount }})</span>
</span>
</span>
</span> -->
</span>
</span>
</template>
+305 -1
View File
@@ -1,6 +1,310 @@
<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>
<template>
quiz
<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">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>
+294 -1
View File
@@ -1,6 +1,299 @@
<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>
<template>
Survey
<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>
@@ -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
export { default as Article_BasicCard } from './articles/individuals/Card.vue'
export { default as Article_BasicCollection } from './articles/collections/BasicCollection.vue'
// Category
@@ -8,3 +9,7 @@ export { default as CollectionPaging } from './pageCategories/collection_page.vu
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>
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<{
settings: any;
component?: any;
}>();
const definedDynamicComponent: Record<string, any> = {
[enumPageComponentTemplates.ARTICLE]: Article_BasicCard,
[enumPageComponentTemplates.ARTICLE]: Dynamic_Article,
[enumPageComponentTemplates.CATEGORY]: BasicCategories,
[enumPageComponentTemplates.COLLECTION]: Article_BasicCollection,
[enumPageComponentTemplates.COLLECTION]: Dynamic_Collection,
[enumPageComponentTemplates.SECTION]: CollectionPaging,
[enumPageComponentTemplates.OTHER]: Dynamic_Other
[enumPageComponentTemplates.OTHER]: Dynamic_Other,
[enumPageComponentTemplates.ADVERTISING]: Dynamic_Advertising
};
const getCurrentComponent = computed(() => `${_props.settings.template}`);
const GET_PROPS = computed(() => {
return () => {
let props: any = {};
@@ -1,38 +1,73 @@
<script setup lang="ts">
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')) {
localStorage.setItem('step', '0')
}
useDynamicPageStore().step = Number(localStorage.getItem('step')) ?? 0
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() {
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 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(() => {
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')
}
console.log('b')
})
</script>
<template>
<div class="flex justify-between items-center my-3">
<ul class="flex gap-6 items-center text-md">
<li class="first:text-primary-600 font-semibold">
<nuxt-link to="/">Trang chủ</nuxt-link>
<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">
@@ -47,12 +82,9 @@ onMounted(() => {
</div>
</div>
</template>
<style lang="scss" scoped>
.empty {
border-radius: 6px;
background: #409eff;
width: 40px;
min-height: 20px;
<style lang="scss">
:root {
--step: 0;
}
@@ -1,4 +1,10 @@
<script setup lang="ts">
import { useCategoryStore } from '@/stores/category';
const store = {
category: useCategoryStore()
}
const { currentCategoryTree } = storeToRefs(store.category)
const isBookmark = ref(false)
const onClickBookmark = () => {
isBookmark.value = !isBookmark.value
@@ -14,11 +20,12 @@ async function copyLink() {
}
}
</script>
<template>
<div class="py-5 flex flex-wrap justify-between 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" />
</nuxt-link>
<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 Tag from '@/components/article/immerse/Tag.vue'
import Articlerelation from '~/components/article/immerse/ArticleRelation.vue'
const { currentArticle } = storeToRefs(useArticleStore());
const { step } = storeToRefs(useDynamicPageStore());
import * as cherrio from 'cheerio'
const $ = cherrio.load(currentArticle.value.detail)
// console.log($, 'cherrip')
const router = useRouter()
// 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 () => {
// 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(() => {
// const documentElements = document.querySelectorAll('document, attachment')
@@ -50,15 +90,24 @@ const $ = cherrio.load(currentArticle.value.detail)
</script>
<template>
<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>
<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>
<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>
<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="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, Document, Attachment, Tag} }" />
<!-- <component :is="{template: currentArticle.detail, components: { Poll, Quiz, Survey, Document, Attachment, Tag} }" /> -->
<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>
</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>
@@ -15,7 +15,7 @@ const definedDynamicComponent: Record<string, any> = {
'ARTICLE_DETAIL_EMAGAZINE': Article_Detail_Emagazine,
'ADS_DEFAULT': ADS_Default,
'ARTICLE_BUTTON': Article_Button,
COMMENT: Comment,
'COMMENT_DEFAULT': Comment,
PODCAST: Article_Detail_Podcast,
VIDEO: Article_Detail_Video
};
@@ -37,7 +37,7 @@ const CLASS_FOR_LAYOUT = computed(() => {
<template>
<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 />
</div>
</div>
@@ -3,7 +3,7 @@
<template>
<div class="page_container full-size-page">
<div class="layout_container center-layout grid-container">
<div class="container-long my-5">
<slot />
</div>
</div>
+5
View File
@@ -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 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: "mặc định", value: enumPageComponentLayouts[enumPageComponentTemplates.ARTICLE]['DEFAULT'] },
],
[`${enumPageComponentTemplates.CATEGORY}`]: [
{ title: "Danh mục", value: enumPageComponentLayouts[enumPageComponentTemplates.CATEGORY]['DEFAULT'] }
],
[`${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 Mặc định", value: enumPageComponentLayouts[enumPageComponentTemplates.COLLECTION]['DEFAULT'] },
],
[`${enumPageComponentTemplates.ADVERTISING}`]: [
{ title: "Quảng cáo mặc định", value: enumPageComponentLayouts[enumPageComponentTemplates.ADVERTISING]['DEFAULT'] },
]
};
+4
View File
@@ -131,6 +131,7 @@ export const enumPageComponentLayouts = {
'VERTICAL-HIDE_THUMBNAIL': "LAYOUT:vertical-HIDE:thumbnail",
'VERTICAL-HIDE_PARAGRAPH': "LAYOUT:vertical-HIDE:paragraph",
'VERTICAL-HIDE_PARAGRAPH-REVERSE': "LAYOUT:vertical-HIDE:paragraph-REVERSE:true",
"DEFAULT": "TYPE:Detail-LAYOUT:default"
},
[`${enumPageComponentTemplates.CATEGORY}`]: {
NONE: "None",
@@ -141,6 +142,9 @@ export const enumPageComponentLayouts = {
},
[`${enumPageComponentTemplates.OTHER}`]: {
'"ARTICLE_BUTTON"': '"ARTICLE_BUTTON"'
},
[`${enumPageComponentTemplates.ADVERTISING}`]: {
'DEFAULT': 'DEFAULT'
}
};
+7 -14
View File
@@ -40,35 +40,31 @@ watch(currentArticle, async () => {
let isContentType : string = '';
switch (currentArticle.value?.contentType) {
case 1:
isContentType = 'trang-doi-song'
isContentType = 'trang-chi-tiet-bai-viet-general'
break;
case 2:
isContentType = 'ArticleLayoutImage'
isContentType = 'trang-chi-tiet-bai-viet-image'
break;
case 3:
isContentType = 'trang-chi-tiet-podcast'
isContentType = 'trang-chi-tiet-bai-viet-postcart'
break;
case 4:
isContentType = 'trang-chi-tiet-video-clip'
isContentType = 'trang-chi-tiet-bai-viet-video'
break;
case 5:
if (currentArticle.value?.layoutType === 4) {
isContentType = 'trang-chi-tiet-emagazine'
isContentType = 'trang-chi-tiet-bai-viet-emagazine'
break;
}
if (currentArticle.value?.layoutType === 3) {
isContentType = 'trang-chi-tiet-infographics'
isContentType = 'trang-chi-tiet-bai-viet-infographics'
break;
}
// else {
// isContentType = 'trang-chi-tiet-emagazine'
// break;
// }
default:
isContentType = 'trang-chi-tiet-emagazine'
isContentType = 'trang-chi-tiet-bai-viet-general'
break;
}
await loadPage(isContentType);
@@ -83,9 +79,6 @@ useSeoMeta({
twitterCard: 'summary_large_image',
})
onMounted(() => {
console.log(document.querySelectorAll('document'), '12')
})
</script>
<template>
+7
View File
@@ -6,6 +6,9 @@ import * as topicCtrl from '~/server/models/topic'
import * as pollCtrl from '~/server/models/poll'
import * as pollOptionCtrl from '~/server/models/poll-option'
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()
@@ -16,4 +19,8 @@ router.get('/event', defineEventHandler(eventCtrl.fetchById))
router.get('/poll-by-id', defineEventHandler(pollCtrl.fetchById))
router.get('/poll-option/pollId', defineEventHandler(pollOptionCtrl.fetchByPollId))
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)
+8 -6
View File
@@ -24,20 +24,22 @@ export type Category = {
status: number;
} & Base;
export type CategoryTree = Category & {
children?: Category[]
}
export const list = async () => {
console.log('vào category service')
try {
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",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
site: site,
site: 1,
},
});
return items;
return { items } ;
} catch (error) {
handleError(error);
}
+14 -2
View File
@@ -1,13 +1,25 @@
import { H3Event } from 'h3';
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) => {
try {
const { apiUrl } = useRuntimeConfig().public
const { pollId}: any = getQuery(event)
const { items }: any = await $fetch(`${apiUrl}/cms/poll-option/poll:${pollId}`, {
const { pollId }: any = getQuery(event)
const { items }: PollOption[] | any = await $fetch(`${apiUrl}/cms/poll-option/poll:${pollId}`, {
method: 'GET',
headers: {
site: 1
+31 -5
View File
@@ -1,8 +1,17 @@
import { H3Event } from 'h3';
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 {
const { apiUrl } = useRuntimeConfig().public
const payload = await readBody<any>(event)
@@ -11,14 +20,31 @@ import Base from './base'
headers: {
site: 1
},
body: {
payload
}
body: payload
})
console.log(payload, 'payload')
return item
} catch (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);
}
}
+7 -3
View File
@@ -1,6 +1,11 @@
import { H3Event } from 'h3';
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 = {
id?: number; // Mã định danh
siteId?: number; // Mã hệ thống
@@ -12,7 +17,7 @@ export type Poll = {
startTime?: string; // Bắt đầu (string)
endTime?: string; // Kết thúc (string)
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)
taxonomy?: string; // Phân nhóm
isPublished?: boolean; // Đã xuất bản
@@ -25,10 +30,9 @@ export type Poll = {
export const fetchById = async (event: H3Event) => {
try {
const { apiUrl } = useRuntimeConfig().public
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',
headers: {
site: 1
+46
View File
@@ -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);
}
}
+46
View File
@@ -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);
}
}
+93 -63
View File
@@ -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", () => {
const categories = ref<Category[]>([]);
// export const useCategoryStore = defineStore("category-v2", () => {
// const categories = ref<Category[]>([]);
// const categoryTree = ref<any[]>([]);
// const currentCategoryTree = ref<any[]>([])
async function fetchCategories() {
const { data, error } = await useFetch<Category[]>("/api/v2/categories");
if (error.value) {
return [] as Category[];
// const findBySiteId = async () => {
// try {
// const { data } = await useFetch(`/api/services/category-tree`)
// categoryTree.value = data.value
// return categoryTree.value
// } catch (error) {}
// }
// async function fetchCategories() {
// const { data, error } = await useFetch<Category[]>("/api/v2/categories");
// if (error.value) {
// return [] as Category[];
// }
// 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
}
categories.value = Object.assign([], data.value);
return {
categoryTree,
currentCategoryTree,
return categories.value;
fetchBySiteId
}
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, fetchCategories, findByCode, findById, findParents,findSubTree, findChildren };
});
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useCategoryStore, import.meta.hot));
+863 -15
View File
@@ -10,6 +10,866 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
async function fetchPageByCode(slug: any) {
try {
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 = data.value
} 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)
).sort((a: any, b: any) => a.order - b.order);
console.log(sectionPublished.value, 'section');
};
const setComponentPublished = () => {
@@ -44,7 +906,7 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
return section;
});
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) => {
@@ -63,30 +925,16 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
setComponentPublished();
};
function increaseStep(increase: number) {
step.value += increase
return step.value
}
function decreaseStep(decrease: number) {
step.value -= decrease
return step.value
}
return {
currentPage,
sectionPublished,
componentPublished,
step,
fetchPageByCode,
fetchPageById,
setSectionPublished,
setComponentPublished,
setDataQuery,
increaseStep,
decreaseStep,
};
});
+14 -9
View File
@@ -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) {
const { data, error } = await useFetch<any>(`/api/services/poll-option/pollId`, {
try {
const { data } = await useFetch<any>(`/api/services/poll-option/pollId`, {
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) {
import.meta.hot.accept(acceptHMRUpdate(useTagStore, import.meta.hot))
import.meta.hot.accept(acceptHMRUpdate(usePollOptionStore, import.meta.hot))
}
+30 -9
View File
@@ -1,19 +1,40 @@
export const usePollResponseStore = defineStore('usepollResponseStore', () => {
async function create(pollResponse: any) {
const { data, error } = await useFetch<any>(`/api/services/poll-response`, {
import type { PollResponse } from "~/server/models/poll-response"
export const usePollResponseStore = defineStore('usePollResponseStore', () => {
const currentPollResponse = shallowReactive<PollResponse>({})
const currentPollResponses = shallowRef<PollResponse[]>([])
const create = async (pollResponse: any) => {
try {
const { data } = await useFetch<any>(`/api/services/poll-response`, {
method: 'POST',
body: pollResponse
})
if(error.value) {
return null
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) {
import.meta.hot.accept(acceptHMRUpdate(useTagStore, import.meta.hot))
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(usePollResponseStore, import.meta.hot))
}
+19 -6
View File
@@ -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) {
const { data, error } = await useFetch<any>(`/api/services/poll-by-id`, {
try {
const { data } = await useFetch<any>(`/api/services/poll-by-id`, {
query: {
pollId: id
}
})
if(error.value) {
return null
data.value && (Object.assign(currentPoll, data.value))
return currentPoll
} catch(error) {
}
}
async function categoryId() {
try {
const { data } = await useFetch(`/api/services/category-tree`)
return data.value
} catch (error) {}
}
return { fetchById }
return { fetchById, currentPoll, categoryId }
})
if(import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useTagStore, import.meta.hot))
import.meta.hot.accept(acceptHMRUpdate(usePollStore, import.meta.hot))
}
+24
View File
@@ -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))
}
+24
View File
@@ -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))
}
+1
View File
@@ -40,6 +40,7 @@ export default defineConfig({
"after:no-content": "after: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-long': 'px-2 mx-auto w-full sm:w-620px md:w-760px lg:w-980px xl:w-1100px 2xl:w-1200px'
},
],
rules: [