vue2server7 7.0.118 → 7.0.119

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.
Files changed (62) hide show
  1. package/package.json +1 -1
  2. package/test/mini2.0-main/.editorconfig +8 -0
  3. package/test/mini2.0-main/.env.development +3 -0
  4. package/test/mini2.0-main/.env.production +3 -0
  5. package/test/mini2.0-main/.env.test +3 -0
  6. package/test/mini2.0-main/.gitattributes +1 -0
  7. package/test/mini2.0-main/.oxlintrc.json +10 -0
  8. package/test/mini2.0-main/.prettierrc.json +6 -0
  9. package/test/mini2.0-main/README.md +179 -0
  10. package/test/mini2.0-main/auto-imports.d.ts +629 -0
  11. package/test/mini2.0-main/components.d.ts +21 -0
  12. package/test/mini2.0-main/docs/MX_API.md +244 -0
  13. package/test/mini2.0-main/docs/REQUEST.md +217 -0
  14. package/test/mini2.0-main/docs/package-json-guide.md +132 -0
  15. package/test/mini2.0-main/env.d.ts +12 -0
  16. package/test/mini2.0-main/eslint.config.ts +26 -0
  17. package/test/mini2.0-main/index.html +16 -0
  18. package/test/mini2.0-main/package-lock.json +6421 -0
  19. package/test/mini2.0-main/package.json +64 -0
  20. package/test/mini2.0-main/plugins/bump-version.ts +50 -0
  21. package/test/mini2.0-main/postcss.config.ts +15 -0
  22. package/test/mini2.0-main/public/favicon.ico +0 -0
  23. package/test/mini2.0-main/public/images/12a73787-86a9-4891-a65f-66104746f6a8.png +0 -0
  24. package/test/mini2.0-main/public/images/5798d7aa-ba8b-4605-8079-58b35495ac55.png +0 -0
  25. package/test/mini2.0-main/public/images/73fef1e4-0fd0-4a1a-9b8b-a70a5b6acbbc.png +0 -0
  26. package/test/mini2.0-main/public/images/bc685b4c-0cca-4a79-924c-a8ee10e6f8eb.png +0 -0
  27. package/test/mini2.0-main/public/images/c3dbbd9d-be56-490e-b9f4-6ee17ebefffc.png +0 -0
  28. package/test/mini2.0-main/public/images/ea745a10-42aa-4f44-8d7f-3ab02cc0adcd.png +0 -0
  29. package/test/mini2.0-main/public/images/f5876785-b927-4347-ba19-999114240649.png +0 -0
  30. package/test/mini2.0-main/public/images/img.png +0 -0
  31. package/test/mini2.0-main/src/App.vue +11 -0
  32. package/test/mini2.0-main/src/api/user.ts +23 -0
  33. package/test/mini2.0-main/src/auto-imports.d.ts +639 -0
  34. package/test/mini2.0-main/src/components.d.ts +23 -0
  35. package/test/mini2.0-main/src/config/config.properties +3 -0
  36. package/test/mini2.0-main/src/config/env.ts +6 -0
  37. package/test/mini2.0-main/src/config/plugin.properties.pro +6 -0
  38. package/test/mini2.0-main/src/config/plugin.properties.test +6 -0
  39. package/test/mini2.0-main/src/core/mxApi/index.ts +237 -0
  40. package/test/mini2.0-main/src/core/request/index.ts +129 -0
  41. package/test/mini2.0-main/src/main.ts +21 -0
  42. package/test/mini2.0-main/src/router/index.ts +70 -0
  43. package/test/mini2.0-main/src/stores/counter.ts +12 -0
  44. package/test/mini2.0-main/src/stores/user.ts +48 -0
  45. package/test/mini2.0-main/src/types/api.d.ts +14 -0
  46. package/test/mini2.0-main/src/types/nprogress.d.ts +8 -0
  47. package/test/mini2.0-main/src/utils/request.ts +159 -0
  48. package/test/mini2.0-main/src/views/clearing-detail/index.vue +49 -0
  49. package/test/mini2.0-main/src/views/foreign-position/index.vue +49 -0
  50. package/test/mini2.0-main/src/views/home/index.vue +201 -0
  51. package/test/mini2.0-main/src/views/login/index.vue +166 -0
  52. package/test/mini2.0-main/src/views/net-debit/index.vue +49 -0
  53. package/test/mini2.0-main/src/views/pbc-position/index.vue +49 -0
  54. package/test/mini2.0-main/src/views/position-estimate/index.vue +49 -0
  55. package/test/mini2.0-main/src/views/rmb-position/index.vue +49 -0
  56. package/test/mini2.0-main/src/views/warning/index.vue +49 -0
  57. package/test/mini2.0-main/tsconfig.app.json +18 -0
  58. package/test/mini2.0-main/tsconfig.json +11 -0
  59. package/test/mini2.0-main/tsconfig.node.json +28 -0
  60. package/test/mini2.0-main/vite.config.ts +68 -0
  61. package/test/b137a0ec17d13d2093a89a18eb819e89.png +0 -0
  62. package/test/mini2.0-main (2).zip +0 -0
@@ -0,0 +1,23 @@
1
+ /* eslint-disable */
2
+ // @ts-nocheck
3
+ // biome-ignore lint: disable
4
+ // oxlint-disable
5
+ // ------
6
+ // Generated by unplugin-vue-components
7
+ // Read more: https://github.com/vuejs/core/pull/3399
8
+
9
+ export {}
10
+
11
+ /* prettier-ignore */
12
+ declare module 'vue' {
13
+ export interface GlobalComponents {
14
+ RouterLink: typeof import('vue-router')['RouterLink']
15
+ RouterView: typeof import('vue-router')['RouterView']
16
+ VanButton: typeof import('vant/es')['Button']
17
+ VanCellGroup: typeof import('vant/es')['CellGroup']
18
+ VanField: typeof import('vant/es')['Field']
19
+ VanForm: typeof import('vant/es')['Form']
20
+ VanIcon: typeof import('vant/es')['Icon']
21
+ VanLoading: typeof import('vant/es')['Loading']
22
+ }
23
+ }
@@ -0,0 +1,3 @@
1
+ hideWebViewTitle=false;
2
+ hideOptionMenu=true;
3
+ hideToolbar=true;
@@ -0,0 +1,6 @@
1
+ export const appEnv = import.meta.env.VITE_APP_ENV
2
+
3
+ export const apiConfig = {
4
+ baseURL: import.meta.env.VITE_API_BASE_URL,
5
+ timeout: Number(import.meta.env.VITE_API_TIMEOUT) || 10000,
6
+ }
@@ -0,0 +1,6 @@
1
+ app_id=vue_demo;
2
+ version_code=315015;
3
+ version_name=3.15.015;
4
+ type=html5;
5
+ frame=vue;
6
+ platform=[mac,win,ios,android];
@@ -0,0 +1,6 @@
1
+ app_id=vue_demo;
2
+ version_code=315018;
3
+ version_name=3.15.018;
4
+ type=html5;
5
+ frame=vue;
6
+ platform=[mac,win,ios,android];
@@ -0,0 +1,237 @@
1
+ /**
2
+ * MX 原生桥接 API 模块
3
+ *
4
+ * 用于在敏行混合应用中与原生 Android/iOS 通信
5
+ * 提供原生能力调用:UI 控制、用户信息、选人组件、原生 HTTP 请求
6
+ */
7
+
8
+ // ============================================================
9
+ // 类型定义
10
+ // ============================================================
11
+
12
+ /** 原生 AJAX 请求参数 */
13
+ interface MXAjaxParams {
14
+ type: 'GET' | 'POST' | 'PUT' | 'DELETE'
15
+ url: string
16
+ data?: unknown
17
+ async?: boolean
18
+ success?: (data: string, status: number, xhr: unknown) => void
19
+ error?: (data: unknown, status: number, xhr: unknown) => void
20
+ }
21
+
22
+ /** 原生 AJAX 响应 */
23
+ export interface MXAjaxResponse<T = unknown> {
24
+ data: T
25
+ status: number
26
+ }
27
+
28
+ /** 用户信息 */
29
+ export interface MXUser {
30
+ id: string
31
+ name: string
32
+ token: string
33
+ [key: string]: unknown
34
+ }
35
+
36
+ /** 选人组件配置 */
37
+ export interface MXSelectUsersOptions {
38
+ enableSelectDept?: boolean
39
+ canSelectSelf?: boolean
40
+ }
41
+
42
+ /** MXApi 回调函数集合 */
43
+ interface MXApiCallbacks {
44
+ ready?: () => void
45
+ error?: (message: string, namespace: string, api: string) => void
46
+ beforeApply?: (namespace: string, api: string, args: unknown[]) => void
47
+ }
48
+
49
+ /** 原生接口命名空间 */
50
+ type MXNamespace = 'MXCommon' | 'MXWebui' | 'MXContacts'
51
+
52
+ // ============================================================
53
+ // 声明全局原生接口
54
+ // ============================================================
55
+
56
+ declare global {
57
+ interface Window {
58
+ MXCommon?: {
59
+ getCurrentUser: (callback: (user: MXUser) => void) => void
60
+ getEncryptString: (callback: (secret: string) => void) => void
61
+ ajax: (params: MXAjaxParams) => void
62
+ }
63
+ MXWebui?: {
64
+ hideWebViewTitle: () => void
65
+ showOptionMenu: () => void
66
+ setCustomHeaderMenu: (...args: unknown[]) => void
67
+ }
68
+ MXContacts?: {
69
+ selectUsers: (
70
+ callback: (users: MXUser[]) => void,
71
+ options: MXSelectUsersOptions
72
+ ) => void
73
+ }
74
+ }
75
+ }
76
+
77
+ // ============================================================
78
+ // 核心实现
79
+ // ============================================================
80
+
81
+ /**
82
+ * MXApi 工厂函数
83
+ *
84
+ * 创建原生 API 调用器,处理设备就绪状态和任务队列。
85
+ * 在 Cordova/Capacitor 环境中,原生接口在 deviceready 事件触发后才可用。
86
+ */
87
+ function MXApi(callbacks: MXApiCallbacks) {
88
+ let deviceReady = false
89
+ const taskQueue: Array<[MXNamespace, string, unknown[]]> = []
90
+
91
+ document.addEventListener('deviceready', function deviceReadyHandler() {
92
+ deviceReady = true
93
+
94
+ // 执行队列中的所有待处理任务
95
+ taskQueue.forEach((task) => {
96
+ applyApi(...task)
97
+ })
98
+
99
+ callbacks.ready?.()
100
+ document.removeEventListener('deviceready', deviceReadyHandler, false)
101
+ }, false)
102
+
103
+ /**
104
+ * 核心函数:调用原生 API
105
+ *
106
+ * 通过 window[namespace][api] 的方式访问原生注入的方法
107
+ */
108
+ function applyApi(namespace: MXNamespace, api: string, args: unknown[]) {
109
+ const nativeInterface = window[namespace] as Record<string, ((...args: unknown[]) => void) | undefined> | undefined
110
+
111
+ if (nativeInterface && typeof nativeInterface[api] === 'function') {
112
+ callbacks.beforeApply?.(namespace, api, args)
113
+ nativeInterface[api]!(...args)
114
+ } else if (!deviceReady) {
115
+ // 设备未就绪,加入队列等待
116
+ taskQueue.push([namespace, api, args])
117
+ } else {
118
+ const errorMsg = `该终端没有 ${namespace}.${api} 方法!`
119
+ callbacks.error?.(errorMsg, namespace, api)
120
+ throw new Error(errorMsg)
121
+ }
122
+ }
123
+
124
+ return applyApi
125
+ }
126
+
127
+ // 创建全局调用器实例
128
+ const applyApi = MXApi({
129
+ ready() {
130
+ console.log('[MX] 设备就绪')
131
+ },
132
+ error(err) {
133
+ console.error('[MX] 错误:', err)
134
+ },
135
+ beforeApply(namespace, api, args) {
136
+ console.debug(`[MX] 调用 ${namespace}.${api}`, args)
137
+ },
138
+ })
139
+
140
+ // 创建命名空间调用器(柯里化)
141
+ const makeApi =
142
+ (namespace: MXNamespace) =>
143
+ (api: string, ...args: unknown[]) =>
144
+ applyApi(namespace, api, args)
145
+
146
+ const MXCommon = makeApi('MXCommon')
147
+ const MXWebui = makeApi('MXWebui')
148
+ const MXContacts = makeApi('MXContacts')
149
+
150
+ // ============================================================
151
+ // 导出的业务 API
152
+ // ============================================================
153
+
154
+ /** 隐藏 WebView 标题栏 */
155
+ export const hideWebViewTitle = (): void => MXWebui('hideWebViewTitle')
156
+
157
+ /** 显示右上角菜单按钮 */
158
+ export const showOptionMenu = (): void => MXWebui('showOptionMenu')
159
+
160
+ /** 设置自定义头部菜单 */
161
+ export const setCustomHeaderMenu = (...args: unknown[]): void =>
162
+ MXWebui('setCustomHeaderMenu', ...args)
163
+
164
+ /** 获取当前登录用户信息 */
165
+ export const getCurrentUser = (): Promise<MXUser> =>
166
+ new Promise((resolve) => {
167
+ MXCommon('getCurrentUser', resolve)
168
+ })
169
+
170
+ /** 从原生客户端获取加密密钥 */
171
+ export const getEncryptString = (): Promise<string> =>
172
+ new Promise((resolve) => {
173
+ MXCommon('getEncryptString', resolve)
174
+ })
175
+
176
+ /** 打开原生选人组件 */
177
+ export const MXSelectUsers = (
178
+ options: MXSelectUsersOptions = { enableSelectDept: false, canSelectSelf: true }
179
+ ): Promise<MXUser[]> =>
180
+ new Promise((resolve) => {
181
+ MXContacts('selectUsers', (result: MXUser[]) => {
182
+ resolve(result)
183
+ }, options)
184
+ })
185
+
186
+ /**
187
+ * 原生 AJAX 请求
188
+ *
189
+ * 使用原生应用的 HTTP 客户端发起请求,绕过浏览器同源策略限制。
190
+ */
191
+ export const ajax = <T = unknown>(params: Omit<MXAjaxParams, 'success' | 'error'>): Promise<MXAjaxResponse<T>> =>
192
+ new Promise((resolve, reject) => {
193
+ const requestParams: MXAjaxParams = {
194
+ ...params,
195
+ url: `${import.meta.env.VITE_API_BASE_URL || ''}${params.url}`,
196
+ async: true,
197
+ success(data, status) {
198
+ resolve({ data: JSON.parse(data) as T, status })
199
+ },
200
+ error(data, status) {
201
+ reject({ data, status })
202
+ },
203
+ }
204
+
205
+ MXCommon('ajax', requestParams)
206
+ })
207
+
208
+ /** 原生 GET 请求 */
209
+ export const ajaxGet = <T = unknown>(url: string, query?: Record<string, unknown>): Promise<MXAjaxResponse<T>> => {
210
+ const queryString = query
211
+ ? '?' + Object.entries(query)
212
+ .filter(([, value]) => value !== undefined && value !== null)
213
+ .map(([key, value]) => `${key}=${value}`)
214
+ .join('&')
215
+ : ''
216
+
217
+ return ajax<T>({
218
+ type: 'GET',
219
+ url: `${url}${queryString}`,
220
+ })
221
+ }
222
+
223
+ /** 原生 POST 请求 */
224
+ export const ajaxPost = <T = unknown>(url: string, data?: unknown): Promise<MXAjaxResponse<T>> =>
225
+ ajax<T>({ type: 'POST', url, data })
226
+
227
+ /** 原生 PUT 请求 */
228
+ export const ajaxPut = <T = unknown>(url: string, data?: unknown): Promise<MXAjaxResponse<T>> =>
229
+ ajax<T>({ type: 'PUT', url, data })
230
+
231
+ /** 原生 DELETE 请求 */
232
+ export const ajaxDelete = <T = unknown>(url: string, id: string): Promise<MXAjaxResponse<T>> =>
233
+ ajax<T>({ type: 'DELETE', url: `${url}/${id}` })
234
+
235
+ /** 检测是否在原生环境 */
236
+ export const isNativeApp = (): boolean =>
237
+ typeof window.MXCommon !== 'undefined'
@@ -0,0 +1,129 @@
1
+ /**
2
+ * 统一请求中转层
3
+ *
4
+ * 接口与 src/utils/request.ts 的 request 函数完全一致
5
+ * 根据环境自动选择 axios 或原生 AJAX
6
+ */
7
+
8
+ import { isNativeApp, ajaxGet, ajaxPost, ajaxPut, ajaxDelete } from '@/core/mxApi'
9
+ import type { MXAjaxResponse } from '@/core/mxApi'
10
+ import { request as axiosRequest } from '@/utils/request'
11
+ import type { ApiResponse } from '@/types/api'
12
+
13
+ // ============================================================
14
+ // Token 管理
15
+ // ============================================================
16
+
17
+ const TOKEN_KEY = 'token'
18
+
19
+ export const setToken = (token: string) => localStorage.setItem(TOKEN_KEY, token)
20
+ export const getToken = () => localStorage.getItem(TOKEN_KEY)
21
+ export const clearToken = () => localStorage.removeItem(TOKEN_KEY)
22
+
23
+ /**
24
+ * 获取公共请求头
25
+ */
26
+ export function getCommonHeaders(): Record<string, string> {
27
+ const headers: Record<string, string> = {
28
+ 'Content-Type': 'application/json',
29
+ }
30
+
31
+ const token = getToken()
32
+ if (token) {
33
+ headers['Authorization'] = `Bearer ${token}`
34
+ }
35
+
36
+ return headers
37
+ }
38
+
39
+ // ============================================================
40
+ // 请求配置接口(与 request.ts 保持一致)
41
+ // ============================================================
42
+
43
+ export interface RequestConfig<T = unknown> {
44
+ url: string
45
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
46
+ data?: T
47
+ params?: Record<string, unknown>
48
+ headers?: Record<string, string>
49
+ auth?: { username: string; password: string } // HTTP Basic Auth
50
+ }
51
+
52
+ // ============================================================
53
+ // 核心中转函数
54
+ // ============================================================
55
+
56
+ /**
57
+ * 统一请求中转
58
+ *
59
+ * 接口与 request.ts 的 request 函数完全一致
60
+ * 调用方无需关心底层使用的是 axios 还是原生 AJAX
61
+ *
62
+ * @example
63
+ * // 与 request.ts 用法完全一致
64
+ * const res = await request<UserInfo>({ url: '/user/1' })
65
+ * const res = await request<{ token: string }, LoginParams>({
66
+ * url: '/login',
67
+ * method: 'POST',
68
+ * data: { username: 'admin', password: '123' }
69
+ * })
70
+ */
71
+ export async function request<R = unknown, T = unknown>(
72
+ config: RequestConfig<T>
73
+ ): Promise<ApiResponse<R>> {
74
+ const { url, method = 'GET', data, params, headers: customHeaders, auth } = config
75
+
76
+ // 合并公共请求头和自定义请求头
77
+ const headers = {
78
+ ...getCommonHeaders(),
79
+ ...customHeaders,
80
+ }
81
+
82
+
83
+ if (isNativeApp()) {
84
+ return await nativeRequest<R, T>({ url, method, data, params, headers })
85
+ } else {
86
+ // 浏览器环境:axios 原生支持 auth 字段
87
+ return await axiosRequest<R, T>({ url, method, data, params, headers, auth })
88
+ }
89
+ }
90
+
91
+ // ============================================================
92
+ // 原生请求实现
93
+ // ============================================================
94
+
95
+ /**
96
+ * 原生 AJAX 请求
97
+ */
98
+ async function nativeRequest<R, T>(
99
+ config: RequestConfig<T>
100
+ ): Promise<ApiResponse<R>> {
101
+ const { url, method, data, params } = config
102
+
103
+ let response: MXAjaxResponse<unknown>
104
+
105
+ switch (method) {
106
+ case 'GET':
107
+ response = await ajaxGet<R>(url, params)
108
+ break
109
+ case 'POST':
110
+ response = await ajaxPost<R>(url, data)
111
+ break
112
+ case 'PUT':
113
+ response = await ajaxPut<R>(url, data)
114
+ break
115
+ case 'DELETE':
116
+ const id = params?.id as string
117
+ response = await ajaxDelete<R>(url, id)
118
+ break
119
+ default:
120
+ throw new Error(`不支持的请求方法: ${method}`)
121
+ }
122
+
123
+ // 包装成与 axios 拦截器一致的响应格式
124
+ return {
125
+ code: 0,
126
+ message: 'success',
127
+ data: response.data as R,
128
+ } as ApiResponse<R>
129
+ }
@@ -0,0 +1,21 @@
1
+ import { createApp } from 'vue'
2
+ import { createPinia } from 'pinia'
3
+ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
4
+ import 'vant/lib/index.css' // Vant 基础样式,必须引入否则组件无样式
5
+
6
+ import App from './App.vue'
7
+ import router from './router'
8
+
9
+ if (import.meta.env.VITE_APP_ENV !== 'production') {
10
+ import('vconsole').then(({ default: VConsole }) => new VConsole())
11
+ }
12
+
13
+ const app = createApp(App)
14
+ const pinia = createPinia()
15
+
16
+ pinia.use(piniaPluginPersistedstate)
17
+
18
+ app.use(pinia)
19
+ app.use(router)
20
+
21
+ app.mount('#app')
@@ -0,0 +1,70 @@
1
+ import { createRouter, createWebHistory } from 'vue-router'
2
+ import { useUserStore } from '@/stores/user'
3
+
4
+ const router = createRouter({
5
+ history: createWebHistory(import.meta.env.BASE_URL),
6
+ routes: [
7
+ {
8
+ path: '/',
9
+ name: 'Home',
10
+ component: () => import('@/views/home/index.vue'),
11
+ meta: { requiresAuth: true },
12
+ },
13
+ {
14
+ path: '/login',
15
+ name: 'Login',
16
+ component: () => import('@/views/login/index.vue'),
17
+ },
18
+ {
19
+ path: '/rmb-position',
20
+ name: 'RmbPosition',
21
+ component: () => import('@/views/rmb-position/index.vue'),
22
+ meta: { requiresAuth: true },
23
+ },
24
+ {
25
+ path: '/foreign-position',
26
+ name: 'ForeignPosition',
27
+ component: () => import('@/views/foreign-position/index.vue'),
28
+ meta: { requiresAuth: true },
29
+ },
30
+ {
31
+ path: '/pbc-position',
32
+ name: 'PbcPosition',
33
+ component: () => import('@/views/pbc-position/index.vue'),
34
+ meta: { requiresAuth: true },
35
+ },
36
+ {
37
+ path: '/position-estimate',
38
+ name: 'PositionEstimate',
39
+ component: () => import('@/views/position-estimate/index.vue'),
40
+ meta: { requiresAuth: true },
41
+ },
42
+ {
43
+ path: '/net-debit',
44
+ name: 'NetDebit',
45
+ component: () => import('@/views/net-debit/index.vue'),
46
+ meta: { requiresAuth: true },
47
+ },
48
+ {
49
+ path: '/clearing-detail',
50
+ name: 'ClearingDetail',
51
+ component: () => import('@/views/clearing-detail/index.vue'),
52
+ meta: { requiresAuth: true },
53
+ },
54
+ {
55
+ path: '/warning',
56
+ name: 'Warning',
57
+ component: () => import('@/views/warning/index.vue'),
58
+ meta: { requiresAuth: true },
59
+ },
60
+ ],
61
+ })
62
+
63
+ router.beforeEach((to) => {
64
+ const userStore = useUserStore()
65
+ if (to.meta.requiresAuth && !userStore.token) {
66
+ return { name: 'Login' }
67
+ }
68
+ })
69
+
70
+ export default router
@@ -0,0 +1,12 @@
1
+ import { ref, computed } from 'vue'
2
+ import { defineStore } from 'pinia'
3
+
4
+ export const useCounterStore = defineStore('counter', () => {
5
+ const count = ref(0)
6
+ const doubleCount = computed(() => count.value * 2)
7
+ function increment() {
8
+ count.value++
9
+ }
10
+
11
+ return { count, doubleCount, increment }
12
+ })
@@ -0,0 +1,48 @@
1
+ import { defineStore } from 'pinia'
2
+
3
+ /**
4
+ * 用户状态 Store
5
+ *
6
+ * 使用 Composition API 风格(setup 语法)定义,通过 pinia-plugin-persistedstate
7
+ * 自动将 state 持久化到 localStorage,刷新页面后状态不会丢失。
8
+ */
9
+ export const useUserStore = defineStore(
10
+ 'user',
11
+
12
+ () => {
13
+ // -------------------------------- State --------------------------------
14
+
15
+ /** 登录凭证,登录成功后由后端返回,后续请求通过请求头携带 */
16
+ const token = ref('')
17
+
18
+ // ------------------------------ Actions --------------------------------
19
+
20
+ /**
21
+ * 设置 token
22
+ * 登录成功后调用,触发 persist 插件自动写入 localStorage
23
+ */
24
+ function setToken(value: string) {
25
+ token.value = value
26
+ }
27
+
28
+ /**
29
+ * 清空 token
30
+ * 退出登录时调用,触发 persist 插件自动清除 localStorage 对应条目
31
+ */
32
+ function clearToken() {
33
+ token.value = ''
34
+ }
35
+
36
+ // ----------------------------- Return ----------------------------------
37
+
38
+ return { token, setToken, clearToken }
39
+ },
40
+
41
+ /**
42
+ * 持久化配置
43
+ * true = 全量持久化(state 中所有字段自动写入/恢复 localStorage)
44
+ * 如需精细控制,可替换为对象形式:
45
+ * persist: { key: 'user', storage: localStorage, paths: ['token'] }
46
+ */
47
+ { persist: true },
48
+ )
@@ -0,0 +1,14 @@
1
+ /** 后端统一响应格式 */
2
+ export interface ApiResponse<T = unknown> {
3
+ code: number
4
+ message: string
5
+ data: T
6
+ }
7
+
8
+ /** 分页响应 */
9
+ export interface PaginatedData<T> {
10
+ list: T[]
11
+ total: number
12
+ page: number
13
+ pageSize: number
14
+ }
@@ -0,0 +1,8 @@
1
+ declare module 'nprogress' {
2
+ const NProgress: {
3
+ configure(options: { showSpinner?: boolean }): void
4
+ start(): void
5
+ done(): void
6
+ }
7
+ export default NProgress
8
+ }