完成收藏列表展示
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);
|
topicService.interact(new Interact(tid, id, new Date(), type), state);
|
||||||
return RestBean.success();
|
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}
|
select count(*) from db_topic_interact_${type} where tid = #{tid} and uid = #{uid}
|
||||||
""")
|
""")
|
||||||
int userInteractCount(int tid, int uid, String type);
|
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();
|
List<TopicTopVO> topTopics();
|
||||||
TopicDetailVO getTopic(int tid);
|
TopicDetailVO getTopic(int tid);
|
||||||
void interact(Interact interact, boolean state);
|
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){
|
public List<TopicPreviewVO> listTopicByPage(int pageNumber, int type){
|
||||||
String key = Const.FORUM_TOPIC_PREVIEW_CACHE + pageNumber + ":" + type;
|
String key = Const.FORUM_TOPIC_PREVIEW_CACHE + pageNumber + ":" + type;
|
||||||
List<TopicPreviewVO> list = cacheUtils.takeListFromCache(key, TopicPreviewVO.class);
|
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"/>
|
<el-backtop target=".main-content-page .el-scrollbar__wrap" :right="20" :bottom="20"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</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 router from "@/router";
|
||||||
import InteractButton from "@/components/InteractButton.vue";
|
import InteractButton from "@/components/InteractButton.vue";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
|
import TopicTag from "@/components/TopicTag.vue";
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
@ -53,12 +54,7 @@ function interact(type, message) {
|
|||||||
<el-button type="info" :icon="ArrowLeft" size="small"
|
<el-button type="info" :icon="ArrowLeft" size="small"
|
||||||
round plain @click="router.push('/index')">返回列表</el-button>
|
round plain @click="router.push('/index')">返回列表</el-button>
|
||||||
<div style="text-align: center;flex: 1;height: 25px">
|
<div style="text-align: center;flex: 1;height: 25px">
|
||||||
<div class="topic-type"
|
<topic-tag :type="topic.data.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>
|
|
||||||
<span style="margin-left: 5px;font-weight: bold">{{topic.data.title}}</span>
|
<span style="margin-left: 5px;font-weight: bold">{{topic.data.title}}</span>
|
||||||
</div>
|
</div>
|
||||||
</card>
|
</card>
|
||||||
@ -90,7 +86,8 @@ function interact(type, message) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="topic-main-right">
|
<div class="topic-main-right">
|
||||||
<div class="topic-content" v-html="content"></div>
|
<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>发帖时间: {{new Date(topic.data.time).toLocaleString()}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align: right;margin-top: 30px">
|
<div style="text-align: right;margin-top: 30px">
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
Edit,
|
Edit,
|
||||||
EditPen,
|
EditPen,
|
||||||
Link,
|
Link,
|
||||||
Microphone, CircleCheck, Star
|
Microphone, CircleCheck, Star, ArrowRightBold, FolderOpened
|
||||||
} from "@element-plus/icons-vue";
|
} from "@element-plus/icons-vue";
|
||||||
import {computed, reactive, ref, watch} from "vue"
|
import {computed, reactive, ref, watch} from "vue"
|
||||||
import Weather from "@/components/Weather.vue";
|
import Weather from "@/components/Weather.vue";
|
||||||
@ -20,6 +20,8 @@ import TopicEditor from "@/components/TopicEditor.vue";
|
|||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
|
import TopicCollectList from "@/components/TopicCollectList.vue";
|
||||||
|
import TopicTag from "@/components/TopicTag.vue";
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ const topics = reactive({
|
|||||||
end: false,
|
end: false,
|
||||||
top: []
|
top: []
|
||||||
})
|
})
|
||||||
|
const collects = ref(false)
|
||||||
|
|
||||||
watch(() => topics.type, () => {
|
watch(() => topics.type, () => {
|
||||||
topics.page = 0
|
topics.page = 0
|
||||||
@ -144,12 +147,7 @@ navigator.geolocation.getCurrentPosition(position => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 5px">
|
<div style="margin-top: 5px">
|
||||||
<div class="topic-type"
|
<topic-tag :type="item.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>
|
|
||||||
<span style="margin-left: 7px;font-weight: bold">{{ item.title }}</span>
|
<span style="margin-left: 7px;font-weight: bold">{{ item.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="topic-preview-content">{{ item.text }}</div>
|
<div class="topic-preview-content">{{ item.text }}</div>
|
||||||
@ -172,6 +170,12 @@ navigator.geolocation.getCurrentPosition(position => {
|
|||||||
<div style="width: 280px">
|
<div style="width: 280px">
|
||||||
<div style="position: sticky;top: 20px">
|
<div style="position: sticky;top: 20px">
|
||||||
<light-card>
|
<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;">
|
<div style="font-weight: bold;">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<CollectionTag/>
|
<CollectionTag/>
|
||||||
@ -225,10 +229,23 @@ navigator.geolocation.getCurrentPosition(position => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<topic-editor :show="editor" @close="editor = false" @created="onTopicCreate"/>
|
<topic-editor :show="editor" @close="editor = false" @created="onTopicCreate"/>
|
||||||
|
<topic-collect-list :show="collects" @close="collects = false"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<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 {
|
.top-topic {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user