minitest2.0 0.0.0

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 (89) hide show
  1. package/.editorconfig +8 -0
  2. package/.env.development +3 -0
  3. package/.env.production +3 -0
  4. package/.env.test +3 -0
  5. package/.gitattributes +1 -0
  6. package/.oxlintrc.json +10 -0
  7. package/.prettierrc.json +6 -0
  8. package/.vscode/extensions.json +9 -0
  9. package/.vscode/settings.json +13 -0
  10. package/README.md +179 -0
  11. package/auto-imports.d.ts +629 -0
  12. package/components.d.ts +21 -0
  13. package/design-qa.md +36 -0
  14. package/docs/MX_API.md +244 -0
  15. package/docs/REQUEST.md +217 -0
  16. package/docs/jsapi.js +515 -0
  17. package/docs/package-json-guide.md +132 -0
  18. package/env.d.ts +15 -0
  19. package/eslint.config.ts +26 -0
  20. package/index.html +16 -0
  21. package/package.json +83 -0
  22. package/plugins/bump-version.ts +61 -0
  23. package/postcss.config.ts +15 -0
  24. package/public/favicon.ico +0 -0
  25. package/public/images/12a73787-86a9-4891-a65f-66104746f6a8.png +0 -0
  26. package/public/images/5798d7aa-ba8b-4605-8079-58b35495ac55.png +0 -0
  27. package/public/images/73fef1e4-0fd0-4a1a-9b8b-a70a5b6acbbc.png +0 -0
  28. package/public/images/bc685b4c-0cca-4a79-924c-a8ee10e6f8eb.png +0 -0
  29. package/public/images/c3dbbd9d-be56-490e-b9f4-6ee17ebefffc.png +0 -0
  30. package/public/images/ea745a10-42aa-4f44-8d7f-3ab02cc0adcd.png +0 -0
  31. package/public/images/f5876785-b927-4347-ba19-999114240649.png +0 -0
  32. package/public/images/img.png +0 -0
  33. package/public/images/opening-reserve-estimate.png +0 -0
  34. package/public/images/position-estimate-report.png +0 -0
  35. package/src/App.vue +131 -0
  36. package/src/api/announcement.ts +405 -0
  37. package/src/api/health.ts +13 -0
  38. package/src/api/pbc-position.ts +178 -0
  39. package/src/api/rmb-position.ts +233 -0
  40. package/src/api/tam.ts +173 -0
  41. package/src/api/user.ts +92 -0
  42. package/src/auto-imports.d.ts +633 -0
  43. package/src/components/AppTitleBar.vue +376 -0
  44. package/src/components.d.ts +33 -0
  45. package/src/config/config.properties +3 -0
  46. package/src/config/env.ts +6 -0
  47. package/src/config/plugin.properties.pro +6 -0
  48. package/src/config/plugin.properties.test +6 -0
  49. package/src/core/mxApi/index.ts +451 -0
  50. package/src/core/request/index.ts +135 -0
  51. package/src/main.ts +40 -0
  52. package/src/router/index.ts +144 -0
  53. package/src/stores/app.ts +103 -0
  54. package/src/stores/counter.ts +12 -0
  55. package/src/stores/user.ts +137 -0
  56. package/src/styles/nprogress.css +22 -0
  57. package/src/styles/vant-overrides.css +42 -0
  58. package/src/types/api.d.ts +14 -0
  59. package/src/types/nprogress.d.ts +8 -0
  60. package/src/utils/auth-token.ts +241 -0
  61. package/src/utils/code-highlight.ts +165 -0
  62. package/src/utils/copy.ts +36 -0
  63. package/src/utils/query.ts +27 -0
  64. package/src/utils/request.ts +238 -0
  65. package/src/utils/rmb-forecast.ts +84 -0
  66. package/src/utils/toast.ts +61 -0
  67. package/src/views/article-detail/index.vue +289 -0
  68. package/src/views/article-edit/index.vue +600 -0
  69. package/src/views/articles/index.vue +293 -0
  70. package/src/views/clearing-detail/index.vue +26 -0
  71. package/src/views/dashboard/index.vue +18 -0
  72. package/src/views/foreign-position/index.vue +26 -0
  73. package/src/views/home/index.vue +213 -0
  74. package/src/views/login/index.vue +275 -0
  75. package/src/views/mine/index.vue +147 -0
  76. package/src/views/net-debit/index.vue +26 -0
  77. package/src/views/opening-reserve-estimate/index.vue +28 -0
  78. package/src/views/pbc-position/index.vue +357 -0
  79. package/src/views/position-estimate/index.vue +67 -0
  80. package/src/views/position-estimate-report/index.vue +28 -0
  81. package/src/views/rmb-position/index.vue +1013 -0
  82. package/src/views/rmb-position-create/index.vue +221 -0
  83. package/src/views/rmb-position-detail/index.vue +355 -0
  84. package/src/views/settings/index.vue +67 -0
  85. package/src/views/warning/index.vue +26 -0
  86. package/tsconfig.app.json +18 -0
  87. package/tsconfig.json +11 -0
  88. package/tsconfig.node.json +28 -0
  89. package/vite.config.ts +100 -0
@@ -0,0 +1,405 @@
1
+ import { request } from '@/core/request'
2
+ import type { ApiResponse } from '@/types/api'
3
+
4
+ export interface Article {
5
+ id: string
6
+ title: string
7
+ content: string
8
+ author: string
9
+ createdAt: string
10
+ updatedAt: string
11
+ }
12
+
13
+ export interface ArticlePayload {
14
+ title: string
15
+ content: string
16
+ }
17
+
18
+ type RawRecord = Record<string, unknown>
19
+
20
+ const LIST_URL = '/uaa/announcement/get/restricted'
21
+ const DETAIL_URL = '/uaa/announcement/get/id'
22
+ const ADD_URL = '/uaa/announcement/add'
23
+ const UPDATE_URL = '/uaa/announcement/update'
24
+ const DEFAULT_ANNOUNCEMENT_FIELDS = {
25
+ annouZrFteLag: '0',
26
+ annouSts: '0',
27
+ department: '100011',
28
+ efDt: '2026-07-01 00:00:00',
29
+ expireDt: '2026-07-31 00:00:00',
30
+ orgList: [],
31
+ orgNo: '25001',
32
+ roleList: [],
33
+ topFlag: '0',
34
+ userList: [],
35
+ }
36
+
37
+ const ALLOWED_TAGS = new Set([
38
+ 'A',
39
+ 'B',
40
+ 'BLOCKQUOTE',
41
+ 'BR',
42
+ 'DIV',
43
+ 'EM',
44
+ 'H2',
45
+ 'H3',
46
+ 'I',
47
+ 'LI',
48
+ 'OL',
49
+ 'P',
50
+ 'PRE',
51
+ 'S',
52
+ 'SPAN',
53
+ 'STRONG',
54
+ 'U',
55
+ 'UL',
56
+ 'CODE',
57
+ ])
58
+
59
+ export async function queryArticles() {
60
+ const response = await request<unknown>({
61
+ url: LIST_URL,
62
+ method: 'GET',
63
+ })
64
+ const data = unwrapResponse(response)
65
+
66
+ return extractRecords(data).map((record) => mapAnnouncementRecord(record))
67
+ }
68
+
69
+ export async function getArticleDetail(annouId: string) {
70
+ const response = await request<unknown>({
71
+ url: DETAIL_URL,
72
+ method: 'GET',
73
+ params: { annouId },
74
+ })
75
+ const data = unwrapResponse(response)
76
+ const record = extractDetailRecord(data)
77
+
78
+ return mapAnnouncementRecord(record, annouId)
79
+ }
80
+
81
+ export async function createArticle(payload: ArticlePayload) {
82
+ const content = sanitizeArticleHtml(payload.content)
83
+ const response = await request<unknown, RawRecord>({
84
+ url: ADD_URL,
85
+ method: 'POST',
86
+ data: buildAnnouncementPayload({ ...payload, content }),
87
+ })
88
+ const data = unwrapResponse(response)
89
+ const record = extractDetailRecord(data)
90
+
91
+ return mapAnnouncementRecord(record, readString(record, ['annouId', 'id']))
92
+ }
93
+
94
+ export async function updateArticle(annouId: string, payload: ArticlePayload) {
95
+ const content = sanitizeArticleHtml(payload.content)
96
+ const response = await request<unknown, RawRecord>({
97
+ url: UPDATE_URL,
98
+ method: 'POST',
99
+ data: buildAnnouncementPayload({ ...payload, content }, annouId),
100
+ })
101
+ const data = unwrapResponse(response)
102
+ const record = extractDetailRecord(data)
103
+
104
+ return mapAnnouncementRecord(record, annouId)
105
+ }
106
+
107
+ export function formatArticleDate(value: string) {
108
+ const date = new Date(value)
109
+
110
+ if (Number.isNaN(date.getTime())) {
111
+ return ''
112
+ }
113
+
114
+ return new Intl.DateTimeFormat('zh-CN', {
115
+ year: 'numeric',
116
+ month: '2-digit',
117
+ day: '2-digit',
118
+ hour: '2-digit',
119
+ minute: '2-digit',
120
+ }).format(date)
121
+ }
122
+
123
+ export function extractTextFromHtml(html: string) {
124
+ if (!html.trim()) {
125
+ return ''
126
+ }
127
+
128
+ const doc = new DOMParser().parseFromString(html, 'text/html')
129
+
130
+ return doc.body.textContent?.replace(/\s+/g, ' ').trim() || ''
131
+ }
132
+
133
+ export function sanitizeArticleHtml(html: string) {
134
+ if (!html.trim()) {
135
+ return ''
136
+ }
137
+
138
+ const doc = new DOMParser().parseFromString(`<article>${html}</article>`, 'text/html')
139
+ const root = doc.body.firstElementChild
140
+
141
+ if (!root) {
142
+ return ''
143
+ }
144
+
145
+ sanitizeChildren(root, doc)
146
+
147
+ return root.innerHTML.trim()
148
+ }
149
+
150
+ function buildAnnouncementPayload(payload: ArticlePayload, annouId = '') {
151
+ return {
152
+ annouTitle: payload.title.trim(),
153
+ annouConte: payload.content,
154
+ annouId,
155
+ ...DEFAULT_ANNOUNCEMENT_FIELDS,
156
+ }
157
+ }
158
+
159
+ function unwrapResponse(response: ApiResponse<unknown> | unknown) {
160
+ if (!isRecord(response)) {
161
+ return response
162
+ }
163
+
164
+ if ('code' in response && 'data' in response) {
165
+ return response.data
166
+ }
167
+
168
+ return response
169
+ }
170
+
171
+ function extractRecords(data: unknown): RawRecord[] {
172
+ const candidates = [
173
+ data,
174
+ getValue(data, ['list']),
175
+ getValue(data, ['records']),
176
+ getValue(data, ['rows']),
177
+ getValue(data, ['resultList']),
178
+ getValue(data, ['content']),
179
+ getValue(data, ['body', 'list']),
180
+ getValue(data, ['body', 'records']),
181
+ getValue(data, ['body', 'rows']),
182
+ getValue(data, ['body', 'resultList']),
183
+ ]
184
+
185
+ for (const candidate of candidates) {
186
+ if (Array.isArray(candidate)) {
187
+ return candidate.filter(isRecord)
188
+ }
189
+ }
190
+
191
+ return []
192
+ }
193
+
194
+ function extractDetailRecord(data: unknown): RawRecord {
195
+ const records = extractRecords(data)
196
+
197
+ if (records.length > 0) {
198
+ return records[0]!
199
+ }
200
+
201
+ const candidates = [
202
+ data,
203
+ getValue(data, ['announcement']),
204
+ getValue(data, ['announcementInfo']),
205
+ getValue(data, ['article']),
206
+ getValue(data, ['detail']),
207
+ getValue(data, ['info']),
208
+ getValue(data, ['record']),
209
+ getValue(data, ['body']),
210
+ getValue(data, ['body', 'announcement']),
211
+ getValue(data, ['body', 'detail']),
212
+ getValue(data, ['body', 'info']),
213
+ ]
214
+
215
+ return candidates.find(isRecord) || {}
216
+ }
217
+
218
+ function mapAnnouncementRecord(record: RawRecord, fallbackId = ''): Article {
219
+ const now = new Date().toISOString()
220
+ const id =
221
+ readString(record, ['annouId', 'announcementId', 'articleId', 'id', 'uuid']) ||
222
+ fallbackId
223
+ const title = readString(record, [
224
+ 'annouTitle',
225
+ 'announTitle',
226
+ 'announcementTitle',
227
+ 'title',
228
+ 'name',
229
+ 'subject',
230
+ ])
231
+ const content = readString(record, [
232
+ 'annouConte',
233
+ 'announContent',
234
+ 'announcementContent',
235
+ 'articleContent',
236
+ 'contentHtml',
237
+ 'htmlContent',
238
+ 'content',
239
+ ])
240
+ const createdAt =
241
+ readString(record, ['createTime', 'createdAt', 'publishTime', 'pubTime', 'gmtCreate']) || now
242
+ const updatedAt =
243
+ readString(record, ['updateTime', 'updatedAt', 'modifyTime', 'gmtModified']) || createdAt
244
+
245
+ return {
246
+ id,
247
+ title: title || '未命名公告',
248
+ content: sanitizeArticleHtml(content),
249
+ author:
250
+ readString(record, ['author', 'publisherName', 'pubUserName', 'creatorName', 'createBy']) ||
251
+ '管理员',
252
+ createdAt: normalizeDate(createdAt),
253
+ updatedAt: normalizeDate(updatedAt),
254
+ }
255
+ }
256
+
257
+ function readString(record: RawRecord, keys: string[]) {
258
+ for (const key of keys) {
259
+ const value = record[key]
260
+
261
+ if (typeof value === 'string' && value.trim()) {
262
+ return value.trim()
263
+ }
264
+
265
+ if (typeof value === 'number') {
266
+ return String(value)
267
+ }
268
+ }
269
+
270
+ return ''
271
+ }
272
+
273
+ function getValue(value: unknown, path: string[]) {
274
+ return path.reduce<unknown>((current, key) => {
275
+ if (!isRecord(current)) {
276
+ return undefined
277
+ }
278
+
279
+ return current[key]
280
+ }, value)
281
+ }
282
+
283
+ function normalizeDate(value: string) {
284
+ if (/^\d{4}-\d{2}-\d{2}/.test(value)) {
285
+ return value
286
+ }
287
+
288
+ if (/^\d{14}$/.test(value)) {
289
+ return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T${value.slice(8, 10)}:${value.slice(10, 12)}:${value.slice(12, 14)}`
290
+ }
291
+
292
+ if (/^\d{8}$/.test(value)) {
293
+ return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T00:00:00`
294
+ }
295
+
296
+ return value
297
+ }
298
+
299
+ function isRecord(value: unknown): value is RawRecord {
300
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
301
+ }
302
+
303
+ function sanitizeChildren(parent: ParentNode, doc: Document) {
304
+ Array.from(parent.childNodes).forEach((child) => {
305
+ if (child.nodeType === Node.COMMENT_NODE) {
306
+ child.remove()
307
+ return
308
+ }
309
+
310
+ if (child.nodeType !== Node.ELEMENT_NODE) {
311
+ return
312
+ }
313
+
314
+ const element = child as HTMLElement
315
+
316
+ if (!ALLOWED_TAGS.has(element.tagName)) {
317
+ const fragment = doc.createDocumentFragment()
318
+
319
+ while (element.firstChild) {
320
+ fragment.appendChild(element.firstChild)
321
+ }
322
+
323
+ element.replaceWith(fragment)
324
+ sanitizeChildren(parent, doc)
325
+ return
326
+ }
327
+
328
+ sanitizeAttributes(element)
329
+ sanitizeChildren(element, doc)
330
+ })
331
+ }
332
+
333
+ function sanitizeAttributes(element: HTMLElement) {
334
+ Array.from(element.attributes).forEach((attribute) => {
335
+ const name = attribute.name.toLowerCase()
336
+
337
+ if (element.tagName === 'A' && name === 'href') {
338
+ if (!isSafeHref(attribute.value)) {
339
+ element.removeAttribute(attribute.name)
340
+ return
341
+ }
342
+
343
+ element.setAttribute('target', '_blank')
344
+ element.setAttribute('rel', 'noopener noreferrer')
345
+ return
346
+ }
347
+
348
+ if (element.tagName === 'A' && (name === 'target' || name === 'rel')) {
349
+ return
350
+ }
351
+
352
+ if (element.tagName === 'CODE' && name === 'class') {
353
+ const languageClass = normalizeCodeLanguageClass(attribute.value)
354
+
355
+ if (languageClass) {
356
+ element.setAttribute('class', languageClass)
357
+ return
358
+ }
359
+ }
360
+
361
+ if (element.tagName === 'CODE' && name === 'data-language') {
362
+ const language = normalizeCodeLanguage(attribute.value)
363
+
364
+ if (language) {
365
+ element.setAttribute('data-language', language)
366
+ return
367
+ }
368
+ }
369
+
370
+ element.removeAttribute(attribute.name)
371
+ })
372
+ }
373
+
374
+ function normalizeCodeLanguageClass(value: string) {
375
+ const language = value
376
+ .split(/\s+/)
377
+ .find((className) => className.startsWith('language-'))
378
+ ?.replace(/^language-/, '')
379
+
380
+ if (!language) {
381
+ return ''
382
+ }
383
+
384
+ return `language-${normalizeCodeLanguage(language)}`
385
+ }
386
+
387
+ function normalizeCodeLanguage(value: string) {
388
+ return value.trim().toLowerCase().replace(/[^a-z0-9_-]/g, '').slice(0, 24)
389
+ }
390
+
391
+ function isSafeHref(value: string) {
392
+ const href = value.trim()
393
+
394
+ if (href.startsWith('#')) {
395
+ return true
396
+ }
397
+
398
+ try {
399
+ const url = new URL(href, window.location.origin)
400
+
401
+ return ['http:', 'https:', 'mailto:', 'tel:'].includes(url.protocol)
402
+ } catch {
403
+ return false
404
+ }
405
+ }
@@ -0,0 +1,13 @@
1
+ import { request } from '@/core/request'
2
+
3
+ export interface HealthCheckResult {
4
+ status?: string
5
+ timestamp?: string
6
+ }
7
+
8
+ export function healthCheckApi() {
9
+ return request<HealthCheckResult>({
10
+ url: '/uaa/announcement/get/restricted',
11
+ method: 'GET',
12
+ })
13
+ }
@@ -0,0 +1,178 @@
1
+ import {
2
+ buildTamRequestPayload,
3
+ tamRequest,
4
+ type TamRequestPayload,
5
+ type TamResponse,
6
+ } from '@/api/tam'
7
+
8
+ export type PbcPositionSendPayload = {
9
+ appHead: TamRequestPayload<PbcPositionEmptyBody>['appHead']
10
+ body: PbcPositionEmptyBody
11
+ head: TamRequestPayload<PbcPositionEmptyBody>['head']
12
+ }
13
+
14
+ export type PbcPositionQueryPayload = {
15
+ appHead: TamRequestPayload<PbcPositionEmptyBody>['appHead']
16
+ body: PbcPositionEmptyBody
17
+ head: TamRequestPayload<PbcPositionEmptyBody>['head']
18
+ }
19
+
20
+ export type PbcPositionDetailPayload = {
21
+ appHead: TamRequestPayload<PbcPositionDetailRequestBody>['appHead']
22
+ body: PbcPositionDetailRequestBody
23
+ head: TamRequestPayload<PbcPositionDetailRequestBody>['head']
24
+ }
25
+
26
+ export type PbcPositionSendResult = {
27
+ body: PbcPositionSendBody
28
+ head: TamResponse<PbcPositionSendBody>['head']
29
+ }
30
+
31
+ export type PbcPositionQueryResult = {
32
+ body: PbcPositionQueryBody
33
+ head: TamResponse<PbcPositionQueryBody>['head']
34
+ }
35
+
36
+ export type PbcPositionDetailResult = {
37
+ body: PbcPositionDetailBody
38
+ head: TamResponse<PbcPositionDetailBody>['head']
39
+ }
40
+
41
+ export type PbcPositionRecord = {
42
+ /** 应答平台流水号,查询明细入参。 */
43
+ refNo?: string
44
+ /** 清算账户行号。 */
45
+ settleBankNo?: string
46
+ /** 清算账户余额,接口按元返回。 */
47
+ settleBal?: string
48
+ /** 可用头寸,接口按元返回。 */
49
+ avaAmt?: string
50
+ /** 预期头寸,接口按元返回。 */
51
+ expectAmt?: string
52
+ /** 更新时间。 */
53
+ updateTime?: string
54
+ }
55
+
56
+ export type PbcPositionDetailBody = PbcPositionRecord & {
57
+ /** 申请平台流水号。 */
58
+ refNo?: string
59
+ /** 应答平台流水号。 */
60
+ resRefNo?: string
61
+ /** 排队借记总金额,接口按元返回。 */
62
+ lineDrAmt?: string
63
+ /** 排队贷记总金额,接口按元返回。 */
64
+ lineCrAmt?: string
65
+ /** 所辖非清算账户数。 */
66
+ subAcctNumber?: string
67
+ /** 所辖非清算总余额,接口按元返回。 */
68
+ subAcctAmt?: string
69
+ }
70
+
71
+ export type PbcPositionBalance = PbcPositionRecord &
72
+ PbcPositionDetailBody & {
73
+ /** 发送交易返回的申请平台流水号。 */
74
+ requestRefNo?: string
75
+ }
76
+
77
+ type PbcPositionEmptyBody = Record<string, never>
78
+
79
+ type PbcPositionSendBody = {
80
+ refNo?: string
81
+ }
82
+
83
+ type PbcPositionQueryBody =
84
+ | PbcPositionRecord[]
85
+ | {
86
+ resultList?: PbcPositionRecord[]
87
+ }
88
+
89
+ type PbcPositionDetailRequestBody = {
90
+ refNo: string
91
+ settleBankNo: string
92
+ }
93
+
94
+ const SEND_TRAN_CODE = '/TAM/0001/140104009'
95
+ const QUERY_TRAN_CODE = '/TAM/0001/140104010'
96
+ const DETAIL_TRAN_CODE = '/TAM/0001/140104011'
97
+
98
+ export function buildPbcPositionSendPayload(): PbcPositionSendPayload {
99
+ return buildTamRequestPayload({
100
+ tranCode: SEND_TRAN_CODE,
101
+ body: {},
102
+ })
103
+ }
104
+
105
+ export async function sendPbcPositionRequest(
106
+ payload: PbcPositionSendPayload,
107
+ ): Promise<PbcPositionSendResult> {
108
+ return tamRequest<PbcPositionEmptyBody, PbcPositionSendBody>(payload)
109
+ }
110
+
111
+ export function buildPbcPositionQueryPayload(): PbcPositionQueryPayload {
112
+ return buildTamRequestPayload({
113
+ tranCode: QUERY_TRAN_CODE,
114
+ body: {},
115
+ })
116
+ }
117
+
118
+ export async function queryPbcPositionList(
119
+ payload: PbcPositionQueryPayload,
120
+ ): Promise<PbcPositionQueryResult> {
121
+ return tamRequest<PbcPositionEmptyBody, PbcPositionQueryBody>(payload)
122
+ }
123
+
124
+ export function buildPbcPositionDetailPayload(
125
+ record: Pick<PbcPositionRecord, 'refNo' | 'settleBankNo'>,
126
+ ): PbcPositionDetailPayload {
127
+ return buildTamRequestPayload({
128
+ tranCode: DETAIL_TRAN_CODE,
129
+ body: {
130
+ refNo: record.refNo || '',
131
+ settleBankNo: record.settleBankNo || '',
132
+ },
133
+ })
134
+ }
135
+
136
+ export async function queryPbcPositionDetail(
137
+ payload: PbcPositionDetailPayload,
138
+ ): Promise<PbcPositionDetailResult> {
139
+ return tamRequest<PbcPositionDetailRequestBody, PbcPositionDetailBody>(payload)
140
+ }
141
+
142
+ export async function queryPbcPositionBalance(requestRefNo: string): Promise<PbcPositionBalance> {
143
+ const queryPayload = buildPbcPositionQueryPayload()
144
+ console.log('[人行头寸余额查询1入参]', queryPayload)
145
+
146
+ const queryResponse = await queryPbcPositionList(queryPayload)
147
+ const records = getPbcPositionRecords(queryResponse.body)
148
+
149
+ if (records.length === 0) {
150
+ throw new Error('人行头寸余额查询结果为空')
151
+ }
152
+
153
+ for (const record of records) {
154
+ if (!record.refNo || !record.settleBankNo) continue
155
+
156
+ const detailPayload = buildPbcPositionDetailPayload(record)
157
+ console.log('[人行头寸余额查询2入参]', detailPayload)
158
+
159
+ const detailResponse = await queryPbcPositionDetail(detailPayload)
160
+
161
+ if (detailResponse.body.refNo !== requestRefNo) continue
162
+
163
+ return {
164
+ ...record,
165
+ ...detailResponse.body,
166
+ requestRefNo,
167
+ resRefNo: detailResponse.body.resRefNo || record.refNo,
168
+ }
169
+ }
170
+
171
+ throw new Error(`未查询到编号 ${requestRefNo} 对应的余额结果`)
172
+ }
173
+
174
+ function getPbcPositionRecords(body: PbcPositionQueryBody) {
175
+ if (Array.isArray(body)) return body
176
+
177
+ return body.resultList || []
178
+ }