vue2-client 1.18.68 → 1.18.69

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.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/src/assets/svg/female.svg +1 -1
  3. package/src/assets/svg/male.svg +1 -1
  4. package/src/base-client/components/common/HIS/HFormGroup/index.js +3 -3
  5. package/src/base-client/components/common/XCollapse/XCollapse.vue +830 -830
  6. package/src/base-client/components/common/XTimeline/XTimeline.vue +477 -477
  7. package/src/base-client/components/his/HChart/demo.vue +88 -88
  8. package/src/base-client/components/his/HChart/index.md +798 -798
  9. package/src/base-client/components/his/XHDescriptions/XHDescriptions.vue +1412 -1348
  10. package/src/base-client/components/his/XIcon/XIcon.vue +73 -73
  11. package/src/base-client/components/his/XIcon/index.js +3 -3
  12. package/src/base-client/components/his/XIcon/index.md +177 -177
  13. package/src/base-client/components/his/XTimeSelect/XTimeSelect.vue +354 -354
  14. package/src/base-client/components/his/threeTestOrders/editor.vue +113 -113
  15. package/src/pages/userInfoDetailManage/ExceptionRecordQuery/index.vue +45 -45
  16. package/src-base-client/components/common/HIS/HForm/HForm.vue +347 -0
  17. package/src/assets/img/paymentMethod/icon1.png +0 -0
  18. package/src/assets/img/paymentMethod/icon2.png +0 -0
  19. package/src/assets/img/paymentMethod/icon3.png +0 -0
  20. package/src/assets/img/paymentMethod/icon4.png +0 -0
  21. package/src/assets/img/paymentMethod/icon5.png +0 -0
  22. package/src/assets/img/paymentMethod/icon6.png +0 -0
  23. package/src/base-client/components/common/XReport/XReportHospitalizationDemo.vue +0 -45
  24. package/src-base-client/components/his/XCharge/XCharge.vue +0 -0
  25. /package/src-base-client/components/{his/XCharge/README.md → common/XCollapse/XCollapse.vue} +0 -0
@@ -1,1348 +1,1412 @@
1
- <template>
2
- <div class="patient-info-descriptions" :class="wrapperClassObject">
3
- <div class="descriptions-container">
4
- <!-- 详情/收起按钮 -->
5
- <div v-if="hasMoreItems" class="detail-button-wrapper">
6
- <a-button
7
- :type="(config && config.detailsConfig && config.detailsConfig.buttonType) || 'link'"
8
- @click="toggleDetails"
9
- >
10
- {{ showAllItems ? '收起' : ((config && config.detailsConfig && config.detailsConfig.buttonText) || '详情') }}
11
- <a-icon :type="showAllItems ? 'up' : 'down'" />
12
- </a-button>
13
- </div>
14
-
15
- <!-- 当 layout 为数字时使用 a-descriptions -->
16
- <template v-if="config && config.layout && typeof config.layout === 'number' && !wrapperClassObject['xhdesc-medical-history']">
17
- <a-descriptions
18
- :colon="getGlobalColon()"
19
- :column="config.layout"
20
- :size="(config && config.style && config.style.size)"
21
- :bordered="(config && config.style && config.style.bordered)"
22
- layout="horizontal">
23
- <template v-if="data">
24
- <!-- 显示前N个标签 -->
25
- <a-descriptions-item
26
- v-for="(item) in visibleItemsFiltered"
27
- :key="item.field"
28
- :colon="getItemColon(item)"
29
- :class="{ 'with-divider': item.isLine }">
30
- <template #label>
31
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
32
- <div v-if="item.showAvatar" class="gender-icon">
33
- <img :src="maleIcon" alt="male" class="gender-img" />
34
- </div>
35
- <span class="label-text">{{ item.label }}</span>
36
- </div>
37
- </template>
38
- <a-tooltip
39
- v-if="isContentOverflow(data[item.field])"
40
- :title="data[item.field]"
41
- placement="topLeft"
42
- :overlay-style="{ maxWidth: '400px' }"
43
- >
44
- <div
45
- class="content-wrapper ellipsis"
46
- :data-full-text="data[item.field]"
47
- >
48
- <template v-if="wrapperClassObject['xhdesc-report-mode']">
49
- <div class="report-value">
50
- {{ data[item.field] }}
51
- </div>
52
- <div class="report-unit">
53
- {{ item.unit }}
54
- </div>
55
- </template>
56
- <template v-else>
57
- {{ data[item.field] }}
58
- </template>
59
- </div>
60
- </a-tooltip>
61
- <div
62
- v-else
63
- class="content-wrapper"
64
- :data-full-text="data[item.field]"
65
- >
66
- <template v-if="wrapperClassObject['xhdesc-report-mode']">
67
- <div class="report-value">
68
- {{ data[item.field] }}
69
- </div>
70
- <div class="report-unit">
71
- {{ item.unit }}
72
- </div>
73
- </template>
74
- <template v-else>
75
- {{ data[item.field] }}
76
- </template>
77
- </div>
78
- </a-descriptions-item>
79
-
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>
114
- </template>
115
- </a-descriptions>
116
- </template>
117
-
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
- >
129
- <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
- ]"
137
- >
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>
149
- </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>
189
- </div>
190
- </div>
191
- </div>
192
- </div>
193
- </template>
194
- </div>
195
- </template>
196
-
197
- <!-- 医疗病史模式:使用自定义HTML结构实现文本环绕 -->
198
- <template v-else-if="config && config.layout && wrapperClassObject['xhdesc-medical-history']">
199
- <div class="medical-history-descriptions">
200
- <template v-if="data">
201
- <!-- 显示前N个标签 -->
202
- <div
203
- v-for="(item) in visibleItemsFiltered"
204
- :key="item.field"
205
- :class="['medical-history-item', { 'with-divider': item.isLine }]"
206
- >
207
- <div class="medical-history-content">
208
- <a-tooltip
209
- v-if="isContentOverflow(data[item.field])"
210
- :title="data[item.field]"
211
- placement="topLeft"
212
- :overlay-style="{ maxWidth: '400px' }"
213
- >
214
- <div class="medical-history-text ellipsis">
215
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
216
- </div>
217
- </a-tooltip>
218
- <div
219
- v-else
220
- class="medical-history-text"
221
- >
222
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
223
- </div>
224
- </div>
225
- </div>
226
-
227
- <!-- 展开后显示剩余标签 -->
228
- <template v-if="showAllItems">
229
- <div
230
- v-for="item in hiddenItemsFiltered"
231
- :key="item.field"
232
- class="medical-history-item"
233
- >
234
- <div class="medical-history-content">
235
- <a-tooltip
236
- v-if="isContentOverflow(data[item.field])"
237
- :title="data[item.field]"
238
- placement="topLeft"
239
- :overlay-style="{ maxWidth: '400px' }"
240
- >
241
- <div class="medical-history-text ellipsis">
242
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
243
- </div>
244
- </a-tooltip>
245
- <div
246
- v-else
247
- class="medical-history-text"
248
- >
249
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
250
- </div>
251
- </div>
252
- </div>
253
- </template>
254
- </template>
255
- </div>
256
- </template>
257
-
258
- <!-- 当没有 layout 配置时使用自适应布局 -->
259
- <template v-else>
260
- <div class="flex-descriptions">
261
- <template v-if="data">
262
- <!-- 显示可见的标签 -->
263
- <div
264
- v-for="(item) in visibleItemsFiltered"
265
- :key="item.field"
266
- :class="['description-item', { 'with-divider': item.isLine }]"
267
- >
268
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
269
- <div v-if="item.showAvatar" class="gender-icon">
270
- <img :src="maleIcon" alt="male" class="gender-img" />
271
- </div>
272
- <span class="label-text">{{ item.label }}</span>
273
- </div>
274
- <a-tooltip
275
- v-if="isContentOverflow(data[item.field])"
276
- :title="data[item.field]"
277
- placement="topLeft"
278
- :overlay-style="{ maxWidth: '400px' }"
279
- >
280
- <div
281
- class="content-wrapper ellipsis"
282
- :data-full-text="data[item.field]"
283
- >
284
- <template v-if="wrapperClassObject['xhdesc-report-mode']">
285
- <div class="report-value">
286
- {{ data[item.field] }}
287
- </div>
288
- <div class="report-unit">
289
- {{ item.unit }}
290
- </div>
291
- </template>
292
- <template v-else>
293
- {{ data[item.field] }}
294
- </template>
295
- </div>
296
- </a-tooltip>
297
- <div
298
- v-else
299
- class="content-wrapper"
300
- :data-full-text="data[item.field]"
301
- >
302
- <template v-if="wrapperClassObject['xhdesc-report-mode']">
303
- <div class="report-value">
304
- {{ data[item.field] }}
305
- </div>
306
- <div class="report-unit">
307
- {{ item.unit }}
308
- </div>
309
- </template>
310
- <template v-else>
311
- {{ data[item.field] }}
312
- </template>
313
- </div>
314
- </div>
315
-
316
- <!-- 展开后显示的内容 -->
317
- <template v-if="showAllItems">
318
- <div
319
- v-for="item in hiddenItemsFiltered"
320
- :key="item.field"
321
- class="description-item"
322
- >
323
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
324
- <div v-if="item.showAvatar" class="gender-icon">
325
- <img :src="maleIcon" alt="male" class="gender-img" />
326
- </div>
327
- <span class="label-text">{{ item.label }}</span>
328
- </div>
329
- <div
330
- class="content-wrapper"
331
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
332
- :data-full-text="data[item.field]"
333
- >
334
- <template v-if="wrapperClassObject['xhdesc-report-mode']">
335
- <div class="report-value">
336
- {{ data[item.field] }}
337
- </div>
338
- <div class="report-unit">
339
- {{ item.unit }}
340
- </div>
341
- </template>
342
- <template v-else>
343
- {{ data[item.field] }}
344
- </template>
345
- </div>
346
- </div>
347
- </template>
348
- </template>
349
- </div>
350
- </template>
351
-
352
- <!-- 可选:底部区域(分割线 + 三列内容) -->
353
- <div v-if="config && config.footer && Array.isArray(config.footer.items) && data" class="xhdesc-footer">
354
- <div class="xhdesc-divider" />
355
- <!-- 医疗病史模式下的footer结构 -->
356
- <div v-if="wrapperClassObject['xhdesc-medical-history']" class="medical-history-footer">
357
- <div
358
- v-for="(item, idx) in config.footer.items"
359
- :key="item.field || idx"
360
- class="medical-history-item">
361
- <div class="medical-history-content">
362
- <a-tooltip
363
- v-if="isContentOverflow(data[item.field])"
364
- :title="data[item.field]"
365
- placement="topLeft"
366
- :overlay-style="{ maxWidth: '400px' }"
367
- >
368
- <div class="medical-history-text ellipsis">
369
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
370
- </div>
371
- </a-tooltip>
372
- <div
373
- v-else
374
- class="medical-history-text"
375
- >
376
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
377
- </div>
378
- </div>
379
- </div>
380
- <!-- 右侧信息:换到下一行并靠右对齐(如 医生 / 医嘱日期) -->
381
- <div
382
- v-if="Array.isArray(config.footer.rightItems) && config.footer.rightItems.length"
383
- class="footer-right">
384
- <div
385
- v-for="(item, ridx) in config.footer.rightItems"
386
- :key="item.field || ridx"
387
- class="footer-right-item">
388
- <div class="label-wrapper"><span class="label-text">{{ item.label }}</span></div>
389
- <div
390
- class="content-wrapper"
391
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
392
- :data-full-text="data[item.field]"
393
- >{{ data[item.field] }}
394
- </div>
395
- </div>
396
- </div>
397
- </div>
398
- <!-- 非医疗病史模式下的footer结构 -->
399
- <div v-else class="footer-grid">
400
- <div
401
- v-for="(item, idx) in config.footer.items"
402
- :key="item.field || idx"
403
- class="description-item">
404
- <div class="label-wrapper"><span class="label-text">{{ item.label }}</span></div>
405
- <div
406
- class="content-wrapper"
407
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
408
- :data-full-text="data[item.field]"
409
- >{{ data[item.field] }}
410
- </div>
411
- </div>
412
- </div>
413
- <!-- 右侧信息:换到下一行并靠右对齐(如 医生 / 医嘱日期) -->
414
- <div
415
- v-if="!wrapperClassObject['xhdesc-medical-history'] && Array.isArray(config.footer.rightItems) && config.footer.rightItems.length"
416
- class="footer-right">
417
- <div
418
- v-for="(item, ridx) in config.footer.rightItems"
419
- :key="item.field || ridx"
420
- class="footer-right-item">
421
- <div class="label-wrapper"><span class="label-text">{{ item.label }}</span></div>
422
- <div
423
- class="content-wrapper"
424
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
425
- :data-full-text="data[item.field]"
426
- >{{ data[item.field] }}
427
- </div>
428
- </div>
429
- </div>
430
- </div>
431
- </div>
432
- </div>
433
- </template>
434
-
435
- <script>
436
- import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
437
-
438
- export default {
439
- name: 'XHDescriptions',
440
- data () {
441
- return {
442
- hiddenConfig: '-1^',
443
- data: null,
444
- config: null,
445
- showAllItems: false,
446
- maleIcon: require('@vue2-client/assets/svg/male.svg')
447
- }
448
- },
449
- props: {
450
- queryParamsName: {
451
- type: String,
452
- default: ''
453
- },
454
- parameter: {
455
- type: Object,
456
- default: () => {
457
- return {}
458
- }
459
- }
460
- },
461
- computed: {
462
- wrapperClassObject () {
463
- const attrs = this.$attrs || {}
464
- const classes = {}
465
-
466
- const booleanStyleKeys = [
467
- 'description',
468
- 'no-padding',
469
- 'medical-history',
470
- 'patient-style',
471
- 'margin-top-12',
472
- 'padding-left15',
473
- 'line-height30',
474
- 'report-mode',
475
- 'border1',
476
- 'grid-formatted'
477
- ]
478
- booleanStyleKeys.forEach(key => {
479
- const val = attrs[key]
480
- const truthy = val === true || val === '' || val === 'true'
481
- if (truthy) classes[`xhdesc-${key}`] = true
482
- })
483
- const size = attrs.size
484
- if (size && typeof size === 'string') classes[`xhdesc-size-${size}`] = true
485
- if (this.showAllItems && this.config && this.config.detailsConfig) classes['xhdesc-open'] = true
486
- return classes
487
- },
488
- detailsAfterIndex () {
489
- return (this.config && this.config.detailsConfig && this.config.detailsConfig.showAfterIndex) || 999
490
- },
491
- hasMoreItems () {
492
- if (!(this.config && this.config.detailsConfig)) return false
493
- if (!this.data || !(this.config && this.config.items) || !Array.isArray(this.config.items)) return false
494
- const hiddenStartIndex = this.detailsAfterIndex || 0
495
- if (hiddenStartIndex >= this.config.items.length) return false
496
- for (let i = hiddenStartIndex; i < this.config.items.length; i++) {
497
- const item = this.config.items[i]
498
- if (item && item.field && this.data[item.field] !== null && this.data[item.field] !== undefined) {
499
- return true
500
- }
501
- }
502
- return false
503
- },
504
- visibleItems () {
505
- if (!(this.config && this.config.items)) return []
506
- if (!(this.config && this.config.detailsConfig)) return this.config.items
507
- if (this.showAllItems) return this.config.items.slice(0, this.detailsAfterIndex)
508
- return this.config.items.slice(0, this.detailsAfterIndex)
509
- },
510
- hiddenItems () {
511
- if (!(this.config && this.config.items)) return []
512
- if (!(this.config && this.config.detailsConfig)) return []
513
- return this.config.items.slice(this.detailsAfterIndex)
514
- },
515
- visibleItemsFiltered () {
516
- const list = this.visibleItems || []
517
- if (!this.data) return []
518
- // 保留所有配置的字段,包括空字段(用作占位符)
519
- const res = list.filter(item => {
520
- // 空字段(占位符)始终显示
521
- if (!item.field || item.field === '') return true
522
- // 其他字段只有在有数据时才显示
523
- return this.data[item.field] !== null && this.data[item.field] !== undefined
524
- })
525
- if (!this.showAllItems) return res
526
- const hiddenFields = new Set((this.hiddenItems || []).map(i => i.field))
527
- return res.filter(item => !hiddenFields.has(item.field))
528
- },
529
- hiddenItemsFiltered () {
530
- const list = this.hiddenItems || []
531
- if (!this.data) return []
532
- return list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
533
- },
534
- // Grid布局的行分组数据
535
- gridRows () {
536
- if (!Array.isArray(this.config?.layout) || !this.visibleItemsFiltered) return []
537
-
538
- const items = [...this.visibleItemsFiltered]
539
- const rows = []
540
- let currentIndex = 0
541
-
542
- for (let i = 0; i < this.config.layout.length; i++) {
543
- const columnsInRow = this.config.layout[i]
544
- const rowItems = items.slice(currentIndex, currentIndex + columnsInRow)
545
- rows.push(rowItems) // 总是创建行,即使没有项目
546
- currentIndex += columnsInRow
547
- if (currentIndex >= items.length) break
548
- }
549
-
550
- return rows
551
- }
552
- },
553
- created () {
554
- this.getData(this.queryParamsName, {})
555
- },
556
- methods: {
557
- async getData (data, parameterData) {
558
- this.data = null
559
- this.showAllItems = false
560
- getConfigByName(data, 'af-his', res => {
561
- this.config = res
562
- const hiddenConfig = (this.config && this.config.hiddenConfig) || (0 === 1)
563
- const parameter = { ...res.parameter, ...this.parameter, ...parameterData }
564
- runLogic(res.logicName, parameter, 'af-his').then(result => {
565
- if (hiddenConfig) {
566
- for (const key in result) {
567
- if (Object.prototype.hasOwnProperty.call(result, key) && result[key] === this.hiddenConfig) {
568
- delete result[key]
569
- }
570
- }
571
- }
572
- this.data = result
573
- })
574
- })
575
- },
576
- toggleDetails () {
577
- this.showAllItems = !this.showAllItems
578
- },
579
- isContentOverflow (content) {
580
- if (!content || typeof content !== 'string') return false
581
- return content.length > 150
582
- },
583
- // 获取全局 colon 配置
584
- getGlobalColon () {
585
- if (this.config && this.config.style && this.config.style.colon !== undefined) {
586
- return this.config.style.colon
587
- }
588
- return true // 默认显示冒号
589
- },
590
- // 获取单个 item 的 colon 配置
591
- getItemColon (item) {
592
- // 优先级:item配置 > 全局配置 > 默认true
593
- if (item && item.colon !== undefined) {
594
- return item.colon
595
- }
596
- return this.getGlobalColon()
597
- },
598
- // 生成CSS Grid模板列样式
599
- getGridTemplateColumns (columns) {
600
- if (typeof columns !== 'number' || columns <= 0) return 'repeat(auto-fit, minmax(200px, 1fr))'
601
- return `repeat(${columns}, 1fr)`
602
- }
603
- },
604
- watch: {
605
- queryParamsName: {
606
- handler (newValue) {
607
- console.log(newValue)
608
- this.getData(newValue, {})
609
- },
610
- deep: true
611
- },
612
- parameter: {
613
- handler (newValue, oldValue) {
614
- console.log('监听事件触发:', { old: oldValue, new: newValue })
615
- this.getData(this.queryParamsName, {})
616
- },
617
- deep: true
618
- }
619
- }
620
- }
621
- </script>
622
-
623
- <style scoped lang="less">
624
- .patient-info-descriptions {
625
- background: #fff;
626
- border-radius: 4px;
627
- width: 100%;
628
- }
629
-
630
- .descriptions-container {
631
- position: relative;
632
- width: 100%;
633
- padding-right: 80px; /* 为按钮预留空间 */
634
- }
635
-
636
- /* 自适应布局样式 */
637
- .flex-descriptions {
638
- display: flex;
639
- flex-wrap: wrap;
640
- gap: 8px 24px;
641
- width: 100%;
642
- }
643
-
644
- /* Grid布局样式 */
645
- .grid-descriptions {
646
- width: 100%;
647
- }
648
-
649
- .grid-row {
650
- display: grid;
651
- gap: 16px 24px;
652
- width: 100%;
653
- margin-bottom: 16px;
654
- }
655
-
656
- .grid-row:last-child {
657
- margin-bottom: 0;
658
- }
659
-
660
- .grid-item {
661
- display: flex;
662
- align-items: flex-start;
663
- padding: 8px;
664
- border-radius: 4px;
665
- transition: background-color 0.3s;
666
- min-width: 0; /* 允许内容收缩 */
667
- min-height: 40px; /* 确保行高一致 */
668
- }
669
-
670
- .grid-item:hover {
671
- background-color: rgba(0, 0, 0, 0.02);
672
- }
673
-
674
- /* 占位符项目样式 */
675
- .placeholder-item {
676
- background-color: transparent !important;
677
- }
678
-
679
- .placeholder-item:hover {
680
- background-color: transparent !important;
681
- }
682
-
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;
730
- }
731
-
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;
739
- }
740
-
741
- /* Grid布局冒号样式 */
742
- .grid-item .colon {
743
- margin: 0 2px;
744
- color: rgba(0, 0, 0, 0.65);
745
- font-size: 14px;
746
- }
747
-
748
- .description-item {
749
- display: inline-flex;
750
- align-items: center;
751
- padding: 4px 8px;
752
- border-radius: 4px;
753
- transition: background-color 0.3s;
754
- white-space: nowrap;
755
- flex: 0 1 auto;
756
- }
757
-
758
- .description-item:hover {
759
- background-color: rgba(0, 0, 0, 0.02);
760
- }
761
-
762
- /* 共用样式 */
763
- .label-wrapper {
764
- display: flex;
765
- align-items: center;
766
- gap: 8px;
767
- color: rgba(0, 0, 0, 0.65);
768
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
769
- white-space: nowrap;
770
- }
771
-
772
- .label-text {
773
- white-space: nowrap;
774
- color: #313131;
775
- text-decoration: none !important;
776
- }
777
-
778
- .content-wrapper {
779
- display: inline-flex;
780
- align-items: center;
781
- margin-left: 4px;
782
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
783
- color: rgba(0, 0, 0, 0.85);
784
- text-decoration: none !important;
785
- max-width: 300px;
786
- overflow: hidden;
787
- text-overflow: ellipsis;
788
- white-space: nowrap;
789
- }
790
-
791
- /* 强制移除任何链接样式 */
792
- ::v-deep a {
793
- color: #313131 !important;
794
- text-decoration: none !important;
795
- }
796
-
797
- .detail-button-wrapper {
798
- position: absolute;
799
- right: 0;
800
- top: 0;
801
- z-index: 10;
802
- padding: 4px 8px;
803
- white-space: nowrap;
804
- background-color: #fff;
805
- }
806
-
807
- /* 底部区域:分割线 + 三列内容 */
808
- .xhdesc-footer {
809
- margin-top: 12px;
810
- }
811
-
812
- .xhdesc-divider {
813
- width: calc(100% + 24px);
814
- height: 0;
815
- border-bottom: 1px solid #E5E9F0;
816
- margin: 10px -12px 14px;
817
- overflow: hidden;
818
- }
819
-
820
- /* medical-history 模式:左 padding 11px,右 12px */
821
- .patient-info-descriptions.xhdesc-medical-history .xhdesc-divider {
822
- width: calc(100% + 23px);
823
- margin-left: -11px;
824
- margin-right: -12px;
825
- }
826
-
827
- .footer-grid {
828
- display: grid;
829
- grid-template-columns: 1fr; // 单列
830
- gap: 8px 24px; // 与上方描述项间距保持一致
831
- align-items: start; // 左上对齐
832
- }
833
-
834
- .footer-right {
835
- margin-top: 8px;
836
- display: flex;
837
- justify-content: flex-end;
838
- align-items: center;
839
- gap: 16px;
840
- }
841
-
842
- .footer-right-item {
843
- display: inline-flex;
844
- align-items: center;
845
- }
846
-
847
- /* Ant Design 描述列表样式覆盖 */
848
- ::v-deep(.ant-descriptions-row) {
849
- display: flex;
850
- flex-direction: row;
851
- align-items: flex-start;
852
- }
853
-
854
- ::v-deep(.ant-descriptions-item) {
855
- padding: 0 !important;
856
- display: flex !important;
857
- align-items: flex-start !important;
858
- flex-direction: row !important;
859
- margin-right: 24px;
860
- width: fit-content !important;
861
- margin-bottom: 16px;
862
- }
863
-
864
- ::v-deep(.ant-descriptions-item-container) {
865
- display: flex !important;
866
- flex-direction: row !important;
867
- align-items: flex-start !important;
868
- position: relative;
869
- gap: 0 !important;
870
- width: 100% !important;
871
- }
872
-
873
- ::v-deep(.ant-descriptions-item-label) {
874
- color: rgba(0, 0, 0, 0.65);
875
- padding: 0 !important;
876
- margin: 0 !important;
877
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
878
- display: inline-flex !important;
879
- align-items: center !important;
880
- white-space: nowrap !important;
881
- min-width: v-bind('(config && config.style && config.style.labelWidth) || "80px"');
882
- justify-content: flex-start;
883
- padding-right: 2px !important;
884
- }
885
-
886
- ::v-deep(.ant-descriptions-item-content) {
887
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
888
- display: inline-flex !important;
889
- align-items: center !important;
890
- padding: 0 !important;
891
- margin: 0 !important;
892
- margin-left: 0px !important;
893
- }
894
-
895
- ::v-deep(.ant-descriptions-item-colon) {
896
- position: static !important;
897
- display: inline-flex !important;
898
- align-items: center !important;
899
- margin: 0 !important;
900
- padding: 0 !important;
901
- margin-right: 2px !important;
902
- }
903
-
904
- ::v-deep(.ant-descriptions-item-container:hover) {
905
- background-color: rgba(0, 0, 0, 0.02);
906
- border-radius: 4px;
907
- }
908
-
909
- ::v-deep(.ant-btn-link) {
910
- padding: 0;
911
- height: auto;
912
- line-height: 1;
913
- }
914
-
915
- ::v-deep(.ant-btn-link:hover) {
916
- color: #1890ff;
917
- background: transparent;
918
- }
919
-
920
- /* 响应式调整 */
921
- @media screen and (max-width: 768px) {
922
- .content-wrapper {
923
- max-width: 200px;
924
- }
925
- }
926
-
927
- @media screen and (max-width: 576px) {
928
- .content-wrapper {
929
- max-width: 150px;
930
- }
931
- .flex-descriptions {
932
- gap: 4px 12px;
933
- }
934
- }
935
-
936
- /* 添加虚线样式 */
937
- .with-divider {
938
- position: relative;
939
- margin-bottom: 16px !important;
940
- }
941
-
942
- .with-divider::after {
943
- content: '';
944
- position: absolute;
945
- left: 0;
946
- bottom: -8px;
947
- width: 100%;
948
- height: 0;
949
- border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
950
- }
951
-
952
- /* 对于 Ant Design 描述列表的特殊处理 */
953
- ::v-deep(.ant-descriptions-item.with-divider) {
954
- position: relative;
955
- margin-bottom: 16px !important;
956
- }
957
-
958
- ::v-deep(.ant-descriptions-item.with-divider::after) {
959
- content: '';
960
- position: absolute;
961
- left: 0;
962
- bottom: -8px;
963
- width: 100%;
964
- height: 0;
965
- border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
966
- }
967
-
968
- /* 加边框 */
969
- .xhdesc-description {
970
- padding: 4px 4px 4px 4px;
971
-
972
- &.patient-info-descriptions,
973
- .patient-info-descriptions {
974
- border: 1px solid #E5E9F0;
975
- border-radius: 6px;
976
- padding: 6.5px 12px;
977
-
978
- ::v-deep .ant-btn-link {
979
- border: none;
980
- }
981
-
982
- ::v-deep .ant-descriptions-item-content {
983
- font-weight: bold;
984
- }
985
- }
986
- }
987
- /* 病患信息样式开关:patient-style */
988
- .xhdesc-patient-style {
989
- min-height: 41px;
990
- border-radius: 6px;
991
- opacity: 1;
992
- background: #FFFFFF;
993
- box-sizing: border-box;
994
- border: 0px solid #E5E9F0;
995
- padding-bottom: 0px !important;
996
- width: 100%;
997
- overflow: hidden;
998
-
999
- &.patient-info-descriptions,
1000
- .patient-info-descriptions {
1001
- border: 0px solid #E5E9F0;
1002
- border-radius: 6px;
1003
- background: #FFFFFF;
1004
- min-height: 41px;
1005
- display: flex;
1006
- align-items: center;
1007
- flex-wrap: wrap;
1008
- padding: 8px 12px;
1009
-
1010
- ::v-deep .label-wrapper .label-text {
1011
- font-family: "Source Han Sans";
1012
- font-size: 16px !important;
1013
- font-weight: 400 !important;
1014
- line-height: 23px !important;
1015
- letter-spacing: 0em;
1016
- font-feature-settings: "kern" on;
1017
- color: #5D5C5C;
1018
- white-space: nowrap;
1019
- }
1020
-
1021
- ::v-deep .label-wrapper.with-avatar {
1022
- gap: 9px;
1023
- }
1024
-
1025
- .gender-icon {
1026
- margin-top: 2px;
1027
- }
1028
- .gender-img {
1029
- width: 20px;
1030
- height: 20px;
1031
- opacity: 1;
1032
- display: inline-block;
1033
- }
1034
-
1035
- ::v-deep .detail-button-wrapper .ant-btn .anticon {
1036
- margin-left: 4px;
1037
- color: #94979E;
1038
- opacity: 1;
1039
- }
1040
-
1041
- ::v-deep .detail-button-wrapper .ant-btn,
1042
- ::v-deep .detail-button-wrapper .ant-btn span {
1043
- font-family: "Source Han Sans";
1044
- font-size: 16px;
1045
- color: #5D5C5C;
1046
- white-space: nowrap;
1047
- }
1048
-
1049
- ::v-deep .ant-descriptions-item-content,
1050
- ::v-deep .content-wrapper,
1051
- .medical-history-text {
1052
- font-family: "Source Han Sans";
1053
- font-size: 16px !important;
1054
- font-weight: 700;
1055
- line-height: 23px !important;
1056
- letter-spacing: 0em;
1057
- font-feature-settings: "kern" on;
1058
- color: #5D5C5C;
1059
- word-break: break-word;
1060
- }
1061
-
1062
- ::v-deep .ant-descriptions-item {
1063
- padding-bottom: 4px;
1064
- display: flex;
1065
- align-items: center;
1066
- min-height: 32px;
1067
- }
1068
-
1069
- @media (max-width: 768px) {
1070
- padding: 6px 8px;
1071
-
1072
- ::v-deep .ant-descriptions-item {
1073
- flex-basis: 50%; /* 在小屏幕上每行显示两项 */
1074
- }
1075
-
1076
- ::v-deep .label-wrapper .label-text,
1077
- ::v-deep .ant-descriptions-item-content {
1078
- font-size: 14px !important;
1079
- }
1080
- }
1081
- }
1082
- }
1083
-
1084
- /* 展开态:patient-style 自适应高度 */
1085
- .xhdesc-patient-style.xhdesc-open,
1086
- .xhdesc-open .patient-info-descriptions.xhdesc-patient-style,
1087
- .xhdesc-open .xhdesc-patient-style .patient-info-descriptions {
1088
- height: auto;
1089
- }
1090
- .xhdesc-patient-style.xhdesc-open .patient-info-descriptions,
1091
- .xhdesc-open .patient-info-descriptions.xhdesc-patient-style,
1092
- .xhdesc-open .xhdesc-patient-style .patient-info-descriptions {
1093
- align-items: flex-start;
1094
- }
1095
- // 去除住院收费页面两个描述列表之间的间距
1096
- .xhdesc-margin-top-12 {
1097
- margin-top: -12px;
1098
- }
1099
- .xhdesc-no-padding {
1100
- padding: 0px;
1101
- &.patient-info-descriptions,
1102
- .patient-info-descriptions {
1103
- ::v-deep .descriptions-container {
1104
- padding: 0px;
1105
- }
1106
- ::v-deep .content-wrapper {
1107
- margin: 0px;
1108
- }
1109
- }
1110
- }
1111
- // 库存管理左侧边距
1112
- .xhdesc-padding-left15{
1113
- padding-left: 15px;
1114
- }
1115
- // 库存管理左侧字体样式
1116
- .xhdesc-line-height30{
1117
- &.patient-info-descriptions,
1118
- .patient-info-descriptions{
1119
- ::v-deep .ant-descriptions-item{
1120
- margin-bottom: 0px
1121
- }
1122
- ::v-deep .content-wrapper{
1123
- line-height: 30px;
1124
- }
1125
- ::v-deep .ant-descriptions-item-label{
1126
- line-height: 30px;
1127
- }
1128
- ::v-deep .content-wrapper{
1129
- color: #0057FE;
1130
- font-weight: 700
1131
- }
1132
- }
1133
- }
1134
- /* 医疗病史模式:自定义HTML结构样式 */
1135
- .medical-history-descriptions {
1136
- width: 100%;
1137
- }
1138
-
1139
- .medical-history-item {
1140
- margin: 0;
1141
- width: 100%;
1142
- }
1143
-
1144
- .medical-history-item.with-divider {
1145
- position: relative;
1146
- padding-bottom: 4px;
1147
- margin-bottom: 4px;
1148
- }
1149
-
1150
- .medical-history-item.with-divider::after {
1151
- content: '';
1152
- position: absolute;
1153
- left: 0;
1154
- bottom: 0;
1155
- width: 100%;
1156
- height: 0;
1157
- border-bottom: 1px solid rgba(0, 0, 0, 0.15);
1158
- }
1159
-
1160
- .medical-history-content {
1161
- font-family: "Source Han Sans";
1162
- font-size: 18px;
1163
- line-height: 24px;
1164
- letter-spacing: 0em;
1165
- text-align: left;
1166
- word-break: break-word;
1167
- white-space: normal;
1168
- text-indent: 0;
1169
- padding-left: 0;
1170
- margin-left: 0;
1171
- overflow: hidden;
1172
- position: relative;
1173
- }
1174
-
1175
- .medical-history-label {
1176
- font-family: "Source Han Sans";
1177
- font-size: 16px;
1178
- font-weight: 700;
1179
- color: #313131;
1180
- white-space: nowrap;
1181
- float: left;
1182
- margin-right: 0px;
1183
- position: relative;
1184
- z-index: 1;
1185
- }
1186
-
1187
- .medical-history-text {
1188
- font-family: "Source Han Sans";
1189
- font-size: 16px;
1190
- font-weight: 400;
1191
- color: #313131;
1192
- display: block;
1193
- overflow: hidden;
1194
- text-indent: 0;
1195
- padding-left: 0;
1196
- margin-left: 0;
1197
- word-break: break-word;
1198
- white-space: normal;
1199
- text-align: left;
1200
- line-height: 24px;
1201
- margin-top: 0;
1202
- margin-bottom: 0;
1203
- }
1204
-
1205
- .medical-history-text.ellipsis {
1206
- display: -webkit-box;
1207
- -webkit-box-orient: vertical;
1208
- -webkit-line-clamp: 3;
1209
- line-clamp: 3;
1210
- overflow: hidden;
1211
- cursor: pointer;
1212
- position: relative;
1213
- word-break: break-word;
1214
- white-space: normal;
1215
- line-height: 24px;
1216
- text-indent: 0;
1217
- padding-left: 0;
1218
- margin-left: 0;
1219
- text-align: left;
1220
- -webkit-box-pack: start;
1221
- -webkit-box-align: start;
1222
- }
1223
-
1224
- .medical-history-text.ellipsis::after {
1225
- display: none;
1226
- }
1227
-
1228
- .medical-history-text.ellipsis::first-line {
1229
- text-indent: 0;
1230
- }
1231
-
1232
- @supports not (-webkit-line-clamp: 3) {
1233
- .medical-history-text.ellipsis {
1234
- display: block;
1235
- max-height: 72px;
1236
- overflow: hidden;
1237
- position: relative;
1238
- }
1239
-
1240
- .medical-history-text.ellipsis::after {
1241
- content: '...';
1242
- position: absolute;
1243
- right: 0;
1244
- bottom: 0;
1245
- background: #fff;
1246
- padding-left: 4px;
1247
- display: block;
1248
- }
1249
- }
1250
-
1251
- /* 医疗病史样式开关 */
1252
- .patient-info-descriptions.xhdesc-medical-history {
1253
- padding: 9px 12px 10px 11px !important;
1254
- .descriptions-container {
1255
- padding-right: 0;
1256
- padding-left: 0px;
1257
- }
1258
- .medical-history-footer {
1259
- width: 100%;
1260
- }
1261
- .medical-history-footer .footer-right {
1262
- margin-top: 8px;
1263
- display: flex;
1264
- justify-content: flex-end;
1265
- align-items: flex-start;
1266
- gap: 16px;
1267
- width: 100%;
1268
- }
1269
- .medical-history-footer .footer-right .label-wrapper .label-text {
1270
- font-family: "Source Han Sans";
1271
- font-size: 16px;
1272
- font-weight: 700;
1273
- color: #313131;
1274
- line-height: 22px;
1275
- }
1276
- .medical-history-footer .footer-right .content-wrapper {
1277
- font-family: "Source Han Sans";
1278
- font-size: 16px;
1279
- font-weight: 400;
1280
- line-height: 22px;
1281
- color: #313131;
1282
- }
1283
-
1284
- .medical-history-footer .footer-right .medical-history-item {
1285
- display: inline-block;
1286
- text-align: right;
1287
- }
1288
-
1289
- .medical-history-footer .footer-right .medical-history-content {
1290
- text-align: right;
1291
- }
1292
-
1293
- .medical-history-footer .footer-right .medical-history-label {
1294
- float: none;
1295
- display: inline;
1296
- margin-right: 0px;
1297
- }
1298
-
1299
- .medical-history-footer .footer-right .medical-history-text {
1300
- display: inline;
1301
- text-align: right;
1302
- }
1303
-
1304
- .medical-history-footer .footer-right .medical-history-text.ellipsis {
1305
- display: inline;
1306
- text-align: right;
1307
- }
1308
- }
1309
-
1310
- /* 加边框 */
1311
- .xhdesc-border1 {
1312
- &.patient-info-descriptions,
1313
- .patient-info-descriptions {
1314
- border: 1px solid #E5E9F0;
1315
- border-radius: 6px;
1316
- }
1317
- }
1318
-
1319
- .xhdesc-report-mode {
1320
- &.patient-info-descriptions,
1321
- .patient-info-descriptions {
1322
- ::v-deep .flex-descriptions{
1323
- gap: 2px;
1324
- .description-item {
1325
- min-width: 175px;
1326
- border-radius: 0px;
1327
- display: inline-block;
1328
- padding: 10px;
1329
- border: 1px solid #E5E9F0;
1330
- .content-wrapper {
1331
- margin-left: 0px;
1332
- width: 100%;
1333
- margin-top: 14px;
1334
- display: flex; justify-content: space-between;
1335
- }
1336
- }
1337
- }
1338
- ::v-deep .report-value {
1339
- font-weight: bold;
1340
- color: #0057FE;
1341
- }
1342
- ::v-deep .report-unit {
1343
- font-weight: bold;
1344
- text-align: end;
1345
- }
1346
- }
1347
- }
1348
- </style>
1
+ <template>
2
+ <div class="patient-info-descriptions" :class="wrapperClassObject">
3
+ <div class="descriptions-container">
4
+ <!-- 详情/收起按钮 -->
5
+ <div v-if="hasMoreItems" class="detail-button-wrapper">
6
+ <a-button
7
+ :type="(config && config.detailsConfig && config.detailsConfig.buttonType) || 'link'"
8
+ @click="toggleDetails"
9
+ >
10
+ {{ showAllItems ? '收起' : ((config && config.detailsConfig && config.detailsConfig.buttonText) || '详情') }}
11
+ <a-icon :type="showAllItems ? 'up' : 'down'" />
12
+ </a-button>
13
+ </div>
14
+
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']">
91
+ <a-descriptions
92
+ :colon="getGlobalColon()"
93
+ :column="config.layout"
94
+ :size="(config && config.style && config.style.size)"
95
+ :bordered="(config && config.style && config.style.bordered)"
96
+ layout="horizontal">
97
+ <template v-if="data">
98
+ <!-- 显示前N个标签 -->
99
+ <a-descriptions-item
100
+ v-for="(item) in visibleItemsFiltered"
101
+ :key="item.field"
102
+ :colon="getItemColon(item)"
103
+ :class="{ 'with-divider': item.isLine }">
104
+ <template #label>
105
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
106
+ <div v-if="item.showAvatar" class="gender-icon">
107
+ <img :src="maleIcon" alt="male" class="gender-img" />
108
+ </div>
109
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
110
+ </div>
111
+ </template>
112
+ <a-tooltip
113
+ v-if="isContentOverflow(data[item.field])"
114
+ :title="data[item.field]"
115
+ placement="topLeft"
116
+ :overlay-style="{ maxWidth: '400px' }"
117
+ >
118
+ <div
119
+ class="content-wrapper ellipsis"
120
+ :data-full-text="data[item.field]"
121
+ >
122
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
123
+ <div class="report-value">
124
+ {{ data[item.field] }}
125
+ </div>
126
+ <div class="report-unit">
127
+ {{ item.unit }}
128
+ </div>
129
+ </template>
130
+ <template v-else>
131
+ {{ data[item.field] }}
132
+ </template>
133
+ </div>
134
+ </a-tooltip>
135
+ <div
136
+ v-else
137
+ class="content-wrapper"
138
+ :data-full-text="data[item.field]"
139
+ >
140
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
141
+ <div class="report-value">
142
+ {{ data[item.field] }}
143
+ </div>
144
+ <div class="report-unit">
145
+ {{ item.unit }}
146
+ </div>
147
+ </template>
148
+ <template v-else>
149
+ {{ data[item.field] }}
150
+ </template>
151
+ </div>
152
+ </a-descriptions-item>
153
+
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>
161
+ </template>
162
+
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>
178
+ <div
179
+ class="content-wrapper"
180
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
181
+ :data-full-text="data[item.field]"
182
+ >
183
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
184
+ <div class="report-value">
185
+ {{ data[item.field] }}
186
+ </div>
187
+ <div class="report-unit">
188
+ {{ item.unit }}
189
+ </div>
190
+ </template>
191
+ <template v-else>
192
+ {{ data[item.field] }}
193
+ </template>
194
+ </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>
204
+ </template>
205
+ </a-descriptions>
206
+ </template>
207
+
208
+ <!-- 医疗病史模式:使用自定义HTML结构实现文本环绕 -->
209
+ <template v-else-if="config && config.layout && wrapperClassObject['xhdesc-medical-history']">
210
+ <div class="medical-history-descriptions">
211
+ <template v-if="data">
212
+ <!-- 显示前N个标签 -->
213
+ <div
214
+ v-for="(item) in visibleItemsFiltered"
215
+ :key="item.field"
216
+ :class="['medical-history-item', { 'with-divider': item.isLine }]"
217
+ >
218
+ <div class="medical-history-content">
219
+ <a-tooltip
220
+ v-if="isContentOverflow(data[item.field])"
221
+ :title="data[item.field]"
222
+ placement="topLeft"
223
+ :overlay-style="{ maxWidth: '400px' }"
224
+ >
225
+ <div class="medical-history-text ellipsis">
226
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
227
+ </div>
228
+ </a-tooltip>
229
+ <div
230
+ v-else
231
+ class="medical-history-text"
232
+ >
233
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
234
+ </div>
235
+ </div>
236
+ </div>
237
+
238
+ <!-- 展开后显示剩余标签 -->
239
+ <template v-if="showAllItems">
240
+ <div
241
+ v-for="item in hiddenItemsFiltered"
242
+ :key="item.field"
243
+ class="medical-history-item"
244
+ >
245
+ <div class="medical-history-content">
246
+ <a-tooltip
247
+ v-if="isContentOverflow(data[item.field])"
248
+ :title="data[item.field]"
249
+ placement="topLeft"
250
+ :overlay-style="{ maxWidth: '400px' }"
251
+ >
252
+ <div class="medical-history-text ellipsis">
253
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
254
+ </div>
255
+ </a-tooltip>
256
+ <div
257
+ v-else
258
+ class="medical-history-text"
259
+ >
260
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
261
+ </div>
262
+ </div>
263
+ </div>
264
+ </template>
265
+ </template>
266
+ </div>
267
+ </template>
268
+
269
+ <!-- 当没有 layout 配置时使用自适应布局 -->
270
+ <template v-else>
271
+ <div class="flex-descriptions">
272
+ <template v-if="data">
273
+ <!-- 显示可见的标签 -->
274
+ <div
275
+ v-for="(item) in visibleItemsFiltered"
276
+ :key="item.field"
277
+ :class="['description-item', { 'with-divider': item.isLine }]"
278
+ >
279
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
280
+ <div v-if="item.showAvatar" class="gender-icon">
281
+ <img :src="maleIcon" alt="male" class="gender-img" />
282
+ </div>
283
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
284
+ </div>
285
+ <a-tooltip
286
+ v-if="isContentOverflow(data[item.field])"
287
+ :title="data[item.field]"
288
+ placement="topLeft"
289
+ :overlay-style="{ maxWidth: '400px' }"
290
+ >
291
+ <div
292
+ class="content-wrapper ellipsis"
293
+ :data-full-text="data[item.field]"
294
+ >
295
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
296
+ <div class="report-value">
297
+ {{ data[item.field] }}
298
+ </div>
299
+ <div class="report-unit">
300
+ {{ item.unit }}
301
+ </div>
302
+ </template>
303
+ <template v-else>
304
+ {{ data[item.field] }}
305
+ </template>
306
+ </div>
307
+ </a-tooltip>
308
+ <div
309
+ v-else
310
+ class="content-wrapper"
311
+ :data-full-text="data[item.field]"
312
+ >
313
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
314
+ <div class="report-value">
315
+ {{ data[item.field] }}
316
+ </div>
317
+ <div class="report-unit">
318
+ {{ item.unit }}
319
+ </div>
320
+ </template>
321
+ <template v-else>
322
+ {{ data[item.field] }}
323
+ </template>
324
+ </div>
325
+ </div>
326
+
327
+ <!-- 展开后显示的内容 -->
328
+ <template v-if="showAllItems">
329
+ <div
330
+ v-for="item in hiddenItemsFiltered"
331
+ :key="item.field"
332
+ class="description-item"
333
+ >
334
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
335
+ <div v-if="item.showAvatar" class="gender-icon">
336
+ <img :src="maleIcon" alt="male" class="gender-img" />
337
+ </div>
338
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
339
+ </div>
340
+ <div
341
+ class="content-wrapper"
342
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
343
+ :data-full-text="data[item.field]"
344
+ >
345
+ <template v-if="wrapperClassObject['xhdesc-report-mode']">
346
+ <div class="report-value">
347
+ {{ data[item.field] }}
348
+ </div>
349
+ <div class="report-unit">
350
+ {{ item.unit }}
351
+ </div>
352
+ </template>
353
+ <template v-else>
354
+ {{ data[item.field] }}
355
+ </template>
356
+ </div>
357
+ </div>
358
+ </template>
359
+ </template>
360
+ </div>
361
+ </template>
362
+
363
+ <!-- 可选:底部区域(分割线 + 三列内容) -->
364
+ <div v-if="config && config.footer && Array.isArray(config.footer.items) && data" class="xhdesc-footer">
365
+ <div class="xhdesc-divider" />
366
+ <!-- 医疗病史模式下的footer结构 -->
367
+ <div v-if="wrapperClassObject['xhdesc-medical-history']" class="medical-history-footer">
368
+ <div
369
+ v-for="(item, idx) in config.footer.items"
370
+ :key="item.field || idx"
371
+ class="medical-history-item">
372
+ <div class="medical-history-content">
373
+ <a-tooltip
374
+ v-if="isContentOverflow(data[item.field])"
375
+ :title="data[item.field]"
376
+ placement="topLeft"
377
+ :overlay-style="{ maxWidth: '400px' }"
378
+ >
379
+ <div class="medical-history-text ellipsis">
380
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
381
+ </div>
382
+ </a-tooltip>
383
+ <div
384
+ v-else
385
+ class="medical-history-text"
386
+ >
387
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
388
+ </div>
389
+ </div>
390
+ </div>
391
+ <!-- 右侧信息:换到下一行并靠右对齐(如 医生 / 医嘱日期) -->
392
+ <div
393
+ v-if="Array.isArray(config.footer.rightItems) && config.footer.rightItems.length"
394
+ class="footer-right">
395
+ <div
396
+ v-for="(item, ridx) in config.footer.rightItems"
397
+ :key="item.field || ridx"
398
+ class="footer-right-item">
399
+ <div class="label-wrapper">
400
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
401
+ </div>
402
+ <div
403
+ class="content-wrapper"
404
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
405
+ :data-full-text="data[item.field]"
406
+ >{{ data[item.field] }}
407
+ </div>
408
+ </div>
409
+ </div>
410
+ </div>
411
+ <!-- 非医疗病史模式下的footer结构 -->
412
+ <div v-else class="footer-grid">
413
+ <div
414
+ v-for="(item, idx) in config.footer.items"
415
+ :key="item.field || idx"
416
+ class="description-item">
417
+ <div class="label-wrapper">
418
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
419
+ </div>
420
+ <div
421
+ class="content-wrapper"
422
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
423
+ :data-full-text="data[item.field]"
424
+ >{{ data[item.field] }}
425
+ </div>
426
+ </div>
427
+ </div>
428
+ <!-- 右侧信息:换到下一行并靠右对齐(如 医生 / 医嘱日期) -->
429
+ <div
430
+ v-if="!wrapperClassObject['xhdesc-medical-history'] && Array.isArray(config.footer.rightItems) && config.footer.rightItems.length"
431
+ class="footer-right">
432
+ <div
433
+ v-for="(item, ridx) in config.footer.rightItems"
434
+ :key="item.field || ridx"
435
+ class="footer-right-item">
436
+ <div class="label-wrapper">
437
+ <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
438
+ </div>
439
+ <div
440
+ class="content-wrapper"
441
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
442
+ :data-full-text="data[item.field]"
443
+ >{{ data[item.field] }}
444
+ </div>
445
+ </div>
446
+ </div>
447
+ </div>
448
+ </div>
449
+ </div>
450
+ </template>
451
+
452
+ <script>
453
+ import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
454
+
455
+ export default {
456
+ name: 'XHDescriptions',
457
+ data () {
458
+ return {
459
+ hiddenConfig: '-1^',
460
+ data: null,
461
+ config: null,
462
+ showAllItems: false,
463
+ maleIcon: require('@vue2-client/assets/svg/male.svg')
464
+ }
465
+ },
466
+ props: {
467
+ queryParamsName: {
468
+ type: String,
469
+ default: ''
470
+ },
471
+ parameter: {
472
+ type: Object,
473
+ default: () => {
474
+ return {}
475
+ }
476
+ }
477
+ },
478
+ computed: {
479
+ wrapperClassObject () {
480
+ const attrs = this.$attrs || {}
481
+ const classes = {}
482
+
483
+ const booleanStyleKeys = [
484
+ 'description',
485
+ 'no-padding',
486
+ 'medical-history',
487
+ 'patient-style',
488
+ 'margin-top-12',
489
+ 'padding-left15',
490
+ 'line-height30',
491
+ 'report-mode',
492
+ 'border1',
493
+ 'grid-formatted'
494
+ ]
495
+ booleanStyleKeys.forEach(key => {
496
+ const val = attrs[key]
497
+ const truthy = val === true || val === '' || val === 'true'
498
+ if (truthy) classes[`xhdesc-${key}`] = true
499
+ })
500
+ const size = attrs.size
501
+ if (size && typeof size === 'string') classes[`xhdesc-size-${size}`] = true
502
+ if (this.showAllItems && this.config && this.config.detailsConfig) classes['xhdesc-open'] = true
503
+ return classes
504
+ },
505
+ detailsAfterIndex () {
506
+ return (this.config && this.config.detailsConfig && this.config.detailsConfig.showAfterIndex) || 999
507
+ },
508
+ hasMoreItems () {
509
+ if (!(this.config && this.config.detailsConfig)) return false
510
+ if (!this.data || !(this.config && this.config.items) || !Array.isArray(this.config.items)) return false
511
+ const hiddenStartIndex = this.detailsAfterIndex || 0
512
+ if (hiddenStartIndex >= this.config.items.length) return false
513
+ for (let i = hiddenStartIndex; i < this.config.items.length; i++) {
514
+ const item = this.config.items[i]
515
+ if (item && item.field && this.data[item.field] !== null && this.data[item.field] !== undefined) {
516
+ return true
517
+ }
518
+ }
519
+ return false
520
+ },
521
+ visibleItems () {
522
+ if (!(this.config && this.config.items)) return []
523
+ if (!(this.config && this.config.detailsConfig)) return this.config.items
524
+ if (this.showAllItems) return this.config.items.slice(0, this.detailsAfterIndex)
525
+ return this.config.items.slice(0, this.detailsAfterIndex)
526
+ },
527
+ hiddenItems () {
528
+ if (!(this.config && this.config.items)) return []
529
+ if (!(this.config && this.config.detailsConfig)) return []
530
+ return this.config.items.slice(this.detailsAfterIndex)
531
+ },
532
+ visibleItemsFiltered () {
533
+ const list = this.visibleItems || []
534
+ if (!this.data) return []
535
+ // 过滤掉占位符项目,占位符在模板中单独处理
536
+ const res = list.filter(item => {
537
+ // 跳过空字段(占位符)
538
+ if (!item.field || item.field === '') return false
539
+ // 其他字段只有在有数据时才显示
540
+ return this.data[item.field] !== null && this.data[item.field] !== undefined
541
+ })
542
+ if (!this.showAllItems) return res
543
+ const hiddenFields = new Set((this.hiddenItems || []).map(i => i.field))
544
+ return res.filter(item => !hiddenFields.has(item.field))
545
+ },
546
+ hiddenItemsFiltered () {
547
+ const list = this.hiddenItems || []
548
+ if (!this.data) return []
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
557
+ },
558
+ // Grid布局的行分组数据
559
+ gridRows () {
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 []
587
+
588
+ const items = [...this.visibleItemsFiltered]
589
+ const rows = []
590
+ let currentIndex = 0
591
+
592
+ for (let i = 0; i < layout.length; i++) {
593
+ const columnsInRow = layout[i]
594
+ const rowItems = items.slice(currentIndex, currentIndex + columnsInRow)
595
+ rows.push(rowItems)
596
+ currentIndex += columnsInRow
597
+ if (currentIndex >= items.length) break
598
+ }
599
+
600
+ return rows
601
+ }
602
+ },
603
+ created () {
604
+ this.getData(this.queryParamsName, {})
605
+ },
606
+ methods: {
607
+ async getData (data, parameterData) {
608
+ this.data = null
609
+ this.showAllItems = false
610
+ getConfigByName(data, 'af-his', res => {
611
+ this.config = res
612
+ const hiddenConfig = (this.config && this.config.hiddenConfig) || (0 === 1)
613
+ const parameter = { ...res.parameter, ...this.parameter, ...parameterData }
614
+ runLogic(res.logicName, parameter, 'af-his').then(result => {
615
+ if (hiddenConfig) {
616
+ for (const key in result) {
617
+ if (Object.prototype.hasOwnProperty.call(result, key) && result[key] === this.hiddenConfig) {
618
+ delete result[key]
619
+ }
620
+ }
621
+ }
622
+ this.data = result
623
+ })
624
+ })
625
+ },
626
+ toggleDetails () {
627
+ this.showAllItems = !this.showAllItems
628
+ },
629
+ isContentOverflow (content) {
630
+ if (!content || typeof content !== 'string') return false
631
+ return content.length > 150
632
+ },
633
+ // 获取全局 colon 配置
634
+ getGlobalColon () {
635
+ if (this.config && this.config.style && this.config.style.colon !== undefined) {
636
+ return this.config.style.colon
637
+ }
638
+ return true // 默认显示冒号
639
+ },
640
+ // 获取单个 item 的 colon 配置
641
+ getItemColon (item) {
642
+ // 优先级:item配置 > 全局配置 > 默认true
643
+ if (item && item.colon !== undefined) {
644
+ return item.colon
645
+ }
646
+ return this.getGlobalColon()
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
+ },
659
+ // 生成CSS Grid模板列样式
660
+ getGridTemplateColumns (columns) {
661
+ if (typeof columns !== 'number' || columns <= 0) return 'repeat(auto-fit, minmax(200px, 1fr))'
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
668
+ }
669
+ },
670
+ watch: {
671
+ queryParamsName: {
672
+ handler (newValue) {
673
+ console.log(newValue)
674
+ this.getData(newValue, {})
675
+ },
676
+ deep: true
677
+ },
678
+ parameter: {
679
+ handler (newValue, oldValue) {
680
+ console.log('监听事件触发:', { old: oldValue, new: newValue })
681
+ this.getData(this.queryParamsName, {})
682
+ },
683
+ deep: true
684
+ }
685
+ }
686
+ }
687
+ </script>
688
+
689
+ <style scoped lang="less">
690
+ .patient-info-descriptions {
691
+ background: #fff;
692
+ border-radius: 4px;
693
+ width: 100%;
694
+ }
695
+
696
+ .descriptions-container {
697
+ position: relative;
698
+ width: 100%;
699
+ padding-right: 80px; /* 为按钮预留空间 */
700
+ }
701
+
702
+ /* 自适应布局样式 */
703
+ .flex-descriptions {
704
+ display: flex;
705
+ flex-wrap: wrap;
706
+ gap: 8px 24px;
707
+ width: 100%;
708
+ }
709
+
710
+ /* Grid布局样式 */
711
+ .grid-descriptions {
712
+ width: 100%;
713
+ }
714
+
715
+ .grid-row {
716
+ display: grid;
717
+ gap: 16px 24px;
718
+ width: 100%;
719
+ margin-bottom: 16px;
720
+ }
721
+
722
+ .grid-row:last-child {
723
+ margin-bottom: 0;
724
+ }
725
+
726
+ .grid-item {
727
+ display: flex;
728
+ align-items: flex-start;
729
+ padding: 8px;
730
+ border-radius: 4px;
731
+ transition: background-color 0.3s;
732
+ min-width: 0; /* 允许内容收缩 */
733
+ min-height: 40px; /* 确保行高一致 */
734
+ }
735
+
736
+ .grid-item:hover {
737
+ background-color: rgba(0, 0, 0, 0.02);
738
+ }
739
+
740
+ /* 占位符项目样式 */
741
+ .placeholder-item {
742
+ background-color: transparent !important;
743
+ }
744
+
745
+ .placeholder-item:hover {
746
+ background-color: transparent !important;
747
+ }
748
+
749
+ .placeholder-item {
750
+ /* 占位符项目保持布局空间 */
751
+ min-height: 32px;
752
+ width: fit-content;
753
+ margin-right: 24px;
754
+ margin-bottom: 16px;
755
+ }
756
+
757
+ .placeholder-content {
758
+ /* 占位符内容为空,不显示任何内容 */
759
+ min-height: 20px; /* 较小的高度,避免视觉突兀 */
760
+ visibility: hidden; /* 完全隐藏内容 */
761
+ }
762
+
763
+ /* Grid布局冒号样式 */
764
+ .colon {
765
+ margin: 0;
766
+ color: rgba(0, 0, 0, 0.65);
767
+ font-size: 14px;
768
+ }
769
+
770
+ .description-item {
771
+ display: inline-flex;
772
+ align-items: center;
773
+ padding: 4px 8px;
774
+ border-radius: 4px;
775
+ transition: background-color 0.3s;
776
+ white-space: nowrap;
777
+ flex: 0 1 auto;
778
+ }
779
+
780
+ .description-item:hover {
781
+ background-color: rgba(0, 0, 0, 0.02);
782
+ }
783
+
784
+ /* 共用样式 */
785
+ .label-wrapper {
786
+ display: flex;
787
+ align-items: center;
788
+ gap: 8px;
789
+ color: rgba(0, 0, 0, 0.65);
790
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
791
+ white-space: nowrap;
792
+ }
793
+
794
+ .label-text {
795
+ white-space: nowrap;
796
+ color: #313131;
797
+ text-decoration: none !important;
798
+ }
799
+
800
+ .content-wrapper {
801
+ display: inline-flex;
802
+ align-items: center;
803
+ margin-left: 4px;
804
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
805
+ color: rgba(0, 0, 0, 0.85);
806
+ text-decoration: none !important;
807
+ max-width: 300px;
808
+ overflow: hidden;
809
+ text-overflow: ellipsis;
810
+ white-space: nowrap;
811
+ }
812
+
813
+ /* 强制移除任何链接样式 */
814
+ ::v-deep a {
815
+ color: #313131 !important;
816
+ text-decoration: none !important;
817
+ }
818
+
819
+ .detail-button-wrapper {
820
+ position: absolute;
821
+ right: 0;
822
+ top: 0;
823
+ z-index: 10;
824
+ padding: 4px 8px;
825
+ white-space: nowrap;
826
+ background-color: #fff;
827
+ }
828
+
829
+ /* 底部区域:分割线 + 三列内容 */
830
+ .xhdesc-footer {
831
+ margin-top: 12px;
832
+ }
833
+
834
+ .xhdesc-divider {
835
+ width: calc(100% + 24px);
836
+ height: 0;
837
+ border-bottom: 1px solid #E5E9F0;
838
+ margin: 10px -12px 14px;
839
+ overflow: hidden;
840
+ }
841
+
842
+ /* medical-history 模式:左 padding 11px,右 12px */
843
+ .patient-info-descriptions.xhdesc-medical-history .xhdesc-divider {
844
+ width: calc(100% + 23px);
845
+ margin-left: -11px;
846
+ margin-right: -12px;
847
+ }
848
+
849
+ .footer-grid {
850
+ display: grid;
851
+ grid-template-columns: 1fr; // 单列
852
+ gap: 8px 24px; // 与上方描述项间距保持一致
853
+ align-items: start; // 左上对齐
854
+ }
855
+
856
+ .footer-right {
857
+ margin-top: 8px;
858
+ display: flex;
859
+ justify-content: flex-end;
860
+ align-items: center;
861
+ gap: 16px;
862
+ }
863
+
864
+ .footer-right-item {
865
+ display: inline-flex;
866
+ align-items: center;
867
+ }
868
+
869
+ /* Ant Design 描述列表样式覆盖 */
870
+ ::v-deep(.ant-descriptions-row) {
871
+ display: flex;
872
+ flex-direction: row;
873
+ align-items: flex-start;
874
+ }
875
+
876
+ ::v-deep(.ant-descriptions-item) {
877
+ padding: 0 !important;
878
+ display: flex !important;
879
+ align-items: stretch !important; /* 拉伸对齐,确保子项高度一致 */
880
+ flex-direction: row !important;
881
+ margin-right: 24px;
882
+ width: fit-content !important;
883
+ margin-bottom: 16px;
884
+ height: 32px !important; /* 固定高度 */
885
+ }
886
+
887
+ ::v-deep(.ant-descriptions-item-container) {
888
+ display: flex !important;
889
+ flex-direction: row !important;
890
+ align-items: flex-start !important;
891
+ position: relative;
892
+ gap: 0 !important;
893
+ width: 100% !important;
894
+ }
895
+
896
+ ::v-deep(.ant-descriptions-item-label) {
897
+ color: rgba(0, 0, 0, 0.65) !important;
898
+ padding: 0 !important;
899
+ margin: 0 !important;
900
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"') !important;
901
+ display: flex !important;
902
+ align-items: center !important;
903
+ justify-content: flex-start !important;
904
+ white-space: nowrap !important;
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;
909
+ padding-right: 2px !important;
910
+ }
911
+
912
+ ::v-deep(.ant-descriptions-item-content) {
913
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"') !important;
914
+ display: flex !important;
915
+ align-items: center !important;
916
+ justify-content: flex-start !important;
917
+ height: 100% !important; /* 占满父容器高度 */
918
+ padding: 0 !important;
919
+ margin: 0 !important;
920
+ margin-left: 0px !important;
921
+ }
922
+
923
+ ::v-deep(.ant-descriptions-item-colon) {
924
+ position: static !important;
925
+ display: inline-flex !important;
926
+ align-items: center !important;
927
+ margin: 0 !important;
928
+ padding: 0 !important;
929
+ margin-right: 2px !important;
930
+ }
931
+
932
+
933
+ ::v-deep(.ant-descriptions-item-container:hover) {
934
+ background-color: rgba(0, 0, 0, 0.02);
935
+ border-radius: 4px;
936
+ }
937
+
938
+ ::v-deep(.ant-btn-link) {
939
+ padding: 0;
940
+ height: auto;
941
+ line-height: 1;
942
+ }
943
+
944
+ /* 隐藏占位符项目的冒号 */
945
+ ::v-deep(.ant-descriptions-item.placeholder-item .ant-descriptions-item-colon) {
946
+ display: none !important;
947
+ }
948
+
949
+
950
+
951
+ ::v-deep(.ant-btn-link:hover) {
952
+ color: #1890ff;
953
+ background: transparent;
954
+ }
955
+
956
+ /* 响应式调整 */
957
+ @media screen and (max-width: 768px) {
958
+ .content-wrapper {
959
+ max-width: 200px;
960
+ }
961
+ }
962
+
963
+ @media screen and (max-width: 576px) {
964
+ .content-wrapper {
965
+ max-width: 150px;
966
+ }
967
+ .flex-descriptions {
968
+ gap: 4px 12px;
969
+ }
970
+ }
971
+
972
+ /* 添加虚线样式 */
973
+ .with-divider {
974
+ position: relative;
975
+ margin-bottom: 16px !important;
976
+ }
977
+
978
+ .with-divider::after {
979
+ content: '';
980
+ position: absolute;
981
+ left: 0;
982
+ bottom: -8px;
983
+ width: 100%;
984
+ height: 0;
985
+ border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
986
+ }
987
+
988
+ /* 对于 Ant Design 描述列表的特殊处理 */
989
+ ::v-deep(.ant-descriptions-item.with-divider) {
990
+ position: relative;
991
+ margin-bottom: 16px !important;
992
+ }
993
+
994
+ ::v-deep(.ant-descriptions-item.with-divider::after) {
995
+ content: '';
996
+ position: absolute;
997
+ left: 0;
998
+ bottom: -8px;
999
+ width: 100%;
1000
+ height: 0;
1001
+ border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
1002
+ }
1003
+
1004
+ /* 加边框 */
1005
+ .xhdesc-description {
1006
+ padding: 4px 4px 4px 4px;
1007
+
1008
+ &.patient-info-descriptions,
1009
+ .patient-info-descriptions {
1010
+ border: 1px solid #E5E9F0;
1011
+ border-radius: 6px;
1012
+ padding: 6.5px 12px;
1013
+
1014
+ ::v-deep .ant-btn-link {
1015
+ border: none;
1016
+ }
1017
+
1018
+ ::v-deep .ant-descriptions-item-content {
1019
+ font-weight: bold;
1020
+ }
1021
+ }
1022
+ }
1023
+ /* 病患信息样式开关:patient-style */
1024
+ .xhdesc-patient-style {
1025
+ min-height: 41px;
1026
+ border-radius: 6px;
1027
+ opacity: 1;
1028
+ background: #FFFFFF;
1029
+ box-sizing: border-box;
1030
+ border: 0px solid #E5E9F0;
1031
+ padding-bottom: 0px !important;
1032
+ width: 100%;
1033
+ overflow: hidden;
1034
+
1035
+ &.patient-info-descriptions,
1036
+ .patient-info-descriptions {
1037
+ border: 0px solid #E5E9F0;
1038
+ border-radius: 6px;
1039
+ background: #FFFFFF;
1040
+ min-height: 41px;
1041
+ display: flex;
1042
+ align-items: center;
1043
+ flex-wrap: wrap;
1044
+ padding: 8px 12px;
1045
+
1046
+ ::v-deep .label-wrapper .label-text {
1047
+ font-family: "Source Han Sans";
1048
+ font-size: 16px !important;
1049
+ font-weight: 400 !important;
1050
+ line-height: 23px !important;
1051
+ letter-spacing: 0em;
1052
+ font-feature-settings: "kern" on;
1053
+ color: #5D5C5C;
1054
+ white-space: nowrap;
1055
+ }
1056
+
1057
+ ::v-deep .label-wrapper.with-avatar {
1058
+ gap: 9px;
1059
+ }
1060
+
1061
+ .gender-icon {
1062
+ margin-top: 2px;
1063
+ }
1064
+ .gender-img {
1065
+ width: 20px;
1066
+ height: 20px;
1067
+ opacity: 1;
1068
+ display: inline-block;
1069
+ }
1070
+
1071
+ ::v-deep .detail-button-wrapper .ant-btn .anticon {
1072
+ margin-left: 4px;
1073
+ color: #94979E;
1074
+ opacity: 1;
1075
+ }
1076
+
1077
+ ::v-deep .detail-button-wrapper .ant-btn,
1078
+ ::v-deep .detail-button-wrapper .ant-btn span {
1079
+ font-family: "Source Han Sans";
1080
+ font-size: 16px;
1081
+ color: #5D5C5C;
1082
+ white-space: nowrap;
1083
+ }
1084
+
1085
+ ::v-deep .ant-descriptions-item-content,
1086
+ ::v-deep .content-wrapper,
1087
+ .medical-history-text {
1088
+ font-family: "Source Han Sans";
1089
+ font-size: 16px !important;
1090
+ font-weight: 700;
1091
+ line-height: 23px !important;
1092
+ letter-spacing: 0em;
1093
+ font-feature-settings: "kern" on;
1094
+ color: #5D5C5C;
1095
+ word-break: break-word;
1096
+ }
1097
+
1098
+ ::v-deep .ant-descriptions-item {
1099
+ padding-bottom: 4px;
1100
+ display: flex;
1101
+ align-items: center;
1102
+ min-height: 32px;
1103
+ }
1104
+
1105
+ @media (max-width: 768px) {
1106
+ padding: 6px 8px;
1107
+
1108
+ ::v-deep .ant-descriptions-item {
1109
+ flex-basis: 50%; /* 在小屏幕上每行显示两项 */
1110
+ }
1111
+
1112
+ ::v-deep .label-wrapper .label-text,
1113
+ ::v-deep .ant-descriptions-item-content {
1114
+ font-size: 14px !important;
1115
+ }
1116
+ }
1117
+ }
1118
+ }
1119
+
1120
+ /* 展开态:patient-style 自适应高度 */
1121
+ .xhdesc-patient-style.xhdesc-open,
1122
+ .xhdesc-open .patient-info-descriptions.xhdesc-patient-style,
1123
+ .xhdesc-open .xhdesc-patient-style .patient-info-descriptions {
1124
+ height: auto;
1125
+ }
1126
+ .xhdesc-patient-style.xhdesc-open .patient-info-descriptions,
1127
+ .xhdesc-open .patient-info-descriptions.xhdesc-patient-style,
1128
+ .xhdesc-open .xhdesc-patient-style .patient-info-descriptions {
1129
+ align-items: flex-start;
1130
+ }
1131
+ // 去除住院收费页面两个描述列表之间的间距
1132
+ .xhdesc-margin-top-12 {
1133
+ margin-top: -12px;
1134
+ }
1135
+ .xhdesc-no-padding {
1136
+ padding: 0px;
1137
+ &.patient-info-descriptions,
1138
+ .patient-info-descriptions {
1139
+ ::v-deep .descriptions-container {
1140
+ padding: 0px;
1141
+ }
1142
+ ::v-deep .content-wrapper {
1143
+ margin: 0px;
1144
+ }
1145
+ }
1146
+ }
1147
+ // 库存管理左侧边距
1148
+ .xhdesc-padding-left15{
1149
+ padding-left: 15px;
1150
+ }
1151
+ // 库存管理左侧字体样式
1152
+ .xhdesc-line-height30{
1153
+ &.patient-info-descriptions,
1154
+ .patient-info-descriptions{
1155
+ ::v-deep .ant-descriptions-item{
1156
+ margin-bottom: 0px
1157
+ }
1158
+ ::v-deep .content-wrapper{
1159
+ line-height: 30px;
1160
+ }
1161
+ ::v-deep .ant-descriptions-item-label{
1162
+ line-height: 30px;
1163
+ }
1164
+ ::v-deep .content-wrapper{
1165
+ color: #0057FE;
1166
+ font-weight: 700
1167
+ }
1168
+ }
1169
+ }
1170
+ /* 医疗病史模式:自定义HTML结构样式 */
1171
+ .medical-history-descriptions {
1172
+ width: 100%;
1173
+ }
1174
+
1175
+ .medical-history-item {
1176
+ margin: 0;
1177
+ width: 100%;
1178
+ }
1179
+
1180
+ .medical-history-item.with-divider {
1181
+ position: relative;
1182
+ padding-bottom: 4px;
1183
+ margin-bottom: 4px;
1184
+ }
1185
+
1186
+ .medical-history-item.with-divider::after {
1187
+ content: '';
1188
+ position: absolute;
1189
+ left: 0;
1190
+ bottom: 0;
1191
+ width: 100%;
1192
+ height: 0;
1193
+ border-bottom: 1px solid rgba(0, 0, 0, 0.15);
1194
+ }
1195
+
1196
+ .medical-history-content {
1197
+ font-family: "Source Han Sans";
1198
+ font-size: 18px;
1199
+ line-height: 24px;
1200
+ letter-spacing: 0em;
1201
+ text-align: left;
1202
+ word-break: break-word;
1203
+ white-space: normal;
1204
+ text-indent: 0;
1205
+ padding-left: 0;
1206
+ margin-left: 0;
1207
+ overflow: hidden;
1208
+ position: relative;
1209
+ }
1210
+
1211
+ .medical-history-label {
1212
+ font-family: "Source Han Sans";
1213
+ font-size: 16px;
1214
+ font-weight: 700;
1215
+ color: #313131;
1216
+ white-space: nowrap;
1217
+ float: left;
1218
+ margin-right: 0px;
1219
+ position: relative;
1220
+ z-index: 1;
1221
+ }
1222
+
1223
+ .medical-history-text {
1224
+ font-family: "Source Han Sans";
1225
+ font-size: 16px;
1226
+ font-weight: 400;
1227
+ color: #313131;
1228
+ display: block;
1229
+ overflow: hidden;
1230
+ text-indent: 0;
1231
+ padding-left: 0;
1232
+ margin-left: 0;
1233
+ word-break: break-word;
1234
+ white-space: normal;
1235
+ text-align: left;
1236
+ line-height: 24px;
1237
+ margin-top: 0;
1238
+ margin-bottom: 0;
1239
+ }
1240
+
1241
+ .medical-history-text.ellipsis {
1242
+ display: -webkit-box;
1243
+ -webkit-box-orient: vertical;
1244
+ -webkit-line-clamp: 3;
1245
+ line-clamp: 3;
1246
+ overflow: hidden;
1247
+ cursor: pointer;
1248
+ position: relative;
1249
+ word-break: break-word;
1250
+ white-space: normal;
1251
+ line-height: 24px;
1252
+ text-indent: 0;
1253
+ padding-left: 0;
1254
+ margin-left: 0;
1255
+ text-align: left;
1256
+ -webkit-box-pack: start;
1257
+ -webkit-box-align: start;
1258
+ }
1259
+
1260
+ .medical-history-text.ellipsis::after {
1261
+ display: none;
1262
+ }
1263
+
1264
+ .medical-history-text.ellipsis::first-line {
1265
+ text-indent: 0;
1266
+ }
1267
+
1268
+ @supports not (-webkit-line-clamp: 3) {
1269
+ .medical-history-text.ellipsis {
1270
+ display: block;
1271
+ max-height: 72px;
1272
+ overflow: hidden;
1273
+ position: relative;
1274
+ }
1275
+
1276
+ .medical-history-text.ellipsis::after {
1277
+ content: '...';
1278
+ position: absolute;
1279
+ right: 0;
1280
+ bottom: 0;
1281
+ background: #fff;
1282
+ padding-left: 4px;
1283
+ display: block;
1284
+ }
1285
+ }
1286
+
1287
+ /* 医疗病史样式开关 */
1288
+ .patient-info-descriptions.xhdesc-medical-history {
1289
+ padding: 9px 12px 10px 11px !important;
1290
+ .descriptions-container {
1291
+ padding-right: 0;
1292
+ padding-left: 0px;
1293
+ }
1294
+ .medical-history-footer {
1295
+ width: 100%;
1296
+ }
1297
+ .medical-history-footer .footer-right {
1298
+ margin-top: 8px;
1299
+ display: flex;
1300
+ justify-content: flex-end;
1301
+ align-items: flex-start;
1302
+ gap: 16px;
1303
+ width: 100%;
1304
+ }
1305
+ .medical-history-footer .footer-right .label-wrapper .label-text {
1306
+ font-family: "Source Han Sans";
1307
+ font-size: 16px;
1308
+ font-weight: 700;
1309
+ color: #313131;
1310
+ line-height: 22px;
1311
+ }
1312
+ .medical-history-footer .footer-right .content-wrapper {
1313
+ font-family: "Source Han Sans";
1314
+ font-size: 16px;
1315
+ font-weight: 400;
1316
+ line-height: 22px;
1317
+ color: #313131;
1318
+ }
1319
+
1320
+ .medical-history-footer .footer-right .medical-history-item {
1321
+ display: inline-block;
1322
+ text-align: right;
1323
+ }
1324
+
1325
+ .medical-history-footer .footer-right .medical-history-content {
1326
+ text-align: right;
1327
+ }
1328
+
1329
+ .medical-history-footer .footer-right .medical-history-label {
1330
+ float: none;
1331
+ display: inline;
1332
+ margin-right: 0px;
1333
+ }
1334
+
1335
+ .medical-history-footer .footer-right .medical-history-text {
1336
+ display: inline;
1337
+ text-align: right;
1338
+ }
1339
+
1340
+ .medical-history-footer .footer-right .medical-history-text.ellipsis {
1341
+ display: inline;
1342
+ text-align: right;
1343
+ }
1344
+ }
1345
+
1346
+ /* 加边框 */
1347
+ .xhdesc-border1 {
1348
+ &.patient-info-descriptions,
1349
+ .patient-info-descriptions {
1350
+ border: 1px solid #E5E9F0;
1351
+ border-radius: 6px;
1352
+ }
1353
+ }
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
+
1383
+ .xhdesc-report-mode {
1384
+ &.patient-info-descriptions,
1385
+ .patient-info-descriptions {
1386
+ ::v-deep .flex-descriptions{
1387
+ gap: 2px;
1388
+ .description-item {
1389
+ min-width: 175px;
1390
+ border-radius: 0px;
1391
+ display: inline-block;
1392
+ padding: 10px;
1393
+ border: 1px solid #E5E9F0;
1394
+ .content-wrapper {
1395
+ margin-left: 0px;
1396
+ width: 100%;
1397
+ margin-top: 14px;
1398
+ display: flex; justify-content: space-between;
1399
+ }
1400
+ }
1401
+ }
1402
+ ::v-deep .report-value {
1403
+ font-weight: bold;
1404
+ color: #0057FE;
1405
+ }
1406
+ ::v-deep .report-unit {
1407
+ font-weight: bold;
1408
+ text-align: end;
1409
+ }
1410
+ }
1411
+ }
1412
+ </style>