diff --git a/app/page.jsx b/app/page.jsx
index 41bb75b..f3c148d 100644
--- a/app/page.jsx
+++ b/app/page.jsx
@@ -41,8 +41,15 @@ export default function Page() {
>
diff --git a/components/homes/home-15/CategoryItems.jsx b/components/homes/home-15/CategoryItems.jsx
index 0af6ca2..243548e 100644
--- a/components/homes/home-15/CategoryItems.jsx
+++ b/components/homes/home-15/CategoryItems.jsx
@@ -6,7 +6,7 @@ import Link from "next/link";
import Image from "next/image";
import PropTypes from "prop-types";
-export default function CategoryItems({ pagetype = "", category = "", category_slug = "" , count = 8, columns = 4 }) {
+export default function CategoryItems({ pagetype = "", category = "", category_slug = "" , count = 8, columns = 4, title = "", subtitle = "" }) {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
@@ -133,7 +133,14 @@ export default function CategoryItems({ pagetype = "", category = "", category_s
}
return (
-
+
+ {/* 新增模块标题和副标题显示 */}
+ {(title || subtitle) && (
+
+ {title &&
{title}
}
+ {subtitle &&
{subtitle}
}
+
+ )}
{loading ? (
加载中...
@@ -212,6 +219,17 @@ export default function CategoryItems({ pagetype = "", category = "", category_s
))
)}
+ {/* 底部更多按钮 */}
+ {category_slug && (
+
+ )}
);
}
@@ -225,4 +243,6 @@ CategoryItems.propTypes = {
]),
columns: PropTypes.number,
category_slug: PropTypes.string,
+ title: PropTypes.string,
+ subtitle: PropTypes.string,
};
diff --git a/components/homes/home-15/SwiperItems.jsx b/components/homes/home-15/SwiperItems.jsx
new file mode 100644
index 0000000..a202b30
--- /dev/null
+++ b/components/homes/home-15/SwiperItems.jsx
@@ -0,0 +1,253 @@
+"use client";
+import { useEffect, useState } from "react";
+import { Swiper, SwiperSlide } from "swiper/react";
+import { Navigation, Pagination, Grid } from "swiper/modules";
+import Link from "next/link";
+import Image from "next/image";
+import PropTypes from "prop-types";
+
+export default function SwiperItems({ pagetype = "", category = "", category_slug = "" , count = 8, columns = 4, rows = 1 }) {
+ const [posts, setPosts] = useState([]);
+ const [loading, setLoading] = useState(false);
+
+ useEffect(() => {
+ async function fetchData() {
+ setLoading(true);
+ try {
+ const params = new URLSearchParams({ pagetype });
+ if (category) params.append("category", category);
+ if (count !== undefined && count !== null) params.append("count", count);
+ const res = await fetch(`/api/get-listview-data?${params.toString()}`);
+ const json = await res.json();
+ if (Array.isArray(json.data)) {
+ setPosts(json.data);
+ } else {
+ setPosts([]);
+ }
+ } catch (e) {
+ setPosts([]);
+ }
+ setLoading(false);
+ }
+ fetchData();
+ }, [pagetype, category, count]);
+
+ // 渲染卡片内容
+ function renderCardImage(post, idx) {
+ // 多图轮播
+ if (Array.isArray(post.images) && post.images.length > 1) {
+ return (
+
+ {post.images.map((img, i) => (
+
+
+
+ ))}
+
+ );
+ }
+ // 视频
+ if (post.video_src || post.videoId) {
+ if (post.video_src && (post.video_src.endsWith('.mp4') || post.video_src.startsWith('/files/'))) {
+ return (
+
+ );
+ }
+ const vid = post.videoId || (post.video_src && post.video_src.includes('youtube') ? post.video_src.split('embed/')[1] : null);
+ if (vid) {
+ return (
+
+ );
+ }
+ }
+ // 单图
+ const img = post.image || (Array.isArray(post.images) && post.images[0]);
+ if (img) {
+ return (
+
+ );
+ }
+ return null;
+ }
+
+ function getSummary(text, maxLen = 60) {
+ if (!text) return "";
+ // 中文:直接按字符截断
+ if (/[\u4e00-\u9fa5]/.test(text)) {
+ return text.length > maxLen ? text.slice(0, maxLen) + "..." : text;
+ }
+ // 英文:按字符截断,但不截断单词
+ if (text.length <= maxLen) return text;
+ let cut = text.slice(0, maxLen);
+ // 如果最后一个字符不是空格,向前找到最近的空格
+ if (!/\s/.test(text[maxLen])) {
+ const lastSpace = cut.lastIndexOf(" ");
+ if (lastSpace > 0) cut = cut.slice(0, lastSpace);
+ }
+ return cut + "...";
+ }
+
+ // 日期格式化函数,支持自定义是否显示时分秒
+ function formatDate(dateStr, options = {}) {
+ if (!dateStr) return "";
+ const d = new Date(dateStr);
+ if (isNaN(d.getTime())) return dateStr;
+ const { showTime = false } = options;
+ const yyyy = d.getFullYear();
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
+ const dd = String(d.getDate()).padStart(2, '0');
+ let result = `${yyyy}-${mm}-${dd}`;
+ if (showTime) {
+ const hh = String(d.getHours()).padStart(2, '0');
+ const min = String(d.getMinutes()).padStart(2, '0');
+ const ss = String(d.getSeconds()).padStart(2, '0');
+ result += ` ${hh}:${min}:${ss}`;
+ }
+ return result;
+ }
+
+ return (
+
+
+ {loading ? (
+
加载中...
+ ) : posts.length === 0 ? (
+
暂无数据
+ ) : (
+
1 ? 2 : 1 } },
+ 992: { slidesPerView: columns, grid: { rows } },
+ }}
+ >
+ {posts.map((post, idx) => (
+
+
+
+ {/* 图片/轮播/视频部分 */}
+
+
+ {renderCardImage(post, idx)}
+
+
+
+ 查看详情
+
+
+
+
+ {/* 文字内容 */}
+
+
+
+
+
+ {post.title}
+
+
+
+
+
{getSummary(post.subtitle)}
+
+
+ {/* 底部信息 */}
+
+
+ -
+
+ {formatDate(post.creation)}
+
+ {post.author && (
+ -
+
+ {post.author}
+
+ )}
+ {typeof post.comments === 'number' && (
+ -
+
+
+ {post.comments}
+
+
+ )}
+ {typeof post.likes === 'number' && (
+ -
+
+
+ {post.likes}
+
+
+ )}
+
+
+
+
+
+ ))}
+
+ )}
+
+
+
+ );
+}
+
+SwiperItems.propTypes = {
+ pagetype: PropTypes.string,
+ category: PropTypes.string,
+ count: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number
+ ]),
+ columns: PropTypes.number,
+ category_slug: PropTypes.string,
+ rows: PropTypes.number,
+};