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.
@@ -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 '../composables/useManualTheme'
4
- import type { LocaleOption, ThemeColorOption } from '../composables/useManualTheme'
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,5 @@
1
+ export interface UserInfo {
2
+ id: string
3
+ name: string
4
+ nickName: string
5
+ }
@@ -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
+ })
@@ -1,6 +1,6 @@
1
1
  import { computed, onBeforeMount, onUnmounted } from 'vue'
2
2
  import type { ThemeMode } from '../composables/types/theme'
3
-
3
+ import { useThemeStore } from '../store/themeStore'
4
4
  /**
5
5
  * 简化版系统主题管理组合式API
6
6
  *
@@ -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.13",
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
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 获取当前页面路径
3
+ * @returns 当前页面路径
4
+ */
5
+ export function getCurrentPath() {
6
+ const pages = getCurrentPages()
7
+ const currentPage = pages[pages.length - 1]
8
+ return currentPage.route || ''
9
+ }
@@ -0,0 +1,10 @@
1
+ import { JSEncrypt } from 'jsencrypt'
2
+
3
+ // 加密
4
+ function rsaEncrypt(word: string, keyStr: string) {
5
+ const encrypt = new JSEncrypt()
6
+ encrypt.setPublicKey(keyStr)
7
+ return encrypt.encrypt(word)
8
+ }
9
+
10
+ export default rsaEncrypt
@@ -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
- }
@@ -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