wui-components-v2 1.1.62 → 1.1.64
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/detail-popup/detail-popup.vue +82 -18
- package/components/label-value/label-value.vue +61 -47
- package/components/wui-menus/wui-menus.vue +46 -33
- package/components/wui-menus1/wui-menus.vue +1 -4
- package/components/wui-search-history-babbar/wui-search-history-babbar.vue +23 -42
- package/composables/useMenus.ts +32 -41
- package/package.json +1 -1
|
@@ -1,28 +1,92 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { ref, computed, onMounted } from 'vue'
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import type { Columns, Entities } from '../../type'
|
|
4
|
+
import { formatItemData } from '../../utils'
|
|
5
|
+
import ControlTypeSupportor from '../../utils/control-type-supportor'
|
|
6
|
+
import { detailPageConfig, detailPageData } from '@/core-components/api/page'
|
|
8
7
|
|
|
9
8
|
defineOptions({
|
|
10
9
|
name: 'DetailPopup',
|
|
11
10
|
})
|
|
12
|
-
defineProps({
|
|
13
|
-
data: {
|
|
14
|
-
type: Object,
|
|
15
|
-
default: () => {},
|
|
16
|
-
},
|
|
17
|
-
})
|
|
18
11
|
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
source: Columns
|
|
14
|
+
text: string
|
|
15
|
+
code: string
|
|
16
|
+
}>()
|
|
17
|
+
interface DetailItem {
|
|
18
|
+
/** 行数据 */
|
|
19
|
+
data: Entities
|
|
20
|
+
/** 字段配置 */
|
|
21
|
+
columns: Columns[]
|
|
22
|
+
}
|
|
19
23
|
|
|
20
|
-
const
|
|
24
|
+
const showDetail = ref(false)
|
|
25
|
+
const exhibitData = ref<Columns[]>([])
|
|
26
|
+
const rowData = ref<Entities>({} as Entities)
|
|
27
|
+
const columns = ref<Columns[]>([])
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
29
|
+
function isControlType(item: Columns): string {
|
|
30
|
+
return ControlTypeSupportor.getControlType(
|
|
31
|
+
{ ...item, hidden: false, disabled: false, defaultValue: '', transDefaultValue: '', required: false },
|
|
32
|
+
rowData.value.fieldMap[item.sourceId]
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
async function open(item: DetailItem) {
|
|
36
|
+
const code = props.code.split('@R@')[0]
|
|
37
|
+
const formRes = await detailPageConfig(props.source.sourceId)
|
|
38
|
+
const valueRes = await detailPageData(props.source.sourceId, code)
|
|
39
|
+
if (formRes.status === 'success') {
|
|
40
|
+
columns.value = formRes.dtmplConfig.groups?.[0].fields || []
|
|
41
|
+
}
|
|
42
|
+
if (valueRes.status === 'success') {
|
|
43
|
+
rowData.value = valueRes.entity || {}
|
|
44
|
+
}
|
|
45
|
+
showDetail.value = true
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function handleClose() {
|
|
49
|
+
showDetail.value = false
|
|
50
|
+
}
|
|
25
51
|
</script>
|
|
26
52
|
|
|
27
|
-
<
|
|
53
|
+
<template>
|
|
54
|
+
<view class="text-[#1c64fd]" @click="open">{{ text }}</view>
|
|
55
|
+
<wd-popup v-model="showDetail" custom-style="border-radius: 32rpx;">
|
|
56
|
+
<view class="custom-popup">
|
|
57
|
+
<view class="text-center mb-4">详情内容</view>
|
|
58
|
+
<scroll-view scroll-y class="scroll-area">
|
|
59
|
+
<view class="flex items-center gap-2 mb-4 text-[#6b7280]" v-for="(item, sindex) in columns" :key="sindex">
|
|
60
|
+
<view class="break-words">{{ item.title }}:</view>
|
|
61
|
+
<view class="text-[#1f2937] break-all">
|
|
62
|
+
{{ formatItemData(rowData.fieldMap[item.sourceId], isControlType(item)) }}
|
|
63
|
+
</view>
|
|
64
|
+
</view>
|
|
65
|
+
</scroll-view>
|
|
66
|
+
<view class="footer flex justify-center items-center">
|
|
67
|
+
<wd-button class="flex-1" @click="handleClose">确定</wd-button>
|
|
68
|
+
</view>
|
|
69
|
+
</view>
|
|
70
|
+
</wd-popup>
|
|
71
|
+
</template>
|
|
72
|
+
|
|
73
|
+
<style scoped lang="scss">
|
|
74
|
+
.custom-popup {
|
|
75
|
+
color: black;
|
|
76
|
+
padding: 24rpx;
|
|
77
|
+
width: 600rpx;
|
|
78
|
+
max-width: 600rpx;
|
|
79
|
+
font-size: 40rpx;
|
|
80
|
+
border-radius: 32rpx;
|
|
81
|
+
position: relative;
|
|
82
|
+
|
|
83
|
+
.scroll-area {
|
|
84
|
+
height: 50vh;
|
|
85
|
+
overflow: hidden;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.footer {
|
|
89
|
+
margin-top: 24rpx;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
28
92
|
</style>
|
|
@@ -7,6 +7,7 @@ import VideoPlay from '../video-play/video-play.vue'
|
|
|
7
7
|
import audioPlay from '../audio-play/audio-play.vue'
|
|
8
8
|
import { useManualTheme } from '../../composables/useManualTheme'
|
|
9
9
|
import openValueMore from './open-value-more.vue'
|
|
10
|
+
import detailPopup from '../detail-popup/detail-popup.vue'
|
|
10
11
|
|
|
11
12
|
defineOptions({
|
|
12
13
|
name: 'LabelValue',
|
|
@@ -17,7 +18,6 @@ const props = defineProps<{
|
|
|
17
18
|
index: number
|
|
18
19
|
}>()
|
|
19
20
|
const { primary } = useManualTheme()
|
|
20
|
-
const showDetail=ref(false)
|
|
21
21
|
const clums = computed(() => {
|
|
22
22
|
return props.exhibitData.filter(item => !item.title?.includes('y'))
|
|
23
23
|
})
|
|
@@ -28,15 +28,16 @@ function openVideo(uitem: any) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function isControlType(item: Columns): string {
|
|
31
|
-
return ControlTypeSupportor.getControlType(
|
|
31
|
+
return ControlTypeSupportor.getControlType(
|
|
32
|
+
{ ...item, hidden: false, disabled: false, defaultValue: '', transDefaultValue: '', required: false },
|
|
33
|
+
props.data.fieldMap[item.sourceId]
|
|
34
|
+
)
|
|
32
35
|
}
|
|
33
36
|
</script>
|
|
34
37
|
|
|
35
38
|
<template>
|
|
36
39
|
<view v-for="(item, sindex) in clums" :key="sindex" class="flex">
|
|
37
|
-
<view class="mr-2 w-20 p-1 text-gray-500 dark:text-white">
|
|
38
|
-
{{ item.title }}:
|
|
39
|
-
</view>
|
|
40
|
+
<view class="mr-2 w-20 p-1 text-gray-500 dark:text-white">{{ item.title }}:</view>
|
|
40
41
|
<view
|
|
41
42
|
v-if="isControlType(item) === 'file' || isControlType(item) === 'relfile' || isControlType(item) === 'video'"
|
|
42
43
|
class="flex flex-1 items-center text-gray-800 dark:text-white"
|
|
@@ -48,13 +49,14 @@ function isControlType(item: Columns): string {
|
|
|
48
49
|
>
|
|
49
50
|
<!-- 图片 -->
|
|
50
51
|
<wd-img
|
|
51
|
-
v-if="['png', 'jpg', 'jpeg'].includes(uitem.type)"
|
|
52
|
+
v-if="['png', 'jpg', 'jpeg'].includes(uitem.type)"
|
|
53
|
+
enable-preview
|
|
54
|
+
:width="100"
|
|
55
|
+
:height="100"
|
|
52
56
|
:src="uitem.url"
|
|
53
57
|
>
|
|
54
58
|
<template #error>
|
|
55
|
-
<view class="flex items-center pt-4px">
|
|
56
|
-
暂无图片~
|
|
57
|
-
</view>
|
|
59
|
+
<view class="flex items-center pt-4px">暂无图片~</view>
|
|
58
60
|
</template>
|
|
59
61
|
<template #loading>
|
|
60
62
|
<view class="loading-wrap">
|
|
@@ -65,7 +67,15 @@ function isControlType(item: Columns): string {
|
|
|
65
67
|
<!-- 视频 -->
|
|
66
68
|
<view
|
|
67
69
|
v-else-if="['mp4', 'mov', 'wmv', 'avi', 'rmvb', 'flv', 'mkv'].includes(uitem.type)"
|
|
68
|
-
style="
|
|
70
|
+
style="
|
|
71
|
+
width: 70px;
|
|
72
|
+
height: 70px;
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
border: 1px solid #ccc;
|
|
77
|
+
border-radius: 4px;
|
|
78
|
+
"
|
|
69
79
|
@click="openVideo(uitem)"
|
|
70
80
|
>
|
|
71
81
|
<wd-icon name="play-circle-filled" size="22px" />
|
|
@@ -73,12 +83,42 @@ function isControlType(item: Columns): string {
|
|
|
73
83
|
<!-- 音频 -->
|
|
74
84
|
<view
|
|
75
85
|
v-else-if="['mp3', 'wma', 'wav', 'aac', 'ogg', 'flac', 'm4a', 'amr'].includes(uitem.type)"
|
|
76
|
-
style="display: flex;align-items: center;justify-content: center
|
|
86
|
+
style="display: flex; align-items: center; justify-content: center"
|
|
77
87
|
>
|
|
78
88
|
<audioPlay :src="uitem.url" />
|
|
79
89
|
</view>
|
|
80
90
|
<!-- 文件 -->
|
|
81
|
-
<view
|
|
91
|
+
<view
|
|
92
|
+
v-else-if="
|
|
93
|
+
[
|
|
94
|
+
'doc',
|
|
95
|
+
'docx',
|
|
96
|
+
'xls',
|
|
97
|
+
'xlsx',
|
|
98
|
+
'ppt',
|
|
99
|
+
'pptx',
|
|
100
|
+
'pdf',
|
|
101
|
+
'txt',
|
|
102
|
+
'zip',
|
|
103
|
+
'rar',
|
|
104
|
+
'7z',
|
|
105
|
+
'gz',
|
|
106
|
+
'bz2',
|
|
107
|
+
'tar',
|
|
108
|
+
'iso',
|
|
109
|
+
'exe',
|
|
110
|
+
'dmg',
|
|
111
|
+
'apk',
|
|
112
|
+
'apk',
|
|
113
|
+
'apk',
|
|
114
|
+
'apk',
|
|
115
|
+
'apk',
|
|
116
|
+
'apk',
|
|
117
|
+
'apk',
|
|
118
|
+
'apk',
|
|
119
|
+
].includes(uitem.type)
|
|
120
|
+
"
|
|
121
|
+
>
|
|
82
122
|
<span :style="{ color: primary }" @click="downloadFile(uitem.url)">
|
|
83
123
|
{{ uitem.name }}
|
|
84
124
|
</span>
|
|
@@ -89,42 +129,16 @@ function isControlType(item: Columns): string {
|
|
|
89
129
|
<view v-else-if="item.title === '序号'" class="flex flex-1 items-center text-gray-800 dark:text-white">
|
|
90
130
|
{{ index + 1 }}
|
|
91
131
|
</view>
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<view class="flex items-center gap-2 mb-4 text-[#6b7280]" v-for="(item, sindex) in exhibitData" :key="sindex">
|
|
99
|
-
<view class=" whitespace-nowrap">
|
|
100
|
-
{{ item.title }}:
|
|
101
|
-
</view>
|
|
102
|
-
<view class="text-[#1f2937]">
|
|
103
|
-
{{ formatItemData(data.fieldMap[item.sourceId], isControlType(item)) }}
|
|
104
|
-
</view>
|
|
105
|
-
|
|
106
|
-
</view>
|
|
107
|
-
<view class="footer flex justify-center items-center">
|
|
108
|
-
<wd-button class="flex-1" @click="showDetail = false">确定</wd-button>
|
|
132
|
+
<view v-else-if="item.buttons?.includes('detail')" class="flex flex-1 items-center text-gray-800 dark:text-white">
|
|
133
|
+
<detailPopup
|
|
134
|
+
:source="item"
|
|
135
|
+
:text="formatItemData(data.fieldMap[item.sourceId], isControlType(item))"
|
|
136
|
+
:code="data.fieldMap[item.sourceId]"
|
|
137
|
+
/>
|
|
109
138
|
</view>
|
|
139
|
+
<openValueMore v-else :text="formatItemData(data.fieldMap[item.sourceId], isControlType(item))" />
|
|
110
140
|
</view>
|
|
111
|
-
|
|
141
|
+
<VideoPlay ref="videoPlayRef" />
|
|
112
142
|
</template>
|
|
113
143
|
|
|
114
|
-
<style scoped lang="scss">
|
|
115
|
-
.custom-popup {
|
|
116
|
-
color: black;
|
|
117
|
-
padding: 24rpx;
|
|
118
|
-
min-width: 400rpx;
|
|
119
|
-
min-height: 500rpx;
|
|
120
|
-
// height: 600rpx;
|
|
121
|
-
font-size: 40rpx;
|
|
122
|
-
border-radius: 32rpx;
|
|
123
|
-
position:relative;
|
|
124
|
-
.footer{
|
|
125
|
-
position: absolute;
|
|
126
|
-
bottom: 24rpx;
|
|
127
|
-
width: calc(100% - 48rpx);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
</style>
|
|
144
|
+
<style scoped lang="scss"></style>
|
|
@@ -21,7 +21,7 @@ const props = defineProps({
|
|
|
21
21
|
},
|
|
22
22
|
load: {
|
|
23
23
|
type: Function as PropType<() => void>,
|
|
24
|
-
default: () => {
|
|
24
|
+
default: () => {},
|
|
25
25
|
},
|
|
26
26
|
menuTopType: {
|
|
27
27
|
type: String,
|
|
@@ -35,9 +35,7 @@ interface Icon {
|
|
|
35
35
|
id: string
|
|
36
36
|
path: string
|
|
37
37
|
}
|
|
38
|
-
const {
|
|
39
|
-
currentThemeColor,
|
|
40
|
-
} = useManualTheme()
|
|
38
|
+
const { currentThemeColor } = useManualTheme()
|
|
41
39
|
const { generateRandomColor } = useColorGenerator(currentThemeColor.value.primary)
|
|
42
40
|
const menuList = ref([])
|
|
43
41
|
const title = ref('')
|
|
@@ -54,8 +52,7 @@ const paging = ref()
|
|
|
54
52
|
// 点击菜单跳转页面
|
|
55
53
|
function gotoPage(item: any) {
|
|
56
54
|
// 跳转页面
|
|
57
|
-
if (goto(item))
|
|
58
|
-
return
|
|
55
|
+
if (goto(item)) return
|
|
59
56
|
// 打开动作面板
|
|
60
57
|
openSheet(item)
|
|
61
58
|
}
|
|
@@ -63,8 +60,7 @@ function gotoPage(item: any) {
|
|
|
63
60
|
// 点击动作面板跳转页面
|
|
64
61
|
function sheetGotoPage(item: any) {
|
|
65
62
|
// 跳转页面
|
|
66
|
-
if (goto(item))
|
|
67
|
-
return
|
|
63
|
+
if (goto(item)) return
|
|
68
64
|
// 打开动作面板
|
|
69
65
|
openSheet(item, 300)
|
|
70
66
|
}
|
|
@@ -86,7 +82,6 @@ function goto(item: any) {
|
|
|
86
82
|
return true
|
|
87
83
|
|
|
88
84
|
default:
|
|
89
|
-
|
|
90
85
|
return false
|
|
91
86
|
}
|
|
92
87
|
}
|
|
@@ -123,8 +118,7 @@ function openSheet(item: any, s = 0) {
|
|
|
123
118
|
function filterHiddenTree(tree: any, childKey = 'children', deepClone = false) {
|
|
124
119
|
// 深拷贝处理(可选)
|
|
125
120
|
const clone = (data: any) => {
|
|
126
|
-
if (!deepClone)
|
|
127
|
-
return data
|
|
121
|
+
if (!deepClone) return data
|
|
128
122
|
return JSON.parse(JSON.stringify(data))
|
|
129
123
|
}
|
|
130
124
|
|
|
@@ -153,23 +147,22 @@ onShow(() => {
|
|
|
153
147
|
// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用this.$refs.paging.reload()即可
|
|
154
148
|
function queryList() {
|
|
155
149
|
// 此处请求仅为演示,请替换为自己项目中的请求
|
|
156
|
-
menu()
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
})
|
|
150
|
+
menu()
|
|
151
|
+
.then((res: any) => {
|
|
152
|
+
// 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
|
153
|
+
if (!res?.blocks.length) {
|
|
154
|
+
toast.warning('暂无权限,请重新登录或联系管理员')
|
|
155
|
+
}
|
|
156
|
+
uni.setNavigationBarTitle({ title: res?.programName || '' }) // 设置标题
|
|
157
|
+
paging.value.complete(res?.blocks || [])
|
|
158
|
+
})
|
|
159
|
+
.catch((res: any) => {
|
|
160
|
+
// 如果请求失败写this.$refs.paging.complete(false),会自动展示错误页面
|
|
161
|
+
// 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
|
162
|
+
// 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
|
163
|
+
console.log(res, 'menu error')
|
|
164
|
+
paging.value.complete(false)
|
|
165
|
+
})
|
|
173
166
|
}
|
|
174
167
|
</script>
|
|
175
168
|
|
|
@@ -186,15 +179,28 @@ function queryList() {
|
|
|
186
179
|
<view class="border-rd-2 bg-white pa-1 dark:bg-[var(--wot-dark-background2)]">
|
|
187
180
|
<wd-grid :column="4" clickable>
|
|
188
181
|
<wd-grid-item
|
|
189
|
-
v-for="(subItem, subIndex) in item.items"
|
|
182
|
+
v-for="(subItem, subIndex) in item.items"
|
|
183
|
+
:key="subIndex"
|
|
184
|
+
use-text-slot
|
|
185
|
+
use-icon-slot
|
|
190
186
|
@itemclick="gotoPage(subItem)"
|
|
191
187
|
>
|
|
192
188
|
<template #icon>
|
|
193
|
-
<view
|
|
189
|
+
<view
|
|
190
|
+
class="flex items-center justify-center rounded-2"
|
|
191
|
+
:style="{ backgroundColor: desaturateColor(subItem.color, 0.25), height: '80rpx', width: '80rpx' }"
|
|
192
|
+
>
|
|
194
193
|
<!-- <text class="i-carbon:chart-combo-stacked text-center text-5"
|
|
195
194
|
:class="[props.icons.find(item => item.id === subItem.id)?.path]"
|
|
196
195
|
:style="{ color:desaturateColor(subItem.color,0.5) }" /> -->
|
|
197
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" width="80" height="80" viewBox="0 0 80 80"
|
|
196
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" width="80" height="80" viewBox="0 0 80 80">
|
|
197
|
+
<g fill="none" stroke-linecap="round" stroke-width="4">
|
|
198
|
+
<rect width="24" height="24" x="12" y="12" fill="#9b51e0" stroke="#9b51e0" rx="4" />
|
|
199
|
+
<rect width="24" height="24" x="44" y="12" fill="#56ccf2" stroke="#56ccf2" rx="4" />
|
|
200
|
+
<rect width="24" height="24" x="12" y="44" fill="#56ccf2" stroke="#56ccf2" rx="4" />
|
|
201
|
+
<rect width="24" height="24" x="44" y="44" fill="#9b51e0" stroke="#9b51e0" rx="4" />
|
|
202
|
+
</g>
|
|
203
|
+
</svg>
|
|
198
204
|
</view>
|
|
199
205
|
</template>
|
|
200
206
|
<template #text>
|
|
@@ -217,8 +223,15 @@ function queryList() {
|
|
|
217
223
|
</template>
|
|
218
224
|
</z-paging>
|
|
219
225
|
<wd-action-sheet
|
|
220
|
-
v-model="sheetShow"
|
|
221
|
-
|
|
226
|
+
v-model="sheetShow"
|
|
227
|
+
:z-index="9999"
|
|
228
|
+
:actions="actions"
|
|
229
|
+
:title="title"
|
|
230
|
+
@select="
|
|
231
|
+
({ item }) => {
|
|
232
|
+
sheetGotoPage(item)
|
|
233
|
+
}
|
|
234
|
+
"
|
|
222
235
|
/>
|
|
223
236
|
</template>
|
|
224
237
|
|
|
@@ -17,19 +17,17 @@ const toast = useGlobalToast()
|
|
|
17
17
|
|
|
18
18
|
function queryList() {
|
|
19
19
|
// 此处请求仅为演示,请替换为自己项目中的请求
|
|
20
|
-
menu()
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
console.log(res)
|
|
32
|
-
})
|
|
20
|
+
menu()
|
|
21
|
+
.then((res: any) => {
|
|
22
|
+
if (!res?.blocks?.length) {
|
|
23
|
+
toast.warning('暂无权限,请重新登录或联系管理员')
|
|
24
|
+
} else {
|
|
25
|
+
menuList.value = res?.blocks
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
.catch((res: any) => {
|
|
29
|
+
console.log(res)
|
|
30
|
+
})
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
/**
|
|
@@ -38,10 +36,7 @@ function queryList() {
|
|
|
38
36
|
* @param childrenKey - 子节点的键名,默认为 'children'
|
|
39
37
|
* @returns 最深层节点组成的数组
|
|
40
38
|
*/
|
|
41
|
-
function extractDeepestNodes<T>(
|
|
42
|
-
treeData: T[],
|
|
43
|
-
childrenKey: string = 'children',
|
|
44
|
-
): T[] {
|
|
39
|
+
function extractDeepestNodes<T>(treeData: T[], childrenKey: string = 'children'): T[] {
|
|
45
40
|
const result: T[] = []
|
|
46
41
|
|
|
47
42
|
/**
|
|
@@ -55,8 +50,7 @@ function extractDeepestNodes<T>(
|
|
|
55
50
|
if (children && Array.isArray(children) && children.length > 0) {
|
|
56
51
|
// 如果有子节点,继续深入
|
|
57
52
|
traverse(children, depth + 1)
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
53
|
+
} else {
|
|
60
54
|
// 如果没有子节点,这是最深层的节点,添加到结果中
|
|
61
55
|
result.push(node)
|
|
62
56
|
}
|
|
@@ -80,19 +74,16 @@ const filteredMenus = computed<MenuItem[]>(() => {
|
|
|
80
74
|
return a.value
|
|
81
75
|
}
|
|
82
76
|
const query = searchQuery.value.toLowerCase().trim()
|
|
83
|
-
return a.value.filter(
|
|
84
|
-
menu.title.toLowerCase().includes(query)
|
|
85
|
-
|| (menu.tip && menu.tip.toLowerCase().includes(query)),
|
|
77
|
+
return a.value.filter(
|
|
78
|
+
menu => menu.title.toLowerCase().includes(query) || (menu.tip && menu.tip.toLowerCase().includes(query))
|
|
86
79
|
)
|
|
87
80
|
})
|
|
88
81
|
|
|
89
82
|
function highlightedLabel(menu: MenuItem) {
|
|
90
|
-
if (!searchQuery.value.trim())
|
|
91
|
-
return menu.title
|
|
83
|
+
if (!searchQuery.value.trim()) return menu.title
|
|
92
84
|
const query = searchQuery.value.toLowerCase().trim()
|
|
93
85
|
const index = menu.title.toLowerCase().indexOf(query)
|
|
94
|
-
if (index === -1)
|
|
95
|
-
return menu.title
|
|
86
|
+
if (index === -1) return menu.title
|
|
96
87
|
const before = menu.title.substring(0, index)
|
|
97
88
|
const match = menu.title.substring(index, index + query.length)
|
|
98
89
|
const after = menu.title.substring(index + query.length)
|
|
@@ -116,8 +107,7 @@ function handleMenuClick(menu: MenuItem) {
|
|
|
116
107
|
}
|
|
117
108
|
|
|
118
109
|
function addToHistory(keyword: string) {
|
|
119
|
-
if (!keyword.trim())
|
|
120
|
-
return
|
|
110
|
+
if (!keyword.trim()) return
|
|
121
111
|
const current = [...searchHistory.value]
|
|
122
112
|
const index = current.indexOf(keyword)
|
|
123
113
|
if (index > -1) {
|
|
@@ -141,8 +131,7 @@ onMounted(() => {
|
|
|
141
131
|
if (saved) {
|
|
142
132
|
try {
|
|
143
133
|
searchHistory.value = JSON.parse(saved)
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
134
|
+
} catch {
|
|
146
135
|
searchHistory.value = []
|
|
147
136
|
}
|
|
148
137
|
}
|
|
@@ -160,7 +149,7 @@ onMounted(() => {
|
|
|
160
149
|
type="text"
|
|
161
150
|
placeholder="搜索菜单、功能..."
|
|
162
151
|
class="ml-2 flex-1 bg-transparent text-base text-slate-800 outline-none placeholder:text-slate-400"
|
|
163
|
-
|
|
152
|
+
/>
|
|
164
153
|
<view
|
|
165
154
|
v-if="searchQuery"
|
|
166
155
|
class="cursor-pointer rounded-full p-1 transition-colors hover:bg-slate-200"
|
|
@@ -173,15 +162,10 @@ onMounted(() => {
|
|
|
173
162
|
</view>
|
|
174
163
|
|
|
175
164
|
<view class="px-4 pb-4">
|
|
176
|
-
<SearchHistory
|
|
177
|
-
v-model="searchHistory"
|
|
178
|
-
@select="handleSelectHistory"
|
|
179
|
-
/>
|
|
165
|
+
<SearchHistory v-model="searchHistory" @select="handleSelectHistory" />
|
|
180
166
|
|
|
181
167
|
<view v-if="filteredMenus.length === 0" class="mt-6">
|
|
182
|
-
<p class="text-center text-sm text-slate-400">
|
|
183
|
-
未找到相关菜单
|
|
184
|
-
</p>
|
|
168
|
+
<p class="text-center text-sm text-slate-400">未找到相关菜单</p>
|
|
185
169
|
</view>
|
|
186
170
|
|
|
187
171
|
<view v-else class="mt-4">
|
|
@@ -207,10 +191,7 @@ onMounted(() => {
|
|
|
207
191
|
<wd-icon name="picture" size="22px" color="#FFF" />
|
|
208
192
|
</view>
|
|
209
193
|
<view class="flex-1 text-left">
|
|
210
|
-
<p
|
|
211
|
-
class="text-base text-slate-800 font-medium"
|
|
212
|
-
v-html="highlightedLabel(menu)"
|
|
213
|
-
/>
|
|
194
|
+
<p class="text-base text-slate-800 font-medium" v-html="highlightedLabel(menu)" />
|
|
214
195
|
<p v-if="menu.tip" class="mt-0.5 text-xs text-slate-400">
|
|
215
196
|
{{ menu.tip }}
|
|
216
197
|
</p>
|
package/composables/useMenus.ts
CHANGED
|
@@ -26,9 +26,7 @@ export interface MenuItem {
|
|
|
26
26
|
export function useMenus(props?: Props, pagingRef?: Ref<any>) {
|
|
27
27
|
const router = useRouter()
|
|
28
28
|
const toast = useGlobalToast()
|
|
29
|
-
const {
|
|
30
|
-
currentThemeColor,
|
|
31
|
-
} = useManualTheme()
|
|
29
|
+
const { currentThemeColor } = useManualTheme()
|
|
32
30
|
const colorGenerator = new RainbowColorGenerator()
|
|
33
31
|
const menuList = ref<MenuItem[]>([])
|
|
34
32
|
const title = ref('')
|
|
@@ -44,18 +42,16 @@ export function useMenus(props?: Props, pagingRef?: Ref<any>) {
|
|
|
44
42
|
const actions = ref([])
|
|
45
43
|
// 点击菜单跳转页面
|
|
46
44
|
function gotoPage(item: MenuItem) {
|
|
47
|
-
|
|
48
|
-
if (goto(item))
|
|
49
|
-
return
|
|
45
|
+
// 跳转页面
|
|
46
|
+
if (goto(item)) return
|
|
50
47
|
// 打开动作面板
|
|
51
48
|
openSheet(item)
|
|
52
49
|
}
|
|
53
50
|
|
|
54
51
|
// 点击动作面板跳转页面
|
|
55
52
|
function sheetGotoPage(item: MenuItem) {
|
|
56
|
-
|
|
57
|
-
if (goto(item))
|
|
58
|
-
return
|
|
53
|
+
// 跳转页面
|
|
54
|
+
if (goto(item)) return
|
|
59
55
|
// 打开动作面板
|
|
60
56
|
openSheet(item, 300)
|
|
61
57
|
}
|
|
@@ -72,13 +68,12 @@ export function useMenus(props?: Props, pagingRef?: Ref<any>) {
|
|
|
72
68
|
router.push(`/pages/tree-page/index?sourceId=${item.id}&title=${item.title}`)
|
|
73
69
|
return true
|
|
74
70
|
case '报表':
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
// uni.navigateTo({
|
|
72
|
+
// url: `/pages/report-table/report-table?sourceId=${item.id}&title=${item.title}`,
|
|
73
|
+
// })
|
|
78
74
|
return true
|
|
79
75
|
|
|
80
76
|
default:
|
|
81
|
-
|
|
82
77
|
return false
|
|
83
78
|
}
|
|
84
79
|
}
|
|
@@ -113,17 +108,16 @@ export function useMenus(props?: Props, pagingRef?: Ref<any>) {
|
|
|
113
108
|
* @returns {Array} 过滤后的新树形数据
|
|
114
109
|
*/
|
|
115
110
|
function filterHiddenTree(tree: any, childKey = 'children', deepClone = false) {
|
|
116
|
-
|
|
111
|
+
// 深拷贝处理(可选)
|
|
117
112
|
const clone = (data: any) => {
|
|
118
|
-
if (!deepClone)
|
|
119
|
-
return data
|
|
113
|
+
if (!deepClone) return data
|
|
120
114
|
return JSON.parse(JSON.stringify(data))
|
|
121
115
|
}
|
|
122
116
|
|
|
123
117
|
return clone(tree)
|
|
124
118
|
.filter((node: any) => !node.disabled) // 过滤当前层隐藏节点
|
|
125
119
|
.map((node: any) => {
|
|
126
|
-
|
|
120
|
+
// 递归处理子节点
|
|
127
121
|
if (Array.isArray(node[childKey])) {
|
|
128
122
|
node[childKey] = filterHiddenTree(node[childKey], childKey, deepClone)
|
|
129
123
|
}
|
|
@@ -141,31 +135,30 @@ export function useMenus(props?: Props, pagingRef?: Ref<any>) {
|
|
|
141
135
|
|
|
142
136
|
// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用this.$refs.paging.reload()即可
|
|
143
137
|
function queryList() {
|
|
144
|
-
|
|
145
|
-
menu()
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
})
|
|
138
|
+
// 此处请求仅为演示,请替换为自己项目中的请求
|
|
139
|
+
menu()
|
|
140
|
+
.then((res: any) => {
|
|
141
|
+
// 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
|
142
|
+
if (!res?.blocks?.length) {
|
|
143
|
+
toast.warning('暂无权限,请重新登录或联系管理员')
|
|
144
|
+
}
|
|
145
|
+
navTitle.value = res?.programName || ''
|
|
146
|
+
uni.setNavigationBarTitle({ title: res?.programName || '' }) // 设置标题
|
|
147
|
+
pagingRef?.value.complete(res?.blocks || [])
|
|
148
|
+
})
|
|
149
|
+
.catch((res: any) => {
|
|
150
|
+
console.log(res)
|
|
151
|
+
// 如果请求失败写this.$refs.paging.complete(false),会自动展示错误页面
|
|
152
|
+
// 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
|
153
|
+
// 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
|
154
|
+
pagingRef?.value.complete(false)
|
|
155
|
+
})
|
|
163
156
|
}
|
|
164
157
|
|
|
165
158
|
// 快速访问菜单
|
|
166
159
|
const sectionmenu = ref<MenuItem[]>([])
|
|
167
160
|
const filersectiomenus = computed(() => {
|
|
168
|
-
|
|
161
|
+
// 截取数组前4项
|
|
169
162
|
return sectionmenu.value.slice(0, 4)
|
|
170
163
|
})
|
|
171
164
|
|
|
@@ -174,12 +167,10 @@ export function useMenus(props?: Props, pagingRef?: Ref<any>) {
|
|
|
174
167
|
const res = await fastmenu()
|
|
175
168
|
if (res.fastMenu) {
|
|
176
169
|
sectionmenu.value = res.fastMenu.QuickQueryBar || []
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
170
|
+
} else {
|
|
179
171
|
sectionmenu.value = []
|
|
180
172
|
}
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
173
|
+
} catch (error) {
|
|
183
174
|
console.log(error)
|
|
184
175
|
}
|
|
185
176
|
}
|