index.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <template>
  2. <div :class="['cip-tree',border?'border':'']" >
  3. <div class="cip-tree__filter" v-if="showSearch">
  4. <el-input :suffix-icon="icon" :placeholder="searchPlaceholder" size="default" v-model="filterText" ></el-input>
  5. </div>
  6. <div class="cip-tree__header" v-if="showButton">
  7. <cip-button-text v-if="isTreeAppend" icon="el-icon-circle-plus-outline" @click="appendTree">新增</cip-button-text>
  8. <cip-button-text icon="el-icon-refresh-right" @click="reload">刷新</cip-button-text>
  9. <cip-button-text icon="el-icon-bottom" @click="expandAll">展开</cip-button-text>
  10. <cip-button-text icon="el-icon-top" @click="narrowAll">折叠</cip-button-text>
  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. @current-change="onCurrentChange"
  29. @node-click="nodeClick"/>
  30. </el-scrollbar>
  31. </div>
  32. </template>
  33. <script>
  34. import { watch, ref } from 'vue'
  35. import { ElTree, ElInput, ElScrollbar } from 'element-plus'
  36. import CipButtonText from '../cip-button-text'
  37. import { useTree } from './use-tree'
  38. import './index.less'
  39. export default {
  40. name: 'CipTree',
  41. components: { ElTree, ElInput, ElScrollbar, CipButtonText },
  42. props: {
  43. config: {},
  44. options: {},
  45. showButton: {
  46. type: Boolean,
  47. default: true
  48. },
  49. showSearch: {
  50. type: Boolean,
  51. default: true
  52. },
  53. searchPlaceholder: {
  54. type: String,
  55. default: '请输入关键字过滤'
  56. },
  57. size: {
  58. type: String,
  59. default: 'normal'
  60. },
  61. icon: {
  62. type: Object
  63. },
  64. border: {
  65. type: Boolean,
  66. default: false
  67. }
  68. },
  69. emits: ['node-click', 'node-append', 'node-edit', 'node-remove', 'tree-reload', 'expand-all', 'narrow-all', 'handle-remote'],
  70. setup (props, content) {
  71. const { emit } = content
  72. const filterText = ref('')
  73. const tree = ref(null)
  74. const { config, defaultProps, level, buttonLevel, buttonList, ...useTreeOption } = useTree(props, content, tree, filterText)
  75. // 头部按钮
  76. const expandAll = () => {
  77. // eslint-disable-next-line
  78. for (const i in tree.value.store.nodesMap) {
  79. tree.value.store.nodesMap[i].expanded = true
  80. }
  81. }
  82. const narrowAll = () => {
  83. // eslint-disable-next-line
  84. for (const i in tree.value.store.nodesMap) {
  85. tree.value.store.nodesMap[i].expanded = false
  86. }
  87. }
  88. watch(filterText, val => {
  89. if (config.value.remoteFilter) {
  90. emit('handle-remote', val)
  91. } else {
  92. tree.value.filter(val)
  93. }
  94. })
  95. // 节点增删改函数
  96. const nodeAppend = (e, data, node) => {
  97. e.stopPropagation()
  98. emit('node-append', data)
  99. }
  100. const nodeEdit = (e, data, node) => {
  101. e.stopPropagation()
  102. emit('node-edit', data)
  103. }
  104. const nodeRemove = (e, data, node) => {
  105. e.stopPropagation()
  106. emit('node-remove', data)
  107. }
  108. const renderButton = (h, { node, data, store }) => {
  109. const buttonAttr = { size: 'small' }
  110. const appendButton = h(CipButtonText,
  111. { ...buttonAttr, onClick: e => nodeAppend(e, data, node) }, { default: () => h('i', { class: 'el-icon-plus' }) })
  112. const editButton = h(CipButtonText,
  113. { ...buttonAttr, onClick: e => nodeEdit(e, data, node) }, { default: () => h('i', { class: 'el-icon-edit' }) })
  114. const removeButton = h(CipButtonText,
  115. { ...buttonAttr, onClick: e => nodeRemove(e, data, node) }, { default: () => h('i', { class: 'el-icon-delete' }) })
  116. const buttonDefault = [
  117. { type: 'append', component: appendButton },
  118. { type: 'edit', component: editButton },
  119. { type: 'remove', component: removeButton }]
  120. if (node.level > buttonLevel.value) {
  121. buttonDefault.splice(buttonDefault.findIndex(i => i.type === 'append'), 1)
  122. }
  123. return buttonList.value.map((item) => {
  124. // eslint-disable-next-line
  125. for (const btn of buttonDefault) {
  126. if (item === btn.type) {
  127. return btn.component
  128. }
  129. }
  130. })
  131. }
  132. // 自定义树节点
  133. const renderContent = (h, { node, data, store }) => {
  134. const showButton = renderButton(h, { node, data, store })
  135. // 外部传节点
  136. const renderNode = config.value.renderNode
  137. const operationNode = renderNode ? <span class="view-node">{renderNode?.(data)}</span> : <span class='operation'>{showButton}</span>
  138. const iconNode = <span><i class={[data.icon, 'icon-node']}></i>{data.label}</span>
  139. const renderItem = config.value.renderItem
  140. const disabled = data.disabled ? 'is_disabled' : ''
  141. const renderItemNode = renderItem
  142. ? <span class={['custom-tree-node__text', disabled]}>{renderItem({ node, data, store })}</span>
  143. : <span class={['custom-tree-node__text', disabled]} title={data[defaultProps.value.label]}>
  144. {data[defaultProps.value.label]}
  145. </span>
  146. const nodeClass = props.size === 'large' ? '--font-text:14px' : '--font-text:12px'
  147. return <span class='custom-tree-node' style={nodeClass}>
  148. {data.icon ? iconNode : [operationNode, renderItemNode]}
  149. </span>
  150. }
  151. const getCheckedKeys = (leafOnly = false) => {
  152. return tree.value.getCheckedKeys(leafOnly)
  153. }
  154. const setCheckedKeys = (keys, leafOnly = false) => {
  155. return tree.value.setCheckedKeys(keys, leafOnly)
  156. }
  157. const setCurrentKey = (key) => {
  158. tree.value.setCurrentKey(key)
  159. }
  160. return {
  161. tree,
  162. defaultProps,
  163. filterText,
  164. renderContent,
  165. expandAll,
  166. narrowAll,
  167. getCheckedKeys,
  168. setCheckedKeys,
  169. setCurrentKey,
  170. ...useTreeOption
  171. }
  172. }
  173. }
  174. </script>