wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 1 | import React, { useState, useEffect } from 'react';
|
| 2 | import { useNavigate } from 'react-router-dom';
|
| 3 | import './SharedStyles.css';
|
22301133 | 0f9623f | 2025-06-06 00:22:05 +0800 | [diff] [blame] | 4 | import { API_BASE_URL } from "./config";
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 5 | import HomeIcon from "@mui/icons-material/Home";
|
| 6 | import MovieIcon from "@mui/icons-material/Movie";
|
| 7 | import TvIcon from "@mui/icons-material/Tv";
|
| 8 | import MusicNoteIcon from "@mui/icons-material/MusicNote";
|
| 9 | import AnimationIcon from "@mui/icons-material/Animation";
|
| 10 | import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
|
| 11 | import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
|
| 12 | import PersonIcon from "@mui/icons-material/Person";
|
| 13 | import AccountCircleIcon from "@mui/icons-material/AccountCircle";
|
| 14 | import ForumIcon from "@mui/icons-material/Forum";
|
| 15 | import HelpIcon from "@mui/icons-material/Help";
|
| 16 | import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
| 17 | import PublishIcon from "@mui/icons-material/Publish";
|
| 18 | import CategoryIcon from "@mui/icons-material/Category";
|
| 19 | import TitleIcon from "@mui/icons-material/Title";
|
| 20 | import DescriptionIcon from "@mui/icons-material/Description";
|
| 21 | import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
| 22 |
|
| 23 | const navItems = [
|
| 24 | { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
|
| 25 | { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
|
| 26 | { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
|
| 27 | { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
|
| 28 | { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
|
| 29 | { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
|
| 30 | { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
|
| 31 | { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
|
| 32 | { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
|
| 33 | { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
|
| 34 | { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
|
| 35 | ];
|
| 36 |
|
| 37 | // 发布页面专用文字雨内容
|
| 38 | const publishTexts = [
|
| 39 | "分享", "上传", "种子", "资源", "贡献", "精品", "原创", "高清",
|
| 40 | "无损", "蓝光", "1080P", "4K", "HDR", "珍藏", "首发", "独家"
|
| 41 | ];
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 42 |
|
| 43 | const PublishPage = () => {
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 44 | const navigate = useNavigate();
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 45 | const [formData, setFormData] = useState({
|
| 46 | type: '',
|
| 47 | torrentFile: '',
|
| 48 | title: '',
|
| 49 | subtitle: ''
|
| 50 | });
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 51 | const [subType, setSubType] = useState('');
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 52 | const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' }); const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });
|
| 53 | const [uploadProgress, setUploadProgress] = useState(0);
|
| 54 | const [isUploading, setIsUploading] = useState(false);
|
| 55 | const [isDragOver, setIsDragOver] = useState(false);
|
| 56 |
|
| 57 | useEffect(() => {
|
| 58 | // 获取用户信息
|
| 59 | const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
|
| 60 | const userId = match ? match[2] : null;
|
| 61 | if (userId) {
|
| 62 | fetch(`${API_BASE_URL}/api/get-userpt?userid=${encodeURIComponent(userId)}`)
|
| 63 | .then(res => res.json())
|
| 64 | .then(data => {
|
| 65 | setUserInfo({ avatar_url: data.user.avatar_url, username: data.user.username });
|
| 66 | setUserPT({
|
| 67 | magic: data.magic_value || data.magic || 0,
|
| 68 | ratio: data.share_ratio || data.share || 0,
|
| 69 | upload: data.upload_amount || data.upload || 0,
|
| 70 | download: data.download_amount || data.download || 0,
|
| 71 | });
|
| 72 | })
|
| 73 | .catch(err => console.error('Fetching user profile failed', err));
|
| 74 | }
|
| 75 | }, []);
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 76 |
|
| 77 | const typeOptions = {
|
| 78 | '电影': ['大陆', '港台', '欧美', '日韩'],
|
| 79 | '剧集': ['国产电视剧', '港剧', '欧美剧', '日韩剧'],
|
| 80 | '音乐': ['古典音乐', '流行音乐', '摇滚', '电子音乐', '说唱'],
|
| 81 | '动漫': ['国创', '日漫', '欧美动漫', '韩漫'],
|
| 82 | '游戏': ['PC', '主机', '移动', '掌机', '视频'],
|
| 83 | '体育': ['篮球', '足球', '羽毛球', '排球', '电竞'],
|
| 84 | '资料': ['出版物', '学习教程', '素材模板', '演讲交流', '日常娱乐'],
|
| 85 | };
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 86 |
|
| 87 | const handleChange = (e) => {
|
| 88 | const { name, value } = e.target;
|
| 89 | setFormData({ ...formData, [name]: value });
|
| 90 | };
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 91 | const handleFileChange = (e) => {
|
| 92 | const file = e.target.files[0];
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 93 | validateAndSetFile(file);
|
| 94 | };
|
| 95 |
|
| 96 | const validateAndSetFile = (file) => {
|
| 97 | if (file && file.name.split('.').pop().toLowerCase() !== 'torrent') {
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 98 | alert('仅能上传.torrent类型文件');
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 99 | return false;
|
| 100 | } else if (file) {
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 101 | setFormData({ ...formData, torrentFile: file });
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 102 | return true;
|
| 103 | }
|
| 104 | return false;
|
| 105 | };
|
| 106 |
|
| 107 | // 拖拽上传功能
|
| 108 | const handleDragEnter = (e) => {
|
| 109 | e.preventDefault();
|
| 110 | e.stopPropagation();
|
| 111 | setIsDragOver(true);
|
| 112 | };
|
| 113 |
|
| 114 | const handleDragLeave = (e) => {
|
| 115 | e.preventDefault();
|
| 116 | e.stopPropagation();
|
| 117 | // 只有当鼠标真正离开拖拽区域时才设置为false
|
| 118 | if (!e.currentTarget.contains(e.relatedTarget)) {
|
| 119 | setIsDragOver(false);
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 120 | }
|
| 121 | };
|
| 122 |
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 123 | const handleDragOver = (e) => {
|
| 124 | e.preventDefault();
|
| 125 | e.stopPropagation();
|
| 126 | };
|
| 127 |
|
| 128 | const handleDrop = (e) => {
|
| 129 | e.preventDefault();
|
| 130 | e.stopPropagation();
|
| 131 | setIsDragOver(false);
|
| 132 |
|
| 133 | const files = e.dataTransfer.files;
|
| 134 | if (files.length > 0) {
|
| 135 | const file = files[0];
|
| 136 | if (validateAndSetFile(file)) {
|
| 137 | // 如果文件验证成功,清空文件输入框并重新设置
|
| 138 | const fileInput = document.getElementById('torrentFile');
|
| 139 | if (fileInput) {
|
| 140 | // 创建一个新的FileList对象来模拟文件选择
|
| 141 | const dt = new DataTransfer();
|
| 142 | dt.items.add(file);
|
| 143 | fileInput.files = dt.files;
|
| 144 | }
|
| 145 | }
|
| 146 | }
|
| 147 | };
|
22301133 | 0f9623f | 2025-06-06 00:22:05 +0800 | [diff] [blame] | 148 | const handleSubmit = async (e) => {
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 149 | e.preventDefault();
|
wht | 338fc03 | 2025-06-09 17:16:22 +0800 | [diff] [blame] | 150 | const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
|
| 151 | const userId = match ? match[2] : null;
|
| 152 |
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 153 | if (!formData.torrentFile) {
|
| 154 | alert('请上传.torrent文件');
|
| 155 | return;
|
| 156 | }
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 157 |
|
| 158 | setIsUploading(true);
|
| 159 | setUploadProgress(0);
|
| 160 |
|
| 161 | // 模拟上传进度
|
| 162 | const progressInterval = setInterval(() => {
|
| 163 | setUploadProgress(prev => {
|
| 164 | if (prev >= 90) {
|
| 165 | clearInterval(progressInterval);
|
| 166 | return prev;
|
| 167 | }
|
| 168 | return prev + Math.random() * 15;
|
| 169 | });
|
| 170 | }, 200);
|
| 171 |
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 172 | const data = new FormData();
|
wht | 338fc03 | 2025-06-09 17:16:22 +0800 | [diff] [blame] | 173 | data.append('userid', userId);
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 174 | data.append('title', formData.title);
|
| 175 | data.append('tag', subType);
|
| 176 | data.append('file', formData.torrentFile);
|
| 177 | data.append('subtitle', formData.subtitle);
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 178 |
|
| 179 | try {
|
22301133 | 0f9623f | 2025-06-06 00:22:05 +0800 | [diff] [blame] | 180 | const response = await fetch(`${API_BASE_URL}/api/save-torrent`, {
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 181 | method: 'POST',
|
| 182 | body: data,
|
| 183 | });
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 184 |
|
| 185 | clearInterval(progressInterval);
|
| 186 | setUploadProgress(100);
|
| 187 |
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 188 | if (response.ok) {
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 189 | setTimeout(() => {
|
| 190 | alert('上传成功!');
|
| 191 | setIsUploading(false);
|
| 192 | setUploadProgress(0);
|
| 193 | // 重置表单
|
| 194 | setFormData({
|
| 195 | type: '',
|
| 196 | torrentFile: '',
|
| 197 | title: '',
|
| 198 | subtitle: ''
|
| 199 | });
|
| 200 | setSubType('');
|
| 201 | }, 500);
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 202 | } else {
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 203 | setIsUploading(false);
|
| 204 | setUploadProgress(0);
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 205 | alert('上传失败');
|
| 206 | }
|
| 207 | } catch (err) {
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 208 | clearInterval(progressInterval);
|
| 209 | setIsUploading(false);
|
| 210 | setUploadProgress(0);
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 211 | alert('网络错误');
|
| 212 | }
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 213 | };
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 214 | return (
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 215 | <div className="emerald-home-container">
|
| 216 | {/* 发布页面专用文字雨 */}
|
| 217 | <div className="publish-text-rain">
|
| 218 | {publishTexts.map((text, index) => (
|
| 219 | <div key={index} className="text-drop" style={{
|
| 220 | left: `${(index * 4) % 100}%`,
|
| 221 | animationDelay: `${(index * 0.9) % 12}s`,
|
| 222 | animationDuration: `${7 + (index % 6)}s`,
|
| 223 | color: index % 3 === 0 ? '#90ee90' : index % 3 === 1 ? '#2d5016' : '#4a7c59'
|
| 224 | }}>
|
| 225 | {text}
|
rhj | c6a4ee0 | 2025-06-06 00:45:18 +0800 | [diff] [blame] | 226 | </div>
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 227 | ))}
|
| 228 | </div>
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 229 |
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 230 | {/* 浮动园林装饰元素 */}
|
| 231 | <div className="floating-garden-elements">
|
| 232 | <div className="garden-element">📤</div>
|
| 233 | <div className="garden-element">🌟</div>
|
| 234 | <div className="garden-element">💎</div>
|
| 235 | <div className="garden-element">🎯</div>
|
| 236 | </div>
|
| 237 |
|
| 238 | <div className="emerald-content">
|
| 239 | {/* NeuraFlux用户栏 */}
|
| 240 | <div className="emerald-user-bar">
|
| 241 | <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
|
| 242 | {userInfo.avatar_url ? (
|
| 243 | <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
|
| 244 | ) : (
|
| 245 | <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
|
| 246 | )}
|
| 247 | </div>
|
| 248 | <div className="emerald-brand-section">
|
| 249 | <div className="emerald-brand-icon">⚡</div>
|
| 250 | <div className="emerald-user-label">NeuraFlux</div>
|
| 251 | </div>
|
| 252 | <div className="emerald-user-stats">
|
| 253 | <span className="emerald-stat-item">
|
| 254 | 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
|
| 255 | </span>
|
| 256 | <span className="emerald-stat-item">
|
| 257 | 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
|
| 258 | </span>
|
| 259 | <span className="emerald-stat-item">
|
| 260 | 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
|
| 261 | </span>
|
| 262 | <span className="emerald-stat-item">
|
| 263 | 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
|
| 264 | </span>
|
| 265 | </div>
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 266 | </div>
|
| 267 |
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 268 | {/* NeuraFlux导航栏 */}
|
| 269 | <nav className="emerald-nav-bar">
|
| 270 | {navItems.map((item) => (
|
| 271 | <div
|
| 272 | key={item.label}
|
| 273 | className={`emerald-nav-item ${item.label === "发布" ? "active" : ""}`}
|
| 274 | data-type={item.type}
|
| 275 | onClick={() => navigate(item.path)}
|
| 276 | >
|
| 277 | {item.icon}
|
| 278 | <span className="emerald-nav-label">{item.label}</span>
|
| 279 | </div>
|
| 280 | ))}
|
| 281 | </nav>
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 282 |
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 283 | {/* 发布页面内容 */}
|
| 284 | <div className="emerald-content-section">
|
| 285 | <h1 className="emerald-page-title">
|
| 286 | <PublishIcon style={{ marginRight: '15px', fontSize: '36px', color: '#2d5016' }} />
|
| 287 | 🌟 NeuraFlux种子发布
|
| 288 | </h1>
|
| 289 | <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '40px', fontStyle: 'italic' }}>
|
| 290 | 分享优质资源,成就精彩社区 • 每一次上传都是对知识传承的贡献
|
| 291 | </p>
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 292 |
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 293 | {/* 发布表单 */}
|
| 294 | <div className="publish-form-container">
|
| 295 | <form onSubmit={handleSubmit} className="publish-form-advanced">
|
| 296 | {/* 资源类型选择 */}
|
| 297 | <div className="form-section">
|
| 298 | <div className="section-header">
|
| 299 | <CategoryIcon style={{ color: '#2d5016', marginRight: '10px' }} />
|
| 300 | <h3>资源分类</h3>
|
| 301 | </div>
|
| 302 | <div className="form-grid">
|
| 303 | <div className="form-field">
|
| 304 | <label htmlFor="type">主要类型</label>
|
| 305 | <div className="select-wrapper">
|
| 306 | <select
|
| 307 | name="type"
|
| 308 | id="type"
|
| 309 | value={formData.type}
|
| 310 | onChange={e => { handleChange(e); setSubType(''); }}
|
| 311 | required
|
| 312 | className="modern-select"
|
| 313 | >
|
| 314 | <option value="">请选择资源类型</option>
|
| 315 | <option value="电影">🎬 电影</option>
|
| 316 | <option value="剧集">📺 剧集</option>
|
| 317 | <option value="音乐">🎵 音乐</option>
|
| 318 | <option value="动漫">🎨 动漫</option>
|
| 319 | <option value="游戏">🎮 游戏</option>
|
| 320 | <option value="体育">⚽ 体育</option>
|
| 321 | <option value="资料">📚 资料</option>
|
| 322 | </select>
|
| 323 | </div>
|
| 324 | </div>
|
| 325 |
|
| 326 | {formData.type && typeOptions[formData.type] && (
|
| 327 | <div className="form-field">
|
| 328 | <label htmlFor="subtype">具体分类</label>
|
| 329 | <div className="select-wrapper">
|
| 330 | <select
|
| 331 | name="subtype"
|
| 332 | id="subtype"
|
| 333 | value={subType}
|
| 334 | onChange={e => setSubType(e.target.value)}
|
| 335 | required
|
| 336 | className="modern-select"
|
| 337 | >
|
| 338 | <option value="">请选择具体分类</option>
|
| 339 | {typeOptions[formData.type].map(opt => (
|
| 340 | <option key={opt} value={opt}>{opt}</option>
|
| 341 | ))}
|
| 342 | </select>
|
| 343 | </div>
|
| 344 | </div>
|
| 345 | )}
|
| 346 | </div>
|
| 347 | </div>
|
| 348 |
|
| 349 | {/* 种子文件上传 */}
|
| 350 | <div className="form-section">
|
| 351 | <div className="section-header">
|
| 352 | <CloudUploadIcon style={{ color: '#2d5016', marginRight: '10px' }} />
|
| 353 | <h3>种子文件</h3>
|
| 354 | </div> <div
|
| 355 | className={`file-upload-area ${isDragOver ? 'drag-over' : ''}`}
|
| 356 | onDragEnter={handleDragEnter}
|
| 357 | onDragLeave={handleDragLeave}
|
| 358 | onDragOver={handleDragOver}
|
| 359 | onDrop={handleDrop}
|
| 360 | >
|
| 361 | <input
|
| 362 | type="file"
|
| 363 | id="torrentFile"
|
| 364 | name="torrentFile"
|
| 365 | onChange={handleFileChange}
|
| 366 | required
|
| 367 | accept=".torrent"
|
| 368 | className="file-input-hidden"
|
| 369 | />
|
| 370 | <label htmlFor="torrentFile" className="file-upload-label">
|
| 371 | <CloudUploadIcon
|
| 372 | style={{
|
| 373 | fontSize: '48px',
|
| 374 | color: isDragOver ? '#2d5016' : '#90ee90',
|
| 375 | marginBottom: '10px',
|
| 376 | transition: 'all 0.3s ease'
|
| 377 | }}
|
| 378 | />
|
| 379 | <div className="upload-text">
|
| 380 | <span className="upload-main-text">
|
| 381 | {isDragOver ?
|
| 382 | '松开鼠标完成上传' :
|
| 383 | (formData.torrentFile ? formData.torrentFile.name : '点击选择或拖拽.torrent文件')
|
| 384 | }
|
| 385 | </span>
|
| 386 | <span className="upload-sub-text">
|
| 387 | {isDragOver ?
|
| 388 | '🎯 即将上传文件到NeuraFlux' :
|
| 389 | '✨ 支持拖拽上传 • 仅接受.torrent格式文件'
|
| 390 | }
|
| 391 | </span>
|
| 392 | </div>
|
| 393 | </label>
|
| 394 | </div>
|
| 395 | </div>
|
| 396 |
|
| 397 | {/* 标题和描述 */}
|
| 398 | <div className="form-section">
|
| 399 | <div className="section-header">
|
| 400 | <TitleIcon style={{ color: '#2d5016', marginRight: '10px' }} />
|
| 401 | <h3>资源信息</h3>
|
| 402 | </div>
|
| 403 | <div className="form-field">
|
| 404 | <label htmlFor="title">资源标题</label>
|
| 405 | <input
|
| 406 | type="text"
|
| 407 | id="title"
|
| 408 | name="title"
|
| 409 | value={formData.title}
|
| 410 | onChange={handleChange}
|
| 411 | required
|
| 412 | className="modern-input"
|
| 413 | placeholder="请输入简洁明确的资源标题..."
|
| 414 | />
|
| 415 | </div>
|
| 416 |
|
| 417 | <div className="form-field">
|
| 418 | <label htmlFor="subtitle">
|
| 419 | <DescriptionIcon style={{ marginRight: '5px', fontSize: '18px' }} />
|
| 420 | 资源简介
|
| 421 | </label>
|
| 422 | <textarea
|
| 423 | id="subtitle"
|
| 424 | name="subtitle"
|
| 425 | value={formData.subtitle}
|
| 426 | onChange={handleChange}
|
| 427 | className="modern-textarea"
|
| 428 | rows="4"
|
| 429 | placeholder="详细描述资源内容、质量、特色等信息..."
|
| 430 | />
|
| 431 | </div>
|
| 432 | </div>
|
| 433 |
|
| 434 | {/* 上传进度条 */}
|
| 435 | {isUploading && (
|
| 436 | <div className="upload-progress-section">
|
| 437 | <div className="progress-header">
|
| 438 | <span>正在上传资源...</span>
|
| 439 | <span>{Math.round(uploadProgress)}%</span>
|
| 440 | </div>
|
| 441 | <div className="progress-bar">
|
| 442 | <div
|
| 443 | className="progress-fill"
|
| 444 | style={{ width: `${uploadProgress}%` }}
|
| 445 | />
|
| 446 | </div>
|
| 447 | </div>
|
| 448 | )}
|
| 449 |
|
| 450 | {/* 提交按钮 */}
|
| 451 | <div className="form-submit-section">
|
| 452 | <button
|
| 453 | type="submit"
|
| 454 | className="publish-submit-btn"
|
| 455 | disabled={isUploading}
|
| 456 | >
|
| 457 | {isUploading ? (
|
| 458 | <>
|
| 459 | <div className="loading-spinner" />
|
| 460 | 上传中...
|
| 461 | </>
|
| 462 | ) : (
|
| 463 | <>
|
| 464 | <CheckCircleIcon style={{ marginRight: '8px', fontSize: '20px' }} />
|
| 465 | 发布资源
|
| 466 | </>
|
| 467 | )}
|
| 468 | </button>
|
| 469 | <div className="submit-tips">
|
| 470 | 💡 请确保上传的资源合法合规,感谢您的贡献!
|
| 471 | </div>
|
| 472 | </div>
|
| 473 | </form>
|
| 474 | </div>
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 475 | </div>
|
wht | 3058782 | 2025-06-09 23:33:09 +0800 | [diff] [blame] | 476 | </div>
|
956303669 | 9e95ae3 | 2025-06-02 21:42:11 +0800 | [diff] [blame] | 477 | </div>
|
| 478 | );
|
| 479 | };
|
| 480 |
|
| 481 | export default PublishPage; |