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.
- package/package.json +1 -1
- package/test/mini2.0-main/.editorconfig +8 -0
- package/test/mini2.0-main/.env.development +3 -0
- package/test/mini2.0-main/.env.production +3 -0
- package/test/mini2.0-main/.env.test +3 -0
- package/test/mini2.0-main/.gitattributes +1 -0
- package/test/mini2.0-main/.oxlintrc.json +10 -0
- package/test/mini2.0-main/.prettierrc.json +6 -0
- package/test/mini2.0-main/README.md +179 -0
- package/test/mini2.0-main/auto-imports.d.ts +629 -0
- package/test/mini2.0-main/components.d.ts +21 -0
- package/test/mini2.0-main/docs/MX_API.md +244 -0
- package/test/mini2.0-main/docs/REQUEST.md +217 -0
- package/test/mini2.0-main/docs/package-json-guide.md +132 -0
- package/test/mini2.0-main/env.d.ts +12 -0
- package/test/mini2.0-main/eslint.config.ts +26 -0
- package/test/mini2.0-main/index.html +16 -0
- package/test/mini2.0-main/package-lock.json +6421 -0
- package/test/mini2.0-main/package.json +64 -0
- package/test/mini2.0-main/plugins/bump-version.ts +50 -0
- package/test/mini2.0-main/postcss.config.ts +15 -0
- package/test/mini2.0-main/public/favicon.ico +0 -0
- package/test/mini2.0-main/public/images/12a73787-86a9-4891-a65f-66104746f6a8.png +0 -0
- package/test/mini2.0-main/public/images/5798d7aa-ba8b-4605-8079-58b35495ac55.png +0 -0
- package/test/mini2.0-main/public/images/73fef1e4-0fd0-4a1a-9b8b-a70a5b6acbbc.png +0 -0
- package/test/mini2.0-main/public/images/bc685b4c-0cca-4a79-924c-a8ee10e6f8eb.png +0 -0
- package/test/mini2.0-main/public/images/c3dbbd9d-be56-490e-b9f4-6ee17ebefffc.png +0 -0
- package/test/mini2.0-main/public/images/ea745a10-42aa-4f44-8d7f-3ab02cc0adcd.png +0 -0
- package/test/mini2.0-main/public/images/f5876785-b927-4347-ba19-999114240649.png +0 -0
- package/test/mini2.0-main/public/images/img.png +0 -0
- package/test/mini2.0-main/src/App.vue +11 -0
- package/test/mini2.0-main/src/api/user.ts +23 -0
- package/test/mini2.0-main/src/auto-imports.d.ts +639 -0
- package/test/mini2.0-main/src/components.d.ts +23 -0
- package/test/mini2.0-main/src/config/config.properties +3 -0
- package/test/mini2.0-main/src/config/env.ts +6 -0
- package/test/mini2.0-main/src/config/plugin.properties.pro +6 -0
- package/test/mini2.0-main/src/config/plugin.properties.test +6 -0
- package/test/mini2.0-main/src/core/mxApi/index.ts +237 -0
- package/test/mini2.0-main/src/core/request/index.ts +129 -0
- package/test/mini2.0-main/src/main.ts +21 -0
- package/test/mini2.0-main/src/router/index.ts +70 -0
- package/test/mini2.0-main/src/stores/counter.ts +12 -0
- package/test/mini2.0-main/src/stores/user.ts +48 -0
- package/test/mini2.0-main/src/types/api.d.ts +14 -0
- package/test/mini2.0-main/src/types/nprogress.d.ts +8 -0
- package/test/mini2.0-main/src/utils/request.ts +159 -0
- package/test/mini2.0-main/src/views/clearing-detail/index.vue +49 -0
- package/test/mini2.0-main/src/views/foreign-position/index.vue +49 -0
- package/test/mini2.0-main/src/views/home/index.vue +201 -0
- package/test/mini2.0-main/src/views/login/index.vue +166 -0
- package/test/mini2.0-main/src/views/net-debit/index.vue +49 -0
- package/test/mini2.0-main/src/views/pbc-position/index.vue +49 -0
- package/test/mini2.0-main/src/views/position-estimate/index.vue +49 -0
- package/test/mini2.0-main/src/views/rmb-position/index.vue +49 -0
- package/test/mini2.0-main/src/views/warning/index.vue +49 -0
- package/test/mini2.0-main/tsconfig.app.json +18 -0
- package/test/mini2.0-main/tsconfig.json +11 -0
- package/test/mini2.0-main/tsconfig.node.json +28 -0
- package/test/mini2.0-main/vite.config.ts +68 -0
- package/test/b137a0ec17d13d2093a89a18eb819e89.png +0 -0
- 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,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
|
+
)
|