blob: 6c18cf0181aac2b902aa05ec1b28c8bed2b27c51 [file] [log] [blame]
LaoeGaoci85307e62025-05-30 23:28:42 +08001'use client';
lfmylbhf223a10f2025-06-08 20:50:31 +08002import React, {useEffect, useRef, useState} from 'react';
3// import {TabView, TabPanel} from "primereact/tabview";
4import {Card} from "primereact/card";
5import {Image} from "primereact/image";
6import {Button} from "primereact/button";
7// 弹窗
8import { Dialog } from 'primereact/dialog';
9import {InputText} from "primereact/inputtext";
10import {InputTextarea} from "primereact/inputtextarea";
11import {FileUpload} from "primereact/fileupload";
12// 类型转换
13import {toNumber} from "lodash";
14// 消息提醒
15import {Toast} from 'primereact/toast';
16// 接口传输
17import axios from "axios";
18// 页面跳转
19import {useRouter} from "next/navigation";
20// 分页
21import { Paginator, type PaginatorPageChangeEvent } from 'primereact/paginator';
22// 密码
23import { Password } from 'primereact/password';
24// 样式
25import './resources.scss';
LaoeGaoci85307e62025-05-30 23:28:42 +080026
lfmylbhf223a10f2025-06-08 20:50:31 +080027
28
29// 用户发布的资源
30interface Resource {
31 resourceId: number;
32 resourceName: string;
33 resourcePicture: string;
34 resourceSummary: string; // 资源简介(一句话)
35 resourceDetail: string; // 资源介绍
36 uploadTime: string; // 上传时间
37 lastUpdateTime: string; // 最近更新时间
38 price: number;
39 downloads: number;
40 likes: number;
41 collections: number;
42 comments: number;
43 seeds: number; // 种子数
44 classify: string; // 资源分类(材质包:resourcePack,模组:mod,整合包:modPack ,地图:map
45}
46
47// 用户发布的资源列表
48interface ResourceList {
49 records: Resource[];
50 total: number; // 总记录数
51 pages: number; // 总页数
52 current: number; // 当前页码
53 sizes: number; // 每页大小
54}
55
56export default function UserManageResources() {
57 // 路由
58 const router = useRouter();
59 // 发布资源列表
60 const [resourceList, setResourceList] = useState<Resource[]>([]);
61 // 要删除资源的id
62 const [deleteResourceId, setDeleteResourceId] = useState<number>(0);
63 // 资源封面路径
64 const [resourcePictureUrl, setResourcePictureUrl] = useState<string>('');
65 // 编辑资源的分类
66 const [resourceClassify, setResourceClassify] = useState<string>('');
67 // 消息提醒
68 const toast = useRef<Toast>(null);
69 // 分页
70 const [first, setFirst] = useState(0);
71 const [rows, setRows] = useState(5);
72 const [totalResources, setTotalResources] = useState<number>(0);
73 const onPageChange = (event: PaginatorPageChangeEvent) => {
74 setFirst(event.first);
75 setRows(event.rows);
76 };
77 // 删除资源弹窗
78 const [deleteVisible, setDeleteVisible] = useState(false);
79 const [deleteResourceFormData, setDeleteResourceFormData] = useState({
80 password: '',
81 });
82
83 // 编辑资源弹窗
84 const [editVisible, setEditVisible] = useState(false);
85 const [editResourceFormData, setEditResourceFormData] = useState({
86 resourceId: 0,
87 resourceName: '',
88 resourceSummary: '',
89 resourceDetail: '',
90 price: '',
91 });
92
93 useEffect(() => {
94 fetchResourceList();
95 }, [first, rows]);
96
97
98 // 获取用户发布资源
99 const fetchResourceList = async () => {
100 try {
101 const pageNumber = first / rows + 1;
102 const response = await axios.get<ResourceList>(process.env.PUBLIC_URL + `/user/upload`, {
103 params: {userId: 22301010, pageNumber: pageNumber, rows: rows}
104 });
105
106 console.log('获取发布资源列表:', response.data.records);
107 setResourceList(response.data.records);
108 setTotalResources(response.data.total);
109 } catch (err) {
110 console.error('获取发布资源失败', err);
111 toast.current?.show({severity: 'error', summary: 'error', detail: '获取发布资源失败'});
112 }
113 };
114
115 // 处理删除资源接口
116 const handleDeleteSubmit = async () => {
117 try {
118 const deleteData = {
119 resourceId: deleteResourceId,
120 userId: 223010100,
121 password: deleteResourceFormData.password,
122 };
123 // 发送DELETE请求
124 const response = await axios.delete(process.env.PUBLIC_URL + `/resource`, {
125 params: {resourceId: deleteData.resourceId, userId: deleteData.userId, password: deleteData.password},
126 });
127 console.log("用户" + 22301010 + "要删除" + deleteData.resourceId + "号资源");
128 console.log(deleteData);
129 console.log(response);
130 console.log(response.status)
131
132 if (response.status === 204) {
133 console.log("用户成功删除资源");
134 // setIsDeleteResource(true);
135 toast.current?.show({severity: 'success', summary: 'Success', detail: '删除资源成功'});
136 setDeleteVisible(false);
137 // 重置表单
138 setDeleteResourceFormData({
139 password: '',
140 });
141 // 重新拉取资源列表
142 fetchResourceList();
143 } else {
144 console.log('用户密码错误');
145 toast.current?.show({severity: 'error', summary: 'Error', detail: '密码错误,删除资源失败'});
146 }
147
148 } catch (error) {
149 console.error('资源删除失败:', error);
150 toast.current?.show({ severity: 'error', summary: 'error', detail: '密码错误,资源删除失败' });
151 }
152 };
153
154 // 处理编辑资源接口
155 const handleEditSubmit = async () => {
156 try {
157 const postData = {
158 resourceId: editResourceFormData.resourceId,
159 resourceName: editResourceFormData.resourceName,
160 resourcePicture: resourcePictureUrl,
161 resourceSummary: editResourceFormData.resourceSummary,
162 resourceDetail: editResourceFormData.resourceDetail,
163 price: toNumber(editResourceFormData.price),
164 classify: resourceClassify,
165 };
166 // 发送POST请求
167 const response = await axios.put(process.env.PUBLIC_URL + '/resource/info', postData);
168 console.log("编辑资源的信息:", postData);
169
170 if (response.status === 200) {
171 toast.current?.show({ severity: 'success', summary: 'Success', detail: '资源编辑成功' });
172 // 编辑成功
173 setEditVisible(false);
174 fetchResourceList();
175 }
176 } catch (error) {
177 console.error('资源上传失败:', error);
178 toast.current?.show({ severity: 'error', summary: 'error', detail: '资源上传失败' });
179 }
180 };
181
182 return (
183 <div className="resources-container">
184 <Toast ref={toast}></Toast>
185 <div className="resources-title">
186 <h1>我上传的资源</h1>
187 </div>
188
189 <div className="resource-list">
190 {resourceList.map((resourceList) => (
191 <Card key={resourceList.resourceId} className="resources-list-card"
192 onClick={() => router.push(`/resource/resource-detail/${resourceList.resourceId}`)}>
193 <Image alt="avatar"
194 src={process.env.NEXT_PUBLIC_NGINX_URL + "resource/" + resourceList.resourcePicture}
195 className="resource-avatar" width="250" height="140"/>
196 <div className="resource-header">
197 <div className="resource-content">
198 <h3>{resourceList.resourceName}</h3>
199 </div>
200
201 <div className="resource-operation">
202 <Button
203 label="编辑"
204 onClick={(e) => {
205 e.stopPropagation(); // 关键修复:阻止事件冒泡,避免触发Card的点击事件
206 setEditVisible(true);
207
208 setResourceClassify(resourceList.classify);
209 setEditResourceFormData({
210 resourceId: resourceList.resourceId,
211 resourceName: resourceList.resourceName,
212 resourceSummary: resourceList.resourceSummary,
213 resourceDetail: resourceList.resourceDetail,
214 price: resourceList.price.toString(),
215 });
216 console.log("用户编辑资源");
217 }}
218 />
219 <Button
220 label="删除"
221 onClick={(e) => {
222 e.stopPropagation(); // 关键修复:阻止事件冒泡,避免触发Card的点击事件
223 setDeleteResourceId(resourceList.resourceId);
224 setDeleteVisible(true);
225 }}
226 style={{backgroundColor: "rgba(255, 87, 51, 1)"}}
227 />
228 </div>
229 </div>
230 </Card>
231 ))}
232 {totalResources > 5 && <Paginator
233 className="Paginator"
234 first={first}
235 rows={rows}
236 totalRecords={totalResources}
237 rowsPerPageOptions={[5, 10]}
238 onPageChange={onPageChange}
239 />}
240 </div>
241
242 {/*删除资源时,获取用户密码弹窗*/}
243 <Dialog
244 header="删除资源"
245 visible={deleteVisible}
246 onHide={() => setDeleteVisible(false)}
247 className="resource-delete-dialog"
248 modal
249 footer={
250 <div className="dialog-footer">
251 <Button label="确认" icon="pi pi-check" onClick={handleDeleteSubmit} autoFocus />
252 <Button label="取消" icon="pi pi-times" onClick={() => setDeleteVisible(false)} className="p-button-text" />
253 </div>
254 }
255 >
256 <div className="dialog-form">
257 <div className="form-field">
258 <div className="form-field-header">
259 <label htmlFor="name">密码</label>
260 </div>
261 <Password
262 id="passwrod"
263 value={deleteResourceFormData.password}
264 onChange={(e) => setDeleteResourceFormData(prev => ({
265 ...prev,
266 password: e.target.value
267 }))}
268 placeholder="请输入密码"
269 className="w-full"
270 toggleMask
271 />
272 </div>
273 </div>
274 </Dialog>
275
276 {/*编辑资源弹窗*/}
277 <Dialog
278 header="编辑资源"
279 visible={editVisible}
280 onHide={() => setEditVisible(false)}
281 className="resource-edit-dialog"
282 modal
283 footer={
284 <div className="dialog-footer">
285 <Button label="确认" icon="pi pi-check" onClick={handleEditSubmit} autoFocus />
286 <Button label="取消" icon="pi pi-times" onClick={() => setEditVisible(false)} className="p-button-text" />
287 </div>
288 }
289 >
290 <div className="dialog-form">
291 <div className="form-field">
292 <div className="form-field-header">
293 <label htmlFor="name">资源名称</label>
294 </div>
295 <InputText
296 id="name"
297 value={editResourceFormData.resourceName}
298 onChange={(e) => setEditResourceFormData(prev => ({
299 ...prev,
300 resourceName: e.target.value
301 }))}
302 className="w-full"
303 />
304 </div>
305 <div className="form-field">
306 <div className="form-field-header">
307 <label htmlFor="summary">资源简介</label>
308 </div>
309 <InputText
310 id="summary"
311 value={editResourceFormData.resourceSummary}
312 onChange={(e) => setEditResourceFormData(prev => ({
313 ...prev,
314 resourceSummary: e.target.value
315 }))}
316 className="w-full"
317 />
318 </div>
319 <div className="form-field">
320 <div className="form-field-header">
321 <label htmlFor="detail">资源介绍</label>
322 </div>
323 <InputTextarea
324 id="detail"
325 value={editResourceFormData.resourceDetail}
326 onChange={(e) => setEditResourceFormData(prev => ({
327 ...prev,
328 resourceDetail: e.target.value
329 }))}
330 rows={5}
331 className="w-full"
332 />
333 </div>
334 <div className="form-field">
335 <div className="form-field-header">
336 <label htmlFor="price">价格</label>
337 </div>
338 <InputText
339 id="price"
340 value={editResourceFormData?.price.toString()}
341 onChange={(e) => setEditResourceFormData(prev => ({
342 ...prev,
343 price: e.target.value
344 }))}
345 className="w-full"
346 />
347 </div>
348 <div className="form-field">
349 <div className="form-field-header">
350 <span className="form-field-sign">*</span>
351 <label>封面图片</label>
352 </div>
353
354 <FileUpload
355 mode="advanced"
356 name="resource-image"
357 customUpload
358
359 uploadHandler={async (e) => {
360 const formData = new FormData();
361 formData.append("file", e.files[0]);
362
363 try {
364 const res = await axios.post(`${process.env.PUBLIC_URL}/file`, formData);
365
366 const fileUrl = res.data.url;
367 console.log(fileUrl);
368 setResourcePictureUrl(fileUrl);
369 toast.current?.show({ severity: 'success', summary: '上传成功' });
370 } catch (error) {
371 console.log(error);
372 toast.current?.show({ severity: 'error', summary: '上传失败' });
373 }
374 }}
375 auto
376 accept="image/*"
377 chooseLabel="选择资源封面"
378 />
379 </div>
380 </div>
381 </Dialog>
382 </div>
383 )
LaoeGaoci85307e62025-05-30 23:28:42 +0800384};