fix: 更改论坛

This commit is contained in:
Shu Guang 2025-05-17 18:17:51 +08:00
parent ccdb092b29
commit 702d0d6aec
4 changed files with 140 additions and 294 deletions

View File

@ -64,71 +64,27 @@
</div> </div>
</div> </div>
<!-- 文章封面 -->
<!-- <div class="cover-upload fade-in-delay-2">
<div class="cover-title">
<a-icon type="picture" />
<span style="margin-left: 8px">文章封面</span>
</div>
<p class="cover-description">
一个好的封面图能够吸引更多读者建议尺寸 900×500 像素
</p>
<div class="cover-preview hover-lift">
<img v-if="coverUrl" :src="coverUrl" alt="文章封面" />
<div v-else class="upload-placeholder">
<a-icon type="file-image" style="font-size: 48px; color: #d9d9d9" />
<p style="margin-top: 16px; color: #999">点击上传封面图片</p>
</div>
<a-upload
name="file"
:showUploadList="false"
:beforeUpload="beforeUpload"
@change="handleCoverChange"
>
<a-button type="primary" class="cover-upload-btn">
<a-icon :type="coverUrl ? 'edit' : 'upload'" />
{{ coverUrl ? "更换封面" : "上传封面" }}
</a-button>
</a-upload>
</div>
</div> -->
<!-- 编辑器容器 --> <!-- 编辑器容器 -->
<div class="editor-container fade-in-delay-2"> <div class="tinymce-editor">
<Editor <div class="editor-container">
:id="tinymceId" <Editor
:init="init" :id="tinymceId"
:disabled="disabled" :init="init"
v-model="myValue" :disabled="disabled"
@onClick="onClick" v-model="myValue"
></Editor> @onClick="onClick"
<div class="word-count">字数: {{ wordCount }}</div> ></Editor>
</div>
<!-- 内容预览区域 -->
<div v-if="showPreview" class="preview-container fade-in">
<div class="preview-title">
<a-icon type="eye" />
<span>文章预览</span>
</div> </div>
<div class="preview-content" v-html="myValue"></div> <div class="editor-footer">
</div> <div class="word-count">字数{{ wordCount }}</div>
<div class="button-group">
<!-- 操作按钮 --> <a-button type="primary" class="publish-btn" @click="SendTinymce">
<div class="publish-container"> <a-icon type="plus" />
<a-button @click="togglePreview" style="margin-right: 16px"> 发布文章
<a-icon :type="showPreview ? 'eye-invisible' : 'eye'" /> </a-button>
{{ showPreview ? "关闭预览" : "预览文章" }} </div>
</a-button> </div>
<a-button type="primary" class="publish-btn" @click="confirmPublish">
<a-icon type="plus" />
发布文章
</a-button>
</div> </div>
</div> </div>
</template> </template>
@ -498,7 +454,7 @@ export default {
transition: all 0.3s; transition: all 0.3s;
} }
.tinymce-editor .ant-select-selection-search { .tinymce-editor .ant-select-search {
display: flex; display: flex;
align-items: center; align-items: center;
} }

View File

@ -6,14 +6,7 @@
<div class="stat-number">{{ articleCount }}</div> <div class="stat-number">{{ articleCount }}</div>
<div class="stat-title">发布文章</div> <div class="stat-title">发布文章</div>
</div> </div>
<div class="stat-card glow-border">
<div class="stat-number">{{ viewCount }}</div>
<div class="stat-title">文章浏览</div>
</div>
<div class="stat-card glow-border">
<div class="stat-number">{{ likeCount }}</div>
<div class="stat-title">获得点赞</div>
</div>
<div class="stat-card glow-border"> <div class="stat-card glow-border">
<div class="stat-number">{{ matchs.length }}</div> <div class="stat-number">{{ matchs.length }}</div>
<div class="stat-title">参与比赛</div> <div class="stat-title">参与比赛</div>
@ -129,16 +122,6 @@
<div v-if="noTitleKey === 'article'"> <div v-if="noTitleKey === 'article'">
<!-- 文章筛选和排序 --> <!-- 文章筛选和排序 -->
<div class="article-filter"> <div class="article-filter">
<a-radio-group
v-model="articleFilter"
buttonStyle="solid"
@change="filterArticles"
>
<a-radio-button value="all">全部文章</a-radio-button>
<a-radio-button value="hot">热门文章</a-radio-button>
<a-radio-button value="recent">最近发布</a-radio-button>
</a-radio-group>
<a-button type="primary" icon="plus" @click="createNewArticle"> <a-button type="primary" icon="plus" @click="createNewArticle">
发布文章 发布文章
</a-button> </a-button>
@ -152,7 +135,7 @@
class="article-item" class="article-item"
v-for="(article, index) in articles" v-for="(article, index) in articles"
:key="index" :key="index"
@click="viewArticle(article.id)" @click="viewArticle(article)"
> >
<div class="article-cover"> <div class="article-cover">
<img :src="getArticleImage(article)" :alt="article.title" /> <img :src="getArticleImage(article)" :alt="article.title" />
@ -168,7 +151,7 @@
<a-icon type="calendar" /> <a-icon type="calendar" />
{{ formatDate(article.publishTime) }} {{ formatDate(article.publishTime) }}
</div> </div>
<div class="article-stats"> <!-- <div class="article-stats">
<span <span
><a-icon type="eye" /> ><a-icon type="eye" />
{{ article.viewCount || 0 }}</span {{ article.viewCount || 0 }}</span
@ -181,7 +164,7 @@
><a-icon type="message" /> ><a-icon type="message" />
{{ article.commentCount || 0 }}</span {{ article.commentCount || 0 }}</span
> >
</div> </div> -->
</div> </div>
</div> </div>
</div> </div>
@ -244,14 +227,6 @@ export default {
key: "article", key: "article",
tab: "我的文章", tab: "我的文章",
}, },
{
key: "app",
tab: "我的收藏",
},
{
key: "project",
tab: "我的评论",
},
], ],
noTitleKey: "article", noTitleKey: "article",
matchs: [], matchs: [],
@ -294,18 +269,33 @@ export default {
}, },
methods: { methods: {
// //
// fetchCompetitions
fetchCompetitions() { fetchCompetitions() {
this.teamSpinning = true; this.teamSpinning = true;
this.$api this.$api
.RegistrationAll() .RegistrationAll()
.then((res) => { .then((res) => {
//
this.matchs = res.data.filter((match) => { this.matchs = res.data.filter((match) => {
return match.studentId == this.$store.state.user.userId; return match.studentId === this.$store.state.user.userId;
}); });
//
this.matchs = this.matchs.map((match) => ({
...match,
//
competitionName: match.competitionName || "未命名比赛",
competitionType: match.competitionType || "未分类",
registrationTime:
match.registrationTime || new Date().toISOString(),
awardLevel: match.awardLevel || "暂无成绩",
}));
this.teamSpinning = false; this.teamSpinning = false;
}) })
.catch((err) => { .catch((err) => {
console.error("获取比赛信息失败:", err); console.error("获取比赛信息失败:", err);
this.$message.error("获取比赛信息失败");
this.teamSpinning = false; this.teamSpinning = false;
}); });
}, },
@ -447,12 +437,13 @@ export default {
// //
viewArticle(id) { viewArticle(id) {
this.$router.push(`/community/pages?id=${id}`); console.log("id", id);
this.$router.push(`/community/pages?id=${id?.articleId}`);
}, },
// //
createNewArticle() { createNewArticle() {
this.$router.push("/write"); this.$router.push("/community/publish");
}, },
// //

View File

@ -1,175 +0,0 @@
<template>
<div>
<a-card :bordered="false" class="ant-pro-components-tag-select">
<a-form :form="form" layout="inline">
<standard-form-row title="所属类目" block style="padding-bottom: 11px;">
<a-form-item>
<tag-select>
<tag-select-option value="Category1">类目一</tag-select-option>
<tag-select-option value="Category2">类目二</tag-select-option>
<tag-select-option value="Category3">类目三</tag-select-option>
<tag-select-option value="Category4">类目四</tag-select-option>
<tag-select-option value="Category5">类目五</tag-select-option>
<tag-select-option value="Category6">类目六</tag-select-option>
<tag-select-option value="Category7">类目七</tag-select-option>
<tag-select-option value="Category8">类目八</tag-select-option>
<tag-select-option value="Category9">类目九</tag-select-option>
<tag-select-option value="Category10">类目十</tag-select-option>
</tag-select>
</a-form-item>
</standard-form-row>
<standard-form-row title="其它选项" grid last>
<a-row>
<a-col :lg="8" :md="10" :sm="10" :xs="24">
<a-form-item :wrapper-col="{ sm: { span: 16 }, xs: { span: 24 } }" label="作者">
<a-select
style="max-width: 200px; width: 100%;"
mode="multiple"
placeholder="不限"
v-decorator="['author']"
@change="handleChange"
>
<a-select-option value="lisa">王昭君</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :lg="8" :md="10" :sm="10" :xs="24">
<a-form-item :wrapper-col="{ sm: { span: 16 }, xs: { span: 24 } }" label="好评度">
<a-select
style="max-width: 200px; width: 100%;"
placeholder="不限"
v-decorator="['rate']"
>
<a-select-option value="good">优秀</a-select-option>
<a-select-option value="normal">普通</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
</standard-form-row>
</a-form>
</a-card>
<div class="ant-pro-pages-list-projects-cardList">
<a-list :loading="loading" :data-source="data" :grid="{ gutter: 24, xl: 4, lg: 3, md: 3, sm: 2, xs: 1 }">
<a-list-item slot="renderItem" slot-scope="item">
<a-card class="ant-pro-pages-list-projects-card" hoverable>
<img slot="cover" :src="item.cover" :alt="item.title" />
<a-card-meta :title="item.title">
<template slot="description">
<ellipsis :length="50">{{ item.description }}</ellipsis>
</template>
</a-card-meta>
<div class="cardItemContent">
<span>{{ item.updatedAt | fromNow }}</span>
<div class="avatarList">
<avatar-list size="small" :max-length="2">
<avatar-list-item
v-for="(member, i) in item.members"
:key="`${item.id}-avatar-${i}`"
:src="member.avatar"
:tips="member.name"
/>
</avatar-list>
</div>
</div>
</a-card>
</a-list-item>
</a-list>
</div>
</div>
</template>
<script>
import moment from 'moment';
// import { TagSelect, StandardFormRow, Ellipsis, AvatarList } from '../../components';
import TagSelect from '../../components/TagSelect';
import StandardFormRow from '../../components/StandardFormRow';
import Ellipsis from '../../components/Ellipsis';
import AvatarList from '../../components/AvatarList';
const TagSelectOption = TagSelect.Option;
const AvatarListItem = AvatarList.Item;
export default {
components: {
AvatarList,
AvatarListItem,
Ellipsis,
TagSelect,
TagSelectOption,
StandardFormRow,
},
data() {
return {
data: [],
form: this.$form.createForm(this),
loading: true,
};
},
filters: {
fromNow(date) {
return moment(date).fromNow();
},
},
mounted() {
this.getList();
},
methods: {
handleChange(value) {
console.log(`selected ${value}`);
},
getList() {
this.$http.get('/list/article', { params: { count: 8 } }).then(res => {
console.log('res', res);
this.data = res.result;
this.loading = false;
});
},
},
};
</script>
<style lang="less" scoped>
.ant-pro-components-tag-select {
:deep(.ant-pro-tag-select .ant-tag) {
margin-right: 24px;
padding: 0 8px;
font-size: 14px;
}
}
.ant-pro-pages-list-projects-cardList {
margin-top: 24px;
:deep(.ant-card-meta-title) {
margin-bottom: 4px;
}
:deep(.ant-card-meta-description) {
height: 44px;
overflow: hidden;
line-height: 22px;
}
.cardItemContent {
display: flex;
height: 20px;
margin-top: 16px;
margin-bottom: -4px;
line-height: 20px;
> span {
flex: 1 1;
color: rgba(0,0,0,.45);
font-size: 12px;
}
:deep(.ant-pro-avatar-list) {
flex: 0 1 auto;
}
}
}
</style>

View File

@ -146,13 +146,10 @@
data-wow-delay="0.25s" data-wow-delay="0.25s"
id="cmt225" id="cmt225"
> >
<!-- 只有当评论作者是当前用户时才显示删除按钮 -->
<div <div
style=" v-if="item.userId === userId"
display: flex; class="delete-btn"
flex-direction: row;
align-items: end;
justify-content: flex-end;
"
@click="DeleteComments(item)" @click="DeleteComments(item)"
> >
删除 删除
@ -160,17 +157,17 @@
<div class="msgimg"> <div class="msgimg">
<img <img
class="avatar" class="avatar"
src="https://q2.qlogo.cn/headimg_dl?dst_uin=36926842&spec=100" :src="getUserAvatar(item.userId)"
alt="网友昵称:访客" :alt="getUserName(item.userId)"
title="网友昵称:访客" :title="getUserName(item.userId)"
/> />
</div> </div>
<div class="msgtxt"> <div class="msgtxt">
<div class="msgname"> <div class="msgname">
<span class="autlv aut-6 vs">V</span <span class="autlv aut-6 vs">{{ getUserRole(item.userId) }}</span>
><span class="autlv autlvname aut-6">游客</span> <span class="autlv autlvname aut-6">{{ getUserName(item.userId) }}</span>
<span class="dot shafa">沙发</span> <span class="dot">{{ index === 0 ? '沙发' : `${index + 1}` }}</span>
</div> </div>
<div class="interact-bar"> <div class="interact-bar">
<span class="interact-time" title="评论时间">{{ <span class="interact-time" title="评论时间">{{
@ -178,7 +175,8 @@
}}</span> }}</span>
</div> </div>
<div class="msgarticle"> <div class="msgarticle">
{{ item.commentContent }}<label id="AjaxComment225"></label> {{ item.commentContent }}
<label id="AjaxComment225"></label>
</div> </div>
</div> </div>
</div> </div>
@ -213,6 +211,7 @@ export default {
msg: "", msg: "",
comments: [], comments: [],
users: [], users: [],
userMap: {}, //
}; };
}, },
@ -322,20 +321,49 @@ export default {
console.log(error); console.log(error);
}); });
}, },
getuser() { //
AllUser() async getuser() {
.then((response) => { try {
this.users = response.data; const response = await AllUser();
}) this.users = response.data;
.catch((error) => { //
console.error("Failed to load users:", error); this.userMap = this.users.reduce((map, user) => {
}); map[user.userId] = user;
return map;
}, {});
} catch (error) {
console.error("Failed to load users:", error);
this.$message.error("获取用户信息失败");
}
}, },
//
getUserName(userId) { getUserName(userId) {
const user = this.users.find((u) => u.userId === userId); return this.userMap[userId]?.userName || "未知用户";
return user ? user.userName : "未知用户";
}, },
},
//
getUserAvatar(userId) {
return this.userMap[userId]?.avatar || "https://onlinephoto.oss-cn-chengdu.aliyuncs.com/hangtian/touxiang.jpg";
},
//
getUserRole(userId) {
const user = this.userMap[userId];
if (!user) return "V";
switch(user.role) {
case "admin":
return "管理员";
case "teacher":
return "教师";
case "student":
return "学生";
default:
return "V";
}
},
}
}; };
</script> </script>
<style src="@/assets/pages.css"></style> <style src="@/assets/pages.css"></style>
@ -357,4 +385,50 @@ button {
.router-link-exact-active { .router-link-exact-active {
color: none; color: none;
} }
.delete-btn {
display: flex;
justify-content: flex-end;
padding: 5px 10px;
color: #ff4d4f;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
.delete-btn:hover {
color: #ff7875;
}
.msgname {
display: flex;
align-items: center;
gap: 8px;
}
.autlv {
padding: 2px 6px;
border-radius: 3px;
font-size: 12px;
}
.aut-6.vs {
background-color: #3690cf;
color: white;
}
.dot {
color: #999;
font-size: 12px;
}
.interact-time {
color: #999;
font-size: 12px;
}
.msgarticle {
margin-top: 8px;
line-height: 1.6;
}
</style> </style>