feat(image): 添加图片删除功能并优化 Markdown 编辑器
- 在 ImageController 中添加删除图片的接口 - 在 ImageService 中实现删除图片和批量更新图片 ID 的方法 - 在前端集成复制代码插件并优化 Markdown 编辑器配置 - 修复后端分组相关接口的参数类型问题
This commit is contained in:
@@ -47,7 +47,6 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-aop</artifactId>
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- sqlite -->
|
<!-- sqlite -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.xerial</groupId>
|
<groupId>org.xerial</groupId>
|
||||||
|
|||||||
@@ -35,17 +35,20 @@ public class GroupingController {
|
|||||||
@Operation(summary = "更新分组名称")
|
@Operation(summary = "更新分组名称")
|
||||||
@PutMapping("/{id}")
|
@PutMapping("/{id}")
|
||||||
public R<Grouping> updateGrouping(
|
public R<Grouping> updateGrouping(
|
||||||
@PathVariable Long id,
|
@PathVariable String id,
|
||||||
@RequestBody Grouping grouping) {
|
@RequestBody Grouping grouping) {
|
||||||
grouping.setId(id);
|
|
||||||
|
long l = Long.parseLong(id);
|
||||||
|
grouping.setId(l);
|
||||||
Grouping updated = groupingService.updateGrouping(grouping);
|
Grouping updated = groupingService.updateGrouping(grouping);
|
||||||
return R.success(updated);
|
return R.success(updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "删除分组")
|
@Operation(summary = "删除分组")
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public R<Void> deleteGrouping(@PathVariable Long id) {
|
public R<Void> deleteGrouping(@PathVariable String id) {
|
||||||
groupingService.deleteGrouping(id);
|
Long idLong = Long.parseLong(id);
|
||||||
|
groupingService.deleteGrouping(idLong);
|
||||||
return R.success();
|
return R.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Tag(name = "markdown接口")
|
@Tag(name = "markdown接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/images")
|
@RequestMapping("/api/images")
|
||||||
@@ -28,14 +30,39 @@ public class ImageController {
|
|||||||
})
|
})
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public R<Image> uploadImage(
|
public R<Image> uploadImage(
|
||||||
@RequestParam(required = false) Long markdownId,
|
@RequestParam(required = false) String markdownId,
|
||||||
@RequestParam("file") MultipartFile file) {
|
@RequestParam("file") MultipartFile file) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Image image = imageService.uploadImage(markdownId, file);
|
Long markdownIdLong = Long.parseLong(markdownId);
|
||||||
|
Image image = imageService.uploadImage(markdownIdLong, file);
|
||||||
return R.success(image);
|
return R.success(image);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return R.fail();
|
return R.fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "根据id删除图片")
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public R<Void> deleteImage(@PathVariable Long id) {
|
||||||
|
boolean result = imageService.deleteImage(id);
|
||||||
|
if (result) {
|
||||||
|
return R.success();
|
||||||
|
} else {
|
||||||
|
return R.fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "根据url删除图片")
|
||||||
|
@DeleteMapping
|
||||||
|
public R<Void> deleteImageByUrl(@RequestParam String url) {
|
||||||
|
boolean result = imageService.deleteImageByUrl(url);
|
||||||
|
if (result) {
|
||||||
|
return R.success();
|
||||||
|
} else {
|
||||||
|
return R.fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,4 +31,19 @@ public interface ImageService extends IService<Image> {
|
|||||||
* @return 图片列表
|
* @return 图片列表
|
||||||
*/
|
*/
|
||||||
List<Image> getMarkdownImages(Long markdownId);
|
List<Image> getMarkdownImages(Long markdownId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据URL删除图片
|
||||||
|
* @param url
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean deleteImageByUrl(String url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据URL批量更新图片ID
|
||||||
|
* @param list
|
||||||
|
* @param markdownId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean updateImageId(List<String> list, Long markdownId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.test.bijihoudaun.service.impl;
|
package com.test.bijihoudaun.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.stream.CollectorUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
@@ -87,4 +89,38 @@ public class ImageServiceImpl
|
|||||||
.orderByDesc("created_at");
|
.orderByDesc("created_at");
|
||||||
return this.list(queryWrapper);
|
return this.list(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteImageByUrl(String url) {
|
||||||
|
Image image = imageMapper.selectOne(new QueryWrapper<Image>().eq("url", url));
|
||||||
|
if (image == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 删除文件系统中的图片
|
||||||
|
Path filePath = Paths.get(uploadDir, image.getStoredName());
|
||||||
|
Files.deleteIfExists(filePath);
|
||||||
|
|
||||||
|
// 删除数据库记录
|
||||||
|
this.removeById(image.getId());
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("删除图片失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateImageId(List<String> list, Long markdownId) {
|
||||||
|
if (CollUtil.isEmpty( list)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (String url : list) {
|
||||||
|
Image image = imageMapper.selectOne(new QueryWrapper<Image>().eq("url", url));
|
||||||
|
if (image != null) {
|
||||||
|
image.setMarkdownId(markdownId);
|
||||||
|
this.updateById(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,13 +49,18 @@
|
|||||||
<h2>{{ selectedFile.title }}</h2>
|
<h2>{{ selectedFile.title }}</h2>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<el-button v-if="!showEditor" type="primary" @click="selectedFile=null">清空</el-button>
|
<el-button v-if="!showEditor" type="primary" @click="selectedFile=null">清空</el-button>
|
||||||
<el-button v-if="!showEditor" type="primary" @click="editNote(selectedFile)">编辑</el-button>
|
<el-button v-if="!showEditor" type="primary" @click="editNote(selectedFile);isCollapsed=true">编辑</el-button>
|
||||||
<el-button v-if="!showEditor" type="danger" @click="deleteNote(selectedFile)">删除</el-button>
|
<el-button v-if="!showEditor" type="danger" @click="deleteNote(selectedFile)">删除</el-button>
|
||||||
<el-button v-if="showEditor" type="primary" @click="showEditor=!showEditor;selectFile(editData)">返回</el-button>
|
<el-button v-if="showEditor" type="primary" @click="showEditor=!showEditor;selectFile(editData)">返回</el-button>
|
||||||
<el-button v-if="showEditor" type="success" @click="handleSave(editData.content)">保存</el-button>
|
<el-button v-if="showEditor" type="success" @click="handleSave(editData.content)">保存</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<v-md-preview v-if="!showEditor" :text="selectedFile.content" class="markdown-preview"></v-md-preview>
|
<v-md-preview
|
||||||
|
v-if="!showEditor"
|
||||||
|
:text="selectedFile.content"
|
||||||
|
class="markdown-preview"
|
||||||
|
@copy-code-success="handleCopyCodeSuccess"
|
||||||
|
></v-md-preview>
|
||||||
<!-- Markdown编辑器 -->
|
<!-- Markdown编辑器 -->
|
||||||
<v-md-editor
|
<v-md-editor
|
||||||
v-if="showEditor"
|
v-if="showEditor"
|
||||||
@@ -63,6 +68,8 @@
|
|||||||
height="500px"
|
height="500px"
|
||||||
@upload-image="handleImageUpload"
|
@upload-image="handleImageUpload"
|
||||||
@save="handleSave"
|
@save="handleSave"
|
||||||
|
:disabled-menus="[]"
|
||||||
|
@copy-code-success="handleCopyCodeSuccess"
|
||||||
></v-md-editor>
|
></v-md-editor>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -139,6 +146,8 @@ import '@kangc/v-md-editor/lib/theme/style/github.css';
|
|||||||
import {groupingId, groupingAll, markdownAll, addGroupings, Preview, updateMarkdown} from '@/api/CommonApi.js'
|
import {groupingId, groupingAll, markdownAll, addGroupings, Preview, updateMarkdown} from '@/api/CommonApi.js'
|
||||||
import {DArrowRight} from "@element-plus/icons-vue";
|
import {DArrowRight} from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const markdownFiles = ref([]);
|
const markdownFiles = ref([]);
|
||||||
const groupings = ref([]);
|
const groupings = ref([]);
|
||||||
const groupFiles = ref({});
|
const groupFiles = ref({});
|
||||||
@@ -154,6 +163,8 @@ const newNoteForm = ref({ title: '', groupingId: null });
|
|||||||
const editData=ref(null)
|
const editData=ref(null)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 获取所有分组
|
// 获取所有分组
|
||||||
const fetchGroupings = async () => {
|
const fetchGroupings = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -197,6 +208,10 @@ const fetchGroupings = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCopyCodeSuccess = () => {
|
||||||
|
ElMessage.success('代码已复制到剪贴板');
|
||||||
|
};
|
||||||
|
|
||||||
// 获取所有Markdown文件(确保ID为字符串)
|
// 获取所有Markdown文件(确保ID为字符串)
|
||||||
const fetchMarkdownFiles = async () => {
|
const fetchMarkdownFiles = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -277,8 +292,17 @@ const editNote = (file) => {
|
|||||||
showEditor.value = true;
|
showEditor.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageUpload=()=>{
|
const handleImageUpload=(event,insertImage,files)=>{
|
||||||
console.log(666)
|
console.log(files)
|
||||||
|
|
||||||
|
// 插入图片
|
||||||
|
insertImage({
|
||||||
|
// 图片地址
|
||||||
|
url:
|
||||||
|
'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1269952892,3525182336&fm=26&gp=0.jpg'
|
||||||
|
// 图片描述
|
||||||
|
// desc: '七龙珠',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在编辑页面,按Ctrl+S保存笔记,或者点击保存,对数据进行保存
|
// 在编辑页面,按Ctrl+S保存笔记,或者点击保存,对数据进行保存
|
||||||
|
|||||||
@@ -4,32 +4,46 @@ import router from './router/'
|
|||||||
import ElementPlus from 'element-plus'
|
import ElementPlus from 'element-plus'
|
||||||
import 'element-plus/dist/index.css'
|
import 'element-plus/dist/index.css'
|
||||||
|
|
||||||
import VMdEditor from '@kangc/v-md-editor';
|
// 1. 导入编辑器和预览组件
|
||||||
import '@kangc/v-md-editor/lib/style/base-editor.css';
|
import VMdEditor from '@kangc/v-md-editor'
|
||||||
import githubTheme from '@kangc/v-md-editor/lib/theme/github.js';
|
import VMdPreview from '@kangc/v-md-editor/lib/preview'
|
||||||
import '@kangc/v-md-editor/lib/theme/style/github.css';
|
|
||||||
|
|
||||||
import VMdPreview from '@kangc/v-md-editor/lib/preview';
|
// 2. 导入基础样式
|
||||||
import '@kangc/v-md-editor/lib/style/preview.css';
|
import '@kangc/v-md-editor/lib/style/base-editor.css'
|
||||||
import '@kangc/v-md-editor/lib/theme/style/github.css';
|
import '@kangc/v-md-editor/lib/style/preview.css'
|
||||||
|
|
||||||
|
// 3. 导入主题和样式
|
||||||
|
import githubTheme from '@kangc/v-md-editor/lib/theme/github'
|
||||||
|
import '@kangc/v-md-editor/lib/theme/style/github.css'
|
||||||
|
|
||||||
|
// 4. 导入复制代码插件及其样式
|
||||||
|
import createCopyCodePlugin from '@kangc/v-md-editor/lib/plugins/copy-code/index'
|
||||||
|
import '@kangc/v-md-editor/lib/plugins/copy-code/copy-code.css'
|
||||||
|
|
||||||
|
// 5. 导入高亮库
|
||||||
|
import hljs from 'highlight.js'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
// highlightjs
|
// 6. 配置编辑器
|
||||||
import hljs from 'highlight.js';
|
|
||||||
VMdEditor.use(githubTheme, {
|
VMdEditor.use(githubTheme, {
|
||||||
Hljs: hljs,
|
Hljs: hljs,
|
||||||
});
|
})
|
||||||
|
|
||||||
|
// 7. 配置预览组件
|
||||||
VMdPreview.use(githubTheme, {
|
VMdPreview.use(githubTheme, {
|
||||||
Hljs: hljs,
|
Hljs: hljs,
|
||||||
});
|
})
|
||||||
|
|
||||||
// // 配置Markdown编辑器
|
// 8. 为编辑器和预览分别添加复制插件
|
||||||
app.use(VMdEditor);
|
VMdEditor.use(createCopyCodePlugin())
|
||||||
app.use(VMdPreview);
|
VMdPreview.use(createCopyCodePlugin()) // 注意这里使用同一个插件创建函数
|
||||||
|
|
||||||
// 使用Element Plus和路由
|
// 9. 注册组件
|
||||||
|
app.use(VMdEditor)
|
||||||
|
app.use(VMdPreview)
|
||||||
|
|
||||||
|
// 10. 使用Element Plus和路由
|
||||||
app.use(ElementPlus)
|
app.use(ElementPlus)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
||||||
|
|||||||
BIN
mydatabase.db
BIN
mydatabase.db
Binary file not shown.
Reference in New Issue
Block a user