修改提示框样式、完成付费片单、推荐跳转
Change-Id: Ie84c53d4e306435144b1f26ceb39cc182e99d57a
diff --git a/src/pages/SeedList/Recommend/Recommend.jsx b/src/pages/SeedList/Recommend/Recommend.jsx
index 8270145..f58c73d 100644
--- a/src/pages/SeedList/Recommend/Recommend.jsx
+++ b/src/pages/SeedList/Recommend/Recommend.jsx
@@ -2,48 +2,205 @@
import axios from 'axios';
import './Recommend.css';
import { useUser } from '../../../context/UserContext';
+import { useLocation } from 'wouter';
+import toast from 'react-hot-toast';
+import CreatePlaylistModal from './CreatePlaylistModal';
+import { confirmAlert } from 'react-confirm-alert';
+import 'react-confirm-alert/src/react-confirm-alert.css';
const Recommend = () => {
const { user } = useUser();
+ const [paidLists, setPaidLists] = useState([]);
const [popularSeeds, setPopularSeeds] = useState([]);
- const [recommendedSeeds, setRecommendedSeeds] = useState([]);
+ const [recommendedSeeds, setRecommendedSeeds] = useState({
+ movie: [],
+ tv: [],
+ anime: []
+ });
+
+ const [showModal, setShowModal] = useState(false);
+ const [, navigate] = useLocation();
useEffect(() => {
- // 获取热门资源
+ axios
+ .get('/playlist/page', { params: { page: 1, size: 8 } })
+ .then((res) => {
+ if (res.data.code === 0) {
+ setPaidLists(res.data.data);
+ } else {
+ toast.error(`获取片单失败:${res.data.msg}`);
+ }
+ })
+ .catch((err) => {
+ console.error('请求片单失败', err);
+ toast.error('请求片单失败,请稍后重试');
+ });
+
axios
.get('/echo/recommendation/popular', { params: { limit: 16 } })
.then((res) => setPopularSeeds(res.data))
- .catch((err) => console.error('获取热门资源失败', err));
+ .catch((err) => {
+ console.error('获取热门资源失败', err);
+ toast.error('获取热门资源失败');
+ });
}, []);
useEffect(() => {
- // 获取个性化推荐
- if (user && user.userId) {
+ if (user?.userId) {
axios
.get(`/echo/recommendation/seeds/${user.userId}`)
- .then((res) => setRecommendedSeeds(res.data))
- .catch((err) => console.error('获取个性化推荐失败', err));
+ .then((res) => {
+ const categorized = { movie: [], tv: [], anime: [] };
+ res.data.forEach((seed) => {
+ if (seed.category === 'movie') categorized.movie.push(seed);
+ else if (seed.category === 'tv') categorized.tv.push(seed);
+ else if (seed.category === 'anime') categorized.anime.push(seed);
+ });
+ setRecommendedSeeds(categorized);
+ })
+ .catch((err) => {
+ console.error('获取个性化推荐失败', err);
+ toast.error('获取个性化推荐失败');
+ });
}
}, [user]);
- const renderSeedCard = (seed) => (
- <div className="seed-card" key={seed.id}>
- <img src={seed.coverUrl || '/default-cover.jpg'} alt={seed.title} />
- <div className="title">{seed.title}</div>
- </div>
+ const handleDelete = (id) => {
+ confirmAlert({
+ title: '确认删除',
+ message: '确定删除此片单吗?',
+ buttons: [
+ {
+ label: '确定',
+ onClick: async () => {
+ const toastId = toast.loading('正在删除...');
+ try {
+ await axios.delete('/playlist', {
+ params: { ids: id },
+ paramsSerializer: (params) =>
+ `ids=${Array.isArray(params.ids) ? params.ids.join(',') : params.ids}`
+ });
+ setPaidLists(paidLists.filter((list) => list.id !== id));
+ toast.success('删除成功', { id: toastId });
+ } catch (error) {
+ console.error('删除失败', error);
+ toast.error('删除失败,请稍后重试', { id: toastId });
+ }
+ }
+ },
+ { label: '取消' }
+ ]
+ });
+ };
+
+ const handlePurchase = (id) => {
+ confirmAlert({
+ title: '确认购买',
+ message: '确定支付该片单?',
+ buttons: [
+ {
+ label: '确定',
+ onClick: async () => {
+ const toastId = toast.loading('购买中...');
+ try {
+ const res = await axios.post(`/playlist/${id}/pay`);
+ if (res.data.code === 0) {
+ toast.success('购买成功', { id: toastId });
+ navigate(`/playlist/${id}`);
+ } else {
+ toast.error(`购买失败:${res.data.msg}`, { id: toastId });
+ }
+ } catch (err) {
+ console.error('支付失败', err);
+ toast.error('购买失败,请稍后重试', { id: toastId });
+ }
+ }
+ },
+ { label: '取消' }
+ ]
+ });
+ };
+
+const renderSeedCard = (seed) => (
+ <div
+ className="seed-card"
+ key={seed.id}
+ onClick={() => navigate(`/seed/${seed.id}`)}
+ style={{ cursor: 'pointer' }}
+ >
+ <img src={seed.imageUrl || '/default-cover.jpg'} alt={seed.title} />
+ <div className="title">{seed.title}</div>
+ </div>
+);
+
+
+ const renderSection = (title, seeds) => (
+ <>
+ <h2>{title}</h2>
+ <div className="seed-list">{seeds.map(renderSeedCard)}</div>
+ </>
);
return (
<div className="recommendation-page">
- <h2>🎬 正在热映</h2>
- <div className="seed-list">{popularSeeds.map(renderSeedCard)}</div>
+ <h2>💰 付费片单</h2>
+ {user && user.role === 'admin' && (
+ <button className="create-button" onClick={() => setShowModal(true)}>
+ ➕ 创建片单
+ </button>
+ )}
- <h2>🎯 个性化推荐</h2>
+ <div className="recommend-paid-row">
+ {paidLists.map((list) => (
+ <div className="paid-card" key={list.id}>
+ <img
+ className="paid-cover"
+ src={list.coverUrl || '/default-cover.jpg'}
+ alt={list.title}
+ />
+ <div className="paid-title">{list.title}</div>
+
+ {user && user.role === 'admin' ? (
+ <div className="admin-actions">
+ <button onClick={() => handleDelete(list.id)}>删除</button>
+ </div>
+ ) : list.isPaid ? (
+ <button onClick={() => navigate(`/playlist/${list.id}`)}>详情</button>
+ ) : (
+ <button onClick={() => handlePurchase(list.id)}>购买</button>
+ )}
+ </div>
+ ))}
+ </div>
+
+ <h2>🎬 正在热映</h2>
+ <div className="seed-list popular-row">
+ {popularSeeds.slice(0, 8).map(renderSeedCard)}
+ </div>
+
+ <h2>🎯 猜你喜欢</h2>
{user ? (
- <div className="seed-list">{recommendedSeeds.map(renderSeedCard)}</div>
+ <>
+ {recommendedSeeds.movie.length > 0 &&
+ renderSection('🎞️ 电影推荐', recommendedSeeds.movie)}
+ {recommendedSeeds.tv.length > 0 &&
+ renderSection('📺 电视剧推荐', recommendedSeeds.tv)}
+ {recommendedSeeds.anime.length > 0 &&
+ renderSection('🎌 动漫推荐', recommendedSeeds.anime)}
+ </>
) : (
<div className="login-reminder">请登录以获取个性化推荐</div>
)}
+
+ {showModal && (
+ <CreatePlaylistModal
+ onClose={() => setShowModal(false)}
+ onSuccess={(newPlaylist) => {
+ setPaidLists([newPlaylist, ...paidLists]);
+ setShowModal(false);
+ }}
+ />
+ )}
</div>
);
};