diff --git a/app/[...slug]/page.jsx b/app/[...slug]/page.jsx
index f5248fc..cd031e9 100644
--- a/app/[...slug]/page.jsx
+++ b/app/[...slug]/page.jsx
@@ -54,7 +54,7 @@ export async function generateMetadata({ params }) {
};
}
-export default async function DynamicPage({ params }) {
+export default async function DynamicPage({ params, searchParams }) {
const resolvedParams = await params;
const slugArr = resolvedParams.slug;
@@ -96,6 +96,7 @@ export default async function DynamicPage({ params }) {
columns={listColumns}
pageSize={pageSize}
totalItems={total}
+ searchParams={searchParams}
/>
diff --git a/app/api/get-page-data/route.js b/app/api/get-page-data/route.js
new file mode 100644
index 0000000..501ec37
--- /dev/null
+++ b/app/api/get-page-data/route.js
@@ -0,0 +1,125 @@
+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 `
({
- slug: item.slug,
- title: item.title,
- image: item.image || item.cover || item.img || '',
- content: item.content || item.description || '',
- }));
- return (
- <>
-
-
- >
- );
- } else if (data) {
- return (
- <>
-
-
-
-
-
-
-
- {/* 图片和附加信息并排显示,响应式优化 */}
- {(data.image || data.subtitle) && (
-
- {data.image && (
-
-

-
- )}
- {data.subtitle && (
-
- {data.subtitle}
-
- )}
-
- )}
- {/* Product Description 标题 */}
-
- Product Description
-
-
- {data.additional_content && (
- <>
- {/* Testing Report 标题 */}
-
- Testing Report
-
-
- >
- )}
-
-
-
-
-
- >
- );
- } else {
- notFound();
- }
-}
diff --git a/app/applications/page.jsx b/app/applications/page.jsx
deleted file mode 100644
index 6d3efe8..0000000
--- a/app/applications/page.jsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import Banner from "@/components/banner/Banner";
-import Category from "@/components/sidebar/Category";
-import Gallery from "@/components/common/Gallery";
-import Pagination1 from "@/components/common/Pagination1";
-import { getSiteSettings } from "@/utils/siteSettings";
-import ListPageTemplate from "@/components/common/ListPageTemplate";
-import { notFound } from 'next/navigation';
-
-const baseSlug = 'applications';
-
-export const revalidate = 3600;
-
-export async function generateMetadata() {
- // 频道首页只需要基础 meta 信息
- return {
- title: 'Applications',
- description: 'Applications Channel Home',
- };
-}
-
-export default async function Page({ searchParams }) {
- const currentPage = Number(searchParams?.page) || 1;
- const siteSettings = await getSiteSettings(process.env.SITE_URL);
- const pageSize = Number(siteSettings.page_size) || 12;
- // 频道首页只查根 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: [baseSlug], page: currentPage, page_size: pageSize })
- });
- const result = await res.json();
- const { data, error, total } = result;
- if (error) notFound();
- const bannerComponentName = 'Banner-' + baseSlug;
- const categoryComponentName = 'Category-' + baseSlug;
- const galleryComponentName = 'Gallery-' + baseSlug;
- const currentPath = '/' + baseSlug;
- const totalPages = Math.ceil((total || 0) / pageSize);
- const listItems = Array.isArray(data) ? data.map(item => ({
- slug: item.slug,
- title: item.title,
- image: item.image || item.cover || item.img || '',
- content: item.content || item.description || '',
- })) : [];
-
- return (
- <>
-
-
- >
- );
-}
diff --git a/app/products/[...slug]/page.jsx b/app/products/[...slug]/page.jsx
index e01aa5f..462a858 100644
--- a/app/products/[...slug]/page.jsx
+++ b/app/products/[...slug]/page.jsx
@@ -40,7 +40,7 @@ export async function generateMetadata({ params }) {
};
}
-export default async function Page({ params }) {
+export default async function Page({ params, searchParams }) {
const resolvedParams = await params;
const slug = resolvedParams.slug || [];
const slugArr = [baseSlug, ...(Array.isArray(slug) ? slug : [slug])];
@@ -79,6 +79,7 @@ export default async function Page({ params }) {
columns={listColumns}
pageSize={pageSize}
totalItems={total}
+ searchParams={searchParams}
/>
diff --git a/components/common/DynamicListPage.jsx b/components/common/DynamicListPage.jsx
deleted file mode 100644
index 12a02a9..0000000
--- a/components/common/DynamicListPage.jsx
+++ /dev/null
@@ -1,77 +0,0 @@
-'use client';
-
-import { useState, useEffect } from 'react';
-import { useSearchParams } from 'next/navigation';
-import ListPageTemplate from '@/components/common/ListPageTemplate';
-import Pagination1 from '@/components/common/Pagination1';
-import axios from 'axios';
-
-const LoadingSpinner = () => (
-
-);
-
-export default function DynamicListPage({ initialItems, slugArr, basePath, columns, pageSize, totalItems }) {
- const [items, setItems] = useState(initialItems);
- const [total, setTotal] = useState(totalItems);
- const [isLoading, setIsLoading] = useState(false);
- const searchParams = useSearchParams();
- const page = searchParams.get('page');
- const currentPage = Number(page) || 1;
-
- useEffect(() => {
- const fetchPageData = async () => {
- if (currentPage === 1) {
- setItems(initialItems);
- setTotal(totalItems);
- return;
- }
- setIsLoading(true);
- try {
- const res = await axios.post('/api/get-page-data', {
- slug_list: slugArr,
- page: currentPage,
- page_size: pageSize,
- });
- setItems(res.data.data);
- setTotal(res.data.total);
- } catch (error) {
- console.error('Failed to fetch page data:', error);
- // Optionally, handle the error in the UI
- } finally {
- setIsLoading(false);
- }
- };
-
- fetchPageData();
- }, [currentPage, slugArr, pageSize, initialItems, totalItems]);
-
- const listItems = items.map(item => ({
- ...item,
- slug: item.slug,
- title: item.title,
- image: item.image || item.cover || item.img || '',
- additional_title: item.additional_title || '',
- subtitle: item.subtitle || item.content || '',
- }));
-
- const totalPages = Math.ceil((total || 0) / pageSize);
-
- return (
- <>
- {isLoading ? (
-
- ) : (
-
- )}
-
- >
- );
-}
\ No newline at end of file
diff --git a/components/common/DynamicListPage/DynamicListPageUI.jsx b/components/common/DynamicListPage/DynamicListPageUI.jsx
new file mode 100644
index 0000000..cf05617
--- /dev/null
+++ b/components/common/DynamicListPage/DynamicListPageUI.jsx
@@ -0,0 +1,35 @@
+'use client';
+
+import ListPageTemplate from '@/components/common/ListPageTemplate';
+import Pagination1 from '@/components/common/Pagination1';
+import { useSearchParams } from 'next/navigation';
+
+export default function DynamicListPageUI({ initialItems, basePath, columns, pageSize, totalItems }) {
+ const searchParams = useSearchParams();
+ const page = searchParams.get('page');
+ const currentPage = Number(page) || 1;
+
+ const listItems = initialItems.map(item => ({
+ ...item,
+ slug: item.slug,
+ title: item.title,
+ image: item.image || item.cover || item.img || '',
+ additional_title: item.additional_title || '',
+ subtitle: item.subtitle || item.content || '',
+ }));
+
+ const totalPages = Math.ceil((totalItems || 0) / pageSize);
+
+ return (
+ <>
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/components/common/DynamicListPage/index.jsx b/components/common/DynamicListPage/index.jsx
new file mode 100644
index 0000000..2a1325a
--- /dev/null
+++ b/components/common/DynamicListPage/index.jsx
@@ -0,0 +1,40 @@
+import DynamicListPageUI from './DynamicListPageUI';
+import { getPageData } from '@/utils/data';
+
+export default async function DynamicListPage({ slugArr, basePath, columns, pageSize = 10, searchParams }) {
+ // 先 await searchParams
+ const resolvedSearchParams = await searchParams;
+ // 解析当前页码
+ const currentPage = Number(resolvedSearchParams?.page) || 1;
+
+ let items = [];
+ let total = 0;
+ let error = null;
+
+ try {
+ const result = await getPageData({
+ slug_list: slugArr,
+ page: currentPage,
+ page_size: pageSize,
+ downloadFiles: true
+ });
+ items = result.data;
+ total = result.total;
+ error = result.error;
+ } catch (e) {
+ items = [];
+ total = 0;
+ error = e;
+ }
+
+ return (
+
+ );
+}
\ No newline at end of file