vue3 树的增删改查

diaLogTree

<template>
  <div>
    <el-tree @node-click="handleNodeClick" :data="props.fileTree" :props="defaultProps" node-key="id"
      :current-node-key="currentNodeKey" :default-expanded-keys="currentNodeKeyList" :highlight-current="true"
      :expand-on-click-node="false" :default-expand-all="true">
      <template #default="{ node, data }">
        <span class="custom-tree-node fix justify-content-content align-items-content">
          <span @click.stop="onChange(data)">{{ node.label }}</span>
          <el-dropdown>
            <span class="el-dropdown-link" v-if="isEdit">
              <el-icon class="el-icon--right">
                <Setting />
              </el-icon>
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item @click="onNode('add', data)">添加</el-dropdown-item>
                <el-dropdown-item @click="onNode('edit', data)" :disabled="node.level === 1">编辑</el-dropdown-item>
                <el-dropdown-item @click="onNode('rem', data)" :disabled="node.level === 1">删除</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </span>
      </template>
    </el-tree>
    <el-dialog v-model="dialogVisible" :title="dialogVisibletitle" width="400">
      <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="100px" class="demo-ruleForm"
        :size="formSize" status-icon>
        <el-form-item label="树节点名称" prop="dptName">
          <el-input v-model.trim="ruleForm.dptName" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="submitForm(ruleFormRef)">
            确定
          </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, reactive, nextTick } from 'vue';
import { Setting } from '@element-plus/icons-vue'
import type { FormInstance, FormRules } from 'element-plus'
import { RuleFormFileTree } from './type'
const props = defineProps({
  fileTree: {
    type: Array,
    default: () => []
  },

  currentNodeKey: {
    type: String,
    default: ''
  },
  currentNodeKeyList: {
    type: Array,
    default: () => []
  },
  isEdit: {
    type: Boolean,
    default: true
  },
  treeName: {
    type: String,
    default: 'label'
  }
})
const emits = defineEmits(['changeTree', 'deleteTree', 'addTree', 'editTree', 'changeTreeNode'])


/**
 * @description: 弹窗数据
 * @return {*}
 */
const dialogVisible = ref(false)
const ruleFormRef = ref()
const diaTitle = ref('add')

const dialogVisibletitle = computed(() => {
  return diaTitle.value === 'add' ? '添加' : diaTitle.value === 'edit' ? '编辑' : ''
})

const formSize = ref('default')
const ruleForm = reactive<RuleFormFileTree>({
  dptName: ''
})

const rules = reactive<FormRules<RuleFormFileTree>>({
  dptName: [
    { required: true, message: '不能为空', trigger: 'blur' },
  ],
})


/**
 * @description: 组织树格式
 * @return {*}
 */

const defaultProps = {
  children: 'children',
  label: props.treeName,
}

/**
 * @description: 接口穿参数据
 * @return {*}
 */
const dataParams: any = reactive({
  id: null,
  level: null,
  dptName: null,
  pid: null
})



const onChange = (v: any) => {
  emits('changeTree', v.id)
}

const handleNodeClick = (v: any) => {
  emits('changeTreeNode', v.id)
}


/**
 * @description: 点击弹窗并获取对应的数据
 * @param {*} ty
 * @param {*} data
 * @return {*}
 */
const onNode = async (ty: string, data: any) => {
  dataParams.pid = data.id,
    dataParams.id = data.id,
    dataParams.level = data.level,
    ruleForm.dptName = ''
  diaTitle.value = ty
  if (ty === 'edit') {
    ruleForm.dptName = data[props.treeName]
    dialogVisible.value = true
  } else if (ty === 'add') {
    dialogVisible.value = true
  }

  if (ty === 'rem') {
    emits('deleteTree', data.id)
  }
}


/**
 * @description: 点击保存
 * @param {*} formEl
 * @return {*}
 */
const submitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return
  await formEl.validate(async (valid) => {
    if (valid) {
      if (diaTitle.value === 'add') {
        let params = {
          ...dataParams
        }
        params.level = params.level++
        params.dptName = ruleForm.dptName
        emits('addTree', params)
        dialogVisible.value = false
      } else {
        let params = {
          ...dataParams
        }
        params.dptName = ruleForm.dptName
        delete params.pid
        emits('editTree', params)
        dialogVisible.value = false
      }

    }
  })
}


</script>
<style lang="scss" scoped>
::v-deep .el-tree-node.is-current>.el-tree-node__content {
  color: $theme_colors;
}
</style>

baseTree

<template>
  <el-tree :data="dataSource" node-key="id" default-expand-all :expand-on-click-node="false">
    <template #default="{ node, data }">

      <span class="custom-tree-node">

        <el-input v-if="data.id === dataDepartmentTree.flagId && dataDepartmentTree.isView" v-model.trim="data.label"
          style="width: 120px;margin-left: 8px;"></el-input>
        <span v-else>{{ node.label }}</span>
        <span>
          <a @click="edit(data, node)" v-show="!data.editAble && node.level !== 1">编辑</a>
          <a @click="handleSuccess(data)" style="margin-left: 8px" v-show="data.editAble && node.level !== 1">完成</a>
          <a @click="append(data, node)" style="margin-left: 8px"> 新增 </a>
          <a style="margin-left: 8px" @click="remove(node, data)" v-if="node.level !== 1"> 删除 </a>
        </span>
      </span>
    </template>
  </el-tree>
</template>

<script lang="ts" setup>
// import { createTree, deleteTree, updateTree } from '@/api/systeManagement/userManagement'
import { reactive, ref, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { PropsTree, Tree, DataDepartmentTree } from './type'
import type Node from 'element-plus/es/components/tree/src/model/node'

/**
 * 部门树的data响应式数据
 */

const dataDepartmentTree = reactive<DataDepartmentTree>({
  flagId: 0,
  isView: false,
})

const dataSource = ref<Tree[]>([])

/**
* 父组件逻辑
*/
//通过emit向父组件传参
const emit = defineEmits([
  'ok',
  'close',
  'create',
  'remove',
  "update"
])
//父组件传参
const props: PropsTree = defineProps({
  dataTree: {
    type: Array,
    default: () => []
  }
})

watch(() => props.dataTree, (newData, oldData) => {
  console.log('old', oldData);
  dataSource.value = [...newData]
}, { deep: true, immediate: true })




/**
 * @description: 新增部门
 * @param {*} data
 * @return {*}
 */
const append = async (data: Tree, node: any) => {
  console.log('node', node, data);
  let date = new Date().getTime()

  let dataParams = {
    id: null,
    level: data.level++,
    dptName: `新增${String(date).slice(7, String(date).length)}`,
    pid: data.id
  }
  emit('create', dataParams)
}



/**
 * @description: 删除部门
 * @param {*} node
 * @param {*} data
 * @return {*}
 */
const remove = (node: any, data: Tree) => {
  console.log("node", node);
  emit('remove', data.id)
}


/**
 * @description: 编辑部门名称
 * @param {*} data
 * @param {*} node
 * @return {*}
 */
const edit = (data: Tree, node: Node) => {

  dataDepartmentTree.flagId = data.id
  dataDepartmentTree.isView = true
  const parent = node.parent
  const children: Tree[] = parent.data.children || parent.data
  recursionData(dataSource.value, data.id, true)
}

const recursionData = (arr: any, id: any, flagView: boolean) => {
  return arr.map((el: { id: any; editAble: boolean; children: any; }) => {
    if (el.id && el.id === id) {
      el.editAble = flagView
    } else {
      recursionData(el.children, id, flagView)
    }
  });
}

/**
 * @description: 点击完成
 * @param {*} node
 * @param {*} data
 * @return {*}
 */
const handleSuccess = (data: Tree) => {
  if (!data.label) {
    ElMessage.error({
      message: '部门名称不能为空',
      type: 'error',
    })
  } else {

    if (data.label.length < 11) {
      dataDepartmentTree.isView = false
      dataDepartmentTree.isView = false
      recursionData(dataSource.value, data.id, false)
      dataSource.value = [...dataSource.value]

      let dataParams = {
        id: data.id,
        dptName: data.label,
        level: data.level,
      }
      emit("update", dataParams)
    } else {
      ElMessage.error({
        message: '部门名称不能超出10个字符',
        type: 'error',
      })
    }
  }
}




</script>

<style lang="less" scoped>
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}

.el-tree {
  --el-tree-node-content-height: 35px;
}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值