vue2-client 1.18.68 → 1.19.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.
@@ -12,8 +12,82 @@
12
12
  </a-button>
13
13
  </div>
14
14
 
15
- <!-- 当 layout 为数字时使用 a-descriptions -->
16
- <template v-if="config && config.layout && typeof config.layout === 'number' && !wrapperClassObject['xhdesc-medical-history']">
15
+ <!-- 当layout是对象格式且为5列时,使用自定义grid布局 -->
16
+ <template v-if="config && config.layout && typeof config.layout === 'object' && !Array.isArray(config.layout) && Object.values(config.layout).every(val => val === 5) && !wrapperClassObject['xhdesc-medical-history']">
17
+ <div class="grid-descriptions">
18
+ <template v-if="data">
19
+ <div
20
+ v-for="(row, rowIndex) in gridRows"
21
+ :key="'row-' + rowIndex"
22
+ class="grid-row"
23
+ :style="{ gridTemplateColumns: getGridTemplateColumns(getGridColumns()) }"
24
+ >
25
+ <div
26
+ v-for="(item, itemIndex) in row"
27
+ :key="'item-' + rowIndex + '-' + itemIndex"
28
+ class="grid-item"
29
+ >
30
+ <!-- 占位符项目 -->
31
+ <template v-if="!item.field || item.field === ''">
32
+ <div class="placeholder-content"></div>
33
+ </template>
34
+ <!-- 正常项目 -->
35
+ <template v-else-if="data[item.field] !== null && data[item.field] !== undefined">
36
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
37
+ <div v-if="item.showAvatar" class="gender-icon">
38
+ <img :src="maleIcon" alt="male" class="gender-img" />
39
+ </div>
40
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
41
+ </div>
42
+ <a-tooltip
43
+ v-if="isContentOverflow(data[item.field])"
44
+ :title="data[item.field]"
45
+ placement="topLeft"
46
+ :overlay-style="{ maxWidth: '400px' }"
47
+ >
48
+ <div
49
+ class="content-wrapper ellipsis"
50
+ :data-full-text="data[item.field]"
51
+ >
52
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
53
+ <div class="report-value">
54
+ {{ data[item.field] }}
55
+ </div>
56
+ <div class="report-unit">
57
+ {{ item.unit }}
58
+ </div>
59
+ </template>
60
+ <template v-else>
61
+ {{ data[item.field] }}
62
+ </template>
63
+ </div>
64
+ </a-tooltip>
65
+ <div
66
+ v-else
67
+ class="content-wrapper"
68
+ :data-full-text="data[item.field]"
69
+ >
70
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
71
+ <div class="report-value">
72
+ {{ data[item.field] }}
73
+ </div>
74
+ <div class="report-unit">
75
+ {{ item.unit }}
76
+ </div>
77
+ </template>
78
+ <template v-else>
79
+ {{ data[item.field] }}
80
+ </template>
81
+ </div>
82
+ </template>
83
+ </div>
84
+ </div>
85
+ </template>
86
+ </div>
87
+ </template>
88
+
89
+ <!-- 当有 layout 配置时使用 a-descriptions -->
90
+ <template v-else-if="config && config.layout && !wrapperClassObject['xhdesc-medical-history']">
17
91
  <a-descriptions
18
92
  :colon="getGlobalColon()"
19
93
  :column="config.layout"
@@ -32,7 +106,7 @@
32
106
  <div v-if="item.showAvatar" class="gender-icon">
33
107
  <img :src="maleIcon" alt="male" class="gender-img" />
34
108
  </div>
35
- <span class="label-text">{{ item.label }}</span>
109
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
36
110
  </div>
37
111
  </template>
38
112
  <a-tooltip
@@ -77,121 +151,58 @@
77
151
  </div>
78
152
  </a-descriptions-item>
79
153
 
80
- <!-- 展开后显示剩余标签 -->
81
- <template v-if="showAllItems">
82
- <a-descriptions-item
83
- v-for="item in hiddenItemsFiltered"
84
- :key="item.field"
85
- :colon="getItemColon(item)"
86
- :class="{ 'with-divider': item.isLine }">
87
- <template #label>
88
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
89
- <div v-if="item.showAvatar" class="gender-icon">
90
- <img :src="maleIcon" alt="male" class="gender-img" />
91
- </div>
92
- <span class="label-text">{{ item.label }}</span>
93
- </div>
94
- </template>
95
- <div
96
- class="content-wrapper"
97
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
98
- :data-full-text="data[item.field]"
99
- >
100
- <template v-if="wrapperClassObject['xhdesc-report-mode']">
101
- <div class="report-value">
102
- {{ data[item.field] }}
103
- </div>
104
- <div class="report-unit">
105
- {{ item.unit }}
106
- </div>
107
- </template>
108
- <template v-else>
109
- {{ data[item.field] }}
110
- </template>
111
- </div>
112
- </a-descriptions-item>
113
- </template>
154
+ <!-- 占位符项目 -->
155
+ <div
156
+ v-for="(item, index) in visibleItems"
157
+ v-if="!item.field || item.field === ''"
158
+ :key="'placeholder-' + index"
159
+ class="placeholder-item"
160
+ ></div>
114
161
  </template>
115
- </a-descriptions>
116
- </template>
117
162
 
118
- <!-- layout 为数组时使用自定义 Grid 布局 -->
119
- <template v-else-if="config && config.layout && Array.isArray(config.layout) && !wrapperClassObject['xhdesc-medical-history']">
120
- <div class="grid-descriptions">
121
- <template v-if="data">
122
- <!-- 按行分组显示项目 -->
123
- <div
124
- v-for="(rowItems, rowIndex) in gridRows"
125
- :key="rowIndex"
126
- class="grid-row"
127
- :style="{ gridTemplateColumns: getGridTemplateColumns(config.layout[rowIndex]) }"
128
- >
163
+ <!-- 展开后显示剩余标签 -->
164
+ <template v-if="showAllItems">
165
+ <a-descriptions-item
166
+ v-for="item in hiddenItemsFiltered"
167
+ :key="item.field"
168
+ :colon="getItemColon(item)"
169
+ :class="{ 'with-divider': item.isLine }">
170
+ <template #label>
171
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
172
+ <div v-if="item.showAvatar" class="gender-icon">
173
+ <img :src="maleIcon" alt="male" class="gender-img" />
174
+ </div>
175
+ <span class="label-text">{{ item.label }}</span>
176
+ </div>
177
+ </template>
129
178
  <div
130
- v-for="(item, itemIndex) in rowItems"
131
- :key="item.field || `item-${itemIndex}`"
132
- :class="[
133
- 'grid-item',
134
- wrapperClassObject['xhdesc-grid-formatted'] && 'grid-formatted',
135
- { 'with-divider': item.isLine, 'placeholder-item': (!item.field || item.field === '') }
136
- ]"
179
+ class="content-wrapper"
180
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
181
+ :data-full-text="data[item.field]"
137
182
  >
138
- <!-- 占位符项目:只显示空的容器 -->
139
- <div v-if="!item.field || item.field === ''" class="grid-item-content placeholder-content"></div>
140
-
141
- <!-- 普通项目 -->
142
- <div v-else class="grid-item-content">
143
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
144
- <div v-if="item.showAvatar" class="gender-icon">
145
- <img :src="maleIcon" alt="male" class="gender-img" />
146
- </div>
147
- <span class="label-text">{{ item.label }}</span>
148
- <span v-if="getItemColon(item)" class="colon">:</span>
183
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
184
+ <div class="report-value">
185
+ {{ data[item.field] }}
149
186
  </div>
150
- <a-tooltip
151
- v-if="isContentOverflow(data[item.field])"
152
- :title="data[item.field]"
153
- placement="topLeft"
154
- :overlay-style="{ maxWidth: '400px' }"
155
- >
156
- <div
157
- class="content-wrapper ellipsis"
158
- :data-full-text="data[item.field]"
159
- >
160
- <template v-if="wrapperClassObject['xhdesc-report-mode']">
161
- <div class="report-value">
162
- {{ data[item.field] }}
163
- </div>
164
- <div class="report-unit">
165
- {{ item.unit }}
166
- </div>
167
- </template>
168
- <template v-else>
169
- {{ data[item.field] }}
170
- </template>
171
- </div>
172
- </a-tooltip>
173
- <div
174
- v-else
175
- class="content-wrapper"
176
- :data-full-text="data[item.field]"
177
- >
178
- <template v-if="wrapperClassObject['xhdesc-report-mode']">
179
- <div class="report-value">
180
- {{ data[item.field] }}
181
- </div>
182
- <div class="report-unit">
183
- {{ item.unit }}
184
- </div>
185
- </template>
186
- <template v-else>
187
- {{ data[item.field] }}
188
- </template>
187
+ <div class="report-unit">
188
+ {{ item.unit }}
189
189
  </div>
190
- </div>
190
+ </template>
191
+ <template v-else>
192
+ {{ data[item.field] }}
193
+ </template>
191
194
  </div>
192
- </div>
195
+ </a-descriptions-item>
196
+
197
+ <!-- 展开部分的占位符项目 -->
198
+ <div
199
+ v-for="(item, index) in hiddenItems"
200
+ v-if="!item.field || item.field === ''"
201
+ :key="'hidden-placeholder-' + index"
202
+ class="placeholder-item"
203
+ ></div>
193
204
  </template>
194
- </div>
205
+ </a-descriptions>
195
206
  </template>
196
207
 
197
208
  <!-- 医疗病史模式:使用自定义HTML结构实现文本环绕 -->
@@ -269,7 +280,7 @@
269
280
  <div v-if="item.showAvatar" class="gender-icon">
270
281
  <img :src="maleIcon" alt="male" class="gender-img" />
271
282
  </div>
272
- <span class="label-text">{{ item.label }}</span>
283
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
273
284
  </div>
274
285
  <a-tooltip
275
286
  v-if="isContentOverflow(data[item.field])"
@@ -324,7 +335,7 @@
324
335
  <div v-if="item.showAvatar" class="gender-icon">
325
336
  <img :src="maleIcon" alt="male" class="gender-img" />
326
337
  </div>
327
- <span class="label-text">{{ item.label }}</span>
338
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
328
339
  </div>
329
340
  <div
330
341
  class="content-wrapper"
@@ -385,7 +396,9 @@
385
396
  v-for="(item, ridx) in config.footer.rightItems"
386
397
  :key="item.field || ridx"
387
398
  class="footer-right-item">
388
- <div class="label-wrapper"><span class="label-text">{{ item.label }}</span></div>
399
+ <div class="label-wrapper">
400
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
401
+ </div>
389
402
  <div
390
403
  class="content-wrapper"
391
404
  :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
@@ -401,7 +414,9 @@
401
414
  v-for="(item, idx) in config.footer.items"
402
415
  :key="item.field || idx"
403
416
  class="description-item">
404
- <div class="label-wrapper"><span class="label-text">{{ item.label }}</span></div>
417
+ <div class="label-wrapper">
418
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
419
+ </div>
405
420
  <div
406
421
  class="content-wrapper"
407
422
  :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
@@ -418,7 +433,9 @@
418
433
  v-for="(item, ridx) in config.footer.rightItems"
419
434
  :key="item.field || ridx"
420
435
  class="footer-right-item">
421
- <div class="label-wrapper"><span class="label-text">{{ item.label }}</span></div>
436
+ <div class="label-wrapper">
437
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
438
+ </div>
422
439
  <div
423
440
  class="content-wrapper"
424
441
  :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
@@ -515,10 +532,10 @@ export default {
515
532
  visibleItemsFiltered () {
516
533
  const list = this.visibleItems || []
517
534
  if (!this.data) return []
518
- // 保留所有配置的字段,包括空字段(用作占位符)
535
+ // 过滤掉占位符项目,占位符在模板中单独处理
519
536
  const res = list.filter(item => {
520
- // 空字段(占位符)始终显示
521
- if (!item.field || item.field === '') return true
537
+ // 跳过空字段(占位符)
538
+ if (!item.field || item.field === '') return false
522
539
  // 其他字段只有在有数据时才显示
523
540
  return this.data[item.field] !== null && this.data[item.field] !== undefined
524
541
  })
@@ -529,20 +546,53 @@ export default {
529
546
  hiddenItemsFiltered () {
530
547
  const list = this.hiddenItems || []
531
548
  if (!this.data) return []
532
- return list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
549
+ // 过滤掉占位符项目,占位符在模板中单独处理
550
+ const res = list.filter(item => {
551
+ // 跳过空字段(占位符)
552
+ if (!item.field || item.field === '') return false
553
+ // 其他字段只有在有数据时才显示
554
+ return this.data[item.field] !== null && this.data[item.field] !== undefined
555
+ })
556
+ return res
533
557
  },
534
558
  // Grid布局的行分组数据
535
559
  gridRows () {
536
- if (!Array.isArray(this.config?.layout) || !this.visibleItemsFiltered) return []
560
+ if (!this.config?.items || !Array.isArray(this.config.items)) return []
561
+
562
+ const config = this.config || {}
563
+ const layout = config.layout
564
+
565
+ // 处理对象格式的layout配置(如 {"xl":5,"md":5,...})
566
+ if (layout && typeof layout === 'object' && !Array.isArray(layout)) {
567
+ // 检查是否所有断点都是相同的列数
568
+ const columnCounts = Object.values(layout)
569
+ const isUniform = columnCounts.every(count => count === columnCounts[0])
570
+ if (isUniform && columnCounts[0] > 0) {
571
+ const itemsPerRow = columnCounts[0]
572
+ // 根据项目数量创建相应行数,每行按配置列数显示
573
+ const rows = []
574
+ const items = this.config.items
575
+
576
+ for (let i = 0; i < items.length; i += itemsPerRow) {
577
+ const rowItems = items.slice(i, i + itemsPerRow)
578
+ rows.push(rowItems)
579
+ }
580
+
581
+ return rows
582
+ }
583
+ }
584
+
585
+ // 回退到原来的数组格式处理
586
+ if (!Array.isArray(layout) || !this.visibleItemsFiltered) return []
537
587
 
538
588
  const items = [...this.visibleItemsFiltered]
539
589
  const rows = []
540
590
  let currentIndex = 0
541
591
 
542
- for (let i = 0; i < this.config.layout.length; i++) {
543
- const columnsInRow = this.config.layout[i]
592
+ for (let i = 0; i < layout.length; i++) {
593
+ const columnsInRow = layout[i]
544
594
  const rowItems = items.slice(currentIndex, currentIndex + columnsInRow)
545
- rows.push(rowItems) // 总是创建行,即使没有项目
595
+ rows.push(rowItems)
546
596
  currentIndex += columnsInRow
547
597
  if (currentIndex >= items.length) break
548
598
  }
@@ -595,10 +645,26 @@ export default {
595
645
  }
596
646
  return this.getGlobalColon()
597
647
  },
648
+ // 获取当前grid布局的列数
649
+ getGridColumns () {
650
+ const layout = this.config?.layout
651
+ if (layout && typeof layout === 'object' && !Array.isArray(layout)) {
652
+ const columnCounts = Object.values(layout)
653
+ if (columnCounts.length > 0 && columnCounts.every(count => count === columnCounts[0])) {
654
+ return columnCounts[0]
655
+ }
656
+ }
657
+ return 5 // 默认5列
658
+ },
598
659
  // 生成CSS Grid模板列样式
599
660
  getGridTemplateColumns (columns) {
600
661
  if (typeof columns !== 'number' || columns <= 0) return 'repeat(auto-fit, minmax(200px, 1fr))'
601
662
  return `repeat(${columns}, 1fr)`
663
+ },
664
+ // 判断项目是否应该显示(有数据)
665
+ shouldShowItem (item) {
666
+ if (!item.field || item.field === '') return false
667
+ return this.data[item.field] !== null && this.data[item.field] !== undefined
602
668
  }
603
669
  },
604
670
  watch: {
@@ -680,67 +746,23 @@ export default {
680
746
  background-color: transparent !important;
681
747
  }
682
748
 
683
- /* Grid布局格式化样式:对齐 + 字体 */
684
- .grid-item.grid-formatted .grid-item-content {
685
- display: flex;
686
- align-items: center;
687
- gap: 16px;
688
- width: 100%;
689
- height: 100%;
690
- }
691
-
692
- .grid-item.grid-formatted .label-wrapper {
693
- flex: 0 0 auto;
694
- min-width: 80px;
695
- max-width: 120px;
696
- display: flex;
697
- align-items: center;
698
- position: relative;
699
- }
700
-
701
- .grid-item.grid-formatted .label-text {
702
- flex: 1;
703
- text-align: justify; /* 两端对齐 */
704
- padding-right: 12px; /* 为冒号留空间 */
705
- text-justify: inter-word; /* 优化两端对齐 */
706
- word-break: break-all; /* 允许在任意字符间断行 */
707
- letter-spacing: 0.5em; /* 适中的字符间距 */
708
- }
709
-
710
- .grid-item.grid-formatted .colon {
711
- position: absolute;
712
- right: 0;
713
- top: 50%;
714
- transform: translateY(-50%);
715
- }
716
-
717
- .grid-item.grid-formatted .content-wrapper {
718
- flex: 1;
719
- text-align: left;
720
- min-width: 0; /* 允许收缩 */
721
- }
722
-
723
- .grid-item.grid-formatted .label-wrapper .label-text {
724
- font-family: "Source Han Sans";
725
- font-size: 16px;
726
- font-weight: normal;
727
- line-height: 23px;
728
- letter-spacing: 0em;
729
- color: #313131;
749
+ .placeholder-item {
750
+ /* 占位符项目保持布局空间 */
751
+ min-height: 32px;
752
+ width: fit-content;
753
+ margin-right: 24px;
754
+ margin-bottom: 16px;
730
755
  }
731
756
 
732
- .grid-item.grid-formatted .content-wrapper {
733
- font-family: "Source Han Sans";
734
- font-size: 16px;
735
- font-weight: bold;
736
- line-height: 23px;
737
- letter-spacing: 0em;
738
- color: #313131;
757
+ .placeholder-content {
758
+ /* 占位符内容为空,不显示任何内容 */
759
+ min-height: 20px; /* 较小的高度,避免视觉突兀 */
760
+ visibility: hidden; /* 完全隐藏内容 */
739
761
  }
740
762
 
741
763
  /* Grid布局冒号样式 */
742
- .grid-item .colon {
743
- margin: 0 2px;
764
+ .colon {
765
+ margin: 0;
744
766
  color: rgba(0, 0, 0, 0.65);
745
767
  font-size: 14px;
746
768
  }
@@ -854,11 +876,12 @@ export default {
854
876
  ::v-deep(.ant-descriptions-item) {
855
877
  padding: 0 !important;
856
878
  display: flex !important;
857
- align-items: flex-start !important;
879
+ align-items: stretch !important; /* 拉伸对齐,确保子项高度一致 */
858
880
  flex-direction: row !important;
859
881
  margin-right: 24px;
860
882
  width: fit-content !important;
861
883
  margin-bottom: 16px;
884
+ height: 32px !important; /* 固定高度 */
862
885
  }
863
886
 
864
887
  ::v-deep(.ant-descriptions-item-container) {
@@ -871,22 +894,27 @@ export default {
871
894
  }
872
895
 
873
896
  ::v-deep(.ant-descriptions-item-label) {
874
- color: rgba(0, 0, 0, 0.65);
897
+ color: rgba(0, 0, 0, 0.65) !important;
875
898
  padding: 0 !important;
876
899
  margin: 0 !important;
877
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
878
- display: inline-flex !important;
900
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"') !important;
901
+ display: flex !important;
879
902
  align-items: center !important;
903
+ justify-content: flex-start !important;
880
904
  white-space: nowrap !important;
881
- min-width: v-bind('(config && config.style && config.style.labelWidth) || "80px"');
882
- justify-content: flex-start;
905
+ min-width: v-bind('(config && config.style && config.style.labelWidth) || "80px"') !important;
906
+ min-height: 32px !important;
907
+ height: 32px !important;
908
+ line-height: 32px !important;
883
909
  padding-right: 2px !important;
884
910
  }
885
911
 
886
912
  ::v-deep(.ant-descriptions-item-content) {
887
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
888
- display: inline-flex !important;
913
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"') !important;
914
+ display: flex !important;
889
915
  align-items: center !important;
916
+ justify-content: flex-start !important;
917
+ height: 100% !important; /* 占满父容器高度 */
890
918
  padding: 0 !important;
891
919
  margin: 0 !important;
892
920
  margin-left: 0px !important;
@@ -901,6 +929,7 @@ export default {
901
929
  margin-right: 2px !important;
902
930
  }
903
931
 
932
+
904
933
  ::v-deep(.ant-descriptions-item-container:hover) {
905
934
  background-color: rgba(0, 0, 0, 0.02);
906
935
  border-radius: 4px;
@@ -912,6 +941,13 @@ export default {
912
941
  line-height: 1;
913
942
  }
914
943
 
944
+ /* 隐藏占位符项目的冒号 */
945
+ ::v-deep(.ant-descriptions-item.placeholder-item .ant-descriptions-item-colon) {
946
+ display: none !important;
947
+ }
948
+
949
+
950
+
915
951
  ::v-deep(.ant-btn-link:hover) {
916
952
  color: #1890ff;
917
953
  background: transparent;
@@ -1316,6 +1352,34 @@ export default {
1316
1352
  }
1317
1353
  }
1318
1354
 
1355
+ .xhdesc-grid-formatted {
1356
+ &.patient-info-descriptions,
1357
+ .patient-info-descriptions {
1358
+ ::v-deep .label-wrapper .label-text {
1359
+ height: 23px;
1360
+ opacity: 1;
1361
+ font-family: "Source Han Sans";
1362
+ font-size: 16px;
1363
+ font-weight: normal;
1364
+ line-height: normal;
1365
+ letter-spacing: 0em;
1366
+ color: #313131;
1367
+ }
1368
+
1369
+ ::v-deep .content-wrapper,
1370
+ ::v-deep .ant-descriptions-item-content {
1371
+ height: 23px;
1372
+ opacity: 1;
1373
+ font-family: "Source Han Sans";
1374
+ font-size: 16px;
1375
+ font-weight: bold;
1376
+ line-height: normal;
1377
+ letter-spacing: 0em;
1378
+ color: #313131;
1379
+ }
1380
+ }
1381
+ }
1382
+
1319
1383
  .xhdesc-report-mode {
1320
1384
  &.patient-info-descriptions,
1321
1385
  .patient-info-descriptions {