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,178 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { defineEmits, defineOptions, defineProps, onBeforeMount, ref, withDefaults } from 'vue'
|
|
3
|
+
|
|
4
|
+
defineOptions({
|
|
5
|
+
name: 'PrivacyPopup',
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
withDefaults(defineProps<Props>(), {
|
|
9
|
+
title: '用户隐私保护提示',
|
|
10
|
+
desc: '感谢您使用本应用,您使用本应用的服务之前请仔细阅读并同意',
|
|
11
|
+
subDesc: '。当您点击同意并开始时用产品服务时,即表示你已理解并同意该条款内容,该条款将对您产生法律约束力。如您拒绝,将无法使用相应服务。',
|
|
12
|
+
protocol: '《用户隐私保护指引》',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const emit = defineEmits(['agree', 'disagree'])
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
title?: string // 标题
|
|
19
|
+
desc?: string // 描述
|
|
20
|
+
subDesc?: string // 字描述
|
|
21
|
+
protocol?: string // 协议名称
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const showPopup = ref<boolean>(false) // 是否展示popup
|
|
25
|
+
|
|
26
|
+
const privacyResolves = ref(new Set()) // onNeedPrivacyAuthorization的reslove
|
|
27
|
+
|
|
28
|
+
function privacyHandler(resolve: any) {
|
|
29
|
+
showPopup.value = true
|
|
30
|
+
privacyResolves.value.add(resolve)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
onBeforeMount(() => {
|
|
34
|
+
// 注册监听
|
|
35
|
+
if (wx.onNeedPrivacyAuthorization) {
|
|
36
|
+
wx.onNeedPrivacyAuthorization((resolve: any) => {
|
|
37
|
+
if (typeof privacyHandler === 'function') {
|
|
38
|
+
privacyHandler(resolve)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 同意隐私协议
|
|
46
|
+
*/
|
|
47
|
+
function handleAgree() {
|
|
48
|
+
showPopup.value = false
|
|
49
|
+
privacyResolves.value.forEach((resolve: any) => {
|
|
50
|
+
resolve({
|
|
51
|
+
event: 'agree',
|
|
52
|
+
buttonId: 'agree-btn',
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
privacyResolves.value.clear()
|
|
56
|
+
emit('agree')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 拒绝隐私协议
|
|
61
|
+
*/
|
|
62
|
+
function handleDisagree() {
|
|
63
|
+
showPopup.value = false
|
|
64
|
+
privacyResolves.value.forEach((resolve: any) => {
|
|
65
|
+
resolve({
|
|
66
|
+
event: 'disagree',
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
privacyResolves.value.clear()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 打开隐私协议
|
|
74
|
+
*/
|
|
75
|
+
function openPrivacyContract() {
|
|
76
|
+
wx.openPrivacyContract({})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 弹出框关闭时清空
|
|
81
|
+
*/
|
|
82
|
+
function handleClose() {
|
|
83
|
+
privacyResolves.value.clear()
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<script lang="ts">
|
|
88
|
+
export default {
|
|
89
|
+
options: {
|
|
90
|
+
virtualHost: true,
|
|
91
|
+
addGlobalClass: true,
|
|
92
|
+
styleIsolation: 'shared',
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<template>
|
|
98
|
+
<view>
|
|
99
|
+
<wd-popup v-model="showPopup" :close-on-click-modal="false" custom-class="wd-privacy-popup" @close="handleClose">
|
|
100
|
+
<view class="wd-privacy-popup__header">
|
|
101
|
+
<!-- 标题 -->
|
|
102
|
+
<view class="wd-picker__title">
|
|
103
|
+
{{ title }}
|
|
104
|
+
</view>
|
|
105
|
+
</view>
|
|
106
|
+
<view class="wd-privacy-popup__container">
|
|
107
|
+
<text>{{ desc }}</text>
|
|
108
|
+
<text class="wd-privacy-popup__container-protocol" @click="openPrivacyContract">
|
|
109
|
+
{{ protocol }}
|
|
110
|
+
</text>
|
|
111
|
+
<text>{{ subDesc }}</text>
|
|
112
|
+
</view>
|
|
113
|
+
<view class="wd-privacy-popup__footer">
|
|
114
|
+
<button id="disagree-btn" class="is-block is-round is-medium is-plain wd-privacy-popup__footer-disagree wd-button" @click="handleDisagree">
|
|
115
|
+
拒绝
|
|
116
|
+
</button>
|
|
117
|
+
<button
|
|
118
|
+
id="agree-btn"
|
|
119
|
+
class="wd-button is-block is-round is-medium is-primary wd-privacy-popup__footer-agree"
|
|
120
|
+
open-type="agreePrivacyAuthorization"
|
|
121
|
+
@agreeprivacyauthorization="handleAgree"
|
|
122
|
+
>
|
|
123
|
+
同意
|
|
124
|
+
</button>
|
|
125
|
+
</view>
|
|
126
|
+
</wd-popup>
|
|
127
|
+
</view>
|
|
128
|
+
</template>
|
|
129
|
+
|
|
130
|
+
<style lang="scss" scoped>
|
|
131
|
+
@import 'wot-design-uni/components/wd-button/index.scss';
|
|
132
|
+
:deep(.wd-privacy-popup) {
|
|
133
|
+
width: 600rpx;
|
|
134
|
+
padding: 0 24rpx;
|
|
135
|
+
box-sizing: border-box;
|
|
136
|
+
border-radius: 32rpx;
|
|
137
|
+
overflow: hidden;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.wd-privacy-popup {
|
|
141
|
+
&__header {
|
|
142
|
+
width: 100%;
|
|
143
|
+
height: 128rpx;
|
|
144
|
+
line-height: 128rpx;
|
|
145
|
+
color: rgba(0, 0, 0, 0.85);
|
|
146
|
+
font-size: 30rpx;
|
|
147
|
+
padding: 0 12rpx;
|
|
148
|
+
box-sizing: border-box;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
&__container {
|
|
152
|
+
width: 100%;
|
|
153
|
+
box-sizing: border-box;
|
|
154
|
+
padding: 0 12rpx;
|
|
155
|
+
margin-bottom: 32rpx;
|
|
156
|
+
|
|
157
|
+
font-size: 28rpx;
|
|
158
|
+
line-height: 1.8;
|
|
159
|
+
color: #3e3e3e;
|
|
160
|
+
text-align: left;
|
|
161
|
+
font-weight: 550;
|
|
162
|
+
&-protocol {
|
|
163
|
+
color: #4d80f0;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
&__footer {
|
|
168
|
+
display: flex;
|
|
169
|
+
justify-content: space-between;
|
|
170
|
+
padding-bottom: 36rpx;
|
|
171
|
+
|
|
172
|
+
button {
|
|
173
|
+
border: none;
|
|
174
|
+
outline: none;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
</style>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, defineOptions } from 'vue'
|
|
3
|
-
import { useManualTheme } from '
|
|
4
|
-
import type { LocaleOption, ThemeColorOption } from '
|
|
3
|
+
import { useManualTheme } from '../../composables/useManualTheme'
|
|
4
|
+
import type { LocaleOption, ThemeColorOption } from '../../composables/useManualTheme'
|
|
5
|
+
import demoBlock from '../demo-block/demo-block.vue'
|
|
5
6
|
|
|
6
7
|
defineOptions({
|
|
7
8
|
name: 'SystemSettings',
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: weisheng
|
|
3
|
+
* @Date: 2025-04-18 10:46:28
|
|
4
|
+
* @LastEditTime: 2025-06-14 21:24:21
|
|
5
|
+
* @LastEditors: weisheng
|
|
6
|
+
* @Description:
|
|
7
|
+
* @FilePath: /wot-demo/src/composables/useGlobalLoading.ts
|
|
8
|
+
* 记得注释
|
|
9
|
+
*/
|
|
10
|
+
import { defineStore } from 'pinia'
|
|
11
|
+
import type { ToastOptions } from 'wot-design-uni/components/wd-toast/types'
|
|
12
|
+
import { getCurrentPath } from '../utils/index'
|
|
13
|
+
|
|
14
|
+
interface GlobalLoading {
|
|
15
|
+
loadingOptions: ToastOptions
|
|
16
|
+
currentPage: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const defaultOptions: ToastOptions = {
|
|
20
|
+
show: false,
|
|
21
|
+
}
|
|
22
|
+
export const useGlobalLoading = defineStore('global-loading', {
|
|
23
|
+
state: (): GlobalLoading => ({
|
|
24
|
+
loadingOptions: defaultOptions,
|
|
25
|
+
currentPage: '',
|
|
26
|
+
}),
|
|
27
|
+
getters: {},
|
|
28
|
+
actions: {
|
|
29
|
+
// 加载提示
|
|
30
|
+
loading(option: ToastOptions | string) {
|
|
31
|
+
this.currentPage = getCurrentPath()
|
|
32
|
+
this.loadingOptions = CommonUtil.deepMerge({
|
|
33
|
+
iconName: 'loading',
|
|
34
|
+
duration: 0,
|
|
35
|
+
cover: true,
|
|
36
|
+
position: 'middle',
|
|
37
|
+
show: true,
|
|
38
|
+
}, typeof option === 'string' ? { msg: option } : option) as ToastOptions
|
|
39
|
+
},
|
|
40
|
+
// 关闭Toast
|
|
41
|
+
close() {
|
|
42
|
+
this.loadingOptions = defaultOptions
|
|
43
|
+
this.currentPage = ''
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
})
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import type { MessageOptions, MessageResult } from 'wot-design-uni/components/wd-message-box/types'
|
|
3
|
+
|
|
4
|
+
import { getCurrentPath } from '../utils/index'
|
|
5
|
+
|
|
6
|
+
export type GlobalMessageOptions = MessageOptions & {
|
|
7
|
+
success?: (res: MessageResult) => void
|
|
8
|
+
fail?: (res: MessageResult) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface GlobalMessage {
|
|
12
|
+
messageOptions: GlobalMessageOptions | null
|
|
13
|
+
currentPage: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const useGlobalMessage = defineStore('global-message', {
|
|
17
|
+
state: (): GlobalMessage => ({
|
|
18
|
+
messageOptions: null,
|
|
19
|
+
currentPage: '',
|
|
20
|
+
}),
|
|
21
|
+
actions: {
|
|
22
|
+
show(option: GlobalMessageOptions | string) {
|
|
23
|
+
this.currentPage = getCurrentPath()
|
|
24
|
+
this.messageOptions = {
|
|
25
|
+
...(CommonUtil.isString(option) ? { title: option } : option),
|
|
26
|
+
cancelButtonProps: {
|
|
27
|
+
round: false,
|
|
28
|
+
},
|
|
29
|
+
confirmButtonProps: {
|
|
30
|
+
round: false,
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
alert(option: GlobalMessageOptions | string) {
|
|
35
|
+
const messageOptions = CommonUtil.deepMerge({ type: 'alert' }, CommonUtil.isString(option) ? { title: option } : option) as MessageOptions
|
|
36
|
+
messageOptions.showCancelButton = false
|
|
37
|
+
this.show(messageOptions)
|
|
38
|
+
},
|
|
39
|
+
confirm(option: GlobalMessageOptions | string) {
|
|
40
|
+
const messageOptions = CommonUtil.deepMerge({ type: 'confirm' }, CommonUtil.isString(option) ? { title: option } : option) as MessageOptions
|
|
41
|
+
messageOptions.showCancelButton = true
|
|
42
|
+
this.show(messageOptions)
|
|
43
|
+
},
|
|
44
|
+
prompt(option: GlobalMessageOptions | string) {
|
|
45
|
+
const messageOptions = CommonUtil.deepMerge({ type: 'prompt' }, CommonUtil.isString(option) ? { title: option } : option) as MessageOptions
|
|
46
|
+
messageOptions.showCancelButton = true
|
|
47
|
+
this.show(messageOptions)
|
|
48
|
+
},
|
|
49
|
+
close() {
|
|
50
|
+
this.messageOptions = null
|
|
51
|
+
this.currentPage = ''
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
})
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import type { ToastOptions } from 'wot-design-uni/components/wd-toast/types'
|
|
3
|
+
import { getCurrentPath } from '../utils/index'
|
|
4
|
+
|
|
5
|
+
interface GlobalToast {
|
|
6
|
+
toastOptions: ToastOptions
|
|
7
|
+
currentPage: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const defaultOptions: ToastOptions = {
|
|
11
|
+
duration: 2000,
|
|
12
|
+
show: false,
|
|
13
|
+
}
|
|
14
|
+
export const useGlobalToast = defineStore('global-toast', {
|
|
15
|
+
state: (): GlobalToast => ({
|
|
16
|
+
toastOptions: defaultOptions,
|
|
17
|
+
currentPage: '',
|
|
18
|
+
}),
|
|
19
|
+
getters: {},
|
|
20
|
+
actions: {
|
|
21
|
+
// 打开Toast
|
|
22
|
+
show(option: ToastOptions | string) {
|
|
23
|
+
this.currentPage = getCurrentPath()
|
|
24
|
+
const options = CommonUtil.deepMerge(defaultOptions, typeof option === 'string' ? { msg: option } : option) as ToastOptions
|
|
25
|
+
this.toastOptions = CommonUtil.deepMerge(options, {
|
|
26
|
+
show: true,
|
|
27
|
+
position: options.position || 'middle',
|
|
28
|
+
}) as ToastOptions
|
|
29
|
+
},
|
|
30
|
+
// 成功提示
|
|
31
|
+
success(option: ToastOptions | string) {
|
|
32
|
+
this.show(CommonUtil.deepMerge({
|
|
33
|
+
iconName: 'success',
|
|
34
|
+
duration: 1500,
|
|
35
|
+
}, typeof option === 'string' ? { msg: option } : option) as ToastOptions)
|
|
36
|
+
},
|
|
37
|
+
// 关闭提示
|
|
38
|
+
error(option: ToastOptions | string) {
|
|
39
|
+
this.show(CommonUtil.deepMerge({
|
|
40
|
+
iconName: 'error',
|
|
41
|
+
direction: 'vertical',
|
|
42
|
+
}, typeof option === 'string' ? { msg: option } : option) as ToastOptions)
|
|
43
|
+
},
|
|
44
|
+
// 常规提示
|
|
45
|
+
info(option: ToastOptions | string) {
|
|
46
|
+
this.show(CommonUtil.deepMerge({
|
|
47
|
+
iconName: 'info',
|
|
48
|
+
}, typeof option === 'string' ? { msg: option } : option) as ToastOptions)
|
|
49
|
+
},
|
|
50
|
+
// 警告提示
|
|
51
|
+
warning(option: ToastOptions | string) {
|
|
52
|
+
this.show(CommonUtil.deepMerge({
|
|
53
|
+
iconName: 'warning',
|
|
54
|
+
}, typeof option === 'string' ? { msg: option } : option) as ToastOptions)
|
|
55
|
+
},
|
|
56
|
+
// 关闭Toast
|
|
57
|
+
close() {
|
|
58
|
+
this.toastOptions = defaultOptions
|
|
59
|
+
this.currentPage = ''
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
})
|
package/composables/useTheme.ts
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import useUserStore from '../store/userStore'
|
|
2
|
+
import type { UserInfo } from './types/user'
|
|
3
|
+
|
|
4
|
+
export function useUser() {
|
|
5
|
+
const userStore = useUserStore()
|
|
6
|
+
|
|
7
|
+
function setUserInfo(userInfo: UserInfo) {
|
|
8
|
+
userStore.setUserInfo(userInfo)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
getUserInfo: (): UserInfo => {
|
|
13
|
+
return {
|
|
14
|
+
id: userStore.id,
|
|
15
|
+
name: userStore.name,
|
|
16
|
+
nickName: userStore.nickName,
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
setUserInfo,
|
|
20
|
+
}
|
|
21
|
+
}
|
package/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { App } from 'vue'
|
|
2
|
-
import SystemSettings from './components/system-settings.vue'
|
|
2
|
+
import SystemSettings from './components/system-settings/system-settings.vue'
|
|
3
3
|
import { useLocale } from './composables/useLocale'
|
|
4
4
|
import { useManualTheme } from './composables/useManualTheme'
|
|
5
|
-
|
|
5
|
+
import { req } from './api/index'
|
|
6
6
|
// 组件列表
|
|
7
7
|
const coms: Array<{ name: string }> = [
|
|
8
8
|
SystemSettings,
|
|
@@ -24,6 +24,7 @@ function install(app: App): void {
|
|
|
24
24
|
export {
|
|
25
25
|
useLocale,
|
|
26
26
|
useManualTheme,
|
|
27
|
+
req, // 请求封装
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export default install
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wui-components-v2",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "wui 组件库",
|
|
5
5
|
"author": "wgxshh",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,5 +11,10 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"dayjs": "^1.11.13",
|
|
17
|
+
"jsencrypt": "^3.3.2",
|
|
18
|
+
"z-paging": "^2.8.5"
|
|
14
19
|
}
|
|
15
20
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
|
|
3
|
+
const useUserStore = defineStore('userInfo', {
|
|
4
|
+
state: () => ({
|
|
5
|
+
id: '',
|
|
6
|
+
name: '',
|
|
7
|
+
nickName: '',
|
|
8
|
+
}),
|
|
9
|
+
getters: {
|
|
10
|
+
|
|
11
|
+
},
|
|
12
|
+
actions: {
|
|
13
|
+
setUserInfo(userInfo: any) {
|
|
14
|
+
this.id = userInfo.id
|
|
15
|
+
this.name = userInfo.name
|
|
16
|
+
this.nickName = userInfo.nickName
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export default useUserStore
|
package/utils/index.ts
ADDED
package/api/core/handlers.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author: weisheng
|
|
3
|
-
* @Date: 2025-04-17 15:58:11
|
|
4
|
-
* @LastEditTime: 2025-06-15 21:47:22
|
|
5
|
-
* @LastEditors: weisheng
|
|
6
|
-
* @Description: Alova response and error handlers
|
|
7
|
-
* @FilePath: /wot-demo/src/api/core/handlers.ts
|
|
8
|
-
*/
|
|
9
|
-
import type { Method } from 'alova'
|
|
10
|
-
import router from '@/router'
|
|
11
|
-
|
|
12
|
-
// Custom error class for API errors
|
|
13
|
-
export class ApiError extends Error {
|
|
14
|
-
code: number
|
|
15
|
-
data?: any
|
|
16
|
-
|
|
17
|
-
constructor(message: string, code: number, data?: any) {
|
|
18
|
-
super(message)
|
|
19
|
-
this.name = 'ApiError'
|
|
20
|
-
this.code = code
|
|
21
|
-
this.data = data
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Define a type for the expected API response structure
|
|
26
|
-
interface ApiResponse {
|
|
27
|
-
code: number
|
|
28
|
-
msg?: string
|
|
29
|
-
data?: any
|
|
30
|
-
success?: boolean
|
|
31
|
-
total?: number
|
|
32
|
-
more?: boolean
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// 处理成功的响应
|
|
36
|
-
export async function handleAlovaResponse(
|
|
37
|
-
response: UniApp.RequestSuccessCallbackResult | UniApp.UploadFileSuccessCallbackResult | UniApp.DownloadSuccessData,
|
|
38
|
-
) {
|
|
39
|
-
const globalToast = useGlobalToast()
|
|
40
|
-
// Extract status code and data from UniApp response
|
|
41
|
-
const { statusCode, data } = response as UniNamespace.RequestSuccessCallbackResult
|
|
42
|
-
|
|
43
|
-
// 处理401/403错误(如果不是在handleAlovaResponse中处理的)
|
|
44
|
-
if ((statusCode === 401 || statusCode === 403)) {
|
|
45
|
-
// 如果是未授权错误,清除用户信息并跳转到登录页
|
|
46
|
-
globalToast.error({ msg: '登录已过期,请重新登录!', duration: 500 })
|
|
47
|
-
const timer = setTimeout(() => {
|
|
48
|
-
clearTimeout(timer)
|
|
49
|
-
router.replaceAll({ name: 'login' })
|
|
50
|
-
}, 500)
|
|
51
|
-
|
|
52
|
-
throw new ApiError('登录已过期,请重新登录!', statusCode, data)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Handle HTTP error status codes
|
|
56
|
-
if (statusCode >= 400) {
|
|
57
|
-
globalToast.error(`请求失败,状态为: ${statusCode}`)
|
|
58
|
-
throw new ApiError(`请求失败,状态为: ${statusCode}`, statusCode, data)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// The data is already parsed by UniApp adapter
|
|
62
|
-
const json = data as ApiResponse
|
|
63
|
-
// Log response in development
|
|
64
|
-
if (import.meta.env.MODE === 'development') {
|
|
65
|
-
console.log('[Alova Response]', json)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Return data for successful responses
|
|
69
|
-
return json
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 处理失败的响应
|
|
73
|
-
export function handleAlovaError(error: any, method: Method) {
|
|
74
|
-
const globalToast = useGlobalToast()
|
|
75
|
-
// Log error in development
|
|
76
|
-
if (import.meta.env.MODE === 'development') {
|
|
77
|
-
console.error('[Alova Error]', error, method)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 处理401/403错误(如果不是在handleAlovaResponse中处理的)
|
|
81
|
-
if (error instanceof ApiError && (error.code === 401 || error.code === 403)) {
|
|
82
|
-
// 如果是未授权错误,清除用户信息并跳转到登录页
|
|
83
|
-
globalToast.error({ msg: '登录已过期,请重新登录!', duration: 500 })
|
|
84
|
-
const timer = setTimeout(() => {
|
|
85
|
-
clearTimeout(timer)
|
|
86
|
-
router.replaceAll({ name: 'login' })
|
|
87
|
-
}, 500)
|
|
88
|
-
throw new ApiError('登录已过期,请重新登录!', error.code, error.data)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Handle different types of errors
|
|
92
|
-
if (error.name === 'NetworkError') {
|
|
93
|
-
globalToast.error('网络错误,请检查您的网络连接')
|
|
94
|
-
}
|
|
95
|
-
else if (error.name === 'TimeoutError') {
|
|
96
|
-
globalToast.error('请求超时,请重试')
|
|
97
|
-
}
|
|
98
|
-
else if (error instanceof ApiError) {
|
|
99
|
-
globalToast.error(error.message || '请求失败')
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
globalToast.error('发生意外错误')
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
throw error
|
|
106
|
-
}
|
package/api/core/instance.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author: weisheng
|
|
3
|
-
* @Date: 2025-04-10 18:02:00
|
|
4
|
-
* @LastEditTime: 2025-06-15 22:41:52
|
|
5
|
-
* @LastEditors: weisheng
|
|
6
|
-
* @Description: Alova instance configuration
|
|
7
|
-
* @FilePath: /wot-demo/src/api/core/instance.ts
|
|
8
|
-
*/
|
|
9
|
-
import { createAlova } from 'alova'
|
|
10
|
-
import vueHook from 'alova/vue'
|
|
11
|
-
import AdapterUniapp from '@alova/adapter-uniapp'
|
|
12
|
-
import { handleAlovaError, handleAlovaResponse } from './handlers'
|
|
13
|
-
|
|
14
|
-
export const alovaInstance = createAlova({
|
|
15
|
-
baseURL: import.meta.env.VITE_API_BASE_URL || 'https://petstore3.swagger.io/api/v3',
|
|
16
|
-
...AdapterUniapp(),
|
|
17
|
-
statesHook: vueHook,
|
|
18
|
-
beforeRequest: (method) => {
|
|
19
|
-
// 为POST/PUT/PATCH请求添加内容类型
|
|
20
|
-
if (['POST', 'PUT', 'PATCH'].includes(method.type)) {
|
|
21
|
-
method.config.headers['Content-Type'] = 'application/json'
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 添加时间戳以防止缓存GET请求
|
|
25
|
-
if (method.type === 'GET' && CommonUtil.isObj(method.config.params)) {
|
|
26
|
-
method.config.params._t = Date.now()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// 开发中的日志请求
|
|
30
|
-
if (import.meta.env.MODE === 'development') {
|
|
31
|
-
console.log(`[Alova Request] ${method.type} ${method.url}`, method.data || method.config.params)
|
|
32
|
-
console.log(`[API Base URL] ${import.meta.env.VITE_API_BASE_URL}`)
|
|
33
|
-
console.log(`[Environment] ${import.meta.env.VITE_ENV_NAME}`)
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
// 响应处理程序
|
|
38
|
-
responded: {
|
|
39
|
-
// 成功处理程序
|
|
40
|
-
onSuccess: handleAlovaResponse,
|
|
41
|
-
|
|
42
|
-
// 错误处理程序
|
|
43
|
-
onError: handleAlovaError,
|
|
44
|
-
|
|
45
|
-
// 完整处理程序-成功或错误后运行
|
|
46
|
-
onComplete: async () => {
|
|
47
|
-
// Any cleanup or logging can be done here
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
// 我们将在钩子中使用中间件
|
|
52
|
-
// createAlova选项中不直接支持中间件
|
|
53
|
-
|
|
54
|
-
// 默认请求超时(10秒)
|
|
55
|
-
timeout: 60000,
|
|
56
|
-
// 设置为null即可全局关闭全部请求缓存
|
|
57
|
-
cacheFor: null,
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
export default alovaInstance
|