wui-components-v2 1.1.70 → 1.1.72

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 (82) hide show
  1. package/api/feishu.ts +20 -20
  2. package/api/index.ts +4 -4
  3. package/api/login.ts +51 -51
  4. package/api/tree.ts +28 -28
  5. package/components/action-popup/action-popup.vue +116 -116
  6. package/components/add-address-list/add-address-list.vue +187 -187
  7. package/components/add-address-page/config.ts +297 -297
  8. package/components/audio-play/audio-play.vue +220 -220
  9. package/components/batch-upload-file/batch-upload-file.vue +75 -75
  10. package/components/card-botom-buttons/card-botom-buttons.vue +279 -279
  11. package/components/demo-card/demo-card.vue +44 -44
  12. package/components/fold-card/fold-card.vue +2 -2
  13. package/components/form-control/form-control.vue +9 -1
  14. package/components/global-loading/GlobalLoading.md +366 -366
  15. package/components/global-loading/global-loading.vue +55 -55
  16. package/components/global-message/GlobalMessage.md +570 -570
  17. package/components/global-toast/GlobalToast.md +261 -261
  18. package/components/global-toast/global-toast.vue +56 -56
  19. package/components/label-value/open-value-more.vue +56 -56
  20. package/components/loading/loading.vue +5 -5
  21. package/components/login-form-box/login-form-box.vue +65 -65
  22. package/components/phone-login-form/phone-login-form.vue +204 -204
  23. package/components/privacy-popup/privacy-popup.vue +191 -191
  24. package/components/scan-input/scan-input.vue +406 -406
  25. package/components/select-col-picker/select-col-picker.vue +168 -168
  26. package/components/tab-search/tab-search.vue +73 -73
  27. package/components/tree-select/components/TreeNode.vue +200 -200
  28. package/components/tree-select/components/index.vue +471 -471
  29. package/components/tree-select/components/tree-select.vue +56 -56
  30. package/components/tree-select/index.vue +93 -93
  31. package/components/user-choose/user-choose.vue +169 -151
  32. package/components/video-play/video-play.vue +56 -56
  33. package/components/wui-auto-update-component/wui-auto-update-component.vue +132 -132
  34. package/components/wui-default/wui-default.vue +49 -49
  35. package/components/wui-details-page/wui-details-page.vue +147 -147
  36. package/components/wui-edit-page/wui-edit-page-copy.vue +757 -757
  37. package/components/wui-edit-page/wui-edit-page.vue +793 -793
  38. package/components/wui-login/wui-login.vue +43 -43
  39. package/components/wui-login1/wui-login.vue +41 -41
  40. package/components/wui-menus/wui-menus-top.vue +137 -137
  41. package/components/wui-menus/wui-menus-top1.vue +8 -8
  42. package/components/wui-menus1/components/banner-carousel.vue +320 -320
  43. package/components/wui-menus1/components/quick-panel.vue +55 -55
  44. package/components/wui-menus1/components/search-bar.vue +49 -49
  45. package/components/wui-menus1/components/section-menus.vue +208 -208
  46. package/components/wui-menus1/wui-menus-top.vue +718 -718
  47. package/components/wui-menus1/wui-menus-top1.vue +398 -398
  48. package/components/wui-notify-info/notify-handle.vue +53 -53
  49. package/components/wui-scan-binding-sensor/wui-scan-binding-sensor.vue +75 -75
  50. package/components/wui-search-history-babbar/components/SearchBar.vue +70 -70
  51. package/components/wui-select-list/wui-select-list.vue +1 -9
  52. package/components/wui-select-popup/wui-select-popup.vue +1 -0
  53. package/components/wui-tree-page/wui-tree-page.vue +297 -297
  54. package/components/wui-update-component/wui-update-component.vue +221 -221
  55. package/composables/types/theme.ts +65 -65
  56. package/composables/types/user.ts +5 -5
  57. package/composables/useColorGenerator.ts +221 -221
  58. package/composables/useCompanyFieldFilter.ts +26 -24
  59. package/composables/useEnumes.ts +43 -43
  60. package/composables/useEventBus.ts +37 -37
  61. package/composables/useGlobalLoading.ts +47 -47
  62. package/composables/useGlobalMessage.ts +53 -53
  63. package/composables/useGlobalToast.ts +63 -63
  64. package/composables/useLocale.ts +54 -54
  65. package/composables/useManualTheme.ts +179 -179
  66. package/composables/useSectionMenus.ts +120 -120
  67. package/composables/useTabbar.ts +50 -50
  68. package/composables/useTheme.ts +74 -74
  69. package/composables/useUser.ts +24 -24
  70. package/index.d.ts +90 -90
  71. package/package.json +24 -24
  72. package/store/manualThemeStore.ts +143 -143
  73. package/store/persist.ts +41 -41
  74. package/store/themeStore.ts +74 -74
  75. package/store/userStore.ts +22 -22
  76. package/styles/dark-mode.scss +498 -498
  77. package/type.ts +154 -154
  78. package/utils/control-tree.ts +353 -353
  79. package/utils/eventBus.ts +36 -36
  80. package/utils/idata-scan.ts +99 -99
  81. package/utils/index.ts +979 -979
  82. 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>