@dt-frames/ui 1.0.9 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/es/components/curd/src/components/dialog.d.ts +8 -3
  2. package/es/components/forms/src/components/formIcon.d.ts +1 -1
  3. package/es/components/forms/src/components/formInputUseDialog.d.ts +903 -0
  4. package/es/components/forms/src/types/form.type.d.ts +6 -4
  5. package/es/components/index.d.ts +3 -2
  6. package/es/components/modal/src/types/modal.type.d.ts +5 -2
  7. package/es/components/source/src/hooks/useFetch.d.ts +2 -2
  8. package/es/components/source/src/hooks/useSource.d.ts +8 -8
  9. package/es/components/source/src/types/table.type.d.ts +1 -1
  10. package/es/components/table/src/components/TableActions.d.ts +2 -2
  11. package/es/components/table/src/components/TableHeader.d.ts +2 -2
  12. package/es/components/table/src/components/editable/CellComponent.d.ts +14 -0
  13. package/es/components/table/src/components/editable/EditTableCell.d.ts +88 -0
  14. package/es/components/table/src/components/editable/componentMap.d.ts +4 -0
  15. package/es/components/table/src/components/editable/index.d.ts +9 -0
  16. package/es/components/table/src/components/setting/Download.d.ts +2 -2
  17. package/es/components/table/src/components/setting/Size.d.ts +2 -2
  18. package/es/components/table/src/hooks/useCustomRow.d.ts +19 -0
  19. package/es/components/table/src/index.d.ts +29 -6
  20. package/es/components/table/src/props.d.ts +5 -1
  21. package/es/components/table/src/types/table.type.d.ts +16 -0
  22. package/es/components/tree/index.d.ts +2 -0
  23. package/es/components/tree/src/hooks/useTree.d.ts +14 -0
  24. package/es/components/tree/src/props.d.ts +101 -0
  25. package/es/components/tree/src/type/tree.d.ts +85 -0
  26. package/es/components/tree/src/utils/tree.d.ts +5 -0
  27. package/es/components/upload/index.d.ts +3 -0
  28. package/es/components/upload/src/helper.d.ts +4 -0
  29. package/es/components/upload/src/index.d.ts +2807 -0
  30. package/es/components/upload/src/props.d.ts +40 -0
  31. package/es/components/upload/src/upload.d.ts +1653 -0
  32. package/es/index.js +2113 -270
  33. package/es/style/components/forms/index.less +23 -0
  34. package/es/style/components/table/index.less +8 -2
  35. package/es/style/components/tree/index.less +41 -0
  36. package/es/style/components/upload/index.less +43 -0
  37. package/es/style/theme/header/index.less +1 -1
  38. package/es/theme/sider/components/basic-menu/basic-menu.d.ts +3 -3
  39. package/es/theme/tabs/components/TabContent.d.ts +2 -2
  40. package/package.json +2 -1
  41. package/src/components/curd/src/components/dialog.vue +7 -4
  42. package/src/components/curd/src/hooks/useCurd.tsx +1 -1
  43. package/src/components/forms/index.less +23 -0
  44. package/src/components/forms/src/componentMap.ts +2 -0
  45. package/src/components/forms/src/components/formInputUseDialog.vue +43 -0
  46. package/src/components/forms/src/components/formItem.vue +25 -12
  47. package/src/components/forms/src/hooks/useFormEvents.ts +4 -3
  48. package/src/components/forms/src/hooks/useFormValues.ts +1 -1
  49. package/src/components/forms/src/types/form.type.ts +9 -3
  50. package/src/components/index.ts +9 -3
  51. package/src/components/modal/src/hooks/useModal.ts +12 -4
  52. package/src/components/modal/src/index.vue +2 -2
  53. package/src/components/modal/src/types/modal.type.ts +5 -2
  54. package/src/components/source/src/hooks/useFetch.ts +10 -6
  55. package/src/components/source/src/hooks/useSource.ts +33 -12
  56. package/src/components/source/src/types/table.type.ts +1 -1
  57. package/src/components/table/index.less +8 -2
  58. package/src/components/table/src/components/TableHeader.vue +2 -2
  59. package/src/components/table/src/components/editable/CellComponent.ts +57 -0
  60. package/src/components/table/src/components/editable/EditTableCell.vue +181 -0
  61. package/src/components/table/src/components/editable/componentMap.ts +18 -0
  62. package/src/components/table/src/components/editable/index.ts +58 -0
  63. package/src/components/table/src/hooks/useColumns.ts +15 -8
  64. package/src/components/table/src/hooks/useCustomRow.ts +86 -0
  65. package/src/components/table/src/hooks/useDataSource.ts +0 -13
  66. package/src/components/table/src/hooks/useTableHeader.ts +2 -2
  67. package/src/components/table/src/index.vue +20 -3
  68. package/src/components/table/src/props.ts +4 -1
  69. package/src/components/table/src/types/table.type.ts +28 -1
  70. package/src/components/tree/index.less +41 -0
  71. package/src/components/tree/index.ts +5 -0
  72. package/src/components/tree/src/components/TreeHeader.vue +97 -0
  73. package/src/components/tree/src/hooks/useTree.ts +239 -0
  74. package/src/components/tree/src/index.vue +392 -0
  75. package/src/components/tree/src/props.ts +133 -0
  76. package/src/components/tree/src/type/tree.ts +105 -0
  77. package/src/components/tree/src/utils/tree.ts +73 -0
  78. package/src/components/upload/index.less +43 -0
  79. package/src/components/upload/index.ts +7 -0
  80. package/src/components/upload/src/helper.ts +32 -0
  81. package/src/components/upload/src/index.vue +38 -0
  82. package/src/components/upload/src/props.ts +48 -0
  83. package/src/components/upload/src/upload.vue +166 -0
  84. package/src/theme/header/helper/menu-tree.ts +2 -2
  85. package/src/theme/header/index.less +1 -1
  86. package/src/theme/sider/helper/split-menu.ts +2 -2
  87. package/es/components/dialog/index.d.ts +0 -2
  88. package/es/components/dialog/src/hooks/useDialog.d.ts +0 -3
  89. package/src/components/dialog/index.ts +0 -5
  90. package/src/components/dialog/src/hooks/useDialog.ts +0 -85
@@ -0,0 +1,392 @@
1
+ <template>
2
+ <div class="dt-tree">
3
+ <template v-if="showTitle">
4
+ <TreeHeader
5
+ :title="title"
6
+ :toolbar="toolbar"
7
+ :search="search"
8
+ :checkable="checkable"
9
+ :searchText="searchState.searchText"
10
+ :checkAll="checkAll"
11
+ :expandAll="expandAll"
12
+ @search="handleSearch"
13
+ >
14
+ {{ extendSlots(slots) }}
15
+ </TreeHeader>
16
+ </template>
17
+
18
+ <Spin :spinning="loading" tip="加载中...">
19
+ <div v-show="!getNotFound">
20
+ <Tree
21
+ v-bind="getBindValues"
22
+ :showIcon="false"
23
+ :treeData="treeData"
24
+ ></Tree>
25
+ </div>
26
+ <Empty v-show="getNotFound"></Empty>
27
+ </Spin>
28
+ </div>
29
+ </template>
30
+
31
+ <script lang="tsx" setup>
32
+ import { computed, reactive, ref, toRaw, unref, useAttrs, useSlots as vueUseSlots, watch, watchEffect } from 'vue'
33
+ import { cloneDeep, omit, difference, get } from 'lodash-es'
34
+ import { Spin, Empty, Tree } from 'ant-design-vue'
35
+ import TreeHeader from './components/treeHeader.vue'
36
+ import { BasicProps } from './props'
37
+ import { CheckKeys, CreateContextOptions, FieldNames, TreeItem, TreeState, KeyType, TreeActionType } from './type/tree'
38
+ import { isArray, isBoolean, isFunction, Recordable, isEmpty, useSlots } from '@dt-frames/core'
39
+ import { eachTree, filter, treeToList } from './utils/tree'
40
+ import { useTree } from './hooks/useTree'
41
+
42
+ const props = defineProps( BasicProps )
43
+ const attrs = useAttrs()
44
+ const slots = vueUseSlots()
45
+
46
+ const { getSlot, extendSlots } = useSlots()
47
+
48
+ const emit = defineEmits([
49
+ 'update:expandedKeys',
50
+ 'update:selectedKeys',
51
+ 'update:value',
52
+ 'check',
53
+ 'change',
54
+ 'clickNode',
55
+ 'update:searchValue'
56
+ ])
57
+
58
+
59
+ const state = reactive<TreeState>({
60
+ checkStrictly: props.checkStrictly,
61
+ expandedKeys: props.expandedKeys || [],
62
+ selectedKeys: props.selectedKeys || [],
63
+ checkedKeys: props.checkedKeys || [],
64
+ })
65
+
66
+ const searchState = reactive({
67
+ startSearch: false,
68
+ searchText: '',
69
+ searchData: [] as TreeItem[],
70
+ })
71
+
72
+ const treeDataRef = ref<TreeItem[]>([])
73
+
74
+ const getFieldNames = computed(() => {
75
+ const { fieldNames } = props
76
+ return {
77
+ children: 'children',
78
+ title: 'title',
79
+ key: 'key',
80
+ ...(fieldNames as FieldNames)
81
+ }
82
+ })
83
+
84
+ const getTreeData = computed((): TreeItem[] => {
85
+ return searchState.startSearch ? searchState.searchData : unref(treeDataRef)
86
+ })
87
+
88
+ const getNotFound = computed((): boolean => {
89
+ return !getTreeData.value || getTreeData.value.length === 0;
90
+ })
91
+
92
+ const getIcon = (params: Recordable, icon?: string) => {
93
+ if (!icon) {
94
+ if ( props.renderIcon && isFunction( props.renderIcon ) ) {
95
+ return props.renderIcon(params)
96
+ }
97
+ }
98
+
99
+ return icon
100
+ }
101
+
102
+ const treeData = computed(() => {
103
+ const data = cloneDeep(getTreeData.value)
104
+
105
+ eachTree(data, ( item, _parent ) => {
106
+ const searchText = searchState.searchText
107
+
108
+ const { highlight } = unref(props)
109
+ const { title: titleField, key: keyField, children: childrenField } = unref(getFieldNames)
110
+
111
+ const icon = getIcon(item, item.icon)
112
+ const title = get(item, titleField)
113
+
114
+ const searchIdx = searchText ? title.indexOf(searchText) : -1
115
+ const isHighlight = searchState.startSearch && !isEmpty(searchText) && highlight && searchIdx !== -1
116
+ const highlightStyle = `color: ${isBoolean(highlight) ? '#f50' : highlight}`
117
+
118
+ const titleDom = isHighlight ? (
119
+ // 切割高亮的字
120
+ <span class="tree-content">
121
+ <span>{title.substr(0, searchIdx)}</span>
122
+ <span style={ highlightStyle }>{ searchText }</span>
123
+ <span>{ title.substr(searchIdx + (searchText as string).length) }</span>
124
+ </span>
125
+ ) : (
126
+ title
127
+ )
128
+
129
+ item[titleField] = (
130
+ <span
131
+ class="tree-title"
132
+ onClick={ handleClickNode.bind(null, item[keyField], item[childrenField], item) }
133
+ >
134
+ {slots?.title ? (
135
+ getSlot(slots, 'title', item)
136
+ ) : (
137
+ <>
138
+ {icon && <i class={ `i ${icon}`} />}
139
+ {titleDom}
140
+ <span class='tree-action'>{renderAction(item)}</span>
141
+ </>
142
+ )}
143
+ </span>
144
+ )
145
+
146
+ })
147
+
148
+ return data
149
+ })
150
+
151
+
152
+ const showTitle = computed(() => {
153
+ return true
154
+ })
155
+
156
+ const getBindValues = computed(() => {
157
+ let propsData = {
158
+ blockNode: true,
159
+ ...attrs,
160
+ ...props,
161
+ expandedKeys: state.expandedKeys,
162
+ selectedKeys: state.selectedKeys,
163
+ checkedKeys: state.checkedKeys,
164
+ checkStrictly: state.checkStrictly,
165
+ fieldNames: unref(getFieldNames),
166
+ 'onUpdate:expandedKeys': (v: KeyType[]) => {
167
+ state.expandedKeys = v;
168
+ emit('update:expandedKeys', v);
169
+ },
170
+ 'onUpdate:selectedKeys': (v: KeyType[]) => {
171
+ state.selectedKeys = v;
172
+ emit('update:selectedKeys', v);
173
+ },
174
+ onCheck: (v: CheckKeys, e) => {
175
+ let currentValue = toRaw( state.checkedKeys ) as KeyType[]
176
+
177
+ if ( isArray( currentValue ) && searchState.startSearch ) {
178
+ const { key } = unref(getFieldNames)
179
+
180
+ currentValue = difference(currentValue, getChildrenKeys(e.node.$attrs.node[key]))
181
+
182
+ if (e.checked) {
183
+ currentValue.push(e.node.$attrs.node[key]);
184
+ }
185
+
186
+ state.checkedKeys = currentValue
187
+ } else {
188
+ state.checkedKeys = v;
189
+ }
190
+
191
+ const rawVal = toRaw(state.checkedKeys)
192
+
193
+ emit('update:value', rawVal)
194
+ emit('check', rawVal, e)
195
+ }
196
+ }
197
+
198
+ return omit(propsData, 'treeData', 'class')
199
+ })
200
+
201
+ // 设置节点点击事件
202
+ function handleClickNode(key: string, children: TreeItem[], node: TreeItem) {
203
+ emit('clickNode', node)
204
+
205
+ if (!props.clickRowToExpand || !children || children.length === 0) return
206
+
207
+ if (!state.expandedKeys.includes(key)) {
208
+ setExpandedKeys([...state.expandedKeys, key])
209
+ } else {
210
+ const keys = [...state.expandedKeys]
211
+ const index = keys.findIndex((item) => item === key)
212
+ if (index !== -1) {
213
+ keys.splice(index, 1);
214
+ }
215
+
216
+ setExpandedKeys(keys)
217
+ }
218
+ }
219
+
220
+ // 渲染操作栏
221
+ function renderAction(node: TreeItem) {
222
+ const { actionList } = props
223
+ if (!actionList || actionList.length === 0) return
224
+
225
+ return actionList.map((item, index) => {
226
+ let nodeShow = true
227
+
228
+ if (isFunction(item.show)) {
229
+ nodeShow = item.show?.(node);
230
+ } else if (isBoolean(item.show)) {
231
+ nodeShow = item.show;
232
+ }
233
+
234
+ if (!nodeShow) return null
235
+
236
+ return (
237
+ <span key={index} class='tree-action'>
238
+ { item.render(node) }
239
+ </span>
240
+ )
241
+ })
242
+
243
+ }
244
+
245
+ const {
246
+ deleteNodeByKey,
247
+ insertNodeByKey,
248
+ insertNodesByKey,
249
+ filterByLevel,
250
+ updateNodeByKey,
251
+ getAllKeys,
252
+ getChildrenKeys,
253
+ getEnabledKeys,
254
+ getSelectedNode,
255
+ } = useTree( treeDataRef, getFieldNames )
256
+
257
+ // 设置实例暴露的方法
258
+ function setExpandedKeys(keys: KeyType[]) { state.expandedKeys = keys }
259
+ function getExpandedKeys() { return state.expandedKeys }
260
+
261
+ function setSelectedKeys( keys: KeyType[] ) { state.selectedKeys = keys }
262
+ function getSelectedKeys() { return state.selectedKeys }
263
+
264
+ function setCheckedKeys(keys: CheckKeys) { state.checkedKeys = keys }
265
+ function getCheckedKeys() { return state.checkedKeys }
266
+
267
+ function checkAll(checkAll: boolean) { state.checkedKeys = checkAll ? getEnabledKeys() : ([] as KeyType[]) }
268
+ function expandAll(expandAll: boolean) { state.expandedKeys = expandAll ? getAllKeys() : ([] as KeyType[]) }
269
+
270
+ function onStrictlyChange(strictly: boolean) { state.checkStrictly = strictly }
271
+
272
+ const instance: TreeActionType = {
273
+ setExpandedKeys,
274
+ getExpandedKeys,
275
+ setSelectedKeys,
276
+ getSelectedKeys,
277
+ setCheckedKeys,
278
+ getCheckedKeys,
279
+ insertNodeByKey,
280
+ insertNodesByKey,
281
+ deleteNodeByKey,
282
+ updateNodeByKey,
283
+ getSelectedNode,
284
+ checkAll,
285
+ expandAll,
286
+ onStrictlyChange,
287
+ filterByLevel: (level: number) => {
288
+ state.expandedKeys = filterByLevel(level);
289
+ },
290
+ setSearchValue: (value: string) => {
291
+ handleSearch(value);
292
+ },
293
+ getSearchValue: () => {
294
+ return searchState.searchText;
295
+ }
296
+ }
297
+
298
+ function handleSearch(searchValue: string) {
299
+ if (searchValue !== searchState.searchText) searchState.searchText = searchValue
300
+ emit('update:searchValue', searchValue)
301
+
302
+ if (!searchValue) {
303
+ searchState.startSearch = false
304
+ return
305
+ }
306
+
307
+ const { filterFn, checkable, expandOnSearch, checkOnSearch, selectedOnSearch } = unref(props)
308
+ const { title: titleField, key: keyField } = unref(getFieldNames)
309
+ const matchedKeys: string[] = []
310
+
311
+ searchState.startSearch = true
312
+
313
+ searchState.searchData = filter(
314
+ unref(treeDataRef),
315
+ (node) => {
316
+ const result = filterFn
317
+ ? filterFn(searchValue, node, unref(getFieldNames))
318
+ : node[titleField]?.includes(searchValue) ?? false
319
+
320
+ if (result) {
321
+ matchedKeys.push(node[keyField]);
322
+ }
323
+
324
+ return result;
325
+ },
326
+ unref(getFieldNames),
327
+ )
328
+
329
+ if (expandOnSearch) {
330
+ const expandKeys = treeToList(searchState.searchData).map((val) => {
331
+ return val[keyField]
332
+ })
333
+
334
+ if (expandKeys && expandKeys.length) {
335
+ setExpandedKeys(expandKeys)
336
+ }
337
+ }
338
+
339
+ if (checkOnSearch && checkable && matchedKeys.length) {
340
+ setCheckedKeys(matchedKeys)
341
+ }
342
+
343
+ if (selectedOnSearch && matchedKeys.length) {
344
+ setSelectedKeys(matchedKeys)
345
+ }
346
+ }
347
+
348
+ watch(
349
+ () => props.searchValue,
350
+ (val) => {
351
+ if (val !== searchState.searchText) {
352
+ searchState.searchText = val
353
+ }
354
+ },
355
+ { immediate: true }
356
+ )
357
+
358
+ watch(
359
+ () => props.treeData,
360
+ (val) => {
361
+ if (val) {
362
+ handleSearch(searchState.searchText)
363
+ }
364
+ }
365
+ )
366
+
367
+ watch(
368
+ () => props.value,
369
+ () => {
370
+ state.checkedKeys = toRaw(props.value || [])
371
+ },
372
+ { immediate: true }
373
+ )
374
+
375
+ watch(
376
+ () => state.checkedKeys,
377
+ () => {
378
+ const v = toRaw(state.checkedKeys)
379
+ emit('update:value', v)
380
+ emit('change', v)
381
+ }
382
+ )
383
+
384
+ watchEffect(() => { treeDataRef.value = props.treeData as TreeItem[] })
385
+ watchEffect(() => { state.expandedKeys = props.expandedKeys })
386
+ watchEffect(() => { state.selectedKeys = props.selectedKeys })
387
+ watchEffect(() => { state.checkedKeys = props.checkedKeys })
388
+ watchEffect(() => { state.checkStrictly = props.checkStrictly })
389
+
390
+ defineExpose(instance)
391
+
392
+ </script>
@@ -0,0 +1,133 @@
1
+ import { Recordable } from "@dt-frames/core";
2
+ import { TreeDataItem } from "ant-design-vue/lib/tree";
3
+ import { PropType } from "vue";
4
+ import { CheckKeys, ContextMenuItem, FieldNames, TreeActionItem, TreeItem } from "./type/tree"
5
+
6
+ export const BasicProps = {
7
+ loading: {
8
+ type: Boolean,
9
+ default: false,
10
+ },
11
+ // 粘性选择
12
+ checkStrictly: Boolean,
13
+ // 展开的key值
14
+ expandedKeys: {
15
+ type: Array as PropType<KeyType[]>,
16
+ default: () => []
17
+ },
18
+ // 设置选中的key
19
+ selectedKeys: {
20
+ type: Array as PropType<KeyType[]>,
21
+ default: () => []
22
+ },
23
+ // 选中的节点
24
+ checkedKeys: {
25
+ type: Array as PropType<CheckKeys>,
26
+ default: () => []
27
+ },
28
+
29
+ // 定义树节点的lable title children 名称
30
+ fieldNames: {
31
+ type: Object as PropType<FieldNames>,
32
+ },
33
+
34
+ beforeRightClick: {
35
+ type: Function as PropType<(...arg: any) => ContextMenuItem[]>,
36
+ default: undefined,
37
+ },
38
+
39
+ rightMenuList: {
40
+ type: Array as PropType<ContextMenuItem[]>,
41
+ },
42
+
43
+ //
44
+ renderIcon: {
45
+ type: Function as PropType<(params: Recordable) => string>,
46
+ },
47
+
48
+ // 高亮搜索值,仅高亮具体匹配值(通过title)值为true时使用默认色值,值为#xxx时使用此值替代且高亮开启
49
+ highlight: {
50
+ type: [Boolean, String] as PropType<Boolean | String>,
51
+ default: false,
52
+ },
53
+
54
+ actionList: {
55
+ type: Array as PropType<TreeActionItem[]>,
56
+ default: () => [],
57
+ },
58
+
59
+ clickRowToExpand: {
60
+ type: Boolean,
61
+ default: false,
62
+ },
63
+
64
+ searchValue: {
65
+ type: String,
66
+ default: ''
67
+ },
68
+
69
+ filterFn: {
70
+ type: Function as PropType< (searchValue: any, node: TreeItem, fieldNames: FieldNames) => boolean >,
71
+ default: undefined,
72
+ },
73
+
74
+ checkable: Boolean,
75
+
76
+ // 搜索完成时自动展开结果
77
+ expandOnSearch: Boolean,
78
+
79
+ // 搜索完成自动选中所有结果,当且仅当 checkable===true 时生效
80
+ checkOnSearch: Boolean,
81
+
82
+ // 搜索完成自动select所有结果
83
+ selectedOnSearch: Boolean,
84
+
85
+ // 树数据
86
+ treeData: {
87
+ type: Array as PropType<TreeDataItem[]>
88
+ },
89
+
90
+ value: {
91
+ type: [Object, Array] as PropType<KeyType[] | CheckKeys>
92
+ },
93
+
94
+ title: {
95
+ type: String,
96
+ default: '',
97
+ },
98
+
99
+ toolbar: Boolean,
100
+ search: Boolean,
101
+
102
+ }
103
+
104
+ export const searchProps = {
105
+ title: {
106
+ type: String,
107
+ default: '',
108
+ },
109
+ toolbar: {
110
+ type: Boolean,
111
+ default: false,
112
+ },
113
+ checkable: {
114
+ type: Boolean,
115
+ default: false,
116
+ },
117
+ search: {
118
+ type: Boolean,
119
+ default: false,
120
+ },
121
+ searchText: {
122
+ type: String,
123
+ default: '',
124
+ },
125
+ checkAll: {
126
+ type: Function,
127
+ default: undefined,
128
+ },
129
+ expandAll: {
130
+ type: Function,
131
+ default: undefined,
132
+ },
133
+ }
@@ -0,0 +1,105 @@
1
+ import { Recordable } from "@dt-frames/core";
2
+ import { Fn } from "@vueuse/core"
3
+ import { TreeDataItem } from "ant-design-vue/lib/tree"
4
+
5
+
6
+ export enum ToolbarEnum {
7
+ SELECT_ALL,
8
+ UN_SELECT_ALL,
9
+ EXPAND_ALL,
10
+ UN_EXPAND_ALL,
11
+ CHECK_STRICTLY,
12
+ CHECK_UN_STRICTLY,
13
+ }
14
+
15
+ export type KeyType = string | number
16
+
17
+ export type CheckKeys =
18
+ | KeyType[]
19
+ | {
20
+ checked: string[] | number[];
21
+ halfChecked: string[] | number[]
22
+ }
23
+
24
+ export interface TreeState {
25
+ expandedKeys: KeyType[]
26
+ selectedKeys: KeyType[]
27
+ checkedKeys: CheckKeys
28
+ checkStrictly: boolean
29
+ }
30
+
31
+ export interface FieldNames {
32
+ children?: string
33
+ title?: string
34
+ key?: string
35
+ }
36
+
37
+ export interface TreeItem extends TreeDataItem {
38
+ icon?: any
39
+ }
40
+
41
+ export interface CreateContextOptions {
42
+ event: MouseEvent
43
+ icon?: string
44
+ styles?: any
45
+ items?: ContextMenuItem[]
46
+ }
47
+
48
+ export interface InsertNodeParams {
49
+ parentKey: string | null
50
+ node: TreeDataItem
51
+ list?: TreeDataItem[]
52
+ push?: 'push' | 'unshift'
53
+ }
54
+
55
+ export interface ContextMenuItem {
56
+ label: string
57
+ icon?: string
58
+ hidden?: boolean
59
+ disabled?: boolean
60
+ handler?: Fn
61
+ divider?: boolean
62
+ children?: ContextMenuItem[]
63
+ }
64
+
65
+ export interface TreeActionItem {
66
+ render: (record: Recordable) => any
67
+ show?: boolean | ((record: Recordable) => boolean)
68
+ }
69
+
70
+ export interface InsertNodeParams {
71
+ parentKey: string | null
72
+ node: TreeDataItem
73
+ list?: TreeDataItem[]
74
+ push?: 'push' | 'unshift'
75
+ }
76
+
77
+ export interface TreeHelperConfig {
78
+ id: string;
79
+ children: string;
80
+ pid: string;
81
+ }
82
+
83
+ export interface TreeActionType {
84
+ checkAll: (checkAll: boolean) => void
85
+ expandAll: (expandAll: boolean) => void
86
+ setExpandedKeys: (keys: KeyType[]) => void
87
+ getExpandedKeys: () => KeyType[]
88
+ setSelectedKeys: (keys: KeyType[]) => void
89
+ getSelectedKeys: () => KeyType[]
90
+ setCheckedKeys: (keys: CheckKeys) => void
91
+ getCheckedKeys: () => CheckKeys
92
+ filterByLevel: (level: number) => void
93
+ insertNodeByKey: (opt: InsertNodeParams) => void
94
+ insertNodesByKey: (opt: InsertNodeParams) => void
95
+ deleteNodeByKey: (key: string) => void
96
+ updateNodeByKey: (key: string, node: Omit<TreeDataItem, 'key'>) => void
97
+ setSearchValue: (value: string) => void
98
+ getSearchValue: () => string
99
+ onStrictlyChange: ( strictly: boolean ) => void
100
+ getSelectedNode: (
101
+ key: KeyType,
102
+ treeList?: TreeItem[],
103
+ selectNode?: TreeItem | null,
104
+ ) => TreeItem | null
105
+ }
@@ -0,0 +1,73 @@
1
+ import { TreeHelperConfig } from "../type/tree"
2
+
3
+ /**
4
+ * 递归遍历树结构
5
+ * @param treeDatas 树数据
6
+ * @param callBack 回调
7
+ * @param parentNode 父节点
8
+ */
9
+ export function eachTree(treeDatas: any[], callBack: Function, parentNode = {}) {
10
+ treeDatas.forEach( el => {
11
+ const newNode = callBack(el, parentNode) || el
12
+
13
+ if (el.children) {
14
+ eachTree( el.children, callBack, newNode )
15
+ }
16
+ } )
17
+ }
18
+
19
+
20
+ // 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿
21
+ export function forEach<T = any>(
22
+ tree: T[],
23
+ func: (n: T) => any,
24
+ config: Partial<TreeHelperConfig> = {},
25
+ ): void {
26
+ const list: any[] = [...tree]
27
+ const { children = 'children' } = config
28
+
29
+ for (let i = 0; i < list.length; i++) {
30
+ if (func(list[i])) {
31
+ return
32
+ }
33
+ children && list[i][children] && list.splice(i + 1, 0, ...list[i][children])
34
+ }
35
+ }
36
+
37
+ export function filter<T = any>(
38
+ tree: T[],
39
+ func: (n: T) => boolean,
40
+ config: Partial<TreeHelperConfig> = {},
41
+ ): T[] {
42
+ // 获取配置
43
+ const children = config.children as string || 'children';
44
+
45
+ function listFilter(list: T[]) {
46
+ return list
47
+ .map((node: any) => ({ ...node }))
48
+ .filter((node) => {
49
+
50
+ // 递归调用 对含有children项 进行再次调用自身函数 listFilter
51
+ node[children] = node[children] && listFilter(node[children]);
52
+
53
+ // 执行传入的回调 func 进行过滤
54
+ return func(node) || (node[children] && node[children].length);
55
+ });
56
+ }
57
+
58
+ return listFilter(tree);
59
+ }
60
+
61
+ export function treeToList<T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T {
62
+ const { children = 'children' } = config
63
+
64
+ const result: any = [...tree]
65
+
66
+ for (let i = 0; i < result.length; i++) {
67
+ if (!result[i][children!]) continue
68
+ result.splice(i + 1, 0, ...result[i][children!])
69
+ }
70
+
71
+ return result
72
+ }
73
+