minhnt-dev: article api

This commit is contained in:
MoreStrive
2024-05-31 00:46:43 +07:00
parent a7d4781a81
commit 7a92ca829f
11 changed files with 229 additions and 60 deletions
@@ -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, '') }}
@@ -25,7 +25,7 @@ const _dataResult = computed(() => {
<div> <div>
<div class="flex gap-4 items-end py-2"> <div class="flex gap-4 items-end py-2">
<template v-for="(component, index) in _dataResult"> <template v-for="(component, index) in _dataResult">
<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 first:border-b-[1px] first:border-b-solid first:border-b-[#409eff]"> <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">
<h3 class="m-0 leading-none hover:text-primary-100 transition-all duration-300">{{ component.title }}</h3> <h3 class="m-0 leading-none hover:text-primary-100 transition-all duration-300">{{ component.title }}</h3>
</nuxt-link> </nuxt-link>
</template> </template>
+81
View File
@@ -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
View File
@@ -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ủ'
+9
View File
@@ -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)
+2 -2
View File
@@ -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)
-30
View File
@@ -1,30 +0,0 @@
import { createRouter, defineEventHandler, useBase } from 'h3'
import * as DynamicPageCtrl from '~/server/models/dynamic-page'
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 id = event.context.params.id;
const { item } : any = await $fetch(`${apiUrl}/cms/overview-page/${id}`)
return item
} catch (error) {
handleError(error);
}
}))
export default useBase('/api/services', router.handler)
+89
View File
@@ -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);
}
}
+8 -12
View File
@@ -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);
} }
+18
View File
@@ -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));
+4 -2
View File
@@ -7,14 +7,16 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
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 = {}
currentPage.value = data.value currentPage.value = data.value
} catch (error: any) {} } 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 = {}
currentPage.value = data.value currentPage.value = data.value
} catch (error: any) {} } catch (error: any) {}
} }