wui-components-v2 1.1.64 → 1.1.66
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/components/action-popup/action-popup.vue +4 -4
- package/components/add-address-page/add-address-page.vue +20 -20
- package/components/custom-select-picker/custom-select-picker.vue +19 -27
- package/components/demo-block/demo-block.vue +2 -5
- package/components/detail-popup/detail-popup.vue +13 -6
- package/components/fold-card/fold-card.vue +25 -5
- package/components/form-control/form-control.vue +8 -0
- package/components/list-top-buttons/list-top-buttons.vue +1 -1
- package/components/login-form/login-form.vue +31 -26
- package/components/mulselect-picker/mulselect-picker.vue +10 -12
- package/components/privacy-popup/privacy-popup.vue +13 -0
- package/components/product-card/product-card.vue +95 -21
- package/components/search/search.vue +23 -22
- package/components/tree-select/components/index.vue +1 -1
- package/components/wui-edit-page/wui-edit-page-copy.vue +1 -1
- package/components/wui-edit-page/wui-edit-page.vue +2 -2
- package/components/wui-login/wui-login.vue +3 -3
- package/components/wui-login1/wui-login.vue +4 -4
- package/components/wui-menus1/components/navbar.vue +1 -1
- package/components/wui-menus1/components/quick-panel.vue +3 -3
- package/components/wui-menus1/components/section-menus.vue +4 -4
- package/components/wui-menus1/wui-menus-top.vue +1 -1
- package/components/wui-menus1/wui-menus-top1.vue +1 -1
- package/components/wui-menus1/wui-menus.vue +3 -3
- package/components/wui-notify-info/wui-notify-info.vue +65 -35
- package/components/wui-select-list/wui-select-list.vue +1 -1
- package/components/wui-select-popup/wui-select-popup.vue +27 -17
- package/components/wui-system-settings/wui-system-settings.vue +31 -24
- package/components/wui-tabbar/wui-tabbar.vue +14 -5
- package/components/wui-tree-page/components/tree-item.vue +51 -30
- package/components/wui-user/wui-user.vue +68 -57
- package/index.ts +5 -3
- package/package.json +1 -1
- package/store/manualThemeStore.ts +7 -7
- package/styles/dark-mode.scss +424 -0
|
@@ -56,7 +56,7 @@ const rightSidebars = computed(() => {
|
|
|
56
56
|
return data
|
|
57
57
|
})
|
|
58
58
|
const sources = computed(() => {
|
|
59
|
-
return rightSidebars.value.map(
|
|
59
|
+
return rightSidebars.value.map(item => {
|
|
60
60
|
return {
|
|
61
61
|
id: item.id,
|
|
62
62
|
title: item.title,
|
|
@@ -69,41 +69,49 @@ async function getEnums(sourceId: string, config: Config) {
|
|
|
69
69
|
const params: string[] = []
|
|
70
70
|
const criterias = config?.criterias ?? []
|
|
71
71
|
const columns = config?.columns ?? []
|
|
72
|
-
const writes =
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
const writes =
|
|
73
|
+
config?.rowActions?.reduce((acc: any, cur: any) => {
|
|
74
|
+
return [...acc, ...cur.writes]
|
|
75
|
+
}, []) || []
|
|
75
76
|
columns.forEach((item: any) => {
|
|
76
|
-
if (
|
|
77
|
+
if (
|
|
78
|
+
ControlTypeSupportor.getControlType(item) === 'select' ||
|
|
79
|
+
ControlTypeSupportor.getControlType(item) === 'multiselect'
|
|
80
|
+
) {
|
|
77
81
|
params.push(`mstrucIds=${item.mstrucId}`)
|
|
78
82
|
}
|
|
79
83
|
})
|
|
80
84
|
criterias.forEach((item: any) => {
|
|
81
|
-
if (
|
|
85
|
+
if (
|
|
86
|
+
ControlTypeSupportor.getControlType(item) === 'select' ||
|
|
87
|
+
ControlTypeSupportor.getControlType(item) === 'multiselect'
|
|
88
|
+
) {
|
|
82
89
|
params.push(`mstrucIds=${item.mstrucId}`)
|
|
83
90
|
}
|
|
84
91
|
})
|
|
85
92
|
writes.forEach((item: any) => {
|
|
86
|
-
if (
|
|
93
|
+
if (
|
|
94
|
+
ControlTypeSupportor.getControlType(item) === 'select' ||
|
|
95
|
+
ControlTypeSupportor.getControlType(item) === 'multiselect'
|
|
96
|
+
) {
|
|
87
97
|
params.push(`mstrucIds=${item.mstrucId}`)
|
|
88
98
|
}
|
|
89
99
|
})
|
|
90
|
-
if (!params.length)
|
|
91
|
-
return
|
|
100
|
+
if (!params.length) return
|
|
92
101
|
const res = await enums(params.join('&'))
|
|
93
102
|
enumColumn.value[sourceId] = res.enumMap || {}
|
|
94
|
-
}
|
|
95
|
-
catch (error) {
|
|
103
|
+
} catch (error) {
|
|
96
104
|
console.log('error:', error)
|
|
97
105
|
}
|
|
98
106
|
}
|
|
99
107
|
// 获取数据
|
|
100
|
-
async function queryList(source: { id: string
|
|
108
|
+
async function queryList(source: { id: string; title: string }): Promise<Notification | null> {
|
|
101
109
|
try {
|
|
102
110
|
const res = await pageConfig(source.id)
|
|
103
111
|
dtmplConfig.value[source.id] = res.ltmplConfig
|
|
104
112
|
getEnums(source.id, res.ltmplConfig)
|
|
105
|
-
const res1 = await pageKey(source.id, '', '')// 获取key
|
|
106
|
-
const data = await listData(res1.key, 1, 10)// 获取数据
|
|
113
|
+
const res1 = await pageKey(source.id, '', '') // 获取key
|
|
114
|
+
const data = await listData(res1.key, 1, 10) // 获取数据
|
|
107
115
|
return {
|
|
108
116
|
id: source.id,
|
|
109
117
|
title: source.title,
|
|
@@ -125,8 +133,7 @@ async function queryList(source: { id: string, title: string }): Promise<Notific
|
|
|
125
133
|
}
|
|
126
134
|
}),
|
|
127
135
|
}
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
136
|
+
} catch (error) {
|
|
130
137
|
console.error(error)
|
|
131
138
|
return null
|
|
132
139
|
}
|
|
@@ -148,10 +155,14 @@ watch(sources, () => {
|
|
|
148
155
|
|
|
149
156
|
function getIconColor(type: string) {
|
|
150
157
|
switch (type) {
|
|
151
|
-
case 'system':
|
|
152
|
-
|
|
153
|
-
case '
|
|
154
|
-
|
|
158
|
+
case 'system':
|
|
159
|
+
return 'bg-blue-500'
|
|
160
|
+
case 'department':
|
|
161
|
+
return 'bg-amber-500'
|
|
162
|
+
case 'colleague':
|
|
163
|
+
return 'bg-purple-500'
|
|
164
|
+
default:
|
|
165
|
+
return 'bg-slate-500'
|
|
155
166
|
}
|
|
156
167
|
}
|
|
157
168
|
|
|
@@ -190,22 +201,30 @@ function gotoDetailPage(item: Data) {
|
|
|
190
201
|
<template>
|
|
191
202
|
<view v-if="notifications && notifications.length > 0" class="mb-6 mt-6">
|
|
192
203
|
<view class="mb-4 flex items-center justify-between">
|
|
193
|
-
<text class="text-base text-slate-800 font-semibold
|
|
204
|
+
<text class="text-base text-slate-800 font-semibold dark:text-white">
|
|
194
205
|
{{ languageStore.t('最新消息') }}
|
|
195
206
|
</text>
|
|
196
207
|
</view>
|
|
197
208
|
|
|
198
209
|
<view v-for="notification in notifications" :key="notification.id" class="space-y-3">
|
|
199
|
-
<view class="mt-2 flex justify-between text-size-3 color-gray
|
|
210
|
+
<view class="mt-2 flex justify-between text-size-3 color-gray dark:text-white">
|
|
200
211
|
<view>{{ languageStore.t(notification.title) }}</view>
|
|
201
|
-
<view
|
|
212
|
+
<view
|
|
213
|
+
@click="
|
|
214
|
+
() => {
|
|
215
|
+
gotoPage(notification)
|
|
216
|
+
}
|
|
217
|
+
"
|
|
218
|
+
>
|
|
202
219
|
{{ languageStore.t('查看全部') }}
|
|
203
220
|
</view>
|
|
204
221
|
</view>
|
|
205
222
|
<button
|
|
206
|
-
v-for="item in notification.data"
|
|
207
|
-
|
|
208
|
-
|
|
223
|
+
v-for="item in notification.data"
|
|
224
|
+
:key="item.id"
|
|
225
|
+
class="w-full flex cursor-pointer items-start gap-3 rounded-xl bg-white p-4 text-left shadow-[0_4px_16px_rgba(99,102,241,0.1)] transition-all duration-200 dark:bg-black hover:shadow-md"
|
|
226
|
+
:class="{ 'opacity-60': item.read }"
|
|
227
|
+
@click="handleNotificationClick(item)"
|
|
209
228
|
>
|
|
210
229
|
<view
|
|
211
230
|
:class="getIconColor(item.type)"
|
|
@@ -216,20 +235,31 @@ function gotoDetailPage(item: Data) {
|
|
|
216
235
|
|
|
217
236
|
<view class="min-w-0 flex-1">
|
|
218
237
|
<view class="flex justify-between gap-1">
|
|
219
|
-
<span class="text-sm text-slate-800 font-medium
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
238
|
+
<span class="text-sm text-slate-800 font-medium dark:text-white">
|
|
239
|
+
{{ formatItemData(item.primaryColumn, ControlTypeSupportor.getControlType(item.primaryColumnConfig)) }}
|
|
240
|
+
</span>
|
|
241
|
+
<span class="whitespace-nowrap text-xs text-slate-400 dark:text-gray-300">
|
|
242
|
+
{{
|
|
243
|
+
formatItemData(
|
|
244
|
+
item.primaryColumnLabel,
|
|
245
|
+
ControlTypeSupportor.getControlType(item.primaryColumnLabelConfig)
|
|
246
|
+
)
|
|
247
|
+
}}
|
|
248
|
+
</span>
|
|
224
249
|
</view>
|
|
225
|
-
<p class="line-clamp-2 mt-1 text-sm text-slate-500
|
|
250
|
+
<p class="line-clamp-2 mt-1 text-sm text-slate-500 dark:text-gray-400">
|
|
226
251
|
<text class="mr-1">
|
|
227
|
-
{{
|
|
252
|
+
{{
|
|
253
|
+
formatItemData(item.secondColumn, ControlTypeSupportor.getControlType(item.secondColumnConfig || {}))
|
|
228
254
|
}}
|
|
229
255
|
</text>
|
|
230
256
|
<text>
|
|
231
|
-
{{
|
|
232
|
-
|
|
257
|
+
{{
|
|
258
|
+
formatItemData(
|
|
259
|
+
item.secondColumnLabel,
|
|
260
|
+
ControlTypeSupportor.getControlType(item.secondColumnLabelConfig || {})
|
|
261
|
+
)
|
|
262
|
+
}}
|
|
233
263
|
</text>
|
|
234
264
|
</p>
|
|
235
265
|
</view>
|
|
@@ -298,7 +298,7 @@ onUnmounted(() => {
|
|
|
298
298
|
|
|
299
299
|
<template #bottom>
|
|
300
300
|
<slot name="bottom">
|
|
301
|
-
<view class="flex justify-between gap-1 p-2
|
|
301
|
+
<view class="flex justify-between gap-1 p-2 bg-white dark:bg-[var(--wot-dark-background)]">
|
|
302
302
|
<!-- <wd-button class="flex-1" type="info" @click="cancel">
|
|
303
303
|
取消
|
|
304
304
|
</wd-button> -->
|
|
@@ -35,7 +35,7 @@ const props = withDefaults(
|
|
|
35
35
|
defaultSelectFirst: false,
|
|
36
36
|
}
|
|
37
37
|
)
|
|
38
|
-
|
|
38
|
+
console.log(props, '3333333333333333333')
|
|
39
39
|
const emit = defineEmits<{
|
|
40
40
|
(e: 'update:modelValue', value: string | string[]): void
|
|
41
41
|
(e: 'confirm', value: string | string[]): void
|
|
@@ -161,6 +161,8 @@ const formatAddress = (value: string) => {
|
|
|
161
161
|
const isConfigLoaded = ref(false)
|
|
162
162
|
// ★ 防止重复加载
|
|
163
163
|
const isLoading = ref(false)
|
|
164
|
+
// ★ 防止 z-paging 初始化时与手动 reload 重复请求
|
|
165
|
+
const hasInitialized = ref(false)
|
|
164
166
|
|
|
165
167
|
// ★ 是否已完成默认首项选中
|
|
166
168
|
const hasDefaultSelected = ref(false)
|
|
@@ -217,8 +219,17 @@ async function getEnums() {
|
|
|
217
219
|
|
|
218
220
|
// 查询列表数据(完整流程:config -> key -> data)
|
|
219
221
|
async function queryList(pageNo: number, pageSize: number) {
|
|
220
|
-
// ★
|
|
222
|
+
// ★ 只防正在进行的重复请求(分页不拦截)
|
|
221
223
|
if (pageNo === 1 && isLoading.value) return
|
|
224
|
+
|
|
225
|
+
// ★ z-paging 组件初始化时自动触发 @query,popup 未打开时跳过
|
|
226
|
+
// (只跳过第一次,后续打开 popup 后的查询正常放行)
|
|
227
|
+
if (!show.value && !hasInitialized.value) {
|
|
228
|
+
hasInitialized.value = true
|
|
229
|
+
Zpaging.value.complete([])
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
|
|
222
233
|
if (pageNo === 1) isLoading.value = true
|
|
223
234
|
|
|
224
235
|
try {
|
|
@@ -344,9 +355,10 @@ function openPopup(e?: any) {
|
|
|
344
355
|
watch(show, async val => {
|
|
345
356
|
console.log('[WuiSelectPopup] 📢 show 状态变化:', val)
|
|
346
357
|
if (val) {
|
|
347
|
-
if (isLoading.value) return // ★
|
|
348
|
-
isConfigLoaded.value = false
|
|
358
|
+
if (isLoading.value) return // ★ 防重复(正在请求中不重复触发)
|
|
349
359
|
await nextTick()
|
|
360
|
+
// ★ 不重置 isConfigLoaded(配置只需加载一次)
|
|
361
|
+
hasInitialized.value = false // ★ 允许 reload 触发查询
|
|
350
362
|
if (Zpaging.value) {
|
|
351
363
|
Zpaging.value.reload()
|
|
352
364
|
} else {
|
|
@@ -364,7 +376,8 @@ function handleRefresh(refreshSourceId: string) {
|
|
|
364
376
|
if (refreshSourceId !== props.sourceId) return
|
|
365
377
|
console.log('[WuiSelectPopup] 🔄 收到刷新信号,重新加载数据')
|
|
366
378
|
if (show.value && Zpaging.value && !isLoading.value) {
|
|
367
|
-
isConfigLoaded.value = false
|
|
379
|
+
isConfigLoaded.value = false // ★ 刷新时重新加载配置
|
|
380
|
+
hasInitialized.value = false // ★ 允许 reload 触发
|
|
368
381
|
Zpaging.value.reload()
|
|
369
382
|
}
|
|
370
383
|
}
|
|
@@ -391,18 +404,18 @@ defineExpose({
|
|
|
391
404
|
</script>
|
|
392
405
|
|
|
393
406
|
<template>
|
|
394
|
-
<view class="wui-select-popup-wrapper">
|
|
407
|
+
<view class="wui-select-popup-wrapper dark:bg-[var(--wot-dark-background)]">
|
|
395
408
|
<!-- ★ 触发区域 - 原生表单样式(左标签 + 中内容 + 右箭头) -->
|
|
396
409
|
<view v-if="!show" class="trigger-cell" @click="openPopup">
|
|
397
410
|
<!-- 左侧标签 -->
|
|
398
|
-
<text v-if="label" class="cell-label">
|
|
411
|
+
<text v-if="label" class="cell-label dark:text-white">
|
|
399
412
|
{{ label }}
|
|
400
413
|
</text>
|
|
401
414
|
|
|
402
415
|
<!-- 中间内容区 -->
|
|
403
|
-
<view class="cell-content">
|
|
404
|
-
<text v-if="displayValue" class="cell-value">
|
|
405
|
-
{{ displayValue }}
|
|
416
|
+
<view class="cell-content dark:text-white">
|
|
417
|
+
<text v-if="displayValue && displayValue !== 'null'" class="cell-value">
|
|
418
|
+
{{ displayValue || '' }}
|
|
406
419
|
</text>
|
|
407
420
|
<text v-else class="cell-placeholder">
|
|
408
421
|
{{ placeholder || `请选择${title || label}` }}
|
|
@@ -422,6 +435,7 @@ defineExpose({
|
|
|
422
435
|
position="bottom"
|
|
423
436
|
:z-index="999999"
|
|
424
437
|
custom-style="border-radius: 24rpx 24rpx 0 0; overflow: hidden;"
|
|
438
|
+
class="dark:bg-[#1b1b1e]"
|
|
425
439
|
safe-area-inset-bottom
|
|
426
440
|
@close="
|
|
427
441
|
() => {
|
|
@@ -429,10 +443,10 @@ defineExpose({
|
|
|
429
443
|
}
|
|
430
444
|
"
|
|
431
445
|
>
|
|
432
|
-
<view class="select-popup-container">
|
|
446
|
+
<view class="select-popup-container dark:bg-[#1b1b1e]">
|
|
433
447
|
<!-- 标题栏 - 固定高度不参与滚动 -->
|
|
434
448
|
<view
|
|
435
|
-
class="popup-header flex items-center justify-between px-4 py-3 border-b border-gray-200
|
|
449
|
+
class="popup-header flex items-center justify-between px-4 py-3 border-b border-gray-200 shrink-0 dark:text-white"
|
|
436
450
|
>
|
|
437
451
|
<text class="text-base font-bold">选择{{ title }}</text>
|
|
438
452
|
<wd-icon name="close-circle" size="16px" @click="cancel" />
|
|
@@ -491,7 +505,7 @@ defineExpose({
|
|
|
491
505
|
</foldCard>
|
|
492
506
|
|
|
493
507
|
<template #bottom>
|
|
494
|
-
<view class="popup-footer flex justify-center gap-4 p-4
|
|
508
|
+
<view class="popup-footer flex justify-center gap-4 p-4 border-t border-gray-200">
|
|
495
509
|
<wd-button plain custom-class="flex-1" @click="cancel">取消</wd-button>
|
|
496
510
|
<wd-button type="primary" custom-class="flex-1" @click="confirm">确定</wd-button>
|
|
497
511
|
</view>
|
|
@@ -514,7 +528,6 @@ defineExpose({
|
|
|
514
528
|
display: flex;
|
|
515
529
|
align-items: center;
|
|
516
530
|
justify-content: space-between;
|
|
517
|
-
background-color: #fff;
|
|
518
531
|
cursor: pointer;
|
|
519
532
|
position: relative;
|
|
520
533
|
transition: background-color 0.2s;
|
|
@@ -526,7 +539,6 @@ defineExpose({
|
|
|
526
539
|
// 左侧标签 - 固定宽度,不换行
|
|
527
540
|
.cell-label {
|
|
528
541
|
flex-shrink: 0;
|
|
529
|
-
color: #333;
|
|
530
542
|
margin-right: 24rpx;
|
|
531
543
|
white-space: nowrap;
|
|
532
544
|
}
|
|
@@ -537,7 +549,6 @@ defineExpose({
|
|
|
537
549
|
min-width: 0; // 允许文本溢出省略
|
|
538
550
|
|
|
539
551
|
.cell-value {
|
|
540
|
-
color: #333;
|
|
541
552
|
text-align: left;
|
|
542
553
|
overflow: hidden;
|
|
543
554
|
text-overflow: ellipsis;
|
|
@@ -571,7 +582,6 @@ defineExpose({
|
|
|
571
582
|
flex-direction: column;
|
|
572
583
|
height: 75vh; // 固定高度
|
|
573
584
|
max-height: 80vh; // 最大高度
|
|
574
|
-
background-color: #fff;
|
|
575
585
|
overflow: hidden; // 防止内容溢出
|
|
576
586
|
}
|
|
577
587
|
|
|
@@ -36,6 +36,17 @@ const isDark = computed({
|
|
|
36
36
|
toggleTheme()
|
|
37
37
|
},
|
|
38
38
|
})
|
|
39
|
+
|
|
40
|
+
// Cell / CellGroup 暗黑内联样式
|
|
41
|
+
const settingsCellStyle = computed(() => ({
|
|
42
|
+
backgroundColor: isDark.value ? '#161616' : '#fff',
|
|
43
|
+
borderBottom: isDark.value ? '1px solid rgba(255,255,255,0.04)' : 'none',
|
|
44
|
+
}))
|
|
45
|
+
|
|
46
|
+
const settingsGroupStyle = computed(() => ({
|
|
47
|
+
backgroundColor: isDark.value ? '#111111' : 'transparent',
|
|
48
|
+
borderRadius: isDark.value ? '10px' : '0',
|
|
49
|
+
}))
|
|
39
50
|
// 处理主题色选择
|
|
40
51
|
function handleThemeColorSelect(option: ThemeColorOption) {
|
|
41
52
|
selectThemeColor(option)
|
|
@@ -48,25 +59,31 @@ function handleLanguageSelect(option: LocaleOption) {
|
|
|
48
59
|
</script>
|
|
49
60
|
|
|
50
61
|
<template>
|
|
51
|
-
<view>
|
|
52
|
-
<!-- <view class="color-black">{{ languageStore.t('PC新增') }}</view> -->
|
|
62
|
+
<view class="settings-page" :style="{ backgroundColor: isDark ? '#1B1B1E' : '#F8F9FB' }">
|
|
53
63
|
<demo-block :title="languageStore.t('系统设置')" transparent>
|
|
54
|
-
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
|
55
|
-
<wd-cell :title="languageStore.t('暗黑模式')">
|
|
64
|
+
<wd-cell-group border custom-class="rounded-2! overflow-hidden" :custom-style="settingsGroupStyle">
|
|
65
|
+
<wd-cell :title="languageStore.t('暗黑模式')" :custom-style="settingsCellStyle">
|
|
56
66
|
<wd-switch v-model="isDark" size="18px" />
|
|
57
67
|
</wd-cell>
|
|
58
|
-
<wd-cell
|
|
68
|
+
<wd-cell
|
|
69
|
+
:title="languageStore.t('选择主题色')"
|
|
70
|
+
is-link
|
|
71
|
+
@click="openThemeColorPicker"
|
|
72
|
+
:custom-style="settingsCellStyle"
|
|
73
|
+
>
|
|
59
74
|
<view class="flex items-center justify-end gap-2">
|
|
60
|
-
<view
|
|
61
|
-
|
|
62
|
-
:style="{ backgroundColor: currentThemeColor.primary }"
|
|
63
|
-
/>
|
|
64
|
-
<text>{{ currentThemeColor.name }}</text>
|
|
75
|
+
<view class="h-4 w-4 rounded-full" :style="{ backgroundColor: currentThemeColor.primary }" />
|
|
76
|
+
<text :style="{ color: isDark ? '#e8e8e8' : '#333' }">{{ currentThemeColor.name }}</text>
|
|
65
77
|
</view>
|
|
66
78
|
</wd-cell>
|
|
67
|
-
<wd-cell
|
|
79
|
+
<wd-cell
|
|
80
|
+
:title="languageStore.t('选择语言')"
|
|
81
|
+
is-link
|
|
82
|
+
@click="openLanguagePicker"
|
|
83
|
+
:custom-style="settingsCellStyle"
|
|
84
|
+
>
|
|
68
85
|
<view class="flex items-center justify-end gap-2">
|
|
69
|
-
<text>{{ currentLocale.name }}</text>
|
|
86
|
+
<text :style="{ color: isDark ? '#e8e8e8' : '#333' }">{{ currentLocale.name }}</text>
|
|
70
87
|
</view>
|
|
71
88
|
</wd-cell>
|
|
72
89
|
</wd-cell-group>
|
|
@@ -94,12 +111,7 @@ function handleLanguageSelect(option: LocaleOption) {
|
|
|
94
111
|
{{ option.name }}
|
|
95
112
|
</text>
|
|
96
113
|
</view>
|
|
97
|
-
<wd-icon
|
|
98
|
-
v-if="currentThemeColor.value === option.value"
|
|
99
|
-
name="check"
|
|
100
|
-
:color="option.primary"
|
|
101
|
-
size="20px"
|
|
102
|
-
/>
|
|
114
|
+
<wd-icon v-if="currentThemeColor.value === option.value" name="check" :color="option.primary" size="20px" />
|
|
103
115
|
</view>
|
|
104
116
|
</view>
|
|
105
117
|
<wd-gap :height="50" />
|
|
@@ -123,12 +135,7 @@ function handleLanguageSelect(option: LocaleOption) {
|
|
|
123
135
|
{{ option.name }}
|
|
124
136
|
</text>
|
|
125
137
|
</view>
|
|
126
|
-
<wd-icon
|
|
127
|
-
v-if="currentLocale.value === option.value"
|
|
128
|
-
name="check"
|
|
129
|
-
:color="primary"
|
|
130
|
-
size="20px"
|
|
131
|
-
/>
|
|
138
|
+
<wd-icon v-if="currentLocale.value === option.value" name="check" :color="primary" size="20px" />
|
|
132
139
|
</view>
|
|
133
140
|
</view>
|
|
134
141
|
<wd-gap :height="50" />
|
|
@@ -55,13 +55,22 @@ export default {
|
|
|
55
55
|
<wd-config-provider :theme-vars="themeVars" :custom-class="`page-wraper ${theme}`" :theme="theme">
|
|
56
56
|
<slot />
|
|
57
57
|
<wd-tabbar
|
|
58
|
-
:model-value="activeTabbar.name"
|
|
58
|
+
:model-value="activeTabbar.name"
|
|
59
|
+
bordered
|
|
60
|
+
safe-area-inset-bottom
|
|
61
|
+
placeholder
|
|
62
|
+
fixed
|
|
63
|
+
custom-class="z-14!"
|
|
59
64
|
:active-color="currentThemeColor.primary"
|
|
60
65
|
@change="handleTabbarChange"
|
|
61
66
|
>
|
|
62
67
|
<wd-tabbar-item
|
|
63
|
-
v-for="(item, index) in tabbarList"
|
|
64
|
-
:
|
|
68
|
+
v-for="(item, index) in tabbarList"
|
|
69
|
+
:key="index"
|
|
70
|
+
:name="item.name"
|
|
71
|
+
:value="getTabbarItemValue(item.name)"
|
|
72
|
+
:title="item.title"
|
|
73
|
+
:icon="item.icon"
|
|
65
74
|
>
|
|
66
75
|
<!-- 使用 icon 插槽自定义图标 -->
|
|
67
76
|
<template v-if="item.activeIcon" #icon="{ active }">
|
|
@@ -84,11 +93,11 @@ export default {
|
|
|
84
93
|
.page-wraper {
|
|
85
94
|
min-height: calc(100vh - var(--window-top));
|
|
86
95
|
box-sizing: border-box;
|
|
87
|
-
background: #
|
|
96
|
+
background: #f8f9fb;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
.wot-theme-dark.page-wraper {
|
|
91
|
-
background: #
|
|
100
|
+
background: #1b1b1e;
|
|
92
101
|
}
|
|
93
102
|
.custom-icon {
|
|
94
103
|
width: 52rpx;
|
|
@@ -25,9 +25,7 @@ const props = defineProps({
|
|
|
25
25
|
},
|
|
26
26
|
})
|
|
27
27
|
const emit = defineEmits(['addBranch', 'addLeaf', 'remove', 'update', 'toggleExpand'])
|
|
28
|
-
const {
|
|
29
|
-
currentThemeColor,
|
|
30
|
-
} = useManualTheme()
|
|
28
|
+
const { currentThemeColor } = useManualTheme()
|
|
31
29
|
interface TreeNode {
|
|
32
30
|
id: string
|
|
33
31
|
label: string
|
|
@@ -45,8 +43,7 @@ const hasChildren = computed(() => {
|
|
|
45
43
|
|
|
46
44
|
// 计算是否需要高亮
|
|
47
45
|
const isHighlight = computed(() => {
|
|
48
|
-
if (!props.searchKeyword)
|
|
49
|
-
return false
|
|
46
|
+
if (!props.searchKeyword) return false
|
|
50
47
|
return props.node.label.toLowerCase().includes(props.searchKeyword.toLowerCase())
|
|
51
48
|
})
|
|
52
49
|
|
|
@@ -92,20 +89,32 @@ function emitUpdate(e: TreeNode) {
|
|
|
92
89
|
<template>
|
|
93
90
|
<view class="tree-node">
|
|
94
91
|
<!-- 节点内容行 -->
|
|
95
|
-
<view class="node-content bg
|
|
92
|
+
<view class="node-content bg-white dark:bg-[#1B1B1E]" :style="{ paddingLeft: `${level * 30}rpx` }">
|
|
96
93
|
<!-- 展开/收起图标 -->
|
|
97
|
-
<view
|
|
94
|
+
<view
|
|
95
|
+
class="icon-area"
|
|
96
|
+
@click.stop="
|
|
97
|
+
() => {
|
|
98
|
+
toggleExpand()
|
|
99
|
+
}
|
|
100
|
+
"
|
|
101
|
+
>
|
|
98
102
|
<text v-if="node.type !== 'leaf'" class="arrow" :class="{ rotated: node.expanded }">
|
|
99
103
|
<wd-loading v-if="node.loading" size="16" />
|
|
100
104
|
<wd-icon v-else name="arrow-right" size="18px" />
|
|
101
105
|
</text>
|
|
102
|
-
<text v-else class="dot
|
|
103
|
-
•
|
|
104
|
-
</text>
|
|
106
|
+
<text v-else class="dot dark:text-white">•</text>
|
|
105
107
|
</view>
|
|
106
108
|
|
|
107
109
|
<!-- 节点名称 (支持搜索高亮) -->
|
|
108
|
-
<view
|
|
110
|
+
<view
|
|
111
|
+
class="label-area text-gray-800 dark:text-white"
|
|
112
|
+
@click.stop="
|
|
113
|
+
() => {
|
|
114
|
+
toggleExpand()
|
|
115
|
+
}
|
|
116
|
+
"
|
|
117
|
+
>
|
|
109
118
|
<text :class="{ highlight: isHighlight }">
|
|
110
119
|
{{ node.label }}
|
|
111
120
|
</text>
|
|
@@ -113,34 +122,46 @@ function emitUpdate(e: TreeNode) {
|
|
|
113
122
|
|
|
114
123
|
<!-- 操作按钮区域 -->
|
|
115
124
|
<view class="action-area">
|
|
116
|
-
<view
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
<view
|
|
126
|
+
v-if="(node.type === 'branch' || node.type === 'root') && leafRatmplId"
|
|
127
|
+
class="btn"
|
|
128
|
+
:style="{ backgroundColor: desaturateColor(currentThemeColor.primary) }"
|
|
129
|
+
@click.stop="onAddLeaf"
|
|
130
|
+
>
|
|
131
|
+
<text :style="{ color: currentThemeColor.primary }">+</text>
|
|
122
132
|
</view>
|
|
123
|
-
<view
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
<view
|
|
134
|
+
v-if="node.type === 'branch' || node.type === 'root'"
|
|
135
|
+
class="btn"
|
|
136
|
+
:style="{ backgroundColor: desaturateColor(currentThemeColor.primary) }"
|
|
137
|
+
@click.stop="onAddBranch"
|
|
138
|
+
>
|
|
139
|
+
<text class="i-carbon:decision-tree text-3" :style="{ color: currentThemeColor.primary }" />
|
|
128
140
|
</view>
|
|
129
141
|
<wd-icon
|
|
130
|
-
class="btn"
|
|
131
|
-
|
|
142
|
+
class="btn"
|
|
143
|
+
name="edit"
|
|
144
|
+
size="28rpx"
|
|
145
|
+
:style="{ backgroundColor: desaturateColor(currentThemeColor.primary), color: currentThemeColor.primary }"
|
|
146
|
+
@click.stop="handleEdit"
|
|
132
147
|
/>
|
|
133
|
-
<text class="btn del" @click.stop="onRemove">
|
|
134
|
-
-
|
|
135
|
-
</text>
|
|
148
|
+
<text class="btn del" @click.stop="onRemove">-</text>
|
|
136
149
|
</view>
|
|
137
150
|
</view>
|
|
138
151
|
|
|
139
152
|
<!-- 递归渲染子节点 -->
|
|
140
153
|
<view v-if="hasChildren && node.expanded" class="children-container">
|
|
141
154
|
<tree-item
|
|
142
|
-
v-for="child in node.children"
|
|
143
|
-
:
|
|
155
|
+
v-for="child in node.children"
|
|
156
|
+
:key="child.id"
|
|
157
|
+
:node="child"
|
|
158
|
+
:level="level + 1"
|
|
159
|
+
:leaf-ratmpl-id="props.leafRatmplId"
|
|
160
|
+
:search-keyword="searchKeyword"
|
|
161
|
+
@add-leaf="emitAddLeaf"
|
|
162
|
+
@add-branch="emitAddBranch"
|
|
163
|
+
@remove="emitRemove"
|
|
164
|
+
@update="emitUpdate"
|
|
144
165
|
@toggle-expand="toggleExpand"
|
|
145
166
|
/>
|
|
146
167
|
</view>
|
|
@@ -179,7 +200,7 @@ function emitUpdate(e: TreeNode) {
|
|
|
179
200
|
}
|
|
180
201
|
|
|
181
202
|
.dot {
|
|
182
|
-
font-size:60rpx;
|
|
203
|
+
font-size: 60rpx;
|
|
183
204
|
color: #ddd;
|
|
184
205
|
}
|
|
185
206
|
|