Explorar o código

feat(ChapterPanel): 添加章节和卷管理功能,支持增删改操作

- 在章节面板中添加卷和章节的树形结构展示
- 实现添加、编辑和删除节点的对话框功能
- 更新样式以优化用户交互体验
YourName hai 3 semanas
pai
achega
1410e6574c
Modificáronse 1 ficheiros con 157 adicións e 7 borrados
  1. 157 7
      src/components/ChapterPanel.vue

+ 157 - 7
src/components/ChapterPanel.vue

@@ -2,10 +2,55 @@
   <el-tabs v-model="activeTab" class="chapter-tabs">
     <el-tab-pane label="章节列表" name="chapters">
       <div class="tree-container">
-        这还是个树
+        <el-button type="primary" @click="openAddVolumeDialog" style="margin-bottom: 10px;" circle :title="'添加卷'">
+          <el-icon>
+            <Plus />
+          </el-icon>
+        </el-button>
+        <el-tree class="chapter-list" :data="treeData" node-key="id" :props="{ label: 'label', children: 'children' }"
+          default-expand-all>
+          <template #default="{ data }">
+            <span class="custom-tree-node">
+              <span>{{ data.label }}</span>
+              <span class="node-actions">
+                <el-button v-if="data.type === 'volume'" size="small" type="text"
+                  @click.stop="openAddChapterDialog(data)" circle :title="'添加章'">
+                  <el-icon>
+                    <Plus />
+                  </el-icon>
+                </el-button>
+                <el-button size="small" type="text" @click.stop="openEditDialog(data)" circle :title="'编辑'">
+                  <el-icon>
+                    <Edit />
+                  </el-icon>
+                </el-button>
+                <el-button size="small" type="text" @click.stop="deleteNode(data)" class="delete-btn" circle
+                  :title="'删除'">
+                  <el-icon>
+                    <Delete />
+                  </el-icon>
+                </el-button>
+              </span>
+            </span>
+          </template>
+        </el-tree>
       </div>
+      <el-dialog v-model="showAddDialog" :title="addDialogTitle" width="300px">
+        <el-input v-model="newNodeName" :placeholder="addDialogPlaceholder"></el-input>
+        <template #footer>
+          <el-button @click="showAddDialog = false">取消</el-button>
+          <el-button type="primary" @click="confirmAddNode">确定</el-button>
+        </template>
+      </el-dialog>
+      <el-dialog v-model="showEditDialog" title="编辑名称" width="300px">
+        <el-input v-model="editNodeName" placeholder="请输入名称"></el-input>
+        <template #footer>
+          <el-button @click="showEditDialog = false">取消</el-button>
+          <el-button type="primary" @click="confirmEditNode">确定</el-button>
+        </template>
+      </el-dialog>
     </el-tab-pane>
-
+    <!-- 维护书籍信息 -->
     <el-tab-pane label="书籍信息" name="info">
       <div class="book-info">
         书籍信息
@@ -16,10 +61,104 @@
 
 <script setup>
 import { ref } from 'vue';
-import { ElTabs, ElTabPane } from 'element-plus';
+import { ElMessage } from 'element-plus';
+import { Plus, Edit, Delete } from '@element-plus/icons-vue';
 
 const activeTab = ref('chapters');
 
+// 卷-章树数据
+const treeData = ref([
+
+]);
+
+// 添加节点弹窗
+const showAddDialog = ref(false);
+const addDialogTitle = ref('');
+const addDialogPlaceholder = ref('');
+const newNodeName = ref('');
+let addNodeType = '';
+let addParentNode = null;
+
+// 编辑节点弹窗
+const showEditDialog = ref(false);
+const editNodeName = ref('');
+let editNode = null;
+
+// 添加卷
+function openAddVolumeDialog() {
+  showAddDialog.value = true;
+  addDialogTitle.value = '添加卷';
+  addDialogPlaceholder.value = '请输入卷名';
+  newNodeName.value = '';
+  addNodeType = 'volume';
+  addParentNode = null;
+}
+// 添加章
+function openAddChapterDialog(parent) {
+  showAddDialog.value = true;
+  addDialogTitle.value = '添加章';
+  addDialogPlaceholder.value = '请输入章名';
+  newNodeName.value = '';
+  addNodeType = 'chapter';
+  addParentNode = parent;
+}
+// 确认添加
+function confirmAddNode() {
+  const name = newNodeName.value.trim();
+  if (!name) {
+    ElMessage.warning('名称不能为空');
+    return;
+  }
+  if (addNodeType === 'volume') {
+    treeData.value.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: []
+    });
+  }
+  showAddDialog.value = 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;
+  }
+  showEditDialog.value = false;
+}
+// 删除
+function deleteNode(node) {
+  function findAndRemove(nodes, targetId) {
+    for (let i = 0; i < nodes.length; i++) {
+      if (nodes[i].id === targetId) {
+        nodes.splice(i, 1);
+        return true;
+      }
+      if (nodes[i].children) {
+        if (findAndRemove(nodes[i].children, targetId)) return true;
+      }
+    }
+    return false;
+  }
+  findAndRemove(treeData.value, node.id);
+}
 </script>
 
 <style scoped>
@@ -27,10 +166,6 @@ const activeTab = ref('chapters');
   height: 100%;
 }
 
-.search-container {
-  margin-bottom: 10px;
-}
-
 .tree-container {
   height: calc(80vh - 60px);
   overflow: auto;
@@ -39,4 +174,19 @@ const activeTab = ref('chapters');
 .chapter-list {
   width: 100%;
 }
+
+.custom-tree-node {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+}
+
+.node-actions {
+  margin-left: 10px;
+}
+
+.delete-btn {
+  color: #f56c6c;
+}
 </style>