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