修改促销、优化页面布局

Change-Id: Iae813b5b6557efa7059fe6d94bc32e96c984e4ea
diff --git a/src/pages/Forum/promotion-part/PromotionCarousel.jsx b/src/pages/Forum/promotion-part/PromotionCarousel.jsx
new file mode 100644
index 0000000..6408c54
--- /dev/null
+++ b/src/pages/Forum/promotion-part/PromotionCarousel.jsx
@@ -0,0 +1,143 @@
+import React, { useState } from 'react';
+import './PromotionCarousel.css'; 
+
+const PromotionCarousel = ({
+  promotions,
+  isAdmin,
+  openCreateDialog,
+  openCategoryDialog,
+  fetchColdTorrents,
+  handleDeletePromotion,
+  fetchPromotionDetail
+}) => {
+  // 1. 新增状态:跟踪当前轮播项的索引
+  const [currentIndex, setCurrentIndex] = useState(0);
+
+  // 2. 上一个/下一个轮播的逻辑
+  const prevPromo = () => {
+    if (promotions.length === 0) return;
+    setCurrentIndex(prev => 
+      prev === 0 ? promotions.length - 1 : prev - 1
+    );
+  };
+
+  const nextPromo = () => {
+    if (promotions.length === 0) return;
+    setCurrentIndex(prev => 
+      prev === promotions.length - 1 ? 0 : prev + 1
+    );
+  };
+
+  // 3. 当前显示的促销项(从数组中取)
+  const currentPromo = promotions[currentIndex];
+
+  // 原有工具函数保持不变
+  const formatDateTime = (dateTime) => {
+    if (!dateTime) return '未知';
+    // dateTime [2025,1,3,12,10]
+    return new Date(...dateTime).toLocaleString();
+
+  };
+
+  // 修改为一个统一的处理函数,避免混淆
+const getUploadBonusDisplay = (promo) => {
+  if (!promo || typeof promo.discountPercentage !== 'number') return '无';
+  const bonus = promo.discountPercentage;
+  return bonus > 0 ? `${(bonus * 100).toFixed(0)}%` : '无';
+};
+
+const getDownloadDiscountDisplay = (promo) => {
+  if (!promo || typeof promo.discountPercentage !== 'number') return '无';
+  const discount = promo.discountPercentage;
+  return discount < 0 ? `${Math.abs(discount * 100).toFixed(0)}%` : '无';
+};
+
+
+  if (!Array.isArray(promotions) || promotions.length === 0 || !promotions[currentIndex]) {
+  return (
+    <section className="carousel-section">
+      <h2 style={{ marginLeft: '1.6rem' }}>当前促销活动</h2>
+      {isAdmin && (
+        <div style={{ display: 'flex', gap: '0px', marginBottom: '10px' }}>
+          <button className="create-btn" onClick={openCreateDialog}>
+            +创建冷门资源促销
+          </button>
+          <button className="create-btn" onClick={openCategoryDialog}>
+            +创建特定分类促销
+          </button>
+        </div>
+      )}
+      <div className="empty-state">暂无促销活动</div>
+    </section>
+  );
+}
+
+
+  return (
+    <section className="carousel-section">
+      <h2 style={{ marginLeft: '1.6rem' }}>当前促销活动</h2>
+
+      {isAdmin && (
+        <div style={{ display: 'flex', gap: '0px', marginBottom: '10px' }}>
+          <button className="create-btn" onClick={openCreateDialog}>
+            +创建冷门资源促销
+          </button>
+          <button className="create-btn" onClick={openCategoryDialog}>
+            +创建特定分类促销
+          </button>
+        </div>
+      )}
+
+      <div
+        className="carousel"
+        onMouseEnter={() => {}}
+        onMouseLeave={() => {}}
+      >
+
+        <button className="arrow left" onClick={prevPromo}>&lt;</button>
+        <div className="slide">
+          <div className='promotion-name'><strong>{currentPromo?.name ?? '未知'}</strong></div>
+          <div style={{ color: '#135c69' }}><strong>促销时间:</strong>
+            {currentPromo?.startTime && currentPromo?.endTime
+              ? `${formatDateTime(currentPromo.startTime)} ~ ${formatDateTime(currentPromo.endTime)}`
+              : '未知'}
+          </div>
+          <div style={{ color: '#135c69' }}><strong>上传奖励:</strong>{getUploadBonusDisplay(currentPromo)}</div>
+          <div style={{ color: '#135c69' }}><strong>下载折扣:</strong>{getDownloadDiscountDisplay(currentPromo)}</div>
+          {currentPromo?.description && (
+            <div><strong>描述:</strong>{currentPromo.description}</div>
+          )}            
+
+          <div className="action-buttons" style={{ display: 'flex', gap: '10px' }}>
+            {isAdmin && (
+              <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
+                删除活动
+              </button>
+            )}
+            <button
+              className="view-btn"
+              onClick={() => fetchPromotionDetail(currentPromo.id)}
+              aria-label={`查看${currentPromo.name}的详情`}
+            >
+              查看详情
+            </button>
+          </div>
+        </div>
+        <button className="arrow right" onClick={nextPromo}>&gt;</button>
+
+        {/* 4. 新增:底部指示器 */}
+        <div className="carousel-indicators">
+          {promotions.map((_, index) => (
+            <div
+              key={index}
+              className={`indicator ${currentIndex === index ? 'active' : ''}`}
+              onClick={() => setCurrentIndex(index)} // 点击切换轮播项
+            />
+          ))}
+        </div>
+      </div>
+    </section>
+  );
+};
+
+export default PromotionCarousel;
\ No newline at end of file