vue2-client 1.16.69 → 1.16.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/package.json +112 -112
  2. package/src/assets/svg/female.svg +1 -1
  3. package/src/assets/svg/male.svg +1 -1
  4. package/src/base-client/components/common/HIS/HFormGroup/index.js +3 -3
  5. package/src/base-client/components/common/HIS/HFormTable/HFormTable.vue +379 -379
  6. package/src/base-client/components/common/HIS/HTab/HTab.vue +413 -413
  7. package/src/base-client/components/common/XCalendar/XCalendar.vue +399 -399
  8. package/src/base-client/components/common/XCollapse/XCollapse.vue +833 -833
  9. package/src/base-client/components/common/XDescriptions/XDescriptions.vue +174 -174
  10. package/src/base-client/components/common/XInput/XInput.vue +170 -170
  11. package/src/base-client/components/common/XSimpleDescriptions/XSimpleDescriptions.vue +166 -166
  12. package/src/base-client/components/common/XTable/XTable.vue +1610 -1610
  13. package/src/base-client/components/common/XTimeline/XTimeline.vue +454 -454
  14. package/src/base-client/components/his/XHDescriptions/XHDescriptions.vue +919 -919
  15. package/src/base-client/components/his/XHisEditor/XHisEditor.vue +705 -705
  16. package/src/base-client/components/his/XList/XList.vue +829 -829
  17. package/src/base-client/components/his/XRadio/XRadio.vue +305 -305
  18. package/src/base-client/components/his/XSimpleTable/XSimpleTable.vue +159 -159
  19. package/src/base-client/components/his/XTreeRows/XTreeRows.vue +341 -341
  20. package/src/base-client/components/his/threeTestOrders/editor.vue +113 -113
  21. package/src/config/CreateQueryConfig.js +325 -325
  22. package/src/pages/WorkflowDetail/WorkflowDetail.vue +5 -0
  23. package/src/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowHandle.vue +3 -0
  24. package/src/pages/XTreeOneProExample/index.vue +67 -67
  25. package/src/pages/userInfoDetailManage/ExceptionRecordQuery/index.vue +45 -45
  26. package/src-base-client/components/common/XCollapse/XCollapse.vue +0 -0
@@ -1,919 +1,919 @@
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 && !wrapperClassObject['xhdesc-medical-history']">
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
- <a-tooltip
41
- v-if="isContentOverflow(data[item.field])"
42
- :title="data[item.field]"
43
- placement="topLeft"
44
- :overlay-style="{ maxWidth: '400px' }"
45
- >
46
- <div
47
- class="content-wrapper ellipsis"
48
- :data-full-text="data[item.field]"
49
- >
50
- {{ data[item.field] }}
51
- </div>
52
- </a-tooltip>
53
- <div
54
- v-else
55
- class="content-wrapper"
56
- :data-full-text="data[item.field]"
57
- >
58
- {{ data[item.field] }}
59
- </div>
60
- </a-descriptions-item>
61
-
62
- <!-- 展开后显示剩余标签 -->
63
- <template v-if="showAllItems">
64
- <a-descriptions-item
65
- v-for="item in hiddenItemsFiltered"
66
- :key="item.field"
67
- :colon="item.colon !== false">
68
- <template #label>
69
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
70
- <a-avatar
71
- v-if="item.showAvatar"
72
- :size="item.avatar.size"
73
- :icon="item.avatar.icon"
74
- :style="{ background: item.avatar.background }"
75
- />
76
- <span class="label-text">{{ item.label }}</span>
77
- </div>
78
- </template>
79
- <div
80
- class="content-wrapper"
81
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
82
- :data-full-text="data[item.field]"
83
- >
84
- {{ data[item.field] }}
85
- </div>
86
- </a-descriptions-item>
87
- </template>
88
- </template>
89
- </a-descriptions>
90
- </template>
91
-
92
- <!-- 医疗病史模式:使用自定义HTML结构实现文本环绕 -->
93
- <template v-else-if="config && config.layout && wrapperClassObject['xhdesc-medical-history']">
94
- <div class="medical-history-descriptions">
95
- <template v-if="data">
96
- <!-- 显示前N个标签 -->
97
- <div
98
- v-for="(item) in visibleItemsFiltered"
99
- :key="item.field"
100
- :class="['medical-history-item', { 'with-divider': item.isLine }]"
101
- >
102
- <div class="medical-history-content">
103
- <a-tooltip
104
- v-if="isContentOverflow(data[item.field])"
105
- :title="data[item.field]"
106
- placement="topLeft"
107
- :overlay-style="{ maxWidth: '400px' }"
108
- >
109
- <div class="medical-history-text ellipsis">
110
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
111
- </div>
112
- </a-tooltip>
113
- <div
114
- v-else
115
- class="medical-history-text"
116
- >
117
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
118
- </div>
119
- </div>
120
- </div>
121
-
122
- <!-- 展开后显示剩余标签 -->
123
- <template v-if="showAllItems">
124
- <div
125
- v-for="item in hiddenItemsFiltered"
126
- :key="item.field"
127
- class="medical-history-item"
128
- >
129
- <div class="medical-history-content">
130
- <a-tooltip
131
- v-if="isContentOverflow(data[item.field])"
132
- :title="data[item.field]"
133
- placement="topLeft"
134
- :overlay-style="{ maxWidth: '400px' }"
135
- >
136
- <div class="medical-history-text ellipsis">
137
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
138
- </div>
139
- </a-tooltip>
140
- <div
141
- v-else
142
- class="medical-history-text"
143
- >
144
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
145
- </div>
146
- </div>
147
- </div>
148
- </template>
149
- </template>
150
- </div>
151
- </template>
152
-
153
- <!-- 当没有 layout 配置时使用自适应布局 -->
154
- <template v-else>
155
- <div class="flex-descriptions">
156
- <template v-if="data">
157
- <!-- 显示可见的标签 -->
158
- <div
159
- v-for="(item) in visibleItemsFiltered"
160
- :key="item.field"
161
- :class="['description-item', { 'with-divider': item.isLine }]"
162
- >
163
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
164
- <a-avatar
165
- v-if="item.showAvatar"
166
- :size="item.avatar.size"
167
- :icon="item.avatar.icon"
168
- :style="{ background: item.avatar.background }"
169
- />
170
- <span class="label-text">{{ item.label }}:</span>
171
- </div>
172
- <a-tooltip
173
- v-if="isContentOverflow(data[item.field])"
174
- :title="data[item.field]"
175
- placement="topLeft"
176
- :overlay-style="{ maxWidth: '400px' }"
177
- >
178
- <div
179
- class="content-wrapper ellipsis"
180
- :data-full-text="data[item.field]"
181
- >
182
- {{ data[item.field] }}
183
- </div>
184
- </a-tooltip>
185
- <div
186
- v-else
187
- class="content-wrapper"
188
- :data-full-text="data[item.field]"
189
- >
190
- {{ data[item.field] }}
191
- </div>
192
- </div>
193
-
194
- <!-- 展开后显示的内容 -->
195
- <template v-if="showAllItems">
196
- <div
197
- v-for="item in hiddenItemsFiltered"
198
- :key="item.field"
199
- class="description-item"
200
- >
201
- <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
202
- <a-avatar
203
- v-if="item.showAvatar"
204
- :size="item.avatar.size"
205
- :icon="item.avatar.icon"
206
- :style="{ background: item.avatar.background }"
207
- />
208
- <span class="label-text">{{ item.label }}:</span>
209
- </div>
210
- <div
211
- class="content-wrapper"
212
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
213
- :data-full-text="data[item.field]"
214
- >
215
- {{ data[item.field] }}
216
- </div>
217
- </div>
218
- </template>
219
- </template>
220
- </div>
221
- </template>
222
-
223
- <!-- 可选:底部区域(分割线 + 三列内容) -->
224
- <div v-if="config && config.footer && Array.isArray(config.footer.items) && data" class="xhdesc-footer">
225
- <div class="xhdesc-divider" />
226
- <!-- 医疗病史模式下的footer结构 -->
227
- <div v-if="wrapperClassObject['xhdesc-medical-history']" class="medical-history-footer">
228
- <div
229
- v-for="(item, idx) in config.footer.items"
230
- :key="item.field || idx"
231
- class="medical-history-item">
232
- <div class="medical-history-content">
233
- <a-tooltip
234
- v-if="isContentOverflow(data[item.field])"
235
- :title="data[item.field]"
236
- placement="topLeft"
237
- :overlay-style="{ maxWidth: '400px' }"
238
- >
239
- <div class="medical-history-text ellipsis">
240
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
241
- </div>
242
- </a-tooltip>
243
- <div
244
- v-else
245
- class="medical-history-text"
246
- >
247
- <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
248
- </div>
249
- </div>
250
- </div>
251
- <!-- 右侧信息:换到下一行并靠右对齐(如 医生 / 医嘱日期) -->
252
- <div
253
- v-if="Array.isArray(config.footer.rightItems) && config.footer.rightItems.length"
254
- class="footer-right">
255
- <div
256
- v-for="(item, ridx) in config.footer.rightItems"
257
- :key="item.field || ridx"
258
- class="footer-right-item">
259
- <div class="label-wrapper"><span class="label-text">{{ item.label }}:</span></div>
260
- <div
261
- class="content-wrapper"
262
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
263
- :data-full-text="data[item.field]"
264
- >{{ data[item.field] }}
265
- </div>
266
- </div>
267
- </div>
268
- </div>
269
- <!-- 非医疗病史模式下的footer结构 -->
270
- <div v-else class="footer-grid">
271
- <div
272
- v-for="(item, idx) in config.footer.items"
273
- :key="item.field || idx"
274
- class="description-item">
275
- <div class="label-wrapper"><span class="label-text">{{ item.label }}:</span></div>
276
- <div
277
- class="content-wrapper"
278
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
279
- :data-full-text="data[item.field]"
280
- >{{ data[item.field] }}
281
- </div>
282
- </div>
283
- </div>
284
- <!-- 右侧信息:换到下一行并靠右对齐(如 医生 / 医嘱日期) -->
285
- <div
286
- v-if="!wrapperClassObject['xhdesc-medical-history'] && Array.isArray(config.footer.rightItems) && config.footer.rightItems.length"
287
- class="footer-right">
288
- <div
289
- v-for="(item, ridx) in config.footer.rightItems"
290
- :key="item.field || ridx"
291
- class="footer-right-item">
292
- <div class="label-wrapper"><span class="label-text">{{ item.label }}:</span></div>
293
- <div
294
- class="content-wrapper"
295
- :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
296
- :data-full-text="data[item.field]"
297
- >{{ data[item.field] }}
298
- </div>
299
- </div>
300
- </div>
301
- </div>
302
- </div>
303
- </div>
304
- </template>
305
-
306
- <script>
307
- import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
308
-
309
- export default {
310
- name: 'XHDescriptions',
311
- data () {
312
- return {
313
- // 隐藏配置 当数据结果 = -1^ 该数据字段会被delete
314
- hiddenConfig: '-1^',
315
- data: null,
316
- config: null,
317
- showAllItems: false // 控制是否显示所有标签
318
- }
319
- },
320
- props: {
321
- queryParamsName: {
322
- type: String,
323
- default: ''
324
- },
325
- parameter: {
326
- type: Object,
327
- default: () => {
328
- return {}
329
- }
330
- }
331
- },
332
- computed: {
333
- // 动态样式开关(与 HForm 思路一致):布尔开关 + size 派生类
334
- wrapperClassObject () {
335
- const attrs = this.$attrs || {}
336
- const classes = {}
337
-
338
- const booleanStyleKeys = [
339
- 'description',
340
- 'no-padding',
341
- 'medical-history',
342
- 'margin-top-12'
343
- ]
344
- booleanStyleKeys.forEach(key => {
345
- const val = attrs[key]
346
- const truthy = val === true || val === '' || val === 'true'
347
- if (truthy) classes[`xhdesc-${key}`] = true
348
- })
349
- const size = attrs.size
350
- if (size && typeof size === 'string') classes[`xhdesc-size-${size}`] = true
351
- return classes
352
- },
353
- // 获取详情按钮应该显示在第几个标签后
354
- detailsAfterIndex () {
355
- return (this.config && this.config.detailsConfig && this.config.detailsConfig.showAfterIndex) || 999
356
- },
357
- // 判断是否有更多标签需要显示
358
- hasMoreItems () {
359
- if (!(this.config && this.config.detailsConfig)) return false
360
- if (!this.data || !(this.config && this.config.items) || !Array.isArray(this.config.items)) return false
361
- const hiddenStartIndex = this.detailsAfterIndex || 0
362
- if (hiddenStartIndex >= this.config.items.length) return false
363
- for (let i = hiddenStartIndex; i < this.config.items.length; i++) {
364
- const item = this.config.items[i]
365
- if (item && item.field && this.data[item.field] !== null && this.data[item.field] !== undefined) {
366
- return true
367
- }
368
- }
369
- return false
370
- },
371
- // 获取应该显示的标签
372
- visibleItems () {
373
- if (!(this.config && this.config.items)) return []
374
- if (!(this.config && this.config.detailsConfig)) return this.config.items
375
- if (this.showAllItems) return this.config.items.slice(0, this.detailsAfterIndex)
376
- return this.config.items.slice(0, this.detailsAfterIndex)
377
- },
378
- // 获取隐藏的标签(保持原有逻辑)
379
- hiddenItems () {
380
- if (!(this.config && this.config.items)) return []
381
- if (!(this.config && this.config.detailsConfig)) return []
382
- return this.config.items.slice(this.detailsAfterIndex)
383
- },
384
- // 过滤后可直接渲染的可见项
385
- visibleItemsFiltered () {
386
- const list = this.visibleItems || []
387
- if (!this.data) return []
388
- const res = list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
389
- if (!this.showAllItems) return res
390
- const hiddenFields = new Set((this.hiddenItems || []).map(i => i.field))
391
- return res.filter(item => !hiddenFields.has(item.field))
392
- },
393
- // 过滤后可直接渲染的隐藏项(仅展开时使用)
394
- hiddenItemsFiltered () {
395
- const list = this.hiddenItems || []
396
- if (!this.data) return []
397
- return list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
398
- }
399
- },
400
- created () {
401
- this.getData(this.queryParamsName, {})
402
- },
403
- methods: {
404
- async getData (data, parameterData) {
405
- this.data = null
406
- this.showAllItems = false
407
- getConfigByName(data, 'af-his', res => {
408
- this.config = res
409
- const hiddenConfig = (this.config && this.config.hiddenConfig) || (0 === 1)
410
- const parameter = { ...res.parameter, ...this.parameter, ...parameterData }
411
- runLogic(res.logicName, parameter, 'af-his').then(result => {
412
- if (hiddenConfig) {
413
- for (const key in result) {
414
- if (Object.prototype.hasOwnProperty.call(result, key) && result[key] === this.hiddenConfig) {
415
- delete result[key]
416
- }
417
- }
418
- }
419
- this.data = result
420
- })
421
- })
422
- },
423
- toggleDetails () {
424
- this.showAllItems = !this.showAllItems
425
- },
426
- // 判断内容是否超过三行
427
- isContentOverflow (content) {
428
- if (!content || typeof content !== 'string') return false
429
- return content.length > 150
430
- }
431
- },
432
- watch: {
433
- queryParamsName: {
434
- handler (newValue) {
435
- console.log(newValue)
436
- this.getData(newValue, {})
437
- },
438
- deep: true
439
- },
440
- parameter: {
441
- handler (newValue, oldValue) {
442
- console.log('监听事件触发:', { old: oldValue, new: newValue })
443
- // 当 parameter 变化时重新获取数据
444
- this.getData(this.queryParamsName, {})
445
- },
446
- deep: true // 深度监听对象内部变化
447
- }
448
- }
449
- }
450
- </script>
451
-
452
- <style scoped lang="less">
453
- .patient-info-descriptions {
454
- background: #fff;
455
- padding: 12px;
456
- border-radius: 4px;
457
- width: 100%;
458
- }
459
-
460
- .descriptions-container {
461
- position: relative;
462
- width: 100%;
463
- padding-right: 80px; /* 为按钮预留空间 */
464
- }
465
-
466
- /* 自适应布局样式 */
467
- .flex-descriptions {
468
- display: flex;
469
- flex-wrap: wrap;
470
- gap: 8px 24px;
471
- width: 100%;
472
- }
473
-
474
- .description-item {
475
- display: inline-flex;
476
- align-items: center;
477
- padding: 4px 8px;
478
- border-radius: 4px;
479
- transition: background-color 0.3s;
480
- white-space: nowrap;
481
- flex: 0 1 auto;
482
- }
483
-
484
- .description-item:hover {
485
- background-color: rgba(0, 0, 0, 0.02);
486
- }
487
-
488
- /* 共用样式 */
489
- .label-wrapper {
490
- display: flex;
491
- align-items: center;
492
- gap: 8px;
493
- color: rgba(0, 0, 0, 0.65);
494
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
495
- white-space: nowrap;
496
- }
497
-
498
- .label-text {
499
- white-space: nowrap;
500
- color: #313131; // 统一深灰
501
- text-decoration: none !important; // 移除下划线
502
- }
503
-
504
- .content-wrapper {
505
- display: inline-flex;
506
- align-items: center;
507
- margin-left: 4px;
508
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
509
- color: rgba(0, 0, 0, 0.85);
510
- text-decoration: none !important; // 移除可能的下划线
511
- max-width: 300px;
512
- overflow: hidden;
513
- text-overflow: ellipsis;
514
- white-space: nowrap;
515
- }
516
-
517
- /* 强制移除任何链接样式(如接口返回含 <a>) */
518
- ::v-deep a {
519
- color: #313131 !important;
520
- text-decoration: none !important;
521
- }
522
-
523
- .detail-button-wrapper {
524
- position: absolute;
525
- right: 0;
526
- top: 0;
527
- z-index: 10;
528
- padding: 4px 8px;
529
- white-space: nowrap;
530
- background-color: #fff;
531
- }
532
-
533
- /* 底部区域:分割线 + 三列内容 */
534
- .xhdesc-footer {
535
- margin-top: 12px;
536
- }
537
-
538
- .xhdesc-divider {
539
- width: calc(100% + 24px); /* 扩展到左右内边距之外 */
540
- height: 0;
541
- border-bottom: 1px solid #E5E9F0;
542
- margin: 10px -12px 14px; /* 抵消左右 12px 内边距 */
543
- overflow: hidden;
544
- }
545
- /* medical-history 模式:左 padding 11px,右 12px(由外层设置),做精确抵消 */
546
- .patient-info-descriptions.xhdesc-medical-history .xhdesc-divider {
547
- width: calc(100% + 23px);
548
- margin-left: -11px;
549
- margin-right: -12px;
550
- }
551
-
552
- .footer-grid {
553
- display: grid;
554
- grid-template-columns: 1fr; // 单列
555
- gap: 8px 24px; // 与上方描述项间距保持一致
556
- align-items: start; // 左上对齐
557
- }
558
-
559
- /* footer 区域的每项直接沿用通用 .description-item/.label-wrapper/.content-wrapper 样式 */
560
-
561
- .footer-right {
562
- margin-top: 8px;
563
- display: flex;
564
- justify-content: flex-end;
565
- align-items: center;
566
- gap: 16px;
567
- }
568
-
569
- .footer-right-item {
570
- display: inline-flex;
571
- align-items: center;
572
- }
573
-
574
- /* Ant Design 描述列表样式覆盖 */
575
- ::v-deep(.ant-descriptions-row) {
576
- display: flex;
577
- flex-direction: row;
578
- align-items: flex-start;
579
- }
580
-
581
- ::v-deep(.ant-descriptions-item) {
582
- padding: 0 !important;
583
- display: flex !important;
584
- align-items: flex-start !important;
585
- flex-direction: row !important;
586
- margin-right: 24px;
587
- width: fit-content !important;
588
- margin-bottom: 16px;
589
- }
590
-
591
- ::v-deep(.ant-descriptions-item-container) {
592
- display: flex !important;
593
- flex-direction: row !important;
594
- align-items: flex-start !important;
595
- position: relative;
596
- gap: 0 !important;
597
- width: 100% !important;
598
- }
599
-
600
- ::v-deep(.ant-descriptions-item-label) {
601
- color: rgba(0, 0, 0, 0.65);
602
- padding: 0 !important;
603
- margin: 0 !important;
604
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
605
- display: inline-flex !important;
606
- align-items: center !important;
607
- white-space: nowrap !important;
608
- min-width: v-bind('(config && config.style && config.style.labelWidth) || "80px"');
609
- justify-content: flex-start;
610
- padding-right: 2px !important;
611
- }
612
-
613
- ::v-deep(.ant-descriptions-item-content) {
614
- font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
615
- display: inline-flex !important;
616
- align-items: center !important;
617
- padding: 0 !important;
618
- margin: 0 !important;
619
- margin-left: 0px !important;
620
- }
621
-
622
- ::v-deep(.ant-descriptions-item-colon) {
623
- position: static !important;
624
- display: inline-flex !important;
625
- align-items: center !important;
626
- margin: 0 !important;
627
- padding: 0 !important;
628
- margin-right: 2px !important;
629
- }
630
-
631
- ::v-deep(.ant-descriptions-item-container:hover) {
632
- background-color: rgba(0, 0, 0, 0.02);
633
- border-radius: 4px;
634
- }
635
-
636
- ::v-deep(.ant-btn-link) {
637
- padding: 0;
638
- height: auto;
639
- line-height: 1;
640
- }
641
-
642
- ::v-deep(.ant-btn-link:hover) {
643
- color: #1890ff;
644
- background: transparent;
645
- }
646
-
647
- /* 响应式调整 */
648
- @media screen and (max-width: 768px) {
649
- .content-wrapper {
650
- max-width: 200px;
651
- }
652
- }
653
-
654
- @media screen and (max-width: 576px) {
655
- .content-wrapper {
656
- max-width: 150px;
657
- }
658
- .flex-descriptions {
659
- gap: 4px 12px;
660
- }
661
- }
662
-
663
- /* 添加虚线样式 */
664
- .with-divider {
665
- position: relative;
666
- margin-bottom: 16px !important;
667
- }
668
-
669
- .with-divider::after {
670
- content: '';
671
- position: absolute;
672
- left: 0;
673
- bottom: -8px;
674
- width: 100%;
675
- height: 0;
676
- border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
677
- }
678
-
679
- /* 对于 Ant Design 描述列表的特殊处理 */
680
- ::v-deep(.ant-descriptions-item.with-divider) {
681
- position: relative;
682
- margin-bottom: 16px !important;
683
- }
684
-
685
- ::v-deep(.ant-descriptions-item.with-divider::after) {
686
- content: '';
687
- position: absolute;
688
- left: 0;
689
- bottom: -8px;
690
- width: 100%;
691
- height: 0;
692
- border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
693
- }
694
-
695
- /* 加边框 */
696
- .xhdesc-description {
697
- padding: 4px 4px 4px 4px;
698
-
699
- /* 作用域内 *patient-info-descriptions */
700
- &.patient-info-descriptions,
701
- .patient-info-descriptions {
702
- border: 1px solid #E5E9F0;
703
- border-radius: 6px;
704
- padding: 6.5px 12px;
705
-
706
- /* *ant-btn-link */
707
- ::v-deep .ant-btn-link {
708
- border: none;
709
- }
710
-
711
- /* *ant-descriptions-item-content */
712
- ::v-deep .ant-descriptions-item-content {
713
- font-weight: bold;
714
- }
715
- }
716
- }
717
- // 去除住院收费页面两个描述列表之间的间距
718
- .xhdesc-margin-top-12 {
719
- margin-top: -12px;
720
- }
721
- .xhdesc-no-padding {
722
- padding: 0px;
723
- &.patient-info-descriptions,
724
- .patient-info-descriptions {
725
- /* *ant-descriptions-item-content */
726
- ::v-deep .descriptions-container {
727
- padding: 0px;
728
- }
729
- ::v-deep .content-wrapper {
730
- margin: 0px;
731
- }
732
- }
733
- }
734
- /* 医疗病史模式:自定义HTML结构样式 */
735
- .medical-history-descriptions {
736
- width: 100%;
737
- }
738
-
739
- .medical-history-item {
740
- margin: 0;
741
- width: 100%;
742
- }
743
-
744
- .medical-history-item.with-divider {
745
- position: relative;
746
- padding-bottom: 4px; /* 分割线与上方间距 4px */
747
- margin-bottom: 4px; /* 分割线与下方间距 4px */
748
- }
749
-
750
- .medical-history-item.with-divider::after {
751
- content: '';
752
- position: absolute;
753
- left: 0;
754
- bottom: 0; /* 贴合容器底部 */
755
- width: 100%;
756
- height: 0;
757
- border-bottom: 1px solid rgba(0, 0, 0, 0.15);
758
- }
759
-
760
- .medical-history-content {
761
- font-family: "Source Han Sans";
762
- font-size: 18px;
763
- line-height: 24px;
764
- letter-spacing: 0em;
765
- text-align: left;
766
- word-break: break-word;
767
- white-space: normal;
768
- text-indent: 0;
769
- padding-left: 0;
770
- margin-left: 0;
771
- /* 使用float实现真正的文本环绕 */
772
- overflow: hidden;
773
- /* 确保容器能够正确清除浮动 */
774
- position: relative;
775
- }
776
-
777
- .medical-history-label {
778
- font-family: "Source Han Sans";
779
- font-size: 16px;
780
- font-weight: 700;
781
- color: #313131;
782
- white-space: nowrap;
783
- float: left;
784
- margin-right: 0px;
785
- /* 确保标签不会影响文本流 */
786
- position: relative;
787
- z-index: 1;
788
- }
789
-
790
- .medical-history-text {
791
- font-family: "Source Han Sans";
792
- font-size: 16px;
793
- font-weight: 400;
794
- color: #313131;
795
- display: block;
796
- overflow: hidden;
797
- text-indent: 0;
798
- padding-left: 0;
799
- margin-left: 0;
800
- word-break: break-word;
801
- white-space: normal;
802
- text-align: left;
803
- line-height: 24px;
804
- /* 确保文本能够正确环绕浮动元素 */
805
- margin-top: 0;
806
- margin-bottom: 0;
807
- }
808
-
809
- .medical-history-text.ellipsis {
810
- display: -webkit-box;
811
- -webkit-box-orient: vertical;
812
- -webkit-line-clamp: 3;
813
- line-clamp: 3;
814
- overflow: hidden;
815
- cursor: pointer;
816
- position: relative;
817
- word-break: break-word;
818
- white-space: normal;
819
- line-height: 24px;
820
- text-indent: 0;
821
- padding-left: 0;
822
- margin-left: 0;
823
- text-align: left;
824
- -webkit-box-pack: start;
825
- -webkit-box-align: start;
826
- }
827
-
828
- /* 使用-webkit-line-clamp时不需要手动添加省略号 */
829
- .medical-history-text.ellipsis::after {
830
- display: none;
831
- }
832
-
833
- /* 针对多行文本的特殊处理:确保换行文本与首行对齐 */
834
- .medical-history-text.ellipsis::first-line {
835
- text-indent: 0;
836
- }
837
-
838
- /* 为不支持-webkit-line-clamp的浏览器提供后备方案 */
839
- @supports not (-webkit-line-clamp: 3) {
840
- .medical-history-text.ellipsis {
841
- display: block;
842
- max-height: 72px; /* 3行 * 24px行高 */
843
- overflow: hidden;
844
- position: relative;
845
- }
846
-
847
- .medical-history-text.ellipsis::after {
848
- content: '...';
849
- position: absolute;
850
- right: 0;
851
- bottom: 0;
852
- background: #fff;
853
- padding-left: 4px;
854
- display: block;
855
- }
856
- }
857
-
858
- /* 医疗病史样式开关:通过 wrapperClassObject 添加类 xhdesc-medical-history */
859
- .patient-info-descriptions.xhdesc-medical-history {
860
- padding: 9px 12px 10px 11px !important;
861
- /* 移除右侧空白(本模式不需要详情按钮预留空间) */
862
- .descriptions-container {
863
- padding-right: 0;
864
- padding-left: 0px;
865
- }
866
- /* 医疗病史模式下:footer 区域使用与上方相同的医疗病史样式 */
867
- .medical-history-footer {
868
- width: 100%;
869
- }
870
- .medical-history-footer .footer-right {
871
- margin-top: 8px;
872
- display: flex;
873
- justify-content: flex-end;
874
- align-items: flex-start;
875
- gap: 16px;
876
- width: 100%;
877
- }
878
- /* 右侧(医生/医嘱日期)标签与值的字体要求 */
879
- .medical-history-footer .footer-right .label-wrapper .label-text {
880
- font-family: "Source Han Sans";
881
- font-size: 16px;
882
- font-weight: 700;
883
- color: #313131;
884
- line-height: 22px;
885
- }
886
- .medical-history-footer .footer-right .content-wrapper {
887
- font-family: "Source Han Sans";
888
- font-size: 16px;
889
- font-weight: 400;
890
- line-height: 22px;
891
- color: #313131;
892
- }
893
-
894
- .medical-history-footer .footer-right .medical-history-item {
895
- display: inline-block;
896
- text-align: right;
897
- }
898
-
899
- .medical-history-footer .footer-right .medical-history-content {
900
- text-align: right;
901
- }
902
-
903
- .medical-history-footer .footer-right .medical-history-label {
904
- float: none;
905
- display: inline;
906
- margin-right: 0px;
907
- }
908
-
909
- .medical-history-footer .footer-right .medical-history-text {
910
- display: inline;
911
- text-align: right;
912
- }
913
-
914
- .medical-history-footer .footer-right .medical-history-text.ellipsis {
915
- display: inline;
916
- text-align: right;
917
- }
918
- }
919
- </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 && !wrapperClassObject['xhdesc-medical-history']">
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
+ <a-tooltip
41
+ v-if="isContentOverflow(data[item.field])"
42
+ :title="data[item.field]"
43
+ placement="topLeft"
44
+ :overlay-style="{ maxWidth: '400px' }"
45
+ >
46
+ <div
47
+ class="content-wrapper ellipsis"
48
+ :data-full-text="data[item.field]"
49
+ >
50
+ {{ data[item.field] }}
51
+ </div>
52
+ </a-tooltip>
53
+ <div
54
+ v-else
55
+ class="content-wrapper"
56
+ :data-full-text="data[item.field]"
57
+ >
58
+ {{ data[item.field] }}
59
+ </div>
60
+ </a-descriptions-item>
61
+
62
+ <!-- 展开后显示剩余标签 -->
63
+ <template v-if="showAllItems">
64
+ <a-descriptions-item
65
+ v-for="item in hiddenItemsFiltered"
66
+ :key="item.field"
67
+ :colon="item.colon !== false">
68
+ <template #label>
69
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
70
+ <a-avatar
71
+ v-if="item.showAvatar"
72
+ :size="item.avatar.size"
73
+ :icon="item.avatar.icon"
74
+ :style="{ background: item.avatar.background }"
75
+ />
76
+ <span class="label-text">{{ item.label }}</span>
77
+ </div>
78
+ </template>
79
+ <div
80
+ class="content-wrapper"
81
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
82
+ :data-full-text="data[item.field]"
83
+ >
84
+ {{ data[item.field] }}
85
+ </div>
86
+ </a-descriptions-item>
87
+ </template>
88
+ </template>
89
+ </a-descriptions>
90
+ </template>
91
+
92
+ <!-- 医疗病史模式:使用自定义HTML结构实现文本环绕 -->
93
+ <template v-else-if="config && config.layout && wrapperClassObject['xhdesc-medical-history']">
94
+ <div class="medical-history-descriptions">
95
+ <template v-if="data">
96
+ <!-- 显示前N个标签 -->
97
+ <div
98
+ v-for="(item) in visibleItemsFiltered"
99
+ :key="item.field"
100
+ :class="['medical-history-item', { 'with-divider': item.isLine }]"
101
+ >
102
+ <div class="medical-history-content">
103
+ <a-tooltip
104
+ v-if="isContentOverflow(data[item.field])"
105
+ :title="data[item.field]"
106
+ placement="topLeft"
107
+ :overlay-style="{ maxWidth: '400px' }"
108
+ >
109
+ <div class="medical-history-text ellipsis">
110
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
111
+ </div>
112
+ </a-tooltip>
113
+ <div
114
+ v-else
115
+ class="medical-history-text"
116
+ >
117
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
118
+ </div>
119
+ </div>
120
+ </div>
121
+
122
+ <!-- 展开后显示剩余标签 -->
123
+ <template v-if="showAllItems">
124
+ <div
125
+ v-for="item in hiddenItemsFiltered"
126
+ :key="item.field"
127
+ class="medical-history-item"
128
+ >
129
+ <div class="medical-history-content">
130
+ <a-tooltip
131
+ v-if="isContentOverflow(data[item.field])"
132
+ :title="data[item.field]"
133
+ placement="topLeft"
134
+ :overlay-style="{ maxWidth: '400px' }"
135
+ >
136
+ <div class="medical-history-text ellipsis">
137
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
138
+ </div>
139
+ </a-tooltip>
140
+ <div
141
+ v-else
142
+ class="medical-history-text"
143
+ >
144
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
145
+ </div>
146
+ </div>
147
+ </div>
148
+ </template>
149
+ </template>
150
+ </div>
151
+ </template>
152
+
153
+ <!-- 当没有 layout 配置时使用自适应布局 -->
154
+ <template v-else>
155
+ <div class="flex-descriptions">
156
+ <template v-if="data">
157
+ <!-- 显示可见的标签 -->
158
+ <div
159
+ v-for="(item) in visibleItemsFiltered"
160
+ :key="item.field"
161
+ :class="['description-item', { 'with-divider': item.isLine }]"
162
+ >
163
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
164
+ <a-avatar
165
+ v-if="item.showAvatar"
166
+ :size="item.avatar.size"
167
+ :icon="item.avatar.icon"
168
+ :style="{ background: item.avatar.background }"
169
+ />
170
+ <span class="label-text">{{ item.label }}:</span>
171
+ </div>
172
+ <a-tooltip
173
+ v-if="isContentOverflow(data[item.field])"
174
+ :title="data[item.field]"
175
+ placement="topLeft"
176
+ :overlay-style="{ maxWidth: '400px' }"
177
+ >
178
+ <div
179
+ class="content-wrapper ellipsis"
180
+ :data-full-text="data[item.field]"
181
+ >
182
+ {{ data[item.field] }}
183
+ </div>
184
+ </a-tooltip>
185
+ <div
186
+ v-else
187
+ class="content-wrapper"
188
+ :data-full-text="data[item.field]"
189
+ >
190
+ {{ data[item.field] }}
191
+ </div>
192
+ </div>
193
+
194
+ <!-- 展开后显示的内容 -->
195
+ <template v-if="showAllItems">
196
+ <div
197
+ v-for="item in hiddenItemsFiltered"
198
+ :key="item.field"
199
+ class="description-item"
200
+ >
201
+ <div :class="['label-wrapper', { 'with-avatar': item.showAvatar }]">
202
+ <a-avatar
203
+ v-if="item.showAvatar"
204
+ :size="item.avatar.size"
205
+ :icon="item.avatar.icon"
206
+ :style="{ background: item.avatar.background }"
207
+ />
208
+ <span class="label-text">{{ item.label }}:</span>
209
+ </div>
210
+ <div
211
+ class="content-wrapper"
212
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
213
+ :data-full-text="data[item.field]"
214
+ >
215
+ {{ data[item.field] }}
216
+ </div>
217
+ </div>
218
+ </template>
219
+ </template>
220
+ </div>
221
+ </template>
222
+
223
+ <!-- 可选:底部区域(分割线 + 三列内容) -->
224
+ <div v-if="config && config.footer && Array.isArray(config.footer.items) && data" class="xhdesc-footer">
225
+ <div class="xhdesc-divider" />
226
+ <!-- 医疗病史模式下的footer结构 -->
227
+ <div v-if="wrapperClassObject['xhdesc-medical-history']" class="medical-history-footer">
228
+ <div
229
+ v-for="(item, idx) in config.footer.items"
230
+ :key="item.field || idx"
231
+ class="medical-history-item">
232
+ <div class="medical-history-content">
233
+ <a-tooltip
234
+ v-if="isContentOverflow(data[item.field])"
235
+ :title="data[item.field]"
236
+ placement="topLeft"
237
+ :overlay-style="{ maxWidth: '400px' }"
238
+ >
239
+ <div class="medical-history-text ellipsis">
240
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
241
+ </div>
242
+ </a-tooltip>
243
+ <div
244
+ v-else
245
+ class="medical-history-text"
246
+ >
247
+ <span class="medical-history-label">{{ item.label }}:</span>{{ data[item.field] }}
248
+ </div>
249
+ </div>
250
+ </div>
251
+ <!-- 右侧信息:换到下一行并靠右对齐(如 医生 / 医嘱日期) -->
252
+ <div
253
+ v-if="Array.isArray(config.footer.rightItems) && config.footer.rightItems.length"
254
+ class="footer-right">
255
+ <div
256
+ v-for="(item, ridx) in config.footer.rightItems"
257
+ :key="item.field || ridx"
258
+ class="footer-right-item">
259
+ <div class="label-wrapper"><span class="label-text">{{ item.label }}:</span></div>
260
+ <div
261
+ class="content-wrapper"
262
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
263
+ :data-full-text="data[item.field]"
264
+ >{{ data[item.field] }}
265
+ </div>
266
+ </div>
267
+ </div>
268
+ </div>
269
+ <!-- 非医疗病史模式下的footer结构 -->
270
+ <div v-else class="footer-grid">
271
+ <div
272
+ v-for="(item, idx) in config.footer.items"
273
+ :key="item.field || idx"
274
+ class="description-item">
275
+ <div class="label-wrapper"><span class="label-text">{{ item.label }}:</span></div>
276
+ <div
277
+ class="content-wrapper"
278
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
279
+ :data-full-text="data[item.field]"
280
+ >{{ data[item.field] }}
281
+ </div>
282
+ </div>
283
+ </div>
284
+ <!-- 右侧信息:换到下一行并靠右对齐(如 医生 / 医嘱日期) -->
285
+ <div
286
+ v-if="!wrapperClassObject['xhdesc-medical-history'] && Array.isArray(config.footer.rightItems) && config.footer.rightItems.length"
287
+ class="footer-right">
288
+ <div
289
+ v-for="(item, ridx) in config.footer.rightItems"
290
+ :key="item.field || ridx"
291
+ class="footer-right-item">
292
+ <div class="label-wrapper"><span class="label-text">{{ item.label }}:</span></div>
293
+ <div
294
+ class="content-wrapper"
295
+ :class="{ 'ellipsis': isContentOverflow(data[item.field]) }"
296
+ :data-full-text="data[item.field]"
297
+ >{{ data[item.field] }}
298
+ </div>
299
+ </div>
300
+ </div>
301
+ </div>
302
+ </div>
303
+ </div>
304
+ </template>
305
+
306
+ <script>
307
+ import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
308
+
309
+ export default {
310
+ name: 'XHDescriptions',
311
+ data () {
312
+ return {
313
+ // 隐藏配置 当数据结果 = -1^ 该数据字段会被delete
314
+ hiddenConfig: '-1^',
315
+ data: null,
316
+ config: null,
317
+ showAllItems: false // 控制是否显示所有标签
318
+ }
319
+ },
320
+ props: {
321
+ queryParamsName: {
322
+ type: String,
323
+ default: ''
324
+ },
325
+ parameter: {
326
+ type: Object,
327
+ default: () => {
328
+ return {}
329
+ }
330
+ }
331
+ },
332
+ computed: {
333
+ // 动态样式开关(与 HForm 思路一致):布尔开关 + size 派生类
334
+ wrapperClassObject () {
335
+ const attrs = this.$attrs || {}
336
+ const classes = {}
337
+
338
+ const booleanStyleKeys = [
339
+ 'description',
340
+ 'no-padding',
341
+ 'medical-history',
342
+ 'margin-top-12'
343
+ ]
344
+ booleanStyleKeys.forEach(key => {
345
+ const val = attrs[key]
346
+ const truthy = val === true || val === '' || val === 'true'
347
+ if (truthy) classes[`xhdesc-${key}`] = true
348
+ })
349
+ const size = attrs.size
350
+ if (size && typeof size === 'string') classes[`xhdesc-size-${size}`] = true
351
+ return classes
352
+ },
353
+ // 获取详情按钮应该显示在第几个标签后
354
+ detailsAfterIndex () {
355
+ return (this.config && this.config.detailsConfig && this.config.detailsConfig.showAfterIndex) || 999
356
+ },
357
+ // 判断是否有更多标签需要显示
358
+ hasMoreItems () {
359
+ if (!(this.config && this.config.detailsConfig)) return false
360
+ if (!this.data || !(this.config && this.config.items) || !Array.isArray(this.config.items)) return false
361
+ const hiddenStartIndex = this.detailsAfterIndex || 0
362
+ if (hiddenStartIndex >= this.config.items.length) return false
363
+ for (let i = hiddenStartIndex; i < this.config.items.length; i++) {
364
+ const item = this.config.items[i]
365
+ if (item && item.field && this.data[item.field] !== null && this.data[item.field] !== undefined) {
366
+ return true
367
+ }
368
+ }
369
+ return false
370
+ },
371
+ // 获取应该显示的标签
372
+ visibleItems () {
373
+ if (!(this.config && this.config.items)) return []
374
+ if (!(this.config && this.config.detailsConfig)) return this.config.items
375
+ if (this.showAllItems) return this.config.items.slice(0, this.detailsAfterIndex)
376
+ return this.config.items.slice(0, this.detailsAfterIndex)
377
+ },
378
+ // 获取隐藏的标签(保持原有逻辑)
379
+ hiddenItems () {
380
+ if (!(this.config && this.config.items)) return []
381
+ if (!(this.config && this.config.detailsConfig)) return []
382
+ return this.config.items.slice(this.detailsAfterIndex)
383
+ },
384
+ // 过滤后可直接渲染的可见项
385
+ visibleItemsFiltered () {
386
+ const list = this.visibleItems || []
387
+ if (!this.data) return []
388
+ const res = list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
389
+ if (!this.showAllItems) return res
390
+ const hiddenFields = new Set((this.hiddenItems || []).map(i => i.field))
391
+ return res.filter(item => !hiddenFields.has(item.field))
392
+ },
393
+ // 过滤后可直接渲染的隐藏项(仅展开时使用)
394
+ hiddenItemsFiltered () {
395
+ const list = this.hiddenItems || []
396
+ if (!this.data) return []
397
+ return list.filter(item => this.data[item.field] !== null && this.data[item.field] !== undefined)
398
+ }
399
+ },
400
+ created () {
401
+ this.getData(this.queryParamsName, {})
402
+ },
403
+ methods: {
404
+ async getData (data, parameterData) {
405
+ this.data = null
406
+ this.showAllItems = false
407
+ getConfigByName(data, 'af-his', res => {
408
+ this.config = res
409
+ const hiddenConfig = (this.config && this.config.hiddenConfig) || (0 === 1)
410
+ const parameter = { ...res.parameter, ...this.parameter, ...parameterData }
411
+ runLogic(res.logicName, parameter, 'af-his').then(result => {
412
+ if (hiddenConfig) {
413
+ for (const key in result) {
414
+ if (Object.prototype.hasOwnProperty.call(result, key) && result[key] === this.hiddenConfig) {
415
+ delete result[key]
416
+ }
417
+ }
418
+ }
419
+ this.data = result
420
+ })
421
+ })
422
+ },
423
+ toggleDetails () {
424
+ this.showAllItems = !this.showAllItems
425
+ },
426
+ // 判断内容是否超过三行
427
+ isContentOverflow (content) {
428
+ if (!content || typeof content !== 'string') return false
429
+ return content.length > 150
430
+ }
431
+ },
432
+ watch: {
433
+ queryParamsName: {
434
+ handler (newValue) {
435
+ console.log(newValue)
436
+ this.getData(newValue, {})
437
+ },
438
+ deep: true
439
+ },
440
+ parameter: {
441
+ handler (newValue, oldValue) {
442
+ console.log('监听事件触发:', { old: oldValue, new: newValue })
443
+ // 当 parameter 变化时重新获取数据
444
+ this.getData(this.queryParamsName, {})
445
+ },
446
+ deep: true // 深度监听对象内部变化
447
+ }
448
+ }
449
+ }
450
+ </script>
451
+
452
+ <style scoped lang="less">
453
+ .patient-info-descriptions {
454
+ background: #fff;
455
+ padding: 12px;
456
+ border-radius: 4px;
457
+ width: 100%;
458
+ }
459
+
460
+ .descriptions-container {
461
+ position: relative;
462
+ width: 100%;
463
+ padding-right: 80px; /* 为按钮预留空间 */
464
+ }
465
+
466
+ /* 自适应布局样式 */
467
+ .flex-descriptions {
468
+ display: flex;
469
+ flex-wrap: wrap;
470
+ gap: 8px 24px;
471
+ width: 100%;
472
+ }
473
+
474
+ .description-item {
475
+ display: inline-flex;
476
+ align-items: center;
477
+ padding: 4px 8px;
478
+ border-radius: 4px;
479
+ transition: background-color 0.3s;
480
+ white-space: nowrap;
481
+ flex: 0 1 auto;
482
+ }
483
+
484
+ .description-item:hover {
485
+ background-color: rgba(0, 0, 0, 0.02);
486
+ }
487
+
488
+ /* 共用样式 */
489
+ .label-wrapper {
490
+ display: flex;
491
+ align-items: center;
492
+ gap: 8px;
493
+ color: rgba(0, 0, 0, 0.65);
494
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
495
+ white-space: nowrap;
496
+ }
497
+
498
+ .label-text {
499
+ white-space: nowrap;
500
+ color: #313131; // 统一深灰
501
+ text-decoration: none !important; // 移除下划线
502
+ }
503
+
504
+ .content-wrapper {
505
+ display: inline-flex;
506
+ align-items: center;
507
+ margin-left: 4px;
508
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
509
+ color: rgba(0, 0, 0, 0.85);
510
+ text-decoration: none !important; // 移除可能的下划线
511
+ max-width: 300px;
512
+ overflow: hidden;
513
+ text-overflow: ellipsis;
514
+ white-space: nowrap;
515
+ }
516
+
517
+ /* 强制移除任何链接样式(如接口返回含 <a>) */
518
+ ::v-deep a {
519
+ color: #313131 !important;
520
+ text-decoration: none !important;
521
+ }
522
+
523
+ .detail-button-wrapper {
524
+ position: absolute;
525
+ right: 0;
526
+ top: 0;
527
+ z-index: 10;
528
+ padding: 4px 8px;
529
+ white-space: nowrap;
530
+ background-color: #fff;
531
+ }
532
+
533
+ /* 底部区域:分割线 + 三列内容 */
534
+ .xhdesc-footer {
535
+ margin-top: 12px;
536
+ }
537
+
538
+ .xhdesc-divider {
539
+ width: calc(100% + 24px); /* 扩展到左右内边距之外 */
540
+ height: 0;
541
+ border-bottom: 1px solid #E5E9F0;
542
+ margin: 10px -12px 14px; /* 抵消左右 12px 内边距 */
543
+ overflow: hidden;
544
+ }
545
+ /* medical-history 模式:左 padding 11px,右 12px(由外层设置),做精确抵消 */
546
+ .patient-info-descriptions.xhdesc-medical-history .xhdesc-divider {
547
+ width: calc(100% + 23px);
548
+ margin-left: -11px;
549
+ margin-right: -12px;
550
+ }
551
+
552
+ .footer-grid {
553
+ display: grid;
554
+ grid-template-columns: 1fr; // 单列
555
+ gap: 8px 24px; // 与上方描述项间距保持一致
556
+ align-items: start; // 左上对齐
557
+ }
558
+
559
+ /* footer 区域的每项直接沿用通用 .description-item/.label-wrapper/.content-wrapper 样式 */
560
+
561
+ .footer-right {
562
+ margin-top: 8px;
563
+ display: flex;
564
+ justify-content: flex-end;
565
+ align-items: center;
566
+ gap: 16px;
567
+ }
568
+
569
+ .footer-right-item {
570
+ display: inline-flex;
571
+ align-items: center;
572
+ }
573
+
574
+ /* Ant Design 描述列表样式覆盖 */
575
+ ::v-deep(.ant-descriptions-row) {
576
+ display: flex;
577
+ flex-direction: row;
578
+ align-items: flex-start;
579
+ }
580
+
581
+ ::v-deep(.ant-descriptions-item) {
582
+ padding: 0 !important;
583
+ display: flex !important;
584
+ align-items: flex-start !important;
585
+ flex-direction: row !important;
586
+ margin-right: 24px;
587
+ width: fit-content !important;
588
+ margin-bottom: 16px;
589
+ }
590
+
591
+ ::v-deep(.ant-descriptions-item-container) {
592
+ display: flex !important;
593
+ flex-direction: row !important;
594
+ align-items: flex-start !important;
595
+ position: relative;
596
+ gap: 0 !important;
597
+ width: 100% !important;
598
+ }
599
+
600
+ ::v-deep(.ant-descriptions-item-label) {
601
+ color: rgba(0, 0, 0, 0.65);
602
+ padding: 0 !important;
603
+ margin: 0 !important;
604
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
605
+ display: inline-flex !important;
606
+ align-items: center !important;
607
+ white-space: nowrap !important;
608
+ min-width: v-bind('(config && config.style && config.style.labelWidth) || "80px"');
609
+ justify-content: flex-start;
610
+ padding-right: 2px !important;
611
+ }
612
+
613
+ ::v-deep(.ant-descriptions-item-content) {
614
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
615
+ display: inline-flex !important;
616
+ align-items: center !important;
617
+ padding: 0 !important;
618
+ margin: 0 !important;
619
+ margin-left: 0px !important;
620
+ }
621
+
622
+ ::v-deep(.ant-descriptions-item-colon) {
623
+ position: static !important;
624
+ display: inline-flex !important;
625
+ align-items: center !important;
626
+ margin: 0 !important;
627
+ padding: 0 !important;
628
+ margin-right: 2px !important;
629
+ }
630
+
631
+ ::v-deep(.ant-descriptions-item-container:hover) {
632
+ background-color: rgba(0, 0, 0, 0.02);
633
+ border-radius: 4px;
634
+ }
635
+
636
+ ::v-deep(.ant-btn-link) {
637
+ padding: 0;
638
+ height: auto;
639
+ line-height: 1;
640
+ }
641
+
642
+ ::v-deep(.ant-btn-link:hover) {
643
+ color: #1890ff;
644
+ background: transparent;
645
+ }
646
+
647
+ /* 响应式调整 */
648
+ @media screen and (max-width: 768px) {
649
+ .content-wrapper {
650
+ max-width: 200px;
651
+ }
652
+ }
653
+
654
+ @media screen and (max-width: 576px) {
655
+ .content-wrapper {
656
+ max-width: 150px;
657
+ }
658
+ .flex-descriptions {
659
+ gap: 4px 12px;
660
+ }
661
+ }
662
+
663
+ /* 添加虚线样式 */
664
+ .with-divider {
665
+ position: relative;
666
+ margin-bottom: 16px !important;
667
+ }
668
+
669
+ .with-divider::after {
670
+ content: '';
671
+ position: absolute;
672
+ left: 0;
673
+ bottom: -8px;
674
+ width: 100%;
675
+ height: 0;
676
+ border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
677
+ }
678
+
679
+ /* 对于 Ant Design 描述列表的特殊处理 */
680
+ ::v-deep(.ant-descriptions-item.with-divider) {
681
+ position: relative;
682
+ margin-bottom: 16px !important;
683
+ }
684
+
685
+ ::v-deep(.ant-descriptions-item.with-divider::after) {
686
+ content: '';
687
+ position: absolute;
688
+ left: 0;
689
+ bottom: -8px;
690
+ width: 100%;
691
+ height: 0;
692
+ border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
693
+ }
694
+
695
+ /* 加边框 */
696
+ .xhdesc-description {
697
+ padding: 4px 4px 4px 4px;
698
+
699
+ /* 作用域内 *patient-info-descriptions */
700
+ &.patient-info-descriptions,
701
+ .patient-info-descriptions {
702
+ border: 1px solid #E5E9F0;
703
+ border-radius: 6px;
704
+ padding: 6.5px 12px;
705
+
706
+ /* *ant-btn-link */
707
+ ::v-deep .ant-btn-link {
708
+ border: none;
709
+ }
710
+
711
+ /* *ant-descriptions-item-content */
712
+ ::v-deep .ant-descriptions-item-content {
713
+ font-weight: bold;
714
+ }
715
+ }
716
+ }
717
+ // 去除住院收费页面两个描述列表之间的间距
718
+ .xhdesc-margin-top-12 {
719
+ margin-top: -12px;
720
+ }
721
+ .xhdesc-no-padding {
722
+ padding: 0px;
723
+ &.patient-info-descriptions,
724
+ .patient-info-descriptions {
725
+ /* *ant-descriptions-item-content */
726
+ ::v-deep .descriptions-container {
727
+ padding: 0px;
728
+ }
729
+ ::v-deep .content-wrapper {
730
+ margin: 0px;
731
+ }
732
+ }
733
+ }
734
+ /* 医疗病史模式:自定义HTML结构样式 */
735
+ .medical-history-descriptions {
736
+ width: 100%;
737
+ }
738
+
739
+ .medical-history-item {
740
+ margin: 0;
741
+ width: 100%;
742
+ }
743
+
744
+ .medical-history-item.with-divider {
745
+ position: relative;
746
+ padding-bottom: 4px; /* 分割线与上方间距 4px */
747
+ margin-bottom: 4px; /* 分割线与下方间距 4px */
748
+ }
749
+
750
+ .medical-history-item.with-divider::after {
751
+ content: '';
752
+ position: absolute;
753
+ left: 0;
754
+ bottom: 0; /* 贴合容器底部 */
755
+ width: 100%;
756
+ height: 0;
757
+ border-bottom: 1px solid rgba(0, 0, 0, 0.15);
758
+ }
759
+
760
+ .medical-history-content {
761
+ font-family: "Source Han Sans";
762
+ font-size: 18px;
763
+ line-height: 24px;
764
+ letter-spacing: 0em;
765
+ text-align: left;
766
+ word-break: break-word;
767
+ white-space: normal;
768
+ text-indent: 0;
769
+ padding-left: 0;
770
+ margin-left: 0;
771
+ /* 使用float实现真正的文本环绕 */
772
+ overflow: hidden;
773
+ /* 确保容器能够正确清除浮动 */
774
+ position: relative;
775
+ }
776
+
777
+ .medical-history-label {
778
+ font-family: "Source Han Sans";
779
+ font-size: 16px;
780
+ font-weight: 700;
781
+ color: #313131;
782
+ white-space: nowrap;
783
+ float: left;
784
+ margin-right: 0px;
785
+ /* 确保标签不会影响文本流 */
786
+ position: relative;
787
+ z-index: 1;
788
+ }
789
+
790
+ .medical-history-text {
791
+ font-family: "Source Han Sans";
792
+ font-size: 16px;
793
+ font-weight: 400;
794
+ color: #313131;
795
+ display: block;
796
+ overflow: hidden;
797
+ text-indent: 0;
798
+ padding-left: 0;
799
+ margin-left: 0;
800
+ word-break: break-word;
801
+ white-space: normal;
802
+ text-align: left;
803
+ line-height: 24px;
804
+ /* 确保文本能够正确环绕浮动元素 */
805
+ margin-top: 0;
806
+ margin-bottom: 0;
807
+ }
808
+
809
+ .medical-history-text.ellipsis {
810
+ display: -webkit-box;
811
+ -webkit-box-orient: vertical;
812
+ -webkit-line-clamp: 3;
813
+ line-clamp: 3;
814
+ overflow: hidden;
815
+ cursor: pointer;
816
+ position: relative;
817
+ word-break: break-word;
818
+ white-space: normal;
819
+ line-height: 24px;
820
+ text-indent: 0;
821
+ padding-left: 0;
822
+ margin-left: 0;
823
+ text-align: left;
824
+ -webkit-box-pack: start;
825
+ -webkit-box-align: start;
826
+ }
827
+
828
+ /* 使用-webkit-line-clamp时不需要手动添加省略号 */
829
+ .medical-history-text.ellipsis::after {
830
+ display: none;
831
+ }
832
+
833
+ /* 针对多行文本的特殊处理:确保换行文本与首行对齐 */
834
+ .medical-history-text.ellipsis::first-line {
835
+ text-indent: 0;
836
+ }
837
+
838
+ /* 为不支持-webkit-line-clamp的浏览器提供后备方案 */
839
+ @supports not (-webkit-line-clamp: 3) {
840
+ .medical-history-text.ellipsis {
841
+ display: block;
842
+ max-height: 72px; /* 3行 * 24px行高 */
843
+ overflow: hidden;
844
+ position: relative;
845
+ }
846
+
847
+ .medical-history-text.ellipsis::after {
848
+ content: '...';
849
+ position: absolute;
850
+ right: 0;
851
+ bottom: 0;
852
+ background: #fff;
853
+ padding-left: 4px;
854
+ display: block;
855
+ }
856
+ }
857
+
858
+ /* 医疗病史样式开关:通过 wrapperClassObject 添加类 xhdesc-medical-history */
859
+ .patient-info-descriptions.xhdesc-medical-history {
860
+ padding: 9px 12px 10px 11px !important;
861
+ /* 移除右侧空白(本模式不需要详情按钮预留空间) */
862
+ .descriptions-container {
863
+ padding-right: 0;
864
+ padding-left: 0px;
865
+ }
866
+ /* 医疗病史模式下:footer 区域使用与上方相同的医疗病史样式 */
867
+ .medical-history-footer {
868
+ width: 100%;
869
+ }
870
+ .medical-history-footer .footer-right {
871
+ margin-top: 8px;
872
+ display: flex;
873
+ justify-content: flex-end;
874
+ align-items: flex-start;
875
+ gap: 16px;
876
+ width: 100%;
877
+ }
878
+ /* 右侧(医生/医嘱日期)标签与值的字体要求 */
879
+ .medical-history-footer .footer-right .label-wrapper .label-text {
880
+ font-family: "Source Han Sans";
881
+ font-size: 16px;
882
+ font-weight: 700;
883
+ color: #313131;
884
+ line-height: 22px;
885
+ }
886
+ .medical-history-footer .footer-right .content-wrapper {
887
+ font-family: "Source Han Sans";
888
+ font-size: 16px;
889
+ font-weight: 400;
890
+ line-height: 22px;
891
+ color: #313131;
892
+ }
893
+
894
+ .medical-history-footer .footer-right .medical-history-item {
895
+ display: inline-block;
896
+ text-align: right;
897
+ }
898
+
899
+ .medical-history-footer .footer-right .medical-history-content {
900
+ text-align: right;
901
+ }
902
+
903
+ .medical-history-footer .footer-right .medical-history-label {
904
+ float: none;
905
+ display: inline;
906
+ margin-right: 0px;
907
+ }
908
+
909
+ .medical-history-footer .footer-right .medical-history-text {
910
+ display: inline;
911
+ text-align: right;
912
+ }
913
+
914
+ .medical-history-footer .footer-right .medical-history-text.ellipsis {
915
+ display: inline;
916
+ text-align: right;
917
+ }
918
+ }
919
+ </style>