vue2-client 1.16.44 → 1.16.46

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,620 +1,633 @@
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
- <a-icon :type="showAllItems ? 'up' : 'down'" />
11
- {{ showAllItems ? '收起' : ((config && config.detailsConfig && config.detailsConfig.buttonText) || '详情') }}
12
- </a-button>
13
- </div>
14
-
15
- <!-- 当有 layout 配置时使用 a-descriptions -->
16
- <template v-if="config && config.layout">
17
- <a-descriptions
18
- :column="config.layout"
19
- :size="(config && config.style && config.style.size)"
20
- :bordered="(config && config.style && config.style.bordered)"
21
- layout="horizontal">
22
- <template v-if="data">
23
- <!-- 显示前N个标签 -->
24
- <a-descriptions-item
25
- v-for="(item) in visibleItemsFiltered"
26
- :key="item.field"
27
- :colon="item.colon !== false"
28
- :class="{ 'with-divider': item.isLine }">
29
- <template #label>
30
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
31
- <a-avatar
32
- v-if="item.showAvatar"
33
- :size="item.avatar.size"
34
- :icon="item.avatar.icon"
35
- :style="{ background: item.avatar.background }"
36
- />
37
- <span class="label-text">{{ item.label }}</span>
38
- </div>
39
- </template>
40
- <div class="content-wrapper">
41
- {{ data[item.field] }}
42
- </div>
43
- </a-descriptions-item>
44
-
45
- <!-- 展开后显示剩余标签 -->
46
- <template v-if="showAllItems">
47
- <a-descriptions-item
48
- v-for="item in hiddenItemsFiltered"
49
- :key="item.field"
50
- :colon="item.colon !== false">
51
- <template #label>
52
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
53
- <a-avatar
54
- v-if="item.showAvatar"
55
- :size="item.avatar.size"
56
- :icon="item.avatar.icon"
57
- :style="{ background: item.avatar.background }"
58
- />
59
- <span class="label-text">{{ item.label }}</span>
60
- </div>
61
- </template>
62
- <div class="content-wrapper">
63
- {{ data[item.field] }}
64
- </div>
65
- </a-descriptions-item>
66
- </template>
67
- </template>
68
- </a-descriptions>
69
- </template>
70
-
71
- <!-- 当没有 layout 配置时使用自适应布局 -->
72
- <template v-else>
73
- <div class="flex-descriptions">
74
- <template v-if="data">
75
- <!-- 显示可见的标签 -->
76
- <div
77
- v-for="(item) in visibleItemsFiltered"
78
- :key="item.field"
79
- :class="['description-item', { 'with-divider': item.isLine }]"
80
- >
81
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
82
- <a-avatar
83
- v-if="item.showAvatar"
84
- :size="item.avatar.size"
85
- :icon="item.avatar.icon"
86
- :style="{ background: item.avatar.background }"
87
- />
88
- <span class="label-text">{{ item.label }}:</span>
89
- </div>
90
- <div class="content-wrapper">
91
- {{ data[item.field] }}
92
- </div>
93
- </div>
94
-
95
- <!-- 展开后显示的内容 -->
96
- <template v-if="showAllItems">
97
- <div
98
- v-for="item in hiddenItemsFiltered"
99
- :key="item.field"
100
- class="description-item"
101
- >
102
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
103
- <a-avatar
104
- v-if="item.showAvatar"
105
- :size="item.avatar.size"
106
- :icon="item.avatar.icon"
107
- :style="{ background: item.avatar.background }"
108
- />
109
- <span class="label-text">{{ item.label }}:</span>
110
- </div>
111
- <div class="content-wrapper">
112
- {{ data[item.field] }}
113
- </div>
114
- </div>
115
- </template>
116
- </template>
117
- </div>
118
- </template>
119
- </div>
120
- </div>
121
- </template>
122
-
123
- <script>
124
- import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
125
-
126
- export default {
127
- name: 'XHDescriptions',
128
- data () {
129
- return {
130
- // 隐藏配置 当数据结果 = -1^ 该数据字段会被delete
131
- hiddenConfig: '-1^',
132
- data: null,
133
- config: null,
134
- showAllItems: false // 控制是否显示所有标签
135
- }
136
- },
137
- props: {
138
- queryParamsName: {
139
- type: String,
140
- default: ''
141
- },
142
- parameter: {
143
- type: Object,
144
- default: () => {
145
- return {}
146
- }
147
- }
148
- },
149
- computed: {
150
- // 动态样式开关(与 HForm 思路一致):布尔开关 + size 派生类
151
- wrapperClassObject () {
152
- const attrs = this.$attrs || {}
153
- const classes = {}
154
-
155
- const booleanStyleKeys = [
156
- 'description',
157
- 'no-padding',
158
- 'medical-history'
159
- ]
160
- booleanStyleKeys.forEach(key => {
161
- const val = attrs[key]
162
- const truthy = val === true || val === '' || val === 'true'
163
- if (truthy) classes[`xhdesc-${key}`] = true
164
- })
165
- const size = attrs.size
166
- if (size && typeof size === 'string') classes[`xhdesc-size-${size}`] = true
167
- return classes
168
- },
169
- // 获取详情按钮应该显示在第几个标签后
170
- detailsAfterIndex () {
171
- return (this.config && this.config.detailsConfig && this.config.detailsConfig.showAfterIndex) || 999
172
- },
173
- // 判断是否有更多标签需要显示
174
- hasMoreItems () {
175
- if (!(this.config && this.config.detailsConfig)) return false
176
- if (!this.data || !(this.config && this.config.items) || !Array.isArray(this.config.items)) return false
177
- const hiddenStartIndex = this.detailsAfterIndex || 0
178
- if (hiddenStartIndex >= this.config.items.length) return false
179
- for (let i = hiddenStartIndex; i < this.config.items.length; i++) {
180
- const item = this.config.items[i]
181
- if (item && item.field && this.data[item.field] !== null && this.data[item.field] !== undefined) {
182
- return true
183
- }
184
- }
185
- return false
186
- },
187
- // 获取应该显示的标签
188
- visibleItems () {
189
- if (!(this.config && this.config.items)) return []
190
- if (!(this.config && this.config.detailsConfig)) return this.config.items
191
- if (this.showAllItems) return this.config.items.slice(0, this.detailsAfterIndex)
192
- return this.config.items.slice(0, this.detailsAfterIndex)
193
- },
194
- // 获取隐藏的标签(保持原有逻辑)
195
- hiddenItems () {
196
- if (!(this.config && this.config.items)) return []
197
- if (!(this.config && this.config.detailsConfig)) return []
198
- return this.config.items.slice(this.detailsAfterIndex)
199
- },
200
- // 过滤后可直接渲染的可见项
201
- visibleItemsFiltered () {
202
- const list = this.visibleItems || []
203
- if (!this.data) return []
204
- const res = list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
205
- if (!this.showAllItems) return res
206
- const hiddenFields = new Set((this.hiddenItems || []).map(i => i.field))
207
- return res.filter(item => !hiddenFields.has(item.field))
208
- },
209
- // 过滤后可直接渲染的隐藏项(仅展开时使用)
210
- hiddenItemsFiltered () {
211
- const list = this.hiddenItems || []
212
- if (!this.data) return []
213
- return list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
214
- }
215
- },
216
- created () {
217
- this.getData(this.queryParamsName, {})
218
- },
219
- methods: {
220
- async getData (data, parameterData) {
221
- this.data = null
222
- this.showAllItems = false
223
- getConfigByName(data, 'af-his', res => {
224
- this.config = res
225
- const hiddenConfig = (this.config && this.config.hiddenConfig) || (0 === 1)
226
- const parameter = { ...res.parameter, ...this.parameter, ...parameterData }
227
- runLogic(res.logicName, parameter, 'af-his').then(result => {
228
- if (hiddenConfig) {
229
- for (const key in result) {
230
- if (Object.prototype.hasOwnProperty.call(result, key) && result[key] === this.hiddenConfig) {
231
- delete result[key]
232
- }
233
- }
234
- }
235
- this.data = result
236
- })
237
- })
238
- },
239
- toggleDetails () {
240
- this.showAllItems = !this.showAllItems
241
- }
242
- },
243
- watch: {
244
- queryParamsName: {
245
- handler (newValue) {
246
- console.log(newValue)
247
- this.getData(newValue, {})
248
- },
249
- deep: true
250
- },
251
- parameter: {
252
- handler (newValue, oldValue) {
253
- console.log('监听事件触发:', { old: oldValue, new: newValue })
254
- // 当 parameter 变化时重新获取数据
255
- this.getData(this.queryParamsName, {})
256
- },
257
- deep: true // 深度监听对象内部变化
258
- }
259
- }
260
- }
261
- </script>
262
-
263
- <style scoped lang="less">
264
- .patient-info-descriptions {
265
- background: #fff;
266
- padding: 12px;
267
- border-radius: 4px;
268
- width: 100%;
269
- }
270
-
271
- .descriptions-container {
272
- position: relative;
273
- width: 100%;
274
- padding-right: 80px; /* 为按钮预留空间 */
275
- }
276
-
277
- /* 自适应布局样式 */
278
- .flex-descriptions {
279
- display: flex;
280
- flex-wrap: wrap;
281
- gap: 8px 24px;
282
- width: 100%;
283
- }
284
-
285
- .description-item {
286
- display: inline-flex;
287
- align-items: center;
288
- padding: 4px 8px;
289
- border-radius: 4px;
290
- transition: background-color 0.3s;
291
- white-space: nowrap;
292
- flex: 0 1 auto;
293
- }
294
-
295
- .description-item:hover {
296
- background-color: rgba(0, 0, 0, 0.02);
297
- }
298
-
299
- /* 共用样式 */
300
- .label-wrapper {
301
- display: flex;
302
- align-items: center;
303
- gap: 8px;
304
- color: rgba(0, 0, 0, 0.65);
305
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
306
- white-space: nowrap;
307
- }
308
-
309
- .label-wrapper.with-avatar {
310
- gap: 8px;
311
- }
312
-
313
- .label-text {
314
- white-space: nowrap;
315
- }
316
-
317
- .content-wrapper {
318
- display: inline-flex;
319
- align-items: center;
320
- margin-left: 4px;
321
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
322
- color: rgba(0, 0, 0, 0.85);
323
- max-width: 300px;
324
- overflow: hidden;
325
- text-overflow: ellipsis;
326
- white-space: nowrap;
327
- }
328
-
329
- .detail-button-wrapper {
330
- position: absolute;
331
- right: 0;
332
- top: 0;
333
- z-index: 10;
334
- padding: 4px 8px;
335
- white-space: nowrap;
336
- background-color: #fff;
337
- }
338
-
339
- /* Ant Design 描述列表样式覆盖 */
340
- :deep(.ant-descriptions-row) {
341
- display: flex;
342
- flex-direction: row;
343
- align-items: flex-start;
344
- }
345
-
346
- :deep(.ant-descriptions-item) {
347
- padding: 0 !important;
348
- display: flex !important;
349
- align-items: flex-start !important;
350
- flex-direction: row !important;
351
- margin-right: 24px;
352
- width: fit-content !important;
353
- margin-bottom: 16px;
354
- }
355
-
356
- :deep(.ant-descriptions-item-container) {
357
- display: flex !important;
358
- flex-direction: row !important;
359
- align-items: flex-start !important;
360
- position: relative;
361
- gap: 0 !important;
362
- width: 100% !important;
363
- }
364
-
365
- :deep(.ant-descriptions-item-label) {
366
- color: rgba(0, 0, 0, 0.65);
367
- padding: 0 !important;
368
- margin: 0 !important;
369
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
370
- display: inline-flex !important;
371
- align-items: center !important;
372
- white-space: nowrap !important;
373
- min-width: v-bind('(config && config.style && config.style.labelWidth) || "80px"');
374
- justify-content: flex-start;
375
- padding-right: 2px !important;
376
- }
377
-
378
- :deep(.ant-descriptions-item-content) {
379
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
380
- display: inline-flex !important;
381
- align-items: center !important;
382
- padding: 0 !important;
383
- margin: 0 !important;
384
- margin-left: 0px !important;
385
- }
386
-
387
- :deep(.ant-descriptions-item-colon) {
388
- position: static !important;
389
- display: inline-flex !important;
390
- align-items: center !important;
391
- margin: 0 !important;
392
- padding: 0 !important;
393
- margin-right: 2px !important;
394
- }
395
-
396
- :deep(.ant-descriptions-item-container:hover) {
397
- background-color: rgba(0, 0, 0, 0.02);
398
- border-radius: 4px;
399
- }
400
-
401
- :deep(.ant-btn-link) {
402
- padding: 0;
403
- height: auto;
404
- line-height: 1;
405
- }
406
-
407
- :deep(.ant-btn-link:hover) {
408
- color: #1890ff;
409
- background: transparent;
410
- }
411
-
412
- /* 响应式调整 */
413
- @media screen and (max-width: 768px) {
414
- .content-wrapper {
415
- max-width: 200px;
416
- }
417
- }
418
-
419
- @media screen and (max-width: 576px) {
420
- .content-wrapper {
421
- max-width: 150px;
422
- }
423
- .flex-descriptions {
424
- gap: 4px 12px;
425
- }
426
- }
427
-
428
- /* 添加虚线样式 */
429
- .with-divider {
430
- position: relative;
431
- margin-bottom: 16px !important;
432
- }
433
-
434
- .with-divider::after {
435
- content: '';
436
- position: absolute;
437
- left: 0;
438
- bottom: -8px;
439
- width: 100%;
440
- height: 0;
441
- border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
442
- }
443
-
444
- /* 对于 Ant Design 描述列表的特殊处理 */
445
- :deep(.ant-descriptions-item.with-divider) {
446
- position: relative;
447
- margin-bottom: 16px !important;
448
- }
449
-
450
- :deep(.ant-descriptions-item.with-divider::after) {
451
- content: '';
452
- position: absolute;
453
- left: 0;
454
- bottom: -8px;
455
- width: 100%;
456
- height: 0;
457
- border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
458
- }
459
- /* 加边框 */
460
- /* 加边框 */
461
- .xhdesc-description {
462
- padding: 4px 4px 4px 4px;
463
-
464
- /* 作用域内 *patient-info-descriptions */
465
- &.patient-info-descriptions,
466
- .patient-info-descriptions {
467
- border: 1px solid #E5E9F0;
468
- border-radius: 6px;
469
- padding: 6.5px 12px;
470
-
471
- /* *ant-btn-link */
472
- :deep(.ant-btn-link) {
473
- border: none;
474
- }
475
-
476
- /* *ant-descriptions-item-content */
477
- :deep(.ant-descriptions-item-content) {
478
- font-weight: bold;
479
- }
480
- }
481
- }
482
- .xhdesc-no-padding {
483
- padding: 0px;
484
- }
485
- /* 医疗病史样式开关:通过 wrapperClassObject 添加类 xhdesc-medical-history */
486
- .patient-info-descriptions.xhdesc-medical-history {
487
- /* 移除右侧空白(本模式不需要详情按钮预留空间) */
488
- .descriptions-container {
489
- padding-right: 0;
490
- padding-left: 12px;
491
- }
492
-
493
- /* 保持原有的自适应布局样式 */
494
- .flex-descriptions {
495
- gap: 4px 16px;
496
- }
497
-
498
- .description-item {
499
- padding: 2px 4px;
500
- width: 100%;
501
- align-items: flex-start;
502
- display: flex;
503
- flex-direction: column;
504
- }
505
-
506
- /* 只修改布局,保持原有字体样式 */
507
- .label-wrapper {
508
- font-family: "Source Han Sans";
509
- font-size: 18px;
510
- font-weight: 600;
511
- line-height: 24px;
512
- text-align: justify;
513
- letter-spacing: 0em;
514
- white-space: nowrap;
515
- margin-right: 8px;
516
- margin-bottom: 0;
517
- display: inline;
518
- }
519
-
520
- .content-wrapper {
521
- font-family: "Source Han Sans";
522
- font-size: 18px;
523
- font-weight: 400;
524
- line-height: 24px;
525
- letter-spacing: 0em;
526
- margin-left: 0;
527
- max-width: none;
528
- overflow: visible;
529
- text-overflow: initial;
530
- white-space: normal;
531
- word-break: break-word;
532
- display: inline;
533
- }
534
-
535
- /* 修复Ant Design描述列表的布局,保持字体样式 */
536
- :deep(.ant-descriptions-item) {
537
- display: block !important;
538
- white-space: nowrap;
539
- width: 100% !important;
540
- margin-bottom: 8px;
541
- margin-right: 0;
542
- }
543
-
544
- :deep(.ant-descriptions-item-container) {
545
- display: inline !important;
546
- white-space: nowrap;
547
- width: auto !important;
548
- align-items: start !important;
549
- }
550
-
551
- :deep(.ant-descriptions-item-label) {
552
- display: inline !important;
553
- white-space: nowrap !important;
554
- min-width: auto !important;
555
- padding-right: 1px !important;
556
- /* 保持原有字体样式 */
557
- font-family: "Source Han Sans" !important;
558
- font-size: 18px !important;
559
- font-weight: 600 !important;
560
- line-height: 24px !important;
561
- text-align: justify !important;
562
- letter-spacing: 0em !important;
563
- }
564
-
565
- :deep(.ant-descriptions-item-content) {
566
- display: inline !important;
567
- white-space: normal !important;
568
- word-break: break-word !important;
569
- margin-left: 0 !important;
570
- overflow: visible !important;
571
- /* 保持原有字体样式 */
572
- font-family: "Source Han Sans" !important;
573
- font-size: 18px !important;
574
- font-weight: 400 !important;
575
- line-height: 24px !important;
576
- letter-spacing: 0em !important;
577
- }
578
-
579
- :deep(.ant-descriptions-item-colon) {
580
- margin-right: 2px !important;
581
- display: inline !important;
582
- }
583
-
584
- /* 确保内部元素正确对齐 */
585
- :deep(.ant-descriptions-item-label .label-wrapper) {
586
- display: inline !important;
587
- white-space: nowrap !important;
588
- width: auto !important;
589
- gap: 0 !important;
590
- margin: 0 !important;
591
- padding: 0 !important;
592
- line-height: 24px !important;
593
- }
594
-
595
- :deep(.ant-descriptions-row) {
596
- display: block !important;
597
- white-space: nowrap;
598
- width: 100%;
599
- }
600
-
601
- /* 移除所有可能冲突的布局属性 */
602
- :deep(.ant-descriptions-item),
603
- :deep(.ant-descriptions-item-container) {
604
- float: none !important;
605
- flex: none !important;
606
- flex-direction: row !important;
607
- align-items: flex-start !important;
608
- }
609
-
610
- /* 确保表格布局正确 */
611
- :deep(.ant-descriptions-view) {
612
- white-space: nowrap;
613
- table-layout: auto !important;
614
- }
615
-
616
- :deep(.ant-descriptions-table) {
617
- table-layout: auto !important;
618
- }
619
- }
620
- </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
+ <a-icon :type="showAllItems ? 'up' : 'down'" />
11
+ {{ showAllItems ? '收起' : ((config && config.detailsConfig && config.detailsConfig.buttonText) || '详情') }}
12
+ </a-button>
13
+ </div>
14
+
15
+ <!-- 当有 layout 配置时使用 a-descriptions -->
16
+ <template v-if="config && config.layout">
17
+ <a-descriptions
18
+ :column="config.layout"
19
+ :size="(config && config.style && config.style.size)"
20
+ :bordered="(config && config.style && config.style.bordered)"
21
+ layout="horizontal">
22
+ <template v-if="data">
23
+ <!-- 显示前N个标签 -->
24
+ <a-descriptions-item
25
+ v-for="(item) in visibleItemsFiltered"
26
+ :key="item.field"
27
+ :colon="item.colon !== false"
28
+ :class="{ 'with-divider': item.isLine }">
29
+ <template #label>
30
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
31
+ <a-avatar
32
+ v-if="item.showAvatar"
33
+ :size="item.avatar.size"
34
+ :icon="item.avatar.icon"
35
+ :style="{ background: item.avatar.background }"
36
+ />
37
+ <span class="label-text">{{ item.label }}</span>
38
+ </div>
39
+ </template>
40
+ <div class="content-wrapper">
41
+ {{ data[item.field] }}
42
+ </div>
43
+ </a-descriptions-item>
44
+
45
+ <!-- 展开后显示剩余标签 -->
46
+ <template v-if="showAllItems">
47
+ <a-descriptions-item
48
+ v-for="item in hiddenItemsFiltered"
49
+ :key="item.field"
50
+ :colon="item.colon !== false">
51
+ <template #label>
52
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
53
+ <a-avatar
54
+ v-if="item.showAvatar"
55
+ :size="item.avatar.size"
56
+ :icon="item.avatar.icon"
57
+ :style="{ background: item.avatar.background }"
58
+ />
59
+ <span class="label-text">{{ item.label }}</span>
60
+ </div>
61
+ </template>
62
+ <div class="content-wrapper">
63
+ {{ data[item.field] }}
64
+ </div>
65
+ </a-descriptions-item>
66
+ </template>
67
+ </template>
68
+ </a-descriptions>
69
+ </template>
70
+
71
+ <!-- 当没有 layout 配置时使用自适应布局 -->
72
+ <template v-else>
73
+ <div class="flex-descriptions">
74
+ <template v-if="data">
75
+ <!-- 显示可见的标签 -->
76
+ <div
77
+ v-for="(item) in visibleItemsFiltered"
78
+ :key="item.field"
79
+ :class="['description-item', { 'with-divider': item.isLine }]"
80
+ >
81
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
82
+ <a-avatar
83
+ v-if="item.showAvatar"
84
+ :size="item.avatar.size"
85
+ :icon="item.avatar.icon"
86
+ :style="{ background: item.avatar.background }"
87
+ />
88
+ <span class="label-text">{{ item.label }}:</span>
89
+ </div>
90
+ <div class="content-wrapper">
91
+ {{ data[item.field] }}
92
+ </div>
93
+ </div>
94
+
95
+ <!-- 展开后显示的内容 -->
96
+ <template v-if="showAllItems">
97
+ <div
98
+ v-for="item in hiddenItemsFiltered"
99
+ :key="item.field"
100
+ class="description-item"
101
+ >
102
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
103
+ <a-avatar
104
+ v-if="item.showAvatar"
105
+ :size="item.avatar.size"
106
+ :icon="item.avatar.icon"
107
+ :style="{ background: item.avatar.background }"
108
+ />
109
+ <span class="label-text">{{ item.label }}:</span>
110
+ </div>
111
+ <div class="content-wrapper">
112
+ {{ data[item.field] }}
113
+ </div>
114
+ </div>
115
+ </template>
116
+ </template>
117
+ </div>
118
+ </template>
119
+ </div>
120
+ </div>
121
+ </template>
122
+
123
+ <script>
124
+ import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
125
+
126
+ export default {
127
+ name: 'XHDescriptions',
128
+ data () {
129
+ return {
130
+ // 隐藏配置 当数据结果 = -1^ 该数据字段会被delete
131
+ hiddenConfig: '-1^',
132
+ data: null,
133
+ config: null,
134
+ showAllItems: false // 控制是否显示所有标签
135
+ }
136
+ },
137
+ props: {
138
+ queryParamsName: {
139
+ type: String,
140
+ default: ''
141
+ },
142
+ parameter: {
143
+ type: Object,
144
+ default: () => {
145
+ return {}
146
+ }
147
+ }
148
+ },
149
+ computed: {
150
+ // 动态样式开关(与 HForm 思路一致):布尔开关 + size 派生类
151
+ wrapperClassObject () {
152
+ const attrs = this.$attrs || {}
153
+ const classes = {}
154
+
155
+ const booleanStyleKeys = [
156
+ 'description',
157
+ 'no-padding',
158
+ 'medical-history'
159
+ ]
160
+ booleanStyleKeys.forEach(key => {
161
+ const val = attrs[key]
162
+ const truthy = val === true || val === '' || val === 'true'
163
+ if (truthy) classes[`xhdesc-${key}`] = true
164
+ })
165
+ const size = attrs.size
166
+ if (size && typeof size === 'string') classes[`xhdesc-size-${size}`] = true
167
+ return classes
168
+ },
169
+ // 获取详情按钮应该显示在第几个标签后
170
+ detailsAfterIndex () {
171
+ return (this.config && this.config.detailsConfig && this.config.detailsConfig.showAfterIndex) || 999
172
+ },
173
+ // 判断是否有更多标签需要显示
174
+ hasMoreItems () {
175
+ if (!(this.config && this.config.detailsConfig)) return false
176
+ if (!this.data || !(this.config && this.config.items) || !Array.isArray(this.config.items)) return false
177
+ const hiddenStartIndex = this.detailsAfterIndex || 0
178
+ if (hiddenStartIndex >= this.config.items.length) return false
179
+ for (let i = hiddenStartIndex; i < this.config.items.length; i++) {
180
+ const item = this.config.items[i]
181
+ if (item && item.field && this.data[item.field] !== null && this.data[item.field] !== undefined) {
182
+ return true
183
+ }
184
+ }
185
+ return false
186
+ },
187
+ // 获取应该显示的标签
188
+ visibleItems () {
189
+ if (!(this.config && this.config.items)) return []
190
+ if (!(this.config && this.config.detailsConfig)) return this.config.items
191
+ if (this.showAllItems) return this.config.items.slice(0, this.detailsAfterIndex)
192
+ return this.config.items.slice(0, this.detailsAfterIndex)
193
+ },
194
+ // 获取隐藏的标签(保持原有逻辑)
195
+ hiddenItems () {
196
+ if (!(this.config && this.config.items)) return []
197
+ if (!(this.config && this.config.detailsConfig)) return []
198
+ return this.config.items.slice(this.detailsAfterIndex)
199
+ },
200
+ // 过滤后可直接渲染的可见项
201
+ visibleItemsFiltered () {
202
+ const list = this.visibleItems || []
203
+ if (!this.data) return []
204
+ const res = list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
205
+ if (!this.showAllItems) return res
206
+ const hiddenFields = new Set((this.hiddenItems || []).map(i => i.field))
207
+ return res.filter(item => !hiddenFields.has(item.field))
208
+ },
209
+ // 过滤后可直接渲染的隐藏项(仅展开时使用)
210
+ hiddenItemsFiltered () {
211
+ const list = this.hiddenItems || []
212
+ if (!this.data) return []
213
+ return list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
214
+ }
215
+ },
216
+ created () {
217
+ this.getData(this.queryParamsName, {})
218
+ },
219
+ methods: {
220
+ async getData (data, parameterData) {
221
+ this.data = null
222
+ this.showAllItems = false
223
+ getConfigByName(data, 'af-his', res => {
224
+ this.config = res
225
+ const hiddenConfig = (this.config && this.config.hiddenConfig) || (0 === 1)
226
+ const parameter = { ...res.parameter, ...this.parameter, ...parameterData }
227
+ runLogic(res.logicName, parameter, 'af-his').then(result => {
228
+ if (hiddenConfig) {
229
+ for (const key in result) {
230
+ if (Object.prototype.hasOwnProperty.call(result, key) && result[key] === this.hiddenConfig) {
231
+ delete result[key]
232
+ }
233
+ }
234
+ }
235
+ this.data = result
236
+ })
237
+ })
238
+ },
239
+ toggleDetails () {
240
+ this.showAllItems = !this.showAllItems
241
+ }
242
+ },
243
+ watch: {
244
+ queryParamsName: {
245
+ handler (newValue) {
246
+ console.log(newValue)
247
+ this.getData(newValue, {})
248
+ },
249
+ deep: true
250
+ },
251
+ parameter: {
252
+ handler (newValue, oldValue) {
253
+ console.log('监听事件触发:', { old: oldValue, new: newValue })
254
+ // 当 parameter 变化时重新获取数据
255
+ this.getData(this.queryParamsName, {})
256
+ },
257
+ deep: true // 深度监听对象内部变化
258
+ }
259
+ }
260
+ }
261
+ </script>
262
+
263
+ <style scoped lang="less">
264
+ .patient-info-descriptions {
265
+ background: #fff;
266
+ padding: 12px;
267
+ border-radius: 4px;
268
+ width: 100%;
269
+ }
270
+
271
+ .descriptions-container {
272
+ position: relative;
273
+ width: 100%;
274
+ padding-right: 80px; /* 为按钮预留空间 */
275
+ }
276
+
277
+ /* 自适应布局样式 */
278
+ .flex-descriptions {
279
+ display: flex;
280
+ flex-wrap: wrap;
281
+ gap: 8px 24px;
282
+ width: 100%;
283
+ }
284
+
285
+ .description-item {
286
+ display: inline-flex;
287
+ align-items: center;
288
+ padding: 4px 8px;
289
+ border-radius: 4px;
290
+ transition: background-color 0.3s;
291
+ white-space: nowrap;
292
+ flex: 0 1 auto;
293
+ }
294
+
295
+ .description-item:hover {
296
+ background-color: rgba(0, 0, 0, 0.02);
297
+ }
298
+
299
+ /* 共用样式 */
300
+ .label-wrapper {
301
+ display: flex;
302
+ align-items: center;
303
+ gap: 8px;
304
+ color: rgba(0, 0, 0, 0.65);
305
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
306
+ white-space: nowrap;
307
+ }
308
+
309
+ .label-wrapper.with-avatar {
310
+ gap: 8px;
311
+ }
312
+
313
+ .label-text {
314
+ white-space: nowrap;
315
+ }
316
+
317
+ .content-wrapper {
318
+ display: inline-flex;
319
+ align-items: center;
320
+ margin-left: 4px;
321
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
322
+ color: rgba(0, 0, 0, 0.85);
323
+ max-width: 300px;
324
+ overflow: hidden;
325
+ text-overflow: ellipsis;
326
+ white-space: nowrap;
327
+ }
328
+
329
+ .detail-button-wrapper {
330
+ position: absolute;
331
+ right: 0;
332
+ top: 0;
333
+ z-index: 10;
334
+ padding: 4px 8px;
335
+ white-space: nowrap;
336
+ background-color: #fff;
337
+ }
338
+
339
+ /* Ant Design 描述列表样式覆盖 */
340
+ :deep(.ant-descriptions-row) {
341
+ display: flex;
342
+ flex-direction: row;
343
+ align-items: flex-start;
344
+ }
345
+
346
+ :deep(.ant-descriptions-item) {
347
+ padding: 0 !important;
348
+ display: flex !important;
349
+ align-items: flex-start !important;
350
+ flex-direction: row !important;
351
+ margin-right: 24px;
352
+ width: fit-content !important;
353
+ margin-bottom: 16px;
354
+ }
355
+
356
+ :deep(.ant-descriptions-item-container) {
357
+ display: flex !important;
358
+ flex-direction: row !important;
359
+ align-items: flex-start !important;
360
+ position: relative;
361
+ gap: 0 !important;
362
+ width: 100% !important;
363
+ }
364
+
365
+ :deep(.ant-descriptions-item-label) {
366
+ color: rgba(0, 0, 0, 0.65);
367
+ padding: 0 !important;
368
+ margin: 0 !important;
369
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
370
+ display: inline-flex !important;
371
+ align-items: center !important;
372
+ white-space: nowrap !important;
373
+ min-width: v-bind('(config && config.style && config.style.labelWidth) || "80px"');
374
+ justify-content: flex-start;
375
+ padding-right: 2px !important;
376
+ }
377
+
378
+ :deep(.ant-descriptions-item-content) {
379
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
380
+ display: inline-flex !important;
381
+ align-items: center !important;
382
+ padding: 0 !important;
383
+ margin: 0 !important;
384
+ margin-left: 0px !important;
385
+ }
386
+
387
+ :deep(.ant-descriptions-item-colon) {
388
+ position: static !important;
389
+ display: inline-flex !important;
390
+ align-items: center !important;
391
+ margin: 0 !important;
392
+ padding: 0 !important;
393
+ margin-right: 2px !important;
394
+ }
395
+
396
+ :deep(.ant-descriptions-item-container:hover) {
397
+ background-color: rgba(0, 0, 0, 0.02);
398
+ border-radius: 4px;
399
+ }
400
+
401
+ :deep(.ant-btn-link) {
402
+ padding: 0;
403
+ height: auto;
404
+ line-height: 1;
405
+ }
406
+
407
+ :deep(.ant-btn-link:hover) {
408
+ color: #1890ff;
409
+ background: transparent;
410
+ }
411
+
412
+ /* 响应式调整 */
413
+ @media screen and (max-width: 768px) {
414
+ .content-wrapper {
415
+ max-width: 200px;
416
+ }
417
+ }
418
+
419
+ @media screen and (max-width: 576px) {
420
+ .content-wrapper {
421
+ max-width: 150px;
422
+ }
423
+ .flex-descriptions {
424
+ gap: 4px 12px;
425
+ }
426
+ }
427
+
428
+ /* 添加虚线样式 */
429
+ .with-divider {
430
+ position: relative;
431
+ margin-bottom: 16px !important;
432
+ }
433
+
434
+ .with-divider::after {
435
+ content: '';
436
+ position: absolute;
437
+ left: 0;
438
+ bottom: -8px;
439
+ width: 100%;
440
+ height: 0;
441
+ border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
442
+ }
443
+
444
+ /* 对于 Ant Design 描述列表的特殊处理 */
445
+ :deep(.ant-descriptions-item.with-divider) {
446
+ position: relative;
447
+ margin-bottom: 16px !important;
448
+ }
449
+
450
+ :deep(.ant-descriptions-item.with-divider::after) {
451
+ content: '';
452
+ position: absolute;
453
+ left: 0;
454
+ bottom: -8px;
455
+ width: 100%;
456
+ height: 0;
457
+ border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
458
+ }
459
+ /* 加边框 */
460
+ /* 加边框 */
461
+ .xhdesc-description {
462
+ padding: 4px 4px 4px 4px;
463
+
464
+ /* 作用域内 *patient-info-descriptions */
465
+ &.patient-info-descriptions,
466
+ .patient-info-descriptions {
467
+ border: 1px solid #E5E9F0;
468
+ border-radius: 6px;
469
+ padding: 6.5px 12px;
470
+
471
+ /* *ant-btn-link */
472
+ :deep(.ant-btn-link) {
473
+ border: none;
474
+ }
475
+
476
+ /* *ant-descriptions-item-content */
477
+ :deep(.ant-descriptions-item-content) {
478
+ font-weight: bold;
479
+ }
480
+ }
481
+ }
482
+ .xhdesc-no-padding {
483
+ padding: 0px;
484
+ }
485
+ .xhdesc-no-padding {
486
+ padding: 0px;
487
+ &.patient-info-descriptions,
488
+ .patient-info-descriptions {
489
+ /* *ant-descriptions-item-content */
490
+ :deep(.descriptions-container) {
491
+ padding: 0px;
492
+ }
493
+ :deep(.content-wrapper) {
494
+ margin: 0px;
495
+ }
496
+ }
497
+ }
498
+ /* 医疗病史样式开关:通过 wrapperClassObject 添加类 xhdesc-medical-history */
499
+ .patient-info-descriptions.xhdesc-medical-history {
500
+ /* 移除右侧空白(本模式不需要详情按钮预留空间) */
501
+ .descriptions-container {
502
+ padding-right: 0;
503
+ padding-left: 12px;
504
+ }
505
+
506
+ /* 保持原有的自适应布局样式 */
507
+ .flex-descriptions {
508
+ gap: 4px 16px;
509
+ }
510
+
511
+ .description-item {
512
+ padding: 2px 4px;
513
+ width: 100%;
514
+ align-items: flex-start;
515
+ display: flex;
516
+ flex-direction: column;
517
+ }
518
+
519
+ /* 只修改布局,保持原有字体样式 */
520
+ .label-wrapper {
521
+ font-family: "Source Han Sans";
522
+ font-size: 18px;
523
+ font-weight: 600;
524
+ line-height: 24px;
525
+ text-align: justify;
526
+ letter-spacing: 0em;
527
+ white-space: nowrap;
528
+ margin-right: 8px;
529
+ margin-bottom: 0;
530
+ display: inline;
531
+ }
532
+
533
+ .content-wrapper {
534
+ font-family: "Source Han Sans";
535
+ font-size: 18px;
536
+ font-weight: 400;
537
+ line-height: 24px;
538
+ letter-spacing: 0em;
539
+ margin-left: 0;
540
+ max-width: none;
541
+ overflow: visible;
542
+ text-overflow: initial;
543
+ white-space: normal;
544
+ word-break: break-word;
545
+ display: inline;
546
+ }
547
+
548
+ /* 修复Ant Design描述列表的布局,保持字体样式 */
549
+ :deep(.ant-descriptions-item) {
550
+ display: block !important;
551
+ white-space: nowrap;
552
+ width: 100% !important;
553
+ margin-bottom: 8px;
554
+ margin-right: 0;
555
+ }
556
+
557
+ :deep(.ant-descriptions-item-container) {
558
+ display: inline !important;
559
+ white-space: nowrap;
560
+ width: auto !important;
561
+ align-items: start !important;
562
+ }
563
+
564
+ :deep(.ant-descriptions-item-label) {
565
+ display: inline !important;
566
+ white-space: nowrap !important;
567
+ min-width: auto !important;
568
+ padding-right: 1px !important;
569
+ /* 保持原有字体样式 */
570
+ font-family: "Source Han Sans" !important;
571
+ font-size: 18px !important;
572
+ font-weight: 600 !important;
573
+ line-height: 24px !important;
574
+ text-align: justify !important;
575
+ letter-spacing: 0em !important;
576
+ }
577
+
578
+ :deep(.ant-descriptions-item-content) {
579
+ display: inline !important;
580
+ white-space: normal !important;
581
+ word-break: break-word !important;
582
+ margin-left: 0 !important;
583
+ overflow: visible !important;
584
+ /* 保持原有字体样式 */
585
+ font-family: "Source Han Sans" !important;
586
+ font-size: 18px !important;
587
+ font-weight: 400 !important;
588
+ line-height: 24px !important;
589
+ letter-spacing: 0em !important;
590
+ }
591
+
592
+ :deep(.ant-descriptions-item-colon) {
593
+ margin-right: 2px !important;
594
+ display: inline !important;
595
+ }
596
+
597
+ /* 确保内部元素正确对齐 */
598
+ :deep(.ant-descriptions-item-label .label-wrapper) {
599
+ display: inline !important;
600
+ white-space: nowrap !important;
601
+ width: auto !important;
602
+ gap: 0 !important;
603
+ margin: 0 !important;
604
+ padding: 0 !important;
605
+ line-height: 24px !important;
606
+ }
607
+
608
+ :deep(.ant-descriptions-row) {
609
+ display: block !important;
610
+ white-space: nowrap;
611
+ width: 100%;
612
+ }
613
+
614
+ /* 移除所有可能冲突的布局属性 */
615
+ :deep(.ant-descriptions-item),
616
+ :deep(.ant-descriptions-item-container) {
617
+ float: none !important;
618
+ flex: none !important;
619
+ flex-direction: row !important;
620
+ align-items: flex-start !important;
621
+ }
622
+
623
+ /* 确保表格布局正确 */
624
+ :deep(.ant-descriptions-view) {
625
+ white-space: nowrap;
626
+ table-layout: auto !important;
627
+ }
628
+
629
+ :deep(.ant-descriptions-table) {
630
+ table-layout: auto !important;
631
+ }
632
+ }
633
+ </style>