add resource detail and user part interface
Change-Id: I83541b5dc80bde465878cdccdbc77431b56dbff6
diff --git a/src/app/user/page.tsx b/src/app/user/page.tsx
new file mode 100644
index 0000000..0af92a4
--- /dev/null
+++ b/src/app/user/page.tsx
@@ -0,0 +1,356 @@
+'use client';
+
+import React, { useEffect, useState, useRef } from 'react';
+import { TabView, TabPanel } from 'primereact/tabview';
+import { Avatar } from 'primereact/avatar';
+import { Button } from 'primereact/button';
+import { Card } from 'primereact/card';
+import {Image} from "primereact/image";
+// 浮动按钮
+import { SpeedDial } from 'primereact/speeddial';
+// 评分图标
+import { Fire } from '@icon-park/react';
+// 消息提醒
+import { Toast } from 'primereact/toast';
+// 页面跳转
+import { useRouter } from "next/navigation";
+// import Link from 'next/link';
+
+// 接口传输
+import axios from "axios";
+
+// 样式
+import './user.scss';
+
+
+
+// 用户信息
+interface UserInfo {
+ userId: number;
+ username: string;
+ password: string;
+ avatar: string;
+ followerCount: number;// 粉丝数
+ subscriberCount: number;// 关注数
+ signature: string;// 个性签名
+ uploadAmount: number;
+ purchaseAmount: number;
+ credits: number;
+}
+
+// 用户数据
+interface UserData {
+ subscriberCount: number; // 关注数
+ uploadAmount: number; // 上传量(资源个数)
+ beDownloadedAmount: number; // 上传资源被下载量
+ seedPercentageList: number[]; // 上传资源类型百分比列表,按材质包、模组、整合包、地图的顺序返回
+}
+
+// 用户发布的资源
+interface Resource {
+ resourceId: number;
+ resourceName: string;
+ resourcePicture: string;
+ resourceSummary: string; // 资源简介(一句话)
+ resourceDetail: string; // 资源介绍
+ uploadTime: string; // 上传时间
+ lastUpdateTime: string; // 最近更新时间
+ price: number;
+ downloads: number;
+ likes: number;
+ collections: number;
+ comments: number;
+ seeds: number; // 种子数
+ classify: string; // 资源分类(材质包:resourcePack,模组:mod,整合包:modPack ,地图:map
+}
+
+// 用户发布的资源列表
+interface ResourceList {
+ records: Resource[];
+}
+
+export default function UserPage() {
+ // 路由
+ const router = useRouter();
+ // 发布资源列表
+ const [resourceList, setResourceList] = useState<Resource[]>([]);
+ // 用户信息
+ const [userInfo, setUserInfo] = useState<UserInfo>();
+ // 用户数据
+ const [userData, setUserData] = useState<UserData>();
+ // 消息提醒
+ const toast = useRef<Toast>(null);
+
+
+ useEffect(() => {
+ fetchUserInfo();
+ fetchUserData();
+ fetchResourceList();
+ }, []);
+
+ // 获取用户信息
+ const fetchUserInfo = async () => {
+ try {
+ const response = await axios.get<UserInfo>(process.env.PUBLIC_URL + `/user/info`, {
+ params: { userId: 22301010 }
+ });
+ console.log('获取用户信息:', response.data);
+ setUserInfo(response.data);
+ } catch (err) {
+ console.error('获取用户信息失败', err);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '获取用户信息失败' });
+ }
+ };
+
+ // 获取用户数据
+ const fetchUserData = async () => {
+ try {
+ const response = await axios.get<UserData>(process.env.PUBLIC_URL + `/user/data`, {
+ params: { userId: 22301010 }
+ });
+ console.log('获取用户数据:', response.data);
+ setUserData(response.data);
+ } catch (err) {
+ console.error('获取用户数据失败', err);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '获取用户数据失败' });
+ }
+ };
+
+ // 格式化数字显示 (3000 -> 3k)
+ const formatCount = (count?: number): string => {
+ if (count == null) return "0"; // 同时处理 undefined/null
+
+ const absCount = Math.abs(count); // 处理负数
+
+ const format = (num: number, suffix: string) => {
+ const fixed = num.toFixed(1);
+ return fixed.endsWith('.0')
+ ? `${Math.floor(num)}${suffix}`
+ : `${fixed}${suffix}`;
+ };
+
+ if (absCount >= 1e6) return format(count / 1e6, "m");
+ if (absCount >= 1e3) return format(count / 1e3, "k");
+ return count.toString();
+ };
+
+ // 获取发布资源
+ const fetchResourceList = async () => {
+ try {
+ const response = await axios.get<ResourceList>(process.env.PUBLIC_URL +`/user/upload`, {
+ params: { userId: 22301010, pageNumber: 1, rows: 3 }
+ });
+ console.log('获取发布资源列表:', response.data.records);
+ setResourceList(response.data.records);
+
+ // const imgUrl = `${process.env.NEXT_PUBLIC_NGINX_URL}/${resourceList[0].resourcePicture}`;
+ // console.log("Image URL:", imgUrl);
+ } catch (err) {
+ console.error('获取发布资源失败', err);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '获取发布资源失败' });
+ }
+ };
+
+ // 浮动按钮的子模块
+ const actions = [
+ {
+ template: () => (
+ <Button label="管理资源" onClick={() => router.push(`/user/manage/resources/`)}/>
+ )
+ },
+ {
+ template: () => (
+ <Button label="已购资源" onClick={() => router.push(`/user/purchased-resources/`)}/>
+ )
+ },
+ {
+ template: () => (
+ <Button label="发布资源" onClick={() => router.push(`/user/manage/resources/`)}/>
+ )
+ },
+ {
+ template: () => (
+ <Button label="编辑悬赏" onClick={() => router.push(`/user/manage/resources/`)}/>
+ )
+ }
+ ];
+
+
+
+
+ return (
+ <div className="user-container">
+
+ {/*个人信息*/}
+ <div className="user-profile-card">
+ <Avatar
+ image={`${process.env.NEXT_PUBLIC_NGINX_URL}/users/${userInfo?.avatar}`}
+ className="user-avatar"
+ shape="circle"
+ />
+ <div className="user-info">
+ <div className="user-detail-info">
+ <div className="name-container">
+ <h2 className="name">{userInfo?.username}</h2>
+ <span className="signature">{userInfo?.signature}</span>
+ </div>
+
+ <div className="stats-container">
+ <div className="stats">
+ <span className="stats-label">粉丝:</span>
+ <span className="stats-value">{userInfo?.followerCount}</span>
+ </div>
+ <div className="stats">
+ <span className="stats-label">累计上传量:</span>
+ <span className="stats-value">{formatCount(userData?.uploadAmount)}</span>
+ </div>
+ <div className="stats">
+ <span className="stats-label">关注:</span>
+ <span className="stats-value">{userInfo?.subscriberCount}</span>
+ </div>
+ <div className="stats">
+ <span className="stats-label">累计被下载量:</span>
+ <span className="stats-value">{formatCount(userData?.beDownloadedAmount)}</span>
+ </div>
+ </div>
+ </div>
+
+ <Button label="关注" className="action-button"/>
+ </div>
+ </div>
+
+ {/*个人内容*/}
+ <TabView>
+ <TabPanel header="主页">
+ {/*推荐资源*/}
+ <div className="homepage-item">
+ <div className="section-header">
+ <h1>推荐资源</h1>
+ <Button
+ label="显示更多"
+ link
+ onClick={() => router.push('/resource/recommend/模组')}
+ />
+ </div>
+ <div className="resource-grid">
+ {/*{mods.map((mod) => (*/}
+ {/* <Card key={mod.resourceId} className="resource-card" onClick={() => router.push(`/resource/resource-detail/${mod.resourceId}`)}>*/}
+ {/* <Image*/}
+ {/* src={process.env.NEXT_PUBLIC_NGINX_URL + mod.resourcePicture}*/}
+ {/* alt={mod.resourceName}*/}
+ {/* width="368"*/}
+ {/* height="200"*/}
+ {/* />*/}
+ {/* <div className="card-content">*/}
+ {/* <h3>{mod.resourceName}</h3>*/}
+ {/* <div className="view-count">*/}
+ {/* <Fire theme="outline" size="16" fill="#FF8D1A" />*/}
+ {/* <span>{mod.likes}</span>*/}
+ {/* </div>*/}
+ {/* </div>*/}
+ {/* </Card>*/}
+ {/*))}*/}
+ </div>
+ </div>
+
+ {/*发布资源*/}
+ <div className="homepage-item">
+ <div className="section-header">
+ <h1>发布资源</h1>
+ <Button
+ label="显示更多"
+ link
+ onClick={() => router.push('/user/manage/resources/')}
+ />
+ </div>
+ <div className="resource-grid">
+ {resourceList.map((resourceList) => (
+ <Card key={resourceList.resourceId} className="resource-card" onClick={() => router.push(`/resource/resource-detail/${resourceList.resourceId}`)}>
+ <Image
+ src={process.env.NEXT_PUBLIC_NGINX_URL + resourceList.resourcePicture}
+ alt={resourceList.resourceName}
+ width="368"
+ height="200"
+ />
+ <div className="card-content">
+ <h3>{resourceList.resourceName}</h3>
+ <div className="view-count">
+ <Fire theme="outline" size="16" fill="#FF8D1A" />
+ <span>{resourceList.likes}</span>
+ </div>
+ </div>
+ </Card>
+ ))}
+ </div>
+ </div>
+
+ {/*发布帖子*/}
+ <div className="homepage-item">
+ <div className="section-header">
+ <h1>发布帖子</h1>
+ <Button
+ label="显示更多"
+ link
+ onClick={() => router.push('/resource/recommend/模组')}
+ />
+ </div>
+ <div className="resource-grid">
+
+ {/*{mods.map((mod) => (*/}
+ {/* <Card key={mod.resourceId} className="resource-card" onClick={() => router.push(`/resource/resource-detail/${mod.resourceId}`)}>*/}
+ {/* <Image*/}
+ {/* src={process.env.NEXT_PUBLIC_NGINX_URL + mod.resourcePicture}*/}
+ {/* alt={mod.resourceName}*/}
+ {/* width="368"*/}
+ {/* height="200"*/}
+ {/* />*/}
+ {/* <div className="card-content">*/}
+ {/* <h3>{mod.resourceName}</h3>*/}
+ {/* <div className="view-count">*/}
+ {/* <Fire theme="outline" size="16" fill="#FF8D1A" />*/}
+ {/* <span>{mod.likes}</span>*/}
+ {/* </div>*/}
+ {/* </div>*/}
+ {/* </Card>*/}
+ {/*))}*/}
+ </div>
+ </div>
+ </TabPanel>
+
+ <TabPanel header="发布">
+
+ </TabPanel>
+
+ <TabPanel header="帖子">
+
+ </TabPanel>
+
+ <TabPanel header="收藏">
+
+ </TabPanel>
+
+ <TabPanel header="数据">
+
+ </TabPanel>
+
+ <TabPanel header="悬赏">
+
+ </TabPanel>
+ </TabView>
+
+ {/*浮动按钮*/}
+ <div className="card">
+ <SpeedDial
+ model={actions}
+ direction="up"
+ style={{ position: 'fixed', bottom: '2rem', right: '2rem' }}
+ showIcon="pi pi-plus"
+ hideIcon="pi pi-times"
+ buttonClassName="custom-speeddial-button"
+ />
+ </div>
+
+ </div>
+ );
+};
+