imeik-bizui 2.8.0 → 2.8.2

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
- * 会议系统底价接口(FieldFloorPriceBoard scene=meeting)
3
- * 总览 / 明细均为 POST,入参同形(与物资、申请中心一致)
4
- * 应答 data 与物资/申请中心同形,直接交给 normalize
2
+ * 会议系统接口(FieldFloorPriceBoard / FieldPersonBudgetBoard scene=meeting)
3
+ * 底价:总览 / 明细均为 POST,入参同形
4
+ * 个人预算:overview / usagePage / performancePage,入参对齐底价(forceRefresh + meetFormJson)
5
5
  */
6
6
  import request from '../utils/userRequest.js'
7
7
 
@@ -38,3 +38,55 @@ export function fetchMeetingBasePriceOverview(data) {
38
38
  export function fetchMeetingBasePriceDetail(payload) {
39
39
  return getBasePriceDetail(payload)
40
40
  }
41
+
42
+ /**
43
+ * 个人预算概述
44
+ * POST /qxcollege/meeting/personBudget/overview
45
+ * 入参对齐底价:forceRefresh + meetFormJson + meetTypeCode;meetCode / insFlowCode 有值才传
46
+ */
47
+ export function getPersonBudgetOverview(data) {
48
+ return request({
49
+ url: '/qxcollege/meeting/personBudget/overview',
50
+ method: 'post',
51
+ data
52
+ })
53
+ }
54
+
55
+ /**
56
+ * 个人预算使用明细分页
57
+ * POST /qxcollege/meeting/personBudget/usagePage
58
+ */
59
+ export function getPersonBudgetUsagePage(data) {
60
+ return request({
61
+ url: '/qxcollege/meeting/personBudget/usagePage',
62
+ method: 'post',
63
+ data
64
+ })
65
+ }
66
+
67
+ /**
68
+ * 个人预算业绩明细分页
69
+ * POST /qxcollege/meeting/personBudget/performancePage
70
+ */
71
+ export function getPersonBudgetPerformancePage(data) {
72
+ return request({
73
+ url: '/qxcollege/meeting/personBudget/performancePage',
74
+ method: 'post',
75
+ data
76
+ })
77
+ }
78
+
79
+ /** 个人预算概述:业务侧已拼好 requestPayload */
80
+ export function fetchMeetingPersonBudgetOverview(data) {
81
+ return getPersonBudgetOverview(data)
82
+ }
83
+
84
+ /** 个人预算使用明细分页 */
85
+ export function fetchMeetingPersonBudgetUsagePage(data) {
86
+ return getPersonBudgetUsagePage(data)
87
+ }
88
+
89
+ /** 个人预算业绩明细分页 */
90
+ export function fetchMeetingPersonBudgetPerformancePage(data) {
91
+ return getPersonBudgetPerformancePage(data)
92
+ }
@@ -10,7 +10,8 @@
10
10
 
11
11
  ```
12
12
  imeik-bizui/src/bizui/
13
- ├── api/mms.js # 物资/会议 getPersonBudgetOverview / UsagePage / PerformancePage
13
+ ├── api/mms.js # 物资 getPersonBudgetOverview / UsagePage / PerformancePage
14
+ ├── api/meeting.js # 会议 personBudget/overview|usagePage|performancePage
14
15
  ├── api/applycenter.js # 申请中心 openApi/personBudget/*
15
16
  └── src/
16
17
  └── FieldPersonBudgetBoard/
@@ -23,7 +24,7 @@ imeik-bizui/src/bizui/
23
24
 
24
25
  ```vue
25
26
  <FieldPersonBudgetBoard
26
- scene="supplies"
27
+ scene="meeting"
27
28
  :request-payload="payload"
28
29
  :show-detail-link="hasPerm"
29
30
  @submit-blocked="onBlocked"
@@ -34,16 +35,16 @@ imeik-bizui/src/bizui/
34
35
 
35
36
  `scene`:`supplies` | `meeting` | `apply` / `applyCenter`。
36
37
 
37
- 请求体组装在业务系统(如物资 / 申请中心 `buildRequestPayload.js`)。
38
+ 请求体组装在业务系统(如会议 `buildPersonBudgetPayload.js` / 物资 / 申请中心 `buildRequestPayload.js`)。
38
39
 
39
40
  ---
40
41
 
41
42
  ## 二、分层原则
42
43
 
43
- 1. **接口**在 `api/mms.js`(物资/会议)与 `api/applycenter.js`(申请中心)。
44
+ 1. **接口**在 `api/mms.js`(物资)、`api/meeting.js`(会议)、`api/applycenter.js`(申请中心)。
44
45
  2. **对外只注册** `FieldPersonBudgetBoard`;`index.vue` 按 `scene` 选 fetch。
45
46
  3. **宿主组装** `requestPayload` + 权限;不写 debounce / 看板 UI。
46
- 4. **bizui 不解析**各域表单字段(费用承担人、snapshotList、整表 formDataJson 等)。
47
+ 4. **bizui 不解析**各域表单字段(费用承担人、snapshotList、整表 meetFormJson / formDataJson 等)。
47
48
 
48
49
  ```
49
50
  业务系统:表单字段 → requestPayload
@@ -60,10 +61,12 @@ bizui: scene 选接口 → Dashboard 拉数 → Overview / Detail
60
61
  | Props | `scene`、`requestPayload`、`showDetailLink`、`narrowDetailMode`、`useMock`、`emptyText`、`debounceMs` |
61
62
  | Events | `submit-blocked`:`{ blocked, warn }`(禁止提交 / 预警) |
62
63
  | 明细形态 | 宽屏始终弹窗;窄屏(≤768px)由 `narrowDetailMode`:`inline`(默认)或 `dialog` |
63
- | 物资/会议 · 查看 | `{ applyNumber }`(真实申请单号,不是 objectCode) |
64
- | 物资/会议 · 实时 | `{ costBearEmployeeNo, costType, materialList[] }`;`materialList` **允许 `[]`**;可选 `budgetDate` |
64
+ | 物资 · 查看 | `{ applyNumber }`(真实申请单号,不是 objectCode) |
65
+ | 物资 · 实时 | `{ costBearEmployeeNo, costType, materialList[] }`;`materialList` **允许 `[]`**;可选 `budgetDate` |
66
+ | 会议 | `{ forceRefresh, meetTypeCode, meetFormJson, meetCode?, insFlowCode? }`(**对齐底价**;费用承担人/金额由后端从 `meetFormJson` 解析) |
65
67
  | 申请中心 | `{ forceRefresh, formDataJson?, formDataNumber? }`(`PersonBudgetQueryDTO`);明细另带 `usageCurrPage` / `performanceCurrPage` 等 |
66
68
  | 编辑态(物资) | **不传** `applyNumber`(即使草稿已有单号) |
69
+ | 编辑态(会议) | `forceRefresh=true`;`meetCode` **有值才传**(不作为读快照依据,分流看 `forceRefresh`) |
67
70
 
68
71
  ---
69
72
 
@@ -72,8 +75,8 @@ bizui: scene 选接口 → Dashboard 拉数 → Overview / Detail
72
75
  | 域 | scene | 接口 |
73
76
  | --- | --- | --- |
74
77
  | 物资 | `supplies` | `mms.getPersonBudgetOverview` / `UsagePage` / `PerformancePage` |
75
- | 会议 | `meeting` | 同上(传参同形) |
76
- | 申请中心 | `apply` / `applyCenter` | `applycenter` `openApi/personBudget/overview|usagePage|performancePage` |
78
+ | 会议 | `meeting` | `meeting` `personBudget/overview\|usagePage\|performancePage` |
79
+ | 申请中心 | `apply` / `applyCenter` | `applycenter` `openApi/personBudget/overview\|usagePage\|performancePage` |
77
80
 
78
81
  ---
79
82
 
@@ -98,6 +101,30 @@ export function buildSuppliesPersonBudgetPayload(ctx) {
98
101
  }
99
102
  ```
100
103
 
104
+ ### 会议(对齐底价 buildFloorPricePayload)
105
+
106
+ ```js
107
+ export function buildPersonBudgetPayload(options = {}) {
108
+ const meetTypeCode = String(options.meetTypeCode || '').trim()
109
+ if (!meetTypeCode) return null
110
+ const node = options.nodeFormJsonData || {}
111
+ const budget = options.budgetValue || node.meetingBudgetDTO
112
+ const meetFormSource = options.isAddBudget
113
+ ? { ...node, meetingBudgetDTO: budget }
114
+ : node
115
+ const payload = {
116
+ meetTypeCode,
117
+ meetFormJson: JSON.stringify(meetFormSource),
118
+ forceRefresh: !!options.forceRefresh
119
+ }
120
+ const meetCode = String(options.meetCode || '').trim()
121
+ if (meetCode) payload.meetCode = meetCode
122
+ const insFlowCode = String(options.insFlowCode || '').trim()
123
+ if (insFlowCode) payload.insFlowCode = insFlowCode
124
+ return payload
125
+ }
126
+ ```
127
+
101
128
  ### 申请中心
102
129
 
103
130
  ```js
@@ -290,6 +290,11 @@ export default {
290
290
  .person-budget-dashboard {
291
291
  width: 100%;
292
292
  max-width: 100%;
293
+ margin: 0 0 12px;
294
+ padding: 0;
295
+ box-sizing: border-box;
293
296
  min-width: 0;
297
+ /* 收起明细回滚时给宿主固定顶栏留位(对齐底价看板) */
298
+ scroll-margin-top: 80px;
294
299
  }
295
300
  </style>
@@ -371,15 +371,28 @@ export default {
371
371
  usageDateText(row) {
372
372
  return formatDateTime(row && row.lastPostingTime)
373
373
  },
374
- /** 是否申请中心 PersonBudgetQueryDTO 形(forceRefresh / formDataJson / formDataNumber) */
374
+ /** 是否申请中心 PersonBudgetQueryDTO 形(formDataJson / formDataNumber) */
375
375
  isApplyCenterPayload() {
376
376
  const p = this.requestPayload || {}
377
377
  return (
378
- Object.prototype.hasOwnProperty.call(p, 'forceRefresh') ||
379
378
  Object.prototype.hasOwnProperty.call(p, 'formDataJson') ||
380
379
  Object.prototype.hasOwnProperty.call(p, 'formDataNumber')
381
380
  )
382
381
  },
382
+ /**
383
+ * 是否会议形(对齐底价:forceRefresh + meetFormJson + meetTypeCode)
384
+ * 注意:不可仅凭 forceRefresh 判断,申请中心也有该字段
385
+ */
386
+ isMeetingPayload() {
387
+ const p = this.requestPayload || {}
388
+ if (this.isApplyCenterPayload()) return false
389
+ return (
390
+ Object.prototype.hasOwnProperty.call(p, 'meetFormJson') ||
391
+ Object.prototype.hasOwnProperty.call(p, 'meetTypeCode') ||
392
+ (Object.prototype.hasOwnProperty.call(p, 'forceRefresh') &&
393
+ Object.prototype.hasOwnProperty.call(p, 'meetCode'))
394
+ )
395
+ },
383
396
  /** 申请中心:透传查询主键字段 */
384
397
  applyCenterScopeBody() {
385
398
  const p = this.requestPayload || {}
@@ -393,10 +406,28 @@ export default {
393
406
  if (formDataNumber) body.formDataNumber = formDataNumber
394
407
  return body
395
408
  },
396
- /** 物资/会议 MMS 形 */
409
+ /** 会议:透传底价同形主键字段 */
410
+ meetingScopeBody() {
411
+ const p = this.requestPayload || {}
412
+ const body = {}
413
+ if (Object.prototype.hasOwnProperty.call(p, 'forceRefresh')) {
414
+ body.forceRefresh = !!p.forceRefresh
415
+ }
416
+ const meetTypeCode = p.meetTypeCode != null ? String(p.meetTypeCode).trim() : ''
417
+ if (meetTypeCode) body.meetTypeCode = meetTypeCode
418
+ const meetFormJson = p.meetFormJson != null ? String(p.meetFormJson) : ''
419
+ if (meetFormJson) body.meetFormJson = meetFormJson
420
+ const meetCode = p.meetCode != null ? String(p.meetCode).trim() : ''
421
+ if (meetCode) body.meetCode = meetCode
422
+ const insFlowCode = p.insFlowCode != null ? String(p.insFlowCode).trim() : ''
423
+ if (insFlowCode) body.insFlowCode = insFlowCode
424
+ return body
425
+ },
426
+ /** 物资 MMS 形 / 会议 / 申请中心 */
397
427
  scopeBody() {
398
428
  const p = this.requestPayload || {}
399
429
  if (this.isApplyCenterPayload()) return this.applyCenterScopeBody()
430
+ if (this.isMeetingPayload()) return this.meetingScopeBody()
400
431
  if (p.applyNumber) return { applyNumber: p.applyNumber }
401
432
  return {
402
433
  costBearEmployeeNo: p.costBearEmployeeNo,
@@ -408,6 +439,7 @@ export default {
408
439
  performanceScopeBody() {
409
440
  const p = this.requestPayload || {}
410
441
  if (this.isApplyCenterPayload()) return this.applyCenterScopeBody()
442
+ if (this.isMeetingPayload()) return this.meetingScopeBody()
411
443
  if (p.applyNumber) return { applyNumber: p.applyNumber }
412
444
  return {
413
445
  costBearEmployeeNo: p.costBearEmployeeNo,
@@ -26,35 +26,37 @@
26
26
 
27
27
  <div v-if="!accountExists" class="pbo-account-tip">当前费用承担人该年度尚未建账</div>
28
28
 
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>
29
+ <div class="pbo-metrics">
30
+ <div class="pbo-line2">
31
+ <div class="pbo-line2__text">
32
+ <span class="pbo-line2__label">本年累计使用(含本次)</span>
33
+ <b class="pbo-money">{{ formatMoney(overview.usedAmount) }}</b>
34
+ <span class="pbo-sep">/</span>
35
+ <span class="pbo-line2__label">总预算</span>
36
+ <b class="pbo-money">{{ formatMoney(overview.budgetAmount) }}</b>
37
+ </div>
36
38
  </div>
37
39
  <span :class="['pbo-chip', remainingChipDanger ? 'is-danger' : '']">
38
40
  剩余 {{ formatMoney(overview.remainingAmountWithCurrent) }}
39
41
  </span>
40
- </div>
41
42
 
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>
43
+ <div class="pbo-bar-row">
44
+ <div class="pbo-bar-col">
45
+ <div class="pbo-bar">
46
+ <div class="pbo-bar__fill" :style="{ width: fillWidth + '%' }" />
47
+ <div
48
+ v-if="showWarnTick"
49
+ class="pbo-bar__tick"
50
+ :style="{ left: warnTickPercent + '%' }"
51
+ :title="'预警值:' + formatMoney(warnAmount)"
52
+ />
53
+ </div>
54
+ <div v-if="showWarnTick" class="pbo-scale">
55
+ <span
56
+ :class="['pbo-scale__sc', warnScaleClass]"
57
+ :style="{ left: warnTickPercent + '%' }"
58
+ >预警值:{{ formatMoney(warnAmount) }}</span>
59
+ </div>
58
60
  </div>
59
61
  </div>
60
62
  <span class="pbo-bar-label">{{ barLabel }}</span>
@@ -290,12 +292,20 @@ export default {
290
292
  color: #d46b08;
291
293
  word-break: break-word;
292
294
  }
293
- .pbo-line2 {
294
- display: flex;
295
+ .pbo-metrics {
296
+ display: grid;
297
+ grid-template-columns: minmax(0, 1fr) auto;
298
+ grid-template-rows: auto auto;
295
299
  align-items: center;
296
- flex-wrap: wrap;
297
- gap: 8px 12px;
300
+ column-gap: 16px;
301
+ row-gap: 14px;
298
302
  margin-top: 12px;
303
+ min-width: 0;
304
+ max-width: 100%;
305
+ }
306
+ .pbo-line2 {
307
+ grid-column: 1;
308
+ grid-row: 1;
299
309
  font-size: 13.5px;
300
310
  color: #1f2329;
301
311
  min-width: 0;
@@ -307,7 +317,6 @@ export default {
307
317
  align-items: baseline;
308
318
  gap: 4px 6px;
309
319
  min-width: 0;
310
- flex: 1 1 220px;
311
320
  line-height: 1.65;
312
321
  word-break: break-word;
313
322
  overflow-wrap: anywhere;
@@ -324,28 +333,28 @@ export default {
324
333
  color: #8f959e;
325
334
  }
326
335
  .pbo-chip {
336
+ grid-column: 2;
337
+ grid-row: 1;
338
+ justify-self: end;
339
+ align-self: start;
327
340
  font-size: 12px;
328
341
  font-weight: 600;
329
342
  padding: 3px 10px;
330
343
  border-radius: 12px;
331
344
  white-space: nowrap;
332
- flex-shrink: 0;
345
+ line-height: 1.4;
333
346
  }
334
347
  .is-pass .pbo-chip { background: #dcf5cf; color: #237804; }
335
348
  .is-warn .pbo-chip { background: #ffefc2; color: #d46b08; }
336
349
  .is-deny .pbo-chip { background: #ffd9d6; color: #cf1322; }
337
350
  .pbo-chip.is-danger { background: #ffd9d6; color: #cf1322; }
338
351
  .pbo-bar-row {
339
- display: flex;
340
- flex-wrap: wrap;
341
- align-items: center;
342
- gap: 8px 12px;
343
- margin-top: 14px;
352
+ grid-column: 1;
353
+ grid-row: 2;
344
354
  min-width: 0;
345
355
  max-width: 100%;
346
356
  }
347
357
  .pbo-bar-col {
348
- flex: 1 1 0;
349
358
  min-width: 0;
350
359
  }
351
360
  .pbo-bar {
@@ -388,11 +397,16 @@ export default {
388
397
  &.is-right { transform: translateX(-100%); margin-right: 6px; }
389
398
  }
390
399
  .pbo-bar-label {
391
- flex: 0 0 auto;
400
+ grid-column: 2;
401
+ grid-row: 2;
402
+ justify-self: end;
403
+ align-self: start;
392
404
  font-size: 12px;
393
405
  font-weight: 700;
394
406
  white-space: nowrap;
395
407
  line-height: 1.2;
408
+ /* 与 8px 进度条视觉居中 */
409
+ margin-top: -3px;
396
410
  }
397
411
  .is-pass .pbo-bar-label { color: #00b578; }
398
412
  .is-warn .pbo-bar-label { color: #ff8f1f; }
@@ -425,31 +439,34 @@ export default {
425
439
  margin-top: 4px;
426
440
  }
427
441
 
428
- .pbo-line2 {
442
+ .pbo-metrics {
443
+ grid-template-columns: minmax(0, 1fr);
444
+ grid-template-rows: auto;
429
445
  margin-top: 10px;
430
- gap: 8px;
446
+ row-gap: 8px;
447
+ column-gap: 0;
431
448
  }
432
449
 
433
- .pbo-line2__text {
434
- flex: 1 1 100%;
435
- font-size: 13px;
450
+ .pbo-line2,
451
+ .pbo-chip,
452
+ .pbo-bar-row,
453
+ .pbo-bar-label {
454
+ grid-column: 1;
455
+ grid-row: auto;
456
+ justify-self: stretch;
436
457
  }
437
458
 
438
459
  .pbo-chip {
439
- flex: 0 0 auto;
460
+ justify-self: start;
440
461
  }
441
462
 
442
- .pbo-bar-row {
443
- margin-top: 12px;
444
- }
445
-
446
- .pbo-bar-col {
447
- flex: 1 1 100%;
448
- width: 100%;
463
+ .pbo-bar-label {
464
+ justify-self: start;
465
+ margin-top: 0;
449
466
  }
450
467
 
451
- .pbo-bar-label {
452
- flex: 1 1 auto;
468
+ .pbo-line2__text {
469
+ font-size: 13px;
453
470
  }
454
471
 
455
472
  .pbo-scale__sc {
@@ -40,10 +40,15 @@ import {
40
40
  getPersonBudgetUsagePage as getApplyPersonBudgetUsagePage,
41
41
  getPersonBudgetPerformancePage as getApplyPersonBudgetPerformancePage
42
42
  } from '../../api/applycenter'
43
+ import {
44
+ fetchMeetingPersonBudgetOverview,
45
+ fetchMeetingPersonBudgetUsagePage,
46
+ fetchMeetingPersonBudgetPerformancePage
47
+ } from '../../api/meeting'
43
48
 
44
49
  /**
45
50
  * scene → 个人预算接口
46
- * 物资 / 会议走 MMS;申请中心走 application-center openApi
51
+ * 物资走 MMS;会议走 qxcollege personBudget;申请中心走 application-center openApi
47
52
  */
48
53
  const MMS_PERSON_BUDGET = {
49
54
  fetchOverview: getMmsPersonBudgetOverview,
@@ -52,6 +57,13 @@ const MMS_PERSON_BUDGET = {
52
57
  emptyText: '请完善费用承担人和费用类型后查看个人预算'
53
58
  }
54
59
 
60
+ const MEETING_PERSON_BUDGET = {
61
+ fetchOverview: fetchMeetingPersonBudgetOverview,
62
+ fetchUsagePage: fetchMeetingPersonBudgetUsagePage,
63
+ fetchPerformancePage: fetchMeetingPersonBudgetPerformancePage,
64
+ emptyText: '请完善会议预算后查看个人预算'
65
+ }
66
+
55
67
  const APPLY_CENTER_PERSON_BUDGET = {
56
68
  fetchOverview: getApplyPersonBudgetOverview,
57
69
  fetchUsagePage: getApplyPersonBudgetUsagePage,
@@ -61,10 +73,7 @@ const APPLY_CENTER_PERSON_BUDGET = {
61
73
 
62
74
  const SCENE_API = {
63
75
  supplies: MMS_PERSON_BUDGET,
64
- meeting: {
65
- ...MMS_PERSON_BUDGET,
66
- emptyText: '请完善费用承担人和费用类型后查看个人预算'
67
- },
76
+ meeting: MEETING_PERSON_BUDGET,
68
77
  applyCenter: APPLY_CENTER_PERSON_BUDGET
69
78
  }
70
79
  SCENE_API.apply = SCENE_API.applyCenter
@@ -87,8 +96,9 @@ export default {
87
96
  },
88
97
  /**
89
98
  * 业务侧组装好的请求体;null 表示不发请求
90
- * 物资/会议查看:{ applyNumber }
91
- * 物资/会议实时:{ costBearEmployeeNo, costType, materialList[] }
99
+ * 物资查看:{ applyNumber }
100
+ * 物资实时:{ costBearEmployeeNo, costType, materialList[] }
101
+ * 会议:{ forceRefresh, meetTypeCode, meetFormJson, meetCode?, insFlowCode? }(对齐底价)
92
102
  * 申请中心:{ forceRefresh, formDataJson?, formDataNumber? }(PersonBudgetQueryDTO)
93
103
  */
94
104
  requestPayload: {