完成帖子编辑操作
This commit is contained in:
parent
9777bc26cc
commit
863a1d4f0f
@ -3,6 +3,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.TopicCreateVO;
|
import com.example.entity.vo.request.TopicCreateVO;
|
||||||
|
import com.example.entity.vo.request.TopicUpdateVO;
|
||||||
import com.example.entity.vo.response.*;
|
import com.example.entity.vo.response.*;
|
||||||
import com.example.service.TopicService;
|
import com.example.service.TopicService;
|
||||||
import com.example.service.WeatherService;
|
import com.example.service.WeatherService;
|
||||||
@ -67,8 +68,9 @@ public class ForumController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/topic")
|
@GetMapping("/topic")
|
||||||
public RestBean<TopicDetailVO> topic(@RequestParam @Min(0) int tid){
|
public RestBean<TopicDetailVO> topic(@RequestParam @Min(0) int tid,
|
||||||
return RestBean.success(topicService.getTopic(tid));
|
@RequestAttribute(Const.ATTR_USER_ID) int id){
|
||||||
|
return RestBean.success(topicService.getTopic(tid, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/interact")
|
@GetMapping("/interact")
|
||||||
@ -84,4 +86,11 @@ public class ForumController {
|
|||||||
public RestBean<List<TopicPreviewVO>> collects(@RequestAttribute(Const.ATTR_USER_ID) int id){
|
public RestBean<List<TopicPreviewVO>> collects(@RequestAttribute(Const.ATTR_USER_ID) int id){
|
||||||
return RestBean.success(topicService.listCollectTopic(id));
|
return RestBean.success(topicService.listCollectTopic(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update-topic")
|
||||||
|
public RestBean<Void> updateTopic(@Valid @RequestBody TopicUpdateVO vo,
|
||||||
|
@RequestAttribute(Const.ATTR_USER_ID) int id) {
|
||||||
|
topicService.updateTopic(id, vo);
|
||||||
|
return RestBean.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.example.entity.vo.request;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TopicUpdateVO {
|
||||||
|
@Min(0)
|
||||||
|
int id;
|
||||||
|
@Min(1)
|
||||||
|
@Max(5)
|
||||||
|
int type;
|
||||||
|
@Length(max = 30)
|
||||||
|
String title;
|
||||||
|
JSONObject content;
|
||||||
|
}
|
@ -6,6 +6,7 @@ import java.util.Date;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class AccountVO {
|
public class AccountVO {
|
||||||
|
int id;
|
||||||
String username;
|
String username;
|
||||||
String email;
|
String email;
|
||||||
String role;
|
String role;
|
||||||
|
@ -5,6 +5,7 @@ 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.TopicCreateVO;
|
import com.example.entity.vo.request.TopicCreateVO;
|
||||||
|
import com.example.entity.vo.request.TopicUpdateVO;
|
||||||
import com.example.entity.vo.response.TopicPreviewVO;
|
import com.example.entity.vo.response.TopicPreviewVO;
|
||||||
import com.example.entity.vo.response.TopicTopVO;
|
import com.example.entity.vo.response.TopicTopVO;
|
||||||
import com.example.entity.vo.response.TopicDetailVO;
|
import com.example.entity.vo.response.TopicDetailVO;
|
||||||
@ -14,9 +15,10 @@ import java.util.List;
|
|||||||
public interface TopicService extends IService<Topic> {
|
public interface TopicService extends IService<Topic> {
|
||||||
List<TopicType> listType();
|
List<TopicType> listType();
|
||||||
String createTopic(int uid, TopicCreateVO vo);
|
String createTopic(int uid, TopicCreateVO vo);
|
||||||
|
void updateTopic(int uid, TopicUpdateVO vo);
|
||||||
List<TopicPreviewVO> listTopicByPage(int pageNumber, int type);
|
List<TopicPreviewVO> listTopicByPage(int pageNumber, int type);
|
||||||
List<TopicTopVO> topTopics();
|
List<TopicTopVO> topTopics();
|
||||||
TopicDetailVO getTopic(int tid);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ 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.TopicCreateVO;
|
import com.example.entity.vo.request.TopicCreateVO;
|
||||||
|
import com.example.entity.vo.request.TopicUpdateVO;
|
||||||
import com.example.entity.vo.response.TopicDetailVO;
|
import com.example.entity.vo.response.TopicDetailVO;
|
||||||
import com.example.entity.vo.response.TopicPreviewVO;
|
import com.example.entity.vo.response.TopicPreviewVO;
|
||||||
import com.example.entity.vo.response.TopicTopVO;
|
import com.example.entity.vo.response.TopicTopVO;
|
||||||
@ -54,6 +55,17 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
return typeMapper.selectList(null);
|
return typeMapper.selectList(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTopic(int uid, TopicUpdateVO vo) {
|
||||||
|
baseMapper.update(null, Wrappers.<Topic>update()
|
||||||
|
.eq("uid", uid)
|
||||||
|
.eq("id", vo.getId())
|
||||||
|
.set("title", vo.getTitle())
|
||||||
|
.set("content", vo.getContent().toString())
|
||||||
|
.set("type", vo.getType())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String createTopic(int uid, TopicCreateVO vo) {
|
public String createTopic(int uid, TopicCreateVO vo) {
|
||||||
if(!this.textLimitCheck(vo.getContent()))
|
if(!this.textLimitCheck(vo.getContent()))
|
||||||
@ -116,13 +128,13 @@ public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic> implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TopicDetailVO getTopic(int tid) {
|
public TopicDetailVO getTopic(int tid, int uid) {
|
||||||
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(
|
TopicDetailVO.Interact interact = new TopicDetailVO.Interact(
|
||||||
hasInteract(tid, topic.getUid(), "like"),
|
hasInteract(tid, uid, "like"),
|
||||||
hasInteract(tid, topic.getUid(), "collect")
|
hasInteract(tid, uid, "collect")
|
||||||
);
|
);
|
||||||
vo.setInteract(interact);
|
vo.setInteract(interact);
|
||||||
TopicDetailVO.User user = new TopicDetailVO.User();
|
TopicDetailVO.User user = new TopicDetailVO.User();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {Document} from "@element-plus/icons-vue";
|
import {Document} from "@element-plus/icons-vue";
|
||||||
import {QuillEditor, Quill} from "@vueup/vue-quill";
|
import {QuillEditor, Quill, Delta} from "@vueup/vue-quill";
|
||||||
import {computed, reactive, ref} from "vue";
|
import {computed, reactive, ref} from "vue";
|
||||||
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
||||||
import {accessHeader, post} from "@/net";
|
import {accessHeader, post} from "@/net";
|
||||||
@ -10,9 +10,39 @@ import ImageResize from "quill-image-resize-vue";
|
|||||||
import { ImageExtend, QuillWatch } from "quill-image-super-solution-module";
|
import { ImageExtend, QuillWatch } from "quill-image-super-solution-module";
|
||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
|
|
||||||
defineProps({ show: Boolean })
|
const props = defineProps({
|
||||||
|
show: Boolean,
|
||||||
|
defaultTitle: {
|
||||||
|
default: '',
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
defaultText: {
|
||||||
|
default: '',
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
defaultType: {
|
||||||
|
default: 1,
|
||||||
|
type: Number
|
||||||
|
},
|
||||||
|
submitButton: {
|
||||||
|
default: '立即发布',
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
submit: {
|
||||||
|
default: (editor, success) => {
|
||||||
|
post('/api/forum/create-topic', {
|
||||||
|
type: editor.type,
|
||||||
|
title: editor.title,
|
||||||
|
content: editor.text
|
||||||
|
}, () => {
|
||||||
|
ElMessage.success("帖子发表成功!")
|
||||||
|
success()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
type: Function
|
||||||
|
}
|
||||||
|
})
|
||||||
const emit = defineEmits(['close', 'created'])
|
const emit = defineEmits(['close', 'created'])
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
const refEditor = ref()
|
const refEditor = ref()
|
||||||
@ -24,9 +54,12 @@ const editor = reactive({
|
|||||||
})
|
})
|
||||||
|
|
||||||
function initEditor() {
|
function initEditor() {
|
||||||
refEditor.value.setContents('', 'user')
|
if(props.defaultText)
|
||||||
editor.title = ''
|
editor.text = new Delta(JSON.parse(props.defaultText))
|
||||||
editor.type = 1
|
else
|
||||||
|
refEditor.value.setContents('', 'user')
|
||||||
|
editor.title = props.defaultTitle
|
||||||
|
editor.type = props.defaultType
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitTopic(){
|
function submitTopic(){
|
||||||
@ -43,14 +76,7 @@ function submitTopic(){
|
|||||||
ElMessage.warning('请选择一个合适的帖子类型!')
|
ElMessage.warning('请选择一个合适的帖子类型!')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
post('/api/forum/create-topic', {
|
props.submit(editor, () => emit('created'))
|
||||||
type: editor.type,
|
|
||||||
title: editor.title,
|
|
||||||
content: editor.text
|
|
||||||
}, () => {
|
|
||||||
ElMessage.success("帖子发表成功!")
|
|
||||||
emit('created')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function deltaToText(delta) {
|
function deltaToText(delta) {
|
||||||
@ -154,7 +180,7 @@ const editorOption = {
|
|||||||
当前字数: {{ contentLength }}(最大支持20000字)
|
当前字数: {{ contentLength }}(最大支持20000字)
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-button @click="submitTopic" type="success" plain>立即发布</el-button>
|
<el-button @click="submitTopic" type="success" plain>{{submitButton}}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
@ -5,6 +5,7 @@ export const useStore = defineStore('general', {
|
|||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
user: {
|
user: {
|
||||||
|
id: -1,
|
||||||
username: '',
|
username: '',
|
||||||
email: '',
|
email: '',
|
||||||
role: '',
|
role: '',
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {useRoute} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import {get} from "@/net";
|
import {get, post} from "@/net";
|
||||||
import {computed, reactive} from "vue";
|
import {computed, reactive, ref} from "vue";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {ArrowLeft, CircleCheck, Female, Male, Star} from "@element-plus/icons-vue";
|
import {ArrowLeft, CircleCheck, EditPen, Female, Male, 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";
|
||||||
@ -11,6 +11,7 @@ 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";
|
import TopicTag from "@/components/TopicTag.vue";
|
||||||
|
import TopicEditor from "@/components/TopicEditor.vue";
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
@ -23,12 +24,16 @@ const topic = reactive({
|
|||||||
collect: false,
|
collect: false,
|
||||||
comments: []
|
comments: []
|
||||||
})
|
})
|
||||||
|
const edit = ref(false)
|
||||||
|
|
||||||
get(`/api/forum/topic?tid=${tid}`, data => {
|
function init() {
|
||||||
topic.data = data
|
get(`/api/forum/topic?tid=${tid}`, data => {
|
||||||
topic.like = data.interact.like
|
topic.data = data
|
||||||
topic.collect = data.interact.collect
|
topic.like = data.interact.like
|
||||||
})
|
topic.collect = data.interact.collect
|
||||||
|
})
|
||||||
|
}
|
||||||
|
init()
|
||||||
|
|
||||||
const content = computed(() => {
|
const content = computed(() => {
|
||||||
const ops = JSON.parse(topic.data.content).ops
|
const ops = JSON.parse(topic.data.content).ops
|
||||||
@ -45,6 +50,19 @@ function interact(type, message) {
|
|||||||
ElMessage.success(`已取消${message}!`)
|
ElMessage.success(`已取消${message}!`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTopic(editor) {
|
||||||
|
post('/api/forum/update-topic', {
|
||||||
|
id: tid,
|
||||||
|
type: editor.type,
|
||||||
|
title: editor.title,
|
||||||
|
content: editor.text
|
||||||
|
}, () => {
|
||||||
|
ElMessage.success("帖子内容更新成功!")
|
||||||
|
edit.value = false
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -91,6 +109,10 @@ function interact(type, message) {
|
|||||||
<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">
|
||||||
|
<interact-button name="编辑帖子" color="dodgerblue" style="margin-right: 20px"
|
||||||
|
:check="false" @check="edit = true" v-if="store.user.id === topic.data.user.uid">
|
||||||
|
<el-icon><EditPen /></el-icon>
|
||||||
|
</interact-button>
|
||||||
<interact-button name="点个赞吧" check-name="已点赞" color="pink"
|
<interact-button name="点个赞吧" check-name="已点赞" color="pink"
|
||||||
:check="topic.like" @check="interact('like', '点赞')">
|
:check="topic.like" @check="interact('like', '点赞')">
|
||||||
<el-icon><CircleCheck /></el-icon>
|
<el-icon><CircleCheck /></el-icon>
|
||||||
@ -103,6 +125,10 @@ function interact(type, message) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<topic-editor :show="edit" @close="edit = false" v-if="topic.data"
|
||||||
|
:default-title="topic.data.title" :default-text="topic.data.content"
|
||||||
|
:default-type="topic.data.type" submit-button="更新帖子内容"
|
||||||
|
:submit="updateTopic"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user