完成收藏列表展示
This commit is contained in:
parent
ebcd6ab4ae
commit
9777bc26cc
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
73
my-project-frontend/src/components/TopicCollectList.vue
Normal file
73
my-project-frontend/src/components/TopicCollectList.vue
Normal 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>
|
30
my-project-frontend/src/components/TopicTag.vue
Normal file
30
my-project-frontend/src/components/TopicTag.vue
Normal 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>
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user