final

Change-Id: Icf4ec3950a6bd1e066fa4a1976af36721af62a06
diff --git a/front/src/PublishPage.js b/front/src/PublishPage.js
index df03cae..d9f7db9 100644
--- a/front/src/PublishPage.js
+++ b/front/src/PublishPage.js
@@ -1,9 +1,47 @@
-import React, { useState } from 'react';

-import './App.css';

-import './PublishPage.css';

+import React, { useState, useEffect } from 'react';

+import { useNavigate } from 'react-router-dom';

+import './SharedStyles.css';

 import { API_BASE_URL } from "./config";

+import HomeIcon from "@mui/icons-material/Home";

+import MovieIcon from "@mui/icons-material/Movie";

+import TvIcon from "@mui/icons-material/Tv";

+import MusicNoteIcon from "@mui/icons-material/MusicNote";

+import AnimationIcon from "@mui/icons-material/Animation";

+import SportsEsportsIcon from "@mui/icons-material/SportsEsports";

+import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";

+import PersonIcon from "@mui/icons-material/Person";

+import AccountCircleIcon from "@mui/icons-material/AccountCircle";

+import ForumIcon from "@mui/icons-material/Forum";

+import HelpIcon from "@mui/icons-material/Help";

+import CloudUploadIcon from "@mui/icons-material/CloudUpload";

+import PublishIcon from "@mui/icons-material/Publish";

+import CategoryIcon from "@mui/icons-material/Category";

+import TitleIcon from "@mui/icons-material/Title";

+import DescriptionIcon from "@mui/icons-material/Description";

+import CheckCircleIcon from "@mui/icons-material/CheckCircle";

+

+const navItems = [

+  { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },

+  { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },

+  { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },

+  { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },

+  { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },

+  { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },

+  { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },

+  { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },

+  { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },

+  { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },

+  { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },

+];

+

+// 发布页面专用文字雨内容

+const publishTexts = [

+  "分享", "上传", "种子", "资源", "贡献", "精品", "原创", "高清",

+  "无损", "蓝光", "1080P", "4K", "HDR", "珍藏", "首发", "独家"

+];

 

 const PublishPage = () => {

+  const navigate = useNavigate();

   const [formData, setFormData] = useState({

     type: '',

     torrentFile: '',

@@ -11,6 +49,30 @@
     subtitle: ''

   });

   const [subType, setSubType] = useState('');

+  const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' });  const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });

+  const [uploadProgress, setUploadProgress] = useState(0);

+  const [isUploading, setIsUploading] = useState(false);

+  const [isDragOver, setIsDragOver] = useState(false);

+

+  useEffect(() => {

+    // 获取用户信息

+    const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');

+    const userId = match ? match[2] : null;

+    if (userId) {

+      fetch(`${API_BASE_URL}/api/get-userpt?userid=${encodeURIComponent(userId)}`)

+        .then(res => res.json())

+        .then(data => {

+          setUserInfo({ avatar_url: data.user.avatar_url, username: data.user.username });

+          setUserPT({

+            magic: data.magic_value || data.magic || 0,

+            ratio: data.share_ratio || data.share || 0,

+            upload: data.upload_amount || data.upload || 0,

+            download: data.download_amount || data.download || 0,

+          });

+        })

+        .catch(err => console.error('Fetching user profile failed', err));

+    }

+  }, []);

 

   const typeOptions = {

     '电影': ['大陆', '港台', '欧美', '日韩'],

@@ -26,17 +88,63 @@
     const { name, value } = e.target;

     setFormData({ ...formData, [name]: value });

   };

-

   const handleFileChange = (e) => {

     const file = e.target.files[0];

-    if (file && file.name.split('.').pop() !== 'torrent') {

+    validateAndSetFile(file);

+  };

+

+  const validateAndSetFile = (file) => {

+    if (file && file.name.split('.').pop().toLowerCase() !== 'torrent') {

       alert('仅能上传.torrent类型文件');

-      e.target.value = null;

-    } else {

+      return false;

+    } else if (file) {

       setFormData({ ...formData, torrentFile: file });

+      return true;

+    }

+    return false;

+  };

+

+  // 拖拽上传功能

+  const handleDragEnter = (e) => {

+    e.preventDefault();

+    e.stopPropagation();

+    setIsDragOver(true);

+  };

+

+  const handleDragLeave = (e) => {

+    e.preventDefault();

+    e.stopPropagation();

+    // 只有当鼠标真正离开拖拽区域时才设置为false

+    if (!e.currentTarget.contains(e.relatedTarget)) {

+      setIsDragOver(false);

     }

   };

 

+  const handleDragOver = (e) => {

+    e.preventDefault();

+    e.stopPropagation();

+  };

+

+  const handleDrop = (e) => {

+    e.preventDefault();

+    e.stopPropagation();

+    setIsDragOver(false);

+

+    const files = e.dataTransfer.files;

+    if (files.length > 0) {

+      const file = files[0];

+      if (validateAndSetFile(file)) {

+        // 如果文件验证成功,清空文件输入框并重新设置

+        const fileInput = document.getElementById('torrentFile');

+        if (fileInput) {

+          // 创建一个新的FileList对象来模拟文件选择

+          const dt = new DataTransfer();

+          dt.items.add(file);

+          fileInput.files = dt.files;

+        }

+      }

+    }

+  };

   const handleSubmit = async (e) => {

     e.preventDefault();

     const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');

@@ -46,6 +154,21 @@
       alert('请上传.torrent文件');

       return;

     }

+

+    setIsUploading(true);

+    setUploadProgress(0);

+

+    // 模拟上传进度

+    const progressInterval = setInterval(() => {

+      setUploadProgress(prev => {

+        if (prev >= 90) {

+          clearInterval(progressInterval);

+          return prev;

+        }

+        return prev + Math.random() * 15;

+      });

+    }, 200);

+

     const data = new FormData();

     data.append('userid', userId);

     data.append('title', formData.title);

@@ -58,84 +181,299 @@
         method: 'POST',

         body: data,

       });

+      

+      clearInterval(progressInterval);

+      setUploadProgress(100);

+      

       if (response.ok) {

-        alert('上传成功!');

+        setTimeout(() => {

+          alert('上传成功!');

+          setIsUploading(false);

+          setUploadProgress(0);

+          // 重置表单

+          setFormData({

+            type: '',

+            torrentFile: '',

+            title: '',

+            subtitle: ''

+          });

+          setSubType('');

+        }, 500);

       } else {

+        setIsUploading(false);

+        setUploadProgress(0);

         alert('上传失败');

       }

     } catch (err) {

+      clearInterval(progressInterval);

+      setIsUploading(false);

+      setUploadProgress(0);

       alert('网络错误');

     }

   };

-

   return (

-    <div className="publish-page">

-      <h1 className="page-title">发布种子</h1>

-      <form onSubmit={handleSubmit} className="publish-form">

-        <div className="form-row">

-          <label htmlFor="type">类型</label>

-          <select name="type" id="type" value={formData.type} onChange={e => { handleChange(e); setSubType(''); }} required>

-            <option value="">请选择类型</option>

-            <option value="电影">电影</option>

-            <option value="剧集">剧集</option>

-            <option value="音乐">音乐</option>

-            <option value="动漫">动漫</option>

-            <option value="游戏">游戏</option>

-            <option value="体育">体育</option>

-            <option value="资料">资料</option>

-          </select>

-        </div>

-        {formData.type && typeOptions[formData.type] && (

-          <div className="form-row">

-            <label htmlFor="subtype">具体类型</label>

-            <select name="subtype" id="subtype" value={subType} onChange={e => setSubType(e.target.value)} required>

-              <option value="">请选择具体类型</option>

-              {typeOptions[formData.type].map(opt => (

-                <option key={opt} value={opt}>{opt}</option>

-              ))}

-            </select>

+    <div className="emerald-home-container">

+      {/* 发布页面专用文字雨 */}

+      <div className="publish-text-rain">

+        {publishTexts.map((text, index) => (

+          <div key={index} className="text-drop" style={{

+            left: `${(index * 4) % 100}%`,

+            animationDelay: `${(index * 0.9) % 12}s`,

+            animationDuration: `${7 + (index % 6)}s`,

+            color: index % 3 === 0 ? '#90ee90' : index % 3 === 1 ? '#2d5016' : '#4a7c59'

+          }}>

+            {text}

           </div>

-        )}

+        ))}

+      </div>

 

-        <div className="form-row">

-          <label htmlFor="torrentFile">种子文件</label>

-          <input

-            type="file"

-            id="torrentFile"

-            name="torrentFile"

-            onChange={handleFileChange}

-            required

-          />

-          <span style={{ fontSize: '12px', color: '#666' }}>需上传.torrent类型文件</span>

+      {/* 浮动园林装饰元素 */}

+      <div className="floating-garden-elements">

+        <div className="garden-element">📤</div>

+        <div className="garden-element">🌟</div>

+        <div className="garden-element">💎</div>

+        <div className="garden-element">🎯</div>

+      </div>

+

+      <div className="emerald-content">

+        {/* NeuraFlux用户栏 */}

+        <div className="emerald-user-bar">

+          <div className="emerald-user-avatar" onClick={() => navigate('/user')}>

+            {userInfo.avatar_url ? (

+              <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />

+            ) : (

+              <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />

+            )}

+          </div>

+          <div className="emerald-brand-section">

+            <div className="emerald-brand-icon">⚡</div>

+            <div className="emerald-user-label">NeuraFlux</div>

+          </div>

+          <div className="emerald-user-stats">

+            <span className="emerald-stat-item">

+              魔力值: <span className="emerald-stat-value">{userPT.magic}</span>

+            </span>

+            <span className="emerald-stat-item">

+              分享率: <span className="emerald-stat-value">{userPT.ratio}</span>

+            </span>

+            <span className="emerald-stat-item">

+              上传: <span className="emerald-stat-value">{userPT.upload}GB</span>

+            </span>

+            <span className="emerald-stat-item">

+              下载: <span className="emerald-stat-value">{userPT.download}GB</span>

+            </span>

+          </div>

         </div>

 

-        <div className="form-row">

-          <label htmlFor="title">标题</label>

-          <input

-            type="text"

-            id="title"

-            name="title"

-            value={formData.title}

-            onChange={handleChange}

-            required

-          />

-        </div>

+        {/* NeuraFlux导航栏 */}

+        <nav className="emerald-nav-bar">

+          {navItems.map((item) => (

+            <div

+              key={item.label}

+              className={`emerald-nav-item ${item.label === "发布" ? "active" : ""}`}

+              data-type={item.type}

+              onClick={() => navigate(item.path)}

+            >

+              {item.icon}

+              <span className="emerald-nav-label">{item.label}</span>

+            </div>

+          ))}

+        </nav>

 

-        <div className="form-row">

-          <label htmlFor="subtitle">种子简介</label>

-          <input

-            type="text"

-            id="subtitle"

-            name="subtitle"

-            value={formData.subtitle}

-            onChange={handleChange}

-          />

-        </div>

+        {/* 发布页面内容 */}

+        <div className="emerald-content-section">

+          <h1 className="emerald-page-title">

+            <PublishIcon style={{ marginRight: '15px', fontSize: '36px', color: '#2d5016' }} />

+            🌟 NeuraFlux种子发布

+          </h1>

+          <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '40px', fontStyle: 'italic' }}>

+            分享优质资源,成就精彩社区 • 每一次上传都是对知识传承的贡献

+          </p>

 

-        <div className="form-row submit-row">

-          <button type="submit" className="submit-button">提交</button>

+          {/* 发布表单 */}

+          <div className="publish-form-container">

+            <form onSubmit={handleSubmit} className="publish-form-advanced">

+              {/* 资源类型选择 */}

+              <div className="form-section">

+                <div className="section-header">

+                  <CategoryIcon style={{ color: '#2d5016', marginRight: '10px' }} />

+                  <h3>资源分类</h3>

+                </div>

+                <div className="form-grid">

+                  <div className="form-field">

+                    <label htmlFor="type">主要类型</label>

+                    <div className="select-wrapper">

+                      <select 

+                        name="type" 

+                        id="type" 

+                        value={formData.type} 

+                        onChange={e => { handleChange(e); setSubType(''); }} 

+                        required

+                        className="modern-select"

+                      >

+                        <option value="">请选择资源类型</option>

+                        <option value="电影">🎬 电影</option>

+                        <option value="剧集">📺 剧集</option>

+                        <option value="音乐">🎵 音乐</option>

+                        <option value="动漫">🎨 动漫</option>

+                        <option value="游戏">🎮 游戏</option>

+                        <option value="体育">⚽ 体育</option>

+                        <option value="资料">📚 资料</option>

+                      </select>

+                    </div>

+                  </div>

+

+                  {formData.type && typeOptions[formData.type] && (

+                    <div className="form-field">

+                      <label htmlFor="subtype">具体分类</label>

+                      <div className="select-wrapper">

+                        <select 

+                          name="subtype" 

+                          id="subtype" 

+                          value={subType} 

+                          onChange={e => setSubType(e.target.value)} 

+                          required

+                          className="modern-select"

+                        >

+                          <option value="">请选择具体分类</option>

+                          {typeOptions[formData.type].map(opt => (

+                            <option key={opt} value={opt}>{opt}</option>

+                          ))}

+                        </select>

+                      </div>

+                    </div>

+                  )}

+                </div>

+              </div>

+

+              {/* 种子文件上传 */}

+              <div className="form-section">

+                <div className="section-header">

+                  <CloudUploadIcon style={{ color: '#2d5016', marginRight: '10px' }} />

+                  <h3>种子文件</h3>

+                </div>                <div 

+                  className={`file-upload-area ${isDragOver ? 'drag-over' : ''}`}

+                  onDragEnter={handleDragEnter}

+                  onDragLeave={handleDragLeave}

+                  onDragOver={handleDragOver}

+                  onDrop={handleDrop}

+                >

+                  <input

+                    type="file"

+                    id="torrentFile"

+                    name="torrentFile"

+                    onChange={handleFileChange}

+                    required

+                    accept=".torrent"

+                    className="file-input-hidden"

+                  />

+                  <label htmlFor="torrentFile" className="file-upload-label">

+                    <CloudUploadIcon 

+                      style={{ 

+                        fontSize: '48px', 

+                        color: isDragOver ? '#2d5016' : '#90ee90', 

+                        marginBottom: '10px',

+                        transition: 'all 0.3s ease'

+                      }} 

+                    />

+                    <div className="upload-text">

+                      <span className="upload-main-text">

+                        {isDragOver ? 

+                          '松开鼠标完成上传' : 

+                          (formData.torrentFile ? formData.torrentFile.name : '点击选择或拖拽.torrent文件')

+                        }

+                      </span>

+                      <span className="upload-sub-text">

+                        {isDragOver ? 

+                          '🎯 即将上传文件到NeuraFlux' :

+                          '✨ 支持拖拽上传 • 仅接受.torrent格式文件'

+                        }

+                      </span>

+                    </div>

+                  </label>

+                </div>

+              </div>

+

+              {/* 标题和描述 */}

+              <div className="form-section">

+                <div className="section-header">

+                  <TitleIcon style={{ color: '#2d5016', marginRight: '10px' }} />

+                  <h3>资源信息</h3>

+                </div>

+                <div className="form-field">

+                  <label htmlFor="title">资源标题</label>

+                  <input

+                    type="text"

+                    id="title"

+                    name="title"

+                    value={formData.title}

+                    onChange={handleChange}

+                    required

+                    className="modern-input"

+                    placeholder="请输入简洁明确的资源标题..."

+                  />

+                </div>

+

+                <div className="form-field">

+                  <label htmlFor="subtitle">

+                    <DescriptionIcon style={{ marginRight: '5px', fontSize: '18px' }} />

+                    资源简介

+                  </label>

+                  <textarea

+                    id="subtitle"

+                    name="subtitle"

+                    value={formData.subtitle}

+                    onChange={handleChange}

+                    className="modern-textarea"

+                    rows="4"

+                    placeholder="详细描述资源内容、质量、特色等信息..."

+                  />

+                </div>

+              </div>

+

+              {/* 上传进度条 */}

+              {isUploading && (

+                <div className="upload-progress-section">

+                  <div className="progress-header">

+                    <span>正在上传资源...</span>

+                    <span>{Math.round(uploadProgress)}%</span>

+                  </div>

+                  <div className="progress-bar">

+                    <div 

+                      className="progress-fill" 

+                      style={{ width: `${uploadProgress}%` }}

+                    />

+                  </div>

+                </div>

+              )}

+

+              {/* 提交按钮 */}

+              <div className="form-submit-section">

+                <button 

+                  type="submit" 

+                  className="publish-submit-btn"

+                  disabled={isUploading}

+                >

+                  {isUploading ? (

+                    <>

+                      <div className="loading-spinner" />

+                      上传中...

+                    </>

+                  ) : (

+                    <>

+                      <CheckCircleIcon style={{ marginRight: '8px', fontSize: '20px' }} />

+                      发布资源

+                    </>

+                  )}

+                </button>

+                <div className="submit-tips">

+                  💡 请确保上传的资源合法合规,感谢您的贡献!

+                </div>

+              </div>

+            </form>

+          </div>

         </div>

-      </form>

+      </div>

     </div>

   );

 };