mta-mcp 2.6.0 → 2.7.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,122 @@
1
+ /**
2
+ * Mock 系统入口
3
+ *
4
+ * 提供 Mock 开关和常用工具函数
5
+ */
6
+ import type { ApiResponse, PageData } from '../types'
7
+
8
+ // Mock 开关(由环境变量控制)
9
+ export const MOCK_ENABLED = import.meta.env.VITE_MOCK_ENABLED === 'true'
10
+
11
+ // Mock 延迟时间(模拟网络请求)
12
+ export const MOCK_DELAY = 300
13
+
14
+ /**
15
+ * 延迟函数
16
+ */
17
+ export const delay = (ms: number = MOCK_DELAY) =>
18
+ new Promise(resolve => setTimeout(resolve, ms))
19
+
20
+ // 别名
21
+ export const sleep = delay
22
+
23
+ /**
24
+ * 生成成功响应
25
+ */
26
+ export function successResponse<T>(data: T): ApiResponse<T> {
27
+ return {
28
+ code: 0,
29
+ data,
30
+ message: 'success',
31
+ }
32
+ }
33
+
34
+ /**
35
+ * 生成错误响应
36
+ */
37
+ export function errorResponse(message: string, code = -1): ApiResponse<null> {
38
+ return {
39
+ code,
40
+ data: null,
41
+ message,
42
+ }
43
+ }
44
+
45
+ /**
46
+ * 生成分页响应
47
+ */
48
+ export function generatePageResponse<T>(
49
+ list: T[],
50
+ page: number,
51
+ pageSize: number,
52
+ total?: number
53
+ ): ApiResponse<PageData<T>> {
54
+ const start = (page - 1) * pageSize
55
+ const end = start + pageSize
56
+ const data = list.slice(start, end)
57
+
58
+ return {
59
+ code: 0,
60
+ data: {
61
+ list: data,
62
+ total: total ?? list.length,
63
+ page,
64
+ pageSize,
65
+ },
66
+ message: 'success',
67
+ }
68
+ }
69
+
70
+ /**
71
+ * 生成随机 ID
72
+ */
73
+ export function randomId(): string {
74
+ return Date.now().toString(36) + Math.random().toString(36).substr(2, 9)
75
+ }
76
+
77
+ /**
78
+ * 生成随机日期(近 n 天内)
79
+ */
80
+ export function randomDate(days = 30): string {
81
+ const date = new Date()
82
+ date.setDate(date.getDate() - Math.floor(Math.random() * days))
83
+ return date.toISOString().split('T')[0] + ' ' + date.toTimeString().split(' ')[0]
84
+ }
85
+
86
+ /**
87
+ * 从数组中随机选择
88
+ */
89
+ export function randomPick<T>(arr: T[]): T {
90
+ return arr[Math.floor(Math.random() * arr.length)]
91
+ }
92
+
93
+ /**
94
+ * 生成随机整数
95
+ */
96
+ export function randomInt(min: number, max: number): number {
97
+ return Math.floor(Math.random() * (max - min + 1)) + min
98
+ }
99
+
100
+ /**
101
+ * 生成随机金额(保留两位小数)
102
+ */
103
+ export function randomAmount(min = 100, max = 10000): number {
104
+ return Number((Math.random() * (max - min) + min).toFixed(2))
105
+ }
106
+
107
+ /**
108
+ * 生成随机手机号
109
+ */
110
+ export function randomPhone(): string {
111
+ const prefixes = ['138', '139', '150', '151', '152', '158', '159', '186', '187', '188']
112
+ return randomPick(prefixes) + String(Math.random()).slice(2, 10)
113
+ }
114
+
115
+ /**
116
+ * 生成随机邮箱
117
+ */
118
+ export function randomEmail(name?: string): string {
119
+ const domains = ['qq.com', '163.com', 'gmail.com', 'outlook.com']
120
+ const prefix = name || `user${randomInt(1000, 9999)}`
121
+ return `${prefix}@${randomPick(domains)}`
122
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * [模块名] API
3
+ *
4
+ * 💡 使用说明:
5
+ * 1. 复制此文件,重命名为业务模块名(如 user.ts, order.ts)
6
+ * 2. 修改 URLs 对象中的接口地址
7
+ * 3. 定义业务相关的类型
8
+ * 4. 实现具体的 API 函数
9
+ * 5. 在 modules/index.ts 中导出
10
+ */
11
+ import { post, get, put, del } from '../request'
12
+ import { MOCK_ENABLED } from '../mock'
13
+ // import * as mockModule from '../mock/[module]'
14
+ import type { ApiResponse, PageResponse, PageParams } from '../types'
15
+
16
+ // ========== 接口地址 ==========
17
+
18
+ const URLs = {
19
+ list: '/xxx/list',
20
+ detail: '/xxx/detail',
21
+ create: '/xxx/create',
22
+ update: '/xxx/update',
23
+ delete: '/xxx/delete',
24
+ }
25
+
26
+ // ========== 类型定义 ==========
27
+
28
+ /** 数据项类型 */
29
+ export interface ItemData {
30
+ id: string
31
+ name: string
32
+ status: string
33
+ createdAt: string
34
+ updatedAt: string
35
+ // ... 添加其他字段
36
+ }
37
+
38
+ /** 创建/更新参数 */
39
+ export interface CreateParams {
40
+ name: string
41
+ // ... 添加其他参数
42
+ }
43
+
44
+ /** 列表查询参数 */
45
+ export interface ListParams extends PageParams {
46
+ keyword?: string
47
+ status?: string
48
+ startDate?: string
49
+ endDate?: string
50
+ // ... 添加其他筛选条件
51
+ }
52
+
53
+ // ========== 接口实现 ==========
54
+
55
+ /**
56
+ * 获取列表
57
+ */
58
+ export async function getList(params: ListParams): Promise<PageResponse<ItemData>> {
59
+ // if (MOCK_ENABLED) return mockModule.mockGetList(params)
60
+ return get(URLs.list, params)
61
+ }
62
+
63
+ /**
64
+ * 获取详情
65
+ */
66
+ export async function getDetail(id: string): Promise<ApiResponse<ItemData>> {
67
+ // if (MOCK_ENABLED) return mockModule.mockGetDetail(id)
68
+ return get(URLs.detail, { id })
69
+ }
70
+
71
+ /**
72
+ * 创建
73
+ */
74
+ export async function create(data: CreateParams): Promise<ApiResponse<ItemData>> {
75
+ // if (MOCK_ENABLED) return mockModule.mockCreate(data)
76
+ return post(URLs.create, data)
77
+ }
78
+
79
+ /**
80
+ * 更新
81
+ */
82
+ export async function update(id: string, data: Partial<CreateParams>): Promise<ApiResponse<ItemData>> {
83
+ // if (MOCK_ENABLED) return mockModule.mockUpdate(id, data)
84
+ return put(`${URLs.update}/${id}`, data)
85
+ }
86
+
87
+ /**
88
+ * 删除
89
+ */
90
+ export async function remove(id: string): Promise<ApiResponse<null>> {
91
+ // if (MOCK_ENABLED) return mockModule.mockDelete(id)
92
+ return del(URLs.delete, { id })
93
+ }
94
+
95
+ /**
96
+ * 批量删除
97
+ */
98
+ export async function batchRemove(ids: string[]): Promise<ApiResponse<null>> {
99
+ // if (MOCK_ENABLED) return mockModule.mockBatchDelete(ids)
100
+ return post(`${URLs.delete}/batch`, { ids })
101
+ }
102
+
103
+ /**
104
+ * 更新状态
105
+ */
106
+ export async function updateStatus(id: string, status: string): Promise<ApiResponse<null>> {
107
+ // if (MOCK_ENABLED) return mockModule.mockUpdateStatus(id, status)
108
+ return put(`${URLs.update}/${id}/status`, { status })
109
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * API 模块统一导出
3
+ *
4
+ * 💡 添加新模块时:
5
+ * 1. 复制 _template.ts,重命名为业务模块名
6
+ * 2. 在此处添加 export
7
+ *
8
+ * @example
9
+ * export * as userApi from './user'
10
+ * export * as orderApi from './order'
11
+ * export * as productApi from './product'
12
+ */
13
+
14
+ // 按项目实际模块添加导出...
15
+ // export * as userApi from './user'
16
+ // export * as authApi from './auth'
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Axios 请求封装
3
+ *
4
+ * 💡 自定义点(按项目调整):
5
+ * - API_TIMEOUT: 请求超时时间
6
+ * - NO_TOKEN_URLS: 无需 Token 的接口白名单
7
+ * - TOKEN_KEY/USER_KEY: 本地存储键名
8
+ * - showMessage: UI 框架消息提示方法
9
+ * - 响应拦截器中的业务状态码判断
10
+ */
11
+ import axios from 'axios'
12
+ import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
13
+ import router from '@/router'
14
+ import type { ApiResponse } from './types'
15
+
16
+ // ========== 常量配置 ==========
17
+
18
+ const API_TIMEOUT = 30000
19
+
20
+ // 无需 Token 的接口白名单(按项目调整)
21
+ const NO_TOKEN_URLS = [
22
+ '/login',
23
+ '/register',
24
+ '/captcha',
25
+ '/sms-code',
26
+ ]
27
+
28
+ // ========== Token 管理 ==========
29
+
30
+ const TOKEN_KEY = 'app_token'
31
+ const USER_KEY = 'app_user'
32
+
33
+ export const getToken = (): string | null => localStorage.getItem(TOKEN_KEY)
34
+ export const setToken = (token: string): void => localStorage.setItem(TOKEN_KEY, token)
35
+ export const clearToken = (): void => {
36
+ localStorage.removeItem(TOKEN_KEY)
37
+ localStorage.removeItem(USER_KEY)
38
+ }
39
+
40
+ export const getUserInfo = <T = any>(): T | null => {
41
+ const userStr = localStorage.getItem(USER_KEY)
42
+ if (!userStr) return null
43
+ try {
44
+ return JSON.parse(userStr)
45
+ } catch {
46
+ return null
47
+ }
48
+ }
49
+
50
+ export const setUserInfo = (user: any): void => {
51
+ localStorage.setItem(USER_KEY, JSON.stringify(user))
52
+ }
53
+
54
+ // ========== 消息提示 ==========
55
+
56
+ // 💡 按 UI 框架替换此对象
57
+ // Element Plus: import { ElMessage } from 'element-plus'
58
+ // Ant Design Vue: import { message } from 'ant-design-vue'
59
+
60
+ const showMessage = {
61
+ success: (msg: string) => console.log('✅', msg),
62
+ error: (msg: string) => console.error('❌', msg),
63
+ warning: (msg: string) => console.warn('⚠️', msg),
64
+ }
65
+
66
+ // Element Plus 示例:
67
+ // const showMessage = {
68
+ // success: (msg: string) => ElMessage.success(msg),
69
+ // error: (msg: string) => ElMessage.error(msg),
70
+ // warning: (msg: string) => ElMessage.warning(msg),
71
+ // }
72
+
73
+ // ========== 错误码映射 ==========
74
+
75
+ const ERROR_CODE_MAP: Record<number, string> = {
76
+ 400: '请求参数错误',
77
+ 401: '登录已过期,请重新登录',
78
+ 403: '没有操作权限',
79
+ 404: '请求的资源不存在',
80
+ 500: '服务器内部错误',
81
+ 502: '网关错误',
82
+ 503: '服务暂不可用',
83
+ 504: '网关超时',
84
+ }
85
+
86
+ // ========== 错误处理 ==========
87
+
88
+ const handleRequestError = (error: any): Promise<never> => {
89
+ console.error('请求错误:', error)
90
+
91
+ if (error.code === 'ERR_NETWORK') {
92
+ showMessage.error('网络连接失败,请检查网络设置')
93
+ } else if (error.code === 'ECONNABORTED') {
94
+ showMessage.error('请求超时,请稍后重试')
95
+ }
96
+
97
+ return Promise.reject(error)
98
+ }
99
+
100
+ const handleResponseError = (error: any): Promise<never> => {
101
+ const status = error?.response?.status
102
+ const data = error?.response?.data
103
+ const message = data?.message || ERROR_CODE_MAP[status] || '请求失败,请稍后重试'
104
+
105
+ if (status === 401) {
106
+ clearToken()
107
+ showMessage.warning(message)
108
+ router.push({ name: 'login' }) // 💡 按项目调整登录路由
109
+ return Promise.reject(error)
110
+ }
111
+
112
+ showMessage.error(message)
113
+ return Promise.reject(error)
114
+ }
115
+
116
+ // ========== Axios 实例 ==========
117
+
118
+ const instance: AxiosInstance = axios.create({
119
+ baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
120
+ timeout: API_TIMEOUT,
121
+ headers: { 'Content-Type': 'application/json' },
122
+ })
123
+
124
+ // 请求拦截器
125
+ instance.interceptors.request.use(
126
+ (config: InternalAxiosRequestConfig) => {
127
+ const needToken = !NO_TOKEN_URLS.some(url => config.url?.includes(url))
128
+
129
+ if (needToken) {
130
+ const token = getToken()
131
+ if (token) {
132
+ // 💡 按后端要求调整 Token 传递方式
133
+ config.headers.Authorization = `Bearer ${token}`
134
+ // config.headers.token = token
135
+ }
136
+ }
137
+
138
+ return config
139
+ },
140
+ handleRequestError
141
+ )
142
+
143
+ // 响应拦截器
144
+ instance.interceptors.response.use(
145
+ (response: AxiosResponse) => {
146
+ const res = response.data
147
+
148
+ // 文件流直接返回
149
+ if (response.config.responseType === 'blob') {
150
+ return res
151
+ }
152
+
153
+ // 💡 业务状态码判断(按后端约定调整)
154
+ // 格式 A: { code: 0, data, message }
155
+ // 格式 B: { code: 200, data, msg }
156
+ // 格式 C: { success: true, data, message }
157
+ if (res.code === 0 || res.code === 200 || res.success === true) {
158
+ return res
159
+ }
160
+
161
+ // 401 Token 过期
162
+ if (res.code === 401) {
163
+ clearToken()
164
+ showMessage.warning(res.message || '登录已过期')
165
+ router.push({ name: 'login' })
166
+ return Promise.reject(new Error(res.message))
167
+ }
168
+
169
+ // 其他业务错误
170
+ showMessage.error(res.message || res.msg || '请求失败')
171
+ return Promise.reject(new Error(res.message || res.msg))
172
+ },
173
+ handleResponseError
174
+ )
175
+
176
+ // ========== 请求方法 ==========
177
+
178
+ export async function get<T = any>(
179
+ url: string,
180
+ params?: Record<string, any>,
181
+ config?: AxiosRequestConfig
182
+ ): Promise<ApiResponse<T>> {
183
+ return instance.get(url, { params, ...config })
184
+ }
185
+
186
+ export async function post<T = any>(
187
+ url: string,
188
+ data?: any,
189
+ config?: AxiosRequestConfig
190
+ ): Promise<ApiResponse<T>> {
191
+ return instance.post(url, data, config)
192
+ }
193
+
194
+ export async function put<T = any>(
195
+ url: string,
196
+ data?: any,
197
+ config?: AxiosRequestConfig
198
+ ): Promise<ApiResponse<T>> {
199
+ return instance.put(url, data, config)
200
+ }
201
+
202
+ export async function del<T = any>(
203
+ url: string,
204
+ params?: Record<string, any>,
205
+ config?: AxiosRequestConfig
206
+ ): Promise<ApiResponse<T>> {
207
+ return instance.delete(url, { params, ...config })
208
+ }
209
+
210
+ // ========== 工具函数 ==========
211
+
212
+ /**
213
+ * 包装异步请求,返回 [data, error] 元组
214
+ * 借鉴 Go 语言错误处理风格,避免 try/catch
215
+ *
216
+ * @example
217
+ * const [res, err] = await wrap(userApi.getList(params))
218
+ * if (err) {
219
+ * console.error('请求失败:', err)
220
+ * return
221
+ * }
222
+ * // 使用 res.data
223
+ */
224
+ export async function wrap<T>(
225
+ promise: Promise<T>
226
+ ): Promise<[T, null] | [null, Error]> {
227
+ try {
228
+ const data = await promise
229
+ return [data, null]
230
+ } catch (error) {
231
+ return [null, error as Error]
232
+ }
233
+ }
234
+
235
+ /**
236
+ * 下载文件
237
+ */
238
+ export async function downloadFile(
239
+ url: string,
240
+ params?: Record<string, any>,
241
+ filename?: string
242
+ ): Promise<void> {
243
+ const response = await instance.get(url, {
244
+ params,
245
+ responseType: 'blob',
246
+ })
247
+
248
+ const blob = new Blob([response as any])
249
+ const link = document.createElement('a')
250
+ link.href = URL.createObjectURL(blob)
251
+ link.download = filename || 'download'
252
+ link.click()
253
+ URL.revokeObjectURL(link.href)
254
+ }
255
+
256
+ /**
257
+ * 上传文件
258
+ */
259
+ export async function uploadFile<T = any>(
260
+ url: string,
261
+ file: File,
262
+ fieldName = 'file',
263
+ extraData?: Record<string, any>
264
+ ): Promise<ApiResponse<T>> {
265
+ const formData = new FormData()
266
+ formData.append(fieldName, file)
267
+
268
+ if (extraData) {
269
+ Object.entries(extraData).forEach(([key, value]) => {
270
+ formData.append(key, value)
271
+ })
272
+ }
273
+
274
+ return instance.post(url, formData, {
275
+ headers: { 'Content-Type': 'multipart/form-data' },
276
+ })
277
+ }
278
+
279
+ export default instance
@@ -0,0 +1,80 @@
1
+ /**
2
+ * API 通用类型定义
3
+ *
4
+ * 💡 按后端实际响应结构调整字段名
5
+ */
6
+
7
+ /**
8
+ * API 响应基础结构
9
+ *
10
+ * 常见格式:
11
+ * - { code: 0, data: T, message: '' }
12
+ * - { code: 200, data: T, msg: '' }
13
+ * - { success: true, data: T, message: '' }
14
+ */
15
+ export interface ApiResponse<T = any> {
16
+ code: number
17
+ data: T
18
+ message: string
19
+ // msg?: string // 备选字段名
20
+ // success?: boolean // 备选判断字段
21
+ }
22
+
23
+ /**
24
+ * 分页请求参数
25
+ *
26
+ * 常见字段名:
27
+ * - page / pageNum / current
28
+ * - pageSize / size / limit
29
+ */
30
+ export interface PageParams {
31
+ page: number
32
+ pageSize: number
33
+ }
34
+
35
+ /**
36
+ * 分页响应数据
37
+ *
38
+ * 常见字段名:
39
+ * - list / records / items / rows
40
+ * - total / totalCount / count
41
+ */
42
+ export interface PageData<T> {
43
+ list: T[]
44
+ total: number
45
+ page: number
46
+ pageSize: number
47
+ }
48
+
49
+ /**
50
+ * 分页响应(完整)
51
+ */
52
+ export type PageResponse<T> = ApiResponse<PageData<T>>
53
+
54
+ /**
55
+ * 通用 ID 类型
56
+ */
57
+ export type ID = string | number
58
+
59
+ /**
60
+ * 通用状态枚举
61
+ */
62
+ export type CommonStatus = 'active' | 'inactive' | 'pending' | 'deleted'
63
+
64
+ /**
65
+ * 排序参数
66
+ */
67
+ export interface SortParams {
68
+ sortField?: string
69
+ sortOrder?: 'asc' | 'desc' | 'ascend' | 'descend'
70
+ }
71
+
72
+ /**
73
+ * 时间范围参数
74
+ */
75
+ export interface DateRangeParams {
76
+ startDate?: string
77
+ endDate?: string
78
+ startTime?: string
79
+ endTime?: string
80
+ }