blob: 8388b7bc12f135ae3972a05bf4b939680141e749 [file] [log] [blame]
蒋大力35f939b2025-06-08 13:52:07 +08001import React, { useState } from 'react'
2import {
3 Home,
4 Settings,
5 BarChart3,
6 PieChart,
7 TrendingUp,
8 Activity,
9 BookOpen,
10 Users,
11 Upload,
12 Image,
13 Video,
14 ChevronDown,
15 User
16} from 'lucide-react'
17import './App.css'
18
19function App() {
20 const [activeTab, setActiveTab] = useState('image')
21 const [expandedMenu, setExpandedMenu] = useState('dashboard')
22 const [activePage, setActivePage] = useState('dashboard') // 新增:当前激活的页面
23 const [isDragOver, setIsDragOver] = useState(false)
24 const [isUploading, setIsUploading] = useState(false)
25 const [uploadedFiles, setUploadedFiles] = useState([])
26 const [uploadProgress, setUploadProgress] = useState(0)
27
28 const validateFiles = (files) => {
29 const validImageTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
30 const validVideoTypes = ['video/mp4', 'video/mov', 'video/avi']
31
32 const validTypes = activeTab === 'video' ? validVideoTypes : validImageTypes
33 const maxSize = activeTab === 'video' ? 2 * 1024 * 1024 * 1024 : 32 * 1024 * 1024 // 2GB for video, 32MB for images
34
35 const invalidFiles = files.filter(file => {
36 return !validTypes.includes(file.type) || file.size > maxSize
37 })
38
39 if (invalidFiles.length > 0) {
40 alert(`发现 ${invalidFiles.length} 个无效文件,请检查文件格式和大小`)
41 return false
42 }
43
44 return true
45 }
46
47 const simulateUpload = (files) => {
48 setIsUploading(true)
49 setUploadProgress(0)
50 setUploadedFiles(files)
51
52 // 模拟上传进度
53 const interval = setInterval(() => {
54 setUploadProgress(prev => {
55 if (prev >= 100) {
56 clearInterval(interval)
57 setIsUploading(false)
58 alert(`成功上传了 ${files.length} 个文件`)
59 return 100
60 }
61 return prev + 10
62 })
63 }, 200)
64 }
65
66 const handleFileUpload = () => {
67 if (isUploading) return
68
69 const input = document.createElement('input')
70 input.type = 'file'
71 input.accept = activeTab === 'video' ? 'video/*' : 'image/*'
72 input.multiple = activeTab === 'image'
73 input.onchange = (e) => {
74 const files = Array.from(e.target.files)
75 if (files.length > 0 && validateFiles(files)) {
76 simulateUpload(files)
77 }
78 }
79 input.click()
80 }
81
82 const handleDragOver = (e) => {
83 e.preventDefault()
84 e.stopPropagation()
85 setIsDragOver(true)
86 }
87
88 const handleDragLeave = (e) => {
89 e.preventDefault()
90 e.stopPropagation()
91 setIsDragOver(false)
92 }
93
94 const handleDrop = (e) => {
95 e.preventDefault()
96 e.stopPropagation()
97 setIsDragOver(false)
98
99 if (isUploading) return
100
101 const files = Array.from(e.dataTransfer.files)
102 if (files.length > 0 && validateFiles(files)) {
103 simulateUpload(files)
104 }
105 }
106
107 const clearUploadedFiles = () => {
108 setUploadedFiles([])
109 }
110
111 const removeFile = (indexToRemove) => {
112 setUploadedFiles(prev => prev.filter((_, index) => index !== indexToRemove))
113 }
114
115 const menuItems = [
116 { id: 'home', label: '首页', icon: Home },
117 { id: 'notebooks', label: '笔记管理', icon: BookOpen },
118 {
119 id: 'dashboard',
120 label: '数据看板',
121 icon: BarChart3,
122 submenu: [
123 { id: 'overview', label: '账号概况' },
124 { id: 'content', label: '内容分析' },
125 { id: 'fans', label: '粉丝数据' }
126 ]
127 },
128 { id: 'activity', label: '活动中心', icon: Activity },
129 { id: 'notes', label: '笔记灵感', icon: BookOpen },
130 { id: 'creator', label: '创作学院', icon: Users },
131 { id: 'journal', label: '创作日刊', icon: BookOpen }
132 ]
133 const toggleMenu = (menuId) => {
134 setExpandedMenu(expandedMenu === menuId ? null : menuId)
135 }
136
137 // 新增:处理页面切换的函数
138 const handlePageChange = (pageId) => {
139 setActivePage(pageId)
140 // 如果点击的是有子菜单的项目,也要展开子菜单
141 const menuItem = menuItems.find(item => item.id === pageId)
142 if (menuItem && menuItem.submenu) {
143 setExpandedMenu(pageId)
144 }
145 }
146
147 return (
148 <div className="app">
149 {/* Header */}
150 <header className="header">
151 <div className="header-left">
152 <div className="logo">小红书</div>
153 <h1 className="header-title">创作服务平台</h1>
154 </div>
155 <div className="header-right">
156 <div className="user-info">
157 <User size={16} />
158 <span>小红薯63081EA1</span>
159 </div>
160 </div>
161 </header>
162
163 {/* Sidebar */}
164 <aside className="sidebar">
165 <button className="publish-btn">发布笔记</button>
166 <nav className="nav-menu">
167 {menuItems.map((item) => (
168 <div key={item.id} className="nav-item">
169 <a
170 href="#"
171 className={`nav-link ${activePage === item.id ? 'active' : ''}`}
172 onClick={(e) => {
173 e.preventDefault()
174 if (item.submenu) {
175 toggleMenu(item.id)
176 } else {
177 handlePageChange(item.id)
178 }
179 }}
180 >
181 <item.icon size={16} />
182 <span>{item.label}</span>
183 {item.submenu && <ChevronDown size={16} style={{ marginLeft: 'auto', transform: expandedMenu === item.id ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform 0.3s ease' }} />}
184 </a>
185
186 {item.submenu && expandedMenu === item.id && (
187 <div className="nav-submenu">
188 {item.submenu.map((subItem) => (
189 <a
190 key={subItem.id}
191 href="#"
192 className={`nav-link ${activePage === subItem.id ? 'active' : ''}`}
193 onClick={(e) => {
194 e.preventDefault()
195 handlePageChange(subItem.id)
196 }}
197 >
198 {subItem.label}
199 </a>
200 ))}
201 </div>
202 )}
203 </div>
204 ))}
205 </nav>
206 </aside> {/* Main Content */}
207 <main className="main-content">
208 <div className="content-wrapper">
209 {activePage === 'dashboard' || activePage === 'overview' || activePage === 'content' || activePage === 'fans' ? (
210 // 上传页面内容(数据看板相关页面显示上传功能)
211 <>
212 {/* Upload Tabs */}
213 <div className="upload-tabs">
214 <button
215 className={`upload-tab ${activeTab === 'video' ? 'active' : ''}`}
216 onClick={() => setActiveTab('video')}
217 >
218 上传视频
219 </button>
220 <button
221 className={`upload-tab ${activeTab === 'image' ? 'active' : ''}`}
222 onClick={() => setActiveTab('image')}
223 >
224 上传图文
225 </button>
226 </div>
227
228 {/* Upload Area */}
229 <div
230 className={`upload-area ${isDragOver ? 'drag-over' : ''}`}
231 onDragOver={handleDragOver}
232 onDragLeave={handleDragLeave}
233 onDrop={handleDrop}
234 >
235 <div className="upload-icon">
236 {activeTab === 'video' ? <Video /> : <Image />}
237 </div>
238 <h2 className="upload-title">
239 {activeTab === 'video' ? '拖拽视频到此处或点击上传' : '拖拽图片到此处或点击上传'}
240 </h2>
241 <p className="upload-subtitle">
242 {activeTab === 'video' ? '(需支持上传格式)' : '(需支持上传格式)'}
243 </p>
244 <button
245 className={`upload-btn ${isUploading ? 'uploading' : ''}`}
246 onClick={handleFileUpload}
247 disabled={isUploading}
248 >
249 {isUploading ? `上传中... ${uploadProgress}%` : (activeTab === 'video' ? '上传视频' : '上传图片')}
250 </button>
251
252 {/* Upload Progress Bar */}
253 {isUploading && (
254 <div className="progress-container">
255 <div className="progress-bar">
256 <div
257 className="progress-fill"
258 style={{ width: `${uploadProgress}%` }}
259 ></div>
260 </div>
261 <div className="progress-text">{uploadProgress}%</div>
262 </div>
263 )}
264 </div>
265
266 {/* File Preview Area */}
267 {uploadedFiles.length > 0 && (
268 <div className="file-preview-area">
269 <div className="preview-header">
270 <h3 className="preview-title">已上传文件 ({uploadedFiles.length})</h3>
271 <button className="clear-files-btn" onClick={clearUploadedFiles}>
272 清除所有
273 </button>
274 </div>
275 <div className="file-grid">
276 {uploadedFiles.map((file, index) => (
277 <div key={index} className="file-item">
278 <button
279 className="remove-file-btn"
280 onClick={() => removeFile(index)}
281 title="删除文件"
282 >
283 ×
284 </button>
285 {file.type?.startsWith('image/') ? (
286 <div className="file-thumbnail">
287 <img src={URL.createObjectURL(file)} alt={file.name} />
288 </div>
289 ) : (
290 <div className="file-thumbnail video-thumbnail">
291 <Video size={24} />
292 </div>
293 )}
294 <div className="file-info">
295 <div className="file-name" title={file.name}>
296 {file.name.length > 20 ? file.name.substring(0, 17) + '...' : file.name}
297 </div>
298 <div className="file-size">
299 {(file.size / 1024 / 1024).toFixed(2)} MB
300 </div>
301 </div>
302 </div>
303 ))}
304 </div>
305 </div>
306 )}
307
308 {/* Upload Info */}
309 <div className="upload-info fade-in" key={activeTab}>
310 {activeTab === 'image' ? (
311 <>
312 <div className="info-item">
313 <h3 className="info-title">图片大小</h3>
314 <p className="info-desc">
315 支持上传的图片大小,<br />
316 最大32MB的图片文件
317 </p>
318 </div>
319 <div className="info-item">
320 <h3 className="info-title">图片格式</h3>
321 <p className="info-desc">
322 支持上传的图片格式:<br />
323 推荐使用pngjpgjpegwebp,不支持giflive及其他转化的动图
324 </p>
325 </div>
326 <div className="info-item">
327 <h3 className="info-title">图片分辨率</h3>
328 <p className="info-desc">
329 不要竖图片尺寸,推荐上传3:4尺寸之间,分辨率不低于720*960的图片,<br />
330 超过17张的时候图片将自动压缩至相配尺寸
331 </p>
332 </div>
333 </>
334 ) : (
335 <>
336 <div className="info-item">
337 <h3 className="info-title">视频大小</h3>
338 <p className="info-desc">
339 支持种类5分钟内视频,<br />
340 最大2GB的视频文件
341 </p>
342 </div>
343 <div className="info-item">
344 <h3 className="info-title">视频格式</h3>
345 <p className="info-desc">
346 支持常用视频格式:<br />
347 推荐使用mp4mov
348 </p>
349 </div>
350 <div className="info-item">
351 <h3 className="info-title">视频分辨率</h3>
352 <p className="info-desc">
353 推荐上传720P (1280*720) 及以上视频,<br />
354 超过1080P的视频可能可能导致上传稍慢且消耗流量
355 </p>
356 </div>
357 </>
358 )}
359 </div>
360 </>
361 ) : (
362 // 其他页面的内容
363 <div className="page-content">
364 <div className="page-header">
365 <h1 className="page-title">
366 {activePage === 'home' && '首页'}
367 {activePage === 'notebooks' && '笔记管理'}
368 {activePage === 'activity' && '活动中心'}
369 {activePage === 'notes' && '笔记灵感'}
370 {activePage === 'creator' && '创作学院'}
371 {activePage === 'journal' && '创作日刊'}
372 </h1>
373 </div>
374 <div className="page-body">
375 <div className="placeholder-content">
376 <div className="placeholder-icon">
377 {activePage === 'home' && <Home size={48} />}
378 {activePage === 'notebooks' && <BookOpen size={48} />}
379 {activePage === 'activity' && <Activity size={48} />}
380 {activePage === 'notes' && <BookOpen size={48} />}
381 {activePage === 'creator' && <Users size={48} />}
382 {activePage === 'journal' && <BookOpen size={48} />}
383 </div>
384 <h3 className="placeholder-title">
385 {activePage === 'home' && '欢迎来到小红书创作平台'}
386 {activePage === 'notebooks' && '笔记管理功能开发中'}
387 {activePage === 'activity' && '活动中心功能开发中'}
388 {activePage === 'notes' && '笔记灵感功能开发中'}
389 {activePage === 'creator' && '创作学院功能开发中'}
390 {activePage === 'journal' && '创作日刊功能开发中'}
391 </h3>
392 <p className="placeholder-desc">
393 {activePage === 'home' && '在这里您可以管理您的创作内容,查看数据分析,获取创作灵感。'}
394 {activePage === 'notebooks' && '这里将显示您的所有笔记,支持编辑、删除、分类等操作。'}
395 {activePage === 'activity' && '这里将展示最新的平台活动,让您参与更多有趣的创作活动。'}
396 {activePage === 'notes' && '这里将为您提供创作灵感和写作建议,帮助您创作更好的内容。'}
397 {activePage === 'creator' && '这里将提供创作技巧教学和平台规则说明,助您成为优秀创作者。'}
398 {activePage === 'journal' && '这里将展示创作相关的最新资讯和平台动态。'}
399 </p>
400 </div>
401 </div>
402 </div>
403 )}
404 </div>
405 </main>
406 </div>
407 )
408}
409
410export default App