22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 1 | // export default PublishSeed; |
| 2 | import React, { useState, useRef, useEffect } from 'react'; |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 3 | import axios from 'axios'; |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 4 | import Header from '../../components/Header'; |
| 5 | import './PublishSeed.css'; |
| 6 | import { useUser } from '../../context/UserContext'; |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 7 | |
| 8 | const PublishSeed = () => { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 9 | console.log('[DEBUG] PublishSeed 组件渲染'); |
| 10 | |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 11 | const [title, setTitle] = useState(''); |
| 12 | const [description, setDescription] = useState(''); |
| 13 | const [tags, setTags] = useState([]); |
| 14 | const [category, setCategory] = useState('movie'); |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 15 | const [message, setMessage] = useState(''); |
| 16 | const [isLoading, setIsLoading] = useState(false); |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 17 | const [fileName, setFileName] = useState(''); |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 18 | const [imageFile, setImageFile] = useState(null); |
| 19 | const [previewUrl, setPreviewUrl] = useState(''); |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 20 | |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 21 | const fileInputRef = useRef(null); |
| 22 | const imageInputRef = useRef(null); |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 23 | const { user } = useUser(); |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 24 | |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 25 | useEffect(() => { |
| 26 | console.log('[DEBUG] 当前用户:', user); |
| 27 | }, [user]); |
| 28 | |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 29 | const handleTagsChange = (e) => { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 30 | console.log('[DEBUG] 标签输入变化:', e.target.value); |
| 31 | setTags(e.target.value.split(',').map(tag => tag.trim()).filter(Boolean)); |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 32 | }; |
| 33 | |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 34 | const handleFileButtonClick = () => { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 35 | console.log('[DEBUG] 触发文件选择按钮点击'); |
| 36 | fileInputRef.current?.click(); |
| 37 | }; |
| 38 | |
| 39 | const handleImageButtonClick = () => { |
| 40 | console.log('[DEBUG] 触发封面图片选择按钮点击'); |
| 41 | imageInputRef.current?.click(); |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 42 | }; |
| 43 | |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 44 | const handleFileChange = (e) => { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 45 | console.log('[DEBUG] 种子文件选择变化:', e.target.files); |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 46 | const selectedFile = e.target.files[0]; |
| 47 | if (selectedFile) { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 48 | setFileName(selectedFile.name); |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 49 | } |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 50 | }; |
| 51 | |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 52 | const handleImageChange = (e) => { |
| 53 | console.log('[DEBUG] 封面图片选择变化:', e.target.files); |
| 54 | const img = e.target.files[0]; |
| 55 | if (!img) return; |
| 56 | setImageFile(img); |
| 57 | setPreviewUrl(URL.createObjectURL(img)); |
| 58 | }; |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 59 | |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 60 | const handleSubmit = async (e) => { |
| 61 | console.log('[DEBUG] handleSubmit 被触发', e); |
| 62 | e.preventDefault(); |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 63 | |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 64 | setIsLoading(true); |
| 65 | setMessage(''); |
| 66 | |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 67 | const currentFile = fileInputRef.current?.files[0]; |
| 68 | console.log('[DEBUG] 当前选择文件:', currentFile); |
| 69 | |
| 70 | if (!user || !user.userId) { |
| 71 | console.log('[DEBUG] 用户未登录,阻止上传'); |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 72 | setMessage('请先登录'); |
| 73 | setIsLoading(false); |
| 74 | return; |
| 75 | } |
| 76 | |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 77 | if (!currentFile || !currentFile.name.toLowerCase().endsWith('.torrent')) { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 78 | console.log('[DEBUG] 文件校验失败'); |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 79 | setMessage('请上传一个 .torrent 文件'); |
| 80 | setIsLoading(false); |
| 81 | return; |
| 82 | } |
| 83 | |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 84 | const formData = new FormData(); |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 85 | formData.append('file', currentFile); |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 86 | formData.append('title', title); |
| 87 | formData.append('description', description); |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 88 | formData.append('category', category); |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 89 | formData.append('tags', tags.join(',')); // 逗号分隔字符串 |
| 90 | formData.append('uploader', user.userId); |
| 91 | |
| 92 | if (imageFile) { |
| 93 | formData.append('image_url', imageFile); |
| 94 | } |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 95 | |
| 96 | try { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 97 | console.log('[DEBUG] 发送上传请求...'); |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 98 | const response = await axios.post('/seeds/upload', formData, { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 99 | // axios 会自动处理 multipart/form-data Content-Type 边界,不用手动设置 |
| 100 | // headers: { 'Content-Type': 'multipart/form-data' }, |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 101 | }); |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 102 | console.log('[DEBUG] 请求成功,响应:', response.data); |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 103 | |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 104 | if (response.data.status === 'success') { |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 105 | setMessage('种子上传成功'); |
| 106 | } else { |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 107 | setMessage(response.data.message || '上传失败,请稍后再试'); |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 108 | } |
| 109 | } catch (error) { |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 110 | console.error('[handleSubmit] 上传失败:', error); |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 111 | setMessage('上传失败,发生了错误'); |
| 112 | } finally { |
| 113 | setIsLoading(false); |
| 114 | } |
| 115 | }; |
| 116 | |
| 117 | return ( |
| 118 | <div className="publish-seed-container"> |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 119 | <Header /> |
Krishya | c0f7e9b | 2025-04-22 15:28:28 +0800 | [diff] [blame] | 120 | <div className="pub-card"> |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 121 | {message && <div className="message">{message}</div>} |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 122 | <form |
| 123 | onSubmit={(e) => { |
| 124 | console.log('[DEBUG] form onSubmit 触发'); |
| 125 | handleSubmit(e); |
| 126 | }} |
| 127 | encType="multipart/form-data" |
| 128 | > |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 129 | <div className="title-tag"> |
| 130 | <label>标题</label> |
| 131 | <input |
| 132 | type="text" |
| 133 | value={title} |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 134 | onChange={(e) => { |
| 135 | console.log('[DEBUG] 标题输入变化:', e.target.value); |
| 136 | setTitle(e.target.value); |
| 137 | }} |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 138 | required |
| 139 | /> |
| 140 | </div> |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 141 | |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 142 | <div className="discription"> |
| 143 | <label>描述</label> |
| 144 | <textarea |
| 145 | value={description} |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 146 | onChange={(e) => { |
| 147 | console.log('[DEBUG] 描述输入变化:', e.target.value); |
| 148 | setDescription(e.target.value); |
| 149 | }} |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 150 | required |
| 151 | /> |
| 152 | </div> |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 153 | |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 154 | <div className="title-tag"> |
| 155 | <label>标签 (逗号分隔)</label> |
| 156 | <input |
| 157 | type="text" |
| 158 | value={tags.join(', ')} |
| 159 | onChange={handleTagsChange} |
| 160 | placeholder="例如:科幻, 动作" |
| 161 | required |
| 162 | /> |
| 163 | </div> |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 164 | |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 165 | <div className="pub-categoty"> |
| 166 | <label>分类</label> |
| 167 | <select |
| 168 | value={category} |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 169 | onChange={(e) => { |
| 170 | console.log('[DEBUG] 分类选择变化:', e.target.value); |
| 171 | setCategory(e.target.value); |
| 172 | }} |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 173 | required |
| 174 | > |
| 175 | <option value="movie">电影</option> |
| 176 | <option value="tv">电视剧</option> |
| 177 | <option value="music">音乐</option> |
| 178 | </select> |
| 179 | </div> |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 180 | |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 181 | <div className="seed-file"> |
| 182 | <label>种子文件</label> |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 183 | <div |
| 184 | className="seed-file-label" |
| 185 | onClick={handleFileButtonClick} |
| 186 | style={{ cursor: 'pointer' }} |
| 187 | > |
Krishya | f1d0ea8 | 2025-05-03 17:01:58 +0800 | [diff] [blame] | 188 | 点击选择文件 |
22301009 | df48f96 | 2025-06-05 13:40:44 +0800 | [diff] [blame] | 189 | </div> |
| 190 | <input |
| 191 | type="file" |
| 192 | accept=".torrent" |
| 193 | ref={fileInputRef} |
| 194 | onChange={handleFileChange} |
| 195 | style={{ display: 'none' }} |
| 196 | /> |
| 197 | {fileName && <div style={{ marginTop: '5px' }}>{fileName}</div>} |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 198 | </div> |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 199 | |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 200 | <div className="form-group"> |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 201 | <label>封面图</label> |
| 202 | <div className="cover-upload"> |
| 203 | <button type="button" onClick={handleImageButtonClick}> |
| 204 | 上传图片 |
| 205 | </button> |
| 206 | <input |
| 207 | type="file" |
| 208 | accept="image/*" |
| 209 | ref={imageInputRef} |
| 210 | onChange={handleImageChange} |
| 211 | style={{ display: 'none' }} |
| 212 | /> |
| 213 | </div> |
| 214 | {previewUrl && ( |
| 215 | <div style={{ marginTop: '10px' }}> |
| 216 | <img |
| 217 | src={previewUrl} |
| 218 | alt="封面预览" |
| 219 | style={{ maxWidth: '100%', maxHeight: '200px' }} |
| 220 | /> |
| 221 | </div> |
| 222 | )} |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 223 | </div> |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 224 | |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 225 | <div className="upload-button"> |
22301009 | 80aaf0d | 2025-06-05 23:20:05 +0800 | [diff] [blame] | 226 | <button |
| 227 | type="submit" |
| 228 | disabled={isLoading} |
| 229 | onClick={() => console.log('[DEBUG] 上传按钮 onClick 触发')} |
| 230 | > |
22301009 | 6401163 | 2025-06-04 21:57:22 +0800 | [diff] [blame] | 231 | {isLoading ? '正在上传...' : '上传种子'} |
| 232 | </button> |
| 233 | </div> |
| 234 | </form> |
Krishya | c0f7e9b | 2025-04-22 15:28:28 +0800 | [diff] [blame] | 235 | </div> |
22301009 | 5b28c67 | 2025-04-10 20:12:45 +0800 | [diff] [blame] | 236 | </div> |
| 237 | ); |
| 238 | }; |
| 239 | |
| 240 | export default PublishSeed; |