用户个人中心、兴趣小组
Change-Id: I0e2f3f4ad586f237505613238cbb7bebb6118b63
diff --git a/src/pages/Forum/promotion-part/Promotion.jsx b/src/pages/Forum/promotion-part/Promotion.jsx
index 8ca4067..953a37f 100644
--- a/src/pages/Forum/promotion-part/Promotion.jsx
+++ b/src/pages/Forum/promotion-part/Promotion.jsx
@@ -1,3 +1,829 @@
+// 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}><</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}>></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}><</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}>></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}><</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}>></button>
+// // </div>
+// // )}
+// // </section>
+// // </div>
+// // );
+// // };
+
+// // export default Promotion;
+
+
import React, { useEffect, useState, useRef } from 'react';
import './Promotion.css';
import { useUser } from '../../../context/UserContext';
@@ -123,7 +949,7 @@
discountPercentage: Number(formData.discountPercentage),
uploadCoeff: formData.uploadCoeff ? Number(formData.uploadCoeff) : undefined,
downloadCoeff: formData.downloadCoeff ? Number(formData.downloadCoeff) : undefined,
- applicableTorrentIds: JSON.stringify(applicableTorrentIds), // ✅ 关键修改
+ applicableTorrentIds: applicableTorrentIds,
description: formData.description
};
@@ -135,7 +961,7 @@
body: JSON.stringify(newPromo)
});
const json = await res.json();
- if (json.code === 200) {
+ if (json.code === 200 || json.code === 0) {
alert('促销活动创建成功');
fetchData();
setShowCreateDialog(false);
@@ -154,11 +980,11 @@
try {
const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
const json = await res.json();
- if (json.success) {
+ if (json.code === 0 || json.code === 200) {
alert('删除成功');
fetchData();
} else {
- alert('删除失败: ' + json.message);
+ alert('删除失败: ' + (json.msg || '未知错误'));
}
} catch (err) {
console.error('删除失败:', err);
@@ -310,516 +1136,3 @@
};
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}><</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}>></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}><</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}>></button>
-// </div>
-// )}
-// </section>
-// </div>
-// );
-// };
-
-// export default Promotion;
-