imeik-bizui 2.8.1 → 2.8.3

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.
@@ -7,19 +7,17 @@
7
7
  <div v-loading="bootLoading" :class="['pbd', `pbd--${variant}`]">
8
8
  <div v-if="bootError" class="pbd-error">{{ bootError }}</div>
9
9
  <template v-else-if="overview">
10
- <div :class="['pbd-state', stateClass]">{{ stateText }}</div>
11
-
12
10
  <section class="pbd-stats" aria-label="预算汇总">
13
11
  <div class="pbd-stat">
14
- <div class="pbd-stat__value num">{{ formatMoney(overview.budgetAmount) }}</div>
12
+ <div class="pbd-stat__value num">{{ formatMoneyYuan(overview.budgetAmount) }}</div>
15
13
  <div class="pbd-stat__label">总预算</div>
16
14
  </div>
17
15
  <div class="pbd-stat" :class="{ 'is-used-danger': isForbid }">
18
- <div class="pbd-stat__value num">{{ formatMoney(overview.usedAmount) }}</div>
16
+ <div class="pbd-stat__value num">{{ formatMoneyYuan(overview.usedAmount) }}</div>
19
17
  <div class="pbd-stat__label">已使用</div>
20
18
  </div>
21
19
  <div class="pbd-stat" :class="{ 'is-remain-danger': remainDanger }">
22
- <div class="pbd-stat__value num">{{ formatMoney(overview.remainingAmountWithCurrent) }}</div>
20
+ <div class="pbd-stat__value num">{{ formatMoneyYuan(overview.remainingAmountWithCurrent) }}</div>
23
21
  <div class="pbd-stat__label">剩余可用</div>
24
22
  </div>
25
23
  </section>
@@ -109,7 +107,7 @@
109
107
  </div>
110
108
  <div class="pbd-total pbd-total--usage">
111
109
  <span>{{ usageTotalLabel }}</span>
112
- <strong>¥{{ formatMoneyPlain(usageTotalAmount) }}</strong>
110
+ <strong>{{ formatMoneyYuan(usageTotalAmount) }}</strong>
113
111
  </div>
114
112
  </section>
115
113
 
@@ -194,7 +192,7 @@
194
192
  </div>
195
193
  <div class="pbd-total pbd-total--perf">
196
194
  <span>{{ performanceTotalLabel }}</span>
197
- <strong>¥{{ formatMoneyPlain(performanceTotalAmount) }}</strong>
195
+ <strong>{{ formatMoneyYuan(performanceTotalAmount) }}</strong>
198
196
  </div>
199
197
  </section>
200
198
  </div>
@@ -212,8 +210,8 @@
212
210
  import {
213
211
  BUDGET_STATUS,
214
212
  formatDateTime,
215
- formatMoney,
216
213
  formatMoneyPlain,
214
+ formatMoneyYuan,
217
215
  normalizeBudgetStatus,
218
216
  parseAmount
219
217
  } from './format'
@@ -290,21 +288,6 @@ export default {
290
288
  isForbid() {
291
289
  return this.status === BUDGET_STATUS.FORBID
292
290
  },
293
- stateClass() {
294
- if (this.status === BUDGET_STATUS.FORBID) return 'is-deny'
295
- if (this.status === BUDGET_STATUS.WARN) return 'is-warn'
296
- return 'is-pass'
297
- },
298
- stateText() {
299
- const remain = parseAmount(this.overview && this.overview.remainingAmountWithCurrent)
300
- if (this.status === BUDGET_STATUS.FORBID) {
301
- const over = Number.isFinite(remain) && remain < 0 ? ` · 超出 ${formatMoney(String(Math.abs(remain)))}` : ''
302
- return `已超预算${over}`
303
- }
304
- if (this.status === BUDGET_STATUS.WARN) return '预算预警 · 本年累计使用已超过预警值'
305
- if (this.status === BUDGET_STATUS.PASS) return '预算正常 · 本年累计使用未超过预警值'
306
- return (this.overview && this.overview.message) || '预算状态待确认'
307
- },
308
291
  remainDanger() {
309
292
  const n = parseAmount(this.overview && this.overview.remainingAmountWithCurrent)
310
293
  return Number.isFinite(n) && n < 0
@@ -365,7 +348,7 @@ export default {
365
348
  }
366
349
  },
367
350
  methods: {
368
- formatMoney,
351
+ formatMoneyYuan,
369
352
  formatMoneyPlain,
370
353
  formatDateTime,
371
354
  usageDateText(row) {
@@ -584,17 +567,6 @@ export default {
584
567
  color: #cf1322;
585
568
  font-size: 13px;
586
569
  }
587
- .pbd-state {
588
- padding: 7px 12px;
589
- margin-bottom: 12px;
590
- border-radius: 6px;
591
- font-size: 12px;
592
- line-height: 18px;
593
- word-break: break-word;
594
- &.is-pass { background: #f6ffed; color: #237804; }
595
- &.is-warn { background: #fffbe6; color: #d46b08; }
596
- &.is-deny { background: #fff1f0; color: #cf1322; }
597
- }
598
570
  .pbd-stats {
599
571
  display: grid;
600
572
  grid-template-columns: repeat(3, minmax(0, 1fr));
@@ -1,6 +1,6 @@
1
1
  <!--
2
- 个人预算概述看板 UI(对齐原型:通过/预警/禁止 + 进度条 + 查看详情)
3
- 移动端布局对齐费率 / 底价:标题行钉详情链、说明与金额独立成行、进度条可叠放
2
+ 个人预算概述看板 UI(对齐费率:状态+说明同行,金额+剩余chip同行,进度条右侧剩余%)
3
+ 移动端:标题行钉详情链,进度条满宽叠放;status 空值展示 '-'
4
4
  -->
5
5
  <template>
6
6
  <div class="person-budget-overview">
@@ -11,10 +11,12 @@
11
11
  <div :class="['pbo-head', { 'pbo-head--with-link': showDetailLink }]">
12
12
  <div class="pbo-head__main">
13
13
  <div class="pbo-head__row">
14
- <span class="pbo-icon">{{ statusMeta.icon }}</span>
15
- <span class="pbo-title">{{ statusMeta.title }}</span>
14
+ <span class="pbo-badge">
15
+ <span class="pbo-icon" aria-hidden="true">{{ statusMeta.icon }}</span>
16
+ <span class="pbo-title">{{ statusMeta.title }}</span>
17
+ </span>
18
+ <span v-if="statusDesc" class="pbo-desc">{{ statusDesc }}</span>
16
19
  </div>
17
- <p class="pbo-desc">{{ statusDesc }}</p>
18
20
  </div>
19
21
  <el-button
20
22
  v-if="showDetailLink"
@@ -26,35 +28,37 @@
26
28
 
27
29
  <div v-if="!accountExists" class="pbo-account-tip">当前费用承担人该年度尚未建账</div>
28
30
 
29
- <div class="pbo-line2">
30
- <div class="pbo-line2__text">
31
- <span class="pbo-line2__label">本年累计使用(含本次)</span>
32
- <b class="pbo-money">{{ formatMoney(overview.usedAmount) }}</b>
33
- <span class="pbo-sep">/</span>
34
- <span class="pbo-line2__label">总预算</span>
35
- <b class="pbo-money">{{ formatMoney(overview.budgetAmount) }}</b>
31
+ <div class="pbo-metrics">
32
+ <div class="pbo-line2">
33
+ <div class="pbo-line2__text">
34
+ <span class="pbo-line2__label">本年累计使用(含本次):</span>
35
+ <b class="pbo-money">{{ formatMoneyYuan(overview.usedAmount) }}</b>
36
+ <span class="pbo-sep">/</span>
37
+ <span class="pbo-line2__label">总预算</span>
38
+ <b class="pbo-money">{{ formatMoneyYuan(overview.budgetAmount) }}</b>
39
+ <span :class="['pbo-chip', remainingChipDanger ? 'is-danger' : '']">
40
+ 剩余 {{ formatMoneyYuan(overview.remainingAmountWithCurrent) }}
41
+ </span>
42
+ </div>
36
43
  </div>
37
- <span :class="['pbo-chip', remainingChipDanger ? 'is-danger' : '']">
38
- 剩余 {{ formatMoney(overview.remainingAmountWithCurrent) }}
39
- </span>
40
- </div>
41
44
 
42
- <div class="pbo-bar-row">
43
- <div class="pbo-bar-col">
44
- <div class="pbo-bar">
45
- <div class="pbo-bar__fill" :style="{ width: fillWidth + '%' }" />
46
- <div
47
- v-if="showWarnTick"
48
- class="pbo-bar__tick"
49
- :style="{ left: warnTickPercent + '%' }"
50
- :title="'预警值:' + formatMoney(warnAmount)"
51
- />
52
- </div>
53
- <div v-if="showWarnTick" class="pbo-scale">
54
- <span
55
- :class="['pbo-scale__sc', warnScaleClass]"
56
- :style="{ left: warnTickPercent + '%' }"
57
- >预警值:{{ formatMoney(warnAmount) }}</span>
45
+ <div class="pbo-bar-row">
46
+ <div class="pbo-bar-col">
47
+ <div class="pbo-bar">
48
+ <div class="pbo-bar__fill" :style="{ width: fillWidth + '%' }" />
49
+ <div
50
+ v-if="showWarnTick"
51
+ class="pbo-bar__tick"
52
+ :style="{ left: warnTickPercent + '%' }"
53
+ :title="'预警值:' + formatMoneyYuan(warnAmount)"
54
+ />
55
+ </div>
56
+ <div v-if="showWarnTick" class="pbo-scale">
57
+ <span
58
+ :class="['pbo-scale__sc', warnScaleClass]"
59
+ :style="{ left: warnTickPercent + '%' }"
60
+ >预警值:{{ formatMoneyYuan(warnAmount) }}</span>
61
+ </div>
58
62
  </div>
59
63
  </div>
60
64
  <span class="pbo-bar-label">{{ barLabel }}</span>
@@ -66,7 +70,7 @@
66
70
  <script>
67
71
  import {
68
72
  BUDGET_STATUS,
69
- formatMoney,
73
+ formatMoneyYuan,
70
74
  formatPercent,
71
75
  normalizeBudgetStatus,
72
76
  parseAmount
@@ -173,7 +177,7 @@ export default {
173
177
  }
174
178
  },
175
179
  methods: {
176
- formatMoney
180
+ formatMoneyYuan
177
181
  }
178
182
  }
179
183
  </script>
@@ -241,37 +245,54 @@ export default {
241
245
  display: flex;
242
246
  align-items: center;
243
247
  flex-wrap: wrap;
244
- gap: 8px;
248
+ gap: 8px 10px;
245
249
  min-width: 0;
246
250
  }
251
+ /* 对齐费率:图标 + 状态文案收成同一徽章,垂直居中 */
252
+ .pbo-badge {
253
+ display: inline-flex;
254
+ align-items: center;
255
+ flex: none;
256
+ gap: 6px;
257
+ min-height: 24px;
258
+ padding: 2px 10px 2px 8px;
259
+ border-radius: 12px;
260
+ box-sizing: border-box;
261
+ line-height: 1;
262
+ }
263
+ .is-pass .pbo-badge { background: #dcf5cf; }
264
+ .is-warn .pbo-badge { background: #ffefc2; }
265
+ .is-deny .pbo-badge { background: #ffd9d6; }
266
+ /* 对齐费率:小实心圆点,不放字符 */
247
267
  .pbo-icon {
248
- width: 22px;
249
- height: 22px;
268
+ width: 6px;
269
+ height: 6px;
250
270
  border-radius: 50%;
251
271
  flex: none;
252
- display: inline-flex;
253
- align-items: center;
254
- justify-content: center;
255
- color: #fff;
256
- font-size: 13px;
257
- font-weight: 700;
272
+ display: inline-block;
273
+ font-size: 0;
274
+ line-height: 0;
275
+ overflow: hidden;
276
+ color: transparent;
258
277
  }
259
278
  .is-pass .pbo-icon { background: #00b578; }
260
279
  .is-warn .pbo-icon { background: #ff8f1f; }
261
280
  .is-deny .pbo-icon { background: #fa5151; }
262
281
  .pbo-title {
263
- font-size: 15px;
282
+ font-size: 13px;
264
283
  font-weight: 600;
265
- line-height: 22px;
284
+ line-height: 16px;
266
285
  }
267
- .is-pass .pbo-title { color: #00b578; }
268
- .is-warn .pbo-title { color: #ff8f1f; }
269
- .is-deny .pbo-title { color: #fa5151; }
286
+ .is-pass .pbo-title { color: #237804; }
287
+ .is-warn .pbo-title { color: #d46b08; }
288
+ .is-deny .pbo-title { color: #cf1322; }
270
289
  .pbo-desc {
271
- margin: 6px 0 0;
290
+ margin: 0;
272
291
  font-size: 12px;
273
- line-height: 18px;
292
+ line-height: 24px;
274
293
  color: #646a73;
294
+ flex: 1 1 auto;
295
+ min-width: 0;
275
296
  word-break: break-word;
276
297
  overflow-wrap: anywhere;
277
298
  }
@@ -290,12 +311,20 @@ export default {
290
311
  color: #d46b08;
291
312
  word-break: break-word;
292
313
  }
293
- .pbo-line2 {
294
- display: flex;
314
+ .pbo-metrics {
315
+ display: grid;
316
+ grid-template-columns: minmax(0, 1fr) auto;
317
+ grid-template-rows: auto auto;
295
318
  align-items: center;
296
- flex-wrap: wrap;
297
- gap: 8px 12px;
319
+ column-gap: 16px;
320
+ row-gap: 14px;
298
321
  margin-top: 12px;
322
+ min-width: 0;
323
+ max-width: 100%;
324
+ }
325
+ .pbo-line2 {
326
+ grid-column: 1 / -1;
327
+ grid-row: 1;
299
328
  font-size: 13.5px;
300
329
  color: #1f2329;
301
330
  min-width: 0;
@@ -304,10 +333,9 @@ export default {
304
333
  .pbo-line2__text {
305
334
  display: inline-flex;
306
335
  flex-wrap: wrap;
307
- align-items: baseline;
308
- gap: 4px 6px;
336
+ align-items: center;
337
+ gap: 4px 8px;
309
338
  min-width: 0;
310
- flex: 1 1 220px;
311
339
  line-height: 1.65;
312
340
  word-break: break-word;
313
341
  overflow-wrap: anywhere;
@@ -320,6 +348,9 @@ export default {
320
348
  font-variant-numeric: tabular-nums;
321
349
  white-space: nowrap;
322
350
  }
351
+ .is-pass .pbo-money { color: #00b578; }
352
+ .is-warn .pbo-money { color: #ff8f1f; }
353
+ .is-deny .pbo-money { color: #fa5151; }
323
354
  .pbo-sep {
324
355
  color: #8f959e;
325
356
  }
@@ -329,23 +360,19 @@ export default {
329
360
  padding: 3px 10px;
330
361
  border-radius: 12px;
331
362
  white-space: nowrap;
332
- flex-shrink: 0;
363
+ line-height: 1.4;
333
364
  }
334
365
  .is-pass .pbo-chip { background: #dcf5cf; color: #237804; }
335
366
  .is-warn .pbo-chip { background: #ffefc2; color: #d46b08; }
336
367
  .is-deny .pbo-chip { background: #ffd9d6; color: #cf1322; }
337
368
  .pbo-chip.is-danger { background: #ffd9d6; color: #cf1322; }
338
369
  .pbo-bar-row {
339
- display: flex;
340
- flex-wrap: wrap;
341
- align-items: center;
342
- gap: 8px 12px;
343
- margin-top: 14px;
370
+ grid-column: 1;
371
+ grid-row: 2;
344
372
  min-width: 0;
345
373
  max-width: 100%;
346
374
  }
347
375
  .pbo-bar-col {
348
- flex: 1 1 0;
349
376
  min-width: 0;
350
377
  }
351
378
  .pbo-bar {
@@ -388,11 +415,16 @@ export default {
388
415
  &.is-right { transform: translateX(-100%); margin-right: 6px; }
389
416
  }
390
417
  .pbo-bar-label {
391
- flex: 0 0 auto;
418
+ grid-column: 2;
419
+ grid-row: 2;
420
+ justify-self: end;
421
+ align-self: start;
392
422
  font-size: 12px;
393
423
  font-weight: 700;
394
424
  white-space: nowrap;
395
425
  line-height: 1.2;
426
+ /* 与 8px 进度条视觉居中 */
427
+ margin-top: -3px;
396
428
  }
397
429
  .is-pass .pbo-bar-label { color: #00b578; }
398
430
  .is-warn .pbo-bar-label { color: #ff8f1f; }
@@ -421,35 +453,29 @@ export default {
421
453
  min-height: 22px;
422
454
  }
423
455
 
424
- .pbo-desc {
425
- margin-top: 4px;
426
- }
427
-
428
- .pbo-line2 {
456
+ .pbo-metrics {
457
+ grid-template-columns: minmax(0, 1fr);
458
+ grid-template-rows: auto;
429
459
  margin-top: 10px;
430
- gap: 8px;
431
- }
432
-
433
- .pbo-line2__text {
434
- flex: 1 1 100%;
435
- font-size: 13px;
436
- }
437
-
438
- .pbo-chip {
439
- flex: 0 0 auto;
460
+ row-gap: 8px;
461
+ column-gap: 0;
440
462
  }
441
463
 
442
- .pbo-bar-row {
443
- margin-top: 12px;
464
+ .pbo-line2,
465
+ .pbo-bar-row,
466
+ .pbo-bar-label {
467
+ grid-column: 1;
468
+ grid-row: auto;
469
+ justify-self: stretch;
444
470
  }
445
471
 
446
- .pbo-bar-col {
447
- flex: 1 1 100%;
448
- width: 100%;
472
+ .pbo-bar-label {
473
+ justify-self: start;
474
+ margin-top: 0;
449
475
  }
450
476
 
451
- .pbo-bar-label {
452
- flex: 1 1 auto;
477
+ .pbo-line2__text {
478
+ font-size: 13px;
453
479
  }
454
480
 
455
481
  .pbo-scale__sc {
@@ -32,12 +32,18 @@ function formatAmountFixed2(value) {
32
32
  return `${neg ? '-' : ''}${withComma}.${decPart}`
33
33
  }
34
34
 
35
- /** null/空展示 —;展示固定两位小数 */
35
+ /** null/空展示 —;展示固定两位小数,前缀 ¥ */
36
36
  export function formatMoney(value) {
37
37
  const formatted = formatAmountFixed2(value)
38
38
  return formatted == null ? '—' : `¥ ${formatted}`
39
39
  }
40
40
 
41
+ /** 对齐费率文案:248,601.00 元 */
42
+ export function formatMoneyYuan(value) {
43
+ const formatted = formatAmountFixed2(value)
44
+ return formatted == null ? '—' : `${formatted} 元`
45
+ }
46
+
41
47
  export function formatMoneyPlain(value) {
42
48
  const formatted = formatAmountFixed2(value)
43
49
  return formatted == null ? '—' : formatted