添加评论发表操作
This commit is contained in:
parent
863a1d4f0f
commit
47b71807e1
@ -2,6 +2,7 @@ package com.example.controller;
|
|||||||
|
|
||||||
import com.example.entity.RestBean;
|
import com.example.entity.RestBean;
|
||||||
import com.example.entity.dto.Interact;
|
import com.example.entity.dto.Interact;
|
||||||
|
import com.example.entity.vo.request.AddCommentVO;
|
||||||
import com.example.entity.vo.request.TopicCreateVO;
|
import com.example.entity.vo.request.TopicCreateVO;
|
||||||
import com.example.entity.vo.request.TopicUpdateVO;
|
import com.example.entity.vo.request.TopicUpdateVO;
|
||||||
import com.example.entity.vo.response.*;
|
import com.example.entity.vo.response.*;
|
||||||
@ -93,4 +94,10 @@ public class ForumController {
|
|||||||
topicService.updateTopic(id, vo);
|
topicService.updateTopic(id, vo);
|
||||||
return RestBean.success();
|
return RestBean.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/add-comment")
|
||||||
|
public RestBean<String> addComment(@Valid @RequestBody AddCommentVO vo,
|
||||||
|
@RequestAttribute(Const.ATTR_USER_ID) int id) {
|
||||||
|
return utils.messageHandle(() -> topicService.createComment(vo, id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.example.entity.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("db_topic_comments")
|
||||||
|
public class TopicComment {
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
Integer id;
|
||||||
|
Integer tid;
|
||||||
|
Integer uid;
|
||||||
|
String content;
|
||||||
|
Date time;
|
||||||
|
Integer quote;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.example.entity.vo.request;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AddCommentVO {
|
||||||
|
@Min(1)
|
||||||
|
int tid;
|
||||||
|
String content;
|
||||||
|
@Min(-1)
|
||||||
|
int quote;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.example.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.example.entity.dto.TopicComment;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface TopicCommentMapper extends BaseMapper<TopicComment> {
|
||||||
|
}
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||||||
import com.example.entity.dto.Interact;
|
import com.example.entity.dto.Interact;
|
||||||
import com.example.entity.dto.Topic;
|
import com.example.entity.dto.Topic;
|
||||||
import com.example.entity.dto.TopicType;
|
import com.example.entity.dto.TopicType;
|
||||||
|
import com.example.entity.vo.request.AddCommentVO;
|
||||||
import com.example.entity.vo.request.TopicCreateVO;
|
import com.example.entity.vo.request.TopicCreateVO;
|
||||||
import com.example.entity.vo.request.TopicUpdateVO;
|
import com.example.entity.vo.request.TopicUpdateVO;
|
||||||
import com.example.entity.vo.response.TopicPreviewVO;
|
import com.example.entity.vo.response.TopicPreviewVO;
|
||||||
@ -21,4 +22,5 @@ public interface TopicService extends IService<Topic> {
|
|||||||
TopicDetailVO getTopic(int tid, int uid);
|
TopicDetailVO getTopic(int tid, int uid);
|
||||||
void interact(Interact interact, boolean state);
|
void interact(Interact interact, boolean state);
|
||||||
List<TopicPreviewVO> listCollectTopic(int uid);
|
List<TopicPreviewVO> listCollectTopic(int uid);
|
||||||
|
String createComment(AddCommentVO vo, int uid);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.example.entity.dto.*;
|
import com.example.entity.dto.*;
|
||||||
|
import com.example.entity.vo.request.AddCommentVO;
|
||||||
import com.example.entity.vo.request.TopicCreateVO;
|
import com.example.entity.vo.request.TopicCreateVO;
|
||||||
import com.example.entity.vo.request.TopicUpdateVO;
|
import com.example.entity.vo.request.TopicUpdateVO;
|
||||||
import com.example.entity.vo.response.TopicDetailVO;
|
import com.example.entity.vo.response.TopicDetailVO;
|
||||||
@ -41,6 +42,9 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
@Resource
|
@Resource
|
||||||
AccountPrivacyMapper accountPrivacyMapper;
|
AccountPrivacyMapper accountPrivacyMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
TopicCommentMapper commentMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
FlowUtils flowUtils;
|
FlowUtils flowUtils;
|
||||||
|
|
||||||
@ -152,6 +156,19 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createComment(AddCommentVO vo, int uid) {
|
||||||
|
String key = Const.FORUM_TOPIC_COMMENT_COUNTER + uid;
|
||||||
|
if(!flowUtils.limitPeriodCounterCheck(key, 2, 60))
|
||||||
|
return "发表评论频繁,请稍后再试!";
|
||||||
|
TopicComment comment = new TopicComment();
|
||||||
|
comment.setUid(uid);
|
||||||
|
BeanUtils.copyProperties(vo, comment);
|
||||||
|
comment.setTime(new Date());
|
||||||
|
commentMapper.insert(comment);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasInteract(int tid, int uid, String type){
|
private boolean hasInteract(int tid, int uid, String type){
|
||||||
String key = tid + ":" + uid;
|
String key = tid + ":" + uid;
|
||||||
if(template.opsForHash().hasKey(type, key))
|
if(template.opsForHash().hasKey(type, key))
|
||||||
|
@ -26,5 +26,6 @@ public final class Const {
|
|||||||
public final static String FORUM_IMAGE_COUNTER = "image:upload:";
|
public final static String FORUM_IMAGE_COUNTER = "image:upload:";
|
||||||
public final static String FORUM_WEATHER_CACHE = "weather:cache:";
|
public final static String FORUM_WEATHER_CACHE = "weather:cache:";
|
||||||
public final static String FORUM_TOPIC_CREATE_COUNTER = "topic:create:";
|
public final static String FORUM_TOPIC_CREATE_COUNTER = "topic:create:";
|
||||||
|
public final static String FORUM_TOPIC_COMMENT_COUNTER = "topic:comment:";
|
||||||
public final static String FORUM_TOPIC_PREVIEW_CACHE = "topic:preview:";
|
public final static String FORUM_TOPIC_PREVIEW_CACHE = "topic:preview:";
|
||||||
}
|
}
|
||||||
|
15
my-project-frontend/src/assets/quill.css
Normal file
15
my-project-frontend/src/assets/quill.css
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
.ql-toolbar {
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
|
border-color: var(--el-border-color) !important;
|
||||||
|
}
|
||||||
|
.ql-container{
|
||||||
|
border-radius: 0 0 5px 5px;
|
||||||
|
border-color: var(--el-border-color) !important;
|
||||||
|
}
|
||||||
|
.ql-editor.ql-blank::before{
|
||||||
|
color: grey !important;
|
||||||
|
font-style: normal !important;
|
||||||
|
}
|
||||||
|
.ql-editor {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
61
my-project-frontend/src/components/TopicCommentEditor.vue
Normal file
61
my-project-frontend/src/components/TopicCommentEditor.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<script setup>
|
||||||
|
import {QuillEditor} from "@vueup/vue-quill";
|
||||||
|
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
||||||
|
import {post} from "@/net";
|
||||||
|
import {reactive, ref} from "vue";
|
||||||
|
import {ElMessage} from "element-plus";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
quote: Number,
|
||||||
|
show: Boolean,
|
||||||
|
tid: String
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
|
const content = ref()
|
||||||
|
|
||||||
|
function submitComment() {
|
||||||
|
post('/api/forum/add-comment', {
|
||||||
|
tid: props.tid,
|
||||||
|
content: JSON.stringify(content.value),
|
||||||
|
quote: props.quote
|
||||||
|
}, () => {
|
||||||
|
ElMessage.success('评论成功')
|
||||||
|
emit('close')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-drawer :model-value="show"
|
||||||
|
title="发表回复"
|
||||||
|
:size="270" direction="btt"
|
||||||
|
@close="emit('close')"
|
||||||
|
:show-close="false">
|
||||||
|
<div style="padding: 10px;width: 100%">
|
||||||
|
<div>
|
||||||
|
<quill-editor style="height: 100px" v-model:content="content"
|
||||||
|
placeholder="请发表友善的评论,不要使用脏话骂人,都是大学生素质高一点"/>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 10px;text-align: right">
|
||||||
|
<el-button @click="submitComment" type="success" plain>发表评论</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
:deep(.el-drawer) {
|
||||||
|
width: 800px;
|
||||||
|
margin: 20px auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
:deep(.el-drawer__header) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
:deep(.el-drawer__body) {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -196,19 +196,4 @@ const editorOption = {
|
|||||||
:deep(.el-drawer__header) {
|
:deep(.el-drawer__header) {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
:deep(.ql-toolbar) {
|
|
||||||
border-radius: 5px 5px 0 0;
|
|
||||||
border-color: var(--el-border-color);
|
|
||||||
}
|
|
||||||
:deep(.ql-container){
|
|
||||||
border-radius: 0 0 5px 5px;
|
|
||||||
border-color: var(--el-border-color);
|
|
||||||
}
|
|
||||||
:deep(.ql-editor.ql-blank::before){
|
|
||||||
color: grey;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
:deep(.ql-editor) {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -5,6 +5,7 @@ import axios from "axios";
|
|||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
|
|
||||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||||
|
import '@/assets/quill.css'
|
||||||
|
|
||||||
axios.defaults.baseURL = 'http://localhost:8080'
|
axios.defaults.baseURL = 'http://localhost:8080'
|
||||||
|
|
||||||
|
@ -21,6 +21,6 @@ get('/api/forum/types', data => {
|
|||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
<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="70"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -3,7 +3,7 @@ import {useRoute} from "vue-router";
|
|||||||
import {get, post} from "@/net";
|
import {get, post} from "@/net";
|
||||||
import {computed, reactive, ref} from "vue";
|
import {computed, reactive, ref} from "vue";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {ArrowLeft, CircleCheck, EditPen, Female, Male, Star} from "@element-plus/icons-vue";
|
import {ArrowLeft, CircleCheck, EditPen, Female, Male, Plus, Star} from "@element-plus/icons-vue";
|
||||||
import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html';
|
import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html';
|
||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import Card from "@/components/Card.vue";
|
import Card from "@/components/Card.vue";
|
||||||
@ -12,6 +12,7 @@ import InteractButton from "@/components/InteractButton.vue";
|
|||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import TopicTag from "@/components/TopicTag.vue";
|
import TopicTag from "@/components/TopicTag.vue";
|
||||||
import TopicEditor from "@/components/TopicEditor.vue";
|
import TopicEditor from "@/components/TopicEditor.vue";
|
||||||
|
import TopicCommentEditor from "@/components/TopicCommentEditor.vue";
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
@ -25,6 +26,11 @@ const topic = reactive({
|
|||||||
comments: []
|
comments: []
|
||||||
})
|
})
|
||||||
const edit = ref(false)
|
const edit = ref(false)
|
||||||
|
const comment = reactive({
|
||||||
|
show: false,
|
||||||
|
text: '',
|
||||||
|
quote: -1
|
||||||
|
})
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
get(`/api/forum/topic?tid=${tid}`, data => {
|
get(`/api/forum/topic?tid=${tid}`, data => {
|
||||||
@ -124,15 +130,43 @@ function updateTopic(editor) {
|
|||||||
</interact-button>
|
</interact-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="topic-main">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<topic-editor :show="edit" @close="edit = false" v-if="topic.data"
|
<topic-editor :show="edit" @close="edit = false" v-if="topic.data"
|
||||||
:default-title="topic.data.title" :default-text="topic.data.content"
|
:default-title="topic.data.title" :default-text="topic.data.content"
|
||||||
:default-type="topic.data.type" submit-button="更新帖子内容"
|
:default-type="topic.data.type" submit-button="更新帖子内容"
|
||||||
:submit="updateTopic"/>
|
:submit="updateTopic"/>
|
||||||
|
<topic-comment-editor :show="comment.show" @close="comment.show = false"
|
||||||
|
:quote="comment.quote" :tid="tid"/>
|
||||||
|
<div class="add-comment" @click="comment.show = true">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.add-comment {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 45px;
|
||||||
|
font-size: 18px;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: var(--el-bg-color-overlay);
|
||||||
|
box-shadow: var(--el-box-shadow-lighter);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--el-border-color-extra-light);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.topic-page {
|
.topic-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user