blob: 8ca4067ce8abb25a2ed3e4d7e08a34b9186aebbb [file] [log] [blame]
import React, { useEffect, useState, useRef } from 'react';
import './Promotion.css';
import { useUser } from '../../../context/UserContext';
const Promotion = () => {
const { user } = useUser();
const [promotions, setPromotions] = useState([]);
const [torrents, setTorrents] = useState([]);
const [loading, setLoading] = useState(true);
const [promoIndex, setPromoIndex] = useState(0);
const promoTimerRef = useRef(null);
// 新增:控制创建对话框显示
const [showCreateDialog, setShowCreateDialog] = useState(false);
// 创建促销活动表单状态
const [formData, setFormData] = useState({
name: '',
startTime: '',
endTime: '',
discountPercentage: '',
uploadCoeff: '',
downloadCoeff: '',
description: ''
});
useEffect(() => {
fetchData();
fetchTorrentList();
}, []);
useEffect(() => {
if (promotions.length === 0) return;
clearInterval(promoTimerRef.current);
promoTimerRef.current = setInterval(() => {
setPromoIndex(prev => (prev + 1) % promotions.length);
}, 5000);
return () => clearInterval(promoTimerRef.current);
}, [promotions]);
const fetchData = async () => {
try {
const response = await fetch('/seeds/promotions');
const json = await response.json();
const promoData = Array.isArray(json?.data) ? json.data : [];
setPromotions(promoData);
} catch (error) {
console.error('获取促销活动失败:', error);
} finally {
setLoading(false);
}
};
const fetchTorrentList = async () => {
try {
const response = await fetch('/seeds/list');
const json = await response.json();
const torrentList = Array.isArray(json?.data) ? json.data : [];
setTorrents(torrentList);
} catch (error) {
console.error('获取种子列表失败:', error);
}
};
// 打开创建促销活动弹窗
const openCreateDialog = () => {
// 重置表单数据
setFormData({
name: '',
startTime: '',
endTime: '',
discountPercentage: '',
uploadCoeff: '',
downloadCoeff: '',
description: ''
});
setShowCreateDialog(true);
};
// 关闭弹窗
const closeCreateDialog = () => {
setShowCreateDialog(false);
};
// 处理表单输入变化
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
// 提交创建促销活动
const handleCreatePromotion = async () => {
if (torrents.length === 0) {
alert('没有可用的种子,请先上传种子');
return;
}
if (!formData.name.trim()) {
alert('促销名称不能为空');
return;
}
if (!formData.startTime || !formData.endTime) {
alert('促销开始时间和结束时间不能为空');
return;
}
if (new Date(formData.startTime) >= new Date(formData.endTime)) {
alert('促销结束时间必须晚于开始时间');
return;
}
if (!formData.discountPercentage || isNaN(formData.discountPercentage)) {
alert('折扣百分比必须是数字');
return;
}
const applicableTorrentIds = torrents.map(t => t.id);
const newPromo = {
name: formData.name,
startTime: new Date(formData.startTime).toISOString(),
endTime: new Date(formData.endTime).toISOString(),
discountPercentage: Number(formData.discountPercentage),
uploadCoeff: formData.uploadCoeff ? Number(formData.uploadCoeff) : undefined,
downloadCoeff: formData.downloadCoeff ? Number(formData.downloadCoeff) : undefined,
applicableTorrentIds: JSON.stringify(applicableTorrentIds), // ✅ 关键修改
description: formData.description
};
try {
const res = await fetch('/seeds/promotions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newPromo)
});
const json = await res.json();
if (json.code === 200) {
alert('促销活动创建成功');
fetchData();
setShowCreateDialog(false);
} else {
alert('创建失败: ' + (json.msg || '未知错误'));
}
} catch (err) {
console.error('创建促销失败:', err);
alert('创建促销失败');
}
};
const handleDeletePromotion = async (promotionId) => {
if (!window.confirm('确认删除该促销活动吗?')) return;
try {
const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
const json = await res.json();
if (json.success) {
alert('删除成功');
fetchData();
} else {
alert('删除失败: ' + json.message);
}
} catch (err) {
console.error('删除失败:', err);
}
};
const isAdmin = user?.role === 'admin';
const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
const currentPromo = promotions[promoIndex];
if (loading) {
return <div className="promotion-container">加载中...</div>;
}
return (
<div className="promotion-container carousel-container">
<section className="carousel-section">
<h2>当前促销活动</h2>
{isAdmin && (
<button className="create-btn" onClick={openCreateDialog}>
创建促销活动
</button>
)}
{promotions.length === 0 || !currentPromo ? (
<div className="empty-state">暂无促销活动</div>
) : (
<div
className="carousel"
onMouseEnter={() => clearInterval(promoTimerRef.current)}
onMouseLeave={() => {
promoTimerRef.current = setInterval(() => {
setPromoIndex(prev => (prev + 1) % promotions.length);
}, 3000);
}}
>
<button className="arrow left" onClick={prevPromo}>&lt;</button>
<div className="slide">
<div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
<div><strong>促销时间:</strong>
{currentPromo?.pStartTime && currentPromo?.pEndTime
? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
: '未知'}
</div>
<div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
<div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
{currentPromo?.description && (
<div><strong>描述:</strong>{currentPromo.description}</div>
)}
{isAdmin && (
<button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
删除该活动
</button>
)}
</div>
<button className="arrow right" onClick={nextPromo}>&gt;</button>
</div>
)}
</section>
{/* 创建促销活动弹窗 */}
{showCreateDialog && (
<div className="dialog-overlay">
<div className="dialog">
<h3>创建促销活动</h3>
<div className="form-item">
<label>促销名称:</label>
<input
type="text"
name="name"
value={formData.name}
onChange={handleInputChange}
placeholder="请输入促销名称"
/>
</div>
<div className="form-item">
<label>开始时间:</label>
<input
type="datetime-local"
name="startTime"
value={formData.startTime}
onChange={handleInputChange}
/>
</div>
<div className="form-item">
<label>结束时间:</label>
<input
type="datetime-local"
name="endTime"
value={formData.endTime}
onChange={handleInputChange}
/>
</div>
<div className="form-item">
<label>折扣百分比(数字):</label>
<input
type="number"
name="discountPercentage"
value={formData.discountPercentage}
onChange={handleInputChange}
placeholder="例如:20 表示 20% 折扣"
min="0"
max="100"
/>
</div>
<div className="form-item">
<label>上传奖励系数(可选):</label>
<input
type="number"
name="uploadCoeff"
value={formData.uploadCoeff}
onChange={handleInputChange}
placeholder="例如:1.5"
step="0.1"
/>
</div>
<div className="form-item">
<label>下载折扣系数(可选):</label>
<input
type="number"
name="downloadCoeff"
value={formData.downloadCoeff}
onChange={handleInputChange}
placeholder="例如:0.8"
step="0.1"
/>
</div>
<div className="form-item">
<label>描述(可选):</label>
<textarea
name="description"
value={formData.description}
onChange={handleInputChange}
placeholder="促销活动描述"
rows={3}
/>
</div>
<div className="dialog-buttons">
<button onClick={handleCreatePromotion}>确定</button>
<button onClick={closeCreateDialog}>取消</button>
</div>
</div>
</div>
)}
</div>
);
};
export default Promotion;
// import React, { useEffect, useState, useRef } from 'react';
// import './Promotion.css';
// import { useUser } from '../../../context/UserContext';
// const Promotion = () => {
// const { user } = useUser();
// const [promotions, setPromotions] = useState([]);
// const [torrents, setTorrents] = useState([]);
// const [loading, setLoading] = useState(true);
// const [promoIndex, setPromoIndex] = useState(0);
// const promoTimerRef = useRef(null);
// // 新增:控制模态框显示与表单状态
// const [showCreateModal, setShowCreateModal] = useState(false);
// const [formData, setFormData] = useState({
// name: '',
// description: '',
// discountPercentage: 0,
// startTime: '',
// endTime: '',
// applicableTorrentIds: [],
// });
// useEffect(() => {
// fetchData();
// fetchTorrentList();
// }, []);
// useEffect(() => {
// if (promotions.length === 0) return;
// clearInterval(promoTimerRef.current);
// promoTimerRef.current = setInterval(() => {
// setPromoIndex(prev => (prev + 1) % promotions.length);
// }, 5000);
// return () => clearInterval(promoTimerRef.current);
// }, [promotions]);
// const fetchData = async () => {
// try {
// const response = await fetch('/seeds/promotions');
// const json = await response.json();
// const promoData = Array.isArray(json?.data) ? json.data : [];
// setPromotions(promoData);
// } catch (error) {
// console.error('获取促销活动失败:', error);
// } finally {
// setLoading(false);
// }
// };
// const fetchTorrentList = async () => {
// try {
// const response = await fetch('/seeds/list');
// const json = await response.json();
// const torrentList = Array.isArray(json?.data) ? json.data : [];
// setTorrents(torrentList);
// } catch (error) {
// console.error('获取种子列表失败:', error);
// }
// };
// // 打开模态框时,重置表单数据,默认设置时间并填入所有种子ID
// const openCreateModal = () => {
// if (torrents.length === 0) {
// alert('没有可用的种子,请先上传种子');
// return;
// }
// setFormData({
// name: '',
// description: '',
// discountPercentage: 20,
// startTime: new Date().toISOString().slice(0, 16), // 用于datetime-local输入框,格式 YYYY-MM-DDTHH:mm
// endTime: new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 16),
// applicableTorrentIds: torrents.map(t => t.id),
// });
// setShowCreateModal(true);
// };
// // 表单输入处理
// const handleInputChange = (e) => {
// const { name, value } = e.target;
// setFormData(prev => ({
// ...prev,
// [name]: name === 'discountPercentage' ? Number(value) : value,
// }));
// };
// // 点击确定提交创建
// const handleCreateConfirm = async () => {
// if (!formData.name) {
// alert('促销名称不能为空');
// return;
// }
// if (!formData.startTime || !formData.endTime) {
// alert('请选择开始时间和结束时间');
// return;
// }
// if (formData.discountPercentage <= 0 || formData.discountPercentage >= 100) {
// alert('折扣百分比应在1-99之间');
// return;
// }
// if (!formData.applicableTorrentIds.length) {
// alert('请选择适用的种子');
// return;
// }
// // 准备发送数据,适配后端字段名
// const newPromo = {
// name: formData.name,
// description: formData.description,
// discountPercentage: formData.discountPercentage,
// startTime: new Date(formData.startTime).toISOString(),
// endTime: new Date(formData.endTime).toISOString(),
// applicableTorrentIds: formData.applicableTorrentIds,
// };
// try {
// const res = await fetch('/seeds/promotions', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(newPromo),
// });
// const json = await res.json();
// if (json.code === 200) {
// alert('促销活动创建成功');
// setShowCreateModal(false);
// fetchData();
// } else {
// alert('创建失败: ' + (json.msg || '未知错误'));
// }
// } catch (err) {
// console.error('创建促销失败:', err);
// alert('创建促销失败');
// }
// };
// const handleCancel = () => {
// setShowCreateModal(false);
// };
// const handleDeletePromotion = async (promotionId) => {
// if (!window.confirm('确认删除该促销活动吗?')) return;
// try {
// const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
// const json = await res.json();
// if (json.success) {
// alert('删除成功');
// fetchData();
// } else {
// alert('删除失败: ' + json.message);
// }
// } catch (err) {
// console.error('删除失败:', err);
// }
// };
// const isAdmin = user?.role === 'admin';
// const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
// const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
// const currentPromo = promotions[promoIndex];
// if (loading) {
// return <div className="promotion-container">加载中...</div>;
// }
// return (
// <div className="promotion-container carousel-container">
// <section className="carousel-section">
// <h2>当前促销活动</h2>
// {isAdmin && (
// <button className="create-btn" onClick={openCreateModal}>
// 创建促销活动
// </button>
// )}
// {promotions.length === 0 || !currentPromo ? (
// <div className="empty-state">暂无促销活动</div>
// ) : (
// <div
// className="carousel"
// onMouseEnter={() => clearInterval(promoTimerRef.current)}
// onMouseLeave={() => {
// promoTimerRef.current = setInterval(() => {
// setPromoIndex(prev => (prev + 1) % promotions.length);
// }, 3000);
// }}
// >
// <button className="arrow left" onClick={prevPromo}>&lt;</button>
// <div className="slide">
// <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
// <div><strong>促销时间:</strong>
// {currentPromo?.startTime && currentPromo?.endTime
// ? `${new Date(currentPromo.startTime).toLocaleString()} ~ ${new Date(currentPromo.endTime).toLocaleString()}`
// : '未知'}
// </div>
// <div><strong>折扣百分比:</strong>{currentPromo?.discountPercentage ?? '无'}</div>
// {currentPromo?.description && (
// <div><strong>描述:</strong>{currentPromo.description}</div>
// )}
// {isAdmin && (
// <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
// 删除该活动
// </button>
// )}
// </div>
// <button className="arrow right" onClick={nextPromo}>&gt;</button>
// </div>
// )}
// </section>
// {/* 创建促销模态框 */}
// {showCreateModal && (
// <div className="modal-overlay">
// <div className="modal-content">
// <h3>创建促销活动</h3>
// <label>
// 促销名称:
// <input
// type="text"
// name="name"
// value={formData.name}
// onChange={handleInputChange}
// />
// </label>
// <label>
// 描述:
// <textarea
// name="description"
// value={formData.description}
// onChange={handleInputChange}
// rows={3}
// />
// </label>
// <label>
// 折扣百分比:
// <input
// type="number"
// name="discountPercentage"
// value={formData.discountPercentage}
// min={1}
// max={99}
// onChange={handleInputChange}
// />
// </label>
// <label>
// 开始时间:
// <input
// type="datetime-local"
// name="startTime"
// value={formData.startTime}
// onChange={handleInputChange}
// />
// </label>
// <label>
// 结束时间:
// <input
// type="datetime-local"
// name="endTime"
// value={formData.endTime}
// onChange={handleInputChange}
// />
// </label>
// <label>
// 适用种子ID(逗号分隔,可留空默认所有):
// <input
// type="text"
// name="applicableTorrentIds"
// value={formData.applicableTorrentIds.join(',')}
// onChange={(e) => {
// const ids = e.target.value
// .split(',')
// .map(id => id.trim())
// .filter(id => id !== '')
// .map(id => Number(id))
// .filter(id => !isNaN(id));
// setFormData(prev => ({ ...prev, applicableTorrentIds: ids }));
// }}
// />
// </label>
// <div className="modal-buttons">
// <button onClick={handleCreateConfirm}>确定</button>
// <button onClick={handleCancel}>取消</button>
// </div>
// </div>
// </div>
// )}
// {/* 模态框简单样式 */}
// <style>{`
// .modal-overlay {
// position: fixed;
// top: 0; left: 0; right: 0; bottom: 0;
// background: rgba(0,0,0,0.4);
// display: flex;
// justify-content: center;
// align-items: center;
// z-index: 999;
// }
// .modal-content {
// background: white;
// padding: 20px;
// border-radius: 6px;
// width: 320px;
// max-width: 90%;
// }
// .modal-content label {
// display: block;
// margin-bottom: 10px;
// font-size: 14px;
// }
// .modal-content input[type="text"],
// .modal-content input[type="number"],
// .modal-content input[type="datetime-local"],
// .modal-content textarea {
// width: 100%;
// box-sizing: border-box;
// padding: 5px;
// font-size: 14px;
// margin-top: 4px;
// }
// .modal-buttons {
// margin-top: 15px;
// text-align: right;
// }
// .modal-buttons button {
// margin-left: 10px;
// padding: 6px 12px;
// font-size: 14px;
// }
// `}</style>
// </div>
// );
// };
// export default Promotion;
// import React, { useEffect, useState, useRef } from 'react';
// import './Promotion.css';
// import { useUser } from '../../../context/UserContext';
// const Promotion = () => {
// const { user } = useUser();
// const [promotions, setPromotions] = useState([]);
// const [torrents, setTorrents] = useState([]); // 新增,存放种子列表
// const [loading, setLoading] = useState(true);
// const [promoIndex, setPromoIndex] = useState(0);
// const promoTimerRef = useRef(null);
// useEffect(() => {
// fetchData();
// fetchTorrentList(); // 新增,获取种子列表
// }, []);
// useEffect(() => {
// if (promotions.length === 0) return;
// clearInterval(promoTimerRef.current);
// promoTimerRef.current = setInterval(() => {
// setPromoIndex(prev => (prev + 1) % promotions.length);
// }, 5000);
// return () => clearInterval(promoTimerRef.current);
// }, [promotions]);
// // 获取促销数据
// const fetchData = async () => {
// try {
// const response = await fetch('/seeds/promotions');
// const json = await response.json();
// const promoData = Array.isArray(json?.data) ? json.data : [];
// setPromotions(promoData);
// } catch (error) {
// console.error('获取促销活动失败:', error);
// } finally {
// setLoading(false);
// }
// };
// // 获取种子列表,赋值给torrents
// const fetchTorrentList = async () => {
// try {
// const response = await fetch('/seeds/list');
// const json = await response.json();
// const torrentList = Array.isArray(json?.data) ? json.data : [];
// setTorrents(torrentList);
// } catch (error) {
// console.error('获取种子列表失败:', error);
// }
// };
// // 创建促销时,自动使用当前种子的id列表,而不是写死
// const handleCreatePromotion = async () => {
// if (torrents.length === 0) {
// alert('没有可用的种子,请先上传种子');
// return;
// }
// const applicableTorrentIds = torrents.map(t => t.id); // 获取所有种子id数组
// const newPromo = {
// name: '测试促销活动',
// startTime: new Date().toISOString(),
// endTime: new Date(Date.now() + 7 * 86400000).toISOString(),
// discountPercentage: 20,
// applicableTorrentIds: applicableTorrentIds, // 动态传入种子ID数组
// description: '这是一个测试促销活动'
// };
// try {
// const res = await fetch('/seeds/promotions', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify(newPromo)
// });
// const json = await res.json();
// if (json.code === 200) {
// alert('促销活动创建成功');
// fetchData();
// } else {
// alert('创建失败: ' + (json.msg || '未知错误'));
// }
// } catch (err) {
// console.error('创建促销失败:', err);
// alert('创建促销失败');
// }
// };
// const handleDeletePromotion = async (promotionId) => {
// if (!window.confirm('确认删除该促销活动吗?')) return;
// try {
// const res = await fetch(`/seeds/promotions/${promotionId}`, {
// method: 'DELETE'
// });
// const json = await res.json();
// if (json.success) {
// alert('删除成功');
// fetchData();
// } else {
// alert('删除失败: ' + json.message);
// }
// } catch (err) {
// console.error('删除失败:', err);
// }
// };
// const isAdmin = user?.role === 'admin';
// const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
// const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
// const currentPromo = promotions[promoIndex];
// if (loading) {
// return <div className="promotion-container">加载中...</div>;
// }
// return (
// <div className="promotion-container carousel-container">
// <section className="carousel-section">
// <h2>当前促销活动</h2>
// {isAdmin && (
// <button className="create-btn" onClick={handleCreatePromotion}>
// 创建促销活动
// </button>
// )}
// {promotions.length === 0 || !currentPromo ? (
// <div className="empty-state">暂无促销活动</div>
// ) : (
// <div
// className="carousel"
// onMouseEnter={() => clearInterval(promoTimerRef.current)}
// onMouseLeave={() => {
// promoTimerRef.current = setInterval(() => {
// setPromoIndex(prev => (prev + 1) % promotions.length);
// }, 3000);
// }}
// >
// <button className="arrow left" onClick={prevPromo}>&lt;</button>
// <div className="slide">
// <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
// <div><strong>促销时间:</strong>
// {currentPromo?.pStartTime && currentPromo?.pEndTime
// ? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
// : '未知'}
// </div>
// <div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
// <div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
// {currentPromo?.description && (
// <div><strong>描述:</strong>{currentPromo.description}</div>
// )}
// {isAdmin && (
// <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
// 删除该活动
// </button>
// )}
// </div>
// <button className="arrow right" onClick={nextPromo}>&gt;</button>
// </div>
// )}
// </section>
// </div>
// );
// };
// export default Promotion;