wui-components-v2 1.1.69 → 1.1.71

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 (117) hide show
  1. package/api/core/index.ts +74 -74
  2. package/api/feishu.ts +20 -20
  3. package/api/index.ts +4 -4
  4. package/api/login.ts +51 -51
  5. package/api/menu.ts +45 -45
  6. package/api/page.ts +114 -114
  7. package/api/sys.ts +12 -12
  8. package/api/tree.ts +28 -28
  9. package/components/action-popup/action-popup.vue +116 -116
  10. package/components/add-address-list/add-address-list.vue +187 -187
  11. package/components/add-address-page/add-address-page.vue +77 -77
  12. package/components/add-address-page/config.ts +297 -297
  13. package/components/audio-play/audio-play.vue +220 -220
  14. package/components/batch-upload-file/batch-upload-file.vue +75 -75
  15. package/components/card-botom-buttons/card-botom-buttons.vue +279 -279
  16. package/components/custom-date-picker/custom-date-picker.vue +106 -106
  17. package/components/custom-select-picker/custom-select-picker.vue +95 -95
  18. package/components/demo-block/demo-block.vue +63 -63
  19. package/components/demo-card/demo-card.vue +44 -44
  20. package/components/detail-popup/detail-popup.vue +99 -99
  21. package/components/evaluation-page/evaluation-page.vue +196 -196
  22. package/components/fold-card/fold-card.vue +171 -171
  23. package/components/form-control/form-control.vue +661 -661
  24. package/components/global-loading/GlobalLoading.md +366 -366
  25. package/components/global-loading/global-loading.vue +55 -55
  26. package/components/global-message/GlobalMessage.md +570 -570
  27. package/components/global-message/global-message.vue +68 -68
  28. package/components/global-toast/GlobalToast.md +261 -261
  29. package/components/global-toast/global-toast.vue +56 -56
  30. package/components/label-value/label-value.vue +144 -144
  31. package/components/label-value/open-value-more.vue +56 -56
  32. package/components/list-top-buttons/list-top-buttons.vue +19 -19
  33. package/components/loading/loading.vue +5 -5
  34. package/components/login-form/login-form.vue +126 -126
  35. package/components/login-form-box/login-form-box.vue +65 -65
  36. package/components/mulselect-picker/mulselect-picker.vue +86 -86
  37. package/components/phone-login-form/phone-login-form.vue +204 -204
  38. package/components/privacy-popup/privacy-popup.vue +191 -191
  39. package/components/product-card/product-card.vue +201 -201
  40. package/components/scan-input/scan-input.vue +406 -406
  41. package/components/search/search.vue +128 -128
  42. package/components/select-col-picker/select-col-picker.vue +168 -168
  43. package/components/tab-search/tab-search.vue +73 -73
  44. package/components/tree-select/components/TreeNode.vue +200 -200
  45. package/components/tree-select/components/index.vue +471 -471
  46. package/components/tree-select/components/tree-select.vue +56 -56
  47. package/components/tree-select/index.vue +93 -93
  48. package/components/user-choose/user-choose.vue +169 -151
  49. package/components/video-play/video-play.vue +56 -56
  50. package/components/wui-auto-update-component/wui-auto-update-component.vue +132 -132
  51. package/components/wui-default/wui-default.vue +49 -49
  52. package/components/wui-details-page/wui-details-page.vue +147 -147
  53. package/components/wui-edit-page/wui-edit-page-copy.vue +757 -757
  54. package/components/wui-edit-page/wui-edit-page.vue +793 -793
  55. package/components/wui-enume-select-control/wui-enume-select-control.vue +92 -92
  56. package/components/wui-list/wui-list.vue +235 -235
  57. package/components/wui-login/wui-login.vue +43 -43
  58. package/components/wui-login1/wui-login.vue +41 -41
  59. package/components/wui-menus/wui-menus-top.vue +137 -137
  60. package/components/wui-menus/wui-menus-top1.vue +8 -8
  61. package/components/wui-menus/wui-menus.vue +247 -247
  62. package/components/wui-menus1/components/banner-carousel.vue +320 -320
  63. package/components/wui-menus1/components/navbar.vue +43 -43
  64. package/components/wui-menus1/components/quick-panel.vue +55 -55
  65. package/components/wui-menus1/components/search-bar.vue +49 -49
  66. package/components/wui-menus1/components/section-menus.vue +208 -208
  67. package/components/wui-menus1/wui-menus-top.vue +718 -718
  68. package/components/wui-menus1/wui-menus-top1.vue +398 -398
  69. package/components/wui-menus1/wui-menus.vue +564 -564
  70. package/components/wui-notify-info/notify-handle.vue +53 -53
  71. package/components/wui-notify-info/wui-notify-info.vue +280 -280
  72. package/components/wui-scan-binding-sensor/wui-scan-binding-sensor.vue +75 -75
  73. package/components/wui-search-history-babbar/components/SearchBar.vue +70 -70
  74. package/components/wui-search-history-babbar/wui-search-history-babbar.vue +204 -204
  75. package/components/wui-select-list/wui-select-list.vue +310 -310
  76. package/components/wui-select-popup/wui-select-popup.vue +613 -612
  77. package/components/wui-system-settings/wui-system-settings.vue +144 -144
  78. package/components/wui-tabbar/wui-tabbar.vue +106 -106
  79. package/components/wui-tree-page/components/tree-item.vue +238 -238
  80. package/components/wui-tree-page/wui-tree-page.vue +297 -297
  81. package/components/wui-update-component/wui-update-component.vue +221 -221
  82. package/components/wui-user/wui-user.vue +202 -202
  83. package/composables/types/theme.ts +65 -65
  84. package/composables/types/user.ts +5 -5
  85. package/composables/useColorGenerator.ts +221 -221
  86. package/composables/useCompanyFieldFilter.ts +91 -91
  87. package/composables/useEnumes.ts +43 -43
  88. package/composables/useEventBus.ts +37 -37
  89. package/composables/useGlobalLoading.ts +47 -47
  90. package/composables/useGlobalMessage.ts +53 -53
  91. package/composables/useGlobalToast.ts +63 -63
  92. package/composables/useLocale.ts +54 -54
  93. package/composables/useManualTheme.ts +179 -179
  94. package/composables/useMenus.ts +193 -193
  95. package/composables/useSectionMenus.ts +120 -120
  96. package/composables/useTabbar.ts +50 -50
  97. package/composables/useTheme.ts +74 -74
  98. package/composables/useUser.ts +24 -24
  99. package/index.d.ts +90 -90
  100. package/index.ts +83 -83
  101. package/package.json +24 -24
  102. package/static/iconfont/iconfont.css +63 -63
  103. package/store/language.ts +151 -151
  104. package/store/manualThemeStore.ts +143 -143
  105. package/store/persist.ts +41 -41
  106. package/store/themeStore.ts +74 -74
  107. package/store/userStore.ts +22 -22
  108. package/styles/dark-mode.css +523 -523
  109. package/styles/dark-mode.min.css +1 -1
  110. package/styles/dark-mode.scss +498 -498
  111. package/type.ts +154 -154
  112. package/utils/control-tree.ts +353 -353
  113. package/utils/control-type-supportor.ts +148 -148
  114. package/utils/eventBus.ts +36 -36
  115. package/utils/idata-scan.ts +99 -99
  116. package/utils/index.ts +979 -979
  117. package/utils/rsaEncrypt.ts +10 -10
@@ -1,297 +1,297 @@
1
- <script lang="ts" setup>
2
- import { computed, defineOptions, onMounted, onUnmounted, ref } from 'vue'
3
- import { onLoad } from '@dcloudio/uni-app'
4
- import { useDialog } from '@wot-ui/ui'
5
- import { useGlobalLoading } from '../../composables/useGlobalLoading'
6
- import { useGlobalToast } from '../../composables/useGlobalToast'
7
- import ListTopButtons from '../list-top-buttons/list-top-buttons.vue'
8
- import { useTreeControlInit } from '../../utils/control-tree'
9
- import type { TreeNode, nodeType } from '../../utils/control-tree'
10
- import { generateHighResolutionID } from '../../utils/index'
11
- import { treeNodeDeleteApi } from '../../api/tree'
12
- import treeItem from './components/tree-item.vue'
13
-
14
- defineOptions({
15
- name: 'WuiTreePage',
16
- })
17
- // --- 数据定义 ---
18
- const searchText = ref('')
19
- const sourceId = ref('')
20
- const pageTitle = ref('')
21
- const mainCode = ref('')
22
- const addEvent = generateHighResolutionID()// 全局事件名称
23
- const Zpaging = ref<any>(null)
24
- const dialog = useDialog()
25
- const parentId = ref('')
26
- const parentNodeType = ref<nodeType>('root')
27
- const targetNodeType = ref<nodeType>('root')
28
- const { loading } = useGlobalLoading()
29
- const { success, error } = useGlobalToast()
30
-
31
- onLoad((option: any) => {
32
- console.log(option)
33
- sourceId.value = option.sourceId
34
- pageTitle.value = option.title
35
- mainCode.value = option.mainCode || ''
36
- uni.setNavigationBarTitle({
37
- title: option.title,
38
- })
39
- })
40
-
41
- const { treeConfig, treeData, findTreeNodeandExpand, getTreeRootData } = useTreeControlInit(sourceId.value, Zpaging)
42
-
43
- onMounted(async () => {
44
- // 监听添加成功的事件
45
- uni.$on(addEvent, async (e) => {
46
- console.log(e)
47
- // findTreeNodeandAppend(parentId.value, treeData.value, [{
48
- // id: e.entityCode,
49
- // parentId: parentId.value,
50
- // label: e.data[targetNodeType.value === 'branch' && treeConfig.value.branchLTmplConfig ? treeConfig.value.branchLTmplConfig.primaryColumn.sourceId : targetNodeType.value === 'leaf' && treeConfig.value.leafLTmplConfig? treeConfig.value.leafLTmplConfig.primaryColumn.sourceId : treeConfig.value.rootLTmplConfig.primaryColumn.sourceId],
51
- // expanded: false,
52
- // type: targetNodeType.value,
53
- // loading: false,
54
- // children: null,
55
- // }], parentNodeType.value)
56
- findTreeNodeandExpand({
57
- id: parentId.value,
58
- type: parentNodeType.value,
59
- parentId: '',
60
- label: '',
61
- expanded: false,
62
- loading: false,
63
- }, treeData.value, 'add')
64
- // Zpaging.value.reload()
65
- })
66
- })
67
- // 在组件卸载时解绑全局事件
68
- onUnmounted(() => {
69
- console.log(`${pageTitle.value}页面卸载`)
70
- uni.$off(addEvent)
71
- })
72
-
73
- function toggleExpand(node: TreeNode) {
74
- // 展开节点
75
- findTreeNodeandExpand(node, treeData.value)
76
- }
77
-
78
- // 添加分支节点
79
- function handleAddBranch(parentNode: TreeNode) {
80
- console.log('添加子节点:', parentNode)
81
- parentId.value = parentNode.id
82
- parentNodeType.value = parentNode.type
83
- targetNodeType.value = 'branch'
84
- uni.navigateTo({
85
- url: `/pages/edit-page/index?sourceId=${treeConfig.value.branchRatmplId}&title=${pageTitle.value}&mainCode=${parentNode.id}&addEvent=${addEvent}`,
86
- })
87
- }
88
- // 添加叶子节点
89
- function handleAddLeaf(parentNode: TreeNode) {
90
- console.log('添加叶子节点:', parentNode)
91
- parentId.value = parentNode.id
92
- parentNodeType.value = parentNode.type
93
- targetNodeType.value = 'leaf'
94
- uni.navigateTo({
95
- url: `/pages/edit-page/index?sourceId=${treeConfig.value.leafRatmplId}&title=${pageTitle.value}&mainCode=${parentNode.id}&addEvent=${addEvent}`,
96
- })
97
- }
98
-
99
- // 处理更新节点
100
- function handleUpdate(targetNode: TreeNode) {
101
- let sourceId = null
102
- if (targetNode.type === 'leaf') {
103
- sourceId = treeConfig.value.leafRatmplId
104
- }
105
- else if (targetNode.type === 'branch') {
106
- sourceId = treeConfig.value.branchRatmplId
107
- }
108
- else {
109
- sourceId = treeConfig.value.rootGtmplId
110
- }
111
-
112
- uni.navigateTo({
113
- url: `/pages/edit-page/index?sourceId=${sourceId}&title=${pageTitle.value}&id=${targetNode.id}&mainCode=${targetNode.parentId}&addEvent=${addEvent}`,
114
- })
115
- }
116
-
117
- // 过滤后的树形数据
118
- const filteredTreeData = computed<TreeNode[]>(() => {
119
- if (!searchText.value) {
120
- return treeData.value
121
- }
122
-
123
- const keyword = searchText.value.toLowerCase()
124
-
125
- // 过滤节点的递归函数
126
- const filterNodes = (nodes: TreeNode[]): TreeNode[] => {
127
- return nodes
128
- .map((node) => {
129
- // 复制节点,避免修改原数据
130
- const newNode = { ...node }
131
-
132
- // 如果有子节点,递归过滤
133
- // if (newNode.children && newNode.children.length > 0) {
134
- // newNode.children = filterNodes(newNode.children)
135
- // }
136
-
137
- // 节点名称包含关键词,或者有符合条件的子节点,则保留该节点
138
- const nodeNameMatch = newNode.label.toLowerCase().includes(keyword)
139
- // const hasMatchingChildren = newNode.children && newNode.children.length > 0
140
-
141
- // return nodeNameMatch || hasMatchingChildren ? newNode : null
142
- return nodeNameMatch ? newNode : null
143
- })
144
- .filter(Boolean) as TreeNode[]
145
- }
146
- console.log('filterNodes:', filterNodes(treeData.value))
147
-
148
- return filterNodes(treeData.value)
149
- })
150
- // 删除节点
151
- function handleRemove(targetNode: TreeNode) {
152
- let sourceId = treeConfig.value.rootGtmplId
153
- if (targetNode.type === 'leaf') {
154
- sourceId = treeConfig.value.leafRatmplId || ''
155
- }
156
-
157
- if (targetNode.type === 'branch') {
158
- sourceId = treeConfig.value.branchRatmplId || ''
159
- }
160
-
161
- dialog
162
- .confirm({
163
- msg: `确定要删除 "${targetNode.label}" 及其子节点吗?`,
164
- title: '提示',
165
- beforeConfirm: async () => {
166
- loading('删除中...')
167
- try {
168
- // const res = await editPageConfig(sourceId || '', targetNode.id)
169
- // const res1 = await editPageDataSave(sourceId || '', targetNode.id, {}, '', res.dtmplConfig.actions[0].id)
170
- const res1 = await treeNodeDeleteApi(sourceId, targetNode.id)
171
- if (res1.status === 'success') {
172
- success('删除成功')
173
- removeNodeRecursively(filteredTreeData.value, targetNode.id)
174
- return true
175
- }
176
- else {
177
- error('删除失败')
178
- return false
179
- }
180
- }
181
- catch (error1) {
182
- error('删除失败')
183
- console.log(error1)
184
- return false
185
- }
186
- },
187
- })
188
- .then(() => { })
189
- .catch((error) => {
190
- console.log(error)
191
- })
192
- }
193
-
194
- // 递归删除逻辑
195
- function removeNodeRecursively(list: TreeNode[], idToRemove: string): boolean {
196
- for (let i = 0; i < list.length; i++) {
197
- if (list[i].id === idToRemove) {
198
- list.splice(i, 1)
199
- return true
200
- }
201
-
202
- const children = list[i].children
203
- if (Array.isArray(children) && children.length > 0) {
204
- const deleted = removeNodeRecursively(children, idToRemove)
205
- if (deleted)
206
- return true
207
- }
208
- }
209
- return false
210
- }
211
-
212
- // --- 搜索逻辑 ---
213
- /*
214
- 搜索策略:
215
- 1. 遍历树。
216
- 2. 如果节点名称包含关键字,标记高亮(通过prop传给子组件)。
217
- 3. 如果节点包含关键字,或者其子孙节点包含关键字,则该节点必须展开 (expanded = true)。
218
- */
219
- function handleSearch() {
220
- const keyword = searchText.value.trim().toLowerCase()
221
-
222
- if (!keyword)
223
- return
224
-
225
- // 定义递归搜索函数
226
- const traverseAndExpand = (nodes: TreeNode[]) => {
227
- let hasMatchInLevel = false
228
-
229
- nodes.forEach((node) => {
230
- // 检查当前节点是否匹配
231
- const isSelfMatch = node.label.toLowerCase().includes(keyword)
232
-
233
- // 递归检查子节点
234
- let hasChildMatch = false
235
- if (node.children && node.children.length > 0) {
236
- hasChildMatch = traverseAndExpand(node.children)
237
- }
238
-
239
- // 核心逻辑:如果自己匹配,或子节点有匹配,则当前路径应激活/展开
240
- if (isSelfMatch || hasChildMatch) {
241
- // node.expanded = true;
242
- hasMatchInLevel = true
243
- }
244
- else {
245
- // 如果不是搜索状态,可以选择收起,这里为了体验保留原状或强制收起均可
246
- // node.expanded = false; // 取消注释则未匹配路径会自动收起
247
- }
248
- })
249
-
250
- return hasMatchInLevel
251
- }
252
-
253
- traverseAndExpand(treeData.value)
254
- }
255
- </script>
256
-
257
- <template>
258
- <z-paging
259
- v-if="treeConfig.id" ref="Zpaging" v-model="filteredTreeData" :auto-show-system-loading="true"
260
- :loading-more-enabled="false" :show-loading-more-when-reload="false"
261
- :to-bottom-loading-more-enabled="false" @query="() => { getTreeRootData(treeConfig.id) }"
262
- >
263
- <template #top>
264
- <wd-search v-model="searchText" hide-cancel @change="handleSearch" />
265
- <view>
266
- <ListTopButtons
267
- :add-event="addEvent" :main-code="mainCode" :buttons="treeConfig.rootLTmplConfig.buttons"
268
- :source-id="treeConfig.rootGtmplId" :page-title="pageTitle" page-type="列表"
269
- />
270
- </view>
271
- </template>
272
- <view class="container">
273
- <!-- 树形内容 -->
274
- <view class="tree-container">
275
- <tree-item
276
- v-for="item in filteredTreeData" :key="item.id" :node="item" :search-keyword="searchText"
277
- :leaf-ratmpl-id="treeConfig.leafRatmplId" @add-leaf="handleAddLeaf" @add-branch="handleAddBranch"
278
- @remove="handleRemove" @update="handleUpdate" @toggle-expand="toggleExpand"
279
- />
280
- </view>
281
- </view>
282
- <wd-dialog />
283
- </z-paging>
284
- </template>
285
-
286
- <style>
287
- .container {
288
- display: flex;
289
- flex-direction: column;
290
- /* height: 100vh; */
291
- }
292
-
293
- .tree-container {
294
- flex: 1;
295
- overflow: hidden;
296
- }
297
- </style>
1
+ <script lang="ts" setup>
2
+ import { computed, defineOptions, onMounted, onUnmounted, ref } from 'vue'
3
+ import { onLoad } from '@dcloudio/uni-app'
4
+ import { useDialog } from '@wot-ui/ui'
5
+ import { useGlobalLoading } from '../../composables/useGlobalLoading'
6
+ import { useGlobalToast } from '../../composables/useGlobalToast'
7
+ import ListTopButtons from '../list-top-buttons/list-top-buttons.vue'
8
+ import { useTreeControlInit } from '../../utils/control-tree'
9
+ import type { TreeNode, nodeType } from '../../utils/control-tree'
10
+ import { generateHighResolutionID } from '../../utils/index'
11
+ import { treeNodeDeleteApi } from '../../api/tree'
12
+ import treeItem from './components/tree-item.vue'
13
+
14
+ defineOptions({
15
+ name: 'WuiTreePage',
16
+ })
17
+ // --- 数据定义 ---
18
+ const searchText = ref('')
19
+ const sourceId = ref('')
20
+ const pageTitle = ref('')
21
+ const mainCode = ref('')
22
+ const addEvent = generateHighResolutionID()// 全局事件名称
23
+ const Zpaging = ref<any>(null)
24
+ const dialog = useDialog()
25
+ const parentId = ref('')
26
+ const parentNodeType = ref<nodeType>('root')
27
+ const targetNodeType = ref<nodeType>('root')
28
+ const { loading } = useGlobalLoading()
29
+ const { success, error } = useGlobalToast()
30
+
31
+ onLoad((option: any) => {
32
+ console.log(option)
33
+ sourceId.value = option.sourceId
34
+ pageTitle.value = option.title
35
+ mainCode.value = option.mainCode || ''
36
+ uni.setNavigationBarTitle({
37
+ title: option.title,
38
+ })
39
+ })
40
+
41
+ const { treeConfig, treeData, findTreeNodeandExpand, getTreeRootData } = useTreeControlInit(sourceId.value, Zpaging)
42
+
43
+ onMounted(async () => {
44
+ // 监听添加成功的事件
45
+ uni.$on(addEvent, async (e) => {
46
+ console.log(e)
47
+ // findTreeNodeandAppend(parentId.value, treeData.value, [{
48
+ // id: e.entityCode,
49
+ // parentId: parentId.value,
50
+ // label: e.data[targetNodeType.value === 'branch' && treeConfig.value.branchLTmplConfig ? treeConfig.value.branchLTmplConfig.primaryColumn.sourceId : targetNodeType.value === 'leaf' && treeConfig.value.leafLTmplConfig? treeConfig.value.leafLTmplConfig.primaryColumn.sourceId : treeConfig.value.rootLTmplConfig.primaryColumn.sourceId],
51
+ // expanded: false,
52
+ // type: targetNodeType.value,
53
+ // loading: false,
54
+ // children: null,
55
+ // }], parentNodeType.value)
56
+ findTreeNodeandExpand({
57
+ id: parentId.value,
58
+ type: parentNodeType.value,
59
+ parentId: '',
60
+ label: '',
61
+ expanded: false,
62
+ loading: false,
63
+ }, treeData.value, 'add')
64
+ // Zpaging.value.reload()
65
+ })
66
+ })
67
+ // 在组件卸载时解绑全局事件
68
+ onUnmounted(() => {
69
+ console.log(`${pageTitle.value}页面卸载`)
70
+ uni.$off(addEvent)
71
+ })
72
+
73
+ function toggleExpand(node: TreeNode) {
74
+ // 展开节点
75
+ findTreeNodeandExpand(node, treeData.value)
76
+ }
77
+
78
+ // 添加分支节点
79
+ function handleAddBranch(parentNode: TreeNode) {
80
+ console.log('添加子节点:', parentNode)
81
+ parentId.value = parentNode.id
82
+ parentNodeType.value = parentNode.type
83
+ targetNodeType.value = 'branch'
84
+ uni.navigateTo({
85
+ url: `/pages/edit-page/index?sourceId=${treeConfig.value.branchRatmplId}&title=${pageTitle.value}&mainCode=${parentNode.id}&addEvent=${addEvent}`,
86
+ })
87
+ }
88
+ // 添加叶子节点
89
+ function handleAddLeaf(parentNode: TreeNode) {
90
+ console.log('添加叶子节点:', parentNode)
91
+ parentId.value = parentNode.id
92
+ parentNodeType.value = parentNode.type
93
+ targetNodeType.value = 'leaf'
94
+ uni.navigateTo({
95
+ url: `/pages/edit-page/index?sourceId=${treeConfig.value.leafRatmplId}&title=${pageTitle.value}&mainCode=${parentNode.id}&addEvent=${addEvent}`,
96
+ })
97
+ }
98
+
99
+ // 处理更新节点
100
+ function handleUpdate(targetNode: TreeNode) {
101
+ let sourceId = null
102
+ if (targetNode.type === 'leaf') {
103
+ sourceId = treeConfig.value.leafRatmplId
104
+ }
105
+ else if (targetNode.type === 'branch') {
106
+ sourceId = treeConfig.value.branchRatmplId
107
+ }
108
+ else {
109
+ sourceId = treeConfig.value.rootGtmplId
110
+ }
111
+
112
+ uni.navigateTo({
113
+ url: `/pages/edit-page/index?sourceId=${sourceId}&title=${pageTitle.value}&id=${targetNode.id}&mainCode=${targetNode.parentId}&addEvent=${addEvent}`,
114
+ })
115
+ }
116
+
117
+ // 过滤后的树形数据
118
+ const filteredTreeData = computed<TreeNode[]>(() => {
119
+ if (!searchText.value) {
120
+ return treeData.value
121
+ }
122
+
123
+ const keyword = searchText.value.toLowerCase()
124
+
125
+ // 过滤节点的递归函数
126
+ const filterNodes = (nodes: TreeNode[]): TreeNode[] => {
127
+ return nodes
128
+ .map((node) => {
129
+ // 复制节点,避免修改原数据
130
+ const newNode = { ...node }
131
+
132
+ // 如果有子节点,递归过滤
133
+ // if (newNode.children && newNode.children.length > 0) {
134
+ // newNode.children = filterNodes(newNode.children)
135
+ // }
136
+
137
+ // 节点名称包含关键词,或者有符合条件的子节点,则保留该节点
138
+ const nodeNameMatch = newNode.label.toLowerCase().includes(keyword)
139
+ // const hasMatchingChildren = newNode.children && newNode.children.length > 0
140
+
141
+ // return nodeNameMatch || hasMatchingChildren ? newNode : null
142
+ return nodeNameMatch ? newNode : null
143
+ })
144
+ .filter(Boolean) as TreeNode[]
145
+ }
146
+ console.log('filterNodes:', filterNodes(treeData.value))
147
+
148
+ return filterNodes(treeData.value)
149
+ })
150
+ // 删除节点
151
+ function handleRemove(targetNode: TreeNode) {
152
+ let sourceId = treeConfig.value.rootGtmplId
153
+ if (targetNode.type === 'leaf') {
154
+ sourceId = treeConfig.value.leafRatmplId || ''
155
+ }
156
+
157
+ if (targetNode.type === 'branch') {
158
+ sourceId = treeConfig.value.branchRatmplId || ''
159
+ }
160
+
161
+ dialog
162
+ .confirm({
163
+ msg: `确定要删除 "${targetNode.label}" 及其子节点吗?`,
164
+ title: '提示',
165
+ beforeConfirm: async () => {
166
+ loading('删除中...')
167
+ try {
168
+ // const res = await editPageConfig(sourceId || '', targetNode.id)
169
+ // const res1 = await editPageDataSave(sourceId || '', targetNode.id, {}, '', res.dtmplConfig.actions[0].id)
170
+ const res1 = await treeNodeDeleteApi(sourceId, targetNode.id)
171
+ if (res1.status === 'success') {
172
+ success('删除成功')
173
+ removeNodeRecursively(filteredTreeData.value, targetNode.id)
174
+ return true
175
+ }
176
+ else {
177
+ error('删除失败')
178
+ return false
179
+ }
180
+ }
181
+ catch (error1) {
182
+ error('删除失败')
183
+ console.log(error1)
184
+ return false
185
+ }
186
+ },
187
+ })
188
+ .then(() => { })
189
+ .catch((error) => {
190
+ console.log(error)
191
+ })
192
+ }
193
+
194
+ // 递归删除逻辑
195
+ function removeNodeRecursively(list: TreeNode[], idToRemove: string): boolean {
196
+ for (let i = 0; i < list.length; i++) {
197
+ if (list[i].id === idToRemove) {
198
+ list.splice(i, 1)
199
+ return true
200
+ }
201
+
202
+ const children = list[i].children
203
+ if (Array.isArray(children) && children.length > 0) {
204
+ const deleted = removeNodeRecursively(children, idToRemove)
205
+ if (deleted)
206
+ return true
207
+ }
208
+ }
209
+ return false
210
+ }
211
+
212
+ // --- 搜索逻辑 ---
213
+ /*
214
+ 搜索策略:
215
+ 1. 遍历树。
216
+ 2. 如果节点名称包含关键字,标记高亮(通过prop传给子组件)。
217
+ 3. 如果节点包含关键字,或者其子孙节点包含关键字,则该节点必须展开 (expanded = true)。
218
+ */
219
+ function handleSearch() {
220
+ const keyword = searchText.value.trim().toLowerCase()
221
+
222
+ if (!keyword)
223
+ return
224
+
225
+ // 定义递归搜索函数
226
+ const traverseAndExpand = (nodes: TreeNode[]) => {
227
+ let hasMatchInLevel = false
228
+
229
+ nodes.forEach((node) => {
230
+ // 检查当前节点是否匹配
231
+ const isSelfMatch = node.label.toLowerCase().includes(keyword)
232
+
233
+ // 递归检查子节点
234
+ let hasChildMatch = false
235
+ if (node.children && node.children.length > 0) {
236
+ hasChildMatch = traverseAndExpand(node.children)
237
+ }
238
+
239
+ // 核心逻辑:如果自己匹配,或子节点有匹配,则当前路径应激活/展开
240
+ if (isSelfMatch || hasChildMatch) {
241
+ // node.expanded = true;
242
+ hasMatchInLevel = true
243
+ }
244
+ else {
245
+ // 如果不是搜索状态,可以选择收起,这里为了体验保留原状或强制收起均可
246
+ // node.expanded = false; // 取消注释则未匹配路径会自动收起
247
+ }
248
+ })
249
+
250
+ return hasMatchInLevel
251
+ }
252
+
253
+ traverseAndExpand(treeData.value)
254
+ }
255
+ </script>
256
+
257
+ <template>
258
+ <z-paging
259
+ v-if="treeConfig.id" ref="Zpaging" v-model="filteredTreeData" :auto-show-system-loading="true"
260
+ :loading-more-enabled="false" :show-loading-more-when-reload="false"
261
+ :to-bottom-loading-more-enabled="false" @query="() => { getTreeRootData(treeConfig.id) }"
262
+ >
263
+ <template #top>
264
+ <wd-search v-model="searchText" hide-cancel @change="handleSearch" />
265
+ <view>
266
+ <ListTopButtons
267
+ :add-event="addEvent" :main-code="mainCode" :buttons="treeConfig.rootLTmplConfig.buttons"
268
+ :source-id="treeConfig.rootGtmplId" :page-title="pageTitle" page-type="列表"
269
+ />
270
+ </view>
271
+ </template>
272
+ <view class="container">
273
+ <!-- 树形内容 -->
274
+ <view class="tree-container">
275
+ <tree-item
276
+ v-for="item in filteredTreeData" :key="item.id" :node="item" :search-keyword="searchText"
277
+ :leaf-ratmpl-id="treeConfig.leafRatmplId" @add-leaf="handleAddLeaf" @add-branch="handleAddBranch"
278
+ @remove="handleRemove" @update="handleUpdate" @toggle-expand="toggleExpand"
279
+ />
280
+ </view>
281
+ </view>
282
+ <wd-dialog />
283
+ </z-paging>
284
+ </template>
285
+
286
+ <style>
287
+ .container {
288
+ display: flex;
289
+ flex-direction: column;
290
+ /* height: 100vh; */
291
+ }
292
+
293
+ .tree-container {
294
+ flex: 1;
295
+ overflow: hidden;
296
+ }
297
+ </style>