imeik-bizui 2.6.3 → 2.6.5

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.
@@ -10,7 +10,12 @@
10
10
  <span class="fpb-title__text">{{ title }}</span>
11
11
  </div>
12
12
 
13
- <div v-loading="loading" class="fpb-body">
13
+ <div
14
+ v-loading="loading"
15
+ class="fpb-body"
16
+ :class="{ 'fpb-body--loading': loading }"
17
+ element-loading-text="加载中..."
18
+ >
14
19
  <div v-if="error" class="fpb-msg fpb-msg--error">{{ error }}</div>
15
20
 
16
21
  <div v-else-if="hasContent" :class="['fpb-panel', panelThemeClass]" role="status">
@@ -406,10 +411,21 @@ export default {
406
411
  }
407
412
 
408
413
  .fpb-body {
414
+ position: relative;
409
415
  min-width: 0;
410
416
  max-width: 100%;
411
417
  }
412
418
 
419
+ /* loading 时内容为空会高度塌陷,spinner 会溢出到下方区块;对齐费率看板预留占位 */
420
+ .fpb-body--loading {
421
+ min-height: 80px;
422
+
423
+ /* Element 默认 loading 文案 margin 过小,和转圈贴在一起 */
424
+ ::v-deep .el-loading-spinner .el-loading-text {
425
+ margin-top: 12px;
426
+ }
427
+ }
428
+
413
429
  .fpb-msg {
414
430
  padding: 12px 16px;
415
431
  font-size: 13px;
@@ -167,6 +167,7 @@ export default {
167
167
  const raw = this.innerDetail || this.detail
168
168
  if (!raw) return EMPTY_DETAIL
169
169
  return normalizeDetail(raw, {
170
+ // 优先接口 customName(在 normalizeDetail 内读取);prop / 概览作兜底
170
171
  customerName: this.customerName || this.board.customerName,
171
172
  // 顶部汇总取概览产品行(与看板同源),明细接口只负责三区列表
172
173
  overviewProducts: this.board.products
@@ -280,10 +281,10 @@ export default {
280
281
  }
281
282
  const res = await this.fetchDetail(detailPayload)
282
283
  if (res && res.code === 200) {
284
+ // 保留接口 customName,勿用空 prop 覆盖
283
285
  this.innerDetail = {
284
286
  ...base,
285
- ...(res.data || {}),
286
- customerName: this.customerName
287
+ ...(res.data || {})
287
288
  }
288
289
  } else {
289
290
  throw new Error((res && res.message) || '底价明细获取失败')
@@ -9,11 +9,11 @@
9
9
  <el-dialog
10
10
  :visible.sync="dialogVisible"
11
11
  :title="title"
12
- :width="width"
13
- :top="top"
12
+ :width="resolvedWidth"
13
+ :top="resolvedTop"
14
14
  :append-to-body="appendToBody"
15
15
  :destroy-on-close="destroyOnClose"
16
- custom-class="floor-price-detail-dialog"
16
+ :custom-class="dialogCustomClass"
17
17
  @close="onClose"
18
18
  >
19
19
  <div v-loading="loading" class="fpd-body">
@@ -21,6 +21,7 @@
21
21
 
22
22
  <template v-else>
23
23
  <div v-if="summaryColumns.length" class="fpd-summary">
24
+ <div v-if="isNarrow" class="fpd-summary__hint">汇总表可左右滑动</div>
24
25
  <el-table
25
26
  :data="summaryRows"
26
27
  border
@@ -37,7 +38,7 @@
37
38
  :min-width="col.minWidth || col.width || 100"
38
39
  :width="col.fixedWidth"
39
40
  :align="col.align || 'left'"
40
- :fixed="col.fixed"
41
+ :fixed="isNarrow ? false : col.fixed"
41
42
  show-overflow-tooltip
42
43
  >
43
44
  <template slot-scope="{ row }">
@@ -67,6 +68,7 @@
67
68
  <div class="fpd-section__head">
68
69
  <span class="fpd-section__title">{{ section.title }}</span>
69
70
  <span v-if="section.subtitle" class="fpd-section__subtitle">{{ section.subtitle }}</span>
71
+ <span v-if="isNarrow" class="fpd-section__hint">左右滑动查看完整信息</span>
70
72
  </div>
71
73
 
72
74
  <div class="fpd-section__table-wrap">
@@ -75,7 +77,7 @@
75
77
  border
76
78
  size="small"
77
79
  class="fpd-table"
78
- :height="tableHeight"
80
+ :height="resolvedTableHeight"
79
81
  :header-cell-style="headerCellStyle"
80
82
  >
81
83
  <el-table-column
@@ -101,7 +103,8 @@
101
103
  :total-count="sectionRowCount(section)"
102
104
  :page="sectionPage(section)"
103
105
  :page-size="pageSize"
104
- :reserve-space="anySectionNeedsPager"
106
+ :reserve-space="showPagerReserve"
107
+ :compact="isNarrow"
105
108
  @update:page="(p) => setSectionPage(section, p)"
106
109
  />
107
110
 
@@ -213,7 +216,8 @@ export default {
213
216
  },
214
217
  data() {
215
218
  return {
216
- sectionPages: {}
219
+ sectionPages: {},
220
+ isNarrow: false
217
221
  }
218
222
  },
219
223
  computed: {
@@ -225,6 +229,22 @@ export default {
225
229
  this.$emit('update:visible', val)
226
230
  }
227
231
  },
232
+ dialogCustomClass() {
233
+ return this.isNarrow
234
+ ? 'floor-price-detail-dialog floor-price-detail-dialog--narrow'
235
+ : 'floor-price-detail-dialog'
236
+ },
237
+ resolvedWidth() {
238
+ return this.isNarrow ? 'calc(100% - 28px)' : this.width
239
+ },
240
+ resolvedTop() {
241
+ return this.isNarrow ? '5vh' : this.top
242
+ },
243
+ resolvedTableHeight() {
244
+ const base = Number(this.tableHeight)
245
+ const fallback = Number.isFinite(base) && base > 0 ? base : 260
246
+ return this.isNarrow ? Math.min(fallback, 200) : fallback
247
+ },
228
248
  formulaList() {
229
249
  if (Array.isArray(this.formulas)) return this.formulas
230
250
  return DEFAULT_DETAIL_FORMULAS
@@ -234,6 +254,10 @@ export default {
234
254
  const size = this.pageSize || 5
235
255
  return (this.sections || []).some((section) => this.sectionRowCount(section) > size)
236
256
  },
257
+ /** 窄屏三区已改为单列,无需为空分页占位 */
258
+ showPagerReserve() {
259
+ return this.anySectionNeedsPager && !this.isNarrow
260
+ },
237
261
  headerCellStyle() {
238
262
  return {
239
263
  background: '#fafbfc',
@@ -245,7 +269,10 @@ export default {
245
269
  },
246
270
  watch: {
247
271
  visible(val) {
248
- if (val) this.resetSectionPages()
272
+ if (val) {
273
+ this.updateNarrow()
274
+ this.resetSectionPages()
275
+ }
249
276
  },
250
277
  sections: {
251
278
  deep: true,
@@ -254,7 +281,22 @@ export default {
254
281
  }
255
282
  }
256
283
  },
284
+ mounted() {
285
+ this.updateNarrow()
286
+ if (typeof window !== 'undefined') {
287
+ window.addEventListener('resize', this.updateNarrow)
288
+ }
289
+ },
290
+ beforeDestroy() {
291
+ if (typeof window !== 'undefined') {
292
+ window.removeEventListener('resize', this.updateNarrow)
293
+ }
294
+ },
257
295
  methods: {
296
+ updateNarrow() {
297
+ if (typeof window === 'undefined') return
298
+ this.isNarrow = window.innerWidth <= 768
299
+ },
258
300
  onClose() {
259
301
  this.$emit('close')
260
302
  this.$emit('update:visible', false)
@@ -392,6 +434,41 @@ export default {
392
434
  border: none;
393
435
  }
394
436
  }
437
+
438
+ @media (max-width: 768px) {
439
+ .floor-price-detail-dialog.floor-price-detail-dialog--narrow {
440
+ width: calc(100% - 28px) !important;
441
+ max-width: 560px;
442
+ margin-bottom: 5vh !important;
443
+ border-radius: 14px;
444
+ border: 1px solid #e4e7ec;
445
+ box-shadow: 0 18px 48px rgba(16, 24, 40, 0.2);
446
+
447
+ .el-dialog__header {
448
+ padding: 14px 16px 12px;
449
+ background: #fff;
450
+ }
451
+
452
+ .el-dialog__title {
453
+ font-size: 16px;
454
+ line-height: 24px;
455
+ padding-right: 28px;
456
+ letter-spacing: 0.01em;
457
+ }
458
+
459
+ .el-dialog__headerbtn {
460
+ top: 15px;
461
+ right: 14px;
462
+ }
463
+
464
+ .el-dialog__body {
465
+ padding: 12px 12px 16px;
466
+ max-height: calc(90vh - 64px);
467
+ background: linear-gradient(180deg, #f4f6f8 0%, #f7f8fa 40%, #f7f8fa 100%);
468
+ -webkit-overflow-scrolling: touch;
469
+ }
470
+ }
471
+ }
395
472
  </style>
396
473
 
397
474
  <style lang="scss" scoped>
@@ -415,11 +492,16 @@ export default {
415
492
  .fpd-summary {
416
493
  margin-bottom: 12px;
417
494
  overflow-x: auto;
495
+ -webkit-overflow-scrolling: touch;
418
496
  background: #fff;
419
497
  border: 1px solid #e5e7eb;
420
498
  border-radius: 8px;
421
499
  }
422
500
 
501
+ .fpd-summary__hint {
502
+ display: none;
503
+ }
504
+
423
505
  .fpd-sections {
424
506
  display: grid;
425
507
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.05fr) minmax(0, 0.9fr);
@@ -464,10 +546,15 @@ export default {
464
546
  color: #8f959e;
465
547
  }
466
548
 
549
+ .fpd-section__hint {
550
+ display: none;
551
+ }
552
+
467
553
  .fpd-section__table-wrap {
468
554
  flex: 0 0 auto;
469
555
  min-width: 0;
470
- overflow-x: hidden;
556
+ overflow-x: auto;
557
+ -webkit-overflow-scrolling: touch;
471
558
  }
472
559
 
473
560
  .fpd-section__footer {
@@ -651,4 +738,160 @@ export default {
651
738
  grid-template-columns: 1fr;
652
739
  }
653
740
  }
741
+
742
+ @media (max-width: 768px) {
743
+ .fpd-summary {
744
+ margin-bottom: 12px;
745
+ border-radius: 10px;
746
+ border-color: #e8ebf0;
747
+ box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
748
+ }
749
+
750
+ .fpd-summary__hint,
751
+ .fpd-section__hint {
752
+ display: block;
753
+ padding: 0;
754
+ font-size: 11px;
755
+ line-height: 16px;
756
+ color: #8f959e;
757
+ font-weight: 400;
758
+ }
759
+
760
+ .fpd-summary__hint {
761
+ padding: 8px 12px 0;
762
+ }
763
+
764
+ .fpd-sections {
765
+ gap: 12px;
766
+ margin-bottom: 12px;
767
+ align-items: start;
768
+ }
769
+
770
+ .fpd-section {
771
+ min-height: 0;
772
+ border-radius: 10px;
773
+ border-color: #e8ebf0;
774
+ box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
775
+ }
776
+
777
+ .fpd-section--purple {
778
+ border-color: #e4e0f5;
779
+
780
+ .fpd-section__head {
781
+ background: linear-gradient(90deg, #f6f4ff 0%, #fafbfc 48%);
782
+ border-bottom-color: #ece8f8;
783
+ }
784
+
785
+ .fpd-section__title::before {
786
+ background: #7b61ff;
787
+ }
788
+
789
+ .fpd-section__footer {
790
+ background: #f8f6ff;
791
+ border-top-color: #ece8f8;
792
+ }
793
+ }
794
+
795
+ .fpd-section--danger {
796
+ border-color: #f3d6d2;
797
+
798
+ .fpd-section__head {
799
+ background: linear-gradient(90deg, #fff6f5 0%, #fafbfc 48%);
800
+ border-bottom-color: #f3e0dd;
801
+ }
802
+
803
+ .fpd-section__title::before {
804
+ background: #e45b4c;
805
+ }
806
+
807
+ .fpd-section__footer {
808
+ background: #fff8f7;
809
+ border-top-color: #f3e0dd;
810
+ }
811
+ }
812
+
813
+ .fpd-section__head {
814
+ padding: 10px 12px 8px;
815
+ gap: 4px;
816
+ }
817
+
818
+ .fpd-section__title {
819
+ display: flex;
820
+ align-items: center;
821
+ gap: 8px;
822
+ font-size: 14px;
823
+ line-height: 20px;
824
+
825
+ &::before {
826
+ content: '';
827
+ flex: none;
828
+ width: 3px;
829
+ height: 14px;
830
+ border-radius: 2px;
831
+ background: #3370ff;
832
+ }
833
+ }
834
+
835
+ .fpd-section__footer {
836
+ padding: 9px 12px;
837
+ font-size: 12px;
838
+ }
839
+
840
+ .fpd-section__footer-values {
841
+ font-size: 13px;
842
+ justify-content: flex-end;
843
+ }
844
+
845
+ .fpd-formulas {
846
+ padding: 10px 12px;
847
+ border-radius: 10px;
848
+ border-color: #e8ebf0;
849
+ font-size: 11px;
850
+ line-height: 18px;
851
+ color: #6b7280;
852
+ box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
853
+ }
854
+
855
+ ::v-deep .fpd-table {
856
+ .cell {
857
+ padding: 9px 10px;
858
+ line-height: 20px;
859
+ }
860
+
861
+ .is-right .cell {
862
+ padding-left: 8px;
863
+ padding-right: 12px;
864
+ }
865
+
866
+ .is-center .cell {
867
+ padding-left: 8px;
868
+ padding-right: 8px;
869
+ }
870
+
871
+ th {
872
+ font-size: 12px;
873
+ }
874
+
875
+ td {
876
+ font-size: 12px;
877
+ }
878
+ }
879
+
880
+ ::v-deep .fpd-table--summary {
881
+ min-width: 960px;
882
+
883
+ th .cell,
884
+ td .cell {
885
+ padding-top: 9px;
886
+ padding-bottom: 9px;
887
+ }
888
+ }
889
+
890
+ .fpd-status {
891
+ min-height: 20px;
892
+ min-width: 40px;
893
+ padding: 0 6px;
894
+ font-size: 11px;
895
+ }
896
+ }
654
897
  </style>
@@ -3,13 +3,22 @@
3
3
  <div
4
4
  v-if="needPager || reserveSpace"
5
5
  class="fpd-pager"
6
- :class="{ 'fpd-pager--placeholder': !needPager }"
6
+ :class="{
7
+ 'fpd-pager--placeholder': !needPager,
8
+ 'fpd-pager--compact': compact
9
+ }"
7
10
  >
8
11
  <template v-if="needPager">
9
12
  <span class="fpd-pager__total">共 {{ totalCount }} 条</span>
10
- <button type="button" class="fpd-pager__btn" :disabled="page <= 1" @click="goPrev">&lt; 上一页</button>
11
- <span class="fpd-pager__page">第 {{ page }} / {{ totalPages }} 页</span>
12
- <button type="button" class="fpd-pager__btn" :disabled="page >= totalPages" @click="goNext">下一页 &gt;</button>
13
+ <button type="button" class="fpd-pager__btn" :disabled="page <= 1" @click="goPrev">
14
+ {{ compact ? '< 上页' : '< 上一页' }}
15
+ </button>
16
+ <span class="fpd-pager__page">
17
+ {{ compact ? `${page}/${totalPages}` : `第 ${page} / ${totalPages} 页` }}
18
+ </span>
19
+ <button type="button" class="fpd-pager__btn" :disabled="page >= totalPages" @click="goNext">
20
+ {{ compact ? '下页 >' : '下一页 >' }}
21
+ </button>
13
22
  </template>
14
23
  </div>
15
24
  </template>
@@ -35,6 +44,11 @@ export default {
35
44
  reserveSpace: {
36
45
  type: Boolean,
37
46
  default: false
47
+ },
48
+ /** 窄屏紧凑文案 */
49
+ compact: {
50
+ type: Boolean,
51
+ default: false
38
52
  }
39
53
  },
40
54
  computed: {
@@ -77,6 +91,17 @@ export default {
77
91
  border-top-color: transparent;
78
92
  }
79
93
 
94
+ .fpd-pager--compact {
95
+ gap: 4px 8px;
96
+ padding: 6px 10px;
97
+ min-height: 36px;
98
+
99
+ .fpd-pager__btn {
100
+ min-height: 28px;
101
+ padding: 0 4px;
102
+ }
103
+ }
104
+
80
105
  .fpd-pager__total {
81
106
  margin-right: auto;
82
107
  }
@@ -172,8 +172,10 @@ function buildExpenseRows() {
172
172
 
173
173
  /** 模拟 getProductPriceDetail data */
174
174
  export function createDemoDetail(overview = {}) {
175
+ const name = overview.customerName || overview.customName || DEMO_CUSTOMER
175
176
  return {
176
- customerName: overview.customerName || DEMO_CUSTOMER,
177
+ customName: name,
178
+ customerName: name,
177
179
  saleOrderList: buildSalesOrderRows(),
178
180
  noSaleOrderList: buildNonSalesRows(),
179
181
  costList: buildExpenseRows()
@@ -83,7 +83,7 @@ export function normalizeOverview(data = {}, options = {}) {
83
83
  applyTotalFee: data.applyTotalFee,
84
84
  year: data.year,
85
85
  footerText: DEFAULT_FOOTER_TEXT,
86
- customerName: options.customerName || data.customerName || '',
86
+ customerName: options.customerName || data.customName || data.customerName || '',
87
87
  controlMethod: data.controlMethod
88
88
  }
89
89
  }
@@ -133,11 +133,11 @@ function buildSections(data = {}) {
133
133
  subtitle: '订单价 × 数量',
134
134
  theme: 'purple',
135
135
  columns: [
136
- { prop: 'orderNum', label: '订单号', minWidth: 120 },
137
- { prop: 'productName', label: '产品', minWidth: 80 },
136
+ { prop: 'orderNum', label: '订单号', minWidth: 140 },
137
+ { prop: 'productName', label: '产品', minWidth: 100 },
138
138
  { prop: 'saleTypeLabel', label: '类型', width: 64 },
139
139
  { prop: 'qty', label: '数量', align: 'right', width: 56 },
140
- { prop: 'amount', label: '金额', type: 'number', digits: 0, align: 'right', width: 88 }
140
+ { prop: 'amount', label: '金额', type: 'number', digits: 0, align: 'right', width: 96 }
141
141
  ],
142
142
  rows: saleRows,
143
143
  footer: {
@@ -154,10 +154,10 @@ function buildSections(data = {}) {
154
154
  subtitle: '折算非销售促进费',
155
155
  theme: 'danger',
156
156
  columns: [
157
- { prop: 'orderNum', label: '出库单号', minWidth: 120 },
158
- { prop: 'productName', label: '产品', minWidth: 80 },
157
+ { prop: 'orderNum', label: '出库单号', minWidth: 140 },
158
+ { prop: 'productName', label: '产品', minWidth: 100 },
159
159
  { prop: 'qty', label: '数量', align: 'right', width: 56 },
160
- { prop: 'amount', label: '折算费用', type: 'number', digits: 0, align: 'right', width: 88 }
160
+ { prop: 'amount', label: '折算费用', type: 'number', digits: 0, align: 'right', width: 96 }
161
161
  ],
162
162
  rows: nonSaleRows,
163
163
  footer: {
@@ -177,9 +177,9 @@ function buildSections(data = {}) {
177
177
  subtitle: '费用申请单口径',
178
178
  theme: 'danger',
179
179
  columns: [
180
- { prop: 'bizOrderCode', label: '单号', minWidth: 100 },
181
- { prop: 'costTypeName', label: '类型', minWidth: 80 },
182
- { prop: 'costAmount', label: '金额', type: 'number', digits: 0, align: 'right', width: 88 }
180
+ { prop: 'bizOrderCode', label: '单号', minWidth: 120 },
181
+ { prop: 'costTypeName', label: '类型', minWidth: 88 },
182
+ { prop: 'costAmount', label: '金额', type: 'number', digits: 0, align: 'right', width: 96 }
183
183
  ],
184
184
  rows: expenseRows,
185
185
  footer: {
@@ -196,7 +196,9 @@ function buildSections(data = {}) {
196
196
  * getProductPriceDetail data → DetailDialog
197
197
  */
198
198
  export function normalizeDetail(data = {}, options = {}) {
199
- const customerName = options.customerName || data.customerName || ''
199
+ // 详情标题优先接口 customName,其次外部传入 / customerName 兼容字段
200
+ const customerName =
201
+ data.customName || options.customerName || data.customerName || ''
200
202
  const overviewProducts = options.overviewProducts
201
203
  const summaryRows =
202
204
  Array.isArray(overviewProducts) && overviewProducts.length