add mainView, reward, community pages
Change-Id: I70da6ed3e91ebf4124c2074b6508192a19ed9909
diff --git a/src/app/reward/page.tsx b/src/app/reward/page.tsx
new file mode 100644
index 0000000..59abf97
--- /dev/null
+++ b/src/app/reward/page.tsx
@@ -0,0 +1,263 @@
+'use client';
+
+import React, { useEffect, useState, useRef } from "react";
+import { InputText } from 'primereact/inputtext';
+import { Button } from 'primereact/button';
+import { Card } from 'primereact/card';
+import { Image } from 'primereact/image';
+// 页面跳转
+import { useRouter } from 'next/navigation';
+// 分页
+import { Paginator, type PaginatorPageChangeEvent } from 'primereact/paginator';
+// 消息提醒
+import { Toast } from 'primereact/toast';
+// 发布帖子
+import { Dialog } from 'primereact/dialog';
+import { FileUpload } from 'primereact/fileupload';
+import { InputTextarea } from 'primereact/inputtextarea';
+// 接口传输
+import axios from 'axios';
+// 防抖函数
+import { debounce } from 'lodash';
+import { TabView, TabPanel } from 'primereact/tabview';
+// 样式
+import './reward.scss';
+
+// 悬赏列表数据
+interface Reward {
+ rewardId: number;
+ userId: number;
+ rewardPicture: string;
+ rewardName: string;
+ createAt: string;
+ rewardDescription: string;
+ price: number;
+}
+interface RewardList {
+ total: number; // 总记录数
+ records: Reward[];
+}
+
+
+// 社区详情页面
+export default function RewardDetailPage() {
+ // 页面跳转
+ const router = useRouter();
+ // 帖子列表数据
+ const [rewards, setRewards] = useState<Reward[]>([]);
+ const [totalRewards, setTotalRewards] = useState<number>(0);
+ const [activeOption, setActiveOption] = useState<number>(0); // 0表示"赏金最高",1表示"最新发布"
+ const options = ["赏金最高", "最新发布"];
+ // 搜索框
+ const [searchValue, setSearchValue] = useState("");
+ const debouncedSearch = useRef(
+ debounce((value: string) => {
+ setSearchValue(value);
+ }, 600)
+ ).current;
+ // 消息提醒
+ const toast = useRef<Toast>(null);
+ // 分页
+ const [first, setFirst] = useState(0);
+ const [rows, setRows] = useState(5);
+ const onPageChange = (event: PaginatorPageChangeEvent) => {
+ setFirst(event.first);
+ setRows(event.rows);
+ };
+
+ // 获取悬赏列表
+ useEffect(() => {
+ fetchRewards();
+ }, [first, rows, searchValue, activeOption]);
+
+ const fetchRewards = async () => {
+ try {
+ const pageNumber = first / rows + 1;
+ console.log("当前页" + pageNumber + "size" + rows + "搜索内容" + searchValue + "排序方式" + activeOption);
+ const response = await axios.get<RewardList>(
+ process.env.PUBLIC_URL + `/reward`, {
+ params: { pageNumber, rows, searchValue, option: options[activeOption] }
+ }
+ );
+ console.log('获取悬赏列表:', response.data.records);
+ setRewards(response.data.records);
+ setTotalRewards(response.data.total); // 假设返回的总数
+ } catch (err) {
+ console.error('获取悬赏失败', err);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '获取悬赏失败' });
+ }
+ };
+
+ // 发布悬赏弹窗
+ const [visible, setVisible] = useState(false);
+ const [formData, setFormData] = useState({
+ rewardName: '',
+ rewardDescription: '',
+ rewardPicture: '',
+ price: ''
+ });
+ // 图片上传消息通知
+ const onUpload = () => {
+ toast.current?.show({ severity: 'info', summary: 'Success', detail: 'File Uploaded' });
+ };
+
+ // 发布悬赏接口
+ const handleSubmit = async () => {
+ try {
+ const currentDate = new Date().toISOString();
+ const postData = {
+ userId: 22301145, // 记得用户登录状态获取
+ rewardPicture: formData.rewardPicture,
+ rewardName: formData.rewardName,
+ rewardDescription: formData.rewardDescription,
+ createdAt: currentDate,
+ price: formData.price
+ };
+ // 发送POST请求
+ const response = await axios.post(process.env.PUBLIC_URL + '/reward', postData);
+
+ if (response.status === 200) {
+ toast.current?.show({ severity: 'success', summary: 'Success', detail: '悬赏发布成功' });
+ // 发帖成功
+ setVisible(false);
+ // 重置表单
+ setFormData({
+ rewardName: '',
+ rewardDescription: '',
+ rewardPicture: '',
+ price: ''
+ });
+ // 可以刷新帖子列表
+ fetchRewards();
+ }
+ } catch (error) {
+ console.error('发布悬赏失败:', error);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '悬赏发布失败' });
+ }
+ };
+ return (
+ <div className="reward">
+ <Toast ref={toast}></Toast>
+ {/* 悬赏标题和介绍 */}
+ <div className="reward-header">
+ <div className="title-section">
+ <h1>悬赏排行</h1>
+ </div>
+ <div className="input">
+ <div className="searchBar">
+ <i className="pi pi-search" />
+ <InputText type="search" className="search-helper" placeholder="搜索你的目标悬赏" onChange={(e) => { const target = e.target as HTMLInputElement; debouncedSearch(target.value); }} />
+ </div>
+ <div className="reward-buttons">
+ <Button label="我的悬赏" onClick={() => router.push(`/user/悬赏`)} />
+ <Button label="发布悬赏" onClick={() => setVisible(true)} />
+ </div>
+ </div>
+ </div>
+
+ {/* 悬赏列表 */}
+ <TabView activeIndex={activeOption} onTabChange={(e) => setActiveOption(e.index)}>
+ <TabPanel header={options[0]} >
+ <div className="rewards-list">
+ {rewards.map((reward) => (
+ <Card key={reward.rewardId} className="rewards-list-card" onClick={() => router.push(`/reward/reward-detail/${reward.rewardId}`)}>
+ <Image alt="avatar" src={process.env.NEXT_PUBLIC_NGINX_URL + "rewards/" + reward.rewardPicture} className="reward-avatar" width="250" height="140" />
+ <div className="reward-header">
+ <div className="reward-content">
+ <h3>{reward.rewardName}</h3>
+ </div>
+ <div className="reward-states">
+ <span className="price">$: {reward.price}</span>
+ <Button label="提交悬赏" />
+ </div>
+ </div>
+ </Card>
+ ))}
+ {totalRewards > 5 && <Paginator className="Paginator" first={first} rows={rows} totalRecords={totalRewards} rowsPerPageOptions={[5, 10]} onPageChange={onPageChange} />}
+ </div>
+ </TabPanel>
+ <TabPanel header={options[1]}>
+ <div className="rewards-list">
+ {rewards.map((reward) => (
+ <Card key={reward.rewardId} className="rewards-list-card" onClick={() => router.push(`/reward/reward-detail/${reward.rewardId}`)}>
+ <Image alt="avatar" src={process.env.NEXT_PUBLIC_NGINX_URL + reward.rewardPicture} className="reward-avatar" width="250" height="140" />
+ <div className="reward-header">
+ <div className="reward-content">
+ <h3>{reward.rewardName}</h3>
+ </div>
+ <div className="reward-states">
+ <span className="price">$: {reward.price}</span>
+ <Button label="提交悬赏" />
+ </div>
+ </div>
+ </Card>
+ ))}
+ {totalRewards > 5 && <Paginator className="Paginator" first={first} rows={rows} totalRecords={totalRewards} rowsPerPageOptions={[5, 10]} onPageChange={onPageChange} />}
+ </div>
+ </TabPanel>
+ </TabView>
+ {/* 发布悬赏弹窗 */}
+ <Dialog
+ header="发布新悬赏"
+ visible={visible}
+ onHide={() => setVisible(false)}
+ className="publish-dialog"
+ modal
+ footer={
+ <div className="dialog-footer">
+ <Button label="发布" icon="pi pi-check" onClick={handleSubmit} autoFocus />
+ <Button label="取消" icon="pi pi-times" onClick={() => setVisible(false)} className="p-button-text" />
+ </div>
+ }
+ >
+ <div className="publish-form">
+ <div className="form-field">
+ <label htmlFor="title">标题</label>
+ <InputText
+ id="title"
+ value={formData.rewardName}
+ onChange={(e) => setFormData(prev => ({ ...prev, title: e.target.value }))}
+ placeholder="请输入悬赏标题"
+ className="w-full"
+ />
+ </div>
+
+ <div className="form-field">
+ <label htmlFor="content">内容</label>
+ <InputTextarea
+ id="content"
+ value={formData.rewardDescription}
+ onChange={(e) => setFormData(prev => ({ ...prev, content: e.target.value }))}
+ rows={5}
+ placeholder="请输入悬赏需求"
+ className="w-full"
+ />
+ </div>
+ <div className="form-field">
+ <label htmlFor="price">赏金</label>
+ <InputText
+ id="price"
+ value={formData.price}
+ onChange={(e) => setFormData(prev => ({ ...prev, price: e.target.value }))}
+ placeholder="请输入赏金金额"
+ className="w-full"
+ />
+ </div>
+ <div className="form-field">
+ <label>封面图片</label>
+ <FileUpload
+ mode="basic"
+ name="thread-image"
+ url={process.env.PUBLIC_URL +"/file"} // 与后端交互的URL
+ accept="image/*"
+ maxFileSize={10000000000}
+ chooseLabel="选择悬赏封面"
+ className="w-full"
+ onUpload={onUpload}
+ />
+ </div>
+ </div>
+ </Dialog>
+ </div>
+ );
+}
\ No newline at end of file