minitest2.0 0.0.4 → 0.0.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minitest2.0",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "repository": {
package/src/App.vue CHANGED
@@ -22,7 +22,7 @@ const tabItems = computed(() =>
22
22
  }),
23
23
  )
24
24
 
25
- const showTabbar = computed(() => route.meta.hideTabbar !== true)
25
+ const showTabbar = computed(() => route.meta.showTabbar === true)
26
26
  const noBackRouteNames = new Set(['Home', 'Login', 'Dashboard', 'Articles', 'Mine'])
27
27
  const headerTitle = computed(() => String(route.meta.title || ''))
28
28
  const showHeaderBack = computed(() => !noBackRouteNames.has(String(route.name || '')))
@@ -0,0 +1,66 @@
1
+ import {
2
+ buildTamRequestPayload,
3
+ tamRequest,
4
+ type TamRequestPayload,
5
+ type TamResponse,
6
+ } from '@/api/tam'
7
+
8
+ export type ClearingDetailQueryForm = {
9
+ /** 清算日期,页面日期控件为 YYYY-MM-DD,接口入参为 YYYYMMDD。 */
10
+ queryDate: string
11
+ }
12
+
13
+ export type ClearingDetailPayload = TamRequestPayload<ClearingDetailQueryBody>
14
+
15
+ export type ClearingDetailResult = TamResponse<ClearingDetailResponseBody>
16
+
17
+ export type ClearingDetailRecord = {
18
+ /** 时间 */
19
+ msgSendDt?: string
20
+ /** 进款 */
21
+ secreditLineAmt?: string
22
+ /** 出款 */
23
+ sedebtLineAmt?: string
24
+ /** 轧差 */
25
+ txnetgBalance?: string
26
+ /** 轧差方向 */
27
+ txnetgBalanceDirection?: string
28
+ /** 轧差日期 */
29
+ txnetgDt?: string
30
+ /** 场次 */
31
+ txnetgRnd?: string
32
+ /** 清算报文编号 */
33
+ txnetgType?: string
34
+ }
35
+
36
+ type ClearingDetailQueryBody = {
37
+ /** 清算日期,格式 YYYYMMDD。 */
38
+ queryDate: string
39
+ }
40
+
41
+ type ClearingDetailResponseBody = {
42
+ result?: ClearingDetailRecord[]
43
+ }
44
+
45
+ const QUERY_TRAN_CODE = '/TAM/0001/140110006'
46
+
47
+ export function buildClearingDetailPayload(form: ClearingDetailQueryForm): ClearingDetailPayload {
48
+ return buildTamRequestPayload({
49
+ tranCode: QUERY_TRAN_CODE,
50
+ body: {
51
+ queryDate: normalizeDate(form.queryDate),
52
+ },
53
+ })
54
+ }
55
+
56
+ export async function queryClearingDetail(
57
+ payload: ClearingDetailPayload,
58
+ ): Promise<ClearingDetailResult> {
59
+ return tamRequest<ClearingDetailQueryBody, ClearingDetailResponseBody>(payload)
60
+ }
61
+
62
+ function normalizeDate(value: string) {
63
+ if (/^\d{8}$/.test(value)) return value
64
+
65
+ return value.replaceAll('-', '')
66
+ }
@@ -0,0 +1,90 @@
1
+ import {
2
+ buildTamRequestPayload,
3
+ tamRequest,
4
+ type TamRequestPayload,
5
+ type TamResponse,
6
+ } from '@/api/tam'
7
+
8
+ type NetDebitEmptyBody = Record<string, never>
9
+
10
+ export type NetDebitSendPayload = TamRequestPayload<NetDebitEmptyBody>
11
+
12
+ export type NetDebitQueryPayload = TamRequestPayload<NetDebitQueryBody>
13
+
14
+ export type NetDebitSendResult = TamResponse<NetDebitSendBody>
15
+
16
+ export type NetDebitQueryResult = TamResponse<NetDebitQuotaDetail>
17
+
18
+ export type NetDebitQuotaDetail = {
19
+ /** 净借记限额 */
20
+ availableDrAmt?: string
21
+ /** 查询处理状态 */
22
+ busiStatus?: string
23
+ /** 委托日期 */
24
+ consignDate?: string
25
+ /** 授信额度 */
26
+ creditAmt?: string
27
+ /** 可用净借记限额 */
28
+ currentAvailableDrAmt?: string
29
+ /** 圈存资金 */
30
+ encloseAmt?: string
31
+ /** 质押额度 */
32
+ impawnLimit?: string
33
+ /** 报文标识号 */
34
+ msgRefNo?: string
35
+ /** 被查询行行号 */
36
+ rcvBankCode?: string
37
+ /** 平台流水号 */
38
+ refNo?: string
39
+ /** 应答委托日期 */
40
+ responseDate?: string
41
+ /** 应答报文序号 */
42
+ responseNo?: string
43
+ /** 被查询清算行行号 */
44
+ settleBankCode?: string
45
+ /** 业务处理状态 */
46
+ status?: string
47
+ /** 发送交易返回的平台流水号,页面状态流转使用。 */
48
+ requestRefNo?: string
49
+ }
50
+
51
+ type NetDebitSendBody = {
52
+ /** 平台流水号,后续查询交易 body.msgId 使用该值。 */
53
+ refNo?: string
54
+ }
55
+
56
+ type NetDebitQueryBody = {
57
+ /** 发送交易返回的平台流水号。 */
58
+ msgId: string
59
+ }
60
+
61
+ const SEND_TRAN_CODE = '/TAM/0001/140110003'
62
+ const QUERY_TRAN_CODE = '/TAM/0001/140110004'
63
+
64
+ export function buildNetDebitSendPayload(): NetDebitSendPayload {
65
+ return buildTamRequestPayload({
66
+ tranCode: SEND_TRAN_CODE,
67
+ body: {},
68
+ })
69
+ }
70
+
71
+ export async function sendNetDebitRequest(
72
+ payload: NetDebitSendPayload,
73
+ ): Promise<NetDebitSendResult> {
74
+ return tamRequest<NetDebitEmptyBody, NetDebitSendBody>(payload)
75
+ }
76
+
77
+ export function buildNetDebitQueryPayload(msgId: string): NetDebitQueryPayload {
78
+ return buildTamRequestPayload({
79
+ tranCode: QUERY_TRAN_CODE,
80
+ body: {
81
+ msgId,
82
+ },
83
+ })
84
+ }
85
+
86
+ export async function queryNetDebitQuota(
87
+ payload: NetDebitQueryPayload,
88
+ ): Promise<NetDebitQueryResult> {
89
+ return tamRequest<NetDebitQueryBody, NetDebitQuotaDetail>(payload)
90
+ }
@@ -0,0 +1,42 @@
1
+ import {
2
+ buildTamRequestPayload,
3
+ tamRequest,
4
+ type TamRequestPayload,
5
+ type TamResponse,
6
+ } from '@/api/tam'
7
+
8
+ type OpeningReserveEstimateEmptyBody = Record<string, never>
9
+
10
+ export type OpeningReserveEstimateBody = {
11
+ /** 法定准备金 */
12
+ fzAmt?: string
13
+ /** 总分行铺底资金之和 */
14
+ pdAmt?: string
15
+ /** 日初备款 */
16
+ preAmt?: string
17
+ /** 人行时点头寸 */
18
+ rhAmt?: string
19
+ /** 预报未核销收入金额 */
20
+ unverifyAmtIn?: string
21
+ /** 预报未核销支出金额 */
22
+ unverifyAmtOut?: string
23
+ }
24
+
25
+ export type OpeningReserveEstimatePayload = TamRequestPayload<OpeningReserveEstimateEmptyBody>
26
+
27
+ export type OpeningReserveEstimateResult = TamResponse<OpeningReserveEstimateBody>
28
+
29
+ const QUERY_TRAN_CODE = '/TAM/0001/140103004'
30
+
31
+ export function buildOpeningReserveEstimatePayload(): OpeningReserveEstimatePayload {
32
+ return buildTamRequestPayload({
33
+ tranCode: QUERY_TRAN_CODE,
34
+ body: {},
35
+ })
36
+ }
37
+
38
+ export async function queryOpeningReserveEstimate(
39
+ payload: OpeningReserveEstimatePayload,
40
+ ): Promise<OpeningReserveEstimateResult> {
41
+ return tamRequest<OpeningReserveEstimateEmptyBody, OpeningReserveEstimateBody>(payload)
42
+ }
@@ -5,43 +5,65 @@ import {
5
5
  type TamResponse,
6
6
  } from '@/api/tam'
7
7
 
8
+ /**
9
+ * 人行头寸余额“发送”交易请求报文。
10
+ *
11
+ * 该交易不携带业务 body,仅用于向后端发起一次余额查询申请,
12
+ * 后端返回的申请平台流水号会作为后续“查询”动作的匹配条件。
13
+ */
8
14
  export type PbcPositionSendPayload = {
9
15
  appHead: TamRequestPayload<PbcPositionEmptyBody>['appHead']
10
16
  body: PbcPositionEmptyBody
11
17
  head: TamRequestPayload<PbcPositionEmptyBody>['head']
12
18
  }
13
19
 
20
+ /**
21
+ * 人行头寸余额列表查询请求报文。
22
+ *
23
+ * 列表查询同样为空 body,后端按当前登录用户、机构、工作日等报文头信息
24
+ * 返回可继续查询明细的记录集合。
25
+ */
14
26
  export type PbcPositionQueryPayload = {
15
27
  appHead: TamRequestPayload<PbcPositionEmptyBody>['appHead']
16
28
  body: PbcPositionEmptyBody
17
29
  head: TamRequestPayload<PbcPositionEmptyBody>['head']
18
30
  }
19
31
 
32
+ /**
33
+ * 人行头寸余额明细查询请求报文。
34
+ *
35
+ * 明细交易需要列表记录中的应答平台流水号和清算账户行号,
36
+ * 查询结果再与发送交易返回的申请平台流水号进行匹配。
37
+ */
20
38
  export type PbcPositionDetailPayload = {
21
39
  appHead: TamRequestPayload<PbcPositionDetailRequestBody>['appHead']
22
40
  body: PbcPositionDetailRequestBody
23
41
  head: TamRequestPayload<PbcPositionDetailRequestBody>['head']
24
42
  }
25
43
 
44
+ /** “发送”交易响应,body 中主要使用后端返回的申请平台流水号。 */
26
45
  export type PbcPositionSendResult = {
27
46
  body: PbcPositionSendBody
28
47
  head: TamResponse<PbcPositionSendBody>['head']
29
48
  }
30
49
 
50
+ /** “列表查询”交易响应,body 可能是数组,也可能被 resultList 包裹。 */
31
51
  export type PbcPositionQueryResult = {
32
52
  body: PbcPositionQueryBody
33
53
  head: TamResponse<PbcPositionQueryBody>['head']
34
54
  }
35
55
 
56
+ /** “明细查询”交易响应,body 为页面最终展示的扩展余额信息。 */
36
57
  export type PbcPositionDetailResult = {
37
58
  body: PbcPositionDetailBody
38
59
  head: TamResponse<PbcPositionDetailBody>['head']
39
60
  }
40
61
 
62
+ /** 列表交易返回的基础记录,也是明细查询的入参来源。 */
41
63
  export type PbcPositionRecord = {
42
- /** 应答平台流水号,查询明细入参。 */
64
+ /** 应答平台流水号,作为明细查询 body.refNo。 */
43
65
  refNo?: string
44
- /** 清算账户行号。 */
66
+ /** 清算账户行号,作为明细查询 body.settleBankNo。 */
45
67
  settleBankNo?: string
46
68
  /** 清算账户余额,接口按元返回。 */
47
69
  settleBal?: string
@@ -49,14 +71,15 @@ export type PbcPositionRecord = {
49
71
  avaAmt?: string
50
72
  /** 预期头寸,接口按元返回。 */
51
73
  expectAmt?: string
52
- /** 更新时间。 */
74
+ /** 余额数据更新时间,页面原样展示。 */
53
75
  updateTime?: string
54
76
  }
55
77
 
78
+ /** 明细交易返回的完整余额记录,补充排队金额和辖内非清算账户信息。 */
56
79
  export type PbcPositionDetailBody = PbcPositionRecord & {
57
- /** 申请平台流水号。 */
80
+ /** 申请平台流水号,用于与发送交易返回的流水号匹配。 */
58
81
  refNo?: string
59
- /** 应答平台流水号。 */
82
+ /** 明细返回的应答平台流水号,页面展示使用。 */
60
83
  resRefNo?: string
61
84
  /** 排队借记总金额,接口按元返回。 */
62
85
  lineDrAmt?: string
@@ -68,33 +91,50 @@ export type PbcPositionDetailBody = PbcPositionRecord & {
68
91
  subAcctAmt?: string
69
92
  }
70
93
 
94
+ /**
95
+ * 页面使用的归一化余额模型。
96
+ *
97
+ * 列表记录和明细记录会合并到同一个对象中,额外保留发送交易返回的
98
+ * requestRefNo,便于页面判断是否允许继续查询并展示当前申请编号。
99
+ */
71
100
  export type PbcPositionBalance = PbcPositionRecord &
72
101
  PbcPositionDetailBody & {
73
102
  /** 发送交易返回的申请平台流水号。 */
74
103
  requestRefNo?: string
75
104
  }
76
105
 
106
+ /** 人行头寸余额相关交易均没有业务入参,body 按接口约定传空对象。 */
77
107
  type PbcPositionEmptyBody = Record<string, never>
78
108
 
109
+ /** 发送交易响应体,仅返回本次申请的平台流水号。 */
79
110
  type PbcPositionSendBody = {
111
+ /** 申请平台流水号,后续查询用它匹配最终明细。 */
80
112
  refNo?: string
81
113
  }
82
114
 
115
+ /** 列表查询响应体,兼容后端返回数组或 { resultList } 两种结构。 */
83
116
  type PbcPositionQueryBody =
84
117
  | PbcPositionRecord[]
85
118
  | {
86
119
  resultList?: PbcPositionRecord[]
87
120
  }
88
121
 
122
+ /** 明细查询请求体,两个字段均来自列表记录。 */
89
123
  type PbcPositionDetailRequestBody = {
124
+ /** 列表记录中的应答平台流水号。 */
90
125
  refNo: string
126
+ /** 列表记录中的清算账户行号。 */
91
127
  settleBankNo: string
92
128
  }
93
129
 
130
+ /** 140104009:发起人行头寸余额查询申请。 */
94
131
  const SEND_TRAN_CODE = '/TAM/0001/140104009'
132
+ /** 140104010:查询可用于继续取明细的人行头寸余额记录列表。 */
95
133
  const QUERY_TRAN_CODE = '/TAM/0001/140104010'
134
+ /** 140104011:按列表记录查询人行头寸余额明细。 */
96
135
  const DETAIL_TRAN_CODE = '/TAM/0001/140104011'
97
136
 
137
+ /** 构造“发送”交易报文,填充 TAM 公共报文头并传空业务 body。 */
98
138
  export function buildPbcPositionSendPayload(): PbcPositionSendPayload {
99
139
  return buildTamRequestPayload({
100
140
  tranCode: SEND_TRAN_CODE,
@@ -102,12 +142,14 @@ export function buildPbcPositionSendPayload(): PbcPositionSendPayload {
102
142
  })
103
143
  }
104
144
 
145
+ /** 调用“发送”交易,成功后返回申请平台流水号。 */
105
146
  export async function sendPbcPositionRequest(
106
147
  payload: PbcPositionSendPayload,
107
148
  ): Promise<PbcPositionSendResult> {
108
149
  return tamRequest<PbcPositionEmptyBody, PbcPositionSendBody>(payload)
109
150
  }
110
151
 
152
+ /** 构造“列表查询”交易报文,按登录上下文查询当前可见的人行头寸记录。 */
111
153
  export function buildPbcPositionQueryPayload(): PbcPositionQueryPayload {
112
154
  return buildTamRequestPayload({
113
155
  tranCode: QUERY_TRAN_CODE,
@@ -115,12 +157,14 @@ export function buildPbcPositionQueryPayload(): PbcPositionQueryPayload {
115
157
  })
116
158
  }
117
159
 
160
+ /** 调用“列表查询”交易,返回可进一步查询明细的记录集合。 */
118
161
  export async function queryPbcPositionList(
119
162
  payload: PbcPositionQueryPayload,
120
163
  ): Promise<PbcPositionQueryResult> {
121
164
  return tamRequest<PbcPositionEmptyBody, PbcPositionQueryBody>(payload)
122
165
  }
123
166
 
167
+ /** 根据列表记录构造“明细查询”交易报文。 */
124
168
  export function buildPbcPositionDetailPayload(
125
169
  record: Pick<PbcPositionRecord, 'refNo' | 'settleBankNo'>,
126
170
  ): PbcPositionDetailPayload {
@@ -133,13 +177,22 @@ export function buildPbcPositionDetailPayload(
133
177
  })
134
178
  }
135
179
 
180
+ /** 调用“明细查询”交易,返回单条人行头寸余额的完整字段。 */
136
181
  export async function queryPbcPositionDetail(
137
182
  payload: PbcPositionDetailPayload,
138
183
  ): Promise<PbcPositionDetailResult> {
139
184
  return tamRequest<PbcPositionDetailRequestBody, PbcPositionDetailBody>(payload)
140
185
  }
141
186
 
187
+ /**
188
+ * 按发送交易返回的申请平台流水号查询最终余额明细。
189
+ *
190
+ * 后端流程拆成“列表查询”和“逐条明细查询”两步:先取到候选记录列表,
191
+ * 再使用每条记录的应答流水号和清算账户行号查询明细;只有明细中的
192
+ * refNo 与发送返回的 requestRefNo 一致时,才认为命中了本次申请结果。
193
+ */
142
194
  export async function queryPbcPositionBalance(requestRefNo: string): Promise<PbcPositionBalance> {
195
+ // 第一步:获取当前登录上下文下可查询的候选人行头寸记录。
143
196
  const queryPayload = buildPbcPositionQueryPayload()
144
197
  console.log('[人行头寸余额查询1入参]', queryPayload)
145
198
 
@@ -151,15 +204,19 @@ export async function queryPbcPositionBalance(requestRefNo: string): Promise<Pbc
151
204
  }
152
205
 
153
206
  for (const record of records) {
207
+ // 明细交易必须同时传入应答流水号和清算账户行号,缺任一字段时跳过。
154
208
  if (!record.refNo || !record.settleBankNo) continue
155
209
 
210
+ // 第二步:逐条查询明细,因为列表交易不直接返回全部展示字段。
156
211
  const detailPayload = buildPbcPositionDetailPayload(record)
157
212
  console.log('[人行头寸余额查询2入参]', detailPayload)
158
213
 
159
214
  const detailResponse = await queryPbcPositionDetail(detailPayload)
160
215
 
216
+ // 明细 refNo 表示申请平台流水号,用它与发送交易返回值做最终匹配。
161
217
  if (detailResponse.body.refNo !== requestRefNo) continue
162
218
 
219
+ // 保留列表字段,使用明细字段覆盖同名字段,并补齐页面需要的流水号别名。
163
220
  return {
164
221
  ...record,
165
222
  ...detailResponse.body,
@@ -171,6 +228,7 @@ export async function queryPbcPositionBalance(requestRefNo: string): Promise<Pbc
171
228
  throw new Error(`未查询到编号 ${requestRefNo} 对应的余额结果`)
172
229
  }
173
230
 
231
+ /** 统一提取列表记录,屏蔽后端数组和 resultList 包裹结构的差异。 */
174
232
  function getPbcPositionRecords(body: PbcPositionQueryBody) {
175
233
  if (Array.isArray(body)) return body
176
234
 
@@ -15,31 +15,31 @@ const router = createRouter({
15
15
  path: '/',
16
16
  name: 'Home',
17
17
  component: () => import('@/views/home/index.vue'),
18
- meta: { requiresAuth: true, title: '头寸管理平台' },
18
+ meta: { requiresAuth: true, showTabbar: true, title: '头寸管理平台' },
19
19
  },
20
20
  {
21
21
  path: '/login',
22
22
  name: 'Login',
23
23
  component: () => import('@/views/login/index.vue'),
24
- meta: { hideTabbar: true, title: '账号登录' },
24
+ meta: { title: '账号登录' },
25
25
  },
26
26
  {
27
27
  path: '/rmb-position',
28
28
  name: 'RmbPosition',
29
29
  component: () => import('@/views/rmb-position/index.vue'),
30
- meta: { requiresAuth: true, hideTabbar: true, title: '本币预报信息查询' },
30
+ meta: { requiresAuth: true, title: '本币预报信息查询' },
31
31
  },
32
32
  {
33
33
  path: '/rmb-position/new',
34
34
  name: 'RmbPositionCreate',
35
35
  component: () => import('@/views/rmb-position-create/index.vue'),
36
- meta: { requiresAuth: true, hideTabbar: true, title: '新增本币预报' },
36
+ meta: { requiresAuth: true, title: '新增本币预报' },
37
37
  },
38
38
  {
39
39
  path: '/rmb-position/:predRefNo',
40
40
  name: 'RmbPositionDetail',
41
41
  component: () => import('@/views/rmb-position-detail/index.vue'),
42
- meta: { requiresAuth: true, hideTabbar: true, title: '预报详情' },
42
+ meta: { requiresAuth: true, title: '预报详情' },
43
43
  },
44
44
  {
45
45
  path: '/foreign-position',
@@ -51,7 +51,7 @@ const router = createRouter({
51
51
  path: '/pbc-position',
52
52
  name: 'PbcPosition',
53
53
  component: () => import('@/views/pbc-position/index.vue'),
54
- meta: { requiresAuth: true, hideTabbar: true, title: '人行头寸余额查询' },
54
+ meta: { requiresAuth: true, title: '人行头寸余额查询' },
55
55
  },
56
56
  {
57
57
  path: '/position-estimate',
@@ -63,13 +63,13 @@ const router = createRouter({
63
63
  path: '/position-estimate/report',
64
64
  name: 'PositionEstimateReport',
65
65
  component: () => import('@/views/position-estimate-report/index.vue'),
66
- meta: { requiresAuth: true, hideTabbar: true, title: '头寸匡算报表' },
66
+ meta: { requiresAuth: true, title: '头寸匡算报表' },
67
67
  },
68
68
  {
69
69
  path: '/position-estimate/opening-reserve',
70
70
  name: 'OpeningReserveEstimate',
71
71
  component: () => import('@/views/opening-reserve-estimate/index.vue'),
72
- meta: { requiresAuth: true, hideTabbar: true, title: '日初备款数匡算' },
72
+ meta: { requiresAuth: true, title: '日初备款数匡算' },
73
73
  },
74
74
  {
75
75
  path: '/net-debit',
@@ -93,43 +93,43 @@ const router = createRouter({
93
93
  path: '/dashboard',
94
94
  name: 'Dashboard',
95
95
  component: () => import('@/views/dashboard/index.vue'),
96
- meta: { requiresAuth: true, title: '看板' },
96
+ meta: { requiresAuth: true, showTabbar: true, title: '看板' },
97
97
  },
98
98
  {
99
99
  path: '/articles',
100
100
  name: 'Articles',
101
101
  component: () => import('@/views/articles/index.vue'),
102
- meta: { requiresAuth: true, title: '公告' },
102
+ meta: { requiresAuth: true, showTabbar: true, title: '公告' },
103
103
  },
104
104
  {
105
105
  path: '/articles/new',
106
106
  name: 'ArticlePublish',
107
107
  component: () => import('@/views/article-edit/index.vue'),
108
- meta: { requiresAuth: true, hideTabbar: true, title: '发布公告' },
108
+ meta: { requiresAuth: true, title: '发布公告' },
109
109
  },
110
110
  {
111
111
  path: '/articles/:id',
112
112
  name: 'ArticleDetail',
113
113
  component: () => import('@/views/article-detail/index.vue'),
114
- meta: { requiresAuth: true, hideTabbar: true, title: '公告详情' },
114
+ meta: { requiresAuth: true, title: '公告详情' },
115
115
  },
116
116
  {
117
117
  path: '/articles/:id/edit',
118
118
  name: 'ArticleEdit',
119
119
  component: () => import('@/views/article-edit/index.vue'),
120
- meta: { requiresAuth: true, hideTabbar: true, title: '编辑公告' },
120
+ meta: { requiresAuth: true, title: '编辑公告' },
121
121
  },
122
122
  {
123
123
  path: '/mine',
124
124
  name: 'Mine',
125
125
  component: () => import('@/views/mine/index.vue'),
126
- meta: { requiresAuth: true, title: '我的' },
126
+ meta: { requiresAuth: true, showTabbar: true, title: '我的' },
127
127
  },
128
128
  {
129
129
  path: '/settings',
130
130
  name: 'Settings',
131
131
  component: () => import('@/views/settings/index.vue'),
132
- meta: { requiresAuth: true, hideTabbar: true, title: '设置' },
132
+ meta: { requiresAuth: true, title: '设置' },
133
133
  },
134
134
  ],
135
135
  })
@@ -68,7 +68,7 @@ export function formatRmbForecastDate(value?: string) {
68
68
  }
69
69
 
70
70
  export function toBillionYuan(value?: string) {
71
- const amount = Number(value || 0)
71
+ const amount = Number(value?.replaceAll(',', '') || 0)
72
72
  return Number.isFinite(amount) ? amount / 100000000 : 0
73
73
  }
74
74
 
@@ -82,3 +82,27 @@ export function formatForecastAmountText(value?: string) {
82
82
 
83
83
  return `${formatForecastAmount(toBillionYuan(value))} 亿元`
84
84
  }
85
+
86
+ export function formatForecastAmountYuanText(value?: string) {
87
+ const text = value?.trim()
88
+
89
+ if (!text) return '-'
90
+
91
+ const normalizedText = text.replaceAll(',', '')
92
+
93
+ if (!/^[-+]?\d+(\.\d+)?$/.test(normalizedText)) {
94
+ return `${text} 元`
95
+ }
96
+
97
+ const sign =
98
+ normalizedText.startsWith('-') || normalizedText.startsWith('+')
99
+ ? normalizedText.slice(0, 1)
100
+ : ''
101
+ const unsignedText = sign ? normalizedText.slice(1) : normalizedText
102
+ const [integerPart = '0', decimalPart] = unsignedText.split('.')
103
+ const normalizedInteger = integerPart.replace(/^0+(?=\d)/, '') || '0'
104
+ const groupedInteger = normalizedInteger.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
105
+ const amountText = decimalPart === undefined ? groupedInteger : `${groupedInteger}.${decimalPart}`
106
+
107
+ return `${sign}${amountText} 元`
108
+ }