|
@@ -7,8 +7,16 @@
|
|
|
<Plus />
|
|
|
</el-icon>
|
|
|
</el-button>
|
|
|
- <el-tree class="chapter-list" :data="treeData" node-key="id" :props="{ label: 'label', children: 'children' }"
|
|
|
- default-expand-all>
|
|
|
+ <el-tree
|
|
|
+ class="chapter-list"
|
|
|
+ :data="treeData"
|
|
|
+ node-key="id"
|
|
|
+ :props="{ label: 'label', children: 'children' }"
|
|
|
+ default-expand-all
|
|
|
+ @node-click="handleNodeClick"
|
|
|
+ :highlight-current="true"
|
|
|
+ :current-node-key="selectedChapterId"
|
|
|
+ >
|
|
|
<template #default="{ data }">
|
|
|
<span class="custom-tree-node">
|
|
|
<span>{{ data.label }}</span>
|
|
@@ -50,7 +58,6 @@
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
</el-tab-pane>
|
|
|
- <!-- 维护书籍信息 -->
|
|
|
<el-tab-pane label="书籍信息" name="info">
|
|
|
<div class="book-info">
|
|
|
书籍信息
|
|
@@ -60,16 +67,41 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
+/* eslint-disable no-undef */
|
|
|
import { ref } from 'vue';
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
import { Plus, Edit, Delete } from '@element-plus/icons-vue';
|
|
|
|
|
|
-const activeTab = ref('chapters');
|
|
|
+// Props
|
|
|
+// eslint-disable-next-line no-undef
|
|
|
+const props = defineProps({
|
|
|
+ treeData: {
|
|
|
+ type: Array,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ selectedChapterId: {
|
|
|
+ type: Number,
|
|
|
+ default: null
|
|
|
+ }
|
|
|
+});
|
|
|
|
|
|
-// 卷-章树数据
|
|
|
-const treeData = ref([
|
|
|
+// Emits
|
|
|
+// eslint-disable-next-line no-undef
|
|
|
+const emit = defineEmits(['select-chapter', 'update-tree']);
|
|
|
|
|
|
-]);
|
|
|
+const activeTab = ref('chapters');
|
|
|
+
|
|
|
+// 处理节点点击
|
|
|
+function handleNodeClick(data) {
|
|
|
+ // 只有点击章节点时才触发选中事件
|
|
|
+ if (data.type === 'chapter') {
|
|
|
+ emit('select-chapter', data.id);
|
|
|
+ } else if (data.type === 'volume') {
|
|
|
+ // 点击卷节点时清空选中的章节
|
|
|
+ emit('select-chapter', null);
|
|
|
+ }
|
|
|
+ // 卷节点不触发选中事件,保持右侧内容区为空
|
|
|
+}
|
|
|
|
|
|
// 添加节点弹窗
|
|
|
const showAddDialog = ref(false);
|
|
@@ -93,6 +125,7 @@ function openAddVolumeDialog() {
|
|
|
addNodeType = 'volume';
|
|
|
addParentNode = null;
|
|
|
}
|
|
|
+
|
|
|
// 添加章
|
|
|
function openAddChapterDialog(parent) {
|
|
|
showAddDialog.value = true;
|
|
@@ -102,6 +135,7 @@ function openAddChapterDialog(parent) {
|
|
|
addNodeType = 'chapter';
|
|
|
addParentNode = parent;
|
|
|
}
|
|
|
+
|
|
|
// 确认添加
|
|
|
function confirmAddNode() {
|
|
|
const name = newNodeName.value.trim();
|
|
@@ -109,42 +143,88 @@ function confirmAddNode() {
|
|
|
ElMessage.warning('名称不能为空');
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ // 深拷贝当前树数据
|
|
|
+ const newTreeData = JSON.parse(JSON.stringify(props.treeData));
|
|
|
+
|
|
|
if (addNodeType === 'volume') {
|
|
|
- treeData.value.push({
|
|
|
+ newTreeData.push({
|
|
|
id: Date.now(),
|
|
|
label: name,
|
|
|
type: 'volume',
|
|
|
children: []
|
|
|
});
|
|
|
} else if (addNodeType === 'chapter' && addParentNode) {
|
|
|
- addParentNode.children.push({
|
|
|
- id: Date.now(),
|
|
|
- label: name,
|
|
|
- type: 'chapter',
|
|
|
- children: []
|
|
|
- });
|
|
|
+ // 找到父节点并添加子节点
|
|
|
+ addChapterToParent(newTreeData, addParentNode.id);
|
|
|
}
|
|
|
+
|
|
|
+ emit('update-tree', newTreeData);
|
|
|
showAddDialog.value = false;
|
|
|
}
|
|
|
+
|
|
|
+// 递归添加章到父节点
|
|
|
+function addChapterToParent(nodes, parentId) {
|
|
|
+ for (const node of nodes) {
|
|
|
+ if (node.id === parentId) {
|
|
|
+ if (!node.children) node.children = [];
|
|
|
+ node.children.push({
|
|
|
+ id: Date.now(),
|
|
|
+ label: newNodeName.value.trim(),
|
|
|
+ type: 'chapter',
|
|
|
+ content: '<p>请输入章节内容...</p>',
|
|
|
+ children: []
|
|
|
+ });
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (node.children && addChapterToParent(node.children, parentId)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
// 编辑
|
|
|
function openEditDialog(node) {
|
|
|
showEditDialog.value = true;
|
|
|
editNodeName.value = node.label;
|
|
|
editNode = node;
|
|
|
}
|
|
|
+
|
|
|
function confirmEditNode() {
|
|
|
const name = editNodeName.value.trim();
|
|
|
if (!name) {
|
|
|
ElMessage.warning('名称不能为空');
|
|
|
return;
|
|
|
}
|
|
|
- if (editNode) {
|
|
|
- editNode.label = name;
|
|
|
+
|
|
|
+ // 深拷贝当前树数据
|
|
|
+ const newTreeData = JSON.parse(JSON.stringify(props.treeData));
|
|
|
+
|
|
|
+ // 递归查找并更新节点
|
|
|
+ function updateNode(nodes, targetId, newLabel) {
|
|
|
+ for (const node of nodes) {
|
|
|
+ if (node.id === targetId) {
|
|
|
+ node.label = newLabel;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (node.children && updateNode(node.children, targetId, newLabel)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
+
|
|
|
+ updateNode(newTreeData, editNode.id, name);
|
|
|
+ emit('update-tree', newTreeData);
|
|
|
showEditDialog.value = false;
|
|
|
}
|
|
|
+
|
|
|
// 删除
|
|
|
function deleteNode(node) {
|
|
|
+ // 深拷贝当前树数据
|
|
|
+ const newTreeData = JSON.parse(JSON.stringify(props.treeData));
|
|
|
+
|
|
|
function findAndRemove(nodes, targetId) {
|
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
|
if (nodes[i].id === targetId) {
|
|
@@ -157,7 +237,9 @@ function deleteNode(node) {
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
- findAndRemove(treeData.value, node.id);
|
|
|
+
|
|
|
+ findAndRemove(newTreeData, node.id);
|
|
|
+ emit('update-tree', newTreeData);
|
|
|
}
|
|
|
</script>
|
|
|
|