blob: 465afda8a2137fac1189027fcaefeba824e63a95 [file] [log] [blame]
ZBDff4d40a2025-05-27 17:05:20 +08001import React, { useState } from 'react';
2import {
3 Box, Container, Typography, Paper,
4 TextField, Button, Stack
5} from '@mui/material';
6import CloudUploadIcon from '@mui/icons-material/CloudUpload';
ZBD4b0e05a2025-06-08 18:11:26 +08007
ZBDff4d40a2025-05-27 17:05:20 +08008
9function Upload() {
10 const [title, setTitle] = useState('');
11 const [file, setFile] = useState(null);
12
13 const handleUpload = () => {
ZBD4b0e05a2025-06-08 18:11:26 +080014 const formData = new FormData();
15 if (file) {
16 formData.append('file', file);
17 }
18 formData.append('title', title);
ZBDff4d40a2025-05-27 17:05:20 +080019
ZBD4b0e05a2025-06-08 18:11:26 +080020 const token = localStorage.getItem('jwt_token'); // 假设你登录后将 token 存在 localStorage
21
22 fetch('http://localhost:8080/api/torrents/upload', {
23 method: 'POST',
24 headers: {
25 Authorization: `Bearer ${token}`,
26 },
27 body: formData,
28 })
ZBDff4d40a2025-05-27 17:05:20 +080029 .then(response => {
30 if (response.ok) {
ZBD4b0e05a2025-06-08 18:11:26 +080031 console.log('上传成功');
32 alert('上传成功');
ZBDff4d40a2025-05-27 17:05:20 +080033 } else {
ZBD4b0e05a2025-06-08 18:11:26 +080034 return response.text().then(text => {
35 console.error('上传失败:', text);
36 alert('上传失败: ' + text);
37 });
ZBDff4d40a2025-05-27 17:05:20 +080038 }
39 })
40 .catch(error => {
41 console.error('上传出错:', error);
ZBD4b0e05a2025-06-08 18:11:26 +080042 alert('上传出错: ' + error.message);
ZBDff4d40a2025-05-27 17:05:20 +080043 });
ZBD4b0e05a2025-06-08 18:11:26 +080044};
ZBDff4d40a2025-05-27 17:05:20 +080045
46 return (
47 <Box sx={{ minHeight: '100vh', py: 4, background: 'linear-gradient(135deg, #2c3e50, #4ca1af)', color: 'white' }}> {/* Moved body styles here for self-containment */}
48 <Container maxWidth="sm" sx={{ position: 'relative', zIndex: 10 }}>
49 <Typography variant="h4" sx={{ textAlign: 'center', mb: 3, fontWeight: 'bold' }}> {/* Replaced className with sx */}
50 ⬆️ 上传种子 · Mini-Tracker
51 </Typography>
52
53 <Paper sx={{ position: 'relative', zIndex: 20, padding: '2rem', backgroundColor: 'rgba(30, 30, 30, 0.9)' }}> {/* Replaced className with sx */}
54 <Stack spacing={3}> {/* Increased spacing a bit */}
55 <TextField
56 label="资源名称"
57 variant="outlined"
58 fullWidth
59 value={title}
60 onChange={e => setTitle(e.target.value)}
61 placeholder="请输入资源名称"
62 InputLabelProps={{
63 sx: {
64 color: '#ccc',
65 '&.Mui-focused': { // Ensure label color remains consistent when focused
66 color: '#ccc',
67 }
68 }
69 }}
70 sx={{
71 // Root element of the TextField
72 backgroundColor: 'transparent',
73
74 // Styles for the HTML input element itself
75 '& .MuiInputBase-input': {
76 color: 'white', // Text color
77 backgroundColor: 'transparent', // **** THIS IS THE FIX **** Ensure input background is transparent
78 caretColor: 'white', // Cursor color
79 '&::placeholder': {
80 color: '#bbb',
81 opacity: 1,
82 },
83 },
84 // Styles for the outlined border
85 '& .MuiOutlinedInput-root': {
86 '& fieldset': {
87 borderColor: '#888', // Default border color
88 },
89 '&:hover fieldset': {
90 borderColor: '#aaa', // Border color on hover
91 },
92 '&.Mui-focused fieldset': {
93 borderColor: '#fff', // Border color when focused
94 },
95 },
96 }}
97 />
98
99 <Button
100 variant="contained"
101 component="label" // Allows the button to act as a label for a hidden input
102 startIcon={<CloudUploadIcon />}
103 sx={{ backgroundColor: '#00bcd4', color: 'white', '&:hover': { backgroundColor: '#0097a7' } }} // Replaced className with sx
104 >
105 选择种子文件
106 <input
107 hidden
108 type="file"
109 accept=".torrent"
110 onChange={e => {
111 if (e.target.files && e.target.files[0]) {
112 setFile(e.target.files[0]);
113 }
114 }}
115 />
116 </Button>
117
118 {file && (
119 <Typography variant="body2" sx={{ color: '#eee', textAlign: 'center' }}>
120 已选择文件: {file.name}
121 </Typography>
122 )}
123
124 <Button
125 variant="outlined"
126 onClick={handleUpload}
127 disabled={!file || !title}
128 sx={{ borderColor: 'white', color: 'white', '&:hover': { borderColor: '#ddd', backgroundColor: 'rgba(255,255,255,0.1)'}, '&.Mui-disabled': { borderColor: '#777', color: '#777' } }} // Replaced className with sx
129 >
130 提交上传
131 </Button>
132 </Stack>
133 </Paper>
134 </Container>
135
136 {/* Background bubbles animation - assuming CSS for .bubbles and .bubble is globally available or defined in an imported CSS file */}
137 {/* For self-containment, these styles would ideally be JSS or defined in a <style> tag if not using styled-components or similar */}
138 <Box className="bubbles" sx={{
139 pointerEvents: 'none',
140 position: 'fixed',
141 top: 0,
142 left: 0,
143 width: '100%',
144 height: '100%',
145 overflow: 'hidden',
146 zIndex: 1, // Ensure it's behind the content paper but above the main background
147 }}>
148 {[...Array(40)].map((_, i) => (
149 <Box
150 key={i}
151 className="bubble" // Assuming .bubble and @keyframes rise are defined in your CSS
152 sx={{
153 position: 'absolute',
154 bottom: '-100px',
155 background: 'rgba(255, 255, 255, 0.15)',
156 borderRadius: '50%',
157 animation: 'rise 20s infinite ease-in', // Make sure @keyframes rise is defined
158 width: `${Math.random() * 20 + 10}px`,
159 height: `${Math.random() * 20 + 10}px`,
160 left: `${Math.random() * 100}%`,
161 animationDuration: `${10 + Math.random() * 20}s`,
162 animationDelay: `${Math.random() * 5}s`
163 }}
164 />
165 ))}
166 </Box>
167 {/* Define keyframes if not in external CSS */}
168 <style>
169 {`
170 @keyframes rise {
171 0% {
172 transform: translateY(0) scale(1);
173 opacity: 0.5;
174 }
175 50% {
176 opacity: 1;
177 }
178 100% {
179 transform: translateY(-120vh) scale(0.5);
180 opacity: 0;
181 }
182 }
183 body { /* Basic reset if base.css is not loaded */
184 margin: 0;
185 font-family: 'Roboto', sans-serif;
186 }
187 `}
188 </style>
189 </Box>
190 );
191}
192
193export default Upload;