vue3+ts项目antd-vue中实现树节点添加,编辑,删除等操作
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
vue3+ts项目antd-vue中实现树节点添加,编辑,删除等操作
对vue3,ts和antd-vue的使用
功能详解:
通过弹框来维护树结构,可以点击根节点、子节点、同级节点、删除 按钮来维护树结构
点击根节点按钮:可以在外层根节点添加一个节点
点击子节点按钮:可以在当前节点下添加一个子节点
点击同级结点按钮:可以在当前节点按钮同级添加一个同级节点
点击删除按钮:可以删除目前选中的节点
点击具体节点右侧表单部分会回显节点名称、组织机构、排序等信息
点击保存可将当前修改节点的信息同步到左侧树上
具体页面如下:
代码实现部分
import { isArray } from 'util';
<script setup lang="ts">
import { ref, reactive, watch, Ref, onMounted, createVNode } from "vue";
import CPage from 'remote_app1/CPage';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
dayjs.locale('zh-cn');
import { typeRequestApi, postRequestApi, getRequestApi } from 'remote_app1/request.ts'
import { useRoute } from 'vue-router'
import rest from "./index.json"
import { message, TreeSelectProps, Modal } from 'ant-design-vue'
import { ExclamationCircleOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { findKeyName, randomUUID } from "remote_app1/common.ts"
const onSelectedNodes = ref<string[]>([]);
const newNodes = ref<string[]>([]);
const selectedKeys = ref<(string | number)[]>([]);
const route = useRoute()
/** 定义数据源 */
const c_rest = reactive(rest);
let organiseData = ref<TreeSelectProps['treeData']>([]);
/**
* 下发页面数据配置
*/
interface winFace {
[propName: string]: any
}
const win: winFace = window;
const p_config = reactive<any>({
requestApi: win['requestApi'],
p_source: reactive(rest),
theme: win['theme'],
route: route
})
let rowData: any = {}
// 新增按钮
let addBtn = findKeyName("c_text", "维护树", c_rest);
const model3 = findKeyName("c_id", "model_id3", c_rest);
const form3 = model3.c_children;
addBtn.c_callback = function (row: any) {
rowData = row
getTreeList()
setTimeout(() => {
modelKey.value = true;
}, 500);
}
// 新增弹框显示/隐藏
let modelKey = ref(false);
const addUserModel: any = reactive({
title: "维护树",
width: "800px",
loading: false,
okText: "保存",
cancelText: "取消",
handleOk: function () {
const newNode: any = {}
newNode.nodeName = nodeMsg.value.nodeName
newNode.nodeId = nodeMsg.value.nodeId
newNode.parentId = newNodes.value.parentId
newNode.treeTypeId = rowData.treeTypeId
newNode.organiseId = nodeMsg.value.organiseId
newNode.nodeOrderNo = nodeMsg.value.nodeOrderNo
newNode['nodeId'] = nodeMsg.value.nodeId
newNode['nodeName'] = nodeMsg.value.nodeName
newNode['children'] = [];
// addUserModel.loading = true;
saveNodeInfo(newNode, "edit")
}
})
let treeData = ref<any>([]);
// 获取组织树列表
function getTreeList() {
let organiseId = rowData.organiseId ? rowData.organiseId : ""
typeRequestApi(
p_config.requestApi,
"/XXXX/selectAll",
{ treeTypeId: rowData.treeTypeId, organiseId: organiseId },
"get"
).then((res: any) => {
treeData.value = res.data.result;
});
};
const searchValue = ref("");
const expandedKeys: any = ref([]);
const checkedKeys = ref([]);
// 查询搜索信息
function searchTreeData(val: string | number, arr: any, parentKey: string): any {
let res = new Set();
for (let i = 0; i < arr.length; i++) {
if (arr[i].title.indexOf(val) > -1) {
res.add(arr[i].key);
if (parentKey) res.add(parentKey);
}
if (arr[i].children) {
let newRes = searchTreeData(val, arr[i].children, arr[i].key);
res = new Set([...res, ...newRes]);
if (newRes.length > 0 && parentKey) {
res.add(parentKey);
}
}
}
return [...res];
}
// 显示子节点信息
let nodeMsg: any = ref({ nodeName: "", nodeId: "", nodeOrderNo: "", organiseId: "" });
// 点击查看详细信息
function showDetail(nodeId: string, nodeName: string, organiseId: string, nodeOrderNo: string) {
nodeMsg.value = reactive({ nodeId: nodeId, nodeName: nodeName, organiseId: organiseId, nodeOrderNo: nodeOrderNo })
}
// 删除树节点
function deleteNode(nodeId: string) {
Modal.confirm({
title: '删除提示',
icon: createVNode(ExclamationCircleOutlined),
content: '确实要删除该节点吗?',
okText: '确认',
cancelText: '取消',
onOk() {
return new Promise<void>((resolve, reject) => {
typeRequestApi(
p_config.requestApi,
"/XXXX/delete",
{ nodeId: nodeId },
"get"
).then((res: any) => {
if (res.status === 200) {
getTreeList()
resolve()
message.success('删除成功!');
}
});
}).catch(() => console.log('Oops errors!'));
},
onCancel() {
//todo
},
});
}
const open = ref<boolean>(false);
function handleClickAddRootNode() {
const newNode: any = {}
newNode.nodeName = '节点'
newNode.nodeId = '_' + randomUUID()
newNode.parentId = 0
newNode.nodeOrderNo = 1
newNode.treeTypeId = rowData.treeTypeId
newNode.organiseId = null
newNode['nodeId'] = newNode.nodeId;
newNode['nodeName'] = newNode.nodeName;
newNode['children'] = [];
//添加到树
treeData.value.push(newNode);
saveNodeInfo(newNode, "add")
}
function handleClickAddChildNode() {
if (!selectedKeys.value.length) {
message.warning("请先选择需要添加子节点的节点");
return
}
const newNode: any = {}
newNode.nodeName = '子节点'
newNode.nodeId = '_' + randomUUID()
newNode.parentId = nodeMsg.value.nodeId
newNode.treeTypeId = rowData.treeTypeId
newNode.organiseId = null
newNode.nodeOrderNo = newNodes.value.children.length + 1
newNode['nodeId'] = newNode.nodeId;
newNode['nodeName'] = newNode.nodeName;
newNode['children'] = [];
//添加到当前节点下面
onSelectedNodes.value[0].children.push(newNode)
saveNodeInfo(newNode, "add")
}
function handleClickAddBrotherNode() {
if (!selectedKeys.value.length) {
message.warning("请先选择需要添加同级节点的节点");
return
}
const newNode: any = {}
newNode.nodeName = '同级节点'
newNode.nodeId = '_' + randomUUID()
newNode.parentId = newNodes.value.parentId
newNode.treeTypeId = rowData.treeTypeId
newNode.organiseId = null
newNode.nodeOrderNo = newNodes.value.children.length + 1
newNode['nodeId'] = newNode.nodeId;
newNode['nodeName'] = newNode.nodeName;
newNode['children'] = [];
const nodes = newNodes.value.parentId === "0" ? null : newNodes.value;
newNodes.value.parentId === "0" ? treeData.value.push(newNode) : nodes.children.push(newNode)
saveNodeInfo(newNode, "add")
}
function handleClickDelNode() {
if (!selectedKeys.value.length) {
message.warning("请先选择需要删除的节点");
return
}
deleteNode(nodeMsg.value.nodeId)
}
/**保存新增节点*/
function saveNodeInfo(newNode: any, val: any) {
postRequestApi(p_config.requestApi, "/XXXXX/saveOrUpdate", newNode).then((res: any) => {
const { data } = res;
if (data.success) {
getTreeList()
if (val === "add") {
message.success("新增节点成功 !")
} else {
message.success("编辑节点成功 !")
}
}
})
}
/**机构类型*/
function organiseTree() {
getRequestApi(p_config.requestApi, "/XXXXX/list?pageNumber=1&pageSize=10&keyWord=&pageNum=1&=").then((res: any) => {
const { data } = res;
if (data.success) {
organiseData = reactive(res.data.result)
// message.success("新增节点成功 !")
}
})
}
// const showModal = () => {
// open.value = true;
// };
const onSelect = (selectedKeys: any, { selected, selectedNodes, node }: any) => {
onSelectedNodes.value = selectedNodes;
if (onSelectedNodes.value.length) {
newNodes.value = node;
}
}
onMounted(() => {
organiseTree();
})
</script>
<template>
<CPage :c_rest="c_rest" :p_config="p_config" />
<a-modal v-bind="addUserModel" v-model:open="modelKey" :confirm-loading="addUserModel.loading"
@ok="addUserModel.handleOk">
<div class="treeWrap">
<div class="search-box">
<a-space style="margin-bottom: 10px">
<a-button type="primary" size="small" @click="handleClickAddRootNode">根节点
</a-button>
<a-button type="primary" size="small" @click="handleClickAddChildNode">
子节点
</a-button>
<a-button type="primary" size="small" @click="handleClickAddBrotherNode">
同级节点
</a-button>
<a-button type="primary" size="small" @click="handleClickDelNode" danger>
删除
</a-button>
</a-space>
<a-input-search v-model:value="searchValue" style="margin-bottom: 8px" placeholder="查询节点名称" />
</div>
</div>
<div class="tree-box" v-if="treeData.length">
<a-tree :tree-data="treeData" v-model:expanded-keys="expandedKeys" v-model:selectedKeys="selectedKeys"
@select="onSelect" autoExpandParent="true" show-line="true">
<template #title="{ nodeName, nodeId, body, organiseId, nodeOrderNo }">
<span v-if="nodeName.indexOf(searchValue) > -1"
@click="showDetail(nodeId, nodeName, organiseId, nodeOrderNo)">
{{ nodeName.substr(0, nodeName.indexOf(searchValue)) }}
<span style="color: #f50" @click="showDetail(nodeId, nodeName, organiseId, nodeOrderNo)">{{ searchValue
}}</span>
{{ nodeName.substr(nodeName.indexOf(searchValue) + searchValue.length) }}
</span>
</template>
</a-tree>
<div class="treeWrap">
<a-form :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<a-form-item label="节点名称" name="节点名称">
<a-input v-model:value="nodeMsg.nodeName" />
</a-form-item>
<a-form-item label="组织机构" name="组织机构">
<a-tree-select v-model:value="nodeMsg.organiseId" show-search style="width: 100%" :field-names="{
children: 'children',
label: 'organiseName',
value: 'organiseId',
}" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" placeholder="组织机构" allow-clear tree-default-expand-all
:tree-data="organiseData" tree-node-filter-prop="value">
<template #title="{ value: val, organiseName }">
<span>{{ organiseName }}</span>
</template>
</a-tree-select>
</a-form-item>
<a-form-item label="排序" name="排序">
<a-input v-model:value="nodeMsg.nodeOrderNo" />
</a-form-item>
</a-form>
</div>
</div>
</a-modal>
</template>
<style lang="less">
.ant-form-item {
margin-bottom: 0 !important;
}
.search-box {
display: flex;
flex-direction: column;
.ant-btn-primary {
// margin-right: 20px;
}
.btn-list {
display: flex;
margin-bottom: 20px;
}
}
.tree-box {
display: flex;
width: 100%;
.ant-tree {
width: 50% !important;
.ant-tree-treenode {
width: 100%;
.ant-tree-title {
display: flex;
}
.ant-tree-block-node .ant-tree-list-holder-inner .ant-tree-node-content-wrapper {
flex: auto;
}
}
}
.ant-form-item {
margin-bottom: 10px !important;
}
.treeWrap {
width: 50%;
}
}
</style>```
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献1条内容
所有评论(0)