index.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <template>
  2. <div class="cip-tree">
  3. <div class="cip-tree__filter">
  4. <el-input placeholder="请输入关键字过滤" size="small" v-model="filterText"></el-input>
  5. </div>
  6. <div class="cip-tree__header" v-if="showButton">
  7. <el-button v-if="isTreeAppend" type="text" icon="el-icon-circle-plus-outline" @click="appendTree">新增</el-button>
  8. <el-button type="text" icon="el-icon-refresh-right" @click="reload">刷新</el-button>
  9. <el-button type="text" icon="el-icon-bottom" @click="expandAll">展开</el-button>
  10. <el-button type="text" icon="el-icon-top" @click="narrowAll">折叠</el-button>
  11. </div>
  12. <el-scrollbar class="cip-tree__scrollbar">
  13. <el-tree class="filter-tree"
  14. ref="tree"
  15. :node-key="nodeKey"
  16. :default-expand-all="defaultExpandAll && !accordion"
  17. :current-node-key="currentNodeKey"
  18. :props="defaultProps"
  19. :expandOnClickNode="expandOnClickNode"
  20. :filter-node-method="filterNode"
  21. :data="options"
  22. :accordion="accordion"
  23. :lazy="!!lazyLoad"
  24. :load="lazyLoad"
  25. :show-checkbox="showCheckbox"
  26. :highlight-current="highlightCurrent"
  27. :render-content="renderContent"
  28. @node-click="nodeClick"/>
  29. </el-scrollbar>
  30. </div>
  31. </template>
  32. <script>
  33. import { watch, ref } from 'vue'
  34. import { ElTree, ElInput, ElScrollbar, ElButton } from 'element-plus'
  35. import { useTree } from './use-tree'
  36. import './index.less'
  37. export default {
  38. name: 'CipTree',
  39. components: { ElTree, ElInput, ElScrollbar, ElButton },
  40. props: {
  41. config: {},
  42. options: {},
  43. showButton: {
  44. type: Boolean,
  45. default: true
  46. }
  47. },
  48. emits: ['node-click', 'node-append', 'node-edit', 'node-remove', 'tree-reload', 'expand-all', 'narrow-all', 'handle-remote'],
  49. setup (props, content) {
  50. const { emit } = content
  51. const filterText = ref('')
  52. const tree = ref(null)
  53. const { config, defaultProps, level, buttonLevel, buttonList, ...useTreeOption } = useTree(props, content, tree, filterText)
  54. // 头部按钮
  55. const expandAll = () => {
  56. // eslint-disable-next-line
  57. for (const i in tree.value.store.nodesMap) {
  58. tree.value.store.nodesMap[i].expanded = true
  59. }
  60. }
  61. const narrowAll = () => {
  62. // eslint-disable-next-line
  63. for (const i in tree.value.store.nodesMap) {
  64. tree.value.store.nodesMap[i].expanded = false
  65. }
  66. }
  67. watch(filterText, val => {
  68. if (config.value.remoteFilter) {
  69. emit('handle-remote', val)
  70. } else {
  71. tree.value.filter(val)
  72. }
  73. })
  74. // 节点增删改函数
  75. const nodeAppend = (e, data, node) => {
  76. e.stopPropagation()
  77. emit('node-append', data)
  78. }
  79. const nodeEdit = (e, data, node) => {
  80. e.stopPropagation()
  81. emit('node-edit', data)
  82. }
  83. const nodeRemove = (e, data, node) => {
  84. e.stopPropagation()
  85. emit('node-remove', data)
  86. }
  87. const renderButton = (h, { node, data, store }) => {
  88. const buttonAttr = { size: 'mini', type: 'text' }
  89. const appendButton = h(ElButton,
  90. { ...buttonAttr, onClick: e => nodeAppend(e, data, node) }, { default: () => h('i', { class: 'el-icon-plus' }) })
  91. const editButton = h(ElButton,
  92. { ...buttonAttr, onClick: e => nodeEdit(e, data, node) }, { default: () => h('i', { class: 'el-icon-edit' }) })
  93. const removeButton = h(ElButton,
  94. { ...buttonAttr, onClick: e => nodeRemove(e, data, node) }, { default: () => h('i', { class: 'el-icon-delete' }) })
  95. const buttonDefault = [
  96. { type: 'append', component: appendButton },
  97. { type: 'edit', component: editButton },
  98. { type: 'remove', component: removeButton }]
  99. if (node.level > buttonLevel.value) {
  100. buttonDefault.splice(buttonDefault.findIndex(i => i.type === 'append'), 1)
  101. }
  102. return buttonList.value.map((item) => {
  103. // eslint-disable-next-line
  104. for (const btn of buttonDefault) {
  105. if (item === btn.type) {
  106. return btn.component
  107. }
  108. }
  109. })
  110. }
  111. // 自定义树节点
  112. const renderContent = (h, { node, data, store }) => {
  113. const showButton = renderButton(h, { node, data, store })
  114. // 外部传节点
  115. const renderNode = config.value.renderNode
  116. const operationNode = renderNode ? <span class="view-node">{renderNode?.(data)}</span> : <span class='operation'>{showButton}</span>
  117. const renderItem = config.value.renderItem
  118. const renderItemNode = renderItem ? <span class="custom-tree-node__text">{renderItem({ node, data, store })}</span> : <span class="custom-tree-node__text" title={data[defaultProps.value.label]}>
  119. {data[defaultProps.value.label]}
  120. </span>
  121. return <span class='custom-tree-node'>
  122. {renderItemNode}
  123. {operationNode}
  124. </span>
  125. }
  126. const getCheckedKeys = (leafOnly = false) => {
  127. return tree.value.getCheckedKeys(leafOnly)
  128. }
  129. const setCheckedKeys = (keys, leafOnly = false) => {
  130. return tree.value.setCheckedKeys(keys, leafOnly)
  131. }
  132. const setCurrentKey = (key) => {
  133. tree.value.setCurrentKey(key)
  134. }
  135. return {
  136. tree,
  137. defaultProps,
  138. filterText,
  139. renderContent,
  140. expandAll,
  141. narrowAll,
  142. getCheckedKeys,
  143. setCheckedKeys,
  144. setCurrentKey,
  145. ...useTreeOption
  146. }
  147. }
  148. }
  149. </script>