Merge "add reward manage" into main
diff --git a/src/app/user/manage/resources/page.tsx b/src/app/user/manage/resources/page.tsx
index 6c18cf0..e3b7301 100644
--- a/src/app/user/manage/resources/page.tsx
+++ b/src/app/user/manage/resources/page.tsx
@@ -126,8 +126,6 @@
});
console.log("用户" + 22301010 + "要删除" + deleteData.resourceId + "号资源");
console.log(deleteData);
- console.log(response);
- console.log(response.status)
if (response.status === 204) {
console.log("用户成功删除资源");
diff --git "a/src/app/user/manage/rewards/data/\133rewardId\135/page.tsx" "b/src/app/user/manage/rewards/data/\133rewardId\135/page.tsx"
deleted file mode 100644
index c48b626..0000000
--- "a/src/app/user/manage/rewards/data/\133rewardId\135/page.tsx"
+++ /dev/null
@@ -1,12 +0,0 @@
-'use client';
-import React from 'react';
-
-const EmptyPage: React.FC = () => {
- return (
- <div className="p-d-flex p-jc-center p-ai-center" style={{ height: '100vh' }}>
- {"一个空页面"}
- </div>
- );
-};
-
-export default EmptyPage;
diff --git a/src/app/user/manage/rewards/page.tsx b/src/app/user/manage/rewards/page.tsx
deleted file mode 100644
index c48b626..0000000
--- a/src/app/user/manage/rewards/page.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-'use client';
-import React from 'react';
-
-const EmptyPage: React.FC = () => {
- return (
- <div className="p-d-flex p-jc-center p-ai-center" style={{ height: '100vh' }}>
- {"一个空页面"}
- </div>
- );
-};
-
-export default EmptyPage;
diff --git a/src/app/user/page.tsx b/src/app/user/page.tsx
index 7a1b631..1172aeb 100644
--- a/src/app/user/page.tsx
+++ b/src/app/user/page.tsx
@@ -23,13 +23,16 @@
import { Toast } from 'primereact/toast';
// 页面跳转
import { useRouter } from "next/navigation";
+// 类型转换
+import {toNumber} from "lodash";
+// 分页
+import { Paginator, type PaginatorPageChangeEvent } from 'primereact/paginator';
// 接口传输
import axios from "axios";
// 样式
import './user.scss';
-import {toNumber} from "lodash";
// 用户信息
interface UserInfo {
@@ -76,6 +79,42 @@
records: Resource[];
}
+// 帖子
+interface Thread {
+ threadId: number;
+ userId: number;
+ threadPicture: string;
+ title: string;
+ likes: number;
+ createAt: string;
+}
+
+// 发布帖子列表
+interface ThreadList {
+ records: Thread[];
+ total: number;
+ pages: number;
+ current: number;
+ size: number;
+}
+
+// 悬赏
+interface Reward {
+ rewardId: number;
+ userId: number;
+ rewardPicture: string;
+ rewardName: string;
+ createAt: string;
+ rewardDescription: string;
+ price: number;
+}
+
+// 我的悬赏列表
+interface RewardList {
+ rewardList: Reward[];
+ total: number; // 总记录数
+}
+
// 资源标签
interface GameplayOption {
name: string;
@@ -112,8 +151,32 @@
const toast = useRef<Toast>(null);
// 资源标签
const [selectedGameplay, setSelectedGameplay] = useState<GameplayOption[]>([]);
- // 判断用户是否上传资源封面
- const [isUploadPicture, setIsUploadPicture] = useState<boolean>(false);
+ // 资源封面路径
+ const [resourcePictureUrl, setResourcePictureUrl] = useState<string>('');
+ // 主页发布帖子列表
+ const [homePageThread, setHomePageThread] = useState<ThreadList>();
+ // 我的帖子列表
+ const [threadList, setThreadList] = useState<Thread[]>([]);
+ // 我的悬赏列表
+ const [rewardList, setRewardList] = useState<Reward[]>([]);
+ // 控制Tab切换
+ const [activeIndex, setActiveIndex] = useState(0);
+ // 帖子分页
+ const [threadFirst, setThreadFirst] = useState(0);
+ const [threadRows, setThreadRows] = useState(6);
+ const [totalThreads, setTotalThreads] = useState<number>(0);
+ const onThreadPageChange = (event: PaginatorPageChangeEvent) => {
+ setThreadFirst(event.first);
+ setThreadRows(event.rows);
+ };
+ // 悬赏分页
+ const [rewardFirst, setRewardFirst] = useState(0);
+ const [rewardRows, setRewardRows] = useState(5);
+ const [totalRewards, setTotalRewards] = useState<number>(0);
+ const onRewardPageChange = (event: PaginatorPageChangeEvent) => {
+ setRewardFirst(event.first);
+ setRewardRows(event.rows);
+ };
useEffect(() => {
fetchUserInfo();
@@ -175,15 +238,71 @@
});
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: '获取发布资源失败' });
}
};
+ useEffect(() => {
+ fetchHomePageThread();
+ }, []);
+
+ // 获取主页部分的发布帖子
+ const fetchHomePageThread = async () => {
+ try {
+ const response = await axios.get<ThreadList>(process.env.PUBLIC_URL + `/user/thread`, {
+ params: { userId: 22301010, pageNumber: 1, rows: 3 }
+ })
+ console.log('获取主页发布帖子:', response.data);
+ setHomePageThread(response.data);
+
+ } catch (err) {
+ console.error('获取主页发布帖子失败', err);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '获取主页发布帖子失败' });
+ }
+ }
+
+ useEffect(() => {
+ fetchThreadList();
+ }, [threadFirst, threadRows]);
+
+ // 获取用户发布的所有帖子
+ const fetchThreadList = async () => {
+ try {
+ const pageNumber = threadFirst / threadRows + 1;
+ const response = await axios.get<ThreadList>(process.env.PUBLIC_URL + `/user/thread`, {
+ params: { userId: 22301010, pageNumber: pageNumber, rows: threadRows }
+ })
+ console.log('获取我的帖子:', response.data);
+ setThreadList(response.data.records);
+ setTotalThreads(response.data.total)
+ }catch (err) {
+ console.error('获取我的帖子失败', err);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '获取我的帖子失败' });
+ }
+ }
+
+ useEffect(() => {
+ fetchRewardList();
+ }, [rewardFirst, rewardRows]);
+
+ // 获取用户发布的所有悬赏
+ const fetchRewardList = async () => {
+ try {
+ const pageNumber = rewardFirst / rewardRows + 1;
+ const response = await axios.get<RewardList>(process.env.PUBLIC_URL + `/user/reward`, {
+ params: { userId: 22301010, pageNumber: pageNumber, rows: rewardRows }
+ })
+ console.log('获取我的悬赏:', response.data);
+ setRewardList(response.data.rewardList);
+ setTotalRewards(response.data.total)
+ }catch (err) {
+ console.error('获取我的悬赏失败', err);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '获取我的悬赏失败' });
+ }
+ }
+
// 浮动按钮的子模块
const actions = [
{
@@ -227,11 +346,68 @@
});
const [ingredient, setIngredient] = useState<string>('');
+ // 删除悬赏弹窗
+ const [deleteVisible, setDeleteVisible] = useState(false);
+ // 要删除悬赏的id
+ const [deleteRewardId, setDeleteResourceId] = useState<number>(0);
+ // 处理删除悬赏接口
+ const handleDeleteSubmit = async () => {
+ try {
+ // 发送DELETE请求
+ const response = await axios.delete(process.env.PUBLIC_URL + `/reward`, {
+ params: {rewardId: deleteRewardId},
+ });
+ console.log("用户" + 22301010 + "要删除" + deleteRewardId + "号悬赏");
- // 图片上传消息通知
- const onUpload = () => {
- setIsUploadPicture(true);
- toast.current?.show({ severity: 'info', summary: 'Success', detail: 'File Uploaded' });
+ if (response.status === 204) {
+ console.log("用户成功删除悬赏");
+ toast.current?.show({severity: 'success', summary: 'Success', detail: '删除悬赏成功'});
+ setDeleteVisible(false);
+ // 重新拉取资源列表
+ fetchRewardList();
+ }
+ } catch (error) {
+ console.error('资源删除失败:', error);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '密码错误,资源删除失败' });
+ }
+ };
+
+
+ // 编辑悬赏弹窗
+ const [editVisible, setEditVisible] = useState(false);
+ // 悬赏封面路径
+ const [rewardPictureUrl, setRewardPictureUrl] = useState<string>('');
+ const [editRewardFormData, setEditRewardFormData] = useState({
+ rewardId: 0,
+ rewardName: '',
+ price: '',
+ rewardDescription: '',
+ });
+
+ // 处理编辑资源接口
+ const handleEditSubmit = async () => {
+ try {
+ const postData = {
+ rewardId: editRewardFormData.rewardId,
+ rewardName: editRewardFormData.rewardName,
+ rewardPicture: rewardPictureUrl,
+ price: toNumber(editRewardFormData.price),
+ rewardDescription: editRewardFormData.rewardDescription,
+ };
+ // 发送POST请求
+ const response = await axios.put(process.env.PUBLIC_URL + '/reward/info', postData);
+ console.log("编辑悬赏的信息:", postData);
+
+ if (response.status === 200) {
+ toast.current?.show({ severity: 'success', summary: 'Success', detail: '悬赏编辑成功' });
+ // 编辑成功
+ setEditVisible(false);
+ fetchRewardList();
+ }
+ } catch (error) {
+ console.error('悬赏编辑失败:', error);
+ toast.current?.show({ severity: 'error', summary: 'error', detail: '悬赏编辑失败' });
+ }
};
// 上传资源接口
@@ -261,7 +437,7 @@
toast.current?.show({ severity: 'info', summary: 'error', detail: '缺少资源标签' });
return;
}
- if (!isUploadPicture) {
+ if (resourcePictureUrl === '') {
toast.current?.show({ severity: 'info', summary: 'error', detail: '缺少资源封面' });
return;
}
@@ -270,7 +446,7 @@
const postData = {
resource: {
resourceName: resourceFormData.resource.resourceName,
- resourcePicture: resourceFormData.resource.resourcePicture,
+ resourcePicture: resourcePictureUrl,
resourceSummary: resourceFormData.resource.resourceSummary,
resourceDetail: resourceFormData.resource.resourceDetail,
uploadTime: currentDate,
@@ -310,8 +486,8 @@
setIngredient("");
// 重置资源标签
setSelectedGameplay([]);
- // 重置上传封面状态
- setIsUploadPicture(false);
+ // 重置资源封面
+ setResourcePictureUrl('');
// 可以刷新资源列表
// fetchResourceList();
}
@@ -321,9 +497,6 @@
}
};
-
-
-
return (
<div className="user-container">
<Toast ref={toast}></Toast>
@@ -366,39 +539,8 @@
</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>
-
+ <TabView activeIndex={activeIndex} onTabChange={(e) => setActiveIndex(e.index)}>
+ <TabPanel header="主页" >
{/*发布资源*/}
<div className="homepage-item">
<div className="section-header">
@@ -437,38 +579,69 @@
<Button
label="显示更多"
link
- onClick={() => router.push('/resource/recommend/模组')}
+ onClick={() => setActiveIndex(1)}
/>
</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>*/}
- {/*))}*/}
+ {homePageThread?.records.map((homePageThread) => (
+ <Card key={homePageThread.threadId} className="resource-card" onClick={() => router.push(`/community/thread-detail/${homePageThread.threadId}`)}>
+ <Image
+ src={process.env.NEXT_PUBLIC_NGINX_URL + homePageThread.threadPicture}
+ alt={homePageThread.title}
+ width="368"
+ height="200"
+ />
+ <div className="card-content">
+ <h3>{homePageThread.title}</h3>
+ <div className="view-count">
+ <Fire theme="outline" size="16" fill="#FF8D1A" />
+ <span>{homePageThread.likes}</span>
+ </div>
+ </div>
+ </Card>
+ ))}
</div>
</div>
</TabPanel>
- <TabPanel header="发布">
+ {/*<TabPanel header="发布">*/}
- </TabPanel>
+ {/*</TabPanel>*/}
<TabPanel header="帖子">
-
+ {/*我的帖子*/}
+ <div className="homepage-item">
+ <div className="section-header">
+ <h1>我的帖子</h1>
+ </div>
+ <div className="resource-grid">
+ {threadList.map((threadList) => (
+ <Card key={threadList.threadId} className="resource-card" onClick={() => router.push(`/community/thread-detail/${threadList.threadId}`)}>
+ <Image
+ src={process.env.NEXT_PUBLIC_NGINX_URL + threadList.threadPicture}
+ alt={threadList.title}
+ width="368"
+ height="200"
+ />
+ <div className="card-content">
+ <h3>{threadList.title}</h3>
+ <div className="view-count">
+ <Fire theme="outline" size="16" fill="#FF8D1A" />
+ <span>{threadList.likes}</span>
+ </div>
+ </div>
+ </Card>
+ ))}
+ </div>
+ {totalThreads > 6 && <Paginator
+ className="Paginator"
+ first={threadFirst}
+ rows={threadRows}
+ totalRecords={totalThreads}
+ rowsPerPageOptions={[6, 12]}
+ onPageChange={onThreadPageChange}
+ />}
+ </div>
</TabPanel>
<TabPanel header="收藏">
@@ -480,7 +653,57 @@
</TabPanel>
<TabPanel header="悬赏">
+ <div className="resource-list">
+ {rewardList.map((rewardItem) => (
+ <Card key={rewardItem.rewardId} className="resources-list-card"
+ onClick={() => router.push(`/reward/reward-detail/${rewardItem.rewardId}`)}>
+ <Image alt="avatar"
+ src={process.env.NEXT_PUBLIC_NGINX_URL + "rewards/" + rewardItem.rewardPicture}
+ className="resource-avatar" width="250" height="140"/>
+ <div className="resource-header">
+ <div className="resource-content">
+ <h3>{rewardItem.rewardName}</h3>
+ </div>
+ <div className="resource-operation">
+ <Button
+ label="编辑"
+ onClick={(e) => {
+ e.stopPropagation(); // 关键修复:阻止事件冒泡,避免触发Card的点击事件
+ setEditVisible(true);
+
+ setEditRewardFormData({
+ rewardId: rewardItem.rewardId,
+ rewardName: rewardItem.rewardName,
+ price: rewardItem.price.toString(),
+ rewardDescription: rewardItem.rewardDescription,
+ });
+ console.log("用户编辑悬赏");
+ }}
+ />
+ <Button
+ label="删除"
+ onClick={(e) => {
+ e.stopPropagation(); // 关键修复:阻止事件冒泡,避免触发Card的点击事件
+ setDeleteResourceId(rewardItem.rewardId);
+ setDeleteVisible(true);
+ }}
+ style={{backgroundColor: "rgba(255, 87, 51, 1)"}}
+ />
+ </div>
+ </div>
+ </Card>
+ ))}
+
+ {totalRewards > 5 && <Paginator
+ className="Paginator"
+ first={rewardFirst}
+ rows={rewardRows}
+ totalRecords={totalRewards}
+ rowsPerPageOptions={[5, 10]}
+ onPageChange={onRewardPageChange}
+ />}
+ </div>
</TabPanel>
</TabView>
@@ -528,7 +751,6 @@
}))}
placeholder="请输入资源名称"
className="w-full"
- required
/>
</div>
<div className="form-field">
@@ -548,7 +770,6 @@
}))}
placeholder="请输入资源简介(一句话)"
className="w-full"
- required
/>
</div>
<div className="form-field">
@@ -568,7 +789,6 @@
rows={5}
placeholder="请输入资源介绍"
className="w-full"
- required
/>
</div>
<div className="form-field">
@@ -711,19 +931,166 @@
<label>封面图片</label>
</div>
<FileUpload
- mode="basic"
+ mode="advanced"
name="resource-image"
- url={process.env.PUBLIC_URL +"/file"} // 与后端交互的URL
+ customUpload
+ uploadHandler={async (e) => {
+ const formData = new FormData();
+ formData.append("file", e.files[0]);
+
+ try {
+ const res = await axios.post(`${process.env.PUBLIC_URL}/file`, formData);
+
+ const fileUrl = res.data.url;
+ console.log(fileUrl);
+ setResourcePictureUrl(fileUrl);
+ toast.current?.show({ severity: 'success', summary: '上传成功' });
+ } catch (error) {
+ console.log(error);
+ toast.current?.show({ severity: 'error', summary: '上传失败' });
+ }
+ }}
+ auto
accept="image/*"
- maxFileSize={10000000000}
- chooseLabel="选择资源封面"
- className="w-full"
- onUpload={onUpload}
+ chooseLabel="上传资源封面"
+
+ // accept="image/*"
+ // maxFileSize={10000000000}
+ // chooseLabel="选择资源封面"
+ // className="w-full"
+ // onUpload={onUpload}
/>
</div>
</div>
</Dialog>
+ {/*删除悬赏弹窗*/}
+ <Dialog
+ header="删除悬赏"
+ visible={deleteVisible}
+ onHide={() => setDeleteVisible(false)}
+ className="resource-delete-dialog"
+ modal
+ footer={
+ <div className="dialog-footer">
+ <Button label="确认" icon="pi pi-check" onClick={handleDeleteSubmit} autoFocus />
+ <Button label="取消" icon="pi pi-times" onClick={() => setDeleteVisible(false)} className="p-button-text" />
+ </div>
+ }
+ >
+ <div className="dialog-form">
+ <span>
+ 确认是否删除该悬赏?
+ </span>
+ {/*<div className="form-field">*/}
+ {/* <div className="form-field-header">*/}
+ {/* <label htmlFor="name">密码</label>*/}
+ {/* </div>*/}
+ {/* <Password*/}
+ {/* id="passwrod"*/}
+ {/* value={deleteResourceFormData.password}*/}
+ {/* onChange={(e) => setDeleteResourceFormData(prev => ({*/}
+ {/* ...prev,*/}
+ {/* password: e.target.value*/}
+ {/* }))}*/}
+ {/* placeholder="请输入密码"*/}
+ {/* className="w-full"*/}
+ {/* toggleMask*/}
+ {/* />*/}
+ {/*</div>*/}
+ </div>
+ </Dialog>
+
+ {/*编辑资源弹窗*/}
+ <Dialog
+ header="编辑资源"
+ visible={editVisible}
+ onHide={() => setEditVisible(false)}
+ className="resource-edit-dialog"
+ modal
+ footer={
+ <div className="dialog-footer">
+ <Button label="确认" icon="pi pi-check" onClick={handleEditSubmit} autoFocus />
+ <Button label="取消" icon="pi pi-times" onClick={() => setEditVisible(false)} className="p-button-text" />
+ </div>
+ }
+ >
+ <div className="dialog-form">
+ <div className="form-field">
+ <div className="form-field-header">
+ <label htmlFor="name">更改标题</label>
+ </div>
+ <InputText
+ id="name"
+ value={editRewardFormData.rewardName}
+ onChange={(e) => setEditRewardFormData(prev => ({
+ ...prev,
+ rewardName: e.target.value
+ }))}
+ className="w-full"
+ />
+ </div>
+ <div className="form-field">
+ <div className="form-field-header">
+ <label htmlFor="summary">更改定价</label>
+ </div>
+ <InputText
+ id="summary"
+ value={editRewardFormData.price}
+ onChange={(e) => setEditRewardFormData(prev => ({
+ ...prev,
+ price: e.target.value
+ }))}
+ className="w-full"
+ />
+ </div>
+ <div className="form-field">
+ <div className="form-field-header">
+ <label htmlFor="detail">更改需求</label>
+ </div>
+ <InputTextarea
+ id="detail"
+ value={editRewardFormData.rewardDescription}
+ onChange={(e) => setEditRewardFormData(prev => ({
+ ...prev,
+ rewardDescription: e.target.value
+ }))}
+ rows={5}
+ className="w-full"
+ />
+ </div>
+ <div className="form-field">
+ <div className="form-field-header">
+ <span className="form-field-sign">*</span>
+ <label>封面图片</label>
+ </div>
+ <FileUpload
+ mode="advanced"
+ name="resource-image"
+ customUpload
+ uploadHandler={async (e) => {
+ const formData = new FormData();
+ formData.append("file", e.files[0]);
+
+ try {
+ const res = await axios.post(`${process.env.PUBLIC_URL}/file`, formData);
+
+ const fileUrl = res.data.url;
+ console.log(fileUrl);
+ setRewardPictureUrl(fileUrl);
+ toast.current?.show({ severity: 'success', summary: '上传成功' });
+ } catch (error) {
+ console.log(error);
+ toast.current?.show({ severity: 'error', summary: '上传失败' });
+ }
+ }}
+ auto
+ accept="image/*"
+ chooseLabel="选择悬赏封面"
+ />
+ </div>
+ </div>
+ </Dialog>
</div>
);
};
diff --git a/src/app/user/user.scss b/src/app/user/user.scss
index a3726b6..d0b10c8 100644
--- a/src/app/user/user.scss
+++ b/src/app/user/user.scss
@@ -103,69 +103,156 @@
}
-//每一模块的首部样式
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-top: 20px;
+.p-tabview-panels {
+ padding-top: 0;
}
-//每个模块中的资源样式
-.resource-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- gap: 1rem;
+.homepage-item {
+ //每一模块的首部样式
+ .section-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 20px;
+ }
- .resource-card {
- transition: transform 0.2s ease;
- cursor: pointer;
- box-shadow: none !important;
+ //每个模块中的资源样式
+ .resource-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+ gap: 1rem;
- .p-image {
- img {
- border-radius: 0.5rem 0.5rem 0 0;
- object-fit: cover;
+ .resource-card {
+ transition: transform 0.2s ease;
+ cursor: pointer;
+ box-shadow: none !important;
+
+ .p-image {
+ img {
+ border-radius: 0.5rem 0.5rem 0 0;
+ object-fit: cover;
+ }
}
+
+ .p-card-body {
+ padding: 0;
+ }
+
+ .p-card-content {
+ padding: 0;
+ }
+
+ &:hover {
+ transform: translateY(-4px);
+ }
+
+ .card-content {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ margin-left: 16px;
+ margin-right: 16px;
+ margin-bottom: 16px;
+
+ h3 {
+ margin: 1rem 0;
+ font-size: 1rem;
+ line-height: 1.5;
+ color: #2d3748;
+ }
+
+ .view-count {
+ position: absolute;
+ bottom: 0rem;
+ right: 0rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ color: #718096;
+ font-size: 0.9rem;
+ }
+ }
+ }
+ }
+}
+
+
+.resources-list {
+ width: 100%;
+ padding: 1rem;
+
+ &-card {
+ height: 140px;
+ padding: 1.5rem;
+ margin-bottom: 1rem;
+ border-radius: 0.5rem;
+ transition: transform 0.3s ease;
+ box-shadow: none !important; // 取消阴影
+
+ //填充卡片
+ &.p-card.p-component {
+ padding: 0;
}
.p-card-body {
padding: 0;
}
+ &:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ }
+
.p-card-content {
+ height: 140px;
+ display: flex;
+ justify-content: space-between;
padding: 0;
}
- &:hover {
- transform: translateY(-4px);
+ img {
+ border-radius: 0.5rem 0 0 0.5rem;
+ object-fit: cover;
}
- .card-content {
+
+ .resource-avatar {
+ width: 80px;
+ height: 80px;
+ border-radius: 8px;
+ object-fit: cover;
+ }
+
+ .resource-header {
+ display: flex;
+ flex: 1;
+ max-width: 850px;
+ padding-left: 20px;
+ padding-right: 20px;
+ margin-bottom: 20px;
+ }
+
+ .resource-content {
+ flex: 1;
display: flex;
flex-direction: column;
- position: relative;
- margin-left: 16px;
- margin-right: 16px;
- margin-bottom: 16px;
h3 {
- margin: 1rem 0;
- font-size: 1rem;
- line-height: 1.5;
- color: #2d3748;
+ font-size: 1.5rem;
+ font-weight: bold;
+ color: #2c3e50;
}
- .view-count {
- position: absolute;
- bottom: 0rem;
- right: 0rem;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- color: #718096;
- font-size: 0.9rem;
- }
+
+ }
+
+ .resource-operation {
+ min-width: 240px;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+ align-items: flex-end;
+ gap: 1rem;
}
}
}
@@ -245,5 +332,115 @@
}
}
+//删除资源弹窗样式
+.resource-delete-dialog {
+ width: 350px !important;
+ max-width: 90vw;
+
+ .dialog-footer {
+ margin-top: 10px;
+ display: flex;
+ justify-content: center;
+ }
+
+ .p-dialog-header {
+ font-size: 1.5rem;
+ font-weight: bold;
+ color: $heading-color;
+ padding-bottom: 0.5rem;
+ }
+
+ .p-dialog-content {
+ padding-top: 0;
+ padding-bottom: 0;
+
+ .dialog-form {
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+ margin-top: 1rem;
+
+ .form-field {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+
+ label {
+ font-weight: 600;
+ color: $heading-color;
+ }
+
+ input,
+ textarea{
+ padding: 0.75rem 1rem;
+ border-radius: 8px;
+ font-size: 1rem;
+ color: #2d3748;
+ }
+
+ }
+ }
+ }
+}
+
+//资源编辑弹窗样式
+.resource-edit-dialog {
+ width: 600px !important;
+ max-width: 90vw;
+
+ .dialog-footer {
+ margin-top: 10px;
+ display: flex;
+ justify-content: center;
+ }
+
+ .p-dialog-header {
+ font-size: 1.5rem;
+ font-weight: bold;
+ color: $heading-color;
+ padding-bottom: 0.5rem;
+ }
+
+ .p-dialog-content {
+ padding-top: 0;
+ padding-bottom: 0;
+
+ .dialog-form {
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+ margin-top: 1rem;
+
+ .form-field {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+
+ label {
+ font-weight: 600;
+ color: $heading-color;
+ }
+
+ input,
+ textarea{
+ padding: 0.75rem 1rem;
+ border-radius: 8px;
+ font-size: 1rem;
+ color: #2d3748;
+ }
+
+ .p-fileupload {
+ .p-button {
+ width: 100%;
+ justify-content: center;
+ border: none;
+ margin-bottom: 1rem;
+ }
+ }
+ }
+ }
+ }
+}
+