vue3 + ant deigin vue + js 实现树的增删改

<template>
<!--{{ t('yl.addBotom') }}这样的都是国际化的中英文,可替换成任意文字  -->
  <div class="department">
    <div class="departData">
      <div class="treeName public-checktree">
        <!-- :load-data="onLoadData"  -->
        <a-tree ref="tree1" :tree-data="treeData" show-icon :defaultExpandAll="true" :selectedKeys="selectedKeys" blockNode>
          <template v-slot:title="nodeData">
            <a-row>
              <a-col :span="24">
                <div class="contentTree">
                  <div class="treeTitle">
                    <span :style="{ color: formState.id === nodeData.key ? '#F7931E' : '#161616' }">
                      <span style="color: #161616; font-size: 12px !important" v-if="nodeData.spaceType == '0'"> ● </span
                      >{{ nodeData.title }}</span
                    >
                  </div>
                  <div class="treeDrop">
                    <a-dropdown>
                      <a class="ant-dropdown-link" @click.prevent>
                        <span style="color: #161616; font-size: 12px !important"> ●●● </span>
                      </a>
                      <template #overlay>
                        <a-menu @click="onClick">
                          <a-menu-item key="1">
                            <span v-if="nodeData.spaceType != '1'" size="small" @click="addNode(nodeData)"
                              ><PlusOutlined /></span
                            ></a-menu-item
                          >
                          <a-menu-item key="2">
                            <span size="small" @click="editNode(nodeData)"
                              ><EditOutlined />{{ t('yl.editSpace') }}</span
                            ></a-menu-item
                          >
                          <a-menu-item key="3">
                            <span size="small" @click="deleteNode(nodeData)"
                              ><DeleteOutlined />{{ t('yl.deleteSpace') }}</span
                            ></a-menu-item
                          >
                        </a-menu>
                      </template>
                    </a-dropdown>
                  </div>
                </div>
              </a-col>
            </a-row>
          </template>
        </a-tree>
      </div>
      <div class="botHandle">
        <div class="line"></div>
        <div class="botTitle" @click="handleAdd">{{ t('yl.newSpace') }}</div>
      </div>
    </div>
    <div class="departData" v-if="visible">
      <div class="treeName" style="padding: 10px">
        <a-form ref="formRef" :model="formState" layout="vertical" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
          <a-row>
            <a-col :span="24">
              <a-form-item ref="spaceName" :label="t('yl.spaceName')" name="spaceName">
                <div class="publicSearch2">
                  <a-input
                    style="width: 400px"
                    v-model:value="formState.spaceName"
                    :placeholder="t('yl.pleaceSpaceName')"
                    :disabled="formState.disabled"
                    @change="inputChange"
                  />
                </div>
              </a-form-item>
            </a-col>
          </a-row>
          <a-row>
            <a-col :span="24">
              <a-form-item ref="spaceType" :label="t('yl.spaceType')" name="spaceType">
                <div class="public-radio">
                  <a-radio-group v-model:value="formState.spaceType" name="radioGroup">
                    <a-radio value="0">{{ t('yl.regionalSpace') }}</a-radio>
                    <a-radio value="1">{{ t('yl.entranceExit') }}</a-radio>
                  </a-radio-group>
                </div>
              </a-form-item></a-col
            >
          </a-row>
        </a-form>
      </div>
      <div class="botHandle">
        <div class="line"></div>
        <div class="botTitle" @click="handleOk">{{ t('yl.save') }}</div>
      </div>
    </div>
  </div>
  <!-- 
  <PlusOutlined /> + 
<EditOutlined /> 编辑
<DeleteOutlined />
   -->
</template>
<script lang="ts">
import { message } from 'ant-design-vue';
import { defineComponent, reactive, toRefs, onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import {
  DownOutlined,
  PlusOutlined,
  EditOutlined,
  DeleteOutlined,
  EllipsisOutlined,
  SmileOutlined,
  FrownOutlined,
  FrownFilled,
} from '@ant-design/icons-vue';
export default defineComponent({
  name: 'entranceExit',
  components: {
    DownOutlined,
    PlusOutlined,
    EditOutlined,
    DeleteOutlined,
    EllipsisOutlined,
    SmileOutlined,
    FrownOutlined,
    FrownFilled,
  },
  props: {
    dataList: {
      type: Array,
      default: () => [],
    },
  },
  emits: ['submitTree', 'checkMast'],
  setup(props, { emit }) {
    const { t } = useI18n();
    const tree = reactive({
      treeData: props.dataList,
      childrens: [],
    });
    const selectedKeys = ref();
    const visible = ref(false);
    const modalTitle = ref('新增空间');
    const formRef = ref();
    const levelId = ref(0);
    const checkSpvoce = ref('0');
    const checkStatus = ref(false);
    const formState = reactive({
      spaceName: '',
      depDes: '',
      parentId: '',
      id: '',
      disabled: false,
      spaceType: '0',
      spaceVos: [],
    });
    const rules = {
      spaceName: [
        {
          required: true,
          message: t('yl.pleaceSpaceName'),
          trigger: 'blur',
        },
      ],
      spaceType: [
        {
          required: true,
          message: '请选择空间类型',
          trigger: 'blur',
        },
      ],
    };

    // 新增下级按钮
    const addNode = (e: any) => {
      levelId.value = e.level;
      checkSpvoce.value = e.spaceType;
      formState.id = e.key;
      modalTitle.value = '添加下级';
      visible.value = true;
    };
    // 新增同级
    const addNodePeer = (val: any) => {
      formState.id = val.key;
      formState.spaceName = val.title;
      modalTitle.value = '新增同级';
      visible.value = true;
    };
    // 修改按钮
    const editNode = (e: any) => {
      visible.value = true;
      formState.spaceName = e.title;
      formState.spaceType = e.spaceType.toString();
      formState.id = e.key;
      tree.childrens = e.children;
      modalTitle.value = '编辑空间';
      checkStatus.value = true;
    };
    // 删除按钮事件
    const deleteNode = (e: any) => {
      formState.id = e.key;
      modalTitle.value = '删除空间';
      removeNodeInTree(tree.treeData, formState.id);
    };

    // 新增下级节点函数
    const appendNodeInTree = (id: any, tree: any, obj: any) => {
      tree.forEach((ele: any) => {
        if (ele.key === id) {
          ele.children ? ele.children.push(obj) : (ele.children = [obj]);
        } else {
          if (ele.children) {
            appendNodeInTree(id, ele.children, obj);
          }
        }
      });
      return tree;
    };
    // 删除节点函数
    const removeNodeInTree = (treeList: any, id: any) => {
      // 通过id从数组(树结构)中移除元素
      if (!treeList || !treeList.length) {
        return;
      }
      for (let i = 0; i < treeList.length; i++) {
        if (treeList[i].key === id) {
          treeList.splice(i, 1);
          break;
        }
        removeNodeInTree(treeList[i].children, id);
      }
    };
    // 增加同级函数
    const addSameLevel = (id: any, tree: any, obj: any) => {
      let nakeTree = { children: tree };
      let parentNode = findParentNode(id, nakeTree);
      if (!parentNode.children) {
        parentNode.children = [];
      }
      parentNode.children.push(obj);
      return nakeTree.children;
    };
    // 查找父节点
    const findParentNode = (key: any, node: any) => {
      if (!node) {
        return null;
      }
      if (node.children) {
        let children = node.children;
        for (let i = 0; i < children.length; i++) {
          if (children[i].key === key) {
            return node;
          } else {
            const res: any = findParentNode(key, children[i]);
            if (res) {
              return res;
            }
          }
        }
      }
      return null;
    };
    // 修改当前节点数据
    const updateNodeInTree = (treeList: any, id: any, obj: any) => {
      if (!treeList || !treeList.length) {
        return;
      }
      for (let i = 0; i < treeList.length; i++) {
        if (treeList[i].key == id) {
          treeList[i] = obj;
          break;
        }
        updateNodeInTree(treeList[i].children, id, obj);
      }
    };
    // 给树添加层级
    const handleTreeData = (data: any, level: any) => {
      if (data instanceof Array) {
        data.map((item) => {
          item['level'] = level;
          if (item.children instanceof Array) {
            handleTreeData(item.children, level + 1);
          }
        });
      }
      return data;
    };
    //递归修改属性结构
    const mapTree = (list: any) => {
      let TreeList = list.map((item: any) => {
        return {
          spaceName: item.title,
          key: item.key,
          spaceType: item.spaceType ? item.spaceType : '0',
          childrens: item.children && item.children.length ? mapTree(item.children) : [],
          slots: {
            icon: 'smile',
          },
        };
      });
      return TreeList;
    };
    watch(
      () => tree.treeData,
      (list) => {
        mapTree(tree.treeData);
        handleTreeData(list, 0);
        emit('submitTree', mapTree(tree.treeData));
      },
      {
        deep: true,
      }
    );
    const handleAdd = () => {
      visible.value = true;
      modalTitle.value = '新增空间';
    };
    const handleOk = () => {
      formRef.value
        .validate()
        .then(() => {
          let params = {
            title: formState.spaceName,
            key: new Date().getTime(),
            children: [],
            spaceType: formState.spaceType,
          };

          if (modalTitle.value == '添加下级' && checkSpvoce.value === '1') return message.warn('出入口下不可创建');
          if (levelId.value >= 5) return message.warn('最多可添加6级');
          if (modalTitle.value == '添加下级') {
            //新增部门
            appendNodeInTree(formState.id, tree.treeData, params);
          } else if (modalTitle.value == '新增同级') {
            addSameLevel(formState.id, tree.treeData, params);
          } else if (modalTitle.value == '编辑空间') {
            const tree_list = {
              title: formState.spaceName,
              key: new Date().getTime(),
              spaceType: formState.spaceType,
              children: tree.childrens ? tree.childrens : [],
            };

            if (tree.childrens.length > 0 && formState.spaceType == '1') {
              return message.warn('该节点下有子节点,不可修改为出入口类型');
            }

            updateNodeInTree(tree.treeData, formState.id, tree_list);
          } else if (modalTitle.value == '新增空间') {
            let faterData: any = {
              title: formState.spaceName,
              key: new Date().getTime(),
              children: [],
              spaceType: formState.spaceType,
            };
            tree.treeData.push(faterData);
          } else {
            message.warn('请选择节点');
          }
          // mapTree(tree.treeData);
          // handleTreeData(list, 0);
          visible.value = false;
          checkStatus.value = false;
          emit('checkMast', false);

          return tree.treeData;
        })

        .catch((error: any) => {});
    };
    const inputChange = (e) => {
      emit('checkMast', true);
    };
    onMounted(() => {});
    return {
      ...toRefs(tree),
      selectedKeys,
      addNode,
      addNodePeer,
      deleteNode,
      editNode,
      visible,
      handleOk,
      formRef,
      t,
      formState,
      rules,
      modalTitle,
      removeNodeInTree,
      handleAdd,
      levelId,
      checkSpvoce,
      checkStatus,
      inputChange,
    };
  },
});
</script>
<style lang="scss" scoped>
.department {
  display: flex;
  justify-content: space-between;
  .departData {
    width: 49%;
    background: #f6f6f6;
    border-radius: 6px 6px;
    padding: 16px;
    .treeName {
      min-height: 400px;
      overflow: auto;
      .contentTree {
        display: flex;
        justify-content: space-between;
      }
    }
    .botHandle {
      text-align: center;
      .line {
        border: 1px solid #e6e6e6;
      }
      .botTitle {
        font-size: 14px;
        font-weight: 400;
        color: #f7931e;
        padding-top: 16px;
      }
    }
  }
}
:deep(.ant-input) {
  border-radius: 26px !important;
  background: #ffffff !important;
  widows: 400px !important;
}
:deep(.anticon svg) {
  color: #161616;
  font-size: 16px;
}
// 叶子在右
:deep(.ant-tree li span.ant-tree-switcher) {
  float: left !important;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值