From 4089d1a4482a7536d840fef2dfa0492cc03f6412 Mon Sep 17 00:00:00 2001 From: jingrow Date: Sun, 22 Jun 2025 21:37:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E4=BF=AE=E5=A4=8DISR?= =?UTF-8?q?=E5=A2=9E=E9=87=8F=E9=9D=99=E6=80=81=E5=86=8D=E7=94=9F=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[...slug]/page.jsx | 45 +++------ app/api/get-all-slugs/route.js | 26 ----- app/api/get-page-data/route.js | 125 ------------------------ utlis/data.js | 173 +++++++++++++++++++++++++++++++++ 4 files changed, 188 insertions(+), 181 deletions(-) delete mode 100644 app/api/get-all-slugs/route.js delete mode 100644 app/api/get-page-data/route.js create mode 100644 utlis/data.js diff --git a/app/[...slug]/page.jsx b/app/[...slug]/page.jsx index e8dc7cd..9568683 100644 --- a/app/[...slug]/page.jsx +++ b/app/[...slug]/page.jsx @@ -4,6 +4,7 @@ import { getSiteSettings } from "@/utlis/siteSettings"; import { notFound } from 'next/navigation'; import DynamicListPage from "@/components/common/DynamicListPage"; import { Suspense } from 'react'; +import { getPageData, getAllSlugs } from "@/utlis/data"; const LoadingSpinner = () => (
@@ -11,39 +12,24 @@ const LoadingSpinner = () => (
); -export const revalidate = 3600; +export const revalidate = 10; export const dynamicParams = true; export async function generateStaticParams() { - try { - const res = await fetch(`${process.env.SITE_URL}/api/get-all-slugs`); - if (!res.ok) { - throw new Error(`Failed to fetch slugs: ${res.status}`); - } - const slugs = await res.json(); - if (!Array.isArray(slugs)) { - console.error("generateStaticParams: received non-array from /api/get-all-slugs", slugs); - return []; - } - return slugs.map(slug => ({ - slug: slug, - })); - } catch (error) { - console.error("Could not generate static params:", error); - return []; - } + const slugs = await getAllSlugs(); + return slugs.map(slug => ({ + slug: slug, + })); } export async function generateMetadata({ params }) { const resolvedParams = await params; const slugArr = resolvedParams.slug; - const res = await fetch(`${process.env.SITE_URL}/api/get-page-data`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ slug_list: slugArr }) + const { data, error, page_info } = await getPageData({ + slug_list: slugArr, + downloadFiles: false // Do not download files for metadata }); - const json = await res.json(); - const { data, error, page_info } = json; + if (error) { return { title: error.title || 'Page Error', @@ -70,13 +56,12 @@ export default async function DynamicPage({ params }) { const pageSize = Number(siteSettings.page_size) || 12; // 始终获取第一页的数据用于静态生成 - const res = await fetch(`${process.env.SITE_URL}/api/get-page-data`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ slug_list: slugArr, page: 1, page_size: pageSize }) + const { data, error, total } = await getPageData({ + slug_list: slugArr, + page: 1, + page_size: pageSize, + downloadFiles: true // Download files for page rendering }); - const result = await res.json(); - const { data, error, total } = result; if (error) { notFound(); diff --git a/app/api/get-all-slugs/route.js b/app/api/get-all-slugs/route.js deleted file mode 100644 index 2433fb1..0000000 --- a/app/api/get-all-slugs/route.js +++ /dev/null @@ -1,26 +0,0 @@ -import axios from 'axios'; - -const JINGROW_SERVER_URL = process.env.JINGROW_SERVER_URL; - -export async function GET() { - try { - const response = await axios.get( - `${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_all_slugs` - ); - - const slugs = response.data.message?.data; - - if (!Array.isArray(slugs)) { - console.error('API did not return an array of slugs:', response.data); - return Response.json({ error: '返回的slugs格式不正确' }, { status: 500 }); - } - - return Response.json(slugs); - } catch (error) { - console.error('Error fetching slugs:', error.message, error?.response?.data); - return Response.json( - { error: '获取slugs失败', detail: error?.response?.data || error.message }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/app/api/get-page-data/route.js b/app/api/get-page-data/route.js deleted file mode 100644 index 501ec37..0000000 --- a/app/api/get-page-data/route.js +++ /dev/null @@ -1,125 +0,0 @@ -import axios from 'axios'; -import fs from 'fs'; -import path from 'path'; - -const JINGROW_SERVER_URL = process.env.JINGROW_SERVER_URL; -const PUBLIC_FILES_DIR = path.join(process.cwd(), 'public/files'); - -if (!fs.existsSync(PUBLIC_FILES_DIR)) { - fs.mkdirSync(PUBLIC_FILES_DIR, { recursive: true }); -} - -async function downloadToLocal(fileUrl) { - try { - let fullUrl = fileUrl; - if (!/^https?:\/\//.test(fileUrl)) { - fullUrl = `${JINGROW_SERVER_URL}${fileUrl}`; - } - const fileName = path.basename(fullUrl.split('?')[0]); - const localPath = path.join(PUBLIC_FILES_DIR, fileName); - const localUrl = `/files/${fileName}`; - if (!fs.existsSync(localPath)) { - const response = await axios.get(fullUrl, { responseType: 'stream' }); - await new Promise((resolve, reject) => { - const writer = fs.createWriteStream(localPath); - response.data.pipe(writer); - writer.on('finish', resolve); - writer.on('error', reject); - }); - } - return localUrl; - } catch (e) { - return fileUrl; - } -} - -// 提取富文本中的所有图片链接 -function extractImageUrlsFromHtml(html) { - if (!html) return []; - const regex = /]+src=["']([^"'>]+)["']/g; - const urls = []; - let match; - while ((match = regex.exec(html)) !== null) { - urls.push(match[1]); - } - return urls; -} - -// 替换富文本中的图片链接为本地路径 -async function replaceImageUrlsInHtml(html) { - if (!html) return html; - const regex = /]+)src=["']([^"'>]+)["']/g; - return await html.replace(regex, async (match, pre, url) => { - const localUrl = await downloadToLocal(url); - return ` { + const writer = fs.createWriteStream(localPath); + response.data.pipe(writer); + writer.on('finish', resolve); + writer.on('error', (error) => { + console.error(`Error writing file ${localPath}:`, error); + // Don't reject, just resolve and return original url later + fs.unlink(localPath, () => resolve()); + }); + }); + } + return localUrl; + } catch (e) { + console.error(`Failed to download ${fileUrl}:`, e.message); + return fileUrl; // Return original url on error + } +} + +function extractImageUrlsFromHtml(html) { + if (!html) return []; + const regex = /]+src=["']([^"'>]+)["']/g; + const urls = []; + let match; + while ((match = regex.exec(html)) !== null) { + urls.push(match[1]); + } + return urls; +} + +async function processDataItem(item, downloadFiles) { + if (!downloadFiles) return item; + + if (item.image) { + item.image = await downloadToLocal(item.image); + } + if (item.image_1) { + item.image_1 = await downloadToLocal(item.image_1); + } + if (item.image_2) { + item.image_2 = await downloadToLocal(item.image_2); + } + if (item.video_src) { + item.video_src = await downloadToLocal(item.video_src); + } + if (item.file_src) { + item.file_src = await downloadToLocal(item.file_src); + } + + if (item.items && Array.isArray(item.items)) { + for (const subItem of item.items) { + if (subItem.item_image) { + subItem.item_image = await downloadToLocal(subItem.item_image); + } + if (subItem.item_video_src) { + subItem.item_video_src = await downloadToLocal(subItem.item_video_src); + } + if (subItem.item_icon) { + subItem.item_icon = await downloadToLocal(subItem.item_icon); + } + } + } + + for (const key of ['content', 'additional_content', 'description', 'p1', 'p2', 'p3']) { + if (item[key]) { + const urls = extractImageUrlsFromHtml(item[key]); + let html = item[key]; + for (const url of urls) { + const localUrl = await downloadToLocal(url); + html = html.replaceAll(url, localUrl); + } + item[key] = html; + } + } + return item; +} + +export async function getPageData({ + slug_list, + page = 1, + page_size, + downloadFiles = false +}) { + try { + if (!Array.isArray(slug_list)) { + throw new Error('slug_list must be an array'); + } + + const params = { slug_list: JSON.stringify(slug_list), page }; + if (page_size) params.page_size = page_size; + + const response = await axios.get( + `${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_page_data`, + { params } + ); + + const message = response.data.message; + if (message?.error) { + const errorMsg = typeof message.error === 'object' ? JSON.stringify(message.error) : message.error; + throw new Error(errorMsg); + } + + let data = message?.data; + + if (Array.isArray(data)) { + if(downloadFiles) { + data = await Promise.all(data.map(item => processDataItem(item, downloadFiles))); + } + } else if (data) { + data = await processDataItem(data, downloadFiles); + } + + return { + data: message.data, + total: message.total, + page_info: message.page_info, + }; + } catch (error) { + console.error("Error in getPageData:", error); + return { error: { message: error.message, detail: error?.response?.data || null } }; + } +} + +export async function getAllSlugs() { + try { + const response = await axios.get( + `${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_all_slugs` + ); + const slugs = response.data.message?.data; + if (!Array.isArray(slugs)) { + console.error('API did not return an array of slugs:', response.data); + return []; + } + // Filter out slugs that represent the root page, as it's handled by app/page.jsx + const filteredSlugs = slugs.filter(slug => { + if (!Array.isArray(slug) || slug.length === 0) { + return false; + } + // Exclude slugs like [''] or ['/'] which are for the homepage + if (slug.length === 1 && (slug[0] === '' || slug[0] === '/')) { + return false; + } + return true; + }); + return filteredSlugs; + } catch (error) { + console.error('Error fetching slugs:', error); + return []; + } +} \ No newline at end of file