blob: 7519d5b1864127d9a37e90a678eaaf9ad2803968 [file] [log] [blame]
TRM-codingd1cbf672025-06-18 15:15:08 +08001// src/components/CreatePost.jsx
2
3import React, { useState } from 'react'
4import { useNavigate } from 'react-router-dom'
5import UploadPage from './UploadPage'
6import { createPost } from '../api/posts_wzy'
7import '../style/CreatePost.css'
8
9export default function CreatePost() {
10 const navigate = useNavigate()
11
12 const [step, setStep] = useState('upload') // 'upload' | 'detail'
13 const [files, setFiles] = useState([]) // 本地 File 对象列表
14 const [mediaUrls, setMediaUrls] = useState([]) // 上传后得到的 URL 列表
15
16 // 详情表单字段
17 const [title, setTitle] = useState('')
18 const [content, setContent] = useState('')
19 const [topicId, setTopicId] = useState('')
20 const [status, setStatus] = useState('published')
21
22 const [error, setError] = useState(null)
23
24 // 静态话题数据
25 const TOPICS = [
26 { id: 1, name: '世俱杯环球评大会' },
27 { id: 2, name: '我的REDmentor' },
28 { id: 3, name: '我染上了拼豆' },
29 // …更多静态话题…
30 ]
31
32 // 上传页面回调 —— 上传完成后切换到“填写详情”步骤
33 const handleUploadComplete = async uploadedFiles => {
34 setFiles(uploadedFiles)
35
36 // TODO: 改成真实上传逻辑,拿到真正的 media_urls
37 const urls = await Promise.all(
38 uploadedFiles.map(f => URL.createObjectURL(f))
39 )
40 setMediaUrls(urls)
41
42 setStep('detail')
43 }
44
45 // 发布按钮
46 const handleSubmit = async () => {
47 if (!title.trim() || !content.trim()) {
48 setError('标题和正文必填')
49 return
50 }
51 setError(null)
52 try {
53 await createPost({
54 user_id: 1,
55 topic_id: topicId || undefined,
56 title: title.trim(),
57 content: content.trim(),
58 media_urls: mediaUrls,
59 status
60 })
61 // 发布成功后跳转回首页
62 navigate('/home', { replace: true })
63 } catch (e) {
64 setError(e.message)
65 }
66 }
67
68 // 渲染上传页
69 if (step === 'upload') {
70 return <UploadPage onComplete={handleUploadComplete} />
71 }
72
73 // 渲染详情页
74 return (
75 <div className="create-post">
76 <h2>填写帖子内容</h2>
77 {error && <div className="error">{error}</div>}
78
79 {/* 已上传媒体预览 */}
80 <div className="preview-media">
81 {mediaUrls.map((url, i) => (
82 <div key={i} className="preview-item">
83 {files[i].type.startsWith('image/') ? (
84 <img src={url} alt={`预览 ${i}`} />
85 ) : (
86 <video src={url} controls />
87 )}
88 </div>
89 ))}
90 </div>
91
92 {/* 标题 */}
93 <label className="form-label">
94 标题(最多20字)
95 <input
96 type="text"
97 maxLength={20}
98 value={title}
99 onChange={e => setTitle(e.target.value)}
100 placeholder="填写标题会有更多赞哦~"
101 />
102 <span className="char-count">{title.length}/20</span>
103 </label>
104
105 {/* 正文 */}
106 <label className="form-label">
107 正文(最多1000字)
108 <textarea
109 maxLength={1000}
110 value={content}
111 onChange={e => setContent(e.target.value)}
112 placeholder="输入正文描述,真诚有价值的分享予人温暖"
113 />
114 <span className="char-count">{content.length}/1000</span>
115 </label>
116
117 {/* 话题选择 */}
118 <label className="form-label">
119 选择话题(可选)
120 <select
121 value={topicId}
122 onChange={e => setTopicId(e.target.value)}
123 >
124 <option value="">不添加话题</option>
125 {TOPICS.map(t => (
126 <option key={t.id} value={t.id}>
127 #{t.name}
128 </option>
129 ))}
130 </select>
131 </label>
132
133 {/* 发布状态 */}
134 <div className="status-group">
135 <label>
136 <input
137 type="radio"
138 name="status"
139 value="published"
140 checked={status === 'published'}
141 onChange={() => setStatus('published')}
142 />
143 立即发布
144 </label>
145 <label>
146 <input
147 type="radio"
148 name="status"
149 value="draft"
150 checked={status === 'draft'}
151 onChange={() => setStatus('draft')}
152 />
153 存为草稿
154 </label>
155 </div>
156
157 {/* 操作按钮 */}
158 <div className="btn-group">
159 <button className="btn btn-primary" onClick={handleSubmit}>
160 发布
161 </button>
162 <button className="btn btn-secondary" onClick={() => setStep('upload')}>
163 上一步
164 </button>
165 </div>
166 </div>
167 )
168}