Initial commit of Vue Website Template
This commit is contained in:
parent
376a04cc0f
commit
89242ec738
@ -1,7 +1,6 @@
|
|||||||
// src/components/TabNews.vue
|
// src/components/TabNews.vue
|
||||||
<template>
|
<template>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<!-- หัวข้อข่าว -->
|
|
||||||
<div class="mb-6 px-2 md:px-4">
|
<div class="mb-6 px-2 md:px-4">
|
||||||
<h4
|
<h4
|
||||||
class="inline-block text-white text-2xl md:text-3xl font-semibold px-6 py-2 bg-[#1b3872] rounded shadow-md"
|
class="inline-block text-white text-2xl md:text-3xl font-semibold px-6 py-2 bg-[#1b3872] rounded shadow-md"
|
||||||
@ -10,7 +9,6 @@
|
|||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tabs -->
|
|
||||||
<div role="tablist" class="flex flex-wrap space-x-2 border-b border-gray-300">
|
<div role="tablist" class="flex flex-wrap space-x-2 border-b border-gray-300">
|
||||||
<button
|
<button
|
||||||
v-for="(tab, index) in tabs"
|
v-for="(tab, index) in tabs"
|
||||||
@ -26,7 +24,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tab Content -->
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div
|
<div
|
||||||
v-for="tab in tabs"
|
v-for="tab in tabs"
|
||||||
@ -53,13 +50,13 @@
|
|||||||
|
|
||||||
<div class="card-body p-4 flex flex-col justify-between flex-1">
|
<div class="card-body p-4 flex flex-col justify-between flex-1">
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/content/${item.id}`"
|
:to="`/tab-news-content/${item.id}`"
|
||||||
class="card-title text-base text-gray-800 hover:underline line-clamp-2 mb-2"
|
class="card-title text-base text-gray-800 hover:underline line-clamp-2 mb-2"
|
||||||
>
|
>
|
||||||
{{ appStore.checkLang.isTh ? item.title_th : item.title_en || 'No Title' }}
|
{{ appStore.checkLang.isTh ? item.title_th : item.title_en || 'No Title' }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<p class="text-sm text-gray-600 line-clamp-2 flex-grow">
|
<p class="text-sm text-gray-600 line-clamp-3 flex-grow">
|
||||||
{{ truncateDetail(appStore.checkLang.isTh ? item.detail_th : item.detail_en || '', 80) }}
|
{{ stripHtmlAndTruncate(appStore.checkLang.isTh ? item.detail_th : item.detail_en || '', 120) }}
|
||||||
</p>
|
</p>
|
||||||
<div class="text-xs text-gray-400 mt-2">
|
<div class="text-xs text-gray-400 mt-2">
|
||||||
<span v-if="item.release_date">{{ formatDate(item.release_date) }}</span>
|
<span v-if="item.release_date">{{ formatDate(item.release_date) }}</span>
|
||||||
@ -76,7 +73,7 @@
|
|||||||
<div class="flex justify-end mt-6">
|
<div class="flex justify-end mt-6">
|
||||||
<router-link
|
<router-link
|
||||||
v-if="newsByTab[tab.category]?.total > 6"
|
v-if="newsByTab[tab.category]?.total > 6"
|
||||||
:to="`/news/${tab.category}`"
|
:to="`/tab-news/${tab.category}`"
|
||||||
class="btn bg-[#1b3872] text-white hover:bg-[#1b3872]/90 rounded-none border-none shadow-md"
|
class="btn bg-[#1b3872] text-white hover:bg-[#1b3872]/90 rounded-none border-none shadow-md"
|
||||||
>
|
>
|
||||||
{{ appStore.checkLang.isTh ? more : more_en }}
|
{{ appStore.checkLang.isTh ? more : more_en }}
|
||||||
@ -107,9 +104,15 @@ const newsByTab = ref({});
|
|||||||
const more = "อ่านข่าวต่อ";
|
const more = "อ่านข่าวต่อ";
|
||||||
const more_en = "Read More";
|
const more_en = "Read More";
|
||||||
|
|
||||||
const truncateDetail = (text, maxLength) => {
|
// ฟังก์ชันสำหรับลบ HTML tags ออกจาก String ก่อนทำการ truncate
|
||||||
if (!text) return '';
|
const stripHtmlAndTruncate = (htmlText, maxLength) => {
|
||||||
return text.length <= maxLength ? text : text.substring(0, maxLength) + '...';
|
if (!htmlText) return '';
|
||||||
|
// 1. สร้าง DOMParser เพื่อ parse HTML string
|
||||||
|
const doc = new DOMParser().parseFromString(htmlText, 'text/html');
|
||||||
|
// 2. ดึง textContent ออกมา ซึ่งจะลบ HTML tags ทั้งหมด
|
||||||
|
const plainText = doc.body.textContent || "";
|
||||||
|
// 3. ทำการ truncate text
|
||||||
|
return plainText.length <= maxLength ? plainText : plainText.substring(0, maxLength) + '...';
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatDate = (dateString) => {
|
const formatDate = (dateString) => {
|
||||||
@ -128,6 +131,7 @@ const formatDate = (dateString) => {
|
|||||||
|
|
||||||
const fetchNewsForTab = async (category) => {
|
const fetchNewsForTab = async (category) => {
|
||||||
try {
|
try {
|
||||||
|
// กำหนด limit แค่ 6 ชิ้นเพื่อแสดงในหน้า TabNews นี้
|
||||||
const { data, total } = await appStore.fetchTabNews(category, 6);
|
const { data, total } = await appStore.fetchTabNews(category, 6);
|
||||||
newsByTab.value[category] = { data, total };
|
newsByTab.value[category] = { data, total };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -138,15 +142,19 @@ const fetchNewsForTab = async (category) => {
|
|||||||
|
|
||||||
const changeTab = async (category) => {
|
const changeTab = async (category) => {
|
||||||
activeTab.value = category;
|
activeTab.value = category;
|
||||||
if (!newsByTab.value[category]) {
|
// ตรวจสอบว่ามีข้อมูลสำหรับ Tab นี้แล้วหรือยังก่อนที่จะ fetch
|
||||||
|
// เพื่อลดการเรียก API ซ้ำซ้อนถ้าผู้ใช้สลับ Tab ไปมา
|
||||||
|
if (!newsByTab.value[category] || newsByTab.value[category].data.length === 0) {
|
||||||
await fetchNewsForTab(category);
|
await fetchNewsForTab(category);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initial data fetch for all tabs on component mount
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
for (const tab of tabs.value) {
|
// Fetch news for all tabs initially
|
||||||
await fetchNewsForTab(tab.category);
|
// Use Promise.all to fetch all tabs concurrently for better performance
|
||||||
}
|
await Promise.all(tabs.value.map(tab => fetchNewsForTab(tab.category)));
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -155,4 +163,11 @@ onMounted(async () => {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
}
|
}
|
||||||
</style>
|
/* เพิ่ม line-clamp สำหรับ p ใน card-body ให้แสดงได้ 3 บรรทัด */
|
||||||
|
.line-clamp-3 {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -9,9 +9,10 @@ import LandingLayout from "@/layouts/LandingLayout.vue";
|
|||||||
import LandingPageView from "@/views/LandingPageView.vue"; // View สำหรับหน้า Landing Page
|
import LandingPageView from "@/views/LandingPageView.vue"; // View สำหรับหน้า Landing Page
|
||||||
import HomeView from "@/views/HomeView.vue"; // View สำหรับหน้า Home หลัก (ที่มี Calousels, News ฯลฯ)
|
import HomeView from "@/views/HomeView.vue"; // View สำหรับหน้า Home หลัก (ที่มี Calousels, News ฯลฯ)
|
||||||
|
|
||||||
import ContentView from "@/views/ContentView.vue"; // View สำหรับแสดงรายละเอียดข่าว
|
import ContentView from "@/views/ContentView.vue"; // View สำหรับแสดงรายละเอียด เรื่องราวดี ๆ ที่อยากบอกต่อ
|
||||||
import NewsCategoryView from "@/views/NewsCategoryView.vue"; // View สำหรับแสดงรายการข่าวตามหมวดหมู่
|
import NewsCategoryView from "@/views/NewsCategoryView.vue"; // View สำหรับแสดงรายการข่าวตามหมวดหมู่
|
||||||
import NotFoundView from '@/views/NotFoundView.vue';
|
import NotFoundView from '@/views/NotFoundView.vue'; // View สำหรับแสดงหน้า Not Found
|
||||||
|
import TabContentView from "@/views/TabContentView.vue"; // // View สำหรับแสดงรายละเอียดข่าวสารอับเดต
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
// --- Route สำหรับหน้า Landing Page (ใช้ LandingLayout) ---
|
// --- Route สำหรับหน้า Landing Page (ใช้ LandingLayout) ---
|
||||||
@ -46,11 +47,18 @@ const routes = [
|
|||||||
},
|
},
|
||||||
// !!! เพิ่ม Route สำหรับ NewsCategoryView !!!
|
// !!! เพิ่ม Route สำหรับ NewsCategoryView !!!
|
||||||
{
|
{
|
||||||
path: 'news/:category', // Path สำหรับข่าวตามหมวดหมู่ เช่น /news/RTAFNews
|
path: 'tab-news/:category', // Path สำหรับข่าวตามหมวดหมู่ เช่น /news/RTAFNews
|
||||||
name: 'NewsCategoryView',
|
name: 'NewsCategoryView',
|
||||||
component: NewsCategoryView,
|
component: NewsCategoryView,
|
||||||
props: true // ส่งค่า parameter (category) เป็น props ไปยัง component ได้
|
props: true // ส่งค่า parameter (category) เป็น props ไปยัง component ได้
|
||||||
},
|
},
|
||||||
|
// !!! เพิ่ม Route สำหรับ ContentView !!!
|
||||||
|
{
|
||||||
|
path: 'tab-news-content/:id', // Path สำหรับรายละเอียดข่าว เช่น /news-content/1, /news-content/2
|
||||||
|
name: 'TabContentView',
|
||||||
|
component: TabContentView,
|
||||||
|
props: true // ส่งค่า parameter (id) เป็น props ไปยัง component ได้
|
||||||
|
},
|
||||||
// ... ( routes อื่นๆ ที่อาจจะใช้ DefaultLayout )
|
// ... ( routes อื่นๆ ที่อาจจะใช้ DefaultLayout )
|
||||||
|
|
||||||
// *** เส้นทาง 404 (ต้องอยู่สุดท้ายเสมอ!) ***
|
// *** เส้นทาง 404 (ต้องอยู่สุดท้ายเสมอ!) ***
|
||||||
|
|||||||
@ -7,10 +7,10 @@ export const useAppStore = defineStore('app', {
|
|||||||
state: () => ({
|
state: () => ({
|
||||||
isTh: true,
|
isTh: true,
|
||||||
tabs: [ // ตรวจสอบว่า tabs array ใน store ตรงกับ TabNews.vue
|
tabs: [ // ตรวจสอบว่า tabs array ใน store ตรงกับ TabNews.vue
|
||||||
{ title: "ข่าวประชาสัมพันธ์หน่วยงาน", title_en: "RTAF News", category: "HumanTechNews" },
|
{ title: "ข่าวประชาสัมพันธ์หน่วยงาน", title_en: "Human Tech News", category: "HumanTechNews" },
|
||||||
{ title: "ข่าวประชาสัมพันธ์ภายใน", title_en: "RTAF Organization News", category: "OrgNews" },
|
{ title: "ข่าวประชาสัมพันธ์ภายใน", title_en: "Organization News", category: "OrgNews" },
|
||||||
{ title: "ข่าวนวัตกรรม", title_en: "RTAF Service News", category: "InnovationNews" },
|
{ title: "ข่าวนวัตกรรม", title_en: "Innovation News", category: "InnovationNews" },
|
||||||
{ title: "Press Release", title_en: "RTAF Press Release", category: "GeneralPublic" },
|
{ title: "Press Release", title_en: "Press Release", category: "GeneralPublic" },
|
||||||
{ title: "ข่าวบริการประชาชน", title_en: "Public Service News", category: "EventActivities" },
|
{ title: "ข่าวบริการประชาชน", title_en: "Public Service News", category: "EventActivities" },
|
||||||
],
|
],
|
||||||
// *** ข้อมูลสำหรับ Header ***
|
// *** ข้อมูลสำหรับ Header ***
|
||||||
@ -228,115 +228,211 @@ export const useAppStore = defineStore('app', {
|
|||||||
mockNewsData : [
|
mockNewsData : [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 1", // RTAF News
|
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 1: การพัฒนาระบบ AI สำหรับการบิน",
|
||||||
title_en: "RTAF News Item 1",
|
title_en: "RTAF News Item 1: AI System Development for Aviation",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 1 เพื่อทดสอบการแสดงผลข้อมูล. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF News Item 1 for testing purposes. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p><strong>กองทัพอากาศ</strong> ได้เริ่มโครงการนำร่องในการพัฒนาระบบปัญญาประดิษฐ์ (AI) เพื่อเพิ่มประสิทธิภาพในการปฏิบัติงานด้านการบินและบำรุงรักษาอากาศยาน</p>
|
||||||
image: { url: "/uploads/news_1.jpg" },
|
<h3>วัตถุประสงค์หลักของโครงการ</h3>
|
||||||
|
<ul>
|
||||||
|
<li>เพิ่มความแม่นยำในการวิเคราะห์ข้อมูลการบิน</li>
|
||||||
|
<li>ลดระยะเวลาในการตรวจสอบและบำรุงรักษา</li>
|
||||||
|
<li>ยกระดับความปลอดภัยในการปฏิบัติภารกิจ</li>
|
||||||
|
</ul>
|
||||||
|
<figure style="text-align: center;">
|
||||||
|
<img src="/uploads/news_1.jpg" alt="การบำรุงรักษาอากาศยาน" style="max-width:90%; height:auto; margin: 15px auto; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
|
||||||
|
<figcaption style="font-style: italic; color: #555; margin-top: 5px;">ภาพ: เจ้าหน้าที่กำลังตรวจสอบอากาศยานด้วยระบบใหม่</figcaption>
|
||||||
|
</figure>
|
||||||
|
<h4><strong>แผนงานในระยะต่อไป</strong></h4>
|
||||||
|
<ol>
|
||||||
|
<li>ทดสอบระบบ AI ในสภาพแวดล้อมจริง</li>
|
||||||
|
<li>รวบรวมข้อมูลและปรับปรุงอัลกอริทึม</li>
|
||||||
|
<li>ขยายผลการใช้งานไปยังหน่วยงานต่างๆ ของกองทัพอากาศ</li>
|
||||||
|
</ol>
|
||||||
|
<p>คาดว่าระบบ AI นี้จะพร้อมใช้งานเต็มรูปแบบภายในปี 2569 ซึ่งจะนำมาซึ่งประโยชน์มหาศาลต่อการปฏิบัติงานและลดค่าใช้จ่ายในระยะยาว</p>
|
||||||
|
<blockquote>
|
||||||
|
"การลงทุนในเทคโนโลยีวันนี้ คือรากฐานความมั่นคงของชาติในวันหน้า"
|
||||||
|
</blockquote>
|
||||||
|
<p>หากมีข้อสงสัยหรือต้องการข้อมูลเพิ่มเติม สามารถติดต่อสอบถามได้ที่ฝ่ายประชาสัมพันธ์ กองทัพอากาศ.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The <strong>Royal Thai Air Force (RTAF)</strong> has launched a pilot project to develop an Artificial Intelligence (AI) system to enhance operational efficiency in aviation and aircraft maintenance.</p>
|
||||||
|
<h3>Key Objectives of the Project</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Increase accuracy in flight data analysis.</li>
|
||||||
|
<li>Reduce inspection and maintenance time.</li>
|
||||||
|
<li>Improve safety in mission operations.</li>
|
||||||
|
</ul>
|
||||||
|
<figure style="text-align: center;">
|
||||||
|
<img src="/uploads/news_1.jpg" alt="Aircraft Maintenance" style="max-width:90%; height:auto; margin: 15px auto; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
|
||||||
|
<figcaption style="font-style: italic; color: #555; margin-top: 5px;">Image: Officers inspecting aircraft with the new system.</figcaption>
|
||||||
|
</figure>
|
||||||
|
<h4>Next Phase Plans</h4>
|
||||||
|
<ol>
|
||||||
|
<li>Test the AI system in a real environment.</li>
|
||||||
|
<li>Collect data and refine algorithms.</li>
|
||||||
|
<li>Expand implementation to various RTAF units.</li>
|
||||||
|
</ol>
|
||||||
|
<p>It is expected that this AI system will be fully operational by 2026, bringing immense benefits to operations and long-term cost reduction.</p>
|
||||||
|
<blockquote>
|
||||||
|
"Investing in technology today is the foundation of national security tomorrow."
|
||||||
|
</blockquote>
|
||||||
|
<p>For more information or inquiries, please contact the RTAF Public Relations Department.</p>
|
||||||
|
`,
|
||||||
|
image: { url: "/uploads/news_1.jpg" }, // ภาพปก
|
||||||
release_date: "07/01/2025",
|
release_date: "07/01/2025",
|
||||||
active: true,
|
active: true,
|
||||||
active_en: true,
|
active_en: true,
|
||||||
type: "HumanTechNews", // <-- ให้ตรงกับ category ใน TabNews.vue
|
type: "HumanTechNews",
|
||||||
feature: false,
|
feature: true, // ตั้งเป็น feature เพื่อให้ปรากฏเด่นถ้าคุณมีส่วนแสดง feature news
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 2",
|
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 2: พิธีมอบรางวัลบุคลากรดีเด่น",
|
||||||
title_en: "RTAF News Item 2",
|
title_en: "RTAF News Item 2: Outstanding Personnel Awards Ceremony",
|
||||||
detail_th: "ข่าวนี้มีรายละเอียดที่ยาวมากจริงๆ เพื่อทดสอบการ truncate detail. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
|
detail_th: `
|
||||||
detail_en: "This news has very long details to test detail truncation. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
|
<p>กองทัพอากาศจัดพิธีมอบรางวัลและประกาศเกียรติคุณแก่บุคลากรดีเด่น ประจำปี 2568 โดยมีผู้เข้ารับรางวัลจากหลากหลายหน่วยงาน</p>
|
||||||
|
<p>พิธีจัดขึ้นอย่างสมเกียรติ ณ ห้องประชุมใหญ่ กองบัญชาการกองทัพอากาศ</p>
|
||||||
|
<p>การมอบรางวัลนี้จัดขึ้นเป็นประจำทุกปี เพื่อยกย่องและเป็นขวัญกำลังใจให้แก่กำลังพลที่ทุ่มเทปฏิบัติหน้าที่อย่างเต็มความสามารถ</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The Royal Thai Air Force held an awards ceremony and commendation for outstanding personnel for the year 2025, with recipients from various units.</p>
|
||||||
|
<p>The ceremony was honorably held in the grand conference hall of the Royal Thai Air Force Headquarters.</p>
|
||||||
|
<p>This award ceremony is held annually to recognize and boost the morale of personnel who dedicate themselves to their duties with full capability.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_2.jpg" },
|
image: { url: "/uploads/news_2.jpg" },
|
||||||
release_date: "07/03/2025",
|
release_date: "07/03/2025",
|
||||||
active: true,
|
active: true,
|
||||||
active_en: true,
|
active_en: true,
|
||||||
type: "HumanTechNews", // <-- ให้ตรงกับ category ใน TabNews.vue
|
type: "HumanTechNews",
|
||||||
feature: false,
|
feature: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 1", // RTAF Organization News
|
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 1: การฝึกอบรมด้านความปลอดภัยไซเบอร์",
|
||||||
title_en: "RTAF Org News Item 1",
|
title_en: "RTAF Org News Item 1: Cybersecurity Training",
|
||||||
detail_th: "รายละเอียดข่าว นขต.ทอ. ชิ้นที่ 1 เพื่อทดสอบการแสดงผลข้อมูล. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Org News Item 1 for testing purposes. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>นขต.ทอ. จัดการฝึกอบรมเชิงปฏิบัติการด้านความปลอดภัยไซเบอร์ ให้แก่เจ้าหน้าที่ เพื่อเสริมสร้างความรู้และทักษะในการป้องกันภัยคุกคามทางไซเบอร์ที่เพิ่มขึ้น.</p>
|
||||||
|
<p>การฝึกอบรมครอบคลุมหัวข้อสำคัญ เช่น การป้องกันฟิชชิง, การเข้ารหัสข้อมูล, และการรับมือกับการโจมตีแบบ DDoS.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>RTAF units organized a practical cybersecurity training for officers to enhance knowledge and skills in preventing increasing cyber threats.</p>
|
||||||
|
<p>The training covered key topics such as phishing prevention, data encryption, and handling DDoS attacks.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_3.jpg" },
|
image: { url: "/uploads/news_3.jpg" },
|
||||||
release_date: "06/15/2025",
|
release_date: "06/15/2025",
|
||||||
active: true,
|
active: true,
|
||||||
active_en: true,
|
active_en: true,
|
||||||
type: "OrgNews", // <-- ให้ตรงกับ category ใน TabNews.vue
|
type: "OrgNews",
|
||||||
feature: false,
|
feature: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 2",
|
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 2: โครงการจิตอาสาพัฒนาชุมชน",
|
||||||
title_en: "RTAF Org News Item 2",
|
title_en: "RTAF Org News Item 2: Community Development Volunteer Project",
|
||||||
detail_th: "รายละเอียดข่าว นขต.ทอ. ชิ้นที่ 2 เพื่อทดสอบการแสดงผลข้อมูล. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Org News Item 2 for testing purposes. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>กำลังพลกองทัพอากาศเข้าร่วมโครงการจิตอาสา "เราทำความดีด้วยหัวใจ" เพื่อพัฒนาและปรับปรุงภูมิทัศน์ของชุมชนใกล้เคียง</p>
|
||||||
|
<p>กิจกรรมประกอบด้วยการทำความสะอาดพื้นที่สาธารณะ, ปลูกต้นไม้, และช่วยเหลือผู้สูงอายุ.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>RTAF personnel participated in the "We Do Good Deeds with Our Hearts" volunteer project to develop and improve the landscape of nearby communities.</p>
|
||||||
|
<p>Activities included cleaning public areas, planting trees, and assisting the elderly.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_4.jpg" },
|
image: { url: "/uploads/news_4.jpg" },
|
||||||
release_date: "07/02/2025",
|
release_date: "07/02/2025",
|
||||||
active: true,
|
active: true,
|
||||||
active_en: true,
|
active_en: true,
|
||||||
type: "OrgNews", // <-- ให้ตรงกับ category ใน TabNews.vue
|
type: "OrgNews",
|
||||||
feature: false,
|
feature: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
title_th: "ข่าวนวัตกรรม ชิ้นที่ 1", // RTAF Service News (หรือชื่อที่เหมาะสมกับ InnovationNews)
|
title_th: "ข่าวนวัตกรรม ชิ้นที่ 1: โดรนสำรวจไร้คนขับเพื่อภารกิจกู้ภัย",
|
||||||
title_en: "RTAF Service News Item 1",
|
title_en: "RTAF Service News Item 1: Unmanned Survey Drones for Rescue Missions",
|
||||||
detail_th: "รายละเอียดข่าวนวัตกรรม ชิ้นที่ 1 เพื่อทดสอบการแสดงผลข้อมูล. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Service News Item 1 for testing purposes. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>กองทัพอากาศได้นำโดรนสำรวจรุ่นใหม่มาทดสอบเพื่อใช้ในภารกิจค้นหาและกู้ภัย</p>
|
||||||
|
<p>โดรนเหล่านี้มาพร้อมกับเทคโนโลยีเซ็นเซอร์ความร้อนและกล้องความละเอียดสูง ทำให้สามารถปฏิบัติงานในพื้นที่เข้าถึงยากได้อย่างมีประสิทธิภาพ.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The RTAF has begun testing a new generation of survey drones for use in search and rescue missions.</p>
|
||||||
|
<p>These drones are equipped with thermal sensors and high-resolution cameras, enabling efficient operations in hard-to-reach areas.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_5.jpg" },
|
image: { url: "/uploads/news_5.jpg" },
|
||||||
release_date: "07/04/2025",
|
release_date: "07/04/2025",
|
||||||
active: true,
|
active: true,
|
||||||
active_en: true,
|
active_en: true,
|
||||||
type: "InnovationNews", // <-- ให้ตรงกับ category ใน TabNews.vue
|
type: "InnovationNews",
|
||||||
feature: false,
|
feature: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
id: 6,
|
||||||
title_th: "ข่าวนวัตกรรม ชิ้นที่ 2",
|
title_th: "ข่าวนวัตกรรม ชิ้นที่ 2: ระบบจำลองการบินเสมือนจริง",
|
||||||
title_en: "RTAF Service News Item 2",
|
title_en: "RTAF Service News Item 2: Virtual Reality Flight Simulator",
|
||||||
detail_th: "รายละเอียดข่าวนวัตกรรม ชิ้นที่ 2 เพื่อทดสอบการแสดงผลข้อมูล. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Service News Item 2 for testing purposes. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>กองทัพอากาศได้ติดตั้งระบบจำลองการบินเสมือนจริง (VR Flight Simulator) เพื่อฝึกอบรมนักบินให้คุ้นเคยกับสถานการณ์ฉุกเฉินต่างๆ ก่อนปฏิบัติการจริง.</p>
|
||||||
|
<p>ระบบนี้ช่วยลดต้นทุนการฝึกอบรมและเพิ่มความปลอดภัยในการฝึกฝน.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The RTAF has installed a new Virtual Reality (VR) Flight Simulator to train pilots to familiarize themselves with various emergency situations before actual operations.</p>
|
||||||
|
<p>This system helps reduce training costs and enhances safety during training.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_5.jpg" },
|
image: { url: "/uploads/news_5.jpg" },
|
||||||
release_date: "07/05/2025",
|
release_date: "07/05/2025",
|
||||||
active: true,
|
active: true,
|
||||||
active_en: true,
|
active_en: true,
|
||||||
type: "InnovationNews", // <-- ให้ตรงกับ category ใน TabNews.vue
|
type: "InnovationNews",
|
||||||
feature: false,
|
feature: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 7,
|
id: 7,
|
||||||
title_th: "Press Release ชิ้นที่ 1", // Press Release
|
title_th: "Press Release ชิ้นที่ 1: การเยือนของคณะผู้แทนจากมิตรประเทศ",
|
||||||
title_en: "RTAF Press Release Item 1",
|
title_en: "RTAF Press Release Item 1: Visit of Delegation from Allied Country",
|
||||||
detail_th: "รายละเอียด Press Release ชิ้นที่ 1 เพื่อทดสอบการแสดงผลข้อมูล. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Press Release Item 1 for testing purposes. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>คณะผู้แทนระดับสูงจากมิตรประเทศเดินทางเยือนกองทัพอากาศ เพื่อกระชับความสัมพันธ์และหารือความร่วมมือทางทหาร.</p>
|
||||||
|
<p>การเยือนครั้งนี้เน้นย้ำถึงความสำคัญของการแลกเปลี่ยนความรู้และประสบการณ์ระหว่างกัน.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>A high-level delegation from an allied country visited the Royal Thai Air Force to strengthen relations and discuss military cooperation.</p>
|
||||||
|
<p>This visit emphasized the importance of exchanging knowledge and experiences between the two nations.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_4.jpg" },
|
image: { url: "/uploads/news_4.jpg" },
|
||||||
release_date: "06/20/2025",
|
release_date: "06/20/2025",
|
||||||
active: true,
|
active: true,
|
||||||
active_en: true,
|
active_en: true,
|
||||||
type: "GeneralPublic", // <-- ให้ตรงกับ category ใน TabNews.vue
|
type: "GeneralPublic",
|
||||||
feature: false,
|
feature: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 8,
|
id: 8,
|
||||||
title_th: "ข่าวบริการประชาชน ชิ้นที่ 1", // Public Service News
|
title_th: "ข่าวบริการประชาชน ชิ้นที่ 1: โครงการบริจาคโลหิตประจำปี",
|
||||||
title_en: "Public Service News Item 1",
|
title_en: "Public Service News Item 1: Annual Blood Donation Drive",
|
||||||
detail_th: "รายละเอียดข่าวบริการประชาชน ชิ้นที่ 1 เพื่อทดสอบการแสดงผลข้อมูล. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for Public Service News Item 1 for testing purposes. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>กองทัพอากาศขอเชิญชวนประชาชนร่วมบริจาคโลหิตในโครงการ "รวมใจบริจาคโลหิตเพื่อเพื่อนมนุษย์" ประจำปี 2568.</p>
|
||||||
|
<p>โครงการนี้จัดขึ้นเพื่อสำรองโลหิตให้กับโรงพยาบาลและผู้ป่วยที่ต้องการ.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The Royal Thai Air Force invites the public to participate in the "Unite for Humanity Blood Donation" project for the year 2025.</p>
|
||||||
|
<p>This project aims to provide blood reserves for hospitals and patients in need.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_3.jpg" },
|
image: { url: "/uploads/news_3.jpg" },
|
||||||
release_date: "07/06/2025",
|
release_date: "07/06/2025",
|
||||||
active: true,
|
active: true,
|
||||||
active_en: true,
|
active_en: true,
|
||||||
type: "EventActivities", // <-- ให้ตรงกับ category ใน TabNews.vue
|
type: "EventActivities",
|
||||||
feature: false,
|
feature: false,
|
||||||
},
|
},
|
||||||
// เพิ่มเติมเพื่อให้มีข้อมูลเพียงพอสำหรับแต่ละแท็บ (อย่างน้อย 6 ชิ้นในแต่ละประเภท เพื่อให้ปุ่ม Read More แสดง)
|
// เพิ่มเติมเพื่อให้มีข้อมูลเพียงพอสำหรับแต่ละแท็บ (อย่างน้อย 6 ชิ้นในแต่ละประเภท เพื่อให้ปุ่ม Read More แสดง)
|
||||||
{
|
{
|
||||||
id: 9,
|
id: 9,
|
||||||
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 3",
|
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 3: สัมมนาเชิงปฏิบัติการเทคโนโลยีดิจิทัล",
|
||||||
title_en: "RTAF News Item 3",
|
title_en: "RTAF News Item 3: Digital Technology Workshop",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 3. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF News Item 3. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>กองทัพอากาศได้จัดสัมมนาเชิงปฏิบัติการเกี่ยวกับเทคโนโลยีดิจิทัลล่าสุด เพื่อให้บุคลากรได้เรียนรู้และปรับตัวเข้ากับการเปลี่ยนแปลงทางเทคโนโลยี</p>
|
||||||
|
<p>การสัมมนามุ่งเน้นที่ AI, Big Data, และ Cybersecurity ซึ่งเป็นสิ่งสำคัญในยุคปัจจุบัน</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The RTAF hosted a workshop on the latest digital technologies, allowing personnel to learn and adapt to technological changes.</p>
|
||||||
|
<p>The seminar focused on AI, Big Data, and Cybersecurity, which are crucial in the current era.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_2.jpg" },
|
image: { url: "/uploads/news_2.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -346,10 +442,16 @@ export const useAppStore = defineStore('app', {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 10,
|
id: 10,
|
||||||
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 4",
|
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 4: โครงการอนุรักษ์สิ่งแวดล้อม",
|
||||||
title_en: "RTAF News Item 4",
|
title_en: "RTAF News Item 4: Environmental Conservation Project",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 4. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF News Item 4. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>กองทัพอากาศจัดกิจกรรมโครงการอนุรักษ์สิ่งแวดล้อม โดยการปลูกป่าและทำความสะอาดพื้นที่สาธารณะรอบค่ายทหาร</p>
|
||||||
|
<p>กิจกรรมนี้เป็นส่วนหนึ่งของความรับผิดชอบต่อสังคมของกองทัพอากาศ</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The RTAF organized an environmental conservation project by planting trees and cleaning public areas around military camps.</p>
|
||||||
|
<p>This activity is part of the RTAF's social responsibility.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_1.jpg" },
|
image: { url: "/uploads/news_1.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -359,10 +461,16 @@ export const useAppStore = defineStore('app', {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 11,
|
id: 11,
|
||||||
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 5",
|
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 5: การพัฒนาศักยภาพกำลังพล",
|
||||||
title_en: "RTAF News Item 5",
|
title_en: "RTAF News Item 5: Personnel Capability Development",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 5. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF News Item 5. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>กองทัพอากาศมุ่งมั่นในการพัฒนาศักยภาพของกำลังพล ผ่านการฝึกอบรมและหลักสูตรต่างๆ</p>
|
||||||
|
<p>เพื่อเพิ่มพูนความรู้และทักษะให้ทันต่อสถานการณ์ปัจจุบัน.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The RTAF is committed to developing the capabilities of its personnel through various training and courses.</p>
|
||||||
|
<p>To enhance knowledge and skills to keep pace with current situations.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_1.jpg" },
|
image: { url: "/uploads/news_1.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -372,10 +480,16 @@ export const useAppStore = defineStore('app', {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 12,
|
id: 12,
|
||||||
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 6",
|
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 6: การซ้อมรบร่วมประจำปี",
|
||||||
title_en: "RTAF News Item 6",
|
title_en: "RTAF News Item 6: Annual Joint Military Exercise",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 6. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF News Item 6. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>กองทัพอากาศเข้าร่วมการซ้อมรบร่วมกับกองทัพบกและกองทัพเรือ เพื่อเสริมสร้างความร่วมมือและบูรณาการการทำงาน</p>
|
||||||
|
<p>การซ้อมรบดำเนินไปอย่างเข้มข้นและประสบความสำเร็จตามวัตถุประสงค์.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The RTAF participated in a joint military exercise with the Royal Thai Army and Royal Thai Navy to enhance cooperation and work integration.</p>
|
||||||
|
<p>The exercise was conducted intensively and achieved its objectives successfully.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_2.jpg" },
|
image: { url: "/uploads/news_2.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -387,8 +501,14 @@ export const useAppStore = defineStore('app', {
|
|||||||
id: 13,
|
id: 13,
|
||||||
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 7 (สำหรับปุ่ม More)",
|
title_th: "ข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 7 (สำหรับปุ่ม More)",
|
||||||
title_en: "RTAF News Item 7 (for More button)",
|
title_en: "RTAF News Item 7 (for More button)",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 7. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF News Item 7. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
<p>รายละเอียดข่าวประชาสัมพันธ์หน่วยงาน ชิ้นที่ 7 เพิ่มเติมสำหรับทดสอบปุ่ม 'ดูเพิ่มเติม'</p>
|
||||||
|
<p>ข้อมูลนี้แสดงให้เห็นว่าสามารถโหลดเนื้อหาเพิ่มขึ้นมาได้เรื่อยๆ</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>Details for RTAF News Item 7, further content for testing the 'Load More' button.</p>
|
||||||
|
<p>This data demonstrates that more content can be continuously loaded.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_3.jpg" },
|
image: { url: "/uploads/news_3.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -396,14 +516,18 @@ export const useAppStore = defineStore('app', {
|
|||||||
type: "HumanTechNews",
|
type: "HumanTechNews",
|
||||||
feature: false,
|
feature: false,
|
||||||
},
|
},
|
||||||
// เพิ่มข้อมูลสำหรับแต่ละ category ใน tabs ของคุณให้มีจำนวนเพียงพอที่จะแสดงผล
|
|
||||||
// ตัวอย่างเช่น สำหรับ OrgNews
|
|
||||||
{
|
{
|
||||||
id: 14,
|
id: 14,
|
||||||
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 3",
|
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 3: โครงการจัดสวัสดิการบุคลากร",
|
||||||
title_en: "RTAF Org News Item 3",
|
title_en: "RTAF Org News Item 3: Personnel Welfare Project",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 3.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Org News Item 3.",
|
<p>นขต.ทอ. ได้ริเริ่มโครงการจัดสวัสดิการใหม่ เพื่อดูแลบุคลากรและครอบครัว</p>
|
||||||
|
<p>โครงการนี้รวมถึงการสนับสนุนด้านสุขภาพ, การศึกษา, และที่อยู่อาศัย.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>RTAF units have initiated a new welfare project to care for personnel and their families.</p>
|
||||||
|
<p>This project includes support for health, education, and housing.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_4.jpg" },
|
image: { url: "/uploads/news_4.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -413,10 +537,16 @@ export const useAppStore = defineStore('app', {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 15,
|
id: 15,
|
||||||
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 4",
|
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 4: การปรับปรุงโครงสร้างองค์กร",
|
||||||
title_en: "RTAF Org News Item 4",
|
title_en: "RTAF Org News Item 4: Organizational Structure Improvement",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 4.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Org News Item 4.",
|
<p>มีการปรับปรุงโครงสร้างองค์กรภายในกองทัพอากาศ เพื่อเพิ่มประสิทธิภาพในการบริหารจัดการ</p>
|
||||||
|
<p>และรองรับภารกิจที่ซับซ้อนมากยิ่งขึ้น.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The internal organizational structure of the RTAF has been improved to enhance management efficiency</p>
|
||||||
|
<p>and accommodate more complex missions.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_5.jpg" },
|
image: { url: "/uploads/news_5.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -426,10 +556,16 @@ export const useAppStore = defineStore('app', {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 16,
|
id: 16,
|
||||||
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 5",
|
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 5: การจัดตั้งศูนย์นวัตกรรม",
|
||||||
title_en: "RTAF Org News Item 5",
|
title_en: "RTAF Org News Item 5: Innovation Center Establishment",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 5.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Org News Item 5.",
|
<p>กองทัพอากาศได้จัดตั้งศูนย์นวัตกรรมแห่งใหม่ เพื่อเป็นแหล่งบ่มเพาะและพัฒนาแนวคิดใหม่ๆ ด้านการทหารและเทคโนโลยี</p>
|
||||||
|
<p>ศูนย์นี้จะเป็นตัวขับเคลื่อนสำคัญในการสร้างสรรค์สิ่งประดิษฐ์และนวัตกรรม.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>The RTAF has established a new innovation center to foster and develop new concepts in military and technology.</p>
|
||||||
|
<p>This center will be a crucial driver in creating inventions and innovations.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_6.jpg" },
|
image: { url: "/uploads/news_6.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -439,10 +575,16 @@ export const useAppStore = defineStore('app', {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 17,
|
id: 17,
|
||||||
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 6",
|
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 6: กิจกรรมส่งเสริมสุขภาพ",
|
||||||
title_en: "RTAF Org News Item 6",
|
title_en: "RTAF Org News Item 6: Health Promotion Activities",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 6.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Org News Item 6.",
|
<p>มีการจัดกิจกรรมส่งเสริมสุขภาพสำหรับกำลังพลและครอบครัว เพื่อสร้างเสริมสุขภาพที่ดีและลดความเสี่ยงจากโรคต่างๆ</p>
|
||||||
|
<p>กิจกรรมรวมถึงการตรวจสุขภาพประจำปี, การออกกำลังกาย, และการให้ความรู้ด้านโภชนาการ.</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>Health promotion activities are organized for personnel and their families to promote good health and reduce the risk of various diseases.</p>
|
||||||
|
<p>Activities include annual health check-ups, physical exercise, and nutrition education.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_1.jpg" },
|
image: { url: "/uploads/news_1.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -454,8 +596,14 @@ export const useAppStore = defineStore('app', {
|
|||||||
id: 18,
|
id: 18,
|
||||||
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 7 (สำหรับปุ่ม More)",
|
title_th: "ข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 7 (สำหรับปุ่ม More)",
|
||||||
title_en: "RTAF Org News Item 7 (for More button)",
|
title_en: "RTAF Org News Item 7 (for More button)",
|
||||||
detail_th: "รายละเอียดข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 7.",
|
detail_th: `
|
||||||
detail_en: "Details for RTAF Org News Item 7.",
|
<p>รายละเอียดข่าวประชาสัมพันธ์ภายใน ชิ้นที่ 7 เพื่อทดสอบปุ่ม 'ดูเพิ่มเติม' ในหมวดหมู่ข่าวภายใน</p>
|
||||||
|
<p>นี่คือข้อมูลเพิ่มเติมที่สามารถโหลดเข้ามาได้</p>
|
||||||
|
`,
|
||||||
|
detail_en: `
|
||||||
|
<p>Details for RTAF Org News Item 7 for testing the 'Load More' button in the internal news category.</p>
|
||||||
|
<p>This is additional data that can be loaded.</p>
|
||||||
|
`,
|
||||||
image: { url: "/uploads/news_2.jpg" },
|
image: { url: "/uploads/news_2.jpg" },
|
||||||
release_date: "07/07/2025",
|
release_date: "07/07/2025",
|
||||||
active: true,
|
active: true,
|
||||||
@ -520,44 +668,51 @@ export const useAppStore = defineStore('app', {
|
|||||||
this.isTh = !this.isTh;
|
this.isTh = !this.isTh;
|
||||||
},
|
},
|
||||||
|
|
||||||
// *** Action ใหม่: สำหรับ TabNews โดยเฉพาะ (return { data, total }) ***
|
// *** ฟังก์ชันกลางสำหรับดึงข่าวจาก mockNewsData ที่รองรับการกรอง, เรียง, และแบ่งหน้า ***
|
||||||
async fetchTabNews(category, limit = 6) {
|
async fetchNewsFromMockData(options = {}) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate API delay
|
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate API delay
|
||||||
|
|
||||||
|
const { category, limit = 6, page = 1, isFeature = null } = options;
|
||||||
const isTh = this.isTh;
|
const isTh = this.isTh;
|
||||||
// const currentDate = new Date(); // ไม่ต้องใช้แล้ว
|
|
||||||
// currentDate.setHours(0, 0, 0, 0); // ไม่ต้องใช้แล้ว
|
|
||||||
|
|
||||||
// ขั้นตอนที่ 1: กรองข้อมูลทั้งหมดที่เข้าเงื่อนไข (active, type) ก่อนที่จะ apply limit
|
let filteredNews = this.mockNewsData.filter(item => {
|
||||||
const allMatchingNews = this.mockNewsData.filter(item => {
|
|
||||||
const isActive = isTh ? item.active : item.active_en;
|
const isActive = isTh ? item.active : item.active_en;
|
||||||
const isCorrectType = item.type === category;
|
let match = isActive;
|
||||||
|
|
||||||
// ลบส่วนการตรวจสอบวันที่ออกไป
|
// กรองตาม category (type) ถ้ามีการระบุ
|
||||||
// const releaseDateParts = item.release_date ? item.release_date.split('/') : null;
|
if (category) {
|
||||||
// const itemReleaseDate = releaseDateParts ? new Date(parseInt(releaseDateParts[2]), parseInt(releaseDateParts[0]) - 1, parseInt(releaseDateParts[1])) : new Date(0);
|
match = match && item.type === category;
|
||||||
// itemReleaseDate.setHours(0, 0, 0, 0);
|
}
|
||||||
|
|
||||||
// return isActive && isCorrectType && (itemReleaseDate <= currentDate); // เงื่อนไขเก่า
|
// กรองตาม feature ถ้ามีการระบุ
|
||||||
return isActive && isCorrectType; // เงื่อนไขใหม่: ไม่สนใจวันที่
|
if (isFeature !== null) {
|
||||||
|
match = match && item.feature === isFeature;
|
||||||
|
}
|
||||||
|
|
||||||
|
return match;
|
||||||
});
|
});
|
||||||
|
|
||||||
// เก็บจำนวนรวมทั้งหมดก่อนการจำกัด (total count)
|
// เรียงลำดับจากวันที่ใหม่สุดไปเก่าสุด
|
||||||
const totalCount = allMatchingNews.length;
|
filteredNews.sort((a, b) => {
|
||||||
|
const dateA = a.release_date ? new Date(a.release_date.split('/').reverse().join('-')) : new Date(0);
|
||||||
// ขั้นตอนที่ 2: เรียงลำดับข้อมูลที่กรองแล้ว (ยังคงเรียงตามวันที่จากใหม่ไปเก่า)
|
const dateB = b.release_date ? new Date(b.release_date.split('/').reverse().join('-')) : new Date(0);
|
||||||
allMatchingNews.sort((a, b) => {
|
return dateB.getTime() - dateA.getTime(); // ใหม่ไปเก่า
|
||||||
const dateA = a.release_date ? new Date(parseInt(a.release_date.split('/')[2]), parseInt(a.release_date.split('/')[0]) - 1, parseInt(a.release_date.split('/')[1])) : new Date(0);
|
|
||||||
dateA.setHours(0, 0, 0, 0);
|
|
||||||
const dateB = b.release_date ? new Date(parseInt(b.release_date.split('/')[2]), parseInt(b.release_date.split('/')[0]) - 1, parseInt(b.release_date.split('/')[1])) : new Date(0);
|
|
||||||
dateB.setHours(0, 0, 0, 0);
|
|
||||||
return dateB.getTime() - dateA.getTime();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ขั้นตอนที่ 3: จำกัดจำนวนตาม _limit สำหรับข้อมูลที่จะแสดงผล
|
const totalCount = filteredNews.length;
|
||||||
const data = allMatchingNews.slice(0, limit);
|
|
||||||
|
|
||||||
return { data: data, total: totalCount }; // ส่ง Object กลับไปสำหรับ TabNews
|
// คำนวณ offset สำหรับ pagination
|
||||||
|
const startIndex = (page - 1) * limit;
|
||||||
|
const endIndex = startIndex + limit;
|
||||||
|
|
||||||
|
const paginatedData = filteredNews.slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
return { data: paginatedData, total: totalCount };
|
||||||
|
},
|
||||||
|
|
||||||
|
// *** อัปเดต fetchTabNews ให้เรียกใช้ fetchNewsFromMockData ***
|
||||||
|
async fetchTabNews(category, limit = 6, page = 1) { // เพิ่ม page parameter
|
||||||
|
return this.fetchNewsFromMockData({ category, limit, page });
|
||||||
},
|
},
|
||||||
|
|
||||||
// *** Action เดิม: find (ยังคง return เป็น Array เหมือนเดิมสำหรับ endpoint อื่นๆ) ***
|
// *** Action เดิม: find (ยังคง return เป็น Array เหมือนเดิมสำหรับ endpoint อื่นๆ) ***
|
||||||
@ -627,34 +782,30 @@ export const useAppStore = defineStore('app', {
|
|||||||
return dateA - dateB;
|
return dateA - dateB;
|
||||||
});
|
});
|
||||||
|
|
||||||
const limitMatch = queryParams.match(/_limit=(\d+)/);
|
|
||||||
if (limitMatch) {
|
|
||||||
data = data.slice(0, parseInt(limitMatch[1]));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'tabNews':
|
|
||||||
data = this.mockNewsData.filter(item => {
|
|
||||||
const isActive = isTh ? item.active : item.active_en;
|
|
||||||
let match = isActive;
|
|
||||||
if (queryParams.includes('feature=true')) {
|
|
||||||
match = match && item.feature;
|
|
||||||
} else if (queryParams.includes('feature=false')) {
|
|
||||||
match = match && !item.feature;
|
|
||||||
}
|
|
||||||
return match;
|
|
||||||
});
|
|
||||||
|
|
||||||
data.sort((a, b) => {
|
|
||||||
const dateA = new Date(a.release_date.split('/').reverse().join('-'));
|
|
||||||
const dateB = new Date(b.release_date.split('/').reverse().join('-'));
|
|
||||||
return dateA - dateB;
|
|
||||||
});
|
|
||||||
|
|
||||||
const limit = queryParams.match(/_limit=(\d+)/);
|
const limit = queryParams.match(/_limit=(\d+)/);
|
||||||
if (limit) {
|
if (limit) {
|
||||||
data = data.slice(0, parseInt(limit[1]));
|
data = data.slice(0, parseInt(limit[1]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'tabNews':
|
||||||
|
// ใช้ fetchNewsFromMockData เพื่อจัดการการกรอง/แบ่งหน้า
|
||||||
|
// ต้องแยก queryParams ออกมาเป็น object ก่อน
|
||||||
|
const limitMatch = queryParams.match(/_limit=(\d+)/);
|
||||||
|
const isFeatureMatch = queryParams.includes('feature=true') ? true : (queryParams.includes('feature=false') ? false : null);
|
||||||
|
|
||||||
|
// หาก find('news') หรือ find('contents') ต้องการดึงทั้งหมดโดยไม่แบ่งหน้า
|
||||||
|
// เราก็สามารถเรียก fetchNewsFromMockData โดยไม่ส่ง limit/page
|
||||||
|
// หรือถ้าต้องการแบ่งหน้าในอนาคต ก็สามารถส่ง limit/page ได้
|
||||||
|
const result = await this.fetchNewsFromMockData({
|
||||||
|
// category: คุณอาจจะต้องเพิ่ม parameter 'category' เข้าไปใน queryParams string ด้วย ถ้าต้องการกรอง
|
||||||
|
limit: limitMatch ? parseInt(limitMatch[1]) : undefined, // ไม่จำกัดถ้าไม่มี limit ใน queryParams
|
||||||
|
isFeature: isFeatureMatch,
|
||||||
|
// หากต้องการ page สำหรับ find('news') ต้องส่งเข้ามาใน queryParams string ด้วย
|
||||||
|
// เช่น find('news', '_limit=5&_page=2')
|
||||||
|
page: queryParams.match(/_page=(\d+)/) ? parseInt(queryParams.match(/_page=(\d+)/)[1]) : 1
|
||||||
|
});
|
||||||
|
data = result.data; // find action เดิม return แค่ data Array
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Endpoint ${endpoint} not mocked or handled by specific action.`);
|
console.warn(`Endpoint ${endpoint} not mocked or handled by specific action.`);
|
||||||
data = [];
|
data = [];
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
:key="item.id"
|
:key="item.id"
|
||||||
class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition-shadow duration-300"
|
class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition-shadow duration-300"
|
||||||
>
|
>
|
||||||
<router-link :to="`/content/${item.id}`" class="block">
|
<router-link :to="`/tab-news-content/${item.id}`" class="block">
|
||||||
<div class="w-full h-48 overflow-hidden">
|
<div class="w-full h-48 overflow-hidden">
|
||||||
<img
|
<img
|
||||||
v-if="item.image && item.image.url"
|
v-if="item.image && item.image.url"
|
||||||
@ -20,15 +20,15 @@
|
|||||||
:alt="appStore.checkLang.isTh ? item.title_th : item.title_en"
|
:alt="appStore.checkLang.isTh ? item.title_th : item.title_en"
|
||||||
/>
|
/>
|
||||||
<div v-else class="w-full h-full bg-gray-200 flex items-center justify-center text-gray-500">
|
<div v-else class="w-full h-full bg-gray-200 flex items-center justify-center text-gray-500">
|
||||||
No Image
|
{{ appStore.checkLang.isTh ? 'ไม่มีรูปภาพ' : 'No Image' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<h3 class="font-semibold text-lg text-gray-800 hover:text-primary-focus leading-tight mb-2">
|
<h3 class="font-semibold text-lg text-gray-800 hover:text-primary-focus leading-tight mb-2 line-clamp-2">
|
||||||
{{ appStore.checkLang.isTh ? item.title_th : item.title_en }}
|
{{ appStore.checkLang.isTh ? item.title_th : item.title_en }}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-sm text-gray-600 leading-snug mb-3">
|
<p class="text-sm text-gray-600 leading-snug mb-3 line-clamp-3">
|
||||||
{{ truncateDetail(appStore.checkLang.isTh ? item.detail_th : item.detail_en, 120) }}
|
{{ stripHtmlAndTruncate(appStore.checkLang.isTh ? item.detail_th : item.detail_en || '', 120) }}
|
||||||
</p>
|
</p>
|
||||||
<div class="text-xs text-gray-500">
|
<div class="text-xs text-gray-500">
|
||||||
<span v-if="item.release_date">{{ formatDate(item.release_date) }}</span>
|
<span v-if="item.release_date">{{ formatDate(item.release_date) }}</span>
|
||||||
@ -37,7 +37,17 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="text-center text-gray-600 py-16">
|
|
||||||
|
<div v-if="newsList.length > 0 && newsList.length < totalNews" class="flex justify-center mt-8">
|
||||||
|
<button
|
||||||
|
@click="loadMoreNews"
|
||||||
|
class="btn bg-[#1b3872] text-white hover:bg-[#1b3872]/90 rounded-none border-none shadow-md"
|
||||||
|
>
|
||||||
|
{{ appStore.checkLang.isTh ? 'ดูเพิ่มเติม' : 'Load More' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="newsList.length === 0 && !isLoading" class="text-center text-gray-600 py-16">
|
||||||
<p class="text-2xl font-semibold mb-4">
|
<p class="text-2xl font-semibold mb-4">
|
||||||
{{ appStore.checkLang.isTh ? 'ไม่พบข่าวสารในหมวดหมู่นี้ หรือข่าวสารนี้ไม่พร้อมใช้งานในภาษาปัจจุบัน' : 'No news found in this category or not available in the current language.' }}
|
{{ appStore.checkLang.isTh ? 'ไม่พบข่าวสารในหมวดหมู่นี้ หรือข่าวสารนี้ไม่พร้อมใช้งานในภาษาปัจจุบัน' : 'No news found in this category or not available in the current language.' }}
|
||||||
</p>
|
</p>
|
||||||
@ -45,6 +55,15 @@
|
|||||||
{{ appStore.checkLang.isTh ? 'กลับหน้าหลัก' : 'Back to Home' }}
|
{{ appStore.checkLang.isTh ? 'กลับหน้าหลัก' : 'Back to Home' }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="isLoading" class="text-center text-gray-500 py-16">
|
||||||
|
<p class="text-xl flex items-center justify-center">
|
||||||
|
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
{{ appStore.checkLang.isTh ? 'กำลังโหลดข่าวสาร...' : 'Loading news...' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -57,15 +76,18 @@ import { RouterLink } from 'vue-router';
|
|||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const newsList = ref([]);
|
const newsList = ref([]);
|
||||||
|
const totalNews = ref(0);
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const newsPerPage = 6;
|
||||||
|
const isLoading = ref(false);
|
||||||
|
|
||||||
// Computed property เพื่อแสดงชื่อหมวดหมู่ตามภาษา
|
// Computed property เพื่อแสดงชื่อหมวดหมู่ตามภาษา
|
||||||
const categoryTitleTh = computed(() => {
|
const categoryTitleTh = computed(() => {
|
||||||
// เพิ่มการตรวจสอบว่า appStore.tabs มีอยู่จริงหรือไม่ และเป็น Array หรือไม่
|
|
||||||
if (appStore.tabs && Array.isArray(appStore.tabs) && appStore.tabs.length > 0) {
|
if (appStore.tabs && Array.isArray(appStore.tabs) && appStore.tabs.length > 0) {
|
||||||
const tab = appStore.tabs.find(t => t.category === route.params.category);
|
const tab = appStore.tabs.find(t => t.category === route.params.category);
|
||||||
return tab ? tab.title : 'ไม่ระบุหมวดหมู่';
|
return tab ? tab.title : 'ไม่ระบุหมวดหมู่';
|
||||||
}
|
}
|
||||||
return 'กำลังโหลด...';
|
return appStore.checkLang.isTh ? 'กำลังโหลด...' : 'Loading...';
|
||||||
});
|
});
|
||||||
|
|
||||||
const categoryTitleEn = computed(() => {
|
const categoryTitleEn = computed(() => {
|
||||||
@ -73,13 +95,18 @@ const categoryTitleEn = computed(() => {
|
|||||||
const tab = appStore.tabs.find(t => t.category === route.params.category);
|
const tab = appStore.tabs.find(t => t.category === route.params.category);
|
||||||
return tab ? tab.title_en : 'Unspecified Category';
|
return tab ? tab.title_en : 'Unspecified Category';
|
||||||
}
|
}
|
||||||
return 'Loading...';
|
return appStore.checkLang.isTh ? 'Loading...' : 'Loading...';
|
||||||
});
|
});
|
||||||
|
|
||||||
const truncateDetail = (text, maxLength) => {
|
// ** ฟังก์ชันสำหรับลบ HTML tags ออกจาก String ก่อนทำการ truncate **
|
||||||
if (!text) return '';
|
const stripHtmlAndTruncate = (htmlText, maxLength) => {
|
||||||
if (text.length <= maxLength) return text;
|
if (!htmlText) return '';
|
||||||
return text.substring(0, maxLength) + '...';
|
// 1. สร้าง DOMParser เพื่อ parse HTML string
|
||||||
|
const doc = new DOMParser().parseFromString(htmlText, 'text/html');
|
||||||
|
// 2. ดึง textContent ออกมา ซึ่งจะลบ HTML tags ทั้งหมด
|
||||||
|
const plainText = doc.body.textContent || "";
|
||||||
|
// 3. ทำการ truncate text
|
||||||
|
return plainText.length <= maxLength ? plainText : plainText.substring(0, maxLength) + '...';
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatDate = (dateString) => {
|
const formatDate = (dateString) => {
|
||||||
@ -96,38 +123,74 @@ const formatDate = (dateString) => {
|
|||||||
return dateString;
|
return dateString;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchNewsForCategory = async (category) => {
|
const fetchNewsForCategory = async (category, pageToLoad = 1) => {
|
||||||
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
// เพราะ appStore.find ควรจะมีการกรอง active, active_en, release_date และ feature ให้เรียบร้อยแล้ว
|
const result = await appStore.fetchNewsFromMockData({
|
||||||
const allNews = await appStore.find('tabNews', ''); // ดึงข่าวทั้งหมดก่อน เพื่อให้ filter ได้ถูกต้อง
|
category: category,
|
||||||
|
limit: newsPerPage,
|
||||||
const filteredNews = allNews.filter(item => {
|
page: pageToLoad,
|
||||||
return item.type === category;
|
// ใส่ภาษาเข้าไปใน parameter ถ้า fetchNewsFromMockData รองรับ
|
||||||
|
// lang: appStore.isTh ? 'th' : 'en'
|
||||||
});
|
});
|
||||||
|
|
||||||
newsList.value = filteredNews;
|
if (pageToLoad === 1) {
|
||||||
|
newsList.value = result.data;
|
||||||
|
} else {
|
||||||
|
newsList.value = [...newsList.value, ...result.data];
|
||||||
|
}
|
||||||
|
totalNews.value = result.total;
|
||||||
|
currentPage.value = pageToLoad;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error fetching news for category ${category}:`, error);
|
console.error(`Error fetching news for category ${category}:`, error);
|
||||||
newsList.value = [];
|
newsList.value = [];
|
||||||
|
totalNews.value = 0;
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadMoreNews = () => {
|
||||||
|
if (newsList.value.length < totalNews.value && !isLoading.value) {
|
||||||
|
fetchNewsForCategory(route.params.category, currentPage.value + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchNewsForCategory(route.params.category);
|
fetchNewsForCategory(route.params.category, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Watch route params changes to refetch news for new category
|
||||||
watch(() => route.params.category, (newCategory) => {
|
watch(() => route.params.category, (newCategory) => {
|
||||||
fetchNewsForCategory(newCategory);
|
newsList.value = []; // Clear current news
|
||||||
|
currentPage.value = 1; // Reset to first page
|
||||||
|
totalNews.value = 0; // Reset total
|
||||||
|
fetchNewsForCategory(newCategory, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Watch for language changes and re-fetch the news list
|
// Watch language changes to refetch news list
|
||||||
watch(() => appStore.checkLang.isTh, () => { // **แก้ไขตรงนี้**
|
watch(() => appStore.isTh, () => {
|
||||||
fetchNewsForCategory(route.params.category);
|
newsList.value = []; // Clear current news
|
||||||
|
currentPage.value = 1; // Reset to first page
|
||||||
|
totalNews.value = 0; // Reset total
|
||||||
|
fetchNewsForCategory(route.params.category, 1);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* เพิ่ม line-clamp สำหรับ p และ h3 ใน card */
|
||||||
|
.line-clamp-2 {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-clamp-3 {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
168
src/views/TabContentView.vue
Normal file
168
src/views/TabContentView.vue
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// src/views/TabContentView.vue
|
||||||
|
<template>
|
||||||
|
<div class="container mx-auto p-4 md:p-8">
|
||||||
|
<div v-if="newsItem" class="bg-white shadow-lg rounded-lg overflow-hidden">
|
||||||
|
<div class="relative w-full h-64 md:h-96 overflow-hidden">
|
||||||
|
<img
|
||||||
|
v-if="newsItem.image && newsItem.image.url"
|
||||||
|
:src="`${appStore.imageBaseUrl}${newsItem.image.url}`"
|
||||||
|
:alt="appStore.checkLang.isTh ? newsItem.title_th : newsItem.title_en"
|
||||||
|
class="w-full h-full object-cover object-center"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
<div v-else class="w-full h-full bg-gray-200 flex items-center justify-center text-gray-500 text-lg">
|
||||||
|
{{ appStore.checkLang.isTh ? 'ไม่มีรูปภาพ' : 'No Image Available' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-6 md:p-8">
|
||||||
|
<nav class="text-sm text-gray-600 mb-4" aria-label="Breadcrumb">
|
||||||
|
<ol class="list-none p-0 inline-flex">
|
||||||
|
<li class="flex items-center">
|
||||||
|
<router-link to="/home" class="text-blue-600 hover:underline">
|
||||||
|
{{ appStore.checkLang.isTh ? 'หน้าหลัก' : 'Home' }}
|
||||||
|
</router-link>
|
||||||
|
<svg class="fill-current w-3 h-3 mx-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 75.253c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.476 239.029c9.373 9.372 9.373 24.568 0 33.942z"/></svg>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center">
|
||||||
|
<router-link :to="`/tab-news/${newsItem.type}`" class="text-blue-600 hover:underline">
|
||||||
|
{{ appStore.checkLang.isTh ? categoryTitleTh : categoryTitleEn }}
|
||||||
|
</router-link>
|
||||||
|
<svg class="fill-current w-3 h-3 mx-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 75.253c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.476 239.029c9.373 9.372 9.373 24.568 0 33.942z"/></svg>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="text-gray-500">{{ appStore.checkLang.isTh ? newsItem.title_th : newsItem.title_en }}</span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<h1 class="text-3xl md:text-4xl font-bold text-gray-900 mb-4 leading-tight">
|
||||||
|
{{ appStore.checkLang.isTh ? newsItem.title_th : newsItem.title_en }}
|
||||||
|
</h1>
|
||||||
|
<p class="text-sm text-gray-500 mb-6">
|
||||||
|
<span v-if="newsItem.release_date">
|
||||||
|
{{ appStore.checkLang.isTh ? 'เผยแพร่เมื่อ' : 'Published on' }}:
|
||||||
|
<span class="font-medium text-gray-700">{{ formatDate(newsItem.release_date) }}</span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="prose lg:prose-lg max-w-3xl mx-auto text-gray-800 leading-relaxed break-words">
|
||||||
|
<div v-html="appStore.checkLang.isTh ? newsItem.detail_th : newsItem.detail_en"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-8 pt-4 border-t border-gray-200 flex justify-end">
|
||||||
|
<button class="btn bg-[#1b3872] text-white hover:bg-[#1b3872]/90 rounded-none border-none shadow-md">
|
||||||
|
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20"><path d="M15 8a3 3 0 10-2.977-2.909L8 7.239V4.75a3 3 0 00-3-3H4.75a3 3 0 00-3 3v.475a3 3 0 003 3V12h-.25a2.75 2.75 0 000 5.5h.25a2.75 2.75 0 000-5.5H4.75a.75.75 0 010-1.5h.25a.75.75 0 01.75.75v.25c0 .285.068.558.196.804l3.153-1.636a3 3 0 003.545-5.908L15 8zM5 4.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zm9.5 9.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM15 6a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0z"></path></svg>
|
||||||
|
{{ appStore.checkLang.isTh ? 'แชร์' : 'Share' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="text-center text-gray-600 py-16">
|
||||||
|
<p class="text-2xl font-semibold mb-4">
|
||||||
|
{{ appStore.checkLang.isTh ? 'ไม่พบข่าวสารนี้ หรือข่าวสารนี้ไม่พร้อมใช้งานในภาษาปัจจุบัน' : 'News not found or not available in the current language.' }}
|
||||||
|
</p>
|
||||||
|
<router-link to="/home" class="btn bg-[#1b3872] text-white hover:bg-[#1b3872]/90 rounded-none border-none shadow-md">
|
||||||
|
{{ appStore.checkLang.isTh ? 'กลับหน้าหลัก' : 'Back to Home' }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, watch, computed } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useAppStore } from '@/stores/app.js';
|
||||||
|
import { RouterLink } from 'vue-router';
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const route = useRoute();
|
||||||
|
const newsItem = ref(null);
|
||||||
|
|
||||||
|
// Computed property เพื่อดึงชื่อหมวดหมู่สำหรับ Breadcrumbs
|
||||||
|
const categoryTitleTh = computed(() => {
|
||||||
|
if (newsItem.value && appStore.tabs && Array.isArray(appStore.tabs) && appStore.tabs.length > 0) {
|
||||||
|
const tab = appStore.tabs.find(t => t.category === newsItem.value.type);
|
||||||
|
return tab ? tab.title : 'ไม่ระบุหมวดหมู่';
|
||||||
|
}
|
||||||
|
return appStore.checkLang.isTh ? 'กำลังโหลด...' : 'Loading...';
|
||||||
|
});
|
||||||
|
|
||||||
|
const categoryTitleEn = computed(() => {
|
||||||
|
if (newsItem.value && appStore.tabs && Array.isArray(appStore.tabs) && appStore.tabs.length > 0) {
|
||||||
|
const tab = appStore.tabs.find(t => t.category === newsItem.value.type);
|
||||||
|
return tab ? tab.title_en : 'Unspecified Category';
|
||||||
|
}
|
||||||
|
return appStore.checkLang.isTh ? 'Loading...' : 'Loading...';
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const fetchNewsDetail = async (id) => {
|
||||||
|
// ในสถานการณ์จริง จะเรียก API เช่น await axios.get(`/api/news/${id}`);
|
||||||
|
// สำหรับตอนนี้ ใช้ mock data ใน store
|
||||||
|
const foundNews = appStore.mockNewsData.find(item => item.id == id);
|
||||||
|
|
||||||
|
if (foundNews) {
|
||||||
|
// ตรวจสอบ active และ active_en ตามภาษาปัจจุบัน
|
||||||
|
if (appStore.isTh && foundNews.active) {
|
||||||
|
newsItem.value = foundNews;
|
||||||
|
} else if (!appStore.isTh && foundNews.active_en) {
|
||||||
|
newsItem.value = foundNews;
|
||||||
|
} else {
|
||||||
|
newsItem.value = null; // ไม่พบข่าวที่ active ในภาษาปัจจุบัน
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newsItem.value = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
if (!dateString) return '';
|
||||||
|
const parts = dateString.split('/'); // Assumes MM/DD/YYYY
|
||||||
|
if (parts.length === 3) {
|
||||||
|
const [month, day, year] = parts;
|
||||||
|
const dateObj = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
|
||||||
|
const formattedDay = String(dateObj.getDate()).padStart(2, '0');
|
||||||
|
const formattedMonth = String(dateObj.getMonth() + 1).padStart(2, '0');
|
||||||
|
const formattedYear = dateObj.getFullYear();
|
||||||
|
return `${formattedDay}/${formattedMonth}/${formattedYear}`;
|
||||||
|
}
|
||||||
|
return dateString;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchNewsDetail(route.params.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => route.params.id, (newId) => {
|
||||||
|
fetchNewsDetail(newId);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => appStore.isTh, () => {
|
||||||
|
fetchNewsDetail(route.params.id);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* ตัวอย่างการกำหนดความกว้างของเนื้อหา */
|
||||||
|
.prose {
|
||||||
|
max-width: 70ch; /* จำกัดความกว้างของข้อความให้อ่านง่ายขึ้น */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ปรับปรุงการแสดงผลรูปภาพภายในเนื้อหา (ถ้าอยู่ใน detail_th/en) */
|
||||||
|
.prose img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block; /* ทำให้รูปภาพเป็น block level */
|
||||||
|
margin: 1em auto; /* จัดกึ่งกลางและมีระยะห่าง */
|
||||||
|
border-radius: 0.5rem; /* ตัวอย่าง: ขอบมน */
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* ตัวอย่าง: เพิ่มเงา */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* สำหรับภาพปก */
|
||||||
|
.object-cover {
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: center; /* ทำให้รูปภาพอยู่ตรงกลางเมื่อถูก crop */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user