合并JWL,WZY,TRM代码
Change-Id: Ifb4fcad3c06733e1e005e7d8d9403e3561010fb4
diff --git a/Merge/front/src/components/CreatePost.jsx b/Merge/front/src/components/CreatePost.jsx
new file mode 100644
index 0000000..7519d5b
--- /dev/null
+++ b/Merge/front/src/components/CreatePost.jsx
@@ -0,0 +1,168 @@
+// src/components/CreatePost.jsx
+
+import React, { useState } from 'react'
+import { useNavigate } from 'react-router-dom'
+import UploadPage from './UploadPage'
+import { createPost } from '../api/posts_wzy'
+import '../style/CreatePost.css'
+
+export default function CreatePost() {
+ const navigate = useNavigate()
+
+ const [step, setStep] = useState('upload') // 'upload' | 'detail'
+ const [files, setFiles] = useState([]) // 本地 File 对象列表
+ const [mediaUrls, setMediaUrls] = useState([]) // 上传后得到的 URL 列表
+
+ // 详情表单字段
+ const [title, setTitle] = useState('')
+ const [content, setContent] = useState('')
+ const [topicId, setTopicId] = useState('')
+ const [status, setStatus] = useState('published')
+
+ const [error, setError] = useState(null)
+
+ // 静态话题数据
+ const TOPICS = [
+ { id: 1, name: '世俱杯环球评大会' },
+ { id: 2, name: '我的REDmentor' },
+ { id: 3, name: '我染上了拼豆' },
+ // …更多静态话题…
+ ]
+
+ // 上传页面回调 —— 上传完成后切换到“填写详情”步骤
+ const handleUploadComplete = async uploadedFiles => {
+ setFiles(uploadedFiles)
+
+ // TODO: 改成真实上传逻辑,拿到真正的 media_urls
+ const urls = await Promise.all(
+ uploadedFiles.map(f => URL.createObjectURL(f))
+ )
+ setMediaUrls(urls)
+
+ setStep('detail')
+ }
+
+ // 发布按钮
+ const handleSubmit = async () => {
+ if (!title.trim() || !content.trim()) {
+ setError('标题和正文必填')
+ return
+ }
+ setError(null)
+ try {
+ await createPost({
+ user_id: 1,
+ topic_id: topicId || undefined,
+ title: title.trim(),
+ content: content.trim(),
+ media_urls: mediaUrls,
+ status
+ })
+ // 发布成功后跳转回首页
+ navigate('/home', { replace: true })
+ } catch (e) {
+ setError(e.message)
+ }
+ }
+
+ // 渲染上传页
+ if (step === 'upload') {
+ return <UploadPage onComplete={handleUploadComplete} />
+ }
+
+ // 渲染详情页
+ return (
+ <div className="create-post">
+ <h2>填写帖子内容</h2>
+ {error && <div className="error">{error}</div>}
+
+ {/* 已上传媒体预览 */}
+ <div className="preview-media">
+ {mediaUrls.map((url, i) => (
+ <div key={i} className="preview-item">
+ {files[i].type.startsWith('image/') ? (
+ <img src={url} alt={`预览 ${i}`} />
+ ) : (
+ <video src={url} controls />
+ )}
+ </div>
+ ))}
+ </div>
+
+ {/* 标题 */}
+ <label className="form-label">
+ 标题(最多20字)
+ <input
+ type="text"
+ maxLength={20}
+ value={title}
+ onChange={e => setTitle(e.target.value)}
+ placeholder="填写标题会有更多赞哦~"
+ />
+ <span className="char-count">{title.length}/20</span>
+ </label>
+
+ {/* 正文 */}
+ <label className="form-label">
+ 正文(最多1000字)
+ <textarea
+ maxLength={1000}
+ value={content}
+ onChange={e => setContent(e.target.value)}
+ placeholder="输入正文描述,真诚有价值的分享予人温暖"
+ />
+ <span className="char-count">{content.length}/1000</span>
+ </label>
+
+ {/* 话题选择 */}
+ <label className="form-label">
+ 选择话题(可选)
+ <select
+ value={topicId}
+ onChange={e => setTopicId(e.target.value)}
+ >
+ <option value="">不添加话题</option>
+ {TOPICS.map(t => (
+ <option key={t.id} value={t.id}>
+ #{t.name}
+ </option>
+ ))}
+ </select>
+ </label>
+
+ {/* 发布状态 */}
+ <div className="status-group">
+ <label>
+ <input
+ type="radio"
+ name="status"
+ value="published"
+ checked={status === 'published'}
+ onChange={() => setStatus('published')}
+ />
+ 立即发布
+ </label>
+ <label>
+ <input
+ type="radio"
+ name="status"
+ value="draft"
+ checked={status === 'draft'}
+ onChange={() => setStatus('draft')}
+ />
+ 存为草稿
+ </label>
+ </div>
+
+ {/* 操作按钮 */}
+ <div className="btn-group">
+ <button className="btn btn-primary" onClick={handleSubmit}>
+ 发布
+ </button>
+ <button className="btn btn-secondary" onClick={() => setStep('upload')}>
+ 上一步
+ </button>
+ </div>
+ </div>
+ )
+}