完成收藏列表展示

This commit is contained in:
柏码の讲师 2023-10-23 01:17:30 +08:00
parent ebcd6ab4ae
commit 9777bc26cc
9 changed files with 153 additions and 25 deletions

View File

@ -79,4 +79,9 @@ public class ForumController {
topicService.interact(new Interact(tid, id, new Date(), type), state);
return RestBean.success();
}
@GetMapping("/collects")
public RestBean<List<TopicPreviewVO>> collects(@RequestAttribute(Const.ATTR_USER_ID) int id){
return RestBean.success(topicService.listCollectTopic(id));
}
}

View File

@ -41,4 +41,9 @@ public interface TopicMapper extends BaseMapper<Topic> {
select count(*) from db_topic_interact_${type} where tid = #{tid} and uid = #{uid}
""")
int userInteractCount(int tid, int uid, String type);
@Select("""
select * from db_topic_interact_collect left join db_topic on tid = id where db_topic_interact_collect.uid = #{uid}
""")
List<Topic> collectTopics(int uid);
}

View File

@ -18,4 +18,5 @@ public interface TopicService extends IService<Topic> {
List<TopicTopVO> topTopics();
TopicDetailVO getTopic(int tid);
void interact(Interact interact, boolean state);
List<TopicPreviewVO> listCollectTopic(int uid);
}

View File

@ -74,6 +74,17 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
}
}
public List<TopicPreviewVO> listCollectTopic(int uid){
return baseMapper.collectTopics(uid)
.stream()
.map(topic -> {
TopicPreviewVO vo = new TopicPreviewVO();
BeanUtils.copyProperties(topic, vo);
return vo;
})
.toList();
}
public List<TopicPreviewVO> listTopicByPage(int pageNumber, int type){
String key = Const.FORUM_TOPIC_PREVIEW_CACHE + pageNumber + ":" + type;
List<TopicPreviewVO> list = cacheUtils.takeListFromCache(key, TopicPreviewVO.class);

View File

@ -0,0 +1,73 @@
<script setup>
import LightCard from "@/components/LightCard.vue";
import {get} from "@/net";
import {ref} from "vue";
import TopicTag from "@/components/TopicTag.vue";
import router from "@/router";
import {ElMessage} from "element-plus";
defineProps({
show: Boolean
})
const emit = defineEmits(['close'])
const list = ref([])
function init() {
get('/api/forum/collects', data => list.value = data)
}
function deleteCollect(index, tid) {
get(`/api/forum/interact?tid=${tid}&type=collect&state=false`, () => {
ElMessage.success('已取消收藏!')
list.value.splice(index, 1)
})
}
</script>
<template>
<el-drawer :model-value="show" @close="emit('close')" @open="init"
title="我收藏的帖子列表">
<div class="collect-list">
<light-card v-for="(item, index) in list" class="topic-card"
@click="router.push(`/index/post-detail/${item.id}`)">
<topic-tag :type="item.type"/>
<div class="title">
<b>{{item.title}}</b>
</div>
<el-link type="danger" @click.stop="deleteCollect(index, item.id)">删除</el-link>
</light-card>
</div>
</el-drawer>
</template>
<style scoped>
.collect-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.topic-card {
background-color: rgba(128, 128, 128, 0.2);
transition: .3s;
display: flex;
justify-content: space-between;
.title {
margin-left: 5px;
font-size: 14px;
flex: 1;
white-space: nowrap;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
&:hover {
scale: 1.02;
cursor: pointer;
}
}
</style>

View File

@ -0,0 +1,30 @@
<script setup>
import {useStore} from "@/store";
const store = useStore()
defineProps({
type: Number
})
</script>
<template>
<div class="topic-type"
:style="{color: store.findTypeById(type)?.color+'DD',
'border-color': store.findTypeById(type)?.color+'EE',
'background-color': store.findTypeById(type)?.color+'22'}">
{{ store.findTypeById(type)?.name }}
</div>
</template>
<style scoped>
.topic-type {
display: inline-block;
border: solid 0.5px grey;
border-radius: 5px;
font-size: 12px;
padding: 0 5px;
height: 18px;
}
</style>

View File

@ -24,14 +24,3 @@ get('/api/forum/types', data => {
<el-backtop target=".main-content-page .el-scrollbar__wrap" :right="20" :bottom="20"/>
</div>
</template>
<style>
.topic-type {
display: inline-block;
border: solid 0.5px grey;
border-radius: 5px;
font-size: 12px;
padding: 0 5px;
height: 18px;
}
</style>

View File

@ -10,6 +10,7 @@ import Card from "@/components/Card.vue";
import router from "@/router";
import InteractButton from "@/components/InteractButton.vue";
import {ElMessage} from "element-plus";
import TopicTag from "@/components/TopicTag.vue";
const route = useRoute()
const store = useStore()
@ -53,12 +54,7 @@ function interact(type, message) {
<el-button type="info" :icon="ArrowLeft" size="small"
round plain @click="router.push('/index')">返回列表</el-button>
<div style="text-align: center;flex: 1;height: 25px">
<div class="topic-type"
:style="{color: store.findTypeById(topic.data.type)?.color+'DD',
'border-color': store.findTypeById(topic.data.type)?.color+'EE',
'background-color': store.findTypeById(topic.data.type)?.color+'22'}">
{{ store.findTypeById(topic.data.type)?.name }}
</div>
<topic-tag :type="topic.data.type"/>
<span style="margin-left: 5px;font-weight: bold">{{topic.data.title}}</span>
</div>
</card>
@ -90,7 +86,8 @@ function interact(type, message) {
</div>
<div class="topic-main-right">
<div class="topic-content" v-html="content"></div>
<div style="font-size: 13px;color: grey;text-align: center;margin-top: 40px">
<el-divider/>
<div style="font-size: 13px;color: grey;text-align: center">
<div>发帖时间: {{new Date(topic.data.time).toLocaleString()}}</div>
</div>
<div style="text-align: right;margin-top: 30px">

View File

@ -10,7 +10,7 @@ import {
Edit,
EditPen,
Link,
Microphone, CircleCheck, Star
Microphone, CircleCheck, Star, ArrowRightBold, FolderOpened
} from "@element-plus/icons-vue";
import {computed, reactive, ref, watch} from "vue"
import Weather from "@/components/Weather.vue";
@ -20,6 +20,8 @@ import TopicEditor from "@/components/TopicEditor.vue";
import {useStore} from "@/store";
import axios from "axios";
import router from "@/router";
import TopicCollectList from "@/components/TopicCollectList.vue";
import TopicTag from "@/components/TopicTag.vue";
const store = useStore()
@ -37,6 +39,7 @@ const topics = reactive({
end: false,
top: []
})
const collects = ref(false)
watch(() => topics.type, () => {
topics.page = 0
@ -144,12 +147,7 @@ navigator.geolocation.getCurrentPosition(position => {
</div>
</div>
<div style="margin-top: 5px">
<div class="topic-type"
:style="{color: store.findTypeById(item.type)?.color+'DD',
'border-color': store.findTypeById(item.type)?.color+'EE',
'background-color': store.findTypeById(item.type)?.color+'22'}">
{{ store.findTypeById(item.type)?.name }}
</div>
<topic-tag :type="item.type"/>
<span style="margin-left: 7px;font-weight: bold">{{ item.title }}</span>
</div>
<div class="topic-preview-content">{{ item.text }}</div>
@ -172,6 +170,12 @@ navigator.geolocation.getCurrentPosition(position => {
<div style="width: 280px">
<div style="position: sticky;top: 20px">
<light-card>
<div class="collect-list-button" @click="collects = true">
<span><el-icon><FolderOpened /></el-icon> 查看我的收藏</span>
<el-icon style="transform: translateY(3px)"><ArrowRightBold/></el-icon>
</div>
</light-card>
<light-card style="margin-top: 10px">
<div style="font-weight: bold;">
<el-icon>
<CollectionTag/>
@ -225,10 +229,23 @@ navigator.geolocation.getCurrentPosition(position => {
</div>
</div>
<topic-editor :show="editor" @close="editor = false" @created="onTopicCreate"/>
<topic-collect-list :show="collects" @close="collects = false"/>
</div>
</template>
<style lang="less" scoped>
.collect-list-button {
font-size: 14px;
display: flex;
justify-content: space-between;
transition: .3s;
&:hover {
cursor: pointer;
opacity: 0.6;
}
}
.top-topic {
display: flex;