feat(note): 新增笔记创建和编辑功能

- 实现了笔记创建和编辑的前端逻辑
- 更新了相关的后端接口和数据库操作
- 优化了分组获取和展示逻辑
-调整了 Markdown 文件更新接口
This commit is contained in:
ikmkj
2025-07-30 07:48:38 +08:00
parent 431e3dea1c
commit 57fb74dc49
9 changed files with 95 additions and 65 deletions

View File

@@ -1,5 +1,6 @@
package com.test.bijihoudaun.controller;
import cn.hutool.core.util.StrUtil;
import com.test.bijihoudaun.common.response.R;
import com.test.bijihoudaun.entity.Grouping;
import com.test.bijihoudaun.service.GroupingService;
@@ -29,14 +30,14 @@ public class GroupingController {
@Operation(summary = "获取全部分组")
@Parameters({
@Parameter(name = "parentId", description = "0是一级其他的是看它的父级id", required = true)
@Parameter(name = "parentId", description = "0是一级其他的是看它的父级id", required = false)
})
@GetMapping
public R<List<Grouping>> getAllGroupings(String parentId) {
if (parentId == null) {
return R.fail("参数不能为空");
public R<List<Grouping>> getAllGroupings(@RequestParam(required = false) String parentId) {
Long l= null;
if (StrUtil.isNotEmpty(parentId)) {
l = Long.parseLong(parentId);
}
long l = Long.parseLong(parentId);
List<Grouping> groupings = groupingService.getAllGroupings(l);
return R.success(groupings);
}

View File

@@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
@Tag(name = "markdown接口")
@@ -61,21 +62,10 @@ public class MarkdownController {
}
@Operation(summary = "更新Markdown文件")
@Parameters({
@Parameter(name = "id", description = "Markdown文件ID", required = true),
@Parameter(name = "content", description = "Markdown文件内容", required = true)
})
@PostMapping("/{id}")
public R<MarkdownFile> updateMarkdown(
@PathVariable String id,
String content) {
long l = Long.parseLong(id);
MarkdownFile file = markdownFileService.updateMarkdownContent(l, content);
if (file != null) {
return R.success(file);
}
return R.fail();
@PostMapping("/updateMarkdown")
public R<MarkdownFile> updateMarkdown(@RequestBody MarkdownFile markdownFile) {
MarkdownFile file = markdownFileService.updateMarkdownContent(markdownFile);
return R.success(file);
}
@Operation(summary = "获取所有Markdown文件")

View File

@@ -18,11 +18,9 @@ public interface MarkdownFileService extends IService<MarkdownFile> {
/**
* 更新Markdown内容
* @param id 文件ID
* @param content 新内容
* @return 更新后的文件对象
*/
MarkdownFile updateMarkdownContent(Long id, String content);
MarkdownFile updateMarkdownContent(MarkdownFile markdownFile);
/**
* 根据ID获取Markdown文件

View File

@@ -27,9 +27,11 @@ public class GroupingServiceImpl
@Override
public List<Grouping> getAllGroupings(Long parentId) {
// return groupingMapper.selectList(new LambdaQueryWrapper<Grouping>()
// .eq(Grouping::getParentId, parentId));
return groupingMapper.selectList(null);
if (parentId == null){
return groupingMapper.selectList(null);
}
return groupingMapper.selectList(new LambdaQueryWrapper<Grouping>()
.eq(Grouping::getParentId, parentId));
}
@Override

View File

@@ -40,14 +40,16 @@ public class MarkdownFileServiceImpl
}
@Override
public MarkdownFile updateMarkdownContent(Long id, String content) {
MarkdownFile file = this.getById(id);
if (file != null) {
file.setContent(content);
file.setUpdatedAt(new Date());
this.updateById(file);
public MarkdownFile updateMarkdownContent(MarkdownFile markdownFile) {
markdownFile.setUpdatedAt(new Date());
if (markdownFile.getId() != null){
markdownFileMapper.update(markdownFile, new QueryWrapper<MarkdownFile>().eq("id", markdownFile.getId()));
}else {
markdownFile.setId(snowflakeIdGenerator.nextId());
markdownFile.setCreatedAt(new Date());
markdownFileMapper.insert(markdownFile);
}
return file;
return markdownFile;
}
@Override

View File

@@ -21,14 +21,8 @@ export const addGroupings = (name) => {
})
}
//更新Markdown文件
export const updateMarkdown = (id, data) => {
const formData = new FormData()
if (data) formData.append('content', data)
return axiosApi.post(`/api/markdown/${id}`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
export const updateMarkdown = (data) => {
return axiosApi.post(`/api/markdown/updateMarkdown`, data)
}
// 批量删除图片
export const deleteImages = (list) => {

View File

@@ -99,7 +99,14 @@
<!-- 分类创建对话框 -->
<el-dialog v-model="showCreateGroupDialog" title="新建分类" width="30%">
<el-form :model="newGroupForm" label-width="80px">
<el-form-item label="分类名称">
<el-switch v-model="isGroup1" active-text="一级分类" inactive-text="二级分类" style="margin-bottom: 20px;margin-left:30%" />
<el-form-item label="一级名称">
<el-input v-model="newGroupForm.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="一级名称">
<el-input v-model="newGroupForm.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item v-if="!isGroup1" label="二级名称">
<el-input v-model="newGroupForm.name" autocomplete="off"></el-input>
</el-form-item>
</el-form>
@@ -115,12 +122,22 @@
<el-form-item label="笔记标题">
<el-input v-model="newNoteForm.title" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="选择大分类">
<el-select v-model="fenlei1" :change="getjb2()" placeholder="请选择">
<el-option
v-for="item in groupings"
:key="item.id"
:label="item.grouping"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="选择分类">
<el-select v-model="newNoteForm.groupingId" placeholder="请选择">
<el-option
v-for="group in groupings"
v-for="group in fenlei2"
:key="group.id"
:label="group.name"
:label="group.grouping"
:value="group.id"
></el-option>
</el-select>
@@ -150,7 +167,11 @@ import {
} from '@/api/CommonApi.js'
import {DArrowRight} from "@element-plus/icons-vue";
const isGroup1=ref(true)
// 创建新文件中大分类的信息
const fenlei1=ref(null)
// 创建新文件中分类信息
const fenlei2=ref(null)
const markdownFiles = ref([]);
const groupings = ref([]);
// 二级分类下的markdown文件
@@ -162,22 +183,36 @@ const isCollapsed = ref(false);
const showCreateGroupDialog = ref(false);
const showCreateNoteDialog = ref(false);
const newGroupForm = ref({ name: '' });
const newNoteForm = ref({ title: '', groupingId: null });
const newNoteForm = ref({
id: null,
title: '',
groupingId: null ,
fileName: '',
content: ''
});
// 创建新笔记的多级菜单
const options=ref([])
// 编辑笔记的数据
const editData=ref(null)
// 笔记中的所有图片url
const imageUrls = ref([]);
// 刚开始笔记中的所有图片url
const originalImages = ref([]);
// 分类为二级的数据
const jb22=ref([])
// 创建md文件时通过大分类获取二级分类
const getjb2 = async () => {
if (fenlei1.value != null) {
const response = await groupingAll(fenlei1.value)
fenlei2.value=response.data
}
}
// 获取所有分组
const fetchGroupings = async () => {
try {
const response = await groupingAll(0)
const response = await groupingAll("")
const jb1 = []
const jb2 = []
for (let i = 0; i <response.data.length; i++) {
@@ -189,6 +224,15 @@ const fetchGroupings = async () => {
}
groupings.value=jb1
jb22.value=jb2
for (let i = 0; i < jb1.length; i++){
jb1[i].children=[]
options.value.push(jb1[i])
for (let j = 0; j < jb2.length; j++) {
if (+jb2[j].parentId===+jb1[i].id){
options.value[i].children.push(jb2[i])
}
}
}
} catch (error) {
console.error('获取分组失败:', error);
ElMessage.error('获取分组失败: ' + (error.response?.data?.message || error.message));
@@ -237,20 +281,13 @@ const createGrouping = async () => {
// 创建新笔记
const createNote = async () => {
// TODO 添加笔记创建逻辑
try {
await axios.post(`${API_BASE_URL}/api/markdown`, '# 新笔记内容', {
params: {
groupingId: newNoteForm.value.groupingId,
title: newNoteForm.value.title,
fileName: newNoteForm.value.title
}
});
ElMessage.success('笔记创建成功');
showCreateNoteDialog.value = false;
newNoteForm.value = { title: '', groupingId: null };
await chushihua()
newNoteForm.value.fileName = newNoteForm.value.title+'.md'
editData.value=newNoteForm.value
console.log(editData.value)
showCreateNoteDialog.value = false
showEditor.value = true;
selectedFile.value=editData.value
} catch (error) {
ElMessage.error('创建笔记失败: ' + error.message);
}
@@ -258,6 +295,11 @@ const createNote = async () => {
// 选择文件预览
const previewFile = async (file) => {
if (file.id === null){
editData.value=file
selectedFile.value=null
return;
}
try {
const response = await Preview(file.id)
@@ -313,7 +355,8 @@ const handleImageUpload=async (event, insertImage, files) => {
const handleSave= async (file) => {
imageUrls.value = extractImageUrls(file);
extractDeletedImageUrls(imageUrls.value)
const filesRes = await updateMarkdown(editData.value.id,file);
editData.value.content = file
const filesRes = await updateMarkdown(editData.value);
if (filesRes.code===200){
ElMessage.success(filesRes.msg);
await chushihua()

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 KiB