| import React, { useState, useEffect } from 'react'; |
| import './PromotionsPage.css'; |
| |
| |
| function PromotionsPage() { |
| const [promotions, setPromotions] = useState([]); |
| const [currentPromotion, setCurrentPromotion] = useState(null); |
| const [isAdmin, setIsAdmin] = useState(false); |
| const [isLoading, setIsLoading] = useState(false); |
| const [error, setError] = useState(null); |
| const [formData, setFormData] = useState({ |
| name: '', |
| uploadCoeff: 1, |
| downloadCoeff: 1, |
| timeRange: 0, |
| criteria: 1, |
| pStartTime: '', |
| pEndTime: '' |
| }); |
| const [isCreating, setIsCreating] = useState(false); |
| const [currentPage, setCurrentPage] = useState(1); |
| const [perPage] = useState(10); |
| const [totalPromotions, setTotalPromotions] = useState(0); |
| |
| const getAuthHeaders = () => { |
| const token = localStorage.getItem('token'); |
| return { |
| 'Authorization': token ? `Bearer ${token}` : '', |
| 'Content-Type': 'application/json' |
| }; |
| }; |
| |
| const fetchPromotions = async (page = 1) => { |
| setIsLoading(true); |
| try { |
| const response = await fetch(`/promotions/list?page=${page}&per_page=${perPage}`, { |
| headers: getAuthHeaders() |
| }); |
| |
| if (!response.ok) { |
| throw new Error('获取促销活动失败'); |
| } |
| |
| const data = await response.json(); |
| if (data.code === 0 && data.result) { |
| setPromotions(data.rows || []); |
| setTotalPromotions(data.total || 0); |
| } else { |
| throw new Error(data.msg || '获取促销活动失败'); |
| } |
| } catch (err) { |
| console.error('获取促销活动错误:', err); |
| setError(err.message); |
| } finally { |
| setIsLoading(false); |
| } |
| }; |
| |
| const fetchPromotionDetails = async (promoId) => { |
| setIsLoading(true); |
| try { |
| const response = await fetch(`/promotions/${promoId}`, { |
| headers: getAuthHeaders() |
| }); |
| |
| if (!response.ok) { |
| throw new Error('获取促销详情失败'); |
| } |
| |
| const data = await response.json(); |
| if (data.code === 0 && data.result) { |
| setCurrentPromotion(data.rows); |
| } else { |
| throw new Error(data.msg || '获取促销详情失败'); |
| } |
| } catch (err) { |
| console.error('获取促销详情错误:', err); |
| setError(err.message); |
| } finally { |
| setIsLoading(false); |
| } |
| }; |
| |
| const createPromotion = async () => { |
| if (!formData.name || !formData.pStartTime || !formData.pEndTime) { |
| alert('请填写完整活动信息'); |
| return; |
| } |
| |
| if (new Date(formData.pStartTime) >= new Date(formData.pEndTime)) { |
| alert('活动时间设置不正确,请重新设定'); |
| return; |
| } |
| |
| setIsLoading(true); |
| try { |
| const response = await fetch('/promotions/add', { |
| method: 'POST', |
| headers: getAuthHeaders(), |
| body: JSON.stringify(formData) |
| }); |
| |
| if (!response.ok) { |
| throw new Error('创建促销活动失败'); |
| } |
| |
| const data = await response.json(); |
| if (data.code === 0 && data.result) { |
| alert(`活动创建成功!活动ID: ${data.msg}`); |
| setIsCreating(false); |
| setFormData({ |
| name: '', |
| uploadCoeff: 1, |
| downloadCoeff: 1, |
| timeRange: 0, |
| criteria: 1, |
| pStartTime: '', |
| pEndTime: '' |
| }); |
| fetchPromotions(); |
| } else { |
| throw new Error(data.msg || '创建促销活动失败'); |
| } |
| } catch (err) { |
| console.error('创建促销活动错误:', err); |
| alert(err.message); |
| } finally { |
| setIsLoading(false); |
| } |
| }; |
| |
| const deletePromotion = async (promoId) => { |
| if (!window.confirm('确定要删除这个促销活动吗?')) { |
| return; |
| } |
| |
| setIsLoading(true); |
| try { |
| const response = await fetch(`/promotions/delete/${promoId}`, { |
| method: 'DELETE', |
| headers: getAuthHeaders() |
| }); |
| |
| if (!response.ok) { |
| throw new Error('删除促销活动失败'); |
| } |
| |
| const data = await response.json(); |
| if (data.code === 0 && data.result) { |
| alert('促销活动删除成功'); |
| fetchPromotions(); |
| if (currentPromotion && currentPromotion.promoId === promoId) { |
| setCurrentPromotion(null); |
| } |
| } else { |
| throw new Error(data.msg || '删除促销活动失败'); |
| } |
| } catch (err) { |
| console.error('删除促销活动错误:', err); |
| alert(err.message); |
| } finally { |
| setIsLoading(false); |
| } |
| }; |
| |
| const checkAdminStatus = () => { |
| const role = localStorage.getItem('role'); |
| setIsAdmin(role === 'admin'); |
| }; |
| |
| useEffect(() => { |
| checkAdminStatus(); |
| fetchPromotions(); |
| }, []); |
| |
| const handleInputChange = (e) => { |
| const { name, value } = e.target; |
| setFormData(prev => ({ |
| ...prev, |
| [name]: name === 'uploadCoeff' || name === 'downloadCoeff' || name === 'timeRange' || name === 'criteria' |
| ? parseFloat(value) |
| : value |
| })); |
| }; |
| |
| const handlePageChange = (newPage) => { |
| setCurrentPage(newPage); |
| fetchPromotions(newPage); |
| }; |
| |
| const getPromotionType = (promo) => { |
| if (promo.downloadCoeff === 0 && promo.uploadCoeff > 1) { |
| return '免费'; |
| } else if (promo.downloadCoeff < 1 && promo.uploadCoeff > 1) { |
| return '折扣+上传奖励'; |
| } else if (promo.downloadCoeff < 1) { |
| return '折扣'; |
| } else if (promo.uploadCoeff > 1) { |
| return '上传奖励'; |
| } |
| return '普通'; |
| }; |
| |
| return ( |
| <div className="promotions-page"> |
| <div className="promotions-container"> |
| <h1>促销活动</h1> |
| |
| {isAdmin && ( |
| <div className="admin-actions"> |
| <button |
| className="create-button" |
| onClick={() => setIsCreating(!isCreating)} |
| > |
| {isCreating ? '取消创建' : '创建新活动'} |
| </button> |
| </div> |
| )} |
| |
| {isCreating && isAdmin && ( |
| <div className="create-promotion-form"> |
| <h2>创建新促销活动</h2> |
| <div className="form-group"> |
| <label>活动名称</label> |
| <input |
| type="text" |
| name="name" |
| value={formData.name} |
| onChange={handleInputChange} |
| placeholder="例如: 春节特惠" |
| /> |
| </div> |
| |
| <div className="form-row"> |
| <div className="form-group"> |
| <label>上传量系数</label> |
| <input |
| type="number" |
| name="uploadCoeff" |
| min="0" |
| step="0.1" |
| value={formData.uploadCoeff} |
| onChange={handleInputChange} |
| /> |
| </div> |
| |
| <div className="form-group"> |
| <label>下载量系数</label> |
| <input |
| type="number" |
| name="downloadCoeff" |
| min="0" |
| step="0.1" |
| value={formData.downloadCoeff} |
| onChange={handleInputChange} |
| /> |
| </div> |
| </div> |
| |
| <div className="form-row"> |
| <div className="form-group"> |
| <label>资源时间范围</label> |
| <select |
| name="timeRange" |
| value={formData.timeRange} |
| onChange={handleInputChange} |
| > |
| <option value="0">全站资源</option> |
| <option value="1">当天上传</option> |
| <option value="2">最近两天</option> |
| <option value="7">最近一周</option> |
| <option value="30">最近一个月</option> |
| </select> |
| </div> |
| |
| <div className="form-group"> |
| <label>最低用户等级</label> |
| <input |
| type="number" |
| name="criteria" |
| min="1" |
| value={formData.criteria} |
| onChange={handleInputChange} |
| /> |
| </div> |
| </div> |
| |
| <div className="form-row"> |
| <div className="form-group"> |
| <label>开始时间</label> |
| <input |
| type="datetime-local" |
| name="pStartTime" |
| value={formData.pStartTime} |
| onChange={handleInputChange} |
| /> |
| </div> |
| |
| <div className="form-group"> |
| <label>结束时间</label> |
| <input |
| type="datetime-local" |
| name="pEndTime" |
| value={formData.pEndTime} |
| onChange={handleInputChange} |
| /> |
| </div> |
| </div> |
| |
| <button |
| className="submit-button" |
| onClick={createPromotion} |
| disabled={isLoading} |
| > |
| {isLoading ? '创建中...' : '提交创建'} |
| </button> |
| </div> |
| )} |
| |
| {error && <div className="error-message">{error}</div>} |
| |
| <div className="promotions-grid"> |
| {/* 促销活动列表 */} |
| <div className="promotions-list"> |
| <h2>当前促销活动</h2> |
| {isLoading && promotions.length === 0 ? ( |
| <div className="loading">加载中...</div> |
| ) : promotions.length === 0 ? ( |
| <div className="no-promotions">暂无促销活动</div> |
| ) : ( |
| <div className="promotion-items"> |
| {promotions.map(promo => ( |
| <div |
| key={promo.promoId} |
| className={`promotion-item ${currentPromotion && currentPromotion.promoId === promo.promoId ? 'active' : ''}`} |
| onClick={() => fetchPromotionDetails(promo.promoId)} |
| > |
| <div className="promotion-header"> |
| <h3>{promo.name}</h3> |
| <span className="promotion-type">{getPromotionType(promo)}</span> |
| </div> |
| <div className="promotion-dates"> |
| {new Date(promo.pStartTime).toLocaleString()} - {new Date(promo.pEndTime).toLocaleString()} |
| </div> |
| <div className="promotion-coeffs"> |
| <span>上传: {promo.uploadCoeff}x</span> |
| <span>下载: {promo.downloadCoeff}x</span> |
| </div> |
| {isAdmin && ( |
| <button |
| className="delete-button" |
| onClick={(e) => { |
| e.stopPropagation(); |
| deletePromotion(promo.promoId); |
| }} |
| disabled={isLoading} |
| > |
| 删除 |
| </button> |
| )} |
| </div> |
| ))} |
| </div> |
| )} |
| |
| {totalPromotions > perPage && ( |
| <div className="pagination"> |
| <button |
| disabled={currentPage === 1} |
| onClick={() => handlePageChange(currentPage - 1)} |
| > |
| 上一页 |
| </button> |
| <span>第 {currentPage} 页</span> |
| <button |
| disabled={currentPage * perPage >= totalPromotions} |
| onClick={() => handlePageChange(currentPage + 1)} |
| > |
| 下一页 |
| </button> |
| </div> |
| )} |
| </div> |
| |
| {/* 促销活动详情 */} |
| <div className="promotion-details"> |
| {currentPromotion ? ( |
| <> |
| <h2>{currentPromotion.name}</h2> |
| <div className="detail-item"> |
| <label>活动ID:</label> |
| <span>{currentPromotion.promoId}</span> |
| </div> |
| <div className="detail-item"> |
| <label>活动时间:</label> |
| <span> |
| {new Date(currentPromotion.pStartTime).toLocaleString()} - {new Date(currentPromotion.pEndTime).toLocaleString()} |
| </span> |
| </div> |
| <div className="detail-item"> |
| <label>促销类型:</label> |
| <span>{getPromotionType(currentPromotion)}</span> |
| </div> |
| <div className="detail-item"> |
| <label>上传量系数:</label> |
| <span>{currentPromotion.uploadCoeff}x</span> |
| </div> |
| <div className="detail-item"> |
| <label>下载量系数:</label> |
| <span>{currentPromotion.downloadCoeff}x</span> |
| </div> |
| <div className="detail-item"> |
| <label>适用资源:</label> |
| <span> |
| {currentPromotion.timeRange === 0 |
| ? '全站资源' |
| : `最近${currentPromotion.timeRange}天内上传的资源`} |
| </span> |
| </div> |
| <div className="detail-item"> |
| <label>参与条件:</label> |
| <span>用户等级 ≥ {currentPromotion.criteria}</span> |
| </div> |
| </> |
| ) : ( |
| <div className="no-selection">请从左侧选择一个促销活动查看详情</div> |
| )} |
| </div> |
| </div> |
| </div> |
| </div> |
| ); |
| } |
| |
| export default PromotionsPage; |