@movk/nuxt 0.1.1 → 1.1.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.
- package/README.md +84 -9
- package/dist/module.d.mts +19 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +77 -8
- package/dist/runtime/components/AutoForm.d.vue.ts +12 -6
- package/dist/runtime/components/AutoForm.vue +4 -1
- package/dist/runtime/components/AutoForm.vue.d.ts +12 -6
- package/dist/runtime/components/ColorChooser.d.vue.ts +11 -5
- package/dist/runtime/components/ColorChooser.vue.d.ts +11 -5
- package/dist/runtime/components/DatePicker.d.vue.ts +14 -5
- package/dist/runtime/components/DatePicker.vue.d.ts +14 -5
- package/dist/runtime/components/SlideVerify.d.vue.ts +107 -0
- package/dist/runtime/components/SlideVerify.vue +147 -0
- package/dist/runtime/components/SlideVerify.vue.d.ts +107 -0
- package/dist/runtime/components/StarRating.d.vue.ts +7 -7
- package/dist/runtime/components/StarRating.vue +1 -0
- package/dist/runtime/components/StarRating.vue.d.ts +7 -7
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererArray.d.vue.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererArray.vue +1 -1
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererArray.vue.d.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererField.d.vue.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererField.vue.d.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererLayout.d.vue.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererLayout.vue.d.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererNested.d.vue.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererNested.vue.d.ts +6 -4
- package/dist/runtime/components/input/WithCharacterLimit.d.vue.ts +11 -5
- package/dist/runtime/components/input/WithCharacterLimit.vue.d.ts +11 -5
- package/dist/runtime/components/input/WithClear.d.vue.ts +12 -5
- package/dist/runtime/components/input/WithClear.vue.d.ts +12 -5
- package/dist/runtime/components/input/WithCopy.d.vue.ts +12 -5
- package/dist/runtime/components/input/WithCopy.vue.d.ts +12 -5
- package/dist/runtime/components/input/WithPasswordToggle.d.vue.ts +11 -5
- package/dist/runtime/components/input/WithPasswordToggle.vue.d.ts +11 -5
- package/dist/runtime/components/theme-picker/ThemePicker.d.vue.ts +3 -0
- package/dist/runtime/components/theme-picker/ThemePicker.vue +235 -0
- package/dist/runtime/components/theme-picker/ThemePicker.vue.d.ts +3 -0
- package/dist/runtime/components/theme-picker/ThemePickerButton.d.vue.ts +18 -0
- package/dist/runtime/components/theme-picker/ThemePickerButton.vue +34 -0
- package/dist/runtime/components/theme-picker/ThemePickerButton.vue.d.ts +18 -0
- package/dist/runtime/composables/useApiAuth.d.ts +47 -0
- package/dist/runtime/composables/useApiAuth.js +66 -0
- package/dist/runtime/composables/useApiFetch.d.ts +42 -0
- package/dist/runtime/composables/useApiFetch.js +41 -0
- package/dist/runtime/composables/useAutoForm.d.ts +81 -605
- package/dist/runtime/composables/useAutoForm.js +3 -1
- package/dist/runtime/composables/useClientApiFetch.d.ts +24 -0
- package/dist/runtime/composables/useClientApiFetch.js +8 -0
- package/dist/runtime/composables/useDateFormatter.d.ts +21 -7
- package/dist/runtime/composables/useDateFormatter.js +92 -57
- package/dist/runtime/composables/useDownloadWithProgress.d.ts +48 -0
- package/dist/runtime/composables/useDownloadWithProgress.js +85 -0
- package/dist/runtime/composables/useTheme.d.ts +21 -0
- package/dist/runtime/composables/useTheme.js +143 -0
- package/dist/runtime/composables/useUploadWithProgress.d.ts +52 -0
- package/dist/runtime/composables/useUploadWithProgress.js +117 -0
- package/dist/runtime/internal/useAutoFormProvider.js +2 -2
- package/dist/runtime/plugins/api.factory.d.ts +2 -0
- package/dist/runtime/plugins/api.factory.js +186 -0
- package/dist/runtime/plugins/theme.d.ts +2 -0
- package/dist/runtime/plugins/theme.js +89 -0
- package/dist/runtime/schemas/api.d.ts +590 -0
- package/dist/runtime/schemas/api.js +228 -0
- package/dist/runtime/server/api/_movk/session.post.d.ts +10 -0
- package/dist/runtime/server/api/_movk/session.post.js +18 -0
- package/dist/runtime/style.css +1 -0
- package/dist/runtime/types/api.d.ts +218 -0
- package/dist/runtime/types/api.js +0 -0
- package/dist/runtime/types/auth.d.ts +34 -0
- package/dist/runtime/types/auto-form-renderer.d.ts +14 -22
- package/dist/runtime/types/auto-form-renderer.js +0 -0
- package/dist/runtime/types/components.d.ts +29 -41
- package/dist/runtime/types/components.js +0 -0
- package/dist/runtime/types/index.d.ts +1 -0
- package/dist/runtime/types/index.js +3 -2
- package/dist/runtime/utils/api-utils.d.ts +79 -0
- package/dist/runtime/utils/api-utils.js +127 -0
- package/package.json +38 -31
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
export const apiResponseConfigSchema = z.object({
|
|
3
|
+
/**
|
|
4
|
+
* 表示成功的业务状态码列表
|
|
5
|
+
* @defaultValue [200, 0]
|
|
6
|
+
*/
|
|
7
|
+
successCodes: z.array(z.union([z.number(), z.string()])).default([200, 0]),
|
|
8
|
+
/**
|
|
9
|
+
* 响应中业务状态码的字段名
|
|
10
|
+
* @defaultValue 'code'
|
|
11
|
+
*/
|
|
12
|
+
codeKey: z.string().default("code"),
|
|
13
|
+
/**
|
|
14
|
+
* 响应中消息内容的字段名
|
|
15
|
+
* @defaultValue 'message'
|
|
16
|
+
*/
|
|
17
|
+
messageKey: z.string().default("message"),
|
|
18
|
+
/**
|
|
19
|
+
* 响应中业务数据的字段名
|
|
20
|
+
* @defaultValue 'data'
|
|
21
|
+
*/
|
|
22
|
+
dataKey: z.string().default("data")
|
|
23
|
+
});
|
|
24
|
+
export const apiUnauthorizedConfigSchema = z.object({
|
|
25
|
+
/**
|
|
26
|
+
* 是否自动重定向到登录页
|
|
27
|
+
* @defaultValue false
|
|
28
|
+
*/
|
|
29
|
+
redirect: z.boolean().default(false),
|
|
30
|
+
/**
|
|
31
|
+
* 登录页路径
|
|
32
|
+
* @defaultValue '/login'
|
|
33
|
+
*/
|
|
34
|
+
loginPath: z.string().default("/login"),
|
|
35
|
+
/**
|
|
36
|
+
* 是否清除用户会话
|
|
37
|
+
* @defaultValue false
|
|
38
|
+
*/
|
|
39
|
+
clearSession: z.boolean().default(false)
|
|
40
|
+
});
|
|
41
|
+
export const apiAuthConfigSchema = z.object({
|
|
42
|
+
/**
|
|
43
|
+
* 是否启用认证
|
|
44
|
+
* @defaultValue false
|
|
45
|
+
*/
|
|
46
|
+
enabled: z.boolean().default(false),
|
|
47
|
+
/**
|
|
48
|
+
* 令牌来源类型
|
|
49
|
+
* @defaultValue 'session'
|
|
50
|
+
*/
|
|
51
|
+
tokenSource: z.enum(["session", "custom"]).default("session"),
|
|
52
|
+
/**
|
|
53
|
+
* 令牌在会话对象中的路径(支持点号分隔的嵌套路径)
|
|
54
|
+
* @defaultValue 'token'
|
|
55
|
+
*/
|
|
56
|
+
sessionTokenPath: z.string().default("token"),
|
|
57
|
+
/**
|
|
58
|
+
* 令牌类型前缀
|
|
59
|
+
* @defaultValue 'Bearer'
|
|
60
|
+
*/
|
|
61
|
+
tokenType: z.enum(["Bearer", "Basic", "Custom"]).default("Bearer"),
|
|
62
|
+
/** 自定义令牌类型前缀(当 tokenType 为 'Custom' 时使用) */
|
|
63
|
+
customTokenType: z.string().optional(),
|
|
64
|
+
/**
|
|
65
|
+
* 认证请求头名称
|
|
66
|
+
* @defaultValue 'Authorization'
|
|
67
|
+
*/
|
|
68
|
+
headerName: z.string().default("Authorization"),
|
|
69
|
+
/** 401 未授权处理配置 */
|
|
70
|
+
unauthorized: apiUnauthorizedConfigSchema.optional()
|
|
71
|
+
});
|
|
72
|
+
export const apiToastConfigSchema = z.looseObject({
|
|
73
|
+
/**
|
|
74
|
+
* 是否启用 Toast 提示
|
|
75
|
+
* @defaultValue true
|
|
76
|
+
*/
|
|
77
|
+
enabled: z.boolean().default(true),
|
|
78
|
+
/** 成功提示配置 */
|
|
79
|
+
success: z.object({
|
|
80
|
+
/**
|
|
81
|
+
* 是否显示成功提示
|
|
82
|
+
* @defaultValue true
|
|
83
|
+
*/
|
|
84
|
+
show: z.boolean().default(true),
|
|
85
|
+
/**
|
|
86
|
+
* 提示颜色
|
|
87
|
+
* @defaultValue 'success'
|
|
88
|
+
*/
|
|
89
|
+
color: z.string().default("success"),
|
|
90
|
+
/**
|
|
91
|
+
* 图标类名
|
|
92
|
+
* @defaultValue 'i-lucide-circle-check'
|
|
93
|
+
*/
|
|
94
|
+
icon: z.string().optional(),
|
|
95
|
+
/**
|
|
96
|
+
* 显示时长(毫秒)
|
|
97
|
+
* @defaultValue 3000
|
|
98
|
+
*/
|
|
99
|
+
duration: z.number().default(3e3)
|
|
100
|
+
}).optional(),
|
|
101
|
+
/** 错误提示配置 */
|
|
102
|
+
error: z.looseObject({
|
|
103
|
+
/**
|
|
104
|
+
* 是否显示错误提示
|
|
105
|
+
* @defaultValue true
|
|
106
|
+
*/
|
|
107
|
+
show: z.boolean().default(true),
|
|
108
|
+
/**
|
|
109
|
+
* 提示颜色
|
|
110
|
+
* @defaultValue 'error'
|
|
111
|
+
*/
|
|
112
|
+
color: z.string().default("error"),
|
|
113
|
+
/**
|
|
114
|
+
* 图标类名
|
|
115
|
+
* @defaultValue 'i-lucide-circle-x'
|
|
116
|
+
*/
|
|
117
|
+
icon: z.string().optional(),
|
|
118
|
+
/**
|
|
119
|
+
* 显示时长(毫秒)
|
|
120
|
+
* @defaultValue 3000
|
|
121
|
+
*/
|
|
122
|
+
duration: z.number().default(3e3)
|
|
123
|
+
}).optional()
|
|
124
|
+
});
|
|
125
|
+
const apiAuthPartialSchema = z.object({
|
|
126
|
+
/** 是否启用认证 */
|
|
127
|
+
enabled: z.boolean().optional(),
|
|
128
|
+
/** 令牌来源类型 */
|
|
129
|
+
tokenSource: z.enum(["session", "custom"]).optional(),
|
|
130
|
+
/** 令牌在会话对象中的路径(支持点号分隔的嵌套路径) */
|
|
131
|
+
sessionTokenPath: z.string().optional(),
|
|
132
|
+
/** 令牌类型前缀 */
|
|
133
|
+
tokenType: z.enum(["Bearer", "Basic", "Custom"]).optional(),
|
|
134
|
+
/** 自定义令牌类型前缀(当 tokenType 为 'Custom' 时使用) */
|
|
135
|
+
customTokenType: z.string().optional(),
|
|
136
|
+
/** 认证请求头名称 */
|
|
137
|
+
headerName: z.string().optional(),
|
|
138
|
+
/** 401 未授权处理配置 */
|
|
139
|
+
unauthorized: z.object({
|
|
140
|
+
/** 是否自动重定向到登录页 */
|
|
141
|
+
redirect: z.boolean().optional(),
|
|
142
|
+
/** 登录页路径 */
|
|
143
|
+
loginPath: z.string().optional(),
|
|
144
|
+
/** 是否清除用户会话 */
|
|
145
|
+
clearSession: z.boolean().optional()
|
|
146
|
+
}).optional()
|
|
147
|
+
}).optional();
|
|
148
|
+
export const apiEndpointPublicConfigSchema = z.object({
|
|
149
|
+
/** 端点的基础 URL */
|
|
150
|
+
baseURL: z.string(),
|
|
151
|
+
/** 端点别名(用于标识) */
|
|
152
|
+
alias: z.string().optional(),
|
|
153
|
+
/** 端点级别的认证配置(覆盖全局配置) */
|
|
154
|
+
auth: apiAuthPartialSchema,
|
|
155
|
+
/** 端点级别的 Toast 配置(覆盖全局配置) */
|
|
156
|
+
toast: apiToastConfigSchema.partial().optional(),
|
|
157
|
+
/** 端点级别的响应配置(覆盖全局配置) */
|
|
158
|
+
response: apiResponseConfigSchema.partial().optional()
|
|
159
|
+
});
|
|
160
|
+
export const apiEndpointPrivateConfigSchema = z.object({
|
|
161
|
+
/** 自定义请求头(仅服务端使用,不会暴露给客户端) */
|
|
162
|
+
headers: z.record(z.string(), z.string()).optional()
|
|
163
|
+
});
|
|
164
|
+
export const movkApiPublicConfigSchema = z.object({
|
|
165
|
+
/**
|
|
166
|
+
* 默认使用的端点名称
|
|
167
|
+
* @defaultValue 'default'
|
|
168
|
+
*/
|
|
169
|
+
defaultEndpoint: z.string().default("default"),
|
|
170
|
+
/**
|
|
171
|
+
* 是否启用调试模式(在控制台输出请求和响应日志)
|
|
172
|
+
* @defaultValue false
|
|
173
|
+
*/
|
|
174
|
+
debug: z.boolean().default(false),
|
|
175
|
+
/**
|
|
176
|
+
* 端点配置映射
|
|
177
|
+
* @defaultValue { default: { baseURL: '/api' } }
|
|
178
|
+
*/
|
|
179
|
+
endpoints: z.record(z.string(), apiEndpointPublicConfigSchema).default({
|
|
180
|
+
default: { baseURL: "/api" }
|
|
181
|
+
}),
|
|
182
|
+
/** 全局响应配置 */
|
|
183
|
+
response: apiResponseConfigSchema.optional(),
|
|
184
|
+
/** 全局认证配置 */
|
|
185
|
+
auth: apiAuthConfigSchema.optional(),
|
|
186
|
+
/** 全局 Toast 配置 */
|
|
187
|
+
toast: apiToastConfigSchema.optional()
|
|
188
|
+
}).transform((data) => ({
|
|
189
|
+
...data,
|
|
190
|
+
response: apiResponseConfigSchema.parse(data.response ?? {}),
|
|
191
|
+
auth: apiAuthConfigSchema.parse(data.auth ?? {}),
|
|
192
|
+
toast: apiToastConfigSchema.parse(data.toast ?? {})
|
|
193
|
+
}));
|
|
194
|
+
export const movkApiPrivateConfigSchema = z.object({
|
|
195
|
+
/** 各端点的私有配置 */
|
|
196
|
+
endpoints: z.record(z.string(), apiEndpointPrivateConfigSchema).optional()
|
|
197
|
+
});
|
|
198
|
+
export const movkApiFullConfigSchema = z.object({
|
|
199
|
+
/**
|
|
200
|
+
* 是否启用 API 模块
|
|
201
|
+
* @defaultValue true
|
|
202
|
+
*/
|
|
203
|
+
enabled: z.boolean().default(true),
|
|
204
|
+
/**
|
|
205
|
+
* 默认使用的端点名称
|
|
206
|
+
* @defaultValue 'default'
|
|
207
|
+
*/
|
|
208
|
+
defaultEndpoint: z.string().default("default"),
|
|
209
|
+
/**
|
|
210
|
+
* 是否启用调试模式
|
|
211
|
+
* @defaultValue false
|
|
212
|
+
*/
|
|
213
|
+
debug: z.boolean().default(false),
|
|
214
|
+
/**
|
|
215
|
+
* 端点配置映射(包含公共和私有配置)
|
|
216
|
+
* @defaultValue { default: { baseURL: '/api' } }
|
|
217
|
+
*/
|
|
218
|
+
endpoints: z.record(
|
|
219
|
+
z.string(),
|
|
220
|
+
apiEndpointPublicConfigSchema.extend(apiEndpointPrivateConfigSchema.shape)
|
|
221
|
+
).default({ default: { baseURL: "/api" } }),
|
|
222
|
+
/** 全局响应配置 */
|
|
223
|
+
response: apiResponseConfigSchema.optional(),
|
|
224
|
+
/** 全局认证配置 */
|
|
225
|
+
auth: apiAuthConfigSchema.optional(),
|
|
226
|
+
/** 全局 Toast 配置 */
|
|
227
|
+
toast: apiToastConfigSchema.optional()
|
|
228
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineEventHandler, readBody, createError } from "h3";
|
|
2
|
+
export default defineEventHandler(async (event) => {
|
|
3
|
+
const body = await readBody(event);
|
|
4
|
+
if (!body || typeof body !== "object") {
|
|
5
|
+
throw createError({
|
|
6
|
+
statusCode: 400,
|
|
7
|
+
message: "Invalid request body"
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
if (!body.user || typeof body.user !== "object") {
|
|
11
|
+
throw createError({
|
|
12
|
+
statusCode: 400,
|
|
13
|
+
message: "User data is required"
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
await setUserSession(event, body);
|
|
17
|
+
return { success: true };
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss" theme(static);@import "@nuxt/ui";@source "./components";
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { $Fetch, FetchOptions, FetchHooks, FetchError } from 'ofetch';
|
|
2
|
+
import type { UseFetchOptions as NuxtUseFetchOptions, AsyncData } from 'nuxt/app';
|
|
3
|
+
import type { ToastProps } from '@nuxt/ui';
|
|
4
|
+
import type { z } from 'zod/v4';
|
|
5
|
+
import type { apiEndpointPublicConfigSchema, movkApiPublicConfigSchema, movkApiPrivateConfigSchema, movkApiFullConfigSchema, apiUnauthorizedConfigSchema, apiResponseConfigSchema, apiAuthConfigSchema, apiToastConfigSchema } from '../schemas/api.js';
|
|
6
|
+
import type { User, UserSession, UserSessionComposable } from '#auth-utils';
|
|
7
|
+
declare module 'ofetch' {
|
|
8
|
+
interface FetchOptions {
|
|
9
|
+
context?: ApiFetchContext;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* API 请求扩展上下文
|
|
14
|
+
* @description 通过 fetch options 的 context 字段传递的额外配置
|
|
15
|
+
*/
|
|
16
|
+
export interface ApiFetchContext {
|
|
17
|
+
/** Toast 提示配置,设置为 false 禁用提示 */
|
|
18
|
+
toast?: RequestToastOptions | false;
|
|
19
|
+
/** 是否跳过业务状态码检查 */
|
|
20
|
+
skipBusinessCheck?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** API 响应配置(包含业务状态码、数据/消息字段映射) */
|
|
23
|
+
export type ApiResponseConfig = z.infer<typeof apiResponseConfigSchema>;
|
|
24
|
+
/** API 认证配置(包含令牌来源、认证头配置) */
|
|
25
|
+
export type ApiAuthConfig = z.infer<typeof apiAuthConfigSchema>;
|
|
26
|
+
/** 401 未授权处理配置(包含重定向和会话清理选项) */
|
|
27
|
+
export type ApiUnauthorizedConfig = z.infer<typeof apiUnauthorizedConfigSchema>;
|
|
28
|
+
/** Toast 提示配置(包含成功/错误提示的样式和行为) */
|
|
29
|
+
export type ApiToastConfig = z.infer<typeof apiToastConfigSchema>;
|
|
30
|
+
/** API 端点公共配置(用于模块配置的公共部分) */
|
|
31
|
+
export type ApiEndpointPublicConfig = z.infer<typeof apiEndpointPublicConfigSchema>;
|
|
32
|
+
/** Movk API 模块公共配置 */
|
|
33
|
+
export type MovkApiPublicConfig = z.infer<typeof movkApiPublicConfigSchema>;
|
|
34
|
+
/** Movk API 模块私有配置(仅服务端可访问) */
|
|
35
|
+
export type MovkApiPrivateConfig = z.infer<typeof movkApiPrivateConfigSchema>;
|
|
36
|
+
/** Movk API 模块完整配置(公共+私有) */
|
|
37
|
+
export type MovkApiFullConfig = z.input<typeof movkApiFullConfigSchema>;
|
|
38
|
+
/**
|
|
39
|
+
* API 响应数据结构
|
|
40
|
+
* @description 适配多种常见的后端响应格式
|
|
41
|
+
* @template T - 业务数据类型
|
|
42
|
+
*/
|
|
43
|
+
export interface ApiResponse<T = unknown> {
|
|
44
|
+
/** 业务状态码 */
|
|
45
|
+
code?: number | string;
|
|
46
|
+
/** HTTP 状态码或业务状态 */
|
|
47
|
+
status?: number | string;
|
|
48
|
+
/** 消息内容(简写) */
|
|
49
|
+
msg?: string;
|
|
50
|
+
/** 消息内容 */
|
|
51
|
+
message?: string;
|
|
52
|
+
/** 业务数据 */
|
|
53
|
+
data?: T;
|
|
54
|
+
/** 业务数据(别名) */
|
|
55
|
+
result?: T;
|
|
56
|
+
/** 认证令牌 */
|
|
57
|
+
token?: string;
|
|
58
|
+
/** 访问令牌 */
|
|
59
|
+
accessToken?: string;
|
|
60
|
+
/** 错误信息 */
|
|
61
|
+
error?: string | null;
|
|
62
|
+
/** 支持任意额外字段 */
|
|
63
|
+
[key: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* API 错误对象
|
|
67
|
+
* @description 扩展标准 Error,包含业务响应和状态码信息
|
|
68
|
+
*/
|
|
69
|
+
export interface ApiError extends Error {
|
|
70
|
+
/** HTTP 或业务状态码 */
|
|
71
|
+
statusCode: number;
|
|
72
|
+
/** 原始 API 响应数据 */
|
|
73
|
+
response?: ApiResponse;
|
|
74
|
+
/** 是否为业务逻辑错误(非 HTTP 错误) */
|
|
75
|
+
isBusinessError: boolean;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 已解析的端点配置
|
|
79
|
+
* @description 合并全局配置和端点配置后的最终配置,供内部使用
|
|
80
|
+
*/
|
|
81
|
+
export interface ResolvedEndpointConfig extends ApiEndpointPublicConfig {
|
|
82
|
+
/** 认证配置(已合并全局配置) */
|
|
83
|
+
auth: Partial<ApiAuthConfig>;
|
|
84
|
+
/** Toast 配置(已合并全局配置) */
|
|
85
|
+
toast: Partial<ApiToastConfig>;
|
|
86
|
+
/** 响应配置(已合并全局配置) */
|
|
87
|
+
response: Partial<ApiResponseConfig>;
|
|
88
|
+
/** 自定义请求头(仅服务端配置) */
|
|
89
|
+
headers?: Record<string, string>;
|
|
90
|
+
/** 内置请求钩子(内部使用) */
|
|
91
|
+
builtinHooks?: FetchHooks;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 请求级别的 Toast 提示选项
|
|
95
|
+
* @description 用于单个请求的 Toast 配置,可覆盖全局配置
|
|
96
|
+
*/
|
|
97
|
+
export interface RequestToastOptions {
|
|
98
|
+
/** 成功提示配置,设置为 false 禁用成功提示 */
|
|
99
|
+
success?: Partial<ToastProps> | false;
|
|
100
|
+
/** 错误提示配置,设置为 false 禁用错误提示 */
|
|
101
|
+
error?: Partial<ToastProps> | false;
|
|
102
|
+
/** 自定义成功消息 */
|
|
103
|
+
successMessage?: string;
|
|
104
|
+
/** 自定义错误消息 */
|
|
105
|
+
errorMessage?: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* useApiFetch 的扩展选项
|
|
109
|
+
* @template ResT - API 响应数据类型
|
|
110
|
+
* @template DataT - 转换后的数据类型
|
|
111
|
+
*/
|
|
112
|
+
export interface ApiFetchExtras<ResT, DataT = ResT> {
|
|
113
|
+
/** 使用的端点名称(默认使用 defaultEndpoint) */
|
|
114
|
+
endpoint?: string;
|
|
115
|
+
/** Toast 提示配置,设置为 false 禁用提示 */
|
|
116
|
+
toast?: RequestToastOptions | false;
|
|
117
|
+
/** 是否跳过业务状态码检查 */
|
|
118
|
+
skipBusinessCheck?: boolean;
|
|
119
|
+
/** 数据转换函数(应用于提取后的业务数据) */
|
|
120
|
+
transform?: (data: ResT) => DataT;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* useApiFetch 选项类型
|
|
124
|
+
* @template ResT - API 响应数据类型
|
|
125
|
+
* @template DataT - 转换后的数据类型
|
|
126
|
+
*/
|
|
127
|
+
export type UseApiFetchOptions<ResT, DataT = ResT> = Omit<NuxtUseFetchOptions<ApiResponse<ResT>, DataT>, 'transform'> & ApiFetchExtras<ResT, DataT>;
|
|
128
|
+
/**
|
|
129
|
+
* useApiFetch 返回值类型
|
|
130
|
+
* @template DataT - 数据类型
|
|
131
|
+
*/
|
|
132
|
+
export type UseApiFetchReturn<DataT> = AsyncData<DataT | null, FetchError | ApiError | null>;
|
|
133
|
+
/**
|
|
134
|
+
* 文件下载选项
|
|
135
|
+
*/
|
|
136
|
+
export interface DownloadOptions extends Omit<FetchOptions<'json'>, 'responseType'> {
|
|
137
|
+
/** Toast 提示配置,设置为 false 禁用提示 */
|
|
138
|
+
toast?: RequestToastOptions | false;
|
|
139
|
+
/** 下载进度回调(0-100) */
|
|
140
|
+
onProgress?: (progress: number) => void;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 文件上传选项
|
|
144
|
+
*/
|
|
145
|
+
export interface UploadOptions extends Omit<FetchOptions<'json'>, 'responseType' | 'body'> {
|
|
146
|
+
/**
|
|
147
|
+
* FormData 中的文件字段名
|
|
148
|
+
* @defaultValue 'file'
|
|
149
|
+
*/
|
|
150
|
+
fieldName?: string;
|
|
151
|
+
/** Toast 提示配置,设置为 false 禁用提示 */
|
|
152
|
+
toast?: RequestToastOptions | false;
|
|
153
|
+
/** 上传进度回调(0-100) */
|
|
154
|
+
onProgress?: (progress: number) => void;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* API 客户端接口
|
|
158
|
+
* @description 提供统一的 API 请求、文件上传下载等功能
|
|
159
|
+
*/
|
|
160
|
+
export interface ApiClient {
|
|
161
|
+
/** ofetch 实例,用于发起请求 */
|
|
162
|
+
$fetch: $Fetch;
|
|
163
|
+
/** 切换到指定端点 */
|
|
164
|
+
use: (endpoint: string) => ApiClient;
|
|
165
|
+
/** 下载文件 */
|
|
166
|
+
download: (url: string, filename?: string, options?: DownloadOptions) => Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* 上传文件
|
|
169
|
+
* @template T - API 响应数据类型
|
|
170
|
+
*/
|
|
171
|
+
upload: <T = unknown>(url: string, file: File | File[] | FormData, options?: UploadOptions) => Promise<ApiResponse<T>>;
|
|
172
|
+
/** 获取当前端点配置 */
|
|
173
|
+
getConfig: () => ResolvedEndpointConfig;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* 登录选项
|
|
177
|
+
* @template LoginRData - 登录接口响应数据类型
|
|
178
|
+
*/
|
|
179
|
+
export interface LoginOptions<LoginRData = unknown> {
|
|
180
|
+
/** 登录接口路径 */
|
|
181
|
+
loginPath: string;
|
|
182
|
+
/** 登录凭证(用户名/密码等) */
|
|
183
|
+
credentials: unknown;
|
|
184
|
+
/** 获取用户信息的接口路径(可选,如果登录接口不返回用户信息) */
|
|
185
|
+
userInfoPath?: string;
|
|
186
|
+
/**
|
|
187
|
+
* 从登录响应中提取令牌的函数
|
|
188
|
+
* @defaultValue 从 response.token 或 response.data.token 提取
|
|
189
|
+
*/
|
|
190
|
+
tokenExtractor?: (response: ApiResponse<LoginRData>) => string | null | undefined;
|
|
191
|
+
/**
|
|
192
|
+
* 自定义会话构建函数
|
|
193
|
+
* @defaultValue 使用 { user, token } 作为会话数据
|
|
194
|
+
*/
|
|
195
|
+
sessionBuilder?: (userInfo: User, token: string) => UserSession;
|
|
196
|
+
/** 使用的端点名称(默认使用 defaultEndpoint) */
|
|
197
|
+
endpoint?: string;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* 登录结果
|
|
201
|
+
*/
|
|
202
|
+
export interface LoginResult {
|
|
203
|
+
/** 用户信息 */
|
|
204
|
+
user: User;
|
|
205
|
+
/** 认证令牌 */
|
|
206
|
+
token: string;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* useApiAuth 返回值类型
|
|
210
|
+
* @description 扩展 nuxt-auth-utils 的 UserSessionComposable,添加 login 方法
|
|
211
|
+
*/
|
|
212
|
+
export interface UseApiAuthReturn extends UserSessionComposable {
|
|
213
|
+
/**
|
|
214
|
+
* 登录方法
|
|
215
|
+
* @template LoginRData - 登录接口响应数据类型
|
|
216
|
+
*/
|
|
217
|
+
login: <LoginRData = unknown>(options: LoginOptions<LoginRData>) => Promise<LoginResult>;
|
|
218
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
declare module '#auth-utils' {
|
|
2
|
+
interface User {
|
|
3
|
+
// Add your own fields
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface UserSession {
|
|
7
|
+
/**
|
|
8
|
+
* Session ID
|
|
9
|
+
*/
|
|
10
|
+
id?: string
|
|
11
|
+
/**
|
|
12
|
+
* User session data, available on client and server
|
|
13
|
+
*/
|
|
14
|
+
user?: User
|
|
15
|
+
/**
|
|
16
|
+
* Private session data, only available on server/ code
|
|
17
|
+
*/
|
|
18
|
+
secure?: SecureSessionData
|
|
19
|
+
/**
|
|
20
|
+
* 认证 Token
|
|
21
|
+
*/
|
|
22
|
+
token?: string
|
|
23
|
+
/**
|
|
24
|
+
* Extra session data, available on client and server
|
|
25
|
+
*/
|
|
26
|
+
[key: string]: unknown
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface SecureSessionData {
|
|
30
|
+
// Add your own fields
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { }
|
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
import type { z } from 'zod/v4'
|
|
2
|
-
import type { AnyObject } from '@movk/core'
|
|
3
|
-
import type { ButtonProps } from '@nuxt/ui'
|
|
4
|
-
import type { AutoFormField } from './auto-form'
|
|
5
|
-
import type { AutoFormProps } from '../components/AutoForm.vue'
|
|
6
|
-
|
|
7
|
-
// AutoFormRendererArray
|
|
1
|
+
import type { z } from 'zod/v4';
|
|
2
|
+
import type { AnyObject } from '@movk/core';
|
|
3
|
+
import type { ButtonProps } from '@nuxt/ui';
|
|
4
|
+
import type { AutoFormField } from './auto-form.js';
|
|
5
|
+
import type { AutoFormProps } from '../components/AutoForm.vue.js';
|
|
8
6
|
export interface AutoFormRendererArrayProps<S extends z.ZodObject> extends Pick<AutoFormProps<S>, 'schema'> {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
field: AutoFormField;
|
|
8
|
+
extraProps?: AnyObject;
|
|
9
|
+
addButtonProps?: Partial<ButtonProps>;
|
|
12
10
|
}
|
|
13
|
-
|
|
14
|
-
// AutoFormRendererField
|
|
15
11
|
export interface AutoFormFieldProps<S extends z.ZodObject> extends Pick<AutoFormProps<S>, 'schema'> {
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
field: AutoFormField;
|
|
13
|
+
extraProps?: AnyObject;
|
|
18
14
|
}
|
|
19
|
-
|
|
20
|
-
// AutoFormRendererLayout
|
|
21
15
|
export interface AutoFormRendererLayoutProps<S extends z.ZodObject> extends Pick<AutoFormProps<S>, 'schema'> {
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
field: AutoFormField;
|
|
17
|
+
extraProps?: AnyObject;
|
|
24
18
|
}
|
|
25
|
-
|
|
26
|
-
// AutoFormRendererNested
|
|
27
19
|
export interface AutoFormRendererNestedProps<S extends z.ZodObject> extends Pick<AutoFormProps<S>, 'schema'> {
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
field: AutoFormField;
|
|
21
|
+
extraProps?: AnyObject;
|
|
30
22
|
}
|
|
File without changes
|
|
@@ -1,55 +1,43 @@
|
|
|
1
|
-
import type { ButtonProps, PopoverProps, ColorPickerProps, PopoverEmits, CalendarProps, CalendarEmits, InputProps, InputEmits, InputSlots, TooltipProps, InputValue } from '@nuxt/ui'
|
|
2
|
-
import type { OmitByKey } from '@movk/core'
|
|
3
|
-
import type { ClassNameValue } from 'tailwind-merge'
|
|
4
|
-
import type { DateFormatterOptions, useDateFormatter } from '../composables/useDateFormatter'
|
|
5
|
-
|
|
6
|
-
// ColorChooser
|
|
1
|
+
import type { ButtonProps, PopoverProps, ColorPickerProps, PopoverEmits, CalendarProps, CalendarEmits, InputProps, InputEmits, InputSlots, TooltipProps, InputValue } from '@nuxt/ui';
|
|
2
|
+
import type { OmitByKey } from '@movk/core';
|
|
3
|
+
import type { ClassNameValue } from 'tailwind-merge';
|
|
4
|
+
import type { DateFormatterOptions, useDateFormatter } from '../composables/useDateFormatter.js';
|
|
7
5
|
export interface ColorChooserProps<P extends 'click' | 'hover' = 'click'> extends /** @vue-ignore */ ColorPickerProps {
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
popoverProps?: PopoverProps<P>;
|
|
7
|
+
buttonProps?: ButtonProps;
|
|
10
8
|
}
|
|
11
|
-
|
|
12
|
-
export type
|
|
13
|
-
|
|
14
|
-
// DatePicker
|
|
15
|
-
export type LabelFormat = 'iso' | 'formatted' | 'date' | 'timestamp' | 'unix'
|
|
16
|
-
export type ValueType<R extends boolean, M extends boolean> = CalendarProps<R, M>['modelValue']
|
|
17
|
-
|
|
9
|
+
export type ColorChooserEmits = PopoverEmits;
|
|
10
|
+
export type LabelFormat = 'iso' | 'formatted' | 'date' | 'timestamp' | 'unix';
|
|
11
|
+
export type ValueType<R extends boolean, M extends boolean> = CalendarProps<R, M>['modelValue'];
|
|
18
12
|
export interface DatePickerProps<R extends boolean, M extends boolean, P extends 'click' | 'hover' = 'click'> extends /** @vue-ignore */ OmitByKey<CalendarProps<R, M>, 'modelValue'>, DateFormatterOptions {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
buttonProps?: ButtonProps;
|
|
14
|
+
popoverProps?: PopoverProps<P>;
|
|
15
|
+
labelFormat?: LabelFormat | ((formatter: ReturnType<typeof useDateFormatter>, modelValue: ValueType<R, M>) => string);
|
|
22
16
|
}
|
|
23
|
-
|
|
24
|
-
export type DatePickerEmits<R extends boolean, M extends boolean> = PopoverEmits & CalendarEmits<R, M>
|
|
25
|
-
|
|
26
|
-
// Input components
|
|
17
|
+
export type DatePickerEmits<R extends boolean, M extends boolean> = PopoverEmits & CalendarEmits<R, M>;
|
|
27
18
|
export interface WithCharacterLimitProps<T extends InputValue = InputValue> extends /** @vue-ignore */ OmitByKey<InputProps<T>, 'modelValue'> {
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
maxLength?: number;
|
|
20
|
+
counterClass?: ClassNameValue;
|
|
30
21
|
}
|
|
31
|
-
export type WithCharacterLimitEmits<T extends InputValue = InputValue> = InputEmits<T
|
|
32
|
-
export type WithCharacterLimitSlots = OmitByKey<InputSlots, 'trailing'
|
|
33
|
-
|
|
22
|
+
export type WithCharacterLimitEmits<T extends InputValue = InputValue> = InputEmits<T>;
|
|
23
|
+
export type WithCharacterLimitSlots = OmitByKey<InputSlots, 'trailing'>;
|
|
34
24
|
export interface WithClearProps<T extends InputValue = InputValue> extends /** @vue-ignore */ OmitByKey<InputProps<T>, 'modelValue'> {
|
|
35
|
-
|
|
25
|
+
buttonProps?: ButtonProps;
|
|
36
26
|
}
|
|
37
27
|
export type WithClearEmits<T extends InputValue = InputValue> = InputEmits<T> & {
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
export type WithClearSlots = OmitByKey<InputSlots, 'trailing'
|
|
41
|
-
|
|
28
|
+
clear: [];
|
|
29
|
+
};
|
|
30
|
+
export type WithClearSlots = OmitByKey<InputSlots, 'trailing'>;
|
|
42
31
|
export interface WithCopyProps<T extends InputValue = InputValue> extends /** @vue-ignore */ OmitByKey<InputProps<T>, 'modelValue'> {
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
buttonProps?: ButtonProps;
|
|
33
|
+
tooltipProps?: TooltipProps;
|
|
45
34
|
}
|
|
46
35
|
export type WithCopyEmits<T extends InputValue = InputValue> = InputEmits<T> & {
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
export type WithCopySlots = OmitByKey<InputSlots, 'trailing'
|
|
50
|
-
|
|
36
|
+
copy: [value: string];
|
|
37
|
+
};
|
|
38
|
+
export type WithCopySlots = OmitByKey<InputSlots, 'trailing'>;
|
|
51
39
|
export interface WithPasswordToggleProps<T extends InputValue = InputValue> extends /** @vue-ignore */ OmitByKey<InputProps<T>, 'type' | 'modelValue'> {
|
|
52
|
-
|
|
40
|
+
buttonProps?: ButtonProps;
|
|
53
41
|
}
|
|
54
|
-
export type WithPasswordToggleEmits<T extends InputValue = InputValue> = InputEmits<T
|
|
55
|
-
export type WithPasswordToggleSlots = OmitByKey<InputSlots, 'trailing'
|
|
42
|
+
export type WithPasswordToggleEmits<T extends InputValue = InputValue> = InputEmits<T>;
|
|
43
|
+
export type WithPasswordToggleSlots = OmitByKey<InputSlots, 'trailing'>;
|
|
File without changes
|