wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 1 | import React, { useState, useEffect } from "react"; |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 2 | import HelpIcon from "@mui/icons-material/Help"; |
| 3 | import { useNavigate } from "react-router-dom"; |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 4 | import { API_BASE_URL } from "./config"; |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 5 | |
| 6 | export default function BegSeedPage() { |
| 7 | const navigate = useNavigate(); |
| 8 | const now = new Date(); |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 9 | const [begSeedList, setBegSeedList] = useState([]); |
| 10 | const [loading, setLoading] = useState(true); |
| 11 | const [error, setError] = useState(null); |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 12 | const [showForm, setShowForm] = useState(false); |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 13 | const [refreshKey, setRefreshKey] = useState(0); // 用于强制重新渲染 |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 14 | const [formData, setFormData] = useState({ |
| 15 | info: "", |
| 16 | reward_magic: "", |
| 17 | deadline: "", |
| 18 | }); |
| 19 | |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 20 | // 从后端获取求种列表 |
| 21 | const fetchBegSeedList = async () => { |
| 22 | setLoading(true); |
| 23 | try { |
| 24 | const response = await fetch(`${API_BASE_URL}/api/begseed-list`); |
| 25 | if (!response.ok) { |
| 26 | throw new Error(`请求失败,状态码: ${response.status}`); |
| 27 | } |
| 28 | const data = await response.json(); |
| 29 | console.log("获取到的求种列表数据:", data); |
| 30 | |
| 31 | // 格式化数据以匹配前端期望的格式 |
| 32 | const formattedData = data.map(item => ({ |
| 33 | beg_id: item.beg_id || item.begid || item.id, |
| 34 | info: item.info || item.description || item.content, |
| 35 | beg_count: item.beg_count || item.begCount || 1, |
| 36 | reward_magic: item.reward_magic || item.rewardMagic || item.magic, |
| 37 | deadline: item.deadline || item.endtime, |
| 38 | has_match: item.has_match || item.hasMatch || item.completed || 0, |
| 39 | })); |
| 40 | |
| 41 | setBegSeedList(formattedData); |
| 42 | setError(null); |
| 43 | } catch (err) { |
| 44 | console.error('获取求种列表失败:', err); |
| 45 | setError(err.message); |
| 46 | // 如果API调用失败,使用默认数据 |
| 47 | setBegSeedList([ |
| 48 | { |
| 49 | beg_id: "beg001", |
| 50 | info: "求《三体》高清资源", |
| 51 | beg_count: 5, |
| 52 | reward_magic: 100, |
| 53 | deadline: "2025-06-10T23:59:59", |
| 54 | has_match: 0, |
| 55 | }, |
| 56 | { |
| 57 | beg_id: "beg002", |
| 58 | info: "求《灌篮高手》国语配音版", |
| 59 | beg_count: 3, |
| 60 | reward_magic: 50, |
| 61 | deadline: "2024-05-01T23:59:59", |
| 62 | has_match: 1, |
| 63 | }, |
| 64 | { |
| 65 | beg_id: "beg003", |
| 66 | info: "求《黑暗之魂3》PC版种子", |
| 67 | beg_count: 2, |
| 68 | reward_magic: 80, |
| 69 | deadline: "2024-04-01T23:59:59", |
| 70 | has_match: 0, |
| 71 | }, |
| 72 | ]); |
| 73 | } finally { |
| 74 | setLoading(false); |
| 75 | } |
| 76 | }; |
| 77 | |
| 78 | // 组件挂载时获取数据 |
| 79 | useEffect(() => { |
| 80 | fetchBegSeedList(); |
| 81 | }, []); |
| 82 | |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 83 | // 表单输入处理 |
| 84 | const handleFormChange = (e) => { |
| 85 | const { name, value } = e.target; |
| 86 | setFormData((prev) => ({ |
| 87 | ...prev, |
| 88 | [name]: value, |
| 89 | })); |
| 90 | }; |
| 91 | |
| 92 | // 提交新求种任务 |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 93 | const handleSubmit = async (e) => { |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 94 | e.preventDefault(); |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 95 | |
| 96 | // 获取用户ID |
| 97 | const match = document.cookie.match('(^|;)\\s*userId=([^;]+)'); |
| 98 | const userId = match ? match[2] : null; |
| 99 | |
| 100 | if (!userId) { |
| 101 | alert("请先登录后再发布求种任务"); |
| 102 | return; |
| 103 | } |
| 104 | |
| 105 | try { |
| 106 | const response = await fetch(`${API_BASE_URL}/api/create-begseed`, { |
| 107 | method: 'POST', |
| 108 | headers: { |
| 109 | 'Content-Type': 'application/json', |
| 110 | }, |
| 111 | body: JSON.stringify({ |
| 112 | userid: userId, |
| 113 | info: formData.info, |
| 114 | reward_magic: Number(formData.reward_magic), |
| 115 | deadline: formData.deadline, |
| 116 | }), |
| 117 | }); |
| 118 | |
| 119 | if (response.ok) { |
| 120 | // 成功创建,重新获取列表并强制重新渲染 |
| 121 | setLoading(true); // 显示加载状态 |
| 122 | await fetchBegSeedList(); |
| 123 | setShowForm(false); |
| 124 | setFormData({ info: "", reward_magic: "", deadline: "" }); |
| 125 | setRefreshKey(prev => prev + 1); // 强制重新渲染 |
| 126 | alert("发布成功!"); |
| 127 | } else { |
| 128 | const errorData = await response.json(); |
| 129 | alert(`发布失败: ${errorData.message || '未知错误'}`); |
| 130 | } |
| 131 | } catch (err) { |
| 132 | console.error('发布求种任务失败:', err); |
| 133 | // 如果后端调用失败,则使用前端演示逻辑 |
| 134 | // setLoading(true); // 显示加载状态 |
| 135 | // const newBegId = "beg" + Math.floor(Math.random() * 10000); |
| 136 | // setBegSeedList([ |
| 137 | // { |
| 138 | // beg_id: newBegId, |
| 139 | // info: formData.info, |
| 140 | // beg_count: 1, |
| 141 | // reward_magic: Number(formData.reward_magic), |
| 142 | // deadline: formData.deadline, |
| 143 | // has_match: 0, |
| 144 | // }, |
| 145 | // ...begSeedList, |
| 146 | // ]); |
| 147 | // setLoading(false); // 隐藏加载状态 |
| 148 | // setShowForm(false); |
| 149 | // setFormData({ info: "", reward_magic: "", deadline: "" }); |
| 150 | // setRefreshKey(prev => prev + 1); // 强制重新渲染 |
| 151 | // alert("发布成功(前端演示)"); |
| 152 | } |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 153 | }; |
| 154 | |
| 155 | return ( |
| 156 | <div className="container"> |
| 157 | <h1 style={{ margin: "24px 0 32px 0", color: "#1976d2" }}> |
| 158 | <HelpIcon style={{ verticalAlign: "middle", marginRight: 8 }} /> |
| 159 | 求种列表 |
| 160 | </h1> |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 161 | |
| 162 | {/* 加载状态 */} |
| 163 | {loading && ( |
| 164 | <div style={{ textAlign: "center", margin: "40px 0", color: "#666" }}> |
| 165 | 正在加载求种列表... |
| 166 | </div> |
| 167 | )} |
| 168 | |
| 169 | {/* 错误状态 */} |
| 170 | {error && ( |
| 171 | <div style={{ |
| 172 | textAlign: "center", |
| 173 | margin: "20px 0", |
| 174 | padding: "10px", |
| 175 | background: "#ffebee", |
| 176 | color: "#c62828", |
| 177 | borderRadius: "4px" |
| 178 | }}> |
| 179 | 加载失败: {error} (已显示默认数据) |
| 180 | </div> |
| 181 | )} |
| 182 | |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 183 | <div style={{ margin: "0 0 32px 0", textAlign: "center" }}> |
| 184 | <button |
| 185 | onClick={() => setShowForm(true)} |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 186 | disabled={loading} |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 187 | style={{ |
| 188 | fontSize: 18, |
| 189 | padding: "12px 36px", |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 190 | background: loading ? "#ccc" : "linear-gradient(90deg, #42a5f5 0%, #1976d2 100%)", |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 191 | color: "#fff", |
| 192 | border: "none", |
| 193 | borderRadius: 8, |
| 194 | fontWeight: 600, |
| 195 | boxShadow: "0 2px 8px #b2d8ea", |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 196 | cursor: loading ? "not-allowed" : "pointer", |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 197 | transition: "background 0.2s", |
| 198 | }} |
| 199 | > |
| 200 | 发布求种任务 |
| 201 | </button> |
| 202 | </div> |
| 203 | {showForm && ( |
| 204 | <div |
| 205 | style={{ |
| 206 | background: "#fff", |
| 207 | border: "1.5px solid #b2d8ea", |
| 208 | borderRadius: 12, |
| 209 | padding: 24, |
| 210 | maxWidth: 480, |
| 211 | margin: "0 auto 32px auto", |
| 212 | boxShadow: "0 2px 8px #e0e7ff", |
| 213 | }} |
| 214 | > |
| 215 | <h3 style={{ color: "#1976d2", marginBottom: 18 }}>发布求种任务</h3> |
| 216 | <form onSubmit={handleSubmit}> |
| 217 | <div style={{ marginBottom: 16 }}> |
| 218 | <label style={{ display: "inline-block", width: 80 }}>求种信息:</label> |
| 219 | <input |
| 220 | type="text" |
| 221 | name="info" |
| 222 | value={formData.info} |
| 223 | onChange={handleFormChange} |
| 224 | required |
| 225 | style={{ |
| 226 | padding: "6px 12px", |
| 227 | borderRadius: 6, |
| 228 | border: "1px solid #b2d8ea", |
| 229 | width: 260, |
| 230 | }} |
| 231 | /> |
| 232 | </div> |
| 233 | <div style={{ marginBottom: 16 }}> |
| 234 | <label style={{ display: "inline-block", width: 80 }}>悬赏魔力值:</label> |
| 235 | <input |
| 236 | type="number" |
| 237 | name="reward_magic" |
| 238 | value={formData.reward_magic} |
| 239 | onChange={handleFormChange} |
| 240 | required |
| 241 | min={1} |
| 242 | style={{ |
| 243 | padding: "6px 12px", |
| 244 | borderRadius: 6, |
| 245 | border: "1px solid #b2d8ea", |
| 246 | width: 120, |
| 247 | }} |
| 248 | /> |
| 249 | </div> |
| 250 | <div style={{ marginBottom: 16 }}> |
| 251 | <label style={{ display: "inline-block", width: 80 }}>截止日期:</label> |
| 252 | <input |
| 253 | type="datetime-local" |
| 254 | name="deadline" |
| 255 | value={formData.deadline} |
| 256 | onChange={handleFormChange} |
| 257 | required |
| 258 | style={{ |
| 259 | padding: "6px 12px", |
| 260 | borderRadius: 6, |
| 261 | border: "1px solid #b2d8ea", |
| 262 | width: 200, |
| 263 | }} |
| 264 | /> |
| 265 | </div> |
| 266 | <div style={{ marginTop: 18 }}> |
| 267 | <button |
| 268 | type="submit" |
| 269 | style={{ |
| 270 | background: "#1976d2", |
| 271 | color: "#fff", |
| 272 | border: "none", |
| 273 | borderRadius: 6, |
| 274 | padding: "8px 28px", |
| 275 | fontWeight: 500, |
| 276 | fontSize: 16, |
| 277 | marginRight: 18, |
| 278 | cursor: "pointer", |
| 279 | }} |
| 280 | > |
| 281 | 提交 |
| 282 | </button> |
| 283 | <button |
| 284 | type="button" |
| 285 | onClick={() => setShowForm(false)} |
| 286 | style={{ |
| 287 | background: "#b0b0b0", |
| 288 | color: "#fff", |
| 289 | border: "none", |
| 290 | borderRadius: 6, |
| 291 | padding: "8px 28px", |
| 292 | fontWeight: 500, |
| 293 | fontSize: 16, |
| 294 | cursor: "pointer", |
| 295 | }} |
| 296 | > |
| 297 | 取消 |
| 298 | </button> |
| 299 | </div> |
| 300 | </form> |
| 301 | </div> |
| 302 | )} |
wht | 2bf8f80 | 2025-06-08 15:52:18 +0800 | [diff] [blame] | 303 | <div key={refreshKey} style={{ display: "flex", flexWrap: "wrap", gap: 24 }}> |
wht | dc90a03 | 2025-06-08 03:03:52 +0800 | [diff] [blame] | 304 | {begSeedList.map((beg) => { |
| 305 | const isExpired = |
| 306 | new Date(beg.deadline) < now || beg.has_match === 1; |
| 307 | return ( |
| 308 | <div |
| 309 | key={beg.beg_id} |
| 310 | style={{ |
| 311 | background: isExpired ? "#f0f0f0" : "#e3f7e7", |
| 312 | color: isExpired ? "#b0b0b0" : "#222", |
| 313 | border: "1.5px solid #b2d8ea", |
| 314 | borderRadius: 12, |
| 315 | padding: 18, |
| 316 | minWidth: 320, |
| 317 | maxWidth: 420, |
| 318 | boxShadow: "0 2px 8px #e0e7ff", |
| 319 | opacity: isExpired ? 0.6 : 1, |
| 320 | cursor: "pointer", |
| 321 | marginBottom: 12, |
| 322 | transition: "box-shadow 0.2s", |
| 323 | }} |
| 324 | onClick={() => navigate(`/begseed/${beg.beg_id}`)} |
| 325 | > |
| 326 | <div style={{ fontWeight: 600, fontSize: 18, marginBottom: 8 }}> |
| 327 | {beg.info} |
| 328 | </div> |
| 329 | <div>求种人数:{beg.beg_count}</div> |
| 330 | <div>悬赏魔力值:{beg.reward_magic}</div> |
| 331 | <div> |
| 332 | 截止时间:{new Date(beg.deadline).toLocaleString()} |
| 333 | </div> |
| 334 | <div> |
| 335 | 状态: |
| 336 | {beg.has_match === 1 |
| 337 | ? "已完成" |
| 338 | : new Date(beg.deadline) < now |
| 339 | ? "已过期" |
| 340 | : "进行中"} |
| 341 | </div> |
| 342 | </div> |
| 343 | ); |
| 344 | })} |
| 345 | </div> |
| 346 | </div> |
| 347 | ); |
| 348 | } |