Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 059ab5463c | |||
| 7a92ca829f | |||
| a7d4781a81 | |||
| c36a985b88 |
@@ -55,13 +55,13 @@ const drop = (e: any) => {
|
|||||||
<div class="basic-article_content" :class="[!parseData && 'no-data']">
|
<div class="basic-article_content" :class="[!parseData && 'no-data']">
|
||||||
<div>
|
<div>
|
||||||
<template v-if="parseData">
|
<template v-if="parseData">
|
||||||
<nuxt-link :to="`/bai-viet/${parseData.slug}`">
|
<nuxt-link :to="`/bai-viet/${parseData.id}`">
|
||||||
<h3 v-if="!LAYOUT_PARSE['HIDE'] || !LAYOUT_PARSE['HIDE'].includes('title')" class="mb-1 line-clamp-2 text-base font-700 hover:text-primary-100 transition-all duration-300">
|
<h3 v-if="!LAYOUT_PARSE['HIDE'] || !LAYOUT_PARSE['HIDE'].includes('title')" class="mb-1 line-clamp-2 text-base font-700 hover:text-primary-100 transition-all duration-300">
|
||||||
{{ parseData.title?.replace(/<[^>]+>/g, '') }}
|
{{ parseData.title?.replace(/<[^>]+>/g, '') }}
|
||||||
</h3>
|
</h3>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</template>
|
</template>
|
||||||
<p v-if="!LAYOUT_PARSE['HIDE'] || !LAYOUT_PARSE['HIDE'].includes('paragraph')" class="mb-0 line-clamp-3 sm:line-clamp-5 text-[14px]">
|
<p v-if="!LAYOUT_PARSE['HIDE'] || !LAYOUT_PARSE['HIDE'].includes('paragraph')" class="mb-0 line-clamp-3 sm:line-clamp-3 text-[14px]">
|
||||||
<template v-if="parseData">
|
<template v-if="parseData">
|
||||||
<template v-if="parseData.intro">
|
<template v-if="parseData.intro">
|
||||||
{{ parseData.intro?.replace(/<[^>]+>/g, '') }}
|
{{ parseData.intro?.replace(/<[^>]+>/g, '') }}
|
||||||
|
|||||||
@@ -23,10 +23,12 @@ const _dataResult = computed(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex gap-4 items-end" @click="selectComponent">
|
<div class="flex gap-4 items-end py-2">
|
||||||
<nuxt-link :to="`/${component.code}`" v-for="(component, index) in _dataResult" :key="index" class=" py-1 font-400 text-[16px] first:font-600 first:text-[20px] sm:block hidden first:block first:border-b-[1px] first:border-b-solid first:border-b-[#409eff]">
|
<template v-for="(component, index) in _dataResult">
|
||||||
<h3 class="m-0 leading-none hover:text-primary-100 transition-all duration-300">{{ component.title }}</h3>
|
<nuxt-link v-if="component" :key="index" :to="`/${component.code}`" class=" py-1 font-400 text-[16px] first:font-600 first:text-[20px] sm:block hidden first:block">
|
||||||
</nuxt-link>
|
<h3 class="m-0 leading-none hover:text-primary-100 transition-all duration-300">{{ component.title }}</h3>
|
||||||
|
</nuxt-link>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
- LayoutType: None=0 | Normal=1 | Short=2 | Long=3 | Page=4 | Other=5
|
||||||
|
- ContentType: None=0 | Normal=1 | Photo=2 | Video=3 | Graphic=4 | Document=5 | Reaction=6 (Poll,Quiz) | Other=7
|
||||||
|
- Type: None=0 | Editorial=1 | General=2 | Reportage=3 | Interview=4 | Survey=5 | Tutorial=6 | Podcast=7 | Broadcast=8 | TalkShow=9 | LiveStream=10 | Translation=11 | Promotion=12 | Other=13
|
||||||
|
*/
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import _cloneDeep from 'lodash/cloneDeep';
|
||||||
|
|
||||||
|
import DynamicTemplate from "~/components/dynamic-page/page/templates/index.vue";
|
||||||
|
import DynamicSection from "~/components/dynamic-page/page-section/templates/index.vue";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
import { useDynamicPageStore } from '~/stores/dynamic-page';
|
||||||
|
import { useArticleStore } from '~/stores/articles';
|
||||||
|
const { currentPage, sectionPublished, componentPublished } = storeToRefs(useDynamicPageStore());
|
||||||
|
const { currentArticle } = storeToRefs(useArticleStore());
|
||||||
|
|
||||||
|
const store = reactive({
|
||||||
|
dynamicPage: useDynamicPageStore(),
|
||||||
|
article: useArticleStore(),
|
||||||
|
});
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
store.article.getArticleById(route.params.slug);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
const loadPage = async (contentType: string | number) => {
|
||||||
|
store.dynamicPage.fetchPageByCode('trang-chu');
|
||||||
|
store.dynamicPage.setSectionPublished();
|
||||||
|
store.dynamicPage.setComponentPublished();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(currentArticle, async () => {
|
||||||
|
let isContentType : string = '';
|
||||||
|
switch (currentArticle.value?.contentType) {
|
||||||
|
case 1:
|
||||||
|
isContentType = 'ArticleLayoutDefault'
|
||||||
|
case 2:
|
||||||
|
isContentType = 'ArticleLayoutImage'
|
||||||
|
case 3:
|
||||||
|
isContentType = 'ArticleLayoutPodcast'
|
||||||
|
case 4:
|
||||||
|
isContentType = 'ArticleLayoutVideo'
|
||||||
|
case 5:
|
||||||
|
if (currentArticle.value?.layoutType === 3) isContentType = 'ArticleLayoutInfographics'
|
||||||
|
else isContentType = 'ArticleLayoutFullPage'
|
||||||
|
default:
|
||||||
|
isContentType = 'ArticleLayoutDefault'
|
||||||
|
}
|
||||||
|
await loadPage(isContentType)
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
useSeoMeta({
|
||||||
|
title: currentArticle.value?.title,
|
||||||
|
ogTitle: currentArticle.value?.title,
|
||||||
|
description: currentArticle.value?.intro,
|
||||||
|
ogDescription: currentArticle.value?.intro,
|
||||||
|
ogImage: currentArticle.value?.thumbnail,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main class="h-screen" v-if="currentPage">
|
||||||
|
<DynamicTemplate :settings="currentPage.settings">
|
||||||
|
<template v-if="sectionPublished && sectionPublished.length > 0">
|
||||||
|
<DynamicSection
|
||||||
|
v-for="(section, index) in sectionPublished"
|
||||||
|
:key="index"
|
||||||
|
:settings="section.settings"
|
||||||
|
:content="section.content ? JSON.parse(section.content) : null"
|
||||||
|
:section="section"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</DynamicTemplate>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
+9
-5
@@ -10,14 +10,18 @@ const { currentPage, sectionPublished, componentPublished } = storeToRefs(useDyn
|
|||||||
const store = reactive({
|
const store = reactive({
|
||||||
dynamicPage: useDynamicPageStore(),
|
dynamicPage: useDynamicPageStore(),
|
||||||
});
|
});
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
store.dynamicPage.fetchPageByCode('trang-chu');
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
const loadData = async () => {
|
watch(currentPage, () => {
|
||||||
store.dynamicPage.fetchPageById(1);
|
|
||||||
|
|
||||||
store.dynamicPage.setSectionPublished();
|
store.dynamicPage.setSectionPublished();
|
||||||
store.dynamicPage.setComponentPublished()
|
store.dynamicPage.setComponentPublished()
|
||||||
}
|
}, { deep: true })
|
||||||
await loadData()
|
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
title: 'Trang chủ'
|
title: 'Trang chủ'
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { createRouter, defineEventHandler, useBase } from 'h3'
|
||||||
|
import * as DynamicArticleCtrl from '~/server/models/articles'
|
||||||
|
|
||||||
|
const router = createRouter()
|
||||||
|
|
||||||
|
router.get('/get-by-id/:id', defineEventHandler(DynamicArticleCtrl.getArticleById))
|
||||||
|
router.get('/get-by-slug/:slug', defineEventHandler(DynamicArticleCtrl.getArticleBySlug))
|
||||||
|
|
||||||
|
export default useBase('/api/articles', router.handler)
|
||||||
@@ -3,7 +3,7 @@ import * as DynamicPageCtrl from '~/server/models/dynamic-page'
|
|||||||
|
|
||||||
const router = createRouter()
|
const router = createRouter()
|
||||||
|
|
||||||
router.get('/getByCode/:code', defineEventHandler(DynamicPageCtrl.getDynamicPageByCode))
|
router.get('/get-by-code/:slug', defineEventHandler(DynamicPageCtrl.getDynamicPageByCode))
|
||||||
router.get('/get-by-id/:id', defineEventHandler(DynamicPageCtrl.getDynamicPageById))
|
router.get('/get-by-id/:id', defineEventHandler(DynamicPageCtrl.getDynamicPageById))
|
||||||
|
|
||||||
export default useBase('/api/services', router.handler)
|
export default useBase('/api/dynamic-page', router.handler)
|
||||||
|
|||||||
@@ -1,32 +1,8 @@
|
|||||||
import { createRouter, defineEventHandler, useBase } from 'h3'
|
import { createRouter, defineEventHandler, useBase } from 'h3'
|
||||||
import * as DynamicPageCtrl from '~/server/models/dynamic-page'
|
|
||||||
import * as navigationCtrl from '~/server/models/navigation'
|
import * as navigationCtrl from '~/server/models/navigation'
|
||||||
|
|
||||||
const router = createRouter()
|
const router = createRouter()
|
||||||
|
|
||||||
router.get('/get-by-code/:slug', defineEventHandler(async (event : any) => {
|
|
||||||
try {
|
|
||||||
const { apiUrl } = useRuntimeConfig().public
|
|
||||||
const slug = event.context.params.slug;
|
|
||||||
const { item } : any = await $fetch(`${apiUrl}/cms/overview-page/1`)
|
|
||||||
|
|
||||||
return item
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
router.get('/get-by-id/:id', defineEventHandler(async (event : any) => {
|
|
||||||
try {
|
|
||||||
const { apiUrl } = useRuntimeConfig().public
|
|
||||||
const slug = event.context.params.slug;
|
|
||||||
const { item } : any = await $fetch(`${apiUrl}/cms/overview-page/1`)
|
|
||||||
|
|
||||||
return item
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
router.get('/navigation', defineEventHandler(navigationCtrl.get))
|
router.get('/navigation', defineEventHandler(navigationCtrl.get))
|
||||||
|
|
||||||
export default useBase('/api/services', router.handler)
|
export default useBase('/api/services', router.handler)
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
interface Base {
|
||||||
|
createdBy?: string | number
|
||||||
|
createdOn?: string
|
||||||
|
updatedBy?: string | number
|
||||||
|
updatedOn?: string
|
||||||
|
}
|
||||||
|
interface Article extends Base {
|
||||||
|
id?: number; // ID của bài viết
|
||||||
|
siteId?: number; // ID của trang web
|
||||||
|
articleId?: number; // ID của bài viết
|
||||||
|
originalId?: number; // ID còn bài viết gốc
|
||||||
|
sub?: string; // Tiêu đề phụ
|
||||||
|
title?: string; // Tiêu đề
|
||||||
|
slug?: string; // Đường dẫn thân thiện cho SEO
|
||||||
|
code?: string; // Mã bài viết
|
||||||
|
intro?: string; // Phần giới thiệu
|
||||||
|
brief?: string; // Tóm tắt
|
||||||
|
detail?: string; // Nội dung chi tiết
|
||||||
|
summary?: string; // Tóm tắt ngắn gọn
|
||||||
|
thumbnail?: string; // Đường dẫn hình ảnh đại diện
|
||||||
|
represent?: string; // Đại diện cho bài viết
|
||||||
|
redirect?: string; // Đường dẫn chuyển hướng
|
||||||
|
keywords?: string; // Từ khóa
|
||||||
|
description?: string; // Mô tả
|
||||||
|
type?: number; // Loại bài viết
|
||||||
|
layoutType?: number; // Loại giao diện
|
||||||
|
contentType?: number; // Loại nội dung
|
||||||
|
priority?: number; // Ưu tiên
|
||||||
|
features?: string; // Các tính năng
|
||||||
|
taxonomy?: string; // Phân loại
|
||||||
|
interaction?: string; // Tương tác
|
||||||
|
language?: string; // Ngôn ngữ
|
||||||
|
settings?: string; // Các tùy chọn
|
||||||
|
categoryId?: number; // ID của danh mục
|
||||||
|
categoryIds?: string; // Các ID danh mục liên quan
|
||||||
|
topicIds?: string; // Các ID chủ đề liên quan
|
||||||
|
eventIds?: string; // Các ID sự kiện liên quan
|
||||||
|
collectionIds?: string; // Các ID bộ sưu tập liên quan
|
||||||
|
urlIds?: string; // Các ID URL liên quan
|
||||||
|
sourceIds?: string; // Các ID nguồn liên quan
|
||||||
|
relatedArticleIds?: string; // Các ID liên quan
|
||||||
|
advertisementIds?: string; // Các ID quảng cáo liên quan
|
||||||
|
attachmentIds?: string; // Các ID tệp đính kèm liên quan
|
||||||
|
authorIds?: string; // Các ID tác giả liên quan
|
||||||
|
views?: number; // Số lượt xem
|
||||||
|
likes?: number; // Số lượt thích
|
||||||
|
rates?: number; // Đánh giá
|
||||||
|
follows?: number; // Số lượt theo dõi
|
||||||
|
shares?: number; // Số lượt chia sẻ
|
||||||
|
reports?: number; // Số lượt báo cáo
|
||||||
|
comments?: number; // Số lượt bình luận
|
||||||
|
statistics?: string; // Thống kê khác
|
||||||
|
isPublished?: boolean; // Đã xuất bản hay chưa
|
||||||
|
publishedBy?: number; // ID người xuất bản
|
||||||
|
publishedOn?: Date; // Ngày xuất bản
|
||||||
|
expiresOn?: Date; // Ngày hết hạn
|
||||||
|
order?: number; // Thứ tự
|
||||||
|
status?: number; // Trạng thái
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getArticleById = async (event : any) => {
|
||||||
|
try {
|
||||||
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
|
const id = event.context.params.id;
|
||||||
|
const { item }: any = await $fetch(`${apiUrl}/cms/digital-Article/${id}`, {
|
||||||
|
headers: new Headers({
|
||||||
|
site: '1' || 1,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
return item
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getArticleBySlug = async (event : any) => {
|
||||||
|
try {
|
||||||
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
|
const slug = event.context.params.slug;
|
||||||
|
const { item }: any = await $fetch(`${apiUrl}/cms/digital-Article/slug:${slug}`, {
|
||||||
|
headers: new Headers({
|
||||||
|
site: '1' || 1,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
return item
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,6 @@ interface PageComponentSettings {
|
|||||||
dataQuery?: string; // Truy vấn dữ liệu: IDS | NEW | VIEW | SQL | REQUEST | ...
|
dataQuery?: string; // Truy vấn dữ liệu: IDS | NEW | VIEW | SQL | REQUEST | ...
|
||||||
dataResult?: string; // Kết quả dữ liệu (Json)
|
dataResult?: string; // Kết quả dữ liệu (Json)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PageSection extends Base {
|
interface PageSection extends Base {
|
||||||
id?: number; // Mã định danh
|
id?: number; // Mã định danh
|
||||||
siteId?: number; // Mã hệ thống
|
siteId?: number; // Mã hệ thống
|
||||||
@@ -102,12 +101,12 @@ export const getDynamicPageByCode = async (event : any) => {
|
|||||||
try {
|
try {
|
||||||
const { apiUrl } = useRuntimeConfig().public
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
const slug = event.context.params.slug;
|
const slug = event.context.params.slug;
|
||||||
|
const { item }: any = await $fetch(`${apiUrl}/cms/overview-page/slug:${slug}`, {
|
||||||
const { item }: any = await $fetch(`${apiUrl}/cms/overview-page/slug:${slug}`)
|
headers: new Headers({
|
||||||
console.log('============')
|
site: '1' || 1,
|
||||||
console.log(item)
|
}),
|
||||||
console.log('============')
|
})
|
||||||
return { item }
|
return item
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
}
|
}
|
||||||
@@ -117,11 +116,8 @@ export const getDynamicPageById = async (event : any) => {
|
|||||||
try {
|
try {
|
||||||
const { apiUrl } = useRuntimeConfig().public
|
const { apiUrl } = useRuntimeConfig().public
|
||||||
const id = event.context.params.id;
|
const id = event.context.params.id;
|
||||||
|
const { item }: any = await $fetch(`${apiUrl}/cms/overview-page/${id}`)
|
||||||
const { item }: any = await $fetch(`${apiUrl}/cms/overview-page/${id}`, {
|
return item
|
||||||
method: 'GET',
|
|
||||||
})
|
|
||||||
return { item }
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export const useArticleStore = defineStore("article", () => {
|
||||||
|
const currentArticle = ref<any>({});
|
||||||
|
|
||||||
|
const getArticleById = async (id: string | number) => {
|
||||||
|
try {
|
||||||
|
const { data } = await useFetch(`/api/articles/get-by-id/${id}`)
|
||||||
|
currentArticle.value = {}
|
||||||
|
currentArticle.value = data.value
|
||||||
|
} catch (error: any) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentArticle,
|
||||||
|
getArticleById
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
import.meta.hot && import.meta.hot.accept(acceptHMRUpdate(useArticleStore, import.meta.hot));
|
||||||
+10
-8
@@ -6,17 +6,19 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
|
|||||||
const componentPublished = ref<any[]>([]);
|
const componentPublished = ref<any[]>([]);
|
||||||
|
|
||||||
async function fetchPageByCode(slug: any) {
|
async function fetchPageByCode(slug: any) {
|
||||||
try {
|
try {
|
||||||
const { data } = await useFetch(`/api/services/get-by-code/${slug}`)
|
const { data } = await useFetch(`/api/dynamic-page/get-by-code/${slug}`)
|
||||||
currentPage.value = data.value
|
currentPage.value = {}
|
||||||
} catch (error: any) {}
|
currentPage.value = data.value
|
||||||
|
} catch (error: any) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchPageById(id: string | number) {
|
async function fetchPageById(id: string | number) {
|
||||||
try {
|
try {
|
||||||
const {data} = await useFetch(`/api/services/get-by-id/${id}`)
|
const { data } = await useFetch(`/api/dynamic-page/get-by-id/${id}`)
|
||||||
currentPage.value = data.value
|
currentPage.value = {}
|
||||||
} catch (error: any) {}
|
currentPage.value = data.value
|
||||||
|
} catch (error: any) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setSectionPublished = () => {
|
const setSectionPublished = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user