minitest2.0 0.0.4 → 0.0.6
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/src/App.vue +1 -1
- package/src/api/announcement.ts +153 -0
- package/src/api/clearing-detail.ts +66 -0
- package/src/api/foreign-position.ts +142 -0
- package/src/api/net-debit.ts +90 -0
- package/src/api/opening-reserve-estimate.ts +42 -0
- package/src/api/pbc-position.ts +63 -5
- package/src/router/index.ts +16 -16
- package/src/stores/user.ts +1 -1
- package/src/utils/foreign-forecast.ts +102 -0
- package/src/utils/rmb-forecast.ts +25 -1
- package/src/views/article-detail/index.vue +9 -0
- package/src/views/article-edit/index.vue +9 -0
- package/src/views/clearing-detail/index.vue +603 -12
- package/src/views/net-debit/index.vue +502 -12
- package/src/views/opening-reserve-estimate/index.vue +424 -12
- package/src/views/pbc-position/index.vue +65 -1
- package/src/views/rmb-position-detail/index.vue +14 -1
- package/src/views/warning/index.vue +566 -12
- package/vite.config.ts +3 -1
package/src/api/pbc-position.ts
CHANGED
|
@@ -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
|
|
package/src/router/index.ts
CHANGED
|
@@ -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: {
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
72
|
+
meta: { requiresAuth: true, title: '日初备款数匡算' },
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
path: '/net-debit',
|
|
@@ -87,49 +87,49 @@ const router = createRouter({
|
|
|
87
87
|
path: '/warning',
|
|
88
88
|
name: 'Warning',
|
|
89
89
|
component: () => import('@/views/warning/index.vue'),
|
|
90
|
-
meta: { requiresAuth: true, title: '
|
|
90
|
+
meta: { requiresAuth: true, title: '头寸管理平台' },
|
|
91
91
|
},
|
|
92
92
|
{
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
132
|
+
meta: { requiresAuth: true, title: '设置' },
|
|
133
133
|
},
|
|
134
134
|
],
|
|
135
135
|
})
|
package/src/stores/user.ts
CHANGED
|
@@ -20,7 +20,7 @@ export const useUserStore = defineStore(
|
|
|
20
20
|
// -------------------------------- State --------------------------------
|
|
21
21
|
|
|
22
22
|
/** 登录凭证,登录成功后由后端返回,后续请求通过请求头携带 */
|
|
23
|
-
const token = ref('
|
|
23
|
+
const token = ref('')
|
|
24
24
|
const refreshToken = ref('')
|
|
25
25
|
const username = ref('')
|
|
26
26
|
const realName = ref('')
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export type ForeignCurrencyOption = {
|
|
2
|
+
label: string
|
|
3
|
+
shortLabel: string
|
|
4
|
+
value: string
|
|
5
|
+
unit: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type ForeignOption = {
|
|
9
|
+
label: string
|
|
10
|
+
value: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type ForeignStatusOption = ForeignOption & {
|
|
14
|
+
className: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const foreignCurrencyOptions: ForeignCurrencyOption[] = [
|
|
18
|
+
{ label: '全部币种', shortLabel: '全部币种', value: '', unit: '万元' },
|
|
19
|
+
{ label: '美元', shortLabel: '美元', value: 'USD', unit: '万美元' },
|
|
20
|
+
{ label: '欧元', shortLabel: '欧元', value: 'EUR', unit: '万欧元' },
|
|
21
|
+
{ label: '港币', shortLabel: '港币', value: 'HKD', unit: '万港币' },
|
|
22
|
+
{ label: '日元', shortLabel: '日元', value: 'JPY', unit: '万日元' },
|
|
23
|
+
{ label: '英镑', shortLabel: '英镑', value: 'GBP', unit: '万英镑' },
|
|
24
|
+
{ label: '加拿大元', shortLabel: '加元', value: 'CAD', unit: '万加元' },
|
|
25
|
+
{ label: '澳大利亚元', shortLabel: '澳元', value: 'AUD', unit: '万澳元' },
|
|
26
|
+
{ label: '新加坡元', shortLabel: '新元', value: 'SGD', unit: '万新元' },
|
|
27
|
+
{ label: '瑞士法郎', shortLabel: '瑞郎', value: 'CHF', unit: '万瑞郎' },
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
export const foreignBusinessOptions: ForeignOption[] = [
|
|
31
|
+
{ label: '全部业务类型', value: '' },
|
|
32
|
+
{ label: '普通汇款', value: '1' },
|
|
33
|
+
{ label: '外汇买卖', value: '2' },
|
|
34
|
+
{ label: '结售汇', value: '3' },
|
|
35
|
+
{ label: '资金调拨', value: '4' },
|
|
36
|
+
{ label: '同业业务', value: '5' },
|
|
37
|
+
{ label: '贸易融资', value: '6' },
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
export const foreignStatusOptions: ForeignStatusOption[] = [
|
|
41
|
+
{ label: '全部预报状态', value: '', className: 'status-tag-unknown' },
|
|
42
|
+
{ label: '已确认', value: '1', className: 'status-tag-confirmed' },
|
|
43
|
+
{ label: '待确认', value: '2', className: 'status-tag-pending' },
|
|
44
|
+
{ label: '已撤销', value: '3', className: 'status-tag-cancelled' },
|
|
45
|
+
{ label: '已核销', value: '4', className: 'status-tag-verified' },
|
|
46
|
+
{ label: '已驳回', value: '5', className: 'status-tag-rejected' },
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
export const unknownForeignStatus: ForeignStatusOption = {
|
|
50
|
+
label: '未知状态',
|
|
51
|
+
value: '',
|
|
52
|
+
className: 'status-tag-unknown',
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function resolveForeignCurrency(value?: string) {
|
|
56
|
+
const normalizedValue = value?.trim().toUpperCase()
|
|
57
|
+
|
|
58
|
+
if (!normalizedValue) {
|
|
59
|
+
return foreignCurrencyOptions[0]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
foreignCurrencyOptions.find((item) => item.value === normalizedValue) || {
|
|
64
|
+
label: normalizedValue,
|
|
65
|
+
shortLabel: normalizedValue,
|
|
66
|
+
value: normalizedValue,
|
|
67
|
+
unit: `万${normalizedValue}`,
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function resolveForeignBusinessType(value?: string) {
|
|
73
|
+
if (!value?.trim()) return '普通汇款'
|
|
74
|
+
|
|
75
|
+
return foreignBusinessOptions.find((item) => item.value === value)?.label || value
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function resolveForeignStatus(value?: string) {
|
|
79
|
+
if (!value?.trim()) {
|
|
80
|
+
return unknownForeignStatus
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return foreignStatusOptions.find((item) => item.value === value) || unknownForeignStatus
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function formatForeignForecastDate(value?: string) {
|
|
87
|
+
if (value && /^\d{8}$/.test(value)) {
|
|
88
|
+
return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return value || '-'
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function toTenThousandAmount(value?: string) {
|
|
95
|
+
const amount = Number(value?.replaceAll(',', '') || 0)
|
|
96
|
+
return Number.isFinite(amount) ? amount / 10000 : 0
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function formatForeignForecastAmount(value: number) {
|
|
100
|
+
const sign = value >= 0 ? '+' : '-'
|
|
101
|
+
return `${sign}${Math.abs(value).toFixed(2)}`
|
|
102
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -219,6 +219,15 @@ function articleContentToText(html: string) {
|
|
|
219
219
|
text-decoration: none;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
.article-content :deep(img) {
|
|
223
|
+
display: block;
|
|
224
|
+
max-width: 100%;
|
|
225
|
+
height: auto;
|
|
226
|
+
margin: 8px auto 14px;
|
|
227
|
+
border-radius: 6px;
|
|
228
|
+
object-fit: contain;
|
|
229
|
+
}
|
|
230
|
+
|
|
222
231
|
.article-content :deep(pre) {
|
|
223
232
|
position: relative;
|
|
224
233
|
overflow-x: auto;
|
|
@@ -514,6 +514,15 @@ function normalizeCodeLanguage(value: string) {
|
|
|
514
514
|
background: #f6f7f9;
|
|
515
515
|
}
|
|
516
516
|
|
|
517
|
+
.rich-editor :deep(img) {
|
|
518
|
+
display: block;
|
|
519
|
+
max-width: 100%;
|
|
520
|
+
height: auto;
|
|
521
|
+
margin: 8px auto 12px;
|
|
522
|
+
border-radius: 6px;
|
|
523
|
+
object-fit: contain;
|
|
524
|
+
}
|
|
525
|
+
|
|
517
526
|
.rich-editor :deep(pre) {
|
|
518
527
|
overflow-x: auto;
|
|
519
528
|
margin: 0 0 12px;
|