wui-components-v2 1.0.13 → 1.0.14
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 -0
- package/api/index.ts +2 -13
- package/api/login.ts +51 -0
- package/api/menu.ts +7 -0
- package/components/demo-block/demo-block.vue +66 -0
- package/components/global-loading/GlobalLoading.md +366 -0
- package/components/global-loading/global-loading.vue +55 -0
- package/components/global-message/GlobalMessage.md +570 -0
- package/components/global-message/global-message.vue +64 -0
- package/components/global-toast/GlobalToast.md +261 -0
- package/components/global-toast/global-toast.vue +56 -0
- package/components/login/login.vue +22 -0
- package/components/login-form/login-form.vue +106 -0
- package/components/menus/menus.vue +180 -0
- package/components/privacy-popup/privacy-popup.vue +178 -0
- package/components/{system-settings.vue → system-settings/system-settings.vue} +3 -2
- package/composables/types/user.ts +5 -0
- package/composables/useGlobalLoading.ts +46 -0
- package/composables/useGlobalMessage.ts +54 -0
- package/composables/useGlobalToast.ts +62 -0
- package/composables/useTheme.ts +1 -1
- package/composables/useUser.ts +21 -0
- package/index.ts +3 -2
- package/package.json +6 -1
- package/store/userStore.ts +22 -0
- package/utils/index.ts +9 -0
- package/utils/rsaEncrypt.ts +10 -0
- package/api/core/handlers.ts +0 -106
- package/api/core/instance.ts +0 -60
- package/api/core/middleware.ts +0 -92
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# GlobalToast 全局提示组件
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
GlobalToast 是基于 `wot-design-uni` 的 `wd-toast` 组件封装的全局提示组件,通过 Pinia 状态管理实现全局调用。
|
|
6
|
+
|
|
7
|
+
## 组件特性
|
|
8
|
+
|
|
9
|
+
- 基于 `wd-toast` 组件封装
|
|
10
|
+
- 支持多种提示类型:成功、错误、信息、警告
|
|
11
|
+
- 自动页面路径检测,确保在正确页面显示
|
|
12
|
+
- 支持自定义图标、位置、持续时间等
|
|
13
|
+
- 虚拟节点设计,不在 DOM 中创建额外层级
|
|
14
|
+
|
|
15
|
+
## 安装使用
|
|
16
|
+
|
|
17
|
+
### 1. 注册全局组件
|
|
18
|
+
|
|
19
|
+
在 `App.vue` 或根组件中注册:
|
|
20
|
+
|
|
21
|
+
```vue
|
|
22
|
+
<template>
|
|
23
|
+
<div>
|
|
24
|
+
<!-- 其他内容 -->
|
|
25
|
+
<GlobalToast />
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2. 在组件中使用
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { useGlobalToast } from '@/composables/useGlobalToast'
|
|
34
|
+
|
|
35
|
+
const toast = useGlobalToast()
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## API 文档
|
|
39
|
+
|
|
40
|
+
### 基础用法
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// 普通提示
|
|
44
|
+
toast.show('这是一条提示信息')
|
|
45
|
+
|
|
46
|
+
// 自定义配置
|
|
47
|
+
toast.show({
|
|
48
|
+
msg: '自定义提示',
|
|
49
|
+
duration: 3000,
|
|
50
|
+
position: 'top'
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 快捷方法
|
|
55
|
+
|
|
56
|
+
#### success(option)
|
|
57
|
+
成功提示,显示绿色成功图标
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
toast.success('操作成功')
|
|
61
|
+
toast.success({
|
|
62
|
+
msg: '保存成功',
|
|
63
|
+
duration: 2000
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**默认配置:**
|
|
68
|
+
- 图标:success
|
|
69
|
+
- 持续时间:1500ms
|
|
70
|
+
|
|
71
|
+
#### error(option)
|
|
72
|
+
错误提示,显示红色错误图标
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
toast.error('操作失败')
|
|
76
|
+
toast.error({
|
|
77
|
+
msg: '网络错误,请重试',
|
|
78
|
+
duration: 3000
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**默认配置:**
|
|
83
|
+
- 图标:error
|
|
84
|
+
- 方向:vertical(垂直布局)
|
|
85
|
+
|
|
86
|
+
#### info(option)
|
|
87
|
+
信息提示,显示蓝色信息图标
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
toast.info('这是一条信息')
|
|
91
|
+
toast.info({
|
|
92
|
+
msg: '请注意查看',
|
|
93
|
+
position: 'top'
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**默认配置:**
|
|
98
|
+
- 图标:info
|
|
99
|
+
|
|
100
|
+
#### warning(option)
|
|
101
|
+
警告提示,显示黄色警告图标
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
toast.warning('警告信息')
|
|
105
|
+
toast.warning({
|
|
106
|
+
msg: '请谨慎操作',
|
|
107
|
+
iconName: 'warning'
|
|
108
|
+
})
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**默认配置:**
|
|
112
|
+
- 图标:warning
|
|
113
|
+
|
|
114
|
+
#### close()
|
|
115
|
+
手动关闭提示
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
toast.close()
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 参数说明
|
|
122
|
+
|
|
123
|
+
### ToastOptions
|
|
124
|
+
|
|
125
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
126
|
+
|------|------|--------|------|
|
|
127
|
+
| msg | string | - | 提示内容 |
|
|
128
|
+
| duration | number | 2000 | 持续时间(ms),0表示不自动关闭 |
|
|
129
|
+
| position | string | 'middle' | 显示位置:'top' \| 'middle' \| 'bottom' |
|
|
130
|
+
| iconName | string | - | 图标名称 |
|
|
131
|
+
| direction | string | - | 布局方向:'horizontal' \| 'vertical' |
|
|
132
|
+
| cover | boolean | false | 是否显示遮罩 |
|
|
133
|
+
| show | boolean | - | 是否显示(内部使用) |
|
|
134
|
+
|
|
135
|
+
### 方法参数
|
|
136
|
+
|
|
137
|
+
所有方法都支持两种参数类型:
|
|
138
|
+
|
|
139
|
+
1. **字符串参数**:直接传入提示文本
|
|
140
|
+
2. **选项对象**:传入完整的 ToastOptions 配置
|
|
141
|
+
|
|
142
|
+
## 使用示例
|
|
143
|
+
|
|
144
|
+
### 基础示例
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
export default {
|
|
148
|
+
setup() {
|
|
149
|
+
const toast = useGlobalToast()
|
|
150
|
+
|
|
151
|
+
const handleSuccess = () => {
|
|
152
|
+
toast.success('操作成功!')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const handleError = () => {
|
|
156
|
+
toast.error('操作失败,请重试')
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const handleCustom = () => {
|
|
160
|
+
toast.show({
|
|
161
|
+
msg: '自定义提示',
|
|
162
|
+
duration: 5000,
|
|
163
|
+
position: 'top',
|
|
164
|
+
iconName: 'info'
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
handleSuccess,
|
|
170
|
+
handleError,
|
|
171
|
+
handleCustom
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 异步操作示例
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
async function handleSubmit() {
|
|
181
|
+
const toast = useGlobalToast()
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
// 提交数据
|
|
185
|
+
await submitData()
|
|
186
|
+
toast.success('提交成功')
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
toast.error(`提交失败:${error.message}`)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 长文本提示
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
function showLongMessage() {
|
|
198
|
+
toast.info({
|
|
199
|
+
msg: '这是一条很长的提示信息,可能需要更长的显示时间',
|
|
200
|
+
duration: 4000,
|
|
201
|
+
position: 'top'
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 实现原理
|
|
207
|
+
|
|
208
|
+
### 状态管理
|
|
209
|
+
- 使用 Pinia 管理全局状态
|
|
210
|
+
- 状态包含:`toastOptions`(提示配置)、`currentPage`(当前页面路径)
|
|
211
|
+
|
|
212
|
+
### 页面检测机制
|
|
213
|
+
- 调用提示方法时记录当前页面路径
|
|
214
|
+
- 组件监听状态变化时验证页面路径
|
|
215
|
+
- 确保提示信息在正确的页面显示
|
|
216
|
+
|
|
217
|
+
### 组件配置
|
|
218
|
+
```typescript
|
|
219
|
+
export default {
|
|
220
|
+
options: {
|
|
221
|
+
virtualHost: true, // 虚拟节点
|
|
222
|
+
addGlobalClass: true, // 支持全局样式
|
|
223
|
+
styleIsolation: 'shared' // 样式隔离共享
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## 最佳实践
|
|
229
|
+
|
|
230
|
+
1. **选择合适的提示类型**
|
|
231
|
+
- 成功操作使用 `success()`
|
|
232
|
+
- 错误信息使用 `error()`
|
|
233
|
+
- 一般信息使用 `info()`
|
|
234
|
+
- 警告信息使用 `warning()`
|
|
235
|
+
|
|
236
|
+
2. **控制显示时长**
|
|
237
|
+
- 简短消息:1500-2000ms
|
|
238
|
+
- 长消息:3000-4000ms
|
|
239
|
+
- 重要消息:可设置为0,用户手动关闭
|
|
240
|
+
|
|
241
|
+
3. **位置选择**
|
|
242
|
+
- 一般提示:middle(默认)
|
|
243
|
+
- 不遮挡内容:top 或 bottom
|
|
244
|
+
- 重要提示:middle + cover
|
|
245
|
+
|
|
246
|
+
4. **避免频繁调用**
|
|
247
|
+
```typescript
|
|
248
|
+
// ❌ 避免快速连续调用
|
|
249
|
+
toast.success('第一条')
|
|
250
|
+
toast.success('第二条') // 会覆盖第一条
|
|
251
|
+
|
|
252
|
+
// ✅ 推荐做法
|
|
253
|
+
toast.success('操作完成')
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## 注意事项
|
|
257
|
+
|
|
258
|
+
1. 组件需要在应用根组件中注册才能正常使用
|
|
259
|
+
2. 提示会自动在对应页面显示,切换页面时会自动关闭
|
|
260
|
+
3. 同时只能显示一个提示,新的提示会覆盖旧的提示
|
|
261
|
+
4. 使用 `duration: 0` 时记得手动调用 `close()` 关闭
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { storeToRefs } from 'pinia'
|
|
3
|
+
import { useToast } from 'wot-design-uni'
|
|
4
|
+
import { defineOptions, nextTick, ref, watch } from 'vue'
|
|
5
|
+
import { useGlobalToast } from '../../composables/useGlobalToast'
|
|
6
|
+
import { getCurrentPath } from '../../utils/index'
|
|
7
|
+
|
|
8
|
+
defineOptions({
|
|
9
|
+
name: 'GlobalToast',
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const { toastOptions, currentPage } = storeToRefs(useGlobalToast())
|
|
13
|
+
|
|
14
|
+
const { close: closeGlobalToast } = useGlobalToast()
|
|
15
|
+
|
|
16
|
+
const toast = useToast('globalToast')
|
|
17
|
+
const currentPath = getCurrentPath()
|
|
18
|
+
|
|
19
|
+
// #ifdef MP-ALIPAY
|
|
20
|
+
const hackAlipayVisible = ref(false)
|
|
21
|
+
|
|
22
|
+
nextTick(() => {
|
|
23
|
+
hackAlipayVisible.value = true
|
|
24
|
+
})
|
|
25
|
+
// #endif
|
|
26
|
+
|
|
27
|
+
watch(() => toastOptions.value, (newVal) => {
|
|
28
|
+
if (newVal && newVal.show) {
|
|
29
|
+
if (currentPage.value === currentPath) {
|
|
30
|
+
toast.show(toastOptions.value)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
toast.close()
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<script lang="ts">
|
|
40
|
+
export default {
|
|
41
|
+
options: {
|
|
42
|
+
virtualHost: true,
|
|
43
|
+
addGlobalClass: true,
|
|
44
|
+
styleIsolation: 'shared',
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<!-- #ifdef MP-ALIPAY -->
|
|
51
|
+
<wd-toast v-if="hackAlipayVisible" selector="globalToast" :closed="closeGlobalToast" />
|
|
52
|
+
<!-- #endif -->
|
|
53
|
+
<!-- #ifndef MP-ALIPAY -->
|
|
54
|
+
<wd-toast selector="globalToast" :closed="closeGlobalToast" />
|
|
55
|
+
<!-- #endif -->
|
|
56
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { defineOptions } from 'vue'
|
|
3
|
+
import LoginForm from '../login-form/login-form.vue'
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'Login',
|
|
7
|
+
})
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<view class="pa-3">
|
|
12
|
+
<view class="flex flex-col items-center justify-center pa-3 pb-5">
|
|
13
|
+
<wd-img :width="100" :height="100" round src="../../../static/vite.png" />
|
|
14
|
+
<view class="text-center">
|
|
15
|
+
<text class="text-2xl">
|
|
16
|
+
欢迎登录
|
|
17
|
+
</text>
|
|
18
|
+
</view>
|
|
19
|
+
</view>
|
|
20
|
+
<LoginForm />
|
|
21
|
+
</view>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { defineOptions } from 'vue'
|
|
3
|
+
import { useRouter } from 'uni-mini-router'
|
|
4
|
+
import { useGlobalToast } from '../../composables/useGlobalToast'
|
|
5
|
+
import { getUserConfig, login } from '../../api/login'
|
|
6
|
+
import { useUser } from '../../composables/useUser'
|
|
7
|
+
|
|
8
|
+
defineOptions({
|
|
9
|
+
name: 'LoginForm',
|
|
10
|
+
})
|
|
11
|
+
const router = useRouter()
|
|
12
|
+
const toast = useGlobalToast()
|
|
13
|
+
const { setUserInfo } = useUser()
|
|
14
|
+
const model = reactive<{
|
|
15
|
+
name: string
|
|
16
|
+
password: string
|
|
17
|
+
remember: boolean
|
|
18
|
+
}>({
|
|
19
|
+
name: uni.getStorageSync('USER_NAME') || '',
|
|
20
|
+
password: uni.getStorageSync('USER_PASSWORD') || '',
|
|
21
|
+
remember: uni.getStorageSync('REMEMBER') || false,
|
|
22
|
+
})
|
|
23
|
+
const { setTabbarItemActive } = useTabbar()
|
|
24
|
+
const form = ref()
|
|
25
|
+
|
|
26
|
+
function handleSubmit() {
|
|
27
|
+
form.value
|
|
28
|
+
.validate()
|
|
29
|
+
.then(async ({ valid, errors }: any) => {
|
|
30
|
+
if (valid) {
|
|
31
|
+
try {
|
|
32
|
+
// 登录
|
|
33
|
+
const res = await login(model.name, model.password)
|
|
34
|
+
|
|
35
|
+
if (res.token) {
|
|
36
|
+
// 保存token
|
|
37
|
+
uni.setStorageSync('TOKEN', res.token)
|
|
38
|
+
// 获取用户配置
|
|
39
|
+
const res1 = await getUserConfig()
|
|
40
|
+
if (res1.status === 'success') {
|
|
41
|
+
// 保存用户信息
|
|
42
|
+
setUserInfo(res1.user)
|
|
43
|
+
|
|
44
|
+
// 记住账号密码
|
|
45
|
+
if (model.remember) {
|
|
46
|
+
uni.setStorageSync('USER_NAME', model.name)
|
|
47
|
+
uni.setStorageSync('USER_PASSWORD', model.password)
|
|
48
|
+
uni.setStorageSync('REMEMBER', model.remember)
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// 删除账号密码
|
|
52
|
+
uni.removeStorageSync('USER_NAME')
|
|
53
|
+
uni.removeStorageSync('USER_PASSWORD')
|
|
54
|
+
uni.removeStorageSync('REMEMBER')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 跳转首页
|
|
58
|
+
router.pushTab('/pages/index/index')
|
|
59
|
+
setTabbarItemActive('index')
|
|
60
|
+
toast.success({ msg: '登录成功!' })
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
toast.error({ msg: res.message })
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.log(error, 'error')
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.log(errors, 'errors')
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
.catch((error: any) => {
|
|
76
|
+
console.log(error, 'error')
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<template>
|
|
82
|
+
<view class="border-rd-2 bg-white pa-3 dark:bg-[var(--wot-dark-background2)]">
|
|
83
|
+
<wd-form ref="form" :model="model">
|
|
84
|
+
<wd-cell-group border>
|
|
85
|
+
<wd-input
|
|
86
|
+
v-model="model.name" label="用户名" label-width="100px" prop="name" clearable placeholder="请输入用户名"
|
|
87
|
+
:rules="[{ required: true, message: '请填写用户名' }]"
|
|
88
|
+
/>
|
|
89
|
+
<wd-input
|
|
90
|
+
v-model="model.password" label="密码" label-width="100px" prop="password" show-password clearable
|
|
91
|
+
placeholder="请输入密码" :rules="[{ required: true, message: '请填写密码' }]"
|
|
92
|
+
/>
|
|
93
|
+
<view class="p-4 pb-0 pt-0">
|
|
94
|
+
<wd-checkbox v-model="model.remember" shape="square">
|
|
95
|
+
记住密码
|
|
96
|
+
</wd-checkbox>
|
|
97
|
+
</view>
|
|
98
|
+
</wd-cell-group>
|
|
99
|
+
<view class="p-4">
|
|
100
|
+
<wd-button block @click="handleSubmit">
|
|
101
|
+
登录
|
|
102
|
+
</wd-button>
|
|
103
|
+
</view>
|
|
104
|
+
</wd-form>
|
|
105
|
+
</view>
|
|
106
|
+
</template>
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { PropType } from 'vue'
|
|
3
|
+
import { computed, defineOptions, defineProps, onMounted, ref } from 'vue'
|
|
4
|
+
import { useRouter } from 'uni-mini-router'
|
|
5
|
+
import { useGlobalToast } from '../../composables/useGlobalToast'
|
|
6
|
+
import { menu } from '../../api/menu'
|
|
7
|
+
import demoBlock from '../demo-block/demo-block.vue'
|
|
8
|
+
|
|
9
|
+
defineOptions({
|
|
10
|
+
name: 'Menus',
|
|
11
|
+
})
|
|
12
|
+
const props = defineProps({
|
|
13
|
+
icons: {
|
|
14
|
+
type: Array as PropType<Icon[]>,
|
|
15
|
+
default: () => [],
|
|
16
|
+
},
|
|
17
|
+
load: {
|
|
18
|
+
type: Function as PropType<() => void>,
|
|
19
|
+
default: () => {},
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
// const router = useRouter()
|
|
23
|
+
// const toast = useGlobalToast()
|
|
24
|
+
interface Icon {
|
|
25
|
+
id: string
|
|
26
|
+
path: string
|
|
27
|
+
}
|
|
28
|
+
const menuList = ref([])
|
|
29
|
+
const title = ref('')
|
|
30
|
+
const filtermenu = computed(() => {
|
|
31
|
+
const arr = filterHiddenTree(menuList.value, 'items', true)
|
|
32
|
+
console.log(arr)
|
|
33
|
+
return arr
|
|
34
|
+
})
|
|
35
|
+
const sheetShow = ref(false)
|
|
36
|
+
const actions = ref([])
|
|
37
|
+
const paging = ref()
|
|
38
|
+
|
|
39
|
+
// 点击菜单跳转页面
|
|
40
|
+
function gotoPage(item: any) {
|
|
41
|
+
// 跳转页面
|
|
42
|
+
if (goto(item))
|
|
43
|
+
return
|
|
44
|
+
// 打开动作面板
|
|
45
|
+
openSheet(item)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 点击动作面板跳转页面
|
|
49
|
+
function sheetGotoPage(item: any) {
|
|
50
|
+
// 跳转页面
|
|
51
|
+
if (goto(item))
|
|
52
|
+
return
|
|
53
|
+
// 打开动作面板
|
|
54
|
+
openSheet(item, 300)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 跳转页面
|
|
58
|
+
function goto(item: any) {
|
|
59
|
+
return
|
|
60
|
+
console.log(item.pageType)
|
|
61
|
+
switch (item.pageType) {
|
|
62
|
+
case '列表':
|
|
63
|
+
if (item.customPath) {
|
|
64
|
+
uni.navigateTo({
|
|
65
|
+
url: `/${item.customPath}`,
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
uni.navigateTo({
|
|
70
|
+
url: `/pages/table/table?sourceId=${item.id}&pageTitle=${item.title}`,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return true
|
|
75
|
+
|
|
76
|
+
case '报表':
|
|
77
|
+
uni.navigateTo({
|
|
78
|
+
url: `/pages/report-table/report-table?sourceId=${item.id}&pageTitle=${item.title}`,
|
|
79
|
+
})
|
|
80
|
+
return true
|
|
81
|
+
|
|
82
|
+
default:
|
|
83
|
+
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 打开wd-action-sheet动作面板
|
|
89
|
+
function openSheet(item: any, s = 0) {
|
|
90
|
+
if (item.items) {
|
|
91
|
+
title.value = item.title
|
|
92
|
+
actions.value = item.items
|
|
93
|
+
? item.items.map((item: any) => {
|
|
94
|
+
return {
|
|
95
|
+
name: item.title,
|
|
96
|
+
// color: '#00000073',
|
|
97
|
+
...item,
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
: []
|
|
101
|
+
|
|
102
|
+
// 设置二次打开的过渡时间
|
|
103
|
+
const id = setTimeout(() => {
|
|
104
|
+
sheetShow.value = true
|
|
105
|
+
clearTimeout(id)
|
|
106
|
+
}, s)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 根据 `disabled: true` 过滤树形数组(支持自定义子节点字段)
|
|
112
|
+
* @param {Array} tree 原始树形数据
|
|
113
|
+
* @param {string} [childKey] 子节点字段名
|
|
114
|
+
* @param {boolean} [deepClone] 是否深拷贝原数据
|
|
115
|
+
* @returns {Array} 过滤后的新树形数据
|
|
116
|
+
*/
|
|
117
|
+
function filterHiddenTree(tree: any, childKey = 'children', deepClone = false) {
|
|
118
|
+
// 深拷贝处理(可选)
|
|
119
|
+
const clone = (data: any) => {
|
|
120
|
+
if (!deepClone)
|
|
121
|
+
return data
|
|
122
|
+
return JSON.parse(JSON.stringify(data))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return clone(tree)
|
|
126
|
+
.filter((node: any) => !node.disabled) // 过滤当前层隐藏节点
|
|
127
|
+
.map((node: any) => {
|
|
128
|
+
// 递归处理子节点
|
|
129
|
+
if (Array.isArray(node[childKey])) {
|
|
130
|
+
node[childKey] = filterHiddenTree(node[childKey], childKey, deepClone)
|
|
131
|
+
}
|
|
132
|
+
const icon = props.icons.find((item: any) => {
|
|
133
|
+
return item.id === node.id
|
|
134
|
+
})
|
|
135
|
+
return {
|
|
136
|
+
...node,
|
|
137
|
+
iconPath: (icon as any)?.path,
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用this.$refs.paging.reload()即可
|
|
143
|
+
function queryList() {
|
|
144
|
+
// 此处请求仅为演示,请替换为自己项目中的请求
|
|
145
|
+
menu().then((res: any) => {
|
|
146
|
+
// 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
|
147
|
+
paging.value.complete(res?.blocks || [])
|
|
148
|
+
// uni.setNavigationBarTitle({ title: res.data?.programName || '' })
|
|
149
|
+
}).catch((res: any) => {
|
|
150
|
+
// 如果请求失败写this.$refs.paging.complete(false),会自动展示错误页面
|
|
151
|
+
// 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
|
152
|
+
// 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
|
153
|
+
console.log(res, 'menu error')
|
|
154
|
+
paging.value.complete(false)
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
</script>
|
|
158
|
+
|
|
159
|
+
<template>
|
|
160
|
+
<z-paging ref="paging" v-model="menuList" class="z-99" :loading-more-enabled="false" @query="queryList" @on-refresh="props.load">
|
|
161
|
+
<template #top>
|
|
162
|
+
<slot name="top" />
|
|
163
|
+
</template>
|
|
164
|
+
<demoBlock v-for="(item, index) in filtermenu" :key="index" :title=" item.title " transparent>
|
|
165
|
+
<view class="border-rd-2 bg-white pa-1 dark:bg-[var(--wot-dark-background2)]">
|
|
166
|
+
<wd-grid :column="4" clickable>
|
|
167
|
+
<wd-grid-item v-for="(subItem, subIndex) in item.items" :key="subIndex" icon="picture" :text="subItem.title" @itemclick="gotoPage(subItem)" />
|
|
168
|
+
</wd-grid>
|
|
169
|
+
</view>
|
|
170
|
+
</demoBlock>
|
|
171
|
+
<wd-action-sheet
|
|
172
|
+
v-model="sheetShow"
|
|
173
|
+
:z-index="9999" :actions="actions" :title="title"
|
|
174
|
+
@select="({ item }) => { sheetGotoPage(item) }"
|
|
175
|
+
/>
|
|
176
|
+
<template #bottom>
|
|
177
|
+
<slot name="bottom" />
|
|
178
|
+
</template>
|
|
179
|
+
</z-paging>
|
|
180
|
+
</template>
|