wui-components-v2 1.0.0

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,106 @@
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
+ }
@@ -0,0 +1,60 @@
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
@@ -0,0 +1,92 @@
1
+ /**
2
+ * 延迟加载中间件
3
+ * 延迟显示加载状态,防止快速请求导致的闪烁
4
+ * @param delay 显示加载状态前的延迟时间(毫秒)
5
+ * @returns Alova 中间件
6
+ */
7
+ export function createDelayLoadingMiddleware(delay = 300) {
8
+ return async (context: any, next: any) => {
9
+ context.controlLoading()
10
+
11
+ const { loading } = context.proxyStates
12
+
13
+ const timer = setTimeout(() => {
14
+ loading.v = true
15
+ }, delay)
16
+
17
+ await next()
18
+
19
+ loading.v = false
20
+ clearTimeout(timer)
21
+ }
22
+ }
23
+
24
+ /**
25
+ * 全局加载中间件
26
+ * 为所有请求显示全局加载指示器,支持延迟显示
27
+ *
28
+ * 使用示例:
29
+ * ```typescript
30
+ * // 1. 基本用法
31
+ * const { send: submit } = useRequest(method, {
32
+ * middleware: createGlobalLoadingMiddleware()
33
+ * });
34
+ *
35
+ * // 2. 自定义延迟时间和加载文本
36
+ * const { send: submit } = useRequest(method, {
37
+ * middleware: createGlobalLoadingMiddleware({
38
+ * delay: 500, // 延迟 500ms 显示加载指示器,防止闪烁
39
+ * loadingText: '正在提交...', // 自定义加载文本
40
+ * })
41
+ * });
42
+ * ```
43
+ *
44
+ * @param options 加载选项
45
+ * @param options.delay 显示加载指示器前的延迟时间(毫秒),默认 300ms
46
+ * @param options.loadingText 加载指示器显示的文本,默认为 'Loading...'
47
+ * @returns Alova 中间件
48
+ */
49
+ export function createGlobalLoadingMiddleware(options: {
50
+ delay?: number
51
+ loadingText?: string
52
+ } = {}) {
53
+ const {
54
+ delay = 0,
55
+ loadingText = 'Loading...',
56
+ } = options
57
+
58
+ return async (ctx: any, next: any) => {
59
+ // 自行控制loading
60
+ ctx.controlLoading()
61
+
62
+ const globalLoading = useGlobalLoading()
63
+ let timer: ReturnType<typeof setTimeout> | null = null
64
+
65
+ // 如果delay为0或未设置,直接显示loading
66
+ if (delay <= 0) {
67
+ globalLoading.loading(loadingText)
68
+ }
69
+ else {
70
+ // 延迟特定时间显示全局loading
71
+ timer = setTimeout(() => {
72
+ globalLoading.loading(loadingText)
73
+ }, delay)
74
+ }
75
+
76
+ try {
77
+ await next()
78
+ }
79
+ finally {
80
+ // 清除定时器并关闭loading
81
+ if (timer) {
82
+ clearTimeout(timer)
83
+ }
84
+ globalLoading.close()
85
+ }
86
+ }
87
+ }
88
+
89
+ // 导出延迟加载中间件作为默认中间件
90
+ export const defaultMiddleware = createDelayLoadingMiddleware()
91
+
92
+ export default defaultMiddleware
package/api/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ // 导入核心alova实例
2
+ import alovaInstance from './core/instance'
3
+
4
+ // 如果需要,导出alova实例以供直接使用
5
+ export { alovaInstance }
6
+
7
+ // 为特定API配置方法选项
8
+ export const $$userConfigMap = withConfigType({})
9
+
10
+ // 创建全局Apis对象
11
+ const Apis = createApis(alovaInstance, $$userConfigMap)
12
+
13
+ // 导出默认导出和命名导出以进行自动导入
14
+ export default Apis
15
+ export { Apis }
@@ -0,0 +1,63 @@
1
+ import type { ConfigProviderThemeVars } from 'wot-design-uni'
2
+
3
+ /**
4
+ * 主题色选项接口
5
+ */
6
+ export interface ThemeColorOption {
7
+ name: string
8
+ value: string
9
+ primary: string
10
+ }
11
+
12
+ /**
13
+ * 语言选项接口
14
+ */
15
+ export interface LocaleOption {
16
+ name: string
17
+ value: string
18
+ }
19
+
20
+ /**
21
+ * 主题类型
22
+ */
23
+ export type ThemeMode = 'light' | 'dark'
24
+
25
+ /**
26
+ * 主题状态接口
27
+ */
28
+ export interface ThemeState {
29
+ theme: ThemeMode
30
+ Locale: LocaleOption
31
+ followSystem: boolean
32
+ hasUserSet: boolean
33
+ currentThemeColor: ThemeColorOption
34
+ themeVars: ConfigProviderThemeVars
35
+ }
36
+
37
+ /**
38
+ * 系统主题状态接口(简化版)
39
+ */
40
+ export interface SystemThemeState {
41
+ theme: ThemeMode
42
+ themeVars: ConfigProviderThemeVars
43
+ }
44
+
45
+ /**
46
+ * 预定义的主题色选项
47
+ */
48
+ export const themeColorOptions: ThemeColorOption[] = [
49
+ { name: '默认蓝', value: 'blue', primary: '#4D7FFF' },
50
+ { name: '活力橙', value: 'orange', primary: '#FF7D00' },
51
+ { name: '薄荷绿', value: 'green', primary: '#07C160' },
52
+ { name: '樱花粉', value: 'pink', primary: '#FF69B4' },
53
+ { name: '紫罗兰', value: 'purple', primary: '#8A2BE2' },
54
+ { name: '朱砂红', value: 'red', primary: '#FF4757' },
55
+ ]
56
+
57
+ /**
58
+ * 预定义的语言选项
59
+ */
60
+ export const LocaleOptions: LocaleOption[] = [
61
+ { name: '简体中文', value: 'zh-CN' },
62
+ { name: 'English', value: 'en-US' },
63
+ ]
@@ -0,0 +1,37 @@
1
+ import { Locale } from 'wot-design-uni'
2
+ // 引入英文语言包
3
+ import enUS from 'wot-design-uni/locale/lang/en-US'
4
+ // 引入中文语言包
5
+ import zhCN from 'wot-design-uni/locale/lang/zh-CN'
6
+ import { useManualThemeStore } from '../store/manualThemeStore'
7
+ /**
8
+ * 简化版系统语言切换组合式API
9
+ *
10
+ */
11
+ export function useLocale() {
12
+ const store = useManualThemeStore()
13
+ // 系统语言切换
14
+ function changeSystemLocale() {
15
+ console.log('系统语言切换为:', store.Locale.value)
16
+ switch (store.Locale.value) {
17
+ case 'en-US':
18
+ Locale.use('en-US', enUS)
19
+ break
20
+ default:
21
+ Locale.use('zh-CN', zhCN)
22
+ break
23
+ }
24
+ }
25
+
26
+ // 组件挂载前初始化系统语言
27
+ onBeforeMount(() => {
28
+ changeSystemLocale()
29
+ })
30
+
31
+ return {
32
+ // 状态(只读)
33
+ locale: computed(() => store.Locale),
34
+ // 方法
35
+ changeSystemLocale,
36
+ }
37
+ }
@@ -0,0 +1,175 @@
1
+ import { useManualThemeStore } from '../store/manualThemeStore'
2
+ import { useLocale } from './useLocale'
3
+ import type { LocaleOption, ThemeColorOption, ThemeMode } from './types/theme'
4
+
5
+ import { LocaleOptions, themeColorOptions } from './types/theme'
6
+
7
+ /**
8
+ * 完整版主题管理组合式API
9
+ *
10
+ * 功能特性:
11
+ * - 支持手动切换暗黑模式
12
+ * - 支持主题色选择
13
+ * - 支持跟随系统主题
14
+ * - 自动同步导航栏颜色
15
+ * - 持久化用户设置
16
+ *
17
+ * 适用场景:
18
+ * - 需要用户手动控制主题的应用
19
+ * - 需要主题色自定义的应用
20
+ * - 需要完整主题管理功能的复杂应用
21
+ *
22
+ * @example
23
+ * ```vue
24
+ * <script setup>
25
+ * import { useManualTheme } from '@/composables/useManualTheme'
26
+ *
27
+ * const {
28
+ * theme,
29
+ * isDark,
30
+ * toggleTheme,
31
+ * openThemeColorPicker,
32
+ * currentThemeColor,
33
+ * themeVars
34
+ * } = useManualTheme()
35
+ * </script>
36
+ *
37
+ * <template>
38
+ * <wd-config-provider :theme-vars="themeVars">
39
+ * <view :class="{ 'dark-mode': isDark }">
40
+ * <wd-button @click="toggleTheme">切换主题</wd-button>
41
+ * <wd-button @click="openThemeColorPicker">选择主题色</wd-button>
42
+ * </view>
43
+ * </wd-config-provider>
44
+ * </template>
45
+ * ```
46
+ */
47
+ export function useManualTheme() {
48
+ const store = useManualThemeStore()
49
+ const showThemeColorSheet = ref(false)
50
+ const showLanguageSheet = ref(false)
51
+ const language = useLocale()
52
+ /**
53
+ * 切换暗黑模式
54
+ * @param mode 指定主题模式,不传则自动切换
55
+ */
56
+ function toggleTheme(mode?: ThemeMode) {
57
+ store.toggleTheme(mode)
58
+ }
59
+
60
+ /**
61
+ * 打开主题色选择器
62
+ */
63
+ function openThemeColorPicker() {
64
+ showThemeColorSheet.value = true
65
+ }
66
+
67
+ /**
68
+ * 关闭主题色选择器
69
+ */
70
+ function closeThemeColorPicker() {
71
+ showThemeColorSheet.value = false
72
+ }
73
+
74
+ /**
75
+ * 选择主题色
76
+ * @param option 主题色选项
77
+ */
78
+ function selectThemeColor(option: ThemeColorOption) {
79
+ store.setCurrentThemeColor(option)
80
+ closeThemeColorPicker()
81
+ }
82
+
83
+ /**
84
+ * 选择语言
85
+ *
86
+ */
87
+ function selectLanguage(option: LocaleOption) {
88
+ store.setLocale(option)
89
+ closeLanguagePicker()
90
+ language.changeSystemLocale()
91
+ }
92
+
93
+ /**
94
+ * 打开语言选择器
95
+ */
96
+ function openLanguagePicker() {
97
+ showLanguageSheet.value = true
98
+ }
99
+
100
+ /**
101
+ * 关闭语言选择器
102
+ */
103
+ function closeLanguagePicker() {
104
+ showLanguageSheet.value = false
105
+ }
106
+
107
+ /**
108
+ * 初始化主题
109
+ */
110
+ function initTheme() {
111
+ store.initTheme()
112
+ }
113
+
114
+ // 组件挂载前初始化主题
115
+ onBeforeMount(() => {
116
+ initTheme()
117
+
118
+ // 监听系统主题变化
119
+ if (typeof uni !== 'undefined' && uni.onThemeChange) {
120
+ uni.onThemeChange((res) => {
121
+ if (store.followSystem) {
122
+ toggleTheme(res.theme as ThemeMode)
123
+ }
124
+ })
125
+ }
126
+ })
127
+
128
+ // 页面显示时更新导航栏颜色,确保每次切换页面时导航栏颜色都是正确的
129
+ onShow(() => {
130
+ store.setNavigationBarColor()
131
+ })
132
+
133
+ // 组件卸载时清理监听
134
+ onUnmounted(() => {
135
+ if (typeof uni !== 'undefined' && uni.offThemeChange) {
136
+ uni.offThemeChange((res) => {
137
+ if (store.followSystem) {
138
+ toggleTheme(res.theme as ThemeMode)
139
+ }
140
+ })
141
+ }
142
+ })
143
+
144
+ return {
145
+ // 状态
146
+ theme: computed(() => store.theme),
147
+ primary: computed(() => store.themeVars.colorTheme),
148
+ isDark: computed(() => store.isDark),
149
+ followSystem: computed(() => store.followSystem),
150
+ hasUserSet: computed(() => store.hasUserSet),
151
+ currentThemeColor: computed(() => store.currentThemeColor),
152
+ currentLocale: computed(() => store.Locale),
153
+ themeVars: computed(() => store.themeVars),
154
+ showThemeColorSheet,
155
+ showLanguageSheet,
156
+ // 常量
157
+ themeColorOptions,
158
+ LocaleOptions,
159
+
160
+ // 方法
161
+ initTheme,
162
+ toggleTheme,
163
+ setFollowSystem: store.setFollowSystem,
164
+ openThemeColorPicker,
165
+ closeThemeColorPicker,
166
+ selectThemeColor,
167
+ openLanguagePicker,
168
+ closeLanguagePicker,
169
+ selectLanguage,
170
+ }
171
+ }
172
+
173
+ // 导出类型和常量供外部使用
174
+ export type { ThemeColorOption, ThemeMode, LocaleOption }
175
+ export { themeColorOptions }
@@ -0,0 +1,73 @@
1
+ import type { ThemeMode } from '@/composables/types/theme'
2
+
3
+ /**
4
+ * 简化版系统主题管理组合式API
5
+ *
6
+ * 功能特性:
7
+ * - 仅跟随系统主题变化
8
+ * - 自动响应系统主题切换
9
+ * - 导航栏颜色通过 theme.json 自动处理
10
+ * - 轻量级,无额外功能
11
+ *
12
+ * 适用场景:
13
+ * - 只需要系统主题适应的简单应用
14
+ * - 不需要用户手动控制主题的应用
15
+ * - 追求轻量级主题管理的应用
16
+ *
17
+ * 注意事项:
18
+ * - 不支持手动切换主题
19
+ * - 不支持主题色自定义
20
+ * - 导航栏颜色依赖 theme.json 配置
21
+ *
22
+ * @example
23
+ * ```vue
24
+ * <script setup>
25
+ * import { useTheme } from '@/composables/useTheme'
26
+ *
27
+ * const { theme, isDark, themeVars } = useTheme()
28
+ * </script>
29
+ *
30
+ * <template>
31
+ * <wd-config-provider :theme-vars="themeVars">
32
+ * <view :class="{ 'dark-mode': isDark }">
33
+ * <text>当前主题: {{ theme }}</text>
34
+ * </view>
35
+ * </wd-config-provider>
36
+ * </template>
37
+ * ```
38
+ */
39
+ export function useTheme() {
40
+ const store = useThemeStore()
41
+
42
+ // 组件挂载前初始化系统主题
43
+ onBeforeMount(() => {
44
+ store.initSystemTheme()
45
+ // 监听系统主题变化
46
+ if (typeof uni !== 'undefined' && uni.onThemeChange) {
47
+ uni.onThemeChange((res) => {
48
+ // 系统主题变化时自动更新,导航栏颜色由 theme.json 自动处理
49
+ store.setTheme(res.theme as ThemeMode)
50
+ console.log('系统主题已切换至:', res.theme)
51
+ })
52
+ }
53
+ })
54
+
55
+ // 组件卸载时清理监听
56
+ onUnmounted(() => {
57
+ if (typeof uni !== 'undefined' && uni.offThemeChange) {
58
+ uni.offThemeChange((res) => {
59
+ store.setTheme(res.theme as ThemeMode)
60
+ })
61
+ }
62
+ })
63
+
64
+ return {
65
+ // 状态(只读)
66
+ theme: computed(() => store.theme),
67
+ isDark: computed(() => store.isDark),
68
+ themeVars: computed(() => store.themeVars),
69
+ }
70
+ }
71
+
72
+ // 导出类型供外部使用
73
+ export type { ThemeMode }
package/index.ts ADDED
@@ -0,0 +1,25 @@
1
+ import type { App } from 'vue'
2
+ // import SystemSettings from './components/system-settings/system-settings.vue'
3
+ // import { useLocale } from './composables/useLocale'
4
+ // import { useManualTheme } from './composables/useManualTheme'
5
+ // import request from './api'
6
+
7
+ import test from './test.vue'
8
+
9
+ const coms: any[] = [
10
+ test,
11
+ ]
12
+ // 批量组件注册
13
+ function install(Vue: App) {
14
+ coms.forEach((com) => {
15
+ Vue.component(com.name, com)
16
+ })
17
+ }
18
+
19
+ // export const coreFunctions = {
20
+ // useLocale,
21
+ // useManualTheme,
22
+ // request,
23
+ // }
24
+
25
+ export default install // 这个方法以后再使用的时候可以被vue.use调用
package/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "wui-components-v2",
3
+ "version": "1.0.0",
4
+ "description": "wui 组件库",
5
+ "author": "wgxshh",
6
+ "license": "MIT",
7
+ "main": "index.ts",
8
+ "publishConfig": {
9
+ "registry": "https://registry.npmjs.org/"
10
+ },
11
+ "scripts": {
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ }
14
+ }
@@ -0,0 +1,141 @@
1
+ import { defineStore } from 'pinia'
2
+ import type { LocaleOption, ThemeColorOption, ThemeMode, ThemeState } from '../composables/types/theme'
3
+ import { LocaleOptions, themeColorOptions } from '../composables/types/theme'
4
+ /**
5
+ * 完整版主题状态管理
6
+ * 支持手动切换主题、主题色选择、跟随系统主题等完整功能
7
+ */
8
+ export const useManualThemeStore = defineStore('manualTheme', {
9
+ state: (): ThemeState => ({
10
+ theme: 'light',
11
+ followSystem: true, // 是否跟随系统主题
12
+ hasUserSet: false, // 用户是否手动设置过主题
13
+ currentThemeColor: themeColorOptions[0],
14
+ Locale: LocaleOptions[0],
15
+ themeVars: {
16
+ darkBackground: '#0f0f0f',
17
+ darkBackground2: '#1a1a1a',
18
+ darkBackground3: '#242424',
19
+ darkBackground4: '#2f2f2f',
20
+ darkBackground5: '#3d3d3d',
21
+ darkBackground6: '#4a4a4a',
22
+ darkBackground7: '#606060',
23
+ darkColor: '#ffffff',
24
+ darkColor2: '#e0e0e0',
25
+ darkColor3: '#a0a0a0',
26
+ colorTheme: themeColorOptions[0].primary,
27
+ },
28
+ }),
29
+
30
+ getters: {
31
+ isDark: state => state.theme === 'dark',
32
+ },
33
+
34
+ actions: {
35
+ /**
36
+ * 手动切换主题
37
+ * @param mode 指定主题模式,不传则自动切换
38
+ */
39
+ toggleTheme(mode?: ThemeMode) {
40
+ this.theme = mode || (this.theme === 'light' ? 'dark' : 'light')
41
+ this.hasUserSet = true // 标记用户已手动设置
42
+ this.followSystem = false // 不再跟随系统
43
+ this.setNavigationBarColor()
44
+ },
45
+
46
+ /**
47
+ * 设置是否跟随系统主题
48
+ * @param follow 是否跟随系统
49
+ */
50
+ setFollowSystem(follow: boolean) {
51
+ this.followSystem = follow
52
+ if (follow) {
53
+ this.hasUserSet = false
54
+ this.initTheme() // 重新获取系统主题
55
+ }
56
+ },
57
+
58
+ /**
59
+ * 设置导航栏颜色
60
+ */
61
+ setNavigationBarColor() {
62
+ uni.setNavigationBarColor({
63
+ frontColor: this.theme === 'light' ? '#000000' : '#ffffff',
64
+ backgroundColor: this.theme === 'light' ? '#ffffff' : '#000000',
65
+ })
66
+ },
67
+
68
+ /**
69
+ * 设置主题色
70
+ * @param color 主题色选项
71
+ */
72
+ setCurrentThemeColor(color: ThemeColorOption) {
73
+ this.currentThemeColor = color
74
+ this.themeVars.colorTheme = color.primary
75
+ },
76
+
77
+ /**
78
+ * 设置语言
79
+ */
80
+ setLocale(locale: LocaleOption) {
81
+ this.Locale = locale
82
+ },
83
+ /**
84
+ * 获取系统主题
85
+ * @returns 系统主题模式
86
+ */
87
+ getSystemTheme(): ThemeMode {
88
+ try {
89
+ // #ifdef MP-WEIXIN
90
+ // 微信小程序使用 getAppBaseInfo
91
+ const appBaseInfo = uni.getAppBaseInfo()
92
+ if (appBaseInfo && appBaseInfo.theme) {
93
+ return appBaseInfo.theme as ThemeMode
94
+ }
95
+ // #endif
96
+
97
+ // #ifndef MP-WEIXIN
98
+ // 其他平台使用 getSystemInfoSync
99
+ const systemInfo = uni.getSystemInfoSync()
100
+ if (systemInfo && systemInfo.theme) {
101
+ return systemInfo.theme as ThemeMode
102
+ }
103
+ // #endif
104
+ }
105
+ catch (error) {
106
+ console.warn('获取系统主题失败:', error)
107
+ }
108
+ return 'light' // 默认返回 light
109
+ },
110
+
111
+ /**
112
+ * 初始化主题
113
+ */
114
+ initTheme() {
115
+ // 如果用户已手动设置且不跟随系统,保持当前主题
116
+ if (this.hasUserSet && !this.followSystem) {
117
+ console.log('使用用户设置的主题:', this.theme)
118
+ this.setNavigationBarColor()
119
+ return
120
+ }
121
+
122
+ // 获取系统主题
123
+ const systemTheme = this.getSystemTheme()
124
+
125
+ // 如果是首次启动或跟随系统,使用系统主题
126
+ if (!this.hasUserSet || this.followSystem) {
127
+ this.theme = systemTheme
128
+ if (!this.hasUserSet) {
129
+ this.followSystem = true
130
+ console.log('首次启动,使用系统主题:', this.theme)
131
+ }
132
+ else {
133
+ console.log('跟随系统主题:', this.theme)
134
+ }
135
+ }
136
+
137
+ this.setNavigationBarColor()
138
+ },
139
+
140
+ },
141
+ })
@@ -0,0 +1,74 @@
1
+ import { defineStore } from 'pinia'
2
+ import type { SystemThemeState, ThemeMode } from '../composables/types/theme'
3
+ import { themeColorOptions } from '../composables/types/theme'
4
+
5
+ /**
6
+ * 简化版系统主题状态管理
7
+ * 仅支持跟随系统主题,不提供手动切换功能
8
+ * 导航栏颜色通过 theme.json 自动处理
9
+ */
10
+ export const useThemeStore = defineStore('theme', {
11
+ state: (): SystemThemeState => ({
12
+ theme: 'light',
13
+ themeVars: {
14
+ darkBackground: '#0f0f0f',
15
+ darkBackground2: '#1a1a1a',
16
+ darkBackground3: '#242424',
17
+ darkBackground4: '#2f2f2f',
18
+ darkBackground5: '#3d3d3d',
19
+ darkBackground6: '#4a4a4a',
20
+ darkBackground7: '#606060',
21
+ darkColor: '#ffffff',
22
+ darkColor2: '#e0e0e0',
23
+ darkColor3: '#a0a0a0',
24
+ colorTheme: themeColorOptions[0].primary,
25
+ },
26
+ }),
27
+
28
+ getters: {
29
+ isDark: state => state.theme === 'dark',
30
+ },
31
+
32
+ actions: {
33
+ /**
34
+ * 获取系统主题
35
+ * @returns 系统主题模式
36
+ */
37
+ getSystemTheme(): ThemeMode {
38
+ // #ifdef MP-WEIXIN
39
+ // 微信小程序使用 getAppBaseInfo
40
+ const appBaseInfo = uni.getAppBaseInfo()
41
+ if (appBaseInfo && appBaseInfo.theme) {
42
+ return appBaseInfo.theme as ThemeMode
43
+ }
44
+ // #endif
45
+
46
+ // #ifndef MP-WEIXIN
47
+ // 其他平台使用 getSystemInfoSync
48
+ const systemInfo = uni.getSystemInfoSync()
49
+ if (systemInfo && systemInfo.theme) {
50
+ return systemInfo.theme as ThemeMode
51
+ }
52
+ // #endif
53
+
54
+ return 'light' // 默认返回 light
55
+ },
56
+
57
+ /**
58
+ * 设置主题(仅内部使用)
59
+ * @param theme 主题模式
60
+ */
61
+ setTheme(theme: ThemeMode) {
62
+ this.theme = theme
63
+ },
64
+
65
+ /**
66
+ * 初始化系统主题
67
+ */
68
+ initSystemTheme() {
69
+ const systemTheme = this.getSystemTheme()
70
+ this.theme = systemTheme
71
+ console.log('初始化系统主题:', this.theme)
72
+ },
73
+ },
74
+ })
package/test.vue ADDED
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+
3
+ </script>
4
+
5
+ <template>
6
+ <view>
7
+ sadsadsa
8
+ </view>
9
+ </template>