feat(笔记): 添加笔记移动功能并优化分类管理
- 后端:修改创建分组接口,支持接收 parent_id 参数 -前端:实现笔记移动功能,增加移动按钮和对话框- 优化分类列表渲染逻辑,支持点击分类名称查看笔记 - 调整笔记列表显示样式,增加分类名称
This commit is contained in:
@@ -24,6 +24,9 @@ public class GroupingController {
|
||||
@Operation(summary = "创建分组")
|
||||
@PostMapping
|
||||
public R<Grouping> createGrouping(@RequestBody Grouping grouping) {
|
||||
if (grouping.getParentId() == null) {
|
||||
grouping.setParentId(0L);
|
||||
}
|
||||
Grouping created = groupingService.createGrouping(grouping);
|
||||
return R.success(created);
|
||||
}
|
||||
|
||||
@@ -11,14 +11,8 @@ export const markdownAll = () => axiosApi.get(`/api/markdown`);
|
||||
export const Preview = (id) => axiosApi.get(`/api/markdown/${id}`);
|
||||
|
||||
// 创建分类分组
|
||||
export const addGroupings = (name) => {
|
||||
const formData = new FormData()
|
||||
if (name) formData.append('grouping', name)
|
||||
return axiosApi.post('/api/groupings', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
export const addGroupings = (group) => {
|
||||
return axiosApi.post('/api/groupings', group);
|
||||
}
|
||||
//更新Markdown文件
|
||||
export const updateMarkdown = (data) => {
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</h2>
|
||||
<div class="actions">
|
||||
<el-button v-if="!showEditor" type="primary" @click="selectedFile = null">返回</el-button>
|
||||
<el-button v-if="!showEditor && userStore.isLoggedIn" type="warning" @click="showMoveNoteDialog = true">移动</el-button>
|
||||
<el-button v-if="!showEditor && userStore.isLoggedIn" type="primary" @click="editNote(selectedFile); isCollapsed = true">编辑</el-button>
|
||||
<el-button v-if="!showEditor && userStore.isLoggedIn" type="danger" @click="deleteNote(selectedFile)">删除</el-button>
|
||||
<el-button v-if="showEditor" type="primary" @click="showEditor = !showEditor; previewFile(editData)">返回</el-button>
|
||||
@@ -93,7 +94,10 @@
|
||||
|
||||
<div v-if="groupMarkdownFiles.length > 0" class="file-list">
|
||||
<el-card v-for="file in groupMarkdownFiles" :key="file.id" shadow="hover" class="file-item">
|
||||
<div @click="previewFile(file)" class="file-title">{{ file.title }}</div>
|
||||
<div @click="previewFile(file)" class="file-title">
|
||||
<span>{{ file.title }}</span>
|
||||
<span class="file-group-name">{{ currentGroupName }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<el-empty v-else description="暂无笔记,请创建或上传" />
|
||||
@@ -169,6 +173,22 @@
|
||||
<el-button type="primary" @click="confirmImport">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 移动笔记对话框 -->
|
||||
<el-dialog v-model="showMoveNoteDialog" title="移动笔记到" width="400px">
|
||||
<el-cascader
|
||||
v-model="moveToGroupId"
|
||||
:options="categoryTree"
|
||||
:props="{ checkStrictly: true, emitPath: false }"
|
||||
clearable
|
||||
placeholder="请选择目标分类"
|
||||
style="width: 100%;"
|
||||
></el-cascader>
|
||||
<template #footer>
|
||||
<el-button @click="showMoveNoteDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleMoveNote">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
@@ -213,6 +233,9 @@ const newName = ref('');
|
||||
const showSelectGroupDialog = ref(false);
|
||||
const importGroupId = ref(null);
|
||||
const fileToImport = ref(null);
|
||||
const showMoveNoteDialog = ref(false);
|
||||
const moveToGroupId = ref(null);
|
||||
const currentGroupName = ref('');
|
||||
|
||||
const groupFormRef = ref(null);
|
||||
const newGroupForm = ref({ name: '', parentId: null });
|
||||
@@ -242,9 +265,7 @@ const previewHtml = ref('');
|
||||
const saveStatus = ref('空闲');
|
||||
let debounceTimer = null;
|
||||
|
||||
const categoryCascaderOptions = computed(() => {
|
||||
return [{ id: 0, grouping: '根分类', value: 0, label: '根分类' }, ...categoryTree.value];
|
||||
});
|
||||
const categoryCascaderOptions = computed(() => categoryTree.value);
|
||||
|
||||
const initVditor = () => {
|
||||
vditor.value = new Vditor('vditor', {
|
||||
@@ -323,6 +344,7 @@ const fetchGroupings = async () => {
|
||||
const selectFile = async (data) => {
|
||||
const promise = await markdownList(data.id);
|
||||
groupMarkdownFiles.value = promise.data;
|
||||
currentGroupName.value = data.grouping;
|
||||
selectedFile.value = null;
|
||||
};
|
||||
|
||||
@@ -344,7 +366,7 @@ const createGrouping = async () => {
|
||||
if (valid) {
|
||||
try {
|
||||
const payload = {
|
||||
name: newGroupForm.value.name,
|
||||
grouping: newGroupForm.value.name, // 将 name 映射到 grouping
|
||||
parentId: newGroupForm.value.parentId || 0
|
||||
};
|
||||
await addGroupings(payload);
|
||||
@@ -406,7 +428,7 @@ const resetNoteForm = () => {
|
||||
const renderMenu = (item) => {
|
||||
if (item.children && item.children.length > 0) {
|
||||
return h(ElSubMenu, { index: `group-${item.id}` }, {
|
||||
title: () => h('div', { class: 'menu-item-title' }, [
|
||||
title: () => h('div', { class: 'menu-item-title', onClick: () => selectFile(item) }, [
|
||||
h(ElIcon, () => h(Folder)),
|
||||
h('span', null, item.grouping),
|
||||
h(ElIcon, { class: 'edit-icon', onClick: (e) => { e.stopPropagation(); openRenameDialog(item, 'group'); } }, () => h(Edit))
|
||||
@@ -710,6 +732,31 @@ const handleExportMd = () => {
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
const handleMoveNote = async () => {
|
||||
if (!moveToGroupId.value) {
|
||||
ElMessage.error('请选择目标分类');
|
||||
return;
|
||||
}
|
||||
if (!selectedFile.value) {
|
||||
ElMessage.error('没有选中的笔记');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const updatedFile = {
|
||||
...selectedFile.value,
|
||||
groupingId: moveToGroupId.value,
|
||||
};
|
||||
await updateMarkdown(updatedFile);
|
||||
ElMessage.success('笔记移动成功');
|
||||
showMoveNoteDialog.value = false;
|
||||
selectedFile.value = null; // 返回列表页
|
||||
await chushihua(); // 刷新数据
|
||||
} catch (error) {
|
||||
ElMessage.error('移动失败: ' + error.message);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -932,6 +979,17 @@ const handleExportMd = () => {
|
||||
font-weight: 500;
|
||||
color: var(--text-color);
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.file-group-name {
|
||||
font-size: 12px;
|
||||
color: var(--text-color-secondary);
|
||||
background-color: var(--bg-color-tertiary);
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* --- File Preview --- */
|
||||
|
||||
BIN
mydatabase.db
BIN
mydatabase.db
Binary file not shown.
Reference in New Issue
Block a user