完善点赞和收藏的实时展示
This commit is contained in:
parent
e808240a32
commit
ebcd6ab4ae
@ -16,7 +16,7 @@ public class Interact {
|
|||||||
public static Interact parseInteract(String key, String type) {
|
public static Interact parseInteract(String key, String type) {
|
||||||
String[] keys = key.split(":");
|
String[] keys = key.split(":");
|
||||||
return new Interact(Integer.parseInt(keys[0]),
|
return new Interact(Integer.parseInt(keys[0]),
|
||||||
Integer.parseInt(keys[0]),
|
Integer.parseInt(keys[1]),
|
||||||
new Date(), type);
|
new Date(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.example.entity.vo.response;
|
package com.example.entity.vo.response;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -12,6 +13,14 @@ public class TopicDetailVO {
|
|||||||
Integer type;
|
Integer type;
|
||||||
Date time;
|
Date time;
|
||||||
User user;
|
User user;
|
||||||
|
Interact interact;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class Interact {
|
||||||
|
Boolean like;
|
||||||
|
Boolean collect;
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class User {
|
public static class User {
|
||||||
|
@ -16,4 +16,6 @@ public class TopicPreviewVO {
|
|||||||
int uid;
|
int uid;
|
||||||
String username;
|
String username;
|
||||||
String avatar;
|
String avatar;
|
||||||
|
int like;
|
||||||
|
int collect;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import com.example.entity.dto.Topic;
|
|||||||
import org.apache.ibatis.annotations.Delete;
|
import org.apache.ibatis.annotations.Delete;
|
||||||
import org.apache.ibatis.annotations.Insert;
|
import org.apache.ibatis.annotations.Insert;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -30,4 +31,14 @@ public interface TopicMapper extends BaseMapper<Topic> {
|
|||||||
</script>
|
</script>
|
||||||
""")
|
""")
|
||||||
int deleteInteract(List<Interact> interacts, String type);
|
int deleteInteract(List<Interact> interacts, String type);
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
select count(*) from db_topic_interact_${type} where tid = #{tid}
|
||||||
|
""")
|
||||||
|
int interactCount(int tid, String type);
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
select count(*) from db_topic_interact_${type} where tid = #{tid} and uid = #{uid}
|
||||||
|
""")
|
||||||
|
int userInteractCount(int tid, int uid, String type);
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,11 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
TopicDetailVO vo = new TopicDetailVO();
|
TopicDetailVO vo = new TopicDetailVO();
|
||||||
Topic topic = baseMapper.selectById(tid);
|
Topic topic = baseMapper.selectById(tid);
|
||||||
BeanUtils.copyProperties(topic, vo);
|
BeanUtils.copyProperties(topic, vo);
|
||||||
|
TopicDetailVO.Interact interact = new TopicDetailVO.Interact(
|
||||||
|
hasInteract(tid, topic.getUid(), "like"),
|
||||||
|
hasInteract(tid, topic.getUid(), "collect")
|
||||||
|
);
|
||||||
|
vo.setInteract(interact);
|
||||||
TopicDetailVO.User user = new TopicDetailVO.User();
|
TopicDetailVO.User user = new TopicDetailVO.User();
|
||||||
BeanUtils.copyProperties(topic, user);
|
BeanUtils.copyProperties(topic, user);
|
||||||
vo.setUser(this.fillUserDetailsByPrivacy(user, topic.getUid()));
|
vo.setUser(this.fillUserDetailsByPrivacy(user, topic.getUid()));
|
||||||
@ -124,6 +129,13 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasInteract(int tid, int uid, String type){
|
||||||
|
String key = tid + ":" + uid;
|
||||||
|
if(template.opsForHash().hasKey(type, key))
|
||||||
|
return Boolean.parseBoolean(template.opsForHash().entries(type).get(key).toString());
|
||||||
|
return baseMapper.userInteractCount(tid, uid, type) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 由于论坛交互数据(如点赞、收藏等)更新可能会非常频繁
|
* 由于论坛交互数据(如点赞、收藏等)更新可能会非常频繁
|
||||||
* 更新信息实时到MySQL不太现实,所以需要用Redis做缓冲并在合适的时机一次性入库一段时间内的全部数据
|
* 更新信息实时到MySQL不太现实,所以需要用Redis做缓冲并在合适的时机一次性入库一段时间内的全部数据
|
||||||
@ -134,7 +146,6 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
private final Map<String, Boolean> state = new HashMap<>();
|
private final Map<String, Boolean> state = new HashMap<>();
|
||||||
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
|
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
|
||||||
private void saveInteractData(String type) {
|
private void saveInteractData(String type) {
|
||||||
System.out.println(state);
|
|
||||||
if(!state.getOrDefault(type, false)) {
|
if(!state.getOrDefault(type, false)) {
|
||||||
state.put(type, true);
|
state.put(type, true);
|
||||||
service.schedule(() -> {
|
service.schedule(() -> {
|
||||||
@ -146,7 +157,6 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
|
|
||||||
private void saveInteract(String type) {
|
private void saveInteract(String type) {
|
||||||
synchronized (type.intern()) {
|
synchronized (type.intern()) {
|
||||||
System.out.println(type);
|
|
||||||
List<Interact> check = new LinkedList<>();
|
List<Interact> check = new LinkedList<>();
|
||||||
List<Interact> uncheck = new LinkedList<>();
|
List<Interact> uncheck = new LinkedList<>();
|
||||||
template.opsForHash().entries(type).forEach((k, v) -> {
|
template.opsForHash().entries(type).forEach((k, v) -> {
|
||||||
@ -177,6 +187,8 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
TopicPreviewVO vo = new TopicPreviewVO();
|
TopicPreviewVO vo = new TopicPreviewVO();
|
||||||
BeanUtils.copyProperties(accountMapper.selectById(topic.getUid()), vo);
|
BeanUtils.copyProperties(accountMapper.selectById(topic.getUid()), vo);
|
||||||
BeanUtils.copyProperties(topic, vo);
|
BeanUtils.copyProperties(topic, vo);
|
||||||
|
vo.setLike(baseMapper.interactCount(topic.getId(), "like"));
|
||||||
|
vo.setCollect(baseMapper.interactCount(topic.getId(), "collect"));
|
||||||
List<String> images = new ArrayList<>();
|
List<String> images = new ArrayList<>();
|
||||||
StringBuilder previewText = new StringBuilder();
|
StringBuilder previewText = new StringBuilder();
|
||||||
JSONArray ops = JSONObject.parseObject(topic.getContent()).getJSONArray("ops");
|
JSONArray ops = JSONObject.parseObject(topic.getContent()).getJSONArray("ops");
|
||||||
|
@ -23,7 +23,11 @@ const topic = reactive({
|
|||||||
comments: []
|
comments: []
|
||||||
})
|
})
|
||||||
|
|
||||||
get(`/api/forum/topic?tid=${tid}`, data => topic.data = data)
|
get(`/api/forum/topic?tid=${tid}`, data => {
|
||||||
|
topic.data = data
|
||||||
|
topic.like = data.interact.like
|
||||||
|
topic.collect = data.interact.collect
|
||||||
|
})
|
||||||
|
|
||||||
const content = computed(() => {
|
const content = computed(() => {
|
||||||
const ops = JSON.parse(topic.data.content).ops
|
const ops = JSON.parse(topic.data.content).ops
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
Edit,
|
Edit,
|
||||||
EditPen,
|
EditPen,
|
||||||
Link,
|
Link,
|
||||||
Microphone
|
Microphone, CircleCheck, Star
|
||||||
} 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";
|
||||||
@ -156,6 +156,14 @@ navigator.geolocation.getCurrentPosition(position => {
|
|||||||
<div style="display: grid;grid-template-columns: repeat(3, 1fr);grid-gap: 10px">
|
<div style="display: grid;grid-template-columns: repeat(3, 1fr);grid-gap: 10px">
|
||||||
<el-image v-for="img in item.images" fit="cover" :src="img" class="topic-image"></el-image>
|
<el-image v-for="img in item.images" fit="cover" :src="img" class="topic-image"></el-image>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display: flex;gap: 20px;font-size: 13px;margin-top: 10px">
|
||||||
|
<div>
|
||||||
|
<el-icon style="vertical-align: middle"><CircleCheck /></el-icon> {{item.like}} 点赞
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-icon style="vertical-align: middle"><Star /></el-icon> {{item.collect}} 收藏
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</light-card>
|
</light-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user