Compare commits

...

2 Commits

Author SHA1 Message Date
Shu Guang
702d0d6aec fix: 更改论坛 2025-05-17 18:17:51 +08:00
Shu Guang
ccdb092b29 fix: 更新路由 2025-05-17 17:50:42 +08:00
5 changed files with 141 additions and 295 deletions

View File

@ -64,71 +64,27 @@
</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">
<Editor
:id="tinymceId"
:init="init"
:disabled="disabled"
v-model="myValue"
@onClick="onClick"
></Editor>
<div class="word-count">字数: {{ wordCount }}</div>
</div>
<!-- 内容预览区域 -->
<div v-if="showPreview" class="preview-container fade-in">
<div class="preview-title">
<a-icon type="eye" />
<span>文章预览</span>
<div class="tinymce-editor">
<div class="editor-container">
<Editor
:id="tinymceId"
:init="init"
:disabled="disabled"
v-model="myValue"
@onClick="onClick"
></Editor>
</div>
<div class="preview-content" v-html="myValue"></div>
</div>
<!-- 操作按钮 -->
<div class="publish-container">
<a-button @click="togglePreview" style="margin-right: 16px">
<a-icon :type="showPreview ? 'eye-invisible' : 'eye'" />
{{ showPreview ? "关闭预览" : "预览文章" }}
</a-button>
<a-button type="primary" class="publish-btn" @click="confirmPublish">
<a-icon type="plus" />
发布文章
</a-button>
<div class="editor-footer">
<div class="word-count">字数{{ wordCount }}</div>
<div class="button-group">
<a-button type="primary" class="publish-btn" @click="SendTinymce">
<a-icon type="plus" />
发布文章
</a-button>
</div>
</div>
</div>
</div>
</template>
@ -498,7 +454,7 @@ export default {
transition: all 0.3s;
}
.tinymce-editor .ant-select-selection-search {
.tinymce-editor .ant-select-search {
display: flex;
align-items: center;
}

View File

@ -139,7 +139,7 @@ export const routes = [
path: '/account/CompetitionAssistant',
name: 'CompetitionAssistant',
meta: { title: '竞赛助手', auth: 0 },
component: () => import('@/views/CompetitionAssistant.vue'),
component: () => import('@/views/user/Ai.vue'),
},
],
},

View File

@ -6,14 +6,7 @@
<div class="stat-number">{{ articleCount }}</div>
<div class="stat-title">发布文章</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-number">{{ matchs.length }}</div>
<div class="stat-title">参与比赛</div>
@ -129,16 +122,6 @@
<div v-if="noTitleKey === 'article'">
<!-- 文章筛选和排序 -->
<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>
@ -152,7 +135,7 @@
class="article-item"
v-for="(article, index) in articles"
:key="index"
@click="viewArticle(article.id)"
@click="viewArticle(article)"
>
<div class="article-cover">
<img :src="getArticleImage(article)" :alt="article.title" />
@ -168,7 +151,7 @@
<a-icon type="calendar" />
{{ formatDate(article.publishTime) }}
</div>
<div class="article-stats">
<!-- <div class="article-stats">
<span
><a-icon type="eye" />
{{ article.viewCount || 0 }}</span
@ -181,7 +164,7 @@
><a-icon type="message" />
{{ article.commentCount || 0 }}</span
>
</div>
</div> -->
</div>
</div>
</div>
@ -244,14 +227,6 @@ export default {
key: "article",
tab: "我的文章",
},
{
key: "app",
tab: "我的收藏",
},
{
key: "project",
tab: "我的评论",
},
],
noTitleKey: "article",
matchs: [],
@ -294,18 +269,33 @@ export default {
},
methods: {
//
// fetchCompetitions
fetchCompetitions() {
this.teamSpinning = true;
this.$api
.RegistrationAll()
.then((res) => {
//
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;
})
.catch((err) => {
console.error("获取比赛信息失败:", err);
this.$message.error("获取比赛信息失败");
this.teamSpinning = false;
});
},
@ -447,12 +437,13 @@ export default {
//
viewArticle(id) {
this.$router.push(`/community/pages?id=${id}`);
console.log("id", id);
this.$router.push(`/community/pages?id=${id?.articleId}`);
},
//
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"
id="cmt225"
>
<!-- 只有当评论作者是当前用户时才显示删除按钮 -->
<div
style="
display: flex;
flex-direction: row;
align-items: end;
justify-content: flex-end;
"
v-if="item.userId === userId"
class="delete-btn"
@click="DeleteComments(item)"
>
删除
@ -160,17 +157,17 @@
<div class="msgimg">
<img
class="avatar"
src="https://q2.qlogo.cn/headimg_dl?dst_uin=36926842&spec=100"
alt="网友昵称:访客"
title="网友昵称:访客"
:src="getUserAvatar(item.userId)"
:alt="getUserName(item.userId)"
:title="getUserName(item.userId)"
/>
</div>
<div class="msgtxt">
<div class="msgname">
<span class="autlv aut-6 vs">V</span
><span class="autlv autlvname aut-6">游客</span>
<span class="dot shafa">沙发</span>
<span class="autlv aut-6 vs">{{ getUserRole(item.userId) }}</span>
<span class="autlv autlvname aut-6">{{ getUserName(item.userId) }}</span>
<span class="dot">{{ index === 0 ? '沙发' : `${index + 1}` }}</span>
</div>
<div class="interact-bar">
<span class="interact-time" title="评论时间">{{
@ -178,7 +175,8 @@
}}</span>
</div>
<div class="msgarticle">
{{ item.commentContent }}<label id="AjaxComment225"></label>
{{ item.commentContent }}
<label id="AjaxComment225"></label>
</div>
</div>
</div>
@ -213,6 +211,7 @@ export default {
msg: "",
comments: [],
users: [],
userMap: {}, //
};
},
@ -322,20 +321,49 @@ export default {
console.log(error);
});
},
getuser() {
AllUser()
.then((response) => {
this.users = response.data;
})
.catch((error) => {
console.error("Failed to load users:", error);
});
//
async getuser() {
try {
const response = await AllUser();
this.users = response.data;
//
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) {
const user = this.users.find((u) => u.userId === userId);
return user ? user.userName : "未知用户";
return this.userMap[userId]?.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>
<style src="@/assets/pages.css"></style>
@ -357,4 +385,50 @@ button {
.router-link-exact-active {
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>