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.
- package/api/core/index.ts +74 -74
- package/api/feishu.ts +20 -20
- package/api/index.ts +4 -4
- package/api/login.ts +51 -51
- package/api/menu.ts +45 -45
- package/api/page.ts +114 -114
- package/api/sys.ts +12 -12
- package/api/tree.ts +28 -28
- package/components/action-popup/action-popup.vue +116 -116
- package/components/add-address-list/add-address-list.vue +187 -187
- package/components/add-address-page/add-address-page.vue +77 -77
- package/components/add-address-page/config.ts +297 -297
- package/components/audio-play/audio-play.vue +220 -220
- package/components/batch-upload-file/batch-upload-file.vue +75 -75
- package/components/card-botom-buttons/card-botom-buttons.vue +279 -279
- package/components/custom-date-picker/custom-date-picker.vue +106 -106
- package/components/custom-select-picker/custom-select-picker.vue +95 -95
- package/components/demo-block/demo-block.vue +63 -63
- package/components/demo-card/demo-card.vue +44 -44
- package/components/detail-popup/detail-popup.vue +99 -99
- package/components/evaluation-page/evaluation-page.vue +196 -196
- package/components/fold-card/fold-card.vue +171 -171
- package/components/form-control/form-control.vue +661 -661
- package/components/global-loading/GlobalLoading.md +366 -366
- package/components/global-loading/global-loading.vue +55 -55
- package/components/global-message/GlobalMessage.md +570 -570
- package/components/global-message/global-message.vue +68 -68
- package/components/global-toast/GlobalToast.md +261 -261
- package/components/global-toast/global-toast.vue +56 -56
- package/components/label-value/label-value.vue +144 -144
- package/components/label-value/open-value-more.vue +56 -56
- package/components/list-top-buttons/list-top-buttons.vue +19 -19
- package/components/loading/loading.vue +5 -5
- package/components/login-form/login-form.vue +126 -126
- package/components/login-form-box/login-form-box.vue +65 -65
- package/components/mulselect-picker/mulselect-picker.vue +86 -86
- package/components/phone-login-form/phone-login-form.vue +204 -204
- package/components/privacy-popup/privacy-popup.vue +191 -191
- package/components/product-card/product-card.vue +201 -201
- package/components/scan-input/scan-input.vue +406 -406
- package/components/search/search.vue +128 -128
- package/components/select-col-picker/select-col-picker.vue +168 -168
- package/components/tab-search/tab-search.vue +73 -73
- package/components/tree-select/components/TreeNode.vue +200 -200
- package/components/tree-select/components/index.vue +471 -471
- package/components/tree-select/components/tree-select.vue +56 -56
- package/components/tree-select/index.vue +93 -93
- package/components/user-choose/user-choose.vue +169 -151
- package/components/video-play/video-play.vue +56 -56
- package/components/wui-auto-update-component/wui-auto-update-component.vue +132 -132
- package/components/wui-default/wui-default.vue +49 -49
- package/components/wui-details-page/wui-details-page.vue +147 -147
- package/components/wui-edit-page/wui-edit-page-copy.vue +757 -757
- package/components/wui-edit-page/wui-edit-page.vue +793 -793
- package/components/wui-enume-select-control/wui-enume-select-control.vue +92 -92
- package/components/wui-list/wui-list.vue +235 -235
- package/components/wui-login/wui-login.vue +43 -43
- package/components/wui-login1/wui-login.vue +41 -41
- package/components/wui-menus/wui-menus-top.vue +137 -137
- package/components/wui-menus/wui-menus-top1.vue +8 -8
- package/components/wui-menus/wui-menus.vue +247 -247
- package/components/wui-menus1/components/banner-carousel.vue +320 -320
- package/components/wui-menus1/components/navbar.vue +43 -43
- package/components/wui-menus1/components/quick-panel.vue +55 -55
- package/components/wui-menus1/components/search-bar.vue +49 -49
- package/components/wui-menus1/components/section-menus.vue +208 -208
- package/components/wui-menus1/wui-menus-top.vue +718 -718
- package/components/wui-menus1/wui-menus-top1.vue +398 -398
- package/components/wui-menus1/wui-menus.vue +564 -564
- package/components/wui-notify-info/notify-handle.vue +53 -53
- package/components/wui-notify-info/wui-notify-info.vue +280 -280
- package/components/wui-scan-binding-sensor/wui-scan-binding-sensor.vue +75 -75
- package/components/wui-search-history-babbar/components/SearchBar.vue +70 -70
- package/components/wui-search-history-babbar/wui-search-history-babbar.vue +204 -204
- package/components/wui-select-list/wui-select-list.vue +310 -310
- package/components/wui-select-popup/wui-select-popup.vue +613 -612
- package/components/wui-system-settings/wui-system-settings.vue +144 -144
- package/components/wui-tabbar/wui-tabbar.vue +106 -106
- package/components/wui-tree-page/components/tree-item.vue +238 -238
- package/components/wui-tree-page/wui-tree-page.vue +297 -297
- package/components/wui-update-component/wui-update-component.vue +221 -221
- package/components/wui-user/wui-user.vue +202 -202
- package/composables/types/theme.ts +65 -65
- package/composables/types/user.ts +5 -5
- package/composables/useColorGenerator.ts +221 -221
- package/composables/useCompanyFieldFilter.ts +91 -91
- package/composables/useEnumes.ts +43 -43
- package/composables/useEventBus.ts +37 -37
- package/composables/useGlobalLoading.ts +47 -47
- package/composables/useGlobalMessage.ts +53 -53
- package/composables/useGlobalToast.ts +63 -63
- package/composables/useLocale.ts +54 -54
- package/composables/useManualTheme.ts +179 -179
- package/composables/useMenus.ts +193 -193
- package/composables/useSectionMenus.ts +120 -120
- package/composables/useTabbar.ts +50 -50
- package/composables/useTheme.ts +74 -74
- package/composables/useUser.ts +24 -24
- package/index.d.ts +90 -90
- package/index.ts +83 -83
- package/package.json +24 -24
- package/static/iconfont/iconfont.css +63 -63
- package/store/language.ts +151 -151
- package/store/manualThemeStore.ts +143 -143
- package/store/persist.ts +41 -41
- package/store/themeStore.ts +74 -74
- package/store/userStore.ts +22 -22
- package/styles/dark-mode.css +523 -523
- package/styles/dark-mode.min.css +1 -1
- package/styles/dark-mode.scss +498 -498
- package/type.ts +154 -154
- package/utils/control-tree.ts +353 -353
- package/utils/control-type-supportor.ts +148 -148
- package/utils/eventBus.ts +36 -36
- package/utils/idata-scan.ts +99 -99
- package/utils/index.ts +979 -979
- package/utils/rsaEncrypt.ts +10 -10
|
@@ -1,471 +1,471 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed, defineEmits, defineOptions, defineProps, onMounted, ref, toRaw } from 'vue'
|
|
3
|
-
import { useManualTheme } from '../../../composables/useManualTheme'
|
|
4
|
-
import { treeConfigApi, treeDataApi, treeNodeDataApi } from '../../../api/tree'
|
|
5
|
-
import { pageConfig } from '../../../api/page'
|
|
6
|
-
import loadingCom from '../../loading/loading.vue'
|
|
7
|
-
import TreeSelect from './tree-select.vue'
|
|
8
|
-
|
|
9
|
-
defineOptions({
|
|
10
|
-
name: 'TreeSelectIndex',
|
|
11
|
-
})
|
|
12
|
-
const props = defineProps<{
|
|
13
|
-
sourceId: string
|
|
14
|
-
selectMode: SelectMode
|
|
15
|
-
}>()
|
|
16
|
-
const emit = defineEmits(['handleConfirm', 'handleClose'])
|
|
17
|
-
// 树形节点数据结构定义
|
|
18
|
-
interface TreeNode {
|
|
19
|
-
id: string
|
|
20
|
-
name: string
|
|
21
|
-
children?: TreeNode[]
|
|
22
|
-
[key: string]: any // 允许其他自定义属性
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const { currentThemeColor } = useManualTheme()
|
|
26
|
-
// 选择模式类型
|
|
27
|
-
type SelectMode = 'single' | 'multiple'
|
|
28
|
-
|
|
29
|
-
// 示例树形数据
|
|
30
|
-
// const treeData: TreeNode[] = [
|
|
31
|
-
// {
|
|
32
|
-
// id: '1',
|
|
33
|
-
// name: '产品管理',
|
|
34
|
-
// children: [
|
|
35
|
-
// {
|
|
36
|
-
// id: '1-1',
|
|
37
|
-
// name: '产品列表',
|
|
38
|
-
// children: [
|
|
39
|
-
// { id: '1-1-1', name: '产品查询' },
|
|
40
|
-
// { id: '1-1-2', name: '产品新增' },
|
|
41
|
-
// { id: '1-1-3', name: '产品编辑' },
|
|
42
|
-
// { id: '1-1-4', name: '产品删除' },
|
|
43
|
-
// ],
|
|
44
|
-
// },
|
|
45
|
-
// {
|
|
46
|
-
// id: '1-2',
|
|
47
|
-
// name: '产品分类',
|
|
48
|
-
// children: [
|
|
49
|
-
// { id: '1-2-1', name: '分类管理' },
|
|
50
|
-
// { id: '1-2-2', name: '分类排序' },
|
|
51
|
-
// ],
|
|
52
|
-
// },
|
|
53
|
-
// ],
|
|
54
|
-
// },
|
|
55
|
-
// {
|
|
56
|
-
// id: '2',
|
|
57
|
-
// name: '订单管理',
|
|
58
|
-
// children: [
|
|
59
|
-
// { id: '2-1', name: '订单列表' },
|
|
60
|
-
// { id: '2-2', name: '订单详情' },
|
|
61
|
-
// { id: '2-3', name: '订单导出' },
|
|
62
|
-
// ],
|
|
63
|
-
// },
|
|
64
|
-
// {
|
|
65
|
-
// id: '3',
|
|
66
|
-
// name: '用户管理',
|
|
67
|
-
// children: [
|
|
68
|
-
// {
|
|
69
|
-
// id: '3-1',
|
|
70
|
-
// name: '用户列表',
|
|
71
|
-
// children: [
|
|
72
|
-
// { id: '3-1-1', name: '用户查询' },
|
|
73
|
-
// { id: '3-1-2', name: '用户编辑' },
|
|
74
|
-
// ],
|
|
75
|
-
// },
|
|
76
|
-
// { id: '3-2', name: '角色管理' },
|
|
77
|
-
// ],
|
|
78
|
-
// },
|
|
79
|
-
// { id: '4', name: '系统设置' },
|
|
80
|
-
// ]
|
|
81
|
-
const treeData = ref<TreeNode[]>([])
|
|
82
|
-
|
|
83
|
-
// 选择模式
|
|
84
|
-
const selectMode = ref<SelectMode>(props.selectMode)
|
|
85
|
-
|
|
86
|
-
// 选中的节点ID
|
|
87
|
-
const selectedKeys = ref<string[]>([])
|
|
88
|
-
// 选中的节点
|
|
89
|
-
const selectedNode = ref<TreeNode[]>([])
|
|
90
|
-
|
|
91
|
-
// 搜索关键词
|
|
92
|
-
const searchKeyword = ref('')
|
|
93
|
-
|
|
94
|
-
// 所有节点的引用,用于滚动定位
|
|
95
|
-
const nodeRefs = ref<Record<string, HTMLElement | null>>({})
|
|
96
|
-
|
|
97
|
-
// 处理选择模式变更
|
|
98
|
-
// function handleModeChange(mode: SelectMode) {
|
|
99
|
-
// // 切换模式时清空选择
|
|
100
|
-
// selectedKeys.value = []
|
|
101
|
-
// }
|
|
102
|
-
const treeConfigs = reactive({
|
|
103
|
-
branchRatmplId: '',
|
|
104
|
-
branchTitle: '',
|
|
105
|
-
id: '',
|
|
106
|
-
rootGtmplId: '',
|
|
107
|
-
primaryColumnId1: '',
|
|
108
|
-
primaryColumnId2: '',
|
|
109
|
-
leafRatmplId: '',
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
const loading = ref(false)
|
|
113
|
-
// 获取配置
|
|
114
|
-
async function treeConfig1() {
|
|
115
|
-
try {
|
|
116
|
-
const res = await treeConfigApi(props.sourceId)
|
|
117
|
-
treeConfigs.branchRatmplId = res.ttmplConfig.branchRatmplId
|
|
118
|
-
treeConfigs.branchTitle = res.ttmplConfig.branchTitle
|
|
119
|
-
treeConfigs.id = res.ttmplConfig.id
|
|
120
|
-
treeConfigs.rootGtmplId = res.ttmplConfig.rootGtmplId
|
|
121
|
-
treeConfigs.leafRatmplId = res.ttmplConfig.leafRatmplId
|
|
122
|
-
treeConfig2(treeConfigs.branchRatmplId)
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
console.log('error:', error)
|
|
126
|
-
// TODO handle the exception
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// 获取配置2
|
|
131
|
-
async function treeConfig2(branchRatmplId: string) {
|
|
132
|
-
try {
|
|
133
|
-
const res1 = await pageConfig(branchRatmplId)
|
|
134
|
-
treeConfigs.primaryColumnId1 = res1.ltmplConfig.primaryColumn.sourceId
|
|
135
|
-
getTreeTopData(treeConfigs.id)
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
console.log('error:', error)
|
|
139
|
-
// TODO handle the exception
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// 根据id找到树节点
|
|
144
|
-
async function findTreeNodeandAppend(id: string, arr: TreeNode[], appendData: any) {
|
|
145
|
-
for (let index = 0; index < arr.length; index++) {
|
|
146
|
-
const element = arr[index]
|
|
147
|
-
if (element.id === id) {
|
|
148
|
-
element.children = appendData.map((item: any) => {
|
|
149
|
-
return {
|
|
150
|
-
id: item.code,
|
|
151
|
-
name: item.fieldMap[treeConfigs.primaryColumnId1],
|
|
152
|
-
children: [],
|
|
153
|
-
}
|
|
154
|
-
})
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
if (element.children)
|
|
158
|
-
findTreeNodeandAppend(id, element.children, appendData)
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// 获取树顶层数据
|
|
164
|
-
async function getTreeTopData(id: string) {
|
|
165
|
-
try {
|
|
166
|
-
loading.value = true
|
|
167
|
-
const res = await treeDataApi(id)
|
|
168
|
-
treeData.value = res.entities.map((item: any) => {
|
|
169
|
-
return {
|
|
170
|
-
id: item.code,
|
|
171
|
-
name: item.fieldMap[treeConfigs.primaryColumnId1],
|
|
172
|
-
children: [],
|
|
173
|
-
}
|
|
174
|
-
})
|
|
175
|
-
}
|
|
176
|
-
catch (error) {
|
|
177
|
-
console.log('error:', error)
|
|
178
|
-
// TODO handle the exception
|
|
179
|
-
}
|
|
180
|
-
finally {
|
|
181
|
-
loading.value = false
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// 获取树节点数据
|
|
186
|
-
async function getTreeNodeData(node: TreeNode) {
|
|
187
|
-
try {
|
|
188
|
-
const res = await treeNodeDataApi(treeConfigs.branchRatmplId, node.id)
|
|
189
|
-
if (!res.entities.length)
|
|
190
|
-
return
|
|
191
|
-
// 追加节点
|
|
192
|
-
findTreeNodeandAppend(node.id, treeData.value, res.entities)
|
|
193
|
-
}
|
|
194
|
-
catch (error) {
|
|
195
|
-
console.log('error:', error)
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function handleToggleExpand(node: TreeNode) {
|
|
200
|
-
getTreeNodeData(node)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
onMounted(() => {
|
|
204
|
-
treeConfig1()
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
// 处理选择变更
|
|
208
|
-
function handleSelectChange(keys: string[], node: TreeNode) {
|
|
209
|
-
selectedNode.value = [node]
|
|
210
|
-
selectedKeys.value = keys
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// 处理标签关闭
|
|
214
|
-
function handleTagClose(key: string) {
|
|
215
|
-
selectedKeys.value = selectedKeys.value.filter(k => k !== key)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// 根据ID获取节点名称
|
|
219
|
-
function getNodeNameByKey(key: string): string {
|
|
220
|
-
const findNode = (nodes: TreeNode[]): TreeNode | null => {
|
|
221
|
-
for (const node of nodes) {
|
|
222
|
-
if (node.id === key) {
|
|
223
|
-
return node
|
|
224
|
-
}
|
|
225
|
-
if (node.children && node.children.length > 0) {
|
|
226
|
-
const found = findNode(node.children)
|
|
227
|
-
if (found)
|
|
228
|
-
return found
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return null
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const node = findNode(treeData.value)
|
|
235
|
-
return node ? node.name : ''
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// 处理搜索
|
|
239
|
-
function handleSearch(keyword?: string) {
|
|
240
|
-
// 搜索逻辑在filteredTreeData计算属性中处理
|
|
241
|
-
if (keyword !== undefined) {
|
|
242
|
-
searchKeyword.value = keyword
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// 过滤后的树形数据
|
|
247
|
-
const filteredTreeData = computed<TreeNode[]>(() => {
|
|
248
|
-
if (!searchKeyword.value) {
|
|
249
|
-
return treeData.value
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const keyword = searchKeyword.value.toLowerCase()
|
|
253
|
-
|
|
254
|
-
// 过滤节点的递归函数
|
|
255
|
-
const filterNodes = (nodes: TreeNode[]): TreeNode[] => {
|
|
256
|
-
return nodes
|
|
257
|
-
.map((node) => {
|
|
258
|
-
// 复制节点,避免修改原数据
|
|
259
|
-
const newNode = { ...node }
|
|
260
|
-
|
|
261
|
-
// 如果有子节点,递归过滤
|
|
262
|
-
if (newNode.children && newNode.children.length > 0) {
|
|
263
|
-
newNode.children = filterNodes(newNode.children)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// 节点名称包含关键词,或者有符合条件的子节点,则保留该节点
|
|
267
|
-
const nodeNameMatch = newNode.name.toLowerCase().includes(keyword)
|
|
268
|
-
const hasMatchingChildren = newNode.children && newNode.children.length > 0
|
|
269
|
-
|
|
270
|
-
return nodeNameMatch || hasMatchingChildren ? newNode : null
|
|
271
|
-
})
|
|
272
|
-
.filter(Boolean) as TreeNode[]
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return filterNodes(treeData.value)
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
// 记录节点引用
|
|
279
|
-
function setNodeRef(id: string, el: HTMLElement | null) {
|
|
280
|
-
if (el) {
|
|
281
|
-
nodeRefs.value[id] = el
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// 滚动到指定节点
|
|
286
|
-
function scrollToNode(id: string) {
|
|
287
|
-
const node = nodeRefs.value[id]
|
|
288
|
-
if (node) {
|
|
289
|
-
node.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
|
290
|
-
// 高亮效果
|
|
291
|
-
node.classList.add('node-highlight')
|
|
292
|
-
setTimeout(() => {
|
|
293
|
-
node.classList.remove('node-highlight')
|
|
294
|
-
}, 2000)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// 页面加载时展开有子节点的节点
|
|
299
|
-
onMounted(() => {
|
|
300
|
-
// 可以在这里添加默认展开逻辑
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
// 确定
|
|
304
|
-
function handleConfirm() {
|
|
305
|
-
emit('handleConfirm', toRaw(selectedKeys.value), toRaw(selectedNode.value), treeConfigs.leafRatmplId)
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// 取消
|
|
309
|
-
function handleClose() {
|
|
310
|
-
emit('handleClose')
|
|
311
|
-
}
|
|
312
|
-
</script>
|
|
313
|
-
|
|
314
|
-
<template>
|
|
315
|
-
<view class="tree-select-page">
|
|
316
|
-
<!-- 选择模式切换 -->
|
|
317
|
-
<!-- <view class="mode-switch-container">
|
|
318
|
-
<view class="mode-label">
|
|
319
|
-
选择模式:
|
|
320
|
-
</view>
|
|
321
|
-
<wd-radio-group
|
|
322
|
-
v-model="selectMode"
|
|
323
|
-
direction="horizontal"
|
|
324
|
-
@change="handleModeChange"
|
|
325
|
-
>
|
|
326
|
-
<wd-radio name="single" label="单选" />
|
|
327
|
-
<wd-radio name="multiple" label="多选" />
|
|
328
|
-
</wd-radio-group>
|
|
329
|
-
</view> -->
|
|
330
|
-
|
|
331
|
-
<!-- 搜索框 -->
|
|
332
|
-
<view class="search-container">
|
|
333
|
-
<wd-search
|
|
334
|
-
v-model="searchKeyword"
|
|
335
|
-
placeholder-class="splaceholderClass"
|
|
336
|
-
placeholder="搜索节点..."
|
|
337
|
-
clearable
|
|
338
|
-
@cancel="handleClose"
|
|
339
|
-
@input="handleSearch"
|
|
340
|
-
@clear="handleSearch"
|
|
341
|
-
/>
|
|
342
|
-
</view>
|
|
343
|
-
<!-- 已选结果 -->
|
|
344
|
-
<view v-if="selectedKeys.length > 0" class="selected-result">
|
|
345
|
-
<view class="result-title">
|
|
346
|
-
已选 {{ selectedKeys.length }} 项:
|
|
347
|
-
</view>
|
|
348
|
-
<view class="result-tags">
|
|
349
|
-
<wd-tag
|
|
350
|
-
v-for="key in selectedKeys"
|
|
351
|
-
:key="key"
|
|
352
|
-
:bg-color="currentThemeColor.primary"
|
|
353
|
-
color="#fff"
|
|
354
|
-
closable
|
|
355
|
-
round
|
|
356
|
-
@close="handleTagClose(key)"
|
|
357
|
-
@click="scrollToNode(key)"
|
|
358
|
-
>
|
|
359
|
-
{{ getNodeNameByKey(key) }}
|
|
360
|
-
</wd-tag>
|
|
361
|
-
</view>
|
|
362
|
-
</view>
|
|
363
|
-
|
|
364
|
-
<!-- 树形选择区域 -->
|
|
365
|
-
<loadingCom v-if="loading" />
|
|
366
|
-
<view v-else class="tree-container">
|
|
367
|
-
<tree-select
|
|
368
|
-
:set-node-ref="setNodeRef"
|
|
369
|
-
:tree-data="filteredTreeData"
|
|
370
|
-
:select-mode="selectMode"
|
|
371
|
-
:selected-keys="selectedKeys"
|
|
372
|
-
@update:selected-keys="handleSelectChange"
|
|
373
|
-
@toggle-expand="handleToggleExpand"
|
|
374
|
-
/>
|
|
375
|
-
|
|
376
|
-
<!-- 空状态 -->
|
|
377
|
-
<view v-if="filteredTreeData.length === 0" class="empty-state">
|
|
378
|
-
<wd-icon name="search" size="48" color="#ccc" />
|
|
379
|
-
<view class="empty-text">
|
|
380
|
-
没有找到匹配的节点
|
|
381
|
-
</view>
|
|
382
|
-
</view>
|
|
383
|
-
</view>
|
|
384
|
-
<view class="h-100px" />
|
|
385
|
-
<!-- 底部按钮 -->
|
|
386
|
-
<view class="fixed bottom-0 left-0 right-0 box-border w-100% flex p-2 bg-white dark:bg-[var(--wot-dark-background)]">
|
|
387
|
-
<wd-button
|
|
388
|
-
custom-class="flex-1"
|
|
389
|
-
type="primary"
|
|
390
|
-
@click="handleConfirm"
|
|
391
|
-
>
|
|
392
|
-
确定
|
|
393
|
-
</wd-button>
|
|
394
|
-
</view>
|
|
395
|
-
</view>
|
|
396
|
-
</template>
|
|
397
|
-
|
|
398
|
-
<style scoped>
|
|
399
|
-
.mode-switch-container {
|
|
400
|
-
padding: 16px;
|
|
401
|
-
/* background-color: #fff; */
|
|
402
|
-
margin-bottom: 10px;
|
|
403
|
-
display: flex;
|
|
404
|
-
align-items: center;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
.mode-label {
|
|
408
|
-
font-size: 14px;
|
|
409
|
-
color: #666;
|
|
410
|
-
margin-right: 12px;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
.tree-container {
|
|
414
|
-
/* background-color: #fff; */
|
|
415
|
-
padding: 10px 0;
|
|
416
|
-
min-height: 300px;
|
|
417
|
-
/* max-height: calc(100vh - 220px); */
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
.empty-state {
|
|
421
|
-
display: flex;
|
|
422
|
-
flex-direction: column;
|
|
423
|
-
align-items: center;
|
|
424
|
-
justify-content: center;
|
|
425
|
-
padding: 40px 0;
|
|
426
|
-
color: #999;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
.empty-text {
|
|
430
|
-
margin-top: 16px;
|
|
431
|
-
font-size: 14px;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
.selected-result {
|
|
435
|
-
/* background-color: #fff; */
|
|
436
|
-
padding: 16px;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
.result-title {
|
|
440
|
-
text-align: left;
|
|
441
|
-
font-size: 14px;
|
|
442
|
-
color: #666;
|
|
443
|
-
margin-bottom: 12px;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
.result-tags {
|
|
447
|
-
display: flex;
|
|
448
|
-
flex-wrap: wrap;
|
|
449
|
-
gap: 8px;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/* 节点高亮动画 */
|
|
453
|
-
.node-highlight {
|
|
454
|
-
animation: highlight 2s ease;
|
|
455
|
-
}
|
|
456
|
-
:deep(.wd-tag__close){
|
|
457
|
-
line-height: 0.8;
|
|
458
|
-
color:#fff;
|
|
459
|
-
}
|
|
460
|
-
:deep(.uni-input-input){
|
|
461
|
-
text-align: left;
|
|
462
|
-
}
|
|
463
|
-
.splaceholderClass{
|
|
464
|
-
text-align: left;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
@keyframes highlight {
|
|
468
|
-
0% { background-color: rgba(64, 158, 255, 0.2); }
|
|
469
|
-
100% { background-color: transparent; }
|
|
470
|
-
}
|
|
471
|
-
</style>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, defineEmits, defineOptions, defineProps, onMounted, ref, toRaw } from 'vue'
|
|
3
|
+
import { useManualTheme } from '../../../composables/useManualTheme'
|
|
4
|
+
import { treeConfigApi, treeDataApi, treeNodeDataApi } from '../../../api/tree'
|
|
5
|
+
import { pageConfig } from '../../../api/page'
|
|
6
|
+
import loadingCom from '../../loading/loading.vue'
|
|
7
|
+
import TreeSelect from './tree-select.vue'
|
|
8
|
+
|
|
9
|
+
defineOptions({
|
|
10
|
+
name: 'TreeSelectIndex',
|
|
11
|
+
})
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
sourceId: string
|
|
14
|
+
selectMode: SelectMode
|
|
15
|
+
}>()
|
|
16
|
+
const emit = defineEmits(['handleConfirm', 'handleClose'])
|
|
17
|
+
// 树形节点数据结构定义
|
|
18
|
+
interface TreeNode {
|
|
19
|
+
id: string
|
|
20
|
+
name: string
|
|
21
|
+
children?: TreeNode[]
|
|
22
|
+
[key: string]: any // 允许其他自定义属性
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { currentThemeColor } = useManualTheme()
|
|
26
|
+
// 选择模式类型
|
|
27
|
+
type SelectMode = 'single' | 'multiple'
|
|
28
|
+
|
|
29
|
+
// 示例树形数据
|
|
30
|
+
// const treeData: TreeNode[] = [
|
|
31
|
+
// {
|
|
32
|
+
// id: '1',
|
|
33
|
+
// name: '产品管理',
|
|
34
|
+
// children: [
|
|
35
|
+
// {
|
|
36
|
+
// id: '1-1',
|
|
37
|
+
// name: '产品列表',
|
|
38
|
+
// children: [
|
|
39
|
+
// { id: '1-1-1', name: '产品查询' },
|
|
40
|
+
// { id: '1-1-2', name: '产品新增' },
|
|
41
|
+
// { id: '1-1-3', name: '产品编辑' },
|
|
42
|
+
// { id: '1-1-4', name: '产品删除' },
|
|
43
|
+
// ],
|
|
44
|
+
// },
|
|
45
|
+
// {
|
|
46
|
+
// id: '1-2',
|
|
47
|
+
// name: '产品分类',
|
|
48
|
+
// children: [
|
|
49
|
+
// { id: '1-2-1', name: '分类管理' },
|
|
50
|
+
// { id: '1-2-2', name: '分类排序' },
|
|
51
|
+
// ],
|
|
52
|
+
// },
|
|
53
|
+
// ],
|
|
54
|
+
// },
|
|
55
|
+
// {
|
|
56
|
+
// id: '2',
|
|
57
|
+
// name: '订单管理',
|
|
58
|
+
// children: [
|
|
59
|
+
// { id: '2-1', name: '订单列表' },
|
|
60
|
+
// { id: '2-2', name: '订单详情' },
|
|
61
|
+
// { id: '2-3', name: '订单导出' },
|
|
62
|
+
// ],
|
|
63
|
+
// },
|
|
64
|
+
// {
|
|
65
|
+
// id: '3',
|
|
66
|
+
// name: '用户管理',
|
|
67
|
+
// children: [
|
|
68
|
+
// {
|
|
69
|
+
// id: '3-1',
|
|
70
|
+
// name: '用户列表',
|
|
71
|
+
// children: [
|
|
72
|
+
// { id: '3-1-1', name: '用户查询' },
|
|
73
|
+
// { id: '3-1-2', name: '用户编辑' },
|
|
74
|
+
// ],
|
|
75
|
+
// },
|
|
76
|
+
// { id: '3-2', name: '角色管理' },
|
|
77
|
+
// ],
|
|
78
|
+
// },
|
|
79
|
+
// { id: '4', name: '系统设置' },
|
|
80
|
+
// ]
|
|
81
|
+
const treeData = ref<TreeNode[]>([])
|
|
82
|
+
|
|
83
|
+
// 选择模式
|
|
84
|
+
const selectMode = ref<SelectMode>(props.selectMode)
|
|
85
|
+
|
|
86
|
+
// 选中的节点ID
|
|
87
|
+
const selectedKeys = ref<string[]>([])
|
|
88
|
+
// 选中的节点
|
|
89
|
+
const selectedNode = ref<TreeNode[]>([])
|
|
90
|
+
|
|
91
|
+
// 搜索关键词
|
|
92
|
+
const searchKeyword = ref('')
|
|
93
|
+
|
|
94
|
+
// 所有节点的引用,用于滚动定位
|
|
95
|
+
const nodeRefs = ref<Record<string, HTMLElement | null>>({})
|
|
96
|
+
|
|
97
|
+
// 处理选择模式变更
|
|
98
|
+
// function handleModeChange(mode: SelectMode) {
|
|
99
|
+
// // 切换模式时清空选择
|
|
100
|
+
// selectedKeys.value = []
|
|
101
|
+
// }
|
|
102
|
+
const treeConfigs = reactive({
|
|
103
|
+
branchRatmplId: '',
|
|
104
|
+
branchTitle: '',
|
|
105
|
+
id: '',
|
|
106
|
+
rootGtmplId: '',
|
|
107
|
+
primaryColumnId1: '',
|
|
108
|
+
primaryColumnId2: '',
|
|
109
|
+
leafRatmplId: '',
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
const loading = ref(false)
|
|
113
|
+
// 获取配置
|
|
114
|
+
async function treeConfig1() {
|
|
115
|
+
try {
|
|
116
|
+
const res = await treeConfigApi(props.sourceId)
|
|
117
|
+
treeConfigs.branchRatmplId = res.ttmplConfig.branchRatmplId
|
|
118
|
+
treeConfigs.branchTitle = res.ttmplConfig.branchTitle
|
|
119
|
+
treeConfigs.id = res.ttmplConfig.id
|
|
120
|
+
treeConfigs.rootGtmplId = res.ttmplConfig.rootGtmplId
|
|
121
|
+
treeConfigs.leafRatmplId = res.ttmplConfig.leafRatmplId
|
|
122
|
+
treeConfig2(treeConfigs.branchRatmplId)
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.log('error:', error)
|
|
126
|
+
// TODO handle the exception
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 获取配置2
|
|
131
|
+
async function treeConfig2(branchRatmplId: string) {
|
|
132
|
+
try {
|
|
133
|
+
const res1 = await pageConfig(branchRatmplId)
|
|
134
|
+
treeConfigs.primaryColumnId1 = res1.ltmplConfig.primaryColumn.sourceId
|
|
135
|
+
getTreeTopData(treeConfigs.id)
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
console.log('error:', error)
|
|
139
|
+
// TODO handle the exception
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 根据id找到树节点
|
|
144
|
+
async function findTreeNodeandAppend(id: string, arr: TreeNode[], appendData: any) {
|
|
145
|
+
for (let index = 0; index < arr.length; index++) {
|
|
146
|
+
const element = arr[index]
|
|
147
|
+
if (element.id === id) {
|
|
148
|
+
element.children = appendData.map((item: any) => {
|
|
149
|
+
return {
|
|
150
|
+
id: item.code,
|
|
151
|
+
name: item.fieldMap[treeConfigs.primaryColumnId1],
|
|
152
|
+
children: [],
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
if (element.children)
|
|
158
|
+
findTreeNodeandAppend(id, element.children, appendData)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 获取树顶层数据
|
|
164
|
+
async function getTreeTopData(id: string) {
|
|
165
|
+
try {
|
|
166
|
+
loading.value = true
|
|
167
|
+
const res = await treeDataApi(id)
|
|
168
|
+
treeData.value = res.entities.map((item: any) => {
|
|
169
|
+
return {
|
|
170
|
+
id: item.code,
|
|
171
|
+
name: item.fieldMap[treeConfigs.primaryColumnId1],
|
|
172
|
+
children: [],
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
console.log('error:', error)
|
|
178
|
+
// TODO handle the exception
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
loading.value = false
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 获取树节点数据
|
|
186
|
+
async function getTreeNodeData(node: TreeNode) {
|
|
187
|
+
try {
|
|
188
|
+
const res = await treeNodeDataApi(treeConfigs.branchRatmplId, node.id)
|
|
189
|
+
if (!res.entities.length)
|
|
190
|
+
return
|
|
191
|
+
// 追加节点
|
|
192
|
+
findTreeNodeandAppend(node.id, treeData.value, res.entities)
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
console.log('error:', error)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function handleToggleExpand(node: TreeNode) {
|
|
200
|
+
getTreeNodeData(node)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
onMounted(() => {
|
|
204
|
+
treeConfig1()
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
// 处理选择变更
|
|
208
|
+
function handleSelectChange(keys: string[], node: TreeNode) {
|
|
209
|
+
selectedNode.value = [node]
|
|
210
|
+
selectedKeys.value = keys
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// 处理标签关闭
|
|
214
|
+
function handleTagClose(key: string) {
|
|
215
|
+
selectedKeys.value = selectedKeys.value.filter(k => k !== key)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 根据ID获取节点名称
|
|
219
|
+
function getNodeNameByKey(key: string): string {
|
|
220
|
+
const findNode = (nodes: TreeNode[]): TreeNode | null => {
|
|
221
|
+
for (const node of nodes) {
|
|
222
|
+
if (node.id === key) {
|
|
223
|
+
return node
|
|
224
|
+
}
|
|
225
|
+
if (node.children && node.children.length > 0) {
|
|
226
|
+
const found = findNode(node.children)
|
|
227
|
+
if (found)
|
|
228
|
+
return found
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return null
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const node = findNode(treeData.value)
|
|
235
|
+
return node ? node.name : ''
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 处理搜索
|
|
239
|
+
function handleSearch(keyword?: string) {
|
|
240
|
+
// 搜索逻辑在filteredTreeData计算属性中处理
|
|
241
|
+
if (keyword !== undefined) {
|
|
242
|
+
searchKeyword.value = keyword
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 过滤后的树形数据
|
|
247
|
+
const filteredTreeData = computed<TreeNode[]>(() => {
|
|
248
|
+
if (!searchKeyword.value) {
|
|
249
|
+
return treeData.value
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const keyword = searchKeyword.value.toLowerCase()
|
|
253
|
+
|
|
254
|
+
// 过滤节点的递归函数
|
|
255
|
+
const filterNodes = (nodes: TreeNode[]): TreeNode[] => {
|
|
256
|
+
return nodes
|
|
257
|
+
.map((node) => {
|
|
258
|
+
// 复制节点,避免修改原数据
|
|
259
|
+
const newNode = { ...node }
|
|
260
|
+
|
|
261
|
+
// 如果有子节点,递归过滤
|
|
262
|
+
if (newNode.children && newNode.children.length > 0) {
|
|
263
|
+
newNode.children = filterNodes(newNode.children)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 节点名称包含关键词,或者有符合条件的子节点,则保留该节点
|
|
267
|
+
const nodeNameMatch = newNode.name.toLowerCase().includes(keyword)
|
|
268
|
+
const hasMatchingChildren = newNode.children && newNode.children.length > 0
|
|
269
|
+
|
|
270
|
+
return nodeNameMatch || hasMatchingChildren ? newNode : null
|
|
271
|
+
})
|
|
272
|
+
.filter(Boolean) as TreeNode[]
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return filterNodes(treeData.value)
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
// 记录节点引用
|
|
279
|
+
function setNodeRef(id: string, el: HTMLElement | null) {
|
|
280
|
+
if (el) {
|
|
281
|
+
nodeRefs.value[id] = el
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// 滚动到指定节点
|
|
286
|
+
function scrollToNode(id: string) {
|
|
287
|
+
const node = nodeRefs.value[id]
|
|
288
|
+
if (node) {
|
|
289
|
+
node.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
|
290
|
+
// 高亮效果
|
|
291
|
+
node.classList.add('node-highlight')
|
|
292
|
+
setTimeout(() => {
|
|
293
|
+
node.classList.remove('node-highlight')
|
|
294
|
+
}, 2000)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// 页面加载时展开有子节点的节点
|
|
299
|
+
onMounted(() => {
|
|
300
|
+
// 可以在这里添加默认展开逻辑
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
// 确定
|
|
304
|
+
function handleConfirm() {
|
|
305
|
+
emit('handleConfirm', toRaw(selectedKeys.value), toRaw(selectedNode.value), treeConfigs.leafRatmplId)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// 取消
|
|
309
|
+
function handleClose() {
|
|
310
|
+
emit('handleClose')
|
|
311
|
+
}
|
|
312
|
+
</script>
|
|
313
|
+
|
|
314
|
+
<template>
|
|
315
|
+
<view class="tree-select-page">
|
|
316
|
+
<!-- 选择模式切换 -->
|
|
317
|
+
<!-- <view class="mode-switch-container">
|
|
318
|
+
<view class="mode-label">
|
|
319
|
+
选择模式:
|
|
320
|
+
</view>
|
|
321
|
+
<wd-radio-group
|
|
322
|
+
v-model="selectMode"
|
|
323
|
+
direction="horizontal"
|
|
324
|
+
@change="handleModeChange"
|
|
325
|
+
>
|
|
326
|
+
<wd-radio name="single" label="单选" />
|
|
327
|
+
<wd-radio name="multiple" label="多选" />
|
|
328
|
+
</wd-radio-group>
|
|
329
|
+
</view> -->
|
|
330
|
+
|
|
331
|
+
<!-- 搜索框 -->
|
|
332
|
+
<view class="search-container">
|
|
333
|
+
<wd-search
|
|
334
|
+
v-model="searchKeyword"
|
|
335
|
+
placeholder-class="splaceholderClass"
|
|
336
|
+
placeholder="搜索节点..."
|
|
337
|
+
clearable
|
|
338
|
+
@cancel="handleClose"
|
|
339
|
+
@input="handleSearch"
|
|
340
|
+
@clear="handleSearch"
|
|
341
|
+
/>
|
|
342
|
+
</view>
|
|
343
|
+
<!-- 已选结果 -->
|
|
344
|
+
<view v-if="selectedKeys.length > 0" class="selected-result">
|
|
345
|
+
<view class="result-title">
|
|
346
|
+
已选 {{ selectedKeys.length }} 项:
|
|
347
|
+
</view>
|
|
348
|
+
<view class="result-tags">
|
|
349
|
+
<wd-tag
|
|
350
|
+
v-for="key in selectedKeys"
|
|
351
|
+
:key="key"
|
|
352
|
+
:bg-color="currentThemeColor.primary"
|
|
353
|
+
color="#fff"
|
|
354
|
+
closable
|
|
355
|
+
round
|
|
356
|
+
@close="handleTagClose(key)"
|
|
357
|
+
@click="scrollToNode(key)"
|
|
358
|
+
>
|
|
359
|
+
{{ getNodeNameByKey(key) }}
|
|
360
|
+
</wd-tag>
|
|
361
|
+
</view>
|
|
362
|
+
</view>
|
|
363
|
+
|
|
364
|
+
<!-- 树形选择区域 -->
|
|
365
|
+
<loadingCom v-if="loading" />
|
|
366
|
+
<view v-else class="tree-container">
|
|
367
|
+
<tree-select
|
|
368
|
+
:set-node-ref="setNodeRef"
|
|
369
|
+
:tree-data="filteredTreeData"
|
|
370
|
+
:select-mode="selectMode"
|
|
371
|
+
:selected-keys="selectedKeys"
|
|
372
|
+
@update:selected-keys="handleSelectChange"
|
|
373
|
+
@toggle-expand="handleToggleExpand"
|
|
374
|
+
/>
|
|
375
|
+
|
|
376
|
+
<!-- 空状态 -->
|
|
377
|
+
<view v-if="filteredTreeData.length === 0" class="empty-state">
|
|
378
|
+
<wd-icon name="search" size="48" color="#ccc" />
|
|
379
|
+
<view class="empty-text">
|
|
380
|
+
没有找到匹配的节点
|
|
381
|
+
</view>
|
|
382
|
+
</view>
|
|
383
|
+
</view>
|
|
384
|
+
<view class="h-100px" />
|
|
385
|
+
<!-- 底部按钮 -->
|
|
386
|
+
<view class="fixed bottom-0 left-0 right-0 box-border w-100% flex p-2 bg-white dark:bg-[var(--wot-dark-background)]">
|
|
387
|
+
<wd-button
|
|
388
|
+
custom-class="flex-1"
|
|
389
|
+
type="primary"
|
|
390
|
+
@click="handleConfirm"
|
|
391
|
+
>
|
|
392
|
+
确定
|
|
393
|
+
</wd-button>
|
|
394
|
+
</view>
|
|
395
|
+
</view>
|
|
396
|
+
</template>
|
|
397
|
+
|
|
398
|
+
<style scoped>
|
|
399
|
+
.mode-switch-container {
|
|
400
|
+
padding: 16px;
|
|
401
|
+
/* background-color: #fff; */
|
|
402
|
+
margin-bottom: 10px;
|
|
403
|
+
display: flex;
|
|
404
|
+
align-items: center;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.mode-label {
|
|
408
|
+
font-size: 14px;
|
|
409
|
+
color: #666;
|
|
410
|
+
margin-right: 12px;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.tree-container {
|
|
414
|
+
/* background-color: #fff; */
|
|
415
|
+
padding: 10px 0;
|
|
416
|
+
min-height: 300px;
|
|
417
|
+
/* max-height: calc(100vh - 220px); */
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.empty-state {
|
|
421
|
+
display: flex;
|
|
422
|
+
flex-direction: column;
|
|
423
|
+
align-items: center;
|
|
424
|
+
justify-content: center;
|
|
425
|
+
padding: 40px 0;
|
|
426
|
+
color: #999;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.empty-text {
|
|
430
|
+
margin-top: 16px;
|
|
431
|
+
font-size: 14px;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.selected-result {
|
|
435
|
+
/* background-color: #fff; */
|
|
436
|
+
padding: 16px;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.result-title {
|
|
440
|
+
text-align: left;
|
|
441
|
+
font-size: 14px;
|
|
442
|
+
color: #666;
|
|
443
|
+
margin-bottom: 12px;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.result-tags {
|
|
447
|
+
display: flex;
|
|
448
|
+
flex-wrap: wrap;
|
|
449
|
+
gap: 8px;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/* 节点高亮动画 */
|
|
453
|
+
.node-highlight {
|
|
454
|
+
animation: highlight 2s ease;
|
|
455
|
+
}
|
|
456
|
+
:deep(.wd-tag__close){
|
|
457
|
+
line-height: 0.8;
|
|
458
|
+
color:#fff;
|
|
459
|
+
}
|
|
460
|
+
:deep(.uni-input-input){
|
|
461
|
+
text-align: left;
|
|
462
|
+
}
|
|
463
|
+
.splaceholderClass{
|
|
464
|
+
text-align: left;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
@keyframes highlight {
|
|
468
|
+
0% { background-color: rgba(64, 158, 255, 0.2); }
|
|
469
|
+
100% { background-color: transparent; }
|
|
470
|
+
}
|
|
471
|
+
</style>
|