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,159 @@
1
+ import axios from 'axios'
2
+ import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from 'axios'
3
+ import { showToast } from 'vant'
4
+ import NProgress from 'nprogress'
5
+ import 'nprogress/nprogress.css'
6
+ import { apiConfig } from '@/config/env'
7
+ import type { ApiResponse } from '@/types/api'
8
+ import router from '@/router'
9
+
10
+ // 关闭 NProgress 右侧旋转小圆圈,保持进度条简洁
11
+ NProgress.configure({ showSpinner: false })
12
+
13
+ // localStorage 中存储 token 的 key,与登录/登出逻辑保持一致
14
+ const TOKEN_KEY = 'token'
15
+
16
+ // 创建 axios 实例,baseURL 和 timeout 从环境变量配置中读取
17
+ const service: AxiosInstance = axios.create({
18
+ baseURL: apiConfig.baseURL, // 接口基础地址,由 .env 文件中的 VITE_API_BASE_URL 决定
19
+ timeout: apiConfig.timeout, // 请求超时时间(毫秒),默认 10000
20
+ })
21
+
22
+ /**
23
+ * 请求拦截器
24
+ * 在每个请求发出前执行:
25
+ * 1. 启动顶部进度条
26
+ * 2. 自动携带 JWT token 到请求头
27
+ */
28
+ service.interceptors.request.use(
29
+ (config: InternalAxiosRequestConfig) => {
30
+ // 开始加载进度条
31
+ NProgress.start()
32
+
33
+ // 从本地存储读取 token,存在则添加到请求头
34
+ const token = localStorage.getItem(TOKEN_KEY)
35
+ if (token) {
36
+ config.headers.Authorization = `Bearer ${token}`
37
+ }
38
+
39
+ return config
40
+ },
41
+ // 请求配置出错时(如网络断开),结束进度条并抛出错误
42
+ (error) => {
43
+ NProgress.done()
44
+ return Promise.reject(error)
45
+ },
46
+ )
47
+
48
+ /**
49
+ * 响应拦截器
50
+ * 在收到响应后执行:
51
+ * 1. 结束进度条
52
+ * 2. 判断后端业务 code,非 0 视为业务失败
53
+ * 3. HTTP 状态码异常时给出中文提示
54
+ * 4. 401 统一清除 token 并跳转登录页
55
+ */
56
+ service.interceptors.response.use(
57
+ // ——— 成功响应(HTTP 2xx)———
58
+ (response: AxiosResponse<ApiResponse>) => {
59
+ NProgress.done()
60
+
61
+ // 后端返回的数据结构:{ code, message, data }
62
+ const res = response.data
63
+
64
+ // 业务层错误:后端返回了 HTTP 200,但 code 不为 0,表示业务处理失败
65
+ if (res.code !== 0) {
66
+ showToast(res.message || '请求失败')
67
+
68
+ // token 过期或无效,清除本地 token 并跳转登录页
69
+ if (res.code === 401) {
70
+ localStorage.removeItem(TOKEN_KEY)
71
+ router.push('/login')
72
+ }
73
+
74
+ // 将业务错误抛出,调用方可通过 catch 捕获
75
+ return Promise.reject(new Error(res.message || '请求失败'))
76
+ }
77
+
78
+ // 业务成功,直接返回 data 字段,调用方无需再解包 response.data.data
79
+ return res as unknown as AxiosResponse
80
+ },
81
+
82
+ // ——— 失败响应(HTTP 非 2xx 或网络错误)———
83
+ (error) => {
84
+ NProgress.done()
85
+
86
+ // HTTP 状态码 → 中文提示映射表
87
+ const statusCodeMap: Record<number, string> = {
88
+ 400: '请求参数错误',
89
+ 401: '未授权,请重新登录',
90
+ 403: '拒绝访问',
91
+ 404: '请求资源不存在',
92
+ 500: '服务器内部错误',
93
+ }
94
+
95
+ // 优先取映射表中的提示,没有则显示状态码;无 response 说明是网络异常
96
+ const status = error.response?.status as number
97
+ const message = error.response
98
+ ? statusCodeMap[status] || `连接错误 ${status}`
99
+ : '网络连接异常'
100
+
101
+ showToast(message)
102
+
103
+ // 401 未授权:清除 token 并跳转登录页
104
+ if (error.response?.status === 401) {
105
+ localStorage.removeItem(TOKEN_KEY)
106
+ router.push('/login')
107
+ }
108
+
109
+ return Promise.reject(error)
110
+ },
111
+ )
112
+
113
+ /**
114
+ * 请求配置接口
115
+ * @property url - 请求地址(必填)
116
+ * @property method - 请求方法,默认 GET
117
+ * @property data - 请求体(POST/PUT/PATCH 时使用)
118
+ * @property params - URL 查询参数(拼接到 ?key=value)
119
+ */
120
+ export interface RequestConfig<T = unknown> {
121
+ url: string
122
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
123
+ data?: T
124
+ params?: Record<string, unknown>
125
+ headers?: Record<string, string>
126
+ auth?: { username: string; password: string } // HTTP Basic Auth
127
+ }
128
+
129
+ /**
130
+ * 通用请求函数
131
+ * @typeParam R - 响应 data 的类型(后端返回的 data 字段类型)
132
+ * @typeParam T - 请求参数的类型(data 的类型)
133
+ * @param config - 请求配置对象
134
+ * @returns Promise,resolve 后直接拿到 ApiResponse<R>
135
+ *
136
+ * @example
137
+ * // GET 请求
138
+ * request<UserInfo>({ url: '/user/1' })
139
+ *
140
+ * // POST 请求
141
+ * request<{ token: string }, LoginParams>({
142
+ * url: '/login',
143
+ * method: 'POST',
144
+ * data: { username: 'admin', password: '123' }
145
+ * })
146
+ */
147
+ export function request<R = unknown, T = unknown>(config: RequestConfig<T>): Promise<ApiResponse<R>> {
148
+ return service.request<ApiResponse<R>>({
149
+ url: config.url,
150
+ method: config.method || 'GET',
151
+ data: config.data,
152
+ params: config.params,
153
+ headers: config.headers,
154
+ auth: config.auth,
155
+ }) as unknown as Promise<ApiResponse<R>>
156
+ }
157
+
158
+ // 同时导出 axios 实例,供需要直接使用 axios 原生方法的场景(如文件上传)
159
+ export default service
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts"></script>
2
+
3
+ <template>
4
+ <main class="page">
5
+ <header class="page-header">
6
+ <button class="back-btn" type="button" @click="$router.back()">←</button>
7
+ <h1>人民币小额网银清算场次明细</h1>
8
+ </header>
9
+ <section class="page-body">
10
+ <p class="placeholder">页面建设中…</p>
11
+ </section>
12
+ </main>
13
+ </template>
14
+
15
+ <style scoped>
16
+ .page {
17
+ max-width: 750px;
18
+ min-height: 100vh;
19
+ margin: 0 auto;
20
+ padding: 0 11px;
21
+ background: #f7f8fa;
22
+ }
23
+ .page-header {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 8px;
27
+ height: 48px;
28
+ }
29
+ .back-btn {
30
+ border: 0;
31
+ background: transparent;
32
+ font-size: 20px;
33
+ cursor: pointer;
34
+ }
35
+ .page-header h1 {
36
+ margin: 0;
37
+ font-size: 17px;
38
+ font-weight: 700;
39
+ }
40
+ .page-body {
41
+ padding: 24px 0;
42
+ }
43
+ .placeholder {
44
+ text-align: center;
45
+ color: #969799;
46
+ font-size: 14px;
47
+ padding-top: 120px;
48
+ }
49
+ </style>
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts"></script>
2
+
3
+ <template>
4
+ <main class="page">
5
+ <header class="page-header">
6
+ <button class="back-btn" type="button" @click="$router.back()">←</button>
7
+ <h1>外币头寸预报及查询</h1>
8
+ </header>
9
+ <section class="page-body">
10
+ <p class="placeholder">页面建设中…</p>
11
+ </section>
12
+ </main>
13
+ </template>
14
+
15
+ <style scoped>
16
+ .page {
17
+ max-width: 750px;
18
+ min-height: 100vh;
19
+ margin: 0 auto;
20
+ padding: 0 11px;
21
+ background: #f7f8fa;
22
+ }
23
+ .page-header {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 8px;
27
+ height: 48px;
28
+ }
29
+ .back-btn {
30
+ border: 0;
31
+ background: transparent;
32
+ font-size: 20px;
33
+ cursor: pointer;
34
+ }
35
+ .page-header h1 {
36
+ margin: 0;
37
+ font-size: 17px;
38
+ font-weight: 700;
39
+ }
40
+ .page-body {
41
+ padding: 24px 0;
42
+ }
43
+ .placeholder {
44
+ text-align: center;
45
+ color: #969799;
46
+ font-size: 14px;
47
+ padding-top: 120px;
48
+ }
49
+ </style>
@@ -0,0 +1,201 @@
1
+ <script setup lang="ts" name="HomePage">
2
+ type HomeFeature = {
3
+ title: string[]
4
+ image: string
5
+ route: string
6
+ }
7
+
8
+ defineOptions({ name: 'HomePage' })
9
+
10
+ const bannerImage = '/images/img.png'
11
+
12
+ const router = useRouter()
13
+
14
+ const features: HomeFeature[] = [
15
+ {
16
+ title: ['人民币头寸', '预报及查询'],
17
+ image: '/images/f5876785-b927-4347-ba19-999114240649.png',
18
+ route: '/rmb-position',
19
+ },
20
+ {
21
+ title: ['外币头寸', '预报及查询'],
22
+ image: '/images/12a73787-86a9-4891-a65f-66104746f6a8.png',
23
+ route: '/foreign-position',
24
+ },
25
+ {
26
+ title: ['人行头寸', '余额查询'],
27
+ image: '/images/73fef1e4-0fd0-4a1a-9b8b-a70a5b6acbbc.png',
28
+ route: '/pbc-position',
29
+ },
30
+ {
31
+ title: ['头寸匡算'],
32
+ image: '/images/ea745a10-42aa-4f44-8d7f-3ab02cc0adcd.png',
33
+ route: '/position-estimate',
34
+ },
35
+ {
36
+ title: ['人民币净借记', '可用额度管理'],
37
+ image: '/images/5798d7aa-ba8b-4605-8079-58b35495ac55.png',
38
+ route: '/net-debit',
39
+ },
40
+ {
41
+ title: ['人民币小额网银', '清算场次明细'],
42
+ image: '/images/c3dbbd9d-be56-490e-b9f4-6ee17ebefffc.png',
43
+ route: '/clearing-detail',
44
+ },
45
+ {
46
+ title: ['预警信息'],
47
+ image: '/images/bc685b4c-0cca-4a79-924c-a8ee10e6f8eb.png',
48
+ route: '/warning',
49
+ },
50
+ ]
51
+ </script>
52
+
53
+ <template>
54
+ <main class="home-page">
55
+ <section class="banner-section" aria-label="欢迎登录头寸管理系统">
56
+ <img class="banner-image" :src="bannerImage" alt="欢迎登录头寸管理系统" />
57
+ </section>
58
+
59
+ <section class="feature-section">
60
+ <div class="section-title">
61
+ <span class="section-title-mark"></span>
62
+ <h2>常用功能</h2>
63
+ </div>
64
+
65
+ <div class="feature-grid">
66
+ <button
67
+ v-for="item in features"
68
+ :key="item.title.join('')"
69
+ class="feature-card"
70
+ type="button"
71
+ @click="router.push(item.route)"
72
+ >
73
+ <span class="feature-title">
74
+ <span v-for="line in item.title" :key="line">{{ line }}</span>
75
+ </span>
76
+ <span class="feature-arrow" aria-hidden="true"><van-icon name="arrow" /></span>
77
+ <img class="feature-image" :src="item.image" :alt="item.title.join('')" />
78
+ </button>
79
+ </div>
80
+ </section>
81
+ </main>
82
+ </template>
83
+
84
+ <style scoped>
85
+ .home-page {
86
+ width: 100%;
87
+ max-width: 750px;
88
+ min-height: 100vh;
89
+ margin: 0 auto;
90
+ padding: 7px 11px 16px;
91
+ color: #171b20;
92
+ background:
93
+ radial-gradient(circle at 50% 12%, rgba(255, 245, 245, 0.88), transparent 124px),
94
+ #ffffff;
95
+ box-sizing: border-box;
96
+ }
97
+
98
+ .feature-card {
99
+ border: 0;
100
+ padding: 0;
101
+ font: inherit;
102
+ background: transparent;
103
+ appearance: none;
104
+ }
105
+
106
+ .banner-image {
107
+ display: block;
108
+ width: 100%;
109
+ height: auto;
110
+ border-radius: 9px;
111
+ }
112
+
113
+ .feature-section {
114
+ margin-top: 18px;
115
+ }
116
+
117
+ .section-title {
118
+ display: flex;
119
+ align-items: center;
120
+ gap: 8px;
121
+ height: 28px;
122
+ margin-bottom: 11px;
123
+ padding-left: 2px;
124
+ }
125
+
126
+ .section-title-mark {
127
+ width: 5px;
128
+ height: 16px;
129
+ border-radius: 8px;
130
+ background: linear-gradient(180deg, #ff1826 0%, #ff4854 100%);
131
+ }
132
+
133
+ .section-title h2 {
134
+ margin: 0;
135
+ color: #171b20;
136
+ font-size: 16px;
137
+ font-weight: 700;
138
+ line-height: 1;
139
+ }
140
+
141
+ .feature-grid {
142
+ display: grid;
143
+ grid-template-columns: repeat(2, minmax(0, 1fr));
144
+ gap: 8px;
145
+ }
146
+
147
+ .feature-card {
148
+ position: relative;
149
+ height: 104px;
150
+ overflow: hidden;
151
+ text-align: left;
152
+ border: 1px solid #ffdfe1;
153
+ border-radius: 9px;
154
+ background:
155
+ radial-gradient(circle at 78% 74%, rgba(255, 225, 225, 0.52), transparent 58px),
156
+ linear-gradient(135deg, #fff4f4 0%, #ffffff 52%, #fffafa 100%);
157
+ box-shadow: 0 4px 14px rgba(250, 70, 78, 0.035);
158
+ }
159
+
160
+ .feature-title {
161
+ position: absolute;
162
+ top: 16px;
163
+ left: 12px;
164
+ z-index: 1;
165
+ display: flex;
166
+ flex-direction: column;
167
+ width: 104px;
168
+ padding: 0;
169
+ color: #15191d;
170
+ font-size: 15px;
171
+ font-weight: 700;
172
+ line-height: 1.42;
173
+ word-break: keep-all;
174
+ }
175
+
176
+ .feature-arrow {
177
+ position: absolute;
178
+ left: 12px;
179
+ bottom: 20px;
180
+ z-index: 2;
181
+ display: flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ width: 18px;
185
+ height: 18px;
186
+ border-radius: 50%;
187
+ background: linear-gradient(135deg, #ff3443 0%, #ff5b62 100%);
188
+ color: #ffffff;
189
+ font-size: 11px;
190
+ }
191
+
192
+ .feature-image {
193
+ position: absolute;
194
+ right: -4px;
195
+ bottom: -7px;
196
+ width: 94px;
197
+ height: 94px;
198
+ object-fit: contain;
199
+ pointer-events: none;
200
+ }
201
+ </style>
@@ -0,0 +1,166 @@
1
+ <script setup lang="ts">
2
+ import { useRouter } from 'vue-router'
3
+ import { login } from '@/api/user'
4
+ import { showToast } from 'vant'
5
+ import { useUserStore } from '@/stores/user'
6
+ import { isNativeApp, getEncryptString } from '@/core/mxApi'
7
+
8
+ const router = useRouter()
9
+ const userStore = useUserStore()
10
+ const isNative = isNativeApp()
11
+
12
+ const form = ref({
13
+ username: '',
14
+ password: '',
15
+ })
16
+
17
+ const loading = ref(false)
18
+
19
+ // 原生环境:从客户端获取密钥,直接交换 token
20
+ onMounted(async () => {
21
+ if (!isNativeApp()) return
22
+
23
+ loading.value = true
24
+ try {
25
+ const secret = await getEncryptString()
26
+ console.log(secret)
27
+ } catch {
28
+ // 错误已由 request.ts 拦截器统一处理
29
+ } finally {
30
+ loading.value = false
31
+ }
32
+ })
33
+
34
+ async function onSubmit() {
35
+ loading.value = true
36
+ try {
37
+ const res = await login(form.value) as any
38
+ userStore.setToken(res.data.token)
39
+ showToast('登录成功')
40
+ router.push('/')
41
+ } catch {
42
+ // 错误已由 request.ts 拦截器统一处理
43
+ } finally {
44
+ loading.value = false
45
+ }
46
+ }
47
+ </script>
48
+
49
+ <template>
50
+ <div class="login-page">
51
+ <!-- 原生环境:自动登录,只显示加载状态 -->
52
+ <van-loading v-if="isNative" vertical class="native-loading">
53
+ 正在登录...
54
+ </van-loading>
55
+
56
+ <!-- 浏览器环境:显示登录表单 -->
57
+ <template v-else>
58
+ <section class="login-header">
59
+ <p class="login-eyebrow">Welcome back</p>
60
+ <h1 class="login-title">账号登录</h1>
61
+ <p class="login-subtitle">请输入账号信息继续访问</p>
62
+ </section>
63
+
64
+ <van-form class="login-form" @submit="onSubmit">
65
+ <van-cell-group inset class="form-panel">
66
+ <van-field
67
+ v-model="form.username"
68
+ name="username"
69
+ label="用户名"
70
+ placeholder="请输入用户名"
71
+ :rules="[{ required: true, message: '请输入用户名' }]"
72
+ />
73
+ <van-field
74
+ v-model="form.password"
75
+ type="password"
76
+ name="password"
77
+ label="密码"
78
+ placeholder="请输入密码"
79
+ :rules="[{ required: true, message: '请输入密码' }]"
80
+ />
81
+ </van-cell-group>
82
+ <div class="btn-wrap">
83
+ <van-button block round type="primary" native-type="submit" :loading="loading">
84
+ 登录
85
+ </van-button>
86
+ </div>
87
+ </van-form>
88
+ </template>
89
+ </div>
90
+ </template>
91
+
92
+ <style scoped>
93
+ .login-page {
94
+ min-height: 100vh;
95
+ padding: 72px 24px 24px;
96
+ background:
97
+ radial-gradient(circle at 18% 8%, rgba(25, 137, 250, 0.16), transparent 110px),
98
+ linear-gradient(180deg, #f6f9ff 0%, #ffffff 44%, #f7f8fa 100%);
99
+ box-sizing: border-box;
100
+ }
101
+
102
+ .login-header {
103
+ margin-bottom: 36px;
104
+ }
105
+
106
+ .login-eyebrow {
107
+ margin: 0 0 10px;
108
+ color: #1989fa;
109
+ font-size: 14px;
110
+ font-weight: 600;
111
+ line-height: 1.2;
112
+ }
113
+
114
+ .login-title {
115
+ margin: 0;
116
+ color: #1f2937;
117
+ font-size: 28px;
118
+ font-weight: 700;
119
+ line-height: 1.18;
120
+ }
121
+
122
+ .login-subtitle {
123
+ margin: 10px 0 0;
124
+ color: #6b7280;
125
+ font-size: 15px;
126
+ line-height: 1.5;
127
+ }
128
+
129
+ .login-form {
130
+ --van-cell-font-size: 15px;
131
+ --van-cell-line-height: 24px;
132
+ --van-cell-vertical-padding: 15px;
133
+ --van-cell-horizontal-padding: 16px;
134
+ --van-field-label-width: 66px;
135
+ --van-field-label-margin-right: 8px;
136
+ --van-field-placeholder-text-color: #b6bdc8;
137
+ --van-button-large-height: 48px;
138
+ --van-button-default-height: 48px;
139
+ --van-button-default-font-size: 17px;
140
+ }
141
+
142
+ .form-panel {
143
+ margin: 0;
144
+ border-radius: 14px;
145
+ overflow: hidden;
146
+ box-shadow: 0 10px 30px rgba(31, 41, 55, 0.08);
147
+ }
148
+
149
+ .btn-wrap {
150
+ margin-top: 28px;
151
+ }
152
+
153
+ .btn-wrap :deep(.van-button) {
154
+ border: 0;
155
+ background: linear-gradient(135deg, #1989fa 0%, #1268e5 100%);
156
+ box-shadow: 0 9px 18px rgba(25, 137, 250, 0.26);
157
+ font-weight: 600;
158
+ }
159
+
160
+ .native-loading {
161
+ display: flex;
162
+ justify-content: center;
163
+ align-items: center;
164
+ min-height: 60vh;
165
+ }
166
+ </style>
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts"></script>
2
+
3
+ <template>
4
+ <main class="page">
5
+ <header class="page-header">
6
+ <button class="back-btn" type="button" @click="$router.back()">←</button>
7
+ <h1>人民币净借记可用额度管理</h1>
8
+ </header>
9
+ <section class="page-body">
10
+ <p class="placeholder">页面建设中…</p>
11
+ </section>
12
+ </main>
13
+ </template>
14
+
15
+ <style scoped>
16
+ .page {
17
+ max-width: 750px;
18
+ min-height: 100vh;
19
+ margin: 0 auto;
20
+ padding: 0 11px;
21
+ background: #f7f8fa;
22
+ }
23
+ .page-header {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 8px;
27
+ height: 48px;
28
+ }
29
+ .back-btn {
30
+ border: 0;
31
+ background: transparent;
32
+ font-size: 20px;
33
+ cursor: pointer;
34
+ }
35
+ .page-header h1 {
36
+ margin: 0;
37
+ font-size: 17px;
38
+ font-weight: 700;
39
+ }
40
+ .page-body {
41
+ padding: 24px 0;
42
+ }
43
+ .placeholder {
44
+ text-align: center;
45
+ color: #969799;
46
+ font-size: 14px;
47
+ padding-top: 120px;
48
+ }
49
+ </style>