blob: 2229bb1db589bba3e7fb16d6ed139a35a47e7f68 [file] [log] [blame]
import React, { useEffect, useState } from 'react';
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';
import AuthButton from '../../../components/AuthButton';
const Recommend = () => {
const { user } = useUser();
const [paidLists, setPaidLists] = useState([]);
const [popularSeeds, setPopularSeeds] = 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);
toast.error('获取热门资源失败');
});
}, []);
useEffect(() => {
if (user?.userId) {
axios
.get(`/echo/recommendation/seeds/${user.userId}`)
.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 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>
{user && user.role === 'admin' && (
<button className="create-button" onClick={() => setShowModal(true)}>
创建片单
</button>
)}
<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>
) : (
<AuthButton roles={['chocolate', 'ice-cream']} onClick={() => handlePurchase(list.id)}>
购买
</AuthButton>
)}
</div>
))}
</div>
<h2>🎬 正在热映</h2>
<div className="seed-list popular-row">
{popularSeeds.slice(0, 8).map(renderSeedCard)}
</div>
<h2>🎯 猜你喜欢</h2>
{user ? (
<>
{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>
);
};
export default Recommend;