oxy-uni-ui 1.2.0 → 1.2.3

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 (116) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +51 -1
  3. package/components/common/path.ts +9 -0
  4. package/components/common/util.ts +42 -0
  5. package/components/composables/useGlobalLoading.ts +42 -0
  6. package/components/composables/useGlobalMessage.ts +48 -0
  7. package/components/composables/useGlobalToast.ts +84 -0
  8. package/components/composables/useVirtualScroll.ts +3 -2
  9. package/components/oxy-cell/oxy-cell.vue +15 -2
  10. package/components/oxy-cell/types.ts +4 -0
  11. package/components/oxy-checkbox/index.scss +1 -1
  12. package/components/oxy-checkbox/oxy-checkbox.vue +2 -2
  13. package/components/oxy-col-picker/oxy-col-picker.vue +3 -0
  14. package/components/oxy-col-picker/types.ts +5 -1
  15. package/components/oxy-corner/oxy-corner.vue +15 -3
  16. package/components/oxy-corner/types.ts +15 -1
  17. package/components/oxy-date-strip/index.scss +10 -0
  18. package/components/oxy-date-strip/oxy-date-strip.vue +198 -0
  19. package/components/oxy-date-strip/types.ts +98 -0
  20. package/components/oxy-date-strip/utils.ts +67 -0
  21. package/components/oxy-date-strip-item/index.scss +94 -0
  22. package/components/oxy-date-strip-item/oxy-date-strip-item.vue +102 -0
  23. package/components/oxy-date-strip-item/types.ts +53 -0
  24. package/components/oxy-datetime-picker/oxy-datetime-picker.vue +3 -1
  25. package/components/oxy-datetime-picker/types.ts +5 -1
  26. package/components/oxy-echarts/index.scss +17 -0
  27. package/components/oxy-echarts/index.ts +1 -0
  28. package/components/oxy-echarts/oxy-echarts.vue +32 -0
  29. package/components/oxy-echarts/types.ts +12 -0
  30. package/components/oxy-file-list/index.scss +26 -0
  31. package/components/oxy-file-list/oxy-file-list.vue +208 -34
  32. package/components/oxy-file-list/types.ts +58 -2
  33. package/components/oxy-global-loading/oxy-global-loading.vue +53 -0
  34. package/components/oxy-global-message/oxy-global-message.vue +64 -0
  35. package/components/oxy-global-toast/oxy-global-toast.vue +53 -0
  36. package/components/oxy-img-lazy/index.scss +17 -0
  37. package/components/oxy-img-lazy/oxy-img-lazy.vue +332 -0
  38. package/components/oxy-img-lazy/types.ts +69 -0
  39. package/components/oxy-link/index.scss +57 -0
  40. package/components/oxy-link/oxy-link.vue +130 -0
  41. package/components/oxy-link/types.ts +81 -0
  42. package/components/oxy-list/index.scss +7 -1
  43. package/components/oxy-list/types.ts +1 -1
  44. package/components/oxy-picker/oxy-picker.vue +3 -0
  45. package/components/oxy-picker/types.ts +5 -1
  46. package/components/oxy-radio/index.scss +3 -3
  47. package/components/oxy-radio/oxy-radio.vue +1 -1
  48. package/components/oxy-rich-text/icon/emjio.svg +1 -0
  49. package/components/oxy-rich-text/icon/quote.svg +1 -0
  50. package/components/oxy-rich-text/icon/text.svg +1 -0
  51. package/components/oxy-rich-text/icon/title.svg +1 -0
  52. package/components/oxy-rich-text/index.scss +159 -0
  53. package/components/oxy-rich-text/mp-html/card/card.vue +122 -0
  54. package/components/oxy-rich-text/mp-html/card/index.js +7 -0
  55. package/components/oxy-rich-text/mp-html/editable/config.js +15 -0
  56. package/components/oxy-rich-text/mp-html/editable/index.js +553 -0
  57. package/components/oxy-rich-text/mp-html/emoji/index.js +203 -0
  58. package/components/oxy-rich-text/mp-html/highlight/config.js +5 -0
  59. package/components/oxy-rich-text/mp-html/highlight/index.js +96 -0
  60. package/components/oxy-rich-text/mp-html/highlight/prism.css +1 -0
  61. package/components/oxy-rich-text/mp-html/highlight/prism.min.js +7 -0
  62. package/components/oxy-rich-text/mp-html/img-cache/index.js +138 -0
  63. package/components/oxy-rich-text/mp-html/latex/index.js +80 -0
  64. package/components/oxy-rich-text/mp-html/latex/katex.css +1 -0
  65. package/components/oxy-rich-text/mp-html/latex/katex.min.js +1 -0
  66. package/components/oxy-rich-text/mp-html/markdown/index.js +50 -0
  67. package/components/oxy-rich-text/mp-html/markdown/marked.min.js +71 -0
  68. package/components/oxy-rich-text/mp-html/mp-html.d.ts +184 -0
  69. package/components/oxy-rich-text/mp-html/mp-html.vue +675 -0
  70. package/components/oxy-rich-text/mp-html/node/node.vue +1161 -0
  71. package/components/oxy-rich-text/mp-html/parser.js +1428 -0
  72. package/components/oxy-rich-text/mp-html/search/index.js +132 -0
  73. package/components/oxy-rich-text/mp-html/style/index.js +129 -0
  74. package/components/oxy-rich-text/mp-html/style/parser.js +175 -0
  75. package/components/oxy-rich-text/mp-html/template/index.js +67 -0
  76. package/components/oxy-rich-text/mp-html/txv-video/index.js +46 -0
  77. package/components/oxy-rich-text/oxy-rich-text.vue +642 -0
  78. package/components/oxy-rich-text/types.ts +71 -0
  79. package/components/oxy-select/index.scss +255 -0
  80. package/components/oxy-select/oxy-select.vue +421 -0
  81. package/components/oxy-select/types.ts +71 -0
  82. package/components/oxy-select-picker/oxy-select-picker.vue +3 -0
  83. package/components/oxy-select-picker/types.ts +5 -1
  84. package/components/oxy-stream-render/index.scss +6 -0
  85. package/components/oxy-stream-render/oxy-stream-render.vue +204 -0
  86. package/components/oxy-stream-render/types.ts +5 -0
  87. package/components/oxy-tree/index.scss +17 -1
  88. package/components/oxy-tree/oxy-tree.vue +89 -8
  89. package/components/oxy-tree/types.ts +11 -1
  90. package/components/oxy-waterfall/index.scss +18 -0
  91. package/components/oxy-waterfall/oxy-waterfall.vue +218 -0
  92. package/components/oxy-waterfall/types.ts +90 -0
  93. package/components/oxy-waterfall-item/index.scss +8 -0
  94. package/components/oxy-waterfall-item/oxy-waterfall-item.vue +89 -0
  95. package/components/oxy-waterfall-item/types.ts +16 -0
  96. package/global.d.ts +7 -0
  97. package/index.ts +3 -0
  98. package/locale/lang/en-US.ts +26 -0
  99. package/locale/lang/zh-CN.ts +26 -0
  100. package/oxy-uni-ui.zip +0 -0
  101. package/package.json +1 -1
  102. package/tags.json +1 -1
  103. package/uni-echarts/changelog.md +2 -0
  104. package/uni-echarts/components/index.js +1 -0
  105. package/uni-echarts/components/uni-echarts/events.js +95 -0
  106. package/uni-echarts/components/uni-echarts/types.d.ts +183 -0
  107. package/uni-echarts/components/uni-echarts/types.js +1 -0
  108. package/uni-echarts/components/uni-echarts/uni-echarts.vue +530 -0
  109. package/uni-echarts/components/uni-echarts/uni-echarts.vue.d.ts +19 -0
  110. package/uni-echarts/global.d.ts +7 -0
  111. package/uni-echarts/index.d.ts +440 -0
  112. package/uni-echarts/index.js +2 -0
  113. package/uni-echarts/package.json +105 -0
  114. package/uni-echarts/shared-core.d.ts +269 -0
  115. package/uni-echarts/shared-core.js +900 -0
  116. package/web-types.json +1 -1
@@ -0,0 +1,71 @@
1
+ import type { ExtractPropTypes } from 'vue'
2
+ import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeRequiredProp, makeStringProp } from '../common/props'
3
+
4
+ export const selectProps = {
5
+ ...baseProps,
6
+ /**
7
+ * 选中项
8
+ */
9
+ modelValue: makeRequiredProp([String, Number, Array]),
10
+ /**
11
+ * 是否多选
12
+ */
13
+ multiple: makeBooleanProp(false),
14
+ /**
15
+ * 是否禁用
16
+ */
17
+ disabled: makeBooleanProp(false),
18
+ /** 只读 */
19
+ readonly: makeBooleanProp(false),
20
+ /**
21
+ * 多作为 key 唯一标识的键名
22
+ */
23
+ labelKey: makeStringProp('label'),
24
+ /**
25
+ * 多作为 value 唯一标识的键名
26
+ */
27
+ valueKey: makeStringProp('value'),
28
+ /**
29
+ * 是否开启搜索
30
+ */
31
+ filterable: makeBooleanProp(false),
32
+ /**
33
+ * 是否折叠显示标签
34
+ */
35
+ collapseTags: makeBooleanProp(false),
36
+ /**
37
+ * 超过多少个标签才折叠
38
+ */
39
+ collapseTagsNum: makeNumberProp(1),
40
+ /**
41
+ * 选择器数据
42
+ */
43
+ columns: makeArrayProp<Record<string, any>>(),
44
+ /**
45
+ * 左侧标题
46
+ */
47
+ label: makeStringProp(''),
48
+ /** 设置左侧标题宽度 */
49
+ labelWidth: makeStringProp(''),
50
+ /** 选择器的值靠右展示 */
51
+ alignRight: makeBooleanProp(false),
52
+ /**
53
+ * 输入框的提示文字
54
+ */
55
+ placeholder: makeStringProp('请选择'),
56
+ /**
57
+ * 无选项提示
58
+ */
59
+ emptyTips: makeStringProp('无选项'),
60
+ /**
61
+ * 是否可清除
62
+ */
63
+ clear: makeBooleanProp(true),
64
+ /**
65
+ * 格式化输出
66
+ */
67
+ format: makeStringProp(''),
68
+ defItem: makeNumberProp(0)
69
+ }
70
+
71
+ export type SelectProps = ExtractPropTypes<typeof selectProps>
@@ -320,6 +320,9 @@ function close() {
320
320
 
321
321
  function open() {
322
322
  if (props.disabled || props.readonly) return
323
+ if (isFunction(props.beforeOpen) && !props.beforeOpen()) {
324
+ return
325
+ }
323
326
  selectList.value = valueFormat(props.modelValue)
324
327
  pickerShow.value = true
325
328
  isConfirm.value = false
@@ -105,7 +105,11 @@ export const selectPickerProps = {
105
105
  /**
106
106
  * 必填标记位置,可选值:before、after
107
107
  */
108
- markerSide: makeStringProp<'before' | 'after'>('before')
108
+ markerSide: makeStringProp<'before' | 'after'>('before'),
109
+ /**
110
+ * 打开pop之前的校验
111
+ */
112
+ beforeOpen: Function as PropType<() => boolean>
109
113
  }
110
114
  export type SelectPickerProps = ExtractPropTypes<typeof selectPickerProps>
111
115
 
@@ -0,0 +1,6 @@
1
+ @import '../common/abstracts/variable';
2
+ @import '../common/abstracts/mixin';
3
+
4
+ @include b(stream-render) {
5
+ display: none;
6
+ }
@@ -0,0 +1,204 @@
1
+ <template>
2
+ <!-- #ifdef H5 || APP-PLUS -->
3
+ <view class="oxy-stream-render" :change:stream-request="appStreamHandler.handleStreamRequest" :stream-request="streamRequest" />
4
+ <!-- #endif -->
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: 'oxy-stream-render',
10
+ props: {
11
+ streamRequest: {
12
+ type: Object,
13
+ default: () => ({})
14
+ }
15
+ },
16
+ options: {
17
+ addGlobalClass: true,
18
+ virtualHost: true,
19
+ styleIsolation: 'shared'
20
+ },
21
+ data() {
22
+ return {
23
+ requestTask: null
24
+ }
25
+ },
26
+ watch: {
27
+ streamRequest: {
28
+ handler(newVal) {
29
+ // #ifndef H5 || APP-PLUS
30
+ this.handleStreamRequest(newVal)
31
+ // #endif
32
+ },
33
+ deep: true
34
+ }
35
+ },
36
+ methods: {
37
+ handleAppStreamData({ chunk, finished }) {
38
+ this.$emit('stream-data', { chunk, finished })
39
+ },
40
+ handleAppStreamError({ message, type }) {
41
+ this.$emit('stream-error', { message, type })
42
+ },
43
+ // #ifndef H5 || APP-PLUS
44
+ handleStreamRequest(newVal) {
45
+ if (newVal && newVal.cancel) {
46
+ if (this.requestTask) {
47
+ this.requestTask.abort()
48
+ this.requestTask = null
49
+ }
50
+ this.handleAppStreamData({
51
+ chunk: null,
52
+ finished: true
53
+ })
54
+ return
55
+ }
56
+
57
+ if (!newVal || !newVal.url) {
58
+ return
59
+ }
60
+
61
+ if (this.requestTask) {
62
+ this.requestTask.abort()
63
+ this.requestTask = null
64
+ }
65
+
66
+ const { url, method, headers, body } = newVal
67
+
68
+ this.requestTask = uni.request({
69
+ url,
70
+ method: method || 'GET',
71
+ header: headers || {},
72
+ data: body,
73
+ enableChunked: true,
74
+ success: (res) => {
75
+ this.handleAppStreamData({
76
+ chunk: null,
77
+ finished: true
78
+ })
79
+ this.requestTask = null
80
+ },
81
+ fail: (err) => {
82
+ this.handleAppStreamError({
83
+ message: err.errMsg || 'Request failed',
84
+ type: err.errMsg === 'request:fail abort' ? 'AbortError' : 'Error'
85
+ })
86
+ this.requestTask = null
87
+ }
88
+ })
89
+ // 这里监听消息
90
+ this.requestTask.onChunkReceived((res) => {
91
+ let decoder = new TextDecoder('utf-8')
92
+ let chunk = decoder.decode(new Uint8Array(res.data))
93
+ this.handleAppStreamData({
94
+ chunk,
95
+ finished: false
96
+ })
97
+ })
98
+ }
99
+ // #endif
100
+ }
101
+ }
102
+ </script>
103
+
104
+ <script module="appStreamHandler" lang="renderjs">
105
+ // #ifdef H5 || APP-PLUS
106
+ module.exports = {
107
+ data() {
108
+ return {
109
+ abortController: null,
110
+ }
111
+ },
112
+ methods: {
113
+ handleStreamRequest(newVal, _oldVal, _ownerInstance) {
114
+ if (newVal && newVal.cancel) {
115
+ if (this.abortController) {
116
+ this.abortController.abort()
117
+ this.abortController = null
118
+ }
119
+ this.$ownerInstance.callMethod('handleAppStreamData', {
120
+ chunk: null,
121
+ finished: true,
122
+ })
123
+ return
124
+ }
125
+
126
+ if (!newVal || !newVal.url) {
127
+ return
128
+ }
129
+
130
+ if (this.abortController) {
131
+ this.abortController.abort()
132
+ this.abortController = null
133
+ }
134
+
135
+ this.abortController = new AbortController()
136
+
137
+ const { url, method, headers, body } = newVal
138
+
139
+ fetch(url, {
140
+ method,
141
+ headers,
142
+ body,
143
+ signal: this.abortController.signal,
144
+ })
145
+ .then((response) => {
146
+ if (!response.ok) {
147
+ throw new Error(`HTTP error! status: ${response.status}`)
148
+ }
149
+
150
+ if (!response.body || !response.body.getReader) {
151
+ throw new Error('ReadableStream not supported')
152
+ }
153
+ const reader = response.body.getReader()
154
+ const decoder = new TextDecoder()
155
+
156
+ const readStream = async () => {
157
+ try {
158
+ const { done, value } = await reader.read()
159
+
160
+ if (done) {
161
+ this.abortController = null
162
+ this.$ownerInstance.callMethod('handleAppStreamData', {
163
+ chunk: null,
164
+ finished: true,
165
+ })
166
+ return
167
+ }
168
+
169
+ const chunk = decoder.decode(value, { stream: true })
170
+
171
+ this.$ownerInstance.callMethod('handleAppStreamData', {
172
+ chunk,
173
+ finished: false,
174
+ })
175
+
176
+ return readStream()
177
+ }
178
+ catch (error) {
179
+ this.abortController = null
180
+ this.$ownerInstance.callMethod('handleAppStreamError', {
181
+ message: error.message,
182
+ type:error.name
183
+ })
184
+ }
185
+ }
186
+
187
+ return readStream()
188
+ })
189
+ .catch((error) => {
190
+ this.abortController = null
191
+ this.$ownerInstance.callMethod('handleAppStreamError', {
192
+ message: error.message,
193
+ type:error.name
194
+ })
195
+ })
196
+ },
197
+ },
198
+ }
199
+ // #endif
200
+ </script>
201
+
202
+ <style lang="scss" scoped>
203
+ @import './index.scss';
204
+ </style>
@@ -0,0 +1,5 @@
1
+ import type { ExtractPropTypes, PropType } from 'vue'
2
+
3
+ export const streamRenderProps = {}
4
+
5
+ export type StreamRenderProps = ExtractPropTypes<typeof streamRenderProps>
@@ -23,6 +23,22 @@
23
23
  left: 0;
24
24
  right: 0;
25
25
  }
26
+ .oxy-tree__search{
27
+ display: flex;
28
+ :deep(.oxy-button){
29
+ min-width: 60px;
30
+ }
31
+ :deep(.oxy-tree__search-input) {
32
+ flex: 1;
33
+ background-color: $-tree-search-input-color;
34
+ padding: 6px 12px;
35
+ border-radius: 4px;
36
+ margin-bottom: 8px;
37
+ margin-right: 12px;
38
+ }
39
+ }
40
+
41
+
26
42
  }
27
43
 
28
44
  .oxy-tree-node-content {
@@ -80,4 +96,4 @@
80
96
  .oxy-tree-node {
81
97
  flex: 1;
82
98
  }
83
- }
99
+ }
@@ -1,5 +1,20 @@
1
1
  <template>
2
2
  <view class="oxy-tree" :class="customClass" :style="customStyle">
3
+ <slot name="search-button" v-if="showFilter">
4
+ <view class="oxy-tree__search">
5
+ <oxy-input
6
+ type="text"
7
+ no-border
8
+ class="oxy-tree__search-input"
9
+ prefix-icon="search"
10
+ :placeholder="filterPlaceholder"
11
+ v-model="searchValue"
12
+ @confirm="handleFilter"
13
+ />
14
+ <oxy-button :round="false" @click="handleFilter">筛选</oxy-button>
15
+ </view>
16
+ </slot>
17
+
3
18
  <view v-if="data.length" class="oxy-tree__virtual-scroll" :style="{ height: height }">
4
19
  <scroll-view class="oxy-tree__view" scroll-y :scroll-x="true" :scroll-top="scrollTop" @scroll="handleScroll">
5
20
  <view class="oxy-tree__container" :style="{ height: totalHeight + 'px' }">
@@ -82,11 +97,12 @@ const emit = defineEmits<{
82
97
 
83
98
  const { getDisabled, getChildren, getLabel, getKey } = useTreeMethods(props)
84
99
  const expandedKeySet = ref<Set<string>>(new Set())
100
+ const bakExpandedKeySet = ref<Set<string> | null>(null)
85
101
  const hiddenNodeKeySet = ref<Set<string>>(new Set())
86
102
  const checkedKeys = ref<Set<string>>(new Set())
87
103
  const immediateKeySet = ref<Set<string>>(new Set())
88
104
  const currentNode = ref<TreeNode>()
89
-
105
+ const searchValue = ref('')
90
106
  const tree = ref<Tree>() as Ref<Tree>
91
107
  const flattenTree = computed<TreeNode[]>(() => {
92
108
  const expandedKeys = expandedKeySet.value
@@ -169,7 +185,6 @@ const createTree = (data: RawTreeNode[]) => {
169
185
  node.checked = checkedKeys.value.has(value)
170
186
  }
171
187
  if (expandAll.value) {
172
- node.expanded = true
173
188
  expandedKeySet.value.add(value)
174
189
  }
175
190
  const children = getChildren(rawNode)
@@ -202,9 +217,8 @@ const createTree = (data: RawTreeNode[]) => {
202
217
  }
203
218
 
204
219
  const toggleExpand = (node: TreeNode, flag: boolean) => {
205
- node.expanded = flag
206
220
  const key = node.key
207
- if (node.expanded) {
221
+ if (flag) {
208
222
  expandedKeySet.value.add(key)
209
223
  emit('node-expand', node)
210
224
  } else {
@@ -279,7 +293,6 @@ const updateNode = (node: TreeNode | undefined) => {
279
293
  const expandNode = (node: TreeNode | undefined) => {
280
294
  if (!node) return
281
295
  !node.isLeaf && expandedKeySet.value.add(node.key)
282
- node.expanded = true
283
296
  if (node.parent) {
284
297
  expandNode(node.parent)
285
298
  }
@@ -287,6 +300,12 @@ const expandNode = (node: TreeNode | undefined) => {
287
300
  const initValue = () => {
288
301
  if (showCheckbox.value) {
289
302
  if (isSetsEqual(checkedKeys.value, new Set(modelValue.value as string[]))) return
303
+ Array.from(checkedKeys.value).map((value) => {
304
+ const node = tree.value?.treeNodeMap.get(value as string)
305
+ if (node) {
306
+ toggleChecked(node, false)
307
+ }
308
+ })
290
309
  checkedKeys.value = new Set(modelValue.value as string[])
291
310
 
292
311
  Array.isArray(modelValue.value) &&
@@ -322,7 +341,7 @@ const getNodeStyle = (item: TreeNode) => {
322
341
  const getNodeClass = (item: TreeNode) => {
323
342
  const currentValue = currentNode?.value
324
343
  return {
325
- expanded: item.expanded,
344
+ expanded: expandedKeySet.value.has(item.key),
326
345
  checked: item.checked,
327
346
  'is-leaf': item.isLeaf,
328
347
  immediate: item.immediate,
@@ -335,7 +354,7 @@ const handleNodeClick = (item: TreeNode) => {
335
354
  handleClick(item)
336
355
  }
337
356
  const handleClickExpand = (item: TreeNode) => {
338
- toggleExpand(item, !item.expanded)
357
+ toggleExpand(item, !expandedKeySet.value.has(item.key))
339
358
  }
340
359
  watch(
341
360
  () => data.value,
@@ -387,17 +406,79 @@ const scrollToElementById = (id: string | number) => {
387
406
  })
388
407
  }
389
408
  }
409
+ const getCheckedNodes = (): (TreeNode | any)[] => {
410
+ const checkNodes = Array.from(checkedKeys.value).map((key) => {
411
+ return tree.value?.treeNodeMap.get(key as string) || { [props.nodeKey]: key }
412
+ })
413
+ return checkNodes
414
+ }
415
+
416
+ const filter = (query: string) => {
417
+ if (bakExpandedKeySet.value === null) {
418
+ bakExpandedKeySet.value = new Set(expandedKeySet.value)
419
+ }
420
+ const keys = doFilter(query)
421
+ if (query && keys) {
422
+ expandedKeySet.value = keys
423
+ } else if (!query) {
424
+ bakExpandedKeySet.value && (expandedKeySet.value = new Set(bakExpandedKeySet.value))
425
+ bakExpandedKeySet.value = null
426
+ }
427
+ }
428
+
429
+ const doFilter = (query: string) => {
430
+ if (typeof props.filterMethod !== 'function') {
431
+ return
432
+ }
433
+ const expandKeySet = new Set<string>()
434
+ const hiddenKeys = hiddenNodeKeySet.value
435
+ const family: TreeNode[] = []
436
+ const nodes = tree.value.treeNodes || []
437
+ const filter = props.filterMethod
438
+ hiddenKeys.clear()
439
+ function traverse(nodes: TreeNode[]) {
440
+ nodes.forEach((node: TreeNode) => {
441
+ family.push(node)
442
+ if (filter(query, node.data)) {
443
+ family.forEach((member) => {
444
+ expandKeySet.add(member.key)
445
+ })
446
+ } else if (node.isLeaf) {
447
+ hiddenKeys.add(node.key)
448
+ }
449
+ const children = node.children
450
+ if (children) {
451
+ traverse(children)
452
+ }
453
+ if (!node.isLeaf) {
454
+ if (!expandKeySet.has(node.key)) {
455
+ hiddenKeys.add(node.key)
456
+ }
457
+ }
458
+ family.pop()
459
+ })
460
+ }
461
+ traverse(nodes)
462
+ return expandKeySet
463
+ }
464
+ const handleFilter = () => {
465
+ filter(searchValue.value)
466
+ }
467
+
390
468
  defineExpose<TreeExpose>({
391
469
  toggleExpand,
392
470
  toggleChecked,
393
471
  getNodeById,
472
+ getCheckedNodes,
473
+ getCurrentNode: () => currentNode.value,
394
474
  useTree: () => tree.value,
395
475
  getTree: () => tree,
396
476
  scrollToTop,
397
477
  scrollToBottom,
398
478
  scrollToPosition,
399
479
  scrollToElement,
400
- scrollToElementById
480
+ scrollToElementById,
481
+ filter
401
482
  })
402
483
  </script>
403
484
 
@@ -1,5 +1,6 @@
1
1
  import type { ComponentPublicInstance, ExtractPropTypes, Ref } from 'vue'
2
2
  import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeNumericProp, makeStringProp } from '../common/props'
3
+ import { type PropType } from 'vue'
3
4
 
4
5
  // 树结构类型定义
5
6
  export type Tree = {
@@ -67,12 +68,20 @@ export const treeProps = {
67
68
  */
68
69
  itemHeight: makeStringProp('44px'),
69
70
  indent: makeNumberProp(16),
70
- selectionLeafOnly: makeBooleanProp(false)
71
+ selectionLeafOnly: makeBooleanProp(false),
72
+ filterMethod: {
73
+ type: Function as PropType<(keyword: string, node: RawTreeNode) => boolean>,
74
+ default: null
75
+ },
76
+ showFilter: makeBooleanProp(false),
77
+ filterPlaceholder: makeStringProp('请输入节点名称')
71
78
  }
72
79
  export type TreeExpose = {
73
80
  toggleExpand: (node: TreeNode, flag: boolean) => void
74
81
  toggleChecked: (node: TreeNode, flag: boolean, isClick: boolean) => void
75
82
  getNodeById: (id: string | number) => TreeNode | undefined
83
+ getCheckedNodes: () => TreeNode[] | any
84
+ getCurrentNode: () => TreeNode | undefined
76
85
  useTree: () => Tree
77
86
  getTree: () => Ref<Tree>
78
87
  scrollToTop: () => void
@@ -80,6 +89,7 @@ export type TreeExpose = {
80
89
  scrollToPosition: (position: number | string) => void
81
90
  scrollToElement: (item: any) => void
82
91
  scrollToElementById: (id: string | number) => void
92
+ filter: (keyword: string) => void
83
93
  }
84
94
  export type TreeProps = ExtractPropTypes<typeof treeProps>
85
95
  export type TreeInstance = ComponentPublicInstance<TreeProps, TreeExpose>
@@ -0,0 +1,18 @@
1
+ @import '../common/abstracts/variable';
2
+ @import '../common/abstracts/mixin';
3
+
4
+ @include b(waterfall) {
5
+ overflow: hidden;
6
+ @include e(wrapper) {
7
+ height: 100%;
8
+ overflow: hidden;
9
+ }
10
+ @include e(container) {
11
+ display: flex;
12
+ flex-direction: row;
13
+ overflow: hidden;
14
+ }
15
+ @include e(column) {
16
+ flex: 1;
17
+ }
18
+ }