| | |
| | | <div class="tree-header"> |
| | | <h3>文档管理</h3> |
| | | <el-button icon="Plus" size="small" type="primary" @click="append('')" |
| | | >新增 |
| | | </el-button |
| | | > |
| | | >新增 |
| | | </el-button> |
| | | </div> |
| | | |
| | | <!-- 搜索框 --> |
| | | <div class="search-box"> |
| | | <el-input |
| | | v-model="filterText" |
| | | clearable |
| | | placeholder="输入关键字进行搜索" |
| | | size="small" |
| | | @input="handleFilter" |
| | | v-model="filterText" |
| | | clearable |
| | | placeholder="输入关键字进行搜索" |
| | | size="small" |
| | | @input="handleFilter" |
| | | > |
| | | <template #prefix> |
| | | <el-icon> |
| | | <Search/> |
| | | <Search /> |
| | | </el-icon> |
| | | </template> |
| | | </el-input> |
| | |
| | | |
| | | <div class="tree-container"> |
| | | <el-tree |
| | | ref="treeRef" |
| | | :data="treeData" |
| | | :default-expand-all="false" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | :props="props" |
| | | class="custom-tree" |
| | | node-key="id" |
| | | @node-click="handleNodeClick" |
| | | ref="treeRef" |
| | | :data="treeData" |
| | | :default-expand-all="false" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | :props="props" |
| | | class="custom-tree" |
| | | node-key="id" |
| | | @node-click="handleNodeClick" |
| | | > |
| | | <template #default="{ node, data }"> |
| | | <div class="tree-node-content" @dblclick="headerDbClick(node,data)"> |
| | | <div |
| | | class="tree-node-content" |
| | | @dblclick="headerDbClick(node, data)" |
| | | > |
| | | <div class="node-icon"> |
| | | <el-icon |
| | | v-if="!node.isLeaf" |
| | | :class="{ expanded: node.expanded }" |
| | | v-if="!node.isLeaf" |
| | | :class="{ expanded: node.expanded }" |
| | | > |
| | | <Folder/> |
| | | <Folder /> |
| | | </el-icon> |
| | | <el-icon v-else> |
| | | <Document/> |
| | | <Document /> |
| | | </el-icon> |
| | | </div> |
| | | |
| | | <div class="node-label"> |
| | | <span v-if="!data.isEdit" class="label-text">{{ |
| | | node.label |
| | | }}</span> |
| | | node.label |
| | | }}</span> |
| | | <el-input |
| | | v-else |
| | | :ref="(el) => setInputRef(el, data)" |
| | | v-model="newName" |
| | | autofocus |
| | | class="tree-input" |
| | | placeholder="请输入节点名称" |
| | | size="small" |
| | | @blur="(event) => handleInputBlur(event, data, node)" |
| | | @keyup.enter=" |
| | | (event) => handleInputBlur(event, data, node) |
| | | " |
| | | v-else |
| | | :ref="(el) => setInputRef(el, data)" |
| | | v-model="newName" |
| | | autofocus |
| | | class="tree-input" |
| | | placeholder="请输入节点名称" |
| | | size="small" |
| | | @blur="(event) => handleInputBlur(event, data, node)" |
| | | @keyup.enter="(event) => handleInputBlur(event, data, node)" |
| | | /> |
| | | </div> |
| | | <div v-show="!data.isEdit" class="node-actions"> |
| | | <el-button |
| | | icon="Plus" |
| | | link |
| | | size="small" |
| | | title="新增子节点" |
| | | @click.stop="append(data)" |
| | | icon="Plus" |
| | | link |
| | | size="small" |
| | | title="新增子节点" |
| | | @click.stop="append(data)" |
| | | ></el-button> |
| | | <el-button |
| | | icon="Delete" |
| | | link |
| | | size="small" |
| | | title="删除" |
| | | @click.stop="remove(node, data)" |
| | | icon="Delete" |
| | | link |
| | | size="small" |
| | | title="删除" |
| | | @click.stop="remove(node, data)" |
| | | ></el-button> |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | <div class="right"> |
| | | <el-row :gutter="24"> |
| | | <el-col :offset="20" :span="2" |
| | | > |
| | | <el-button :icon="Delete" type="danger" @click="delHandler">删除</el-button> |
| | | </el-col |
| | | > |
| | | <el-col :span="2" |
| | | > |
| | | <el-button |
| | | :disabled="!tableSwitch" |
| | | :icon="Plus" |
| | | type="primary" |
| | | @click="add" |
| | | >新增 |
| | | </el-button |
| | | <el-col :span="10"> |
| | | <div> |
| | | <el-input |
| | | style="float: left; width: 50%" |
| | | v-model="searchText" |
| | | placeholder="请输入关键字查询文件" |
| | | clearable |
| | | @input="handleSearch" |
| | | @clear="handleSearch" |
| | | > |
| | | <template #prefix> |
| | | <el-icon> |
| | | <Search /> |
| | | </el-icon> |
| | | </template> |
| | | <template #suffix> |
| | | <el-button @click="handleSearch" link style="border: none"> |
| | | <span>搜索</span> |
| | | </el-button> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | </el-col> |
| | | <el-col :offset="8" :span="3"> |
| | | <el-button :icon="Delete" type="danger" @click="delHandler" |
| | | >删除</el-button |
| | | > |
| | | </el-col |
| | | > |
| | | </el-col> |
| | | <el-col :span="3"> |
| | | <el-button |
| | | :disabled="!tableSwitch" |
| | | :icon="Plus" |
| | | type="primary" |
| | | @click="add" |
| | | >新增 |
| | | </el-button> |
| | | </el-col> |
| | | </el-row> |
| | | <ETable |
| | | :border="true" |
| | | :columns="columns" |
| | | :loading="loading" |
| | | :maxHeight="1200" |
| | | :show-selection="true" |
| | | :table-data="tableData" |
| | | @edit="handleEdit" |
| | | @selection-change="handleSelectionChange" |
| | | :border="true" |
| | | :columns="columns" |
| | | :loading="loading" |
| | | :maxHeight="1200" |
| | | :show-selection="true" |
| | | :table-data="tableData" |
| | | @edit="handleEdit" |
| | | @selection-change="handleSelectionChange" |
| | | style="height: calc(65vh);" |
| | | > |
| | | </ETable> |
| | | <Pagination |
| | | :layout="'total, prev, pager, next, jumper'" |
| | | :limit="queryParams.pageSize" |
| | | :page="queryParams.current" |
| | | :show-total="true" |
| | | :total="total" |
| | | @pagination="handlePageChange" |
| | | :layout="'total, prev, pager, next, jumper'" |
| | | :limit="queryParams.pageSize" |
| | | :page="queryParams.current" |
| | | :show-total="true" |
| | | :total="total" |
| | | @pagination="handlePageChange" |
| | | ></Pagination> |
| | | </div> |
| | | <archiveDialog |
| | | ref="archiveDialogs" |
| | | v-model:centerDialogVisible="dialogVisible" |
| | | :row="row" |
| | | @centerDialogVisible="centerDialogVisible" |
| | | @submitForm="submitForm" |
| | | |
| | | ref="archiveDialogs" |
| | | v-model:centerDialogVisible="dialogVisible" |
| | | :row="row" |
| | | @centerDialogVisible="centerDialogVisible" |
| | | @submitForm="submitForm" |
| | | > |
| | | </archiveDialog> |
| | | </el-card> |
| | | </template> |
| | | <script setup> |
| | | import {nextTick, onMounted, reactive, ref} from "vue"; |
| | | import { nextTick, onMounted, reactive, ref } from "vue"; |
| | | import ETable from "@/components/Table/ETable.vue"; |
| | | import {ElButton, ElIcon, ElInput, ElMessage, ElMessageBox} from "element-plus"; |
| | | import { |
| | | ElButton, |
| | | ElIcon, |
| | | ElInput, |
| | | ElMessage, |
| | | ElMessageBox, |
| | | } from "element-plus"; |
| | | import archiveDialog from "./mould/archiveDialog.vue"; |
| | | import Pagination from "@/components/Pagination/index.vue"; |
| | | import {Delete, Document, Folder, Plus, Search,} from "@element-plus/icons-vue"; |
| | | import {addOrEditTree, delArchive, delTree, getArchiveList, getTree,} from "@/api/archiveManagement"; |
| | | import { |
| | | Delete, |
| | | Document, |
| | | Folder, |
| | | Plus, |
| | | Search, |
| | | } from "@element-plus/icons-vue"; |
| | | import { |
| | | addOrEditTree, |
| | | delArchive, |
| | | delTree, |
| | | getArchiveList, |
| | | getTree, |
| | | } from "@/api/archiveManagement"; |
| | | |
| | | // ===== 响应式状态管理 ===== |
| | | const searchText = ref(""); |
| | | const dialogVisible = ref(false); |
| | | const loading = ref(false); |
| | | const tableData = ref([]); |
| | |
| | | |
| | | // ===== 配置常量 ===== |
| | | const columns = [ |
| | | {prop: "name", label: "名称", minWidth: 180}, |
| | | {prop: "type", label: "类型", minWidth: 120}, |
| | | {prop: "status", label: "状态", minWidth: 100}, |
| | | { prop: "name", label: "名称", minWidth: 180 }, |
| | | { prop: "type", label: "类型", minWidth: 120 }, |
| | | { prop: "status", label: "状态", minWidth: 100 }, |
| | | ]; |
| | | |
| | | const queryParams = reactive({ |
| | |
| | | ElMessage.success(msg); |
| | | }; |
| | | |
| | | // 搜索查询函数 |
| | | const handleSearch = () => { |
| | | queryParams.searchAll = searchText.value; |
| | | queryParams.current = 1; // 重置到第一页 |
| | | getArchiveListData(); |
| | | }; |
| | | |
| | | const showConfirm = (message, title = "确认操作") => { |
| | | return ElMessageBox.confirm(message, title, { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }); |
| | | }; |
| | | |
| | |
| | | const getList = async () => { |
| | | try { |
| | | const res = await getTree(); |
| | | treeData.value = res.code === 200 ? (res.data?.records || res.data || []) : []; |
| | | treeData.value = |
| | | res.code === 200 ? res.data?.records || res.data || [] : []; |
| | | } catch (error) { |
| | | handleError(error, "获取树结构数据失败"); |
| | | treeData.value = []; |
| | |
| | | treeId: queryParams.treeId, |
| | | current: queryParams.current, |
| | | size: queryParams.pageSize, |
| | | searchAll: queryParams.searchAll, |
| | | }); |
| | | |
| | | if (res.code !== 200) { |
| | |
| | | total.value = 0; |
| | | return; |
| | | } |
| | | |
| | | |
| | | tableData.value = res.data?.records || res.data || []; |
| | | total.value = res.data?.total || 0; |
| | | |
| | | |
| | | if (res.data?.current) { |
| | | queryParams.current = res.data.current; |
| | | } |
| | |
| | | row.value = isEdit ? { ...rowData } : {}; |
| | | newName.value = ""; |
| | | dialogVisible.value = true; |
| | | |
| | | |
| | | nextTick(() => { |
| | | if (archiveDialogs.value) { |
| | | const method = isEdit ? 'editForm' : 'initForm'; |
| | | if (typeof archiveDialogs.value[method] === 'function') { |
| | | const method = isEdit ? "editForm" : "initForm"; |
| | | if (typeof archiveDialogs.value[method] === "function") { |
| | | archiveDialogs.value[method](isEdit ? rowData : rowClickData.value); |
| | | } |
| | | } |
| | | }); |
| | | } catch (error) { |
| | | handleError(error, `打开${isEdit ? '编辑' : '新增'}界面失败`); |
| | | handleError(error, `打开${isEdit ? "编辑" : "新增"}界面失败`); |
| | | } |
| | | }; |
| | | |
| | |
| | | } |
| | | |
| | | try { |
| | | await showConfirm(`确定要删除选中的 ${selectedRows.length} 条记录吗?`, '删除确认'); |
| | | |
| | | await showConfirm( |
| | | `确定要删除选中的 ${selectedRows.length} 条记录吗?`, |
| | | "删除确认" |
| | | ); |
| | | |
| | | const ids = selectedRows.map((row) => row.id); |
| | | const { code, msg } = await delArchive(ids); |
| | | |
| | | |
| | | if (code !== 200) { |
| | | ElMessage.error("删除失败: " + msg); |
| | | return; |
| | |
| | | showSuccess("删除成功"); |
| | | await getArchiveListData(); |
| | | selectedRows.splice(0, selectedRows.length); |
| | | |
| | | } catch (error) { |
| | | if (error !== 'cancel') { |
| | | if (error !== "cancel") { |
| | | handleError(error, "删除操作失败"); |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | try { |
| | | await showConfirm(`确定要删除节点 "${data.name}" 吗?`, '删除确认'); |
| | | |
| | | await showConfirm(`确定要删除节点 "${data.name}" 吗?`, "删除确认"); |
| | | |
| | | const { code, msg } = await delTree([data.id]); |
| | | |
| | | |
| | | if (code !== 200) { |
| | | ElMessage.error("删除失败: " + msg); |
| | | return; |
| | |
| | | |
| | | showSuccess("删除成功"); |
| | | await getList(); |
| | | |
| | | } catch (error) { |
| | | if (error !== 'cancel') { |
| | | if (error !== "cancel") { |
| | | handleError(error, "删除节点失败"); |
| | | } |
| | | } |
| | |
| | | |
| | | const handleInputBlur = async (event, comeTreeData, node) => { |
| | | try { |
| | | if (!comeTreeData.isEdit || (event.relatedTarget?.tagName === "BUTTON")) return; |
| | | |
| | | if (!comeTreeData.isEdit || event.relatedTarget?.tagName === "BUTTON") |
| | | return; |
| | | |
| | | comeTreeData.isEdit = false; |
| | | const newValue = newName.value.trim(); |
| | | |
| | | |
| | | if (comeTreeData.name === newValue) return; |
| | | |
| | | |
| | | if (!newValue) { |
| | | newName.value = comeTreeData.name || "新节点"; |
| | | ElMessage.warning("节点名称不能为空"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | const parentId = node?.parent?.data?.id || null; |
| | | |
| | | |
| | | const result = await addOrEditTree({ |
| | | name: newValue, |
| | | parentId, |
| | | id: comeTreeData.id || null, |
| | | }); |
| | | |
| | | |
| | | if (result.code === 200) { |
| | | comeTreeData.name = newValue; |
| | | if (!comeTreeData.id && result.data) { |
| | | comeTreeData.id = result.data.id || result.data; |
| | | } |
| | | showSuccess("保存成功"); |
| | | |
| | | |
| | | const currentNodeId = comeTreeData.id; |
| | | await getList(); |
| | | |
| | | |
| | | nextTick(() => { |
| | | if (currentNodeId && treeRef.value) { |
| | | const targetNode = treeRef.value.getNode(currentNodeId); |
| | |
| | | comeTreeData.name = comeTreeData.name || "新节点"; |
| | | ElMessage.error("保存失败: " + (result.msg || "未知错误")); |
| | | } |
| | | |
| | | } catch (error) { |
| | | handleError(error, "保存节点失败"); |
| | | comeTreeData.name = comeTreeData.name || "新节点"; |
| | |
| | | const nodeKey = data.id || data; |
| | | const node = treeRef.value?.getNode(nodeKey); |
| | | const isExpanded = node?.expanded; |
| | | |
| | | |
| | | // 如果有子级且未展开,先展开节点 |
| | | if (hasChildren && !isExpanded && treeRef.value?.store?.nodesMap[nodeKey]) { |
| | | treeRef.value.store.nodesMap[nodeKey].expanded = true; |
| | | } |
| | | |
| | | |
| | | const newNode = createNewNode("新子节点"); |
| | | |
| | | |
| | | if (!data.children) { |
| | | data.children = []; |
| | | } |
| | |
| | | }; |
| | | |
| | | // ===== 生命周期 ===== |
| | | onMounted(getList); |
| | | onMounted(()=>{ |
| | | getList(); |
| | | getArchiveListData(); |
| | | }); |
| | | </script> |
| | | <style lang="scss" scoped> |
| | | .custom-tree-node { |