| // 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'; |
| |
| 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: 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 || json.code === 0) { |
| 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.code === 0 || json.code === 200) { |
| alert('删除成功'); |
| fetchData(); |
| } else { |
| alert('删除失败: ' + (json.msg || '未知错误')); |
| } |
| } 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; |