minitest2.0 0.0.9 → 0.0.11

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.
@@ -5,12 +5,13 @@ import {
5
5
  type ForeignForecastDetailRecord,
6
6
  } from '@/api/foreign-position'
7
7
  import {
8
- formatForeignForecastAmountText,
9
- formatForeignForecastAmountYuanText,
10
8
  formatForeignForecastDate,
11
9
  resolveForeignBusinessType,
10
+ resolveForeignClientType,
12
11
  resolveForeignCurrency,
13
- resolveForeignStatus,
12
+ resolveForeignOriginalForeign,
13
+ resolveForeignPayDirection,
14
+ resolveForeignPaymentRoute,
14
15
  } from '@/utils/foreign-forecast'
15
16
  import { showAppToast } from '@/utils/toast'
16
17
 
@@ -23,6 +24,7 @@ type DetailField = {
23
24
 
24
25
  type DetailSection = {
25
26
  title: string
27
+ icon: string
26
28
  fields: DetailField[]
27
29
  }
28
30
 
@@ -35,12 +37,11 @@ const loading = ref(false)
35
37
  const loadError = ref(false)
36
38
  const currencyValue = computed(() => getRecordCurrency(detail.value))
37
39
  const currencyOption = computed(() => resolveForeignCurrency(currencyValue.value))
38
- const statusOption = computed(() => resolveForeignStatus(detail.value?.predStatus))
39
- const heroAmount = computed(() =>
40
- formatForeignForecastAmountText(detail.value?.predAmt, currencyValue.value),
40
+ const heroAmount = computed(() => fieldText(detail.value?.predAmt))
41
+ const businessTypeText = computed(() =>
42
+ resolveForeignBusinessType(detail.value?.tranType || detail.value?.busiType),
41
43
  )
42
- const heroAmountYuan = computed(() => formatForeignForecastAmountYuanText(detail.value?.predAmt))
43
- const heroDate = computed(() => formatForeignForecastDate(detail.value?.tranDate))
44
+ const payDirectionText = computed(() => resolveForeignPayDirection(detail.value?.payDirec))
44
45
 
45
46
  const detailSections = computed<DetailSection[]>(() => {
46
47
  const item = detail.value
@@ -50,65 +51,63 @@ const detailSections = computed<DetailSection[]>(() => {
50
51
  return [
51
52
  {
52
53
  title: '基础信息',
54
+ icon: 'orders-o',
53
55
  fields: [
54
- { label: '预报流水号', value: fieldText(item.predRefNo) },
55
- { label: '交易日期', value: formatForeignForecastDate(item.tranDate) },
56
+ { label: '预报人', value: fieldText(item.predCode || item.predName) },
57
+ {
58
+ label: '预报机构',
59
+ value: fieldText(item.predDept || item.predBranchName || item.predBranch),
60
+ },
61
+ { label: '联系电话', value: fieldText(item.phoneNo) },
62
+ {
63
+ label: '落地机构',
64
+ value: fieldText(item.groundBranchName || item.groundBranch),
65
+ },
56
66
  { label: '预报日期', value: formatForeignForecastDate(item.predDate) },
57
- { label: '预报状态', value: statusOption.value.label },
58
- { label: '核销状态', value: fieldText(item.verifyStatus) },
59
- { label: '额度标志', value: fieldText(item.eduFlag) },
60
- ],
61
- },
62
- {
63
- title: '机构与人员',
64
- fields: [
65
- { label: '预报机构', value: fieldText(item.predBranchName || item.predBranch) },
66
- { label: '预报机构代码', value: fieldText(item.predBranch) },
67
- { label: '预报人员编号', value: fieldText(item.predCode) },
68
- { label: '预报人员姓名', value: fieldText(item.predName) },
69
- { label: '落地机构名称', value: fieldText(item.groundBranch) },
70
- { label: '落地机构代码', value: fieldText(item.groundBranchCode) },
67
+ { label: '起息日', value: formatForeignForecastDate(item.tranDate) },
68
+ { label: '业务类型', value: businessTypeText.value },
69
+ { label: '预报金额(元)', value: heroAmount.value },
70
+ { label: '币种', value: currencyOption.value.label },
71
+ { label: '汇款路径', value: resolveForeignPaymentRoute(item.paymentRoute) },
72
+ { label: '收支方向', value: payDirectionText.value },
73
+ { label: '-', value: '-' },
71
74
  ],
72
75
  },
73
76
  {
74
- title: '业务与币种',
77
+ title: '交易/收款信息',
78
+ icon: 'records-o',
75
79
  fields: [
76
- { label: '币种', value: currencyOption.value.label },
77
- { label: '业务类型', value: resolveForeignBusinessType(item.busiType) },
78
- { label: '客户名称', value: fieldText(item.clientName) },
79
- { label: '交易对手名称', value: fieldText(item.competName) },
80
- { label: '交易对手账号', value: fieldText(item.competAcct) },
80
+ { label: '交易对手SwiftCode', value: fieldText(item.competAcctSc) },
81
81
  {
82
- label: '清算行 SWIFT',
83
- value: fieldText(item.bankSwift || item.swiftCode || item.bicCode),
82
+ label: '单证业务编号',
83
+ value: fieldText(item.docBusinessno || item.docbusinessno),
84
84
  },
85
- { label: '标准名称', value: fieldText(item.standardName) },
86
- { label: '用途', value: fieldText(item.purpose) },
87
- { label: '备注', value: fieldText(item.remark) },
85
+ { label: '收款人名称', value: fieldText(item.rcvName) },
86
+ { label: '收款账号', value: fieldText(item.rcvAcct) },
87
+ { label: '收款行名称', value: fieldText(item.rcvBank) },
88
+ { label: '收款行SwiftCode', value: fieldText(item.rcvBankSc) },
89
+ { label: '中间行SwiftCode', value: fieldText(item.midBankSc) },
90
+ { label: '-', value: '-' },
88
91
  ],
89
92
  },
90
93
  {
91
- title: '支付与金额',
94
+ title: '客户信息',
95
+ icon: 'manager-o',
92
96
  fields: [
93
- {
94
- label: '预报金额',
95
- value: formatForeignForecastAmountText(item.predAmt, currencyValue.value),
96
- },
97
- {
98
- label: '已核销金额',
99
- value: formatForeignForecastAmountText(item.verifyAmt, currencyValue.value),
100
- },
101
- { label: '支付渠道', value: fieldText(item.payChannel) },
102
- { label: '收支方向', value: fieldText(item.payDirec) },
97
+ { label: '客户账号', value: fieldText(item.clientAcct) },
98
+ { label: '客户名称', value: fieldText(item.clientName) },
99
+ { label: '客户类型', value: resolveForeignClientType(item.clientType) },
100
+ { label: '账户行', value: fieldText(item.bankAcct) },
101
+ { label: '结汇/购汇/现汇', value: resolveForeignOriginalForeign(item.originalForeign) },
102
+ { label: '-', value: '-' },
103
103
  ],
104
104
  },
105
105
  {
106
- title: '票据与联系',
106
+ title: '附加信息',
107
+ icon: 'notes-o',
107
108
  fields: [
108
- { label: '出票日', value: formatForeignForecastDate(item.billDate) },
109
- { label: '票号', value: fieldText(item.billNo) },
110
- { label: '联系人', value: fieldText(item.linkMan) },
111
- { label: '联系电话', value: fieldText(item.phoneNo) },
109
+ { label: '用途/原因', value: fieldText(item.purpose) },
110
+ { label: '备注', value: fieldText(item.remark) },
112
111
  ],
113
112
  },
114
113
  ]
@@ -160,6 +159,10 @@ function fieldText(value?: string) {
160
159
  const text = value?.trim()
161
160
  return text || '-'
162
161
  }
162
+
163
+ function handleEdit() {
164
+ showAppToast('编辑功能暂未开放')
165
+ }
163
166
  </script>
164
167
 
165
168
  <template>
@@ -170,13 +173,37 @@ function fieldText(value?: string) {
170
173
 
171
174
  <template v-else-if="detail">
172
175
  <section class="hero-card" aria-label="外币预报详情概要">
173
- <div class="hero-topline">
174
- <span class="status-tag" :class="statusOption.className">{{ statusOption.label }}</span>
175
- <span class="hero-date">{{ heroDate }}</span>
176
+ <div class="hero-primary">
177
+ <div class="hero-amount">
178
+ <span>预报金额(元)</span>
179
+ <strong>{{ heroAmount }}</strong>
180
+ </div>
181
+
182
+ <div class="hero-currency">
183
+ <span class="hero-icon"><van-icon name="gold-coin-o" /></span>
184
+ <span class="hero-copy">
185
+ <small>币种</small>
186
+ <strong>{{ currencyOption.label }}</strong>
187
+ </span>
188
+ </div>
189
+ </div>
190
+
191
+ <div class="hero-secondary">
192
+ <div class="hero-summary">
193
+ <span class="hero-icon"><van-icon name="exchange" /></span>
194
+ <span class="hero-copy">
195
+ <small>收支方向</small>
196
+ <strong>{{ payDirectionText }}</strong>
197
+ </span>
198
+ </div>
199
+ <div class="hero-summary">
200
+ <span class="hero-icon"><van-icon name="orders-o" /></span>
201
+ <span class="hero-copy">
202
+ <small>业务类型</small>
203
+ <strong>{{ businessTypeText }}</strong>
204
+ </span>
205
+ </div>
176
206
  </div>
177
- <strong>{{ heroAmount }}</strong>
178
- <span v-if="heroAmountYuan !== '-'" class="hero-amount-yuan">{{ heroAmountYuan }}</span>
179
- <p>{{ detail.predRefNo || predRefNo }}</p>
180
207
  </section>
181
208
 
182
209
  <section
@@ -185,14 +212,26 @@ function fieldText(value?: string) {
185
212
  class="detail-card"
186
213
  :aria-label="section.title"
187
214
  >
188
- <h2>{{ section.title }}</h2>
189
- <dl class="detail-list">
190
- <div v-for="field in section.fields" :key="`${section.title}-${field.label}`">
215
+ <header class="detail-card__header">
216
+ <van-icon :name="section.icon" />
217
+ <h2>{{ section.title }}</h2>
218
+ </header>
219
+ <dl class="detail-grid">
220
+ <div
221
+ v-for="field in section.fields"
222
+ :key="`${section.title}-${field.label}`"
223
+ class="detail-item"
224
+ >
191
225
  <dt>{{ field.label }}</dt>
192
- <dd>{{ field.value }}</dd>
226
+ <dd :title="field.value">{{ field.value }}</dd>
193
227
  </div>
194
228
  </dl>
195
229
  </section>
230
+
231
+ <footer class="action-bar">
232
+ <button class="back-btn" type="button" @click="router.back()">返回</button>
233
+ <button class="edit-btn" type="button" @click="handleEdit">编辑</button>
234
+ </footer>
196
235
  </template>
197
236
 
198
237
  <van-empty v-else image="error" :description="loadError ? '详情加载失败' : '详情不存在'">
@@ -210,17 +249,16 @@ function fieldText(value?: string) {
210
249
  max-width: 750px;
211
250
  min-height: var(--app-page-min-height, 100vh);
212
251
  margin: 0 auto;
213
- padding: 13px 13px calc(env(safe-area-inset-bottom, 0px) + 24px);
214
- color: #080d1f;
215
- background:
216
- radial-gradient(circle at 50% 0%, rgba(255, 242, 243, 0.92), transparent 118px),
217
- linear-gradient(180deg, #ffffff 0%, #fbfcfd 54%, #ffffff 100%);
252
+ padding: 13px 13px calc(env(safe-area-inset-bottom, 0px) + 84px);
253
+ color: #1c2029;
254
+ background: #f8f9fb;
218
255
  box-sizing: border-box;
219
256
  }
220
257
 
221
258
  button {
222
259
  border: 0;
223
260
  padding: 0;
261
+ font: inherit;
224
262
  background: transparent;
225
263
  appearance: none;
226
264
  }
@@ -232,159 +270,245 @@ button {
232
270
  }
233
271
 
234
272
  .hero-card {
235
- margin-top: 15px;
236
- border-radius: 13px;
237
- padding: 16px;
238
- color: #ffffff;
239
- background: linear-gradient(135deg, #f22f3d 0%, #ff5660 100%);
240
- box-shadow: 0 13px 28px rgba(244, 29, 48, 0.18);
273
+ overflow: hidden;
274
+ border: 1px solid #ffd1d5;
275
+ border-radius: 8px;
276
+ background: #fffafa;
277
+ box-shadow: 0 5px 14px rgba(38, 45, 61, 0.05);
241
278
  }
242
279
 
243
- .hero-topline {
244
- display: flex;
280
+ .hero-primary {
281
+ display: grid;
282
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);
245
283
  align-items: center;
246
- justify-content: space-between;
247
- gap: 10px;
284
+ min-height: 112px;
285
+ padding: 18px 16px 16px;
286
+ box-sizing: border-box;
248
287
  }
249
288
 
250
- .hero-card strong {
289
+ .hero-amount span,
290
+ .hero-copy small {
251
291
  display: block;
252
- margin-top: 18px;
253
- font-size: 27px;
254
- font-weight: 800;
255
- line-height: 1.1;
292
+ color: #4f535c;
293
+ font-size: 13px;
294
+ font-weight: 500;
295
+ line-height: 1.35;
256
296
  }
257
297
 
258
- .hero-amount-yuan {
298
+ .hero-amount strong {
259
299
  display: block;
260
300
  margin-top: 7px;
261
301
  overflow-wrap: anywhere;
262
- color: rgba(255, 255, 255, 0.74);
263
- font-size: 12px;
264
- font-weight: 500;
265
- line-height: 1.35;
302
+ color: #f12535;
303
+ font-size: 29px;
304
+ font-weight: 760;
305
+ line-height: 1.05;
266
306
  }
267
307
 
268
- .hero-card p {
308
+ .hero-currency,
309
+ .hero-summary {
310
+ display: flex;
311
+ align-items: center;
312
+ min-width: 0;
313
+ }
314
+
315
+ .hero-icon {
316
+ display: flex;
317
+ flex: 0 0 36px;
318
+ align-items: center;
319
+ justify-content: center;
320
+ width: 36px;
321
+ height: 36px;
322
+ border: 1px solid #ffd2d6;
323
+ border-radius: 50%;
324
+ color: #f22d3c;
325
+ background: #fff0f1;
326
+ font-size: 20px;
327
+ box-sizing: border-box;
328
+ }
329
+
330
+ .hero-copy {
331
+ min-width: 0;
332
+ margin-left: 10px;
333
+ }
334
+
335
+ .hero-copy strong {
336
+ display: block;
337
+ margin-top: 3px;
269
338
  overflow: hidden;
270
- margin: 10px 0 0;
271
- color: rgba(255, 255, 255, 0.82);
272
- font-size: 12px;
273
- line-height: 1.3;
339
+ color: #20242c;
340
+ font-size: 14px;
341
+ font-weight: 700;
342
+ line-height: 1.35;
274
343
  text-overflow: ellipsis;
275
344
  white-space: nowrap;
276
345
  }
277
346
 
278
- .hero-date {
279
- color: rgba(255, 255, 255, 0.88);
280
- font-size: 13px;
281
- font-weight: 650;
347
+ .hero-secondary {
348
+ display: grid;
349
+ grid-template-columns: repeat(2, minmax(0, 1fr));
350
+ min-height: 72px;
351
+ border-top: 1px solid #e8e8ea;
352
+ padding: 12px 16px;
353
+ box-sizing: border-box;
354
+ }
355
+
356
+ .hero-summary:nth-child(2) {
357
+ border-left: 1px solid #e4e5e8;
358
+ padding-left: 18px;
282
359
  }
283
360
 
284
361
  .detail-card {
285
362
  margin-top: 10px;
286
- border-radius: 13px;
287
- padding: 15px;
288
- background: rgba(255, 255, 255, 0.96);
289
- box-shadow: 0 7px 22px rgba(21, 28, 45, 0.055);
363
+ overflow: hidden;
364
+ border: 1px solid #e0e3e8;
365
+ border-radius: 8px;
366
+ background: #ffffff;
367
+ box-shadow: 0 4px 12px rgba(38, 45, 61, 0.04);
368
+ }
369
+
370
+ .detail-card__header {
371
+ display: flex;
372
+ align-items: center;
373
+ min-height: 42px;
374
+ border-bottom: 1px solid #e2e4e8;
375
+ padding: 0 13px;
376
+ box-sizing: border-box;
377
+ }
378
+
379
+ .detail-card__header .van-icon {
380
+ color: #f52b3b;
381
+ font-size: 20px;
290
382
  }
291
383
 
292
384
  .detail-card h2 {
293
- margin: 0;
294
- color: #111728;
385
+ margin: 0 0 0 8px;
386
+ color: #252932;
295
387
  font-size: 15px;
296
- font-weight: 760;
388
+ font-weight: 700;
297
389
  line-height: 1.2;
298
390
  }
299
391
 
300
- .detail-list {
301
- margin: 12px 0 0;
392
+ .detail-grid {
393
+ display: grid;
394
+ grid-template-columns: repeat(2, minmax(0, 1fr));
395
+ margin: 0;
396
+ padding: 0 12px;
302
397
  }
303
398
 
304
- .detail-list div {
399
+ .detail-item {
305
400
  display: grid;
306
- grid-template-columns: 96px minmax(0, 1fr);
307
- gap: 12px;
308
- padding: 10px 0;
309
- border-top: 1px solid #eef0f4;
401
+ grid-template-columns: max-content minmax(0, 1fr);
402
+ align-items: center;
403
+ min-width: 0;
404
+ min-height: 45px;
405
+ border-top: 1px solid #e7e8eb;
406
+ column-gap: 9px;
407
+ box-sizing: border-box;
310
408
  }
311
409
 
312
- .detail-list div:first-child {
410
+ .detail-item:nth-child(-n + 2) {
313
411
  border-top: 0;
314
412
  }
315
413
 
316
- .detail-list dt,
317
- .detail-list dd {
414
+ .detail-item:nth-child(odd) {
415
+ padding-right: 12px;
416
+ }
417
+
418
+ .detail-item:nth-child(even) {
419
+ padding-left: 12px;
420
+ }
421
+
422
+ .detail-item dt,
423
+ .detail-item dd {
424
+ min-width: 0;
318
425
  margin: 0;
319
426
  font-size: 13px;
320
- line-height: 1.42;
427
+ line-height: 1.35;
321
428
  }
322
429
 
323
- .detail-list dt {
324
- color: #7f8798;
430
+ .detail-item dt {
431
+ color: #555b66;
432
+ white-space: nowrap;
325
433
  }
326
434
 
327
- .detail-list dd {
328
- overflow-wrap: anywhere;
329
- color: #151827;
330
- font-weight: 650;
331
- text-align: right;
435
+ .detail-item dd {
436
+ overflow: hidden;
437
+ color: #292e38;
438
+ font-weight: 500;
439
+ text-overflow: ellipsis;
440
+ white-space: nowrap;
332
441
  }
333
442
 
334
- .status-tag {
335
- display: inline-flex;
443
+ .action-bar {
444
+ position: fixed;
445
+ right: max(13px, calc((100vw - 750px) / 2 + 13px));
446
+ bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
447
+ left: max(13px, calc((100vw - 750px) / 2 + 13px));
448
+ z-index: 18;
449
+ display: grid;
450
+ grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr);
451
+ gap: 14px;
452
+ }
453
+
454
+ .back-btn,
455
+ .edit-btn {
456
+ display: flex;
336
457
  align-items: center;
337
458
  justify-content: center;
338
- min-height: 20px;
339
- border: 1px solid transparent;
340
- border-radius: 4px;
341
- padding: 2px 7px;
342
- font-size: 11px;
343
- font-weight: 650;
344
- line-height: 1.25;
345
- white-space: nowrap;
459
+ height: 46px;
460
+ border-radius: 8px;
461
+ font-size: 15px;
462
+ font-weight: 700;
346
463
  }
347
464
 
348
- .status-tag-confirmed {
349
- border-color: #d8e1ee;
350
- color: #687083;
465
+ .back-btn {
466
+ border: 1px solid #e1e4e9;
467
+ color: #313640;
351
468
  background: #ffffff;
352
469
  }
353
470
 
354
- .status-tag-pending {
355
- border-color: #ffd99a;
356
- color: #a05a00;
357
- background: #fff4d8;
471
+ .edit-btn {
472
+ color: #ffffff;
473
+ background: #fa2838;
474
+ box-shadow: 0 7px 16px rgba(250, 40, 56, 0.18);
358
475
  }
359
476
 
360
- .status-tag-cancelled {
361
- border-color: #d6dbe3;
362
- color: #687083;
363
- background: #f3f5f8;
364
- }
477
+ @media (max-width: 360px) {
478
+ .detail-page {
479
+ padding-right: 10px;
480
+ padding-left: 10px;
481
+ }
365
482
 
366
- .status-tag-verified {
367
- border-color: #b7ebc9;
368
- color: #0b8f3a;
369
- background: #e4f8eb;
370
- }
483
+ .hero-primary,
484
+ .hero-secondary {
485
+ padding-right: 12px;
486
+ padding-left: 12px;
487
+ }
371
488
 
372
- .status-tag-rejected {
373
- border-color: #ffc0cb;
374
- color: #bf2549;
375
- background: #ffe8ed;
376
- }
489
+ .hero-summary:nth-child(2) {
490
+ padding-left: 12px;
491
+ }
377
492
 
378
- .status-tag-unknown {
379
- border-color: #d6dbe3;
380
- color: #687083;
381
- background: #f3f5f8;
382
- }
493
+ .detail-grid {
494
+ padding: 0 9px;
495
+ }
496
+
497
+ .detail-item {
498
+ column-gap: 6px;
499
+ }
500
+
501
+ .detail-item:nth-child(odd) {
502
+ padding-right: 7px;
503
+ }
504
+
505
+ .detail-item:nth-child(even) {
506
+ padding-left: 7px;
507
+ }
383
508
 
384
- @media (max-width: 340px) {
385
- .detail-list div {
386
- grid-template-columns: 84px minmax(0, 1fr);
387
- gap: 8px;
509
+ .detail-item dt,
510
+ .detail-item dd {
511
+ font-size: 12px;
388
512
  }
389
513
  }
390
514
  </style>