vue2-client 1.19.1 → 1.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1412 +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是对象格式且为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>
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>