blob: 475fe2f399b31b7589dc0c3c26b2cd1b3145ec65 [file] [log] [blame]
import React, { useState } from 'react'
import { Image, Video, Send } from 'lucide-react'
import { searchAPI } from '../api/search_jwlll'
import { getUserInfo } from '../utils/auth'
import '../style/UploadPage.css'
const categories = [
'穿搭','美食','彩妆','影视',
'职场','情感','家居','游戏','旅行','健身'
]
export default function UploadPageJWLLL({ onComplete }) {
const [activeTab, setActiveTab] = useState('image')
const [isDragOver, setIsDragOver] = useState(false)
const [isUploading, setIsUploading] = useState(false)
const [uploadedFiles, setUploadedFiles] = useState([])
const [uploadProgress, setUploadProgress] = useState(0)
// 新增表单字段
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [tags, setTags] = useState('')
const [category, setCategory] = useState(categories[0])
const [isPublishing, setIsPublishing] = useState(false)
// 获取当前用户ID
const getCurrentUserId = () => {
const userInfo = getUserInfo()
return userInfo?.id || 3 // 如果未登录或无用户信息,使用默认值3(注意这里是数字类型)
}
const validateFiles = files => {
const imgTypes = ['image/jpeg','image/jpg','image/png','image/webp']
const vidTypes = ['video/mp4','video/mov','video/avi']
const types = activeTab==='video'? vidTypes : imgTypes
const max = activeTab==='video'? 2*1024*1024*1024 : 32*1024*1024
const invalid = files.filter(f => !types.includes(f.type) || f.size > max)
if (invalid.length) {
alert(`发现 ${invalid.length} 个无效文件,请检查文件格式和大小`)
return false
}
return true
}
const simulateUpload = files => {
setIsUploading(true)
setUploadProgress(0)
setUploadedFiles(files)
const iv = setInterval(() => {
setUploadProgress(p => {
if (p >= 100) {
clearInterval(iv)
setIsUploading(false)
if (typeof onComplete === 'function') {
onComplete(files)
}
return 100
}
return p + 10
})
}, 200)
}
const handleFileUpload = () => {
if (isUploading) return
const input = document.createElement('input')
input.type = 'file'
input.accept = activeTab==='video'? 'video/*' : 'image/*'
input.multiple = activeTab==='image'
input.onchange = e => {
const files = Array.from(e.target.files)
if (files.length > 0 && validateFiles(files)) simulateUpload(files)
}
input.click()
}
const handleDragOver = e => { e.preventDefault(); e.stopPropagation(); setIsDragOver(true) }
const handleDragLeave = e => { e.preventDefault(); e.stopPropagation(); setIsDragOver(false) }
const handleDrop = e => {
e.preventDefault(); e.stopPropagation(); setIsDragOver(false)
if (isUploading) return
const files = Array.from(e.dataTransfer.files)
if (files.length > 0 && validateFiles(files)) simulateUpload(files)
}
const clearFiles = () => setUploadedFiles([])
const removeFile = idx => setUploadedFiles(f => f.filter((_,i) => i!==idx))
// 发布帖子
const handlePublish = async () => {
if (!title.trim()) {
alert('请输入标题')
return
}
if (!content.trim()) {
alert('请输入内容')
return
} setIsPublishing(true)
try {
const currentUserId = getCurrentUserId()
const postData = {
user_id: currentUserId,
title: title.trim(),
content: content.trim(),
tags: tags.split(',').map(t => t.trim()).filter(t => t),
category: category,
type: activeTab === 'video' ? 'video' : 'image',
media_files: uploadedFiles.map(f => f.name) // 实际项目中应该是上传后的URL
}
await searchAPI.uploadPost(postData)
alert('发布成功!')
// 清空表单
setTitle('')
setContent('')
setTags('')
setUploadedFiles([])
setActiveTab('image')
} catch (error) {
console.error('发布失败:', error)
alert('发布失败,请重试')
} finally {
setIsPublishing(false)
}
}
return (
<div className="upload-page-jwlll">
<div className="upload-tabs">
<button
className={`upload-tab${activeTab==='video'?' active':''}`}
onClick={() => setActiveTab('video')}
>上传视频</button>
<button
className={`upload-tab${activeTab==='image'?' active':''}`}
onClick={() => setActiveTab('image')}
>上传图文</button>
</div>
{/* 内容表单 */}
<div className="content-form">
<div className="form-group">
<label htmlFor="title">标题</label>
<input
id="title"
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="请输入标题..."
className="form-input"
maxLength={100}
/>
</div>
<div className="form-group">
<label htmlFor="content">内容</label>
<textarea
id="content"
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="请输入内容..."
className="form-textarea"
rows={4}
maxLength={1000}
/>
</div>
<div className="form-row">
<div className="form-group">
<label htmlFor="category">分类</label>
<select
id="category"
value={category}
onChange={(e) => setCategory(e.target.value)}
className="form-select"
>
{categories.map(cat => (
<option key={cat} value={cat}>{cat}</option>
))}
</select>
</div>
<div className="form-group">
<label htmlFor="tags">标签</label>
<input
id="tags"
type="text"
value={tags}
onChange={(e) => setTags(e.target.value)}
placeholder="用逗号分隔多个标签..."
className="form-input"
/>
</div>
</div>
</div>
{/* 文件上传区域 */}
<div
className={`upload-area${isDragOver?' drag-over':''}`}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
<div className="upload-icon">
{activeTab==='video'? <Video/> : <Image/>}
</div>
<h2 className="upload-title">
{activeTab==='video'
? '拖拽视频到此处或点击上传'
: '拖拽图片到此处或点击上传'
}
</h2>
<p className="upload-subtitle">(需支持上传格式)</p>
<button
className={`upload-btn${isUploading?' uploading':''}`}
onClick={handleFileUpload}
disabled={isUploading}
>
{isUploading
? `上传中... ${uploadProgress}%`
: activeTab==='video'
? '上传视频'
: '上传图片'
}
</button>
{isUploading && (
<div className="progress-container">
<div className="progress-bar">
<div
className="progress-fill"
style={{ width: `${uploadProgress}%` }}
/>
</div>
<div className="progress-text">{uploadProgress}%</div>
</div>
)}
</div>
{uploadedFiles.length > 0 && (
<div className="file-preview-area">
<div className="preview-header">
<h3 className="preview-title">已上传文件 ({uploadedFiles.length})</h3>
<button className="clear-files-btn" onClick={clearFiles}>
清除所有
</button>
</div>
<div className="file-grid">
{uploadedFiles.map((file, i) => (
<div key={i} className="file-item">
<button
className="remove-file-btn"
onClick={() => removeFile(i)}
title="删除文件"
>×</button>
{file.type.startsWith('image/') ? (
<div className="file-thumbnail">
<img src={URL.createObjectURL(file)} alt={file.name} />
</div>
) : (
<div className="file-thumbnail video-thumbnail">
<Video size={24} />
</div>
)}
<div className="file-info">
<div className="file-name" title={file.name}>
{file.name.length > 20
? file.name.slice(0,17) + '...'
: file.name
}
</div>
<div className="file-size">
{(file.size/1024/1024).toFixed(2)} MB
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* 发布按钮 */}
<div className="publish-section">
<button
className={`publish-btn${isPublishing?' publishing':''}`}
onClick={handlePublish}
disabled={isPublishing || !title.trim() || !content.trim()}
>
<Send size={20} />
{isPublishing ? '发布中...' : '发布'}
</button>
</div>
<div className="upload-info fade-in">
{activeTab==='image' ? (
<>
<div className="info-item">
<h3 className="info-title">图片大小</h3>
<p className="info-desc">最大32MB</p>
</div>
<div className="info-item">
<h3 className="info-title">图片格式</h3>
<p className="info-desc">png/jpg/jpeg/webp</p>
</div>
<div className="info-item">
<h3 className="info-title">分辨率</h3>
<p className="info-desc">建议720×960及以上</p>
</div>
</>
) : (
<>
<div className="info-item">
<h3 className="info-title">视频大小</h3>
<p className="info-desc">最大2GB,时长≤5分钟</p>
</div>
<div className="info-item">
<h3 className="info-title">视频格式</h3>
<p className="info-desc">mp4/mov</p>
</div>
<div className="info-item">
<h3 className="info-title">分辨率</h3>
<p className="info-desc">建议720P及以上</p>
</div>
</>
)}
</div>
</div>
)
}