vue2-client 1.18.34 → 1.18.36

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 (22) hide show
  1. package/package.json +1 -1
  2. package/src/assets/svg/female.svg +1 -1
  3. package/src/assets/svg/male.svg +1 -1
  4. package/src/base-client/components/common/CitySelect/CitySelect.vue +9 -1
  5. package/src/base-client/components/common/HIS/HFormGroup/index.js +3 -3
  6. package/src/base-client/components/common/HIS/HFormTable/HFormTable.vue +22 -0
  7. package/src/base-client/components/common/XAddNativeForm/XAddNativeForm.vue +42 -53
  8. package/src/base-client/components/common/XCollapse/XCollapse.vue +830 -830
  9. package/src/base-client/components/common/XDescriptions/XDescriptions.vue +174 -174
  10. package/src/base-client/components/common/XSimpleDescriptions/XSimpleDescriptions.vue +166 -166
  11. package/src/base-client/components/common/XTimeline/XTimeline.vue +477 -477
  12. package/src/base-client/components/his/XHisEditor/XHisEditor.vue +705 -705
  13. package/src/base-client/components/his/XList/XList.vue +938 -938
  14. package/src/base-client/components/his/XTimeSelect/XTimeSelect.vue +354 -354
  15. package/src/base-client/components/his/XTitle/XTitle.vue +314 -314
  16. package/src/base-client/components/his/XTreeRows/XTreeRows.vue +341 -341
  17. package/src/base-client/components/his/threeTestOrders/editor.vue +113 -113
  18. package/src/config/CreateQueryConfig.js +325 -325
  19. package/src/pages/XTreeOneProExample/index.vue +67 -67
  20. package/src/pages/userInfoDetailManage/ExceptionRecordQuery/index.vue +45 -45
  21. package/src-base-client/components/common/HIS/HForm/HForm.vue +0 -347
  22. package/src-base-client/components/common/XCollapse/XCollapse.vue +0 -0
@@ -1,830 +1,830 @@
1
- <template>
2
- <div class="x-collapse-wrapper" :class="wrapperClassObject">
3
- <div class="collapse-content-wrapper" :class="{ 'with-pagination': shouldShowPagination }">
4
- <a-collapse
5
- :activeKey="activeKey"
6
- @change="handleChange"
7
- :bordered="config.bordered || true"
8
- :expand-icon-position="config.expandIconPosition || 'right'"
9
- :style="config.style || ''"
10
- >
11
- <a-collapse-panel
12
- v-for="(panel, panelIndex) in pagedPanels"
13
- :key="panelIndex.toString()"
14
- :show-arrow="config.showArrow || false"
15
- :disabled="config.collapsible">
16
- <template #header>
17
- <div class="header-content">
18
- <!-- 新增蓝色圆点图标,根据配置显示 -->
19
- <div
20
- v-if="config.showCircleIcon"
21
- class="blue-circle-icon"
22
- :style="config.circleIconStyle || {}"></div>
23
- <span
24
- class="header-text"
25
- :style="config.titleStyle">
26
- {{ getPanelTitle(panel) }}
27
- </span>
28
- <!-- 当有 title2 数据时显示信息项 -->
29
- <template v-if="panel.title2 && panel.title2.length">
30
- <span
31
- v-for="(item, headerIndex) in panel.title2"
32
- :key="headerIndex"
33
- class="info-item"
34
- :style="config.title2Style">
35
- <!-- 根据showTitle是否显示键名 -->
36
- <span v-if="item.showTitle">{{ item.key }}:</span>
37
- <span>{{ item.value }}</span>
38
- </span>
39
- </template>
40
- <!-- 当有 title3 数据时显示时间项(与 title2 一致:支持数组/单项) -->
41
- <template v-if="panel.title3 && Array.isArray(panel.title3) && panel.title3.length">
42
- <span
43
- v-for="(item, t3Index) in panel.title3"
44
- :key="t3Index"
45
- :class="['time-item', { 'time-first': t3Index === 0 }]"
46
- :style="config.title3Style">
47
- <span v-if="item.showTitle">{{ item.key }}:</span>
48
- <span>{{ item.value }}</span>
49
- </span>
50
- </template>
51
- <span
52
- v-else-if="panel.title3"
53
- class="time-item time-first"
54
- :style="config.title3Style">
55
- {{ panel.title3 }}
56
- </span>
57
- <!-- 修改搜索框的显示条件 -->
58
- <a-input-search
59
- v-if="panel.search"
60
- v-model="searchText[panelIndex]"
61
- :placeholder="panel.searchPlace"
62
- class="search-input"
63
- @search="(value) => onSearch(value, panelIndex)"
64
- @click.stop/>
65
- </div>
66
- </template>
67
-
68
- <!-- 新增设置图标,根据配置显示 -->
69
- <template #extra v-if="config.showSettingIcon">
70
- <a-icon
71
- v-if="activeKey.includes(panelIndex.toString())"
72
- :type="config.settingIconType || 'setting'"
73
- class="setting-icon"
74
- @click.stop="handleSettingClick(panel, panelIndex)"/>
75
- </template>
76
-
77
- <!-- 根据类型显示不同内容 -->
78
- <template v-if="panel.type === 'picture'">
79
- <img :src="panel.configName" alt="图片" style="width: 100%; max-width: 500px;"/>
80
- </template>
81
- <template v-else-if="['x-image-report','x-form-table','x-simple-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse','x-h-descriptions', 'x-sidebar', 'x-list','x-input','x-time-line', 'x-radio', 'x-text-card','x-tree-rows'].includes(panel.type)">
82
- <component
83
- :is="getComponentName(panel.type)"
84
- :ref="`dynamicComponent_${ panel.type }_${ panelIndex }`"
85
- :serverName="panel.serverName || 'af-his'"
86
- :queryParamsName="panel.configName"
87
- :parameter="panel.parameter"
88
- :countVisible="false"
89
- :env="env"
90
- :style="config.componentStyle || ''"
91
- v-bind="panel.attrs || {}"
92
- :class="panel.className"
93
- :ipanelIndex="panelIndex"
94
- @deleteData="deleteData"
95
- @add="add"
96
- @listClick="listClick"
97
- @click="click"
98
- @component-mounted="handleMounted"
99
- @search-complete="handleSearchComplete" />
100
- </template>
101
- </a-collapse-panel>
102
- </a-collapse>
103
- </div>
104
- <div v-if="shouldShowPagination" class="xcollapse-pagination">
105
- <div class="pagination-extras">
106
- <a-button-group size="small">
107
- <a-button icon="vertical-right" :disabled="paginationCurrent === 1" @click="goFirstPage"/>
108
- <a-pagination
109
- :current="paginationCurrent"
110
- :pageSize="paginationPageSize"
111
- :total="paginationTotal"
112
- :showSizeChanger="false"
113
- show-less-items
114
- @change="onPageChange"/>
115
- <a-button icon="vertical-left" :disabled="paginationCurrent === maxPage" @click="goLastPage"/>
116
- </a-button-group>
117
- <span class="pagination-info">共 {{ maxPage }} 页, {{ paginationTotal }} 条</span>
118
- </div>
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: 'XCollapse',
128
- components: {
129
- XFormTable: () => import('@vue2-client/base-client/components/common/XFormTable/XFormTable.vue'),
130
- XAddNativeForm: () => import('@vue2-client/base-client/components/common/XAddNativeForm/XAddNativeForm.vue'),
131
- XFormGroup: () => import('@vue2-client/base-client/components/common/XFormGroup/XFormGroup.vue'),
132
- XTreePro: () => import('@vue2-client/base-client/components/common/XTree/XTreePro.vue'),
133
- XHisEditor: () => import('@vue2-client/base-client/components/his/XHisEditor/XHisEditor.vue'),
134
- XTab: () => import('@vue2-client/base-client/components/common/XTab/XTab.vue'),
135
- XReport: () => import('@vue2-client/base-client/components/common/XReport/XReport.vue'),
136
- XButtons: () => import('@vue2-client/base-client/components/common/XButtons/XButtons.vue'),
137
- XLabelSelect: () => import('@vue2-client/base-client/components/common/XLabelSelect/XLabelSelect.vue'),
138
- XConversation: () => import('@vue2-client/base-client/components/common/XConversation/XConversation.vue'),
139
- XCheckList: () => import('@vue2-client/base-client/components/common/XCheckList/XCheckList.vue'),
140
- XCardSet: () => import('@vue2-client/base-client/components/common/XCardSet/XCardSet.vue'),
141
- XCollapse: () => import('@vue2-client/base-client/components/common/XCollapse/XCollapse.vue'),
142
- XHDescriptions: () => import('@vue2-client/base-client/components/his/XHDescriptions/XHDescriptions.vue'),
143
- XImageReport: () => import('@vue2-client/base-client/components/his/XImageReport/XImageReport.vue'),
144
- XSidebar: () => import('@vue2-client/base-client/components/his/XSidebar/XSidebar.vue'),
145
- XList: () => import('@vue2-client/base-client/components/his/XList/XList.vue'),
146
- XInput: () => import('@vue2-client/base-client/components/common/XInput/XInput.vue'),
147
- XTimeLine: () => import('@vue2-client/base-client/components/common/XTimeline/XTimeline.vue'),
148
- XRadio: () => import('@vue2-client/base-client/components/his/XRadio/XRadio.vue'),
149
- XTextCard: () => import('@vue2-client/base-client/components/his/XTextCard/XTextCard.vue'),
150
- XTreeRows: () => import('@vue2-client/base-client/components/his/XTreeRows/XTreeRows.vue'),
151
- XSimpleTable: () => import('@vue2-client/base-client/components/his/XSimpleTable/XSimpleTable.vue')
152
- },
153
- data () {
154
- return {
155
- activeKey: [],
156
- config: {},
157
- configName: '',
158
- searchText: {},
159
- sonInstances: [], // 存储子组件实例
160
- paginationCurrent: 1,
161
- paginationPageSize: 5,
162
- lastParams: {}, // 缓存最近一次非分页参数
163
- paginationTotal: 0, // 后端返回的 total(仅分页模式使用)
164
- }
165
- },
166
- props: {
167
- // 环境
168
- env: {
169
- type: String,
170
- default: 'prod'
171
- },
172
- // json名
173
- queryParamsName: {
174
- type: Object,
175
- default: null
176
- },
177
- parameter: {
178
- type: Object,
179
- default: () => {
180
- return {}
181
- }
182
- }
183
- },
184
- created () {
185
- this.getData(this.queryParamsName, this.parameter)
186
- },
187
- beforeDestroy () {},
188
- computed: {
189
- // 基于 $attrs 的样式类开关(与 XHDescriptions.vue 思路一致)
190
- wrapperClassObject () {
191
- const attrs = this.$attrs || {}
192
- const classes = {}
193
- const booleanStyleKeys = [
194
- 'style1',
195
- 'check-result',
196
- 'medical-entry'
197
- ]
198
- booleanStyleKeys.forEach(key => {
199
- const val = attrs[key]
200
- const truthy = val === true || val === '' || val === 'true'
201
- if (truthy) classes[`xcollapse-${key}`] = true
202
- })
203
- const size = attrs.size
204
- if (size && typeof size === 'string') classes[`xcollapse-size-${size}`] = true
205
- if (this.shouldShowPagination) classes['with-pagination'] = true
206
- return classes
207
- },
208
- enablePagination () { return !!this.config?.pagination },
209
- shouldShowPagination () { return this.enablePagination },
210
- maxPage () {
211
- const size = Number(this.paginationPageSize || 1)
212
- const total = this.paginationTotal
213
- return Math.max(1, Math.ceil(total / size))
214
- },
215
- pagedPanels () {
216
- const showData = this.config?.showData || []
217
- if (this.enablePagination) return showData
218
- const start = (this.paginationCurrent - 1) * this.paginationPageSize
219
- const end = start + this.paginationPageSize
220
- return showData.slice(start, end)
221
- }
222
- },
223
- methods: {
224
- handleMounted (instance) {
225
- this.sonInstances.push(instance)
226
- },
227
- handleSearchComplete ({ hasMatch, panelIndex }) {
228
- if (hasMatch && !this.activeKey.includes(panelIndex.toString())) {
229
- // 只展开包含搜索结果的面板
230
- this.activeKey = [panelIndex.toString()]
231
- }
232
- },
233
- getComponentName (componentName) {
234
- return componentName
235
- },
236
- getPanelTitle (panel) {
237
- // 兼容数据为纯对象数组(无 title 字段)时的显示
238
- if (panel && panel.title) return panel.title
239
- if (panel && panel.name) return panel.name
240
- if (panel && panel.code) return panel.code
241
- return ''
242
- },
243
- add (data) {
244
- this.$emit('add', data)
245
- },
246
- deleteData (data) {
247
- this.$emit('deleteData', data)
248
- },
249
- listClick (data) {
250
- this.$emit('listClick', data)
251
- },
252
- click (data) {
253
- this.$emit('click', data)
254
- },
255
- getConfigByName (componentName) {
256
- const refKey = `dynamicComponent_${componentName}`
257
- return this.$refs[refKey]
258
- },
259
- // xTreeRow 组件搜素功能
260
- searchTreeRows (title) {
261
- this.$nextTick(() => {
262
- const instances = this.sonInstances
263
- instances.forEach(comp => {
264
- try {
265
- comp.searchTitleToggle?.(title)
266
- } catch (e) {
267
- console.error('调用失败:', e)
268
- }
269
- })
270
- })
271
- },
272
- async getData (config, parameter) {
273
- this.configName = config
274
- getConfigByName(config, 'af-his', res => {
275
- // 合并配置,保留已有的 pagination 等开关
276
- const original = this.config || {}
277
- this.config = { ...original, ...res }
278
- // 同步分页初值(仅当配置里提供时)
279
- const p = this.config?.pagination || null
280
- if (p && p.pageSize) this.paginationPageSize = Number(p.pageSize)
281
- // 只在初始化时设置默认页码,避免每次重置
282
- if (p && p.current && this.paginationCurrent === 1) {
283
- this.paginationCurrent = Number(p.current)
284
- }
285
-
286
- // 组合请求参数,启用分页时传递页码与页大小
287
- const baseParams = (parameter && Object.keys(parameter).length ? parameter : this.lastParams) || {}
288
- this.lastParams = { ...baseParams }
289
- const requestParams = { ...baseParams }
290
- if (this.enablePagination) {
291
- requestParams.page = this.paginationCurrent
292
- requestParams.pageSize = this.paginationPageSize
293
- }
294
-
295
- runLogic(res.mainLogic, requestParams, 'af-his').then(result => {
296
- let showData = []
297
- let totalCount = 0
298
-
299
- if (this.enablePagination) {
300
- // 启用分页:后端固定返回 { total, data: [], page, pageSize }
301
- showData = result.data
302
- this.paginationTotal = Number(result.total) || 0
303
- totalCount = this.paginationTotal
304
- } else {
305
- // 未启用分页:直接取数组
306
- showData = Array.isArray(result && result.data) ? result.data : (Array.isArray(result) ? result : [])
307
- totalCount = showData.length
308
- }
309
-
310
- // 赋值
311
- this.$set(this.config, 'showData', showData)
312
- this.$set(this.config, 'totalCount', Number(totalCount))
313
-
314
- // 后端分页边界保护:当前页超界时回退到最后一页并重拉
315
- if (this.enablePagination) {
316
- const total = Number(this.config.totalCount || 0)
317
- const size = Number(this.paginationPageSize || 1)
318
- const maxPage = Math.max(1, Math.ceil(total / size))
319
- if (this.paginationCurrent > maxPage) {
320
- this.paginationCurrent = maxPage
321
- this.getData(this.queryParamsName, this.parameter)
322
- return
323
- }
324
- }
325
-
326
- // 更具timeType更改时间类型
327
- if (this.config.timeType && this.config.timeType === '.') {
328
- this.config.showData.forEach(panel => {
329
- // if (panel.title3) {
330
- // panel.title3 = this.convertToCustomFormat(panel.title3)
331
- // }
332
- })
333
- this.$forceUpdate()
334
- }
335
- // 根据配置决定是否展开面板
336
- const shouldCollapseAll = this.config.collapseAllByDefault || false
337
- if (shouldCollapseAll) {
338
- // 如果配置为默认关闭,直接设置为空数组,避免展开动画
339
- this.activeKey = []
340
- } else {
341
- // 默认展开当前页的所有面板
342
- this.activeKey = (this.config.showData || []).map((_, i) => i.toString())
343
- }
344
- })
345
- })
346
- },
347
- onPageChange (page) {
348
- this.paginationCurrent = page
349
- // 后端分页:重新拉数;前端分页:仅切片
350
- this.getData(this.queryParamsName, this.lastParams)
351
- },
352
- goFirstPage () {
353
- if (this.paginationCurrent === 1) return
354
- this.onPageChange(1)
355
- },
356
- goLastPage () {
357
- if (this.paginationCurrent === this.maxPage) return
358
- this.onPageChange(this.maxPage)
359
- },
360
- refreshXCollapse () {
361
- this.getData(this.queryParamsName, this.parameter)
362
- },
363
- convertToCustomFormat (dateString) {
364
- // 创建一个新的 Date 对象
365
- const date = new Date(dateString)
366
- // 获取年、月、日
367
- const year = date.getFullYear()
368
- const month = date.getMonth() + 1 // 月份从0开始,所以需要加1
369
- const day = date.getDate()
370
- // 返回格式化后的字符串
371
- return `${year}.${month}.${day}`
372
- },
373
- handleChange (keys) {
374
- this.activeKey = keys
375
- // console.log(this.activeKey)
376
- },
377
- onSearch (value, panelIndex) {
378
- this.$emit('searchChange', { value: value, panelIndex: panelIndex })
379
- },
380
- handleSettingClick (panel, panelIndex) {
381
- this.$emit('settingClick', { panel, panelIndex })
382
- }
383
- },
384
- watch: {
385
- queryParamsName: {
386
- handler (newValue) {
387
- this.getData(newValue, this.parameter)
388
- },
389
- deep: true
390
- }
391
- }
392
- }
393
- </script>
394
-
395
- <style scoped lang="less">
396
- .x-collapse-wrapper { position: relative; display: flex; flex-direction: column; min-height: 100%; height: 100%; }
397
- .collapse-content-wrapper { flex: 1; min-height: 0; overflow: auto; position: relative; max-height: 78vh; }
398
- .collapse-content-wrapper.with-pagination { padding-bottom: 0px; }
399
- .header-content {
400
- display: flex;
401
- align-items: center;
402
- justify-content: flex-start; // 左对齐,避免圆点被拉开
403
- gap: 8px; // 圆点与标题的基础间距
404
- white-space: nowrap;
405
- overflow: hidden;
406
- flex: 1; // 占满可用宽度,便于空间分配
407
- }
408
-
409
- .header-text {
410
- margin-right: 14.17px;
411
- font-size: 16px;
412
- font-weight: 800;
413
- flex-shrink: 0;
414
- }
415
-
416
- .info-item {
417
- display: inline-flex;
418
- align-items: center;
419
- gap: 8px;
420
- font-size: 12px;
421
- color: #888888;
422
- flex-shrink: 0;
423
- }
424
-
425
- .time-item {
426
- margin-left: 12px;
427
- text-align: right;
428
- flex-shrink: 0;
429
- }
430
-
431
- :deep(.ant-collapse-header) {
432
- display: flex;
433
- position: relative;
434
- // border-bottom: v-bind('config.showLine ? "1px solid #000000" : "none"');
435
- align-items: center !important;
436
- background-color: #ffffff;
437
- padding: 12px 16px !important; /* 确保头部有足够的内边距 */
438
- }
439
-
440
- :deep(.ant-collapse-header-text) {
441
- flex: 1;
442
- }
443
-
444
- :deep(.ant-collapse-content > .ant-collapse-content-box) {
445
- padding: 16px !important; /* 确保内容区域有足够的内边距 */
446
- }
447
-
448
- .search-input {
449
- margin-left: 12px;
450
- width: auto;
451
- max-width: 40%;
452
- }
453
-
454
- // 右侧块定位:首个 info-item 或 time-item 推到右侧
455
- .header-content .info-item:first-of-type { margin-left: auto; }
456
- .header-content .time-item:first-of-type { margin-left: auto; }
457
-
458
- // 右侧块内部兄弟间距统一
459
- .info-item + .info-item { margin-left: 12px; }
460
- :deep(.ant-collapse-item-disabled > .ant-collapse-header) {
461
- cursor: default !important;
462
- }
463
-
464
- /* 新增样式 */
465
- .blue-circle-icon {
466
- width: 12px;
467
- height: 12px;
468
- border-radius: 6px;
469
- background: #3362DA;
470
- margin-top: 15px;
471
- margin-left: 11px;
472
- margin-bottom: 12px;
473
- flex-shrink: 0;
474
- }
475
-
476
- .setting-icon {
477
- font-size: 16px;
478
- cursor: pointer;
479
- display: inline-flex;
480
- align-items: center;
481
- justify-content: center;
482
- width: 19.47px;
483
- height: 20px;
484
- line-height: 20px;
485
- vertical-align: middle;
486
- color: #313131; /* 仅设置图标颜色,不设置背景 */
487
- margin-top: 0; /* 去除向上偏移 */
488
- margin-right: 47px; /* 与下拉箭头保持 20px 距离 */
489
- }
490
-
491
- :deep(.ant-collapse-extra) {
492
- display: flex !important;
493
- align-items: center;
494
- }
495
-
496
- .configurable-area {
497
- //padding: 16px;
498
- min-height: 100px;
499
- border: 1px dashed #d9d9d9;
500
- border-radius: 4px;
501
- background-color: #fafafa;
502
- }
503
-
504
- .empty-hint {
505
- color: #999;
506
- text-align: center;
507
- margin: 20px 0;
508
- }
509
-
510
- .loading-message {
511
- text-align: center;
512
- padding: 20px;
513
- color: #666;
514
- background: #f5f5f5;
515
- border-radius: 4px;
516
- margin: 10px 0;
517
- }
518
-
519
- .empty-state {
520
- text-align: center;
521
- padding: 40px 20px;
522
- color: #999;
523
- background: #fafafa;
524
- border-radius: 4px;
525
- margin: 10px 0;
526
- flex: 1;
527
- display: flex;
528
- align-items: center;
529
- justify-content: center;
530
- }
531
-
532
- /* 分页组件:固定在组件容器底部(不影响全局布局) */
533
- .with-pagination { padding-bottom: 0; }
534
- .xcollapse-pagination { /* 二盒子:自然流布局,不覆盖内容 */
535
- position: static;
536
- display: flex;
537
- justify-content: center;
538
- padding: 12px 0;
539
- background: #fff;
540
- border-top: 1px solid #f0f0f0;
541
- }
542
- .pagination-extras { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
543
- .pagination-extras .ant-btn-group { gap: 8px; }
544
- .pagination-extras .ant-btn-group + .pagination-info { margin-left: 9px; }
545
- .pagination-info {
546
- color: #5D5C5C;
547
- font-family: 'Source Han Sans', sans-serif;
548
- font-size: 16px;
549
- font-weight: normal;
550
- line-height: normal;
551
- letter-spacing: 0em;
552
- font-feature-settings: "kern" on;
553
- }
554
-
555
- /* 自定义分页按钮样式 */
556
- :deep(.pagination-extras .ant-btn) {
557
- font-family: 'Source Han Sans', sans-serif;
558
- font-size: 16px;
559
- font-weight: normal;
560
- line-height: normal;
561
- letter-spacing: 0em;
562
- font-feature-settings: "kern" on;
563
- color: #5D5C5C;
564
- border-radius: 4px;
565
- border: 1px solid #D8D8D8;
566
- background: #FFFFFF;
567
- box-sizing: border-box;
568
- margin-right: 8px;
569
- }
570
-
571
- :deep(.pagination-extras .ant-btn:last-child) {
572
- margin-right: 0;
573
- }
574
-
575
- /* 直达首页末页按钮样式 */
576
- :deep(.pagination-extras .ant-btn[icon="vertical-left"]),
577
- :deep(.pagination-extras .ant-btn[icon="vertical-right"]) {
578
- position: static; /* 使用常规流布局,避免遮挡分页主体 */
579
- width: 24px;
580
- height: 24px;
581
- border-radius: 4px;
582
- opacity: 1;
583
- background: #FFFFFF;
584
- box-sizing: border-box;
585
- border: 1px solid #D8D8D8;
586
- margin-right: 8px;
587
- }
588
-
589
- /* 上一页下一页按钮样式 */
590
- :deep(.ant-pagination .ant-pagination-prev),
591
- :deep(.ant-pagination .ant-pagination-next) {
592
- width: 24px;
593
- height: 24px;
594
- line-height: 24px;
595
- border-radius: 4px;
596
- opacity: 1;
597
- background: #FFFFFF;
598
- box-sizing: border-box;
599
- border: 1px solid #D8D8D8;
600
- }
601
-
602
- /* 页码选择按钮样式 */
603
- :deep(.ant-pagination .ant-pagination-item) {
604
- width: 24px;
605
- height: 24px;
606
- border-radius: 4px;
607
- border: 1px solid #D8D8D8;
608
- background: #FFFFFF;
609
- box-sizing: border-box;
610
- font-family: 'Source Han Sans', sans-serif;
611
- font-size: 16px;
612
- font-weight: normal;
613
- line-height: normal;
614
- letter-spacing: 0em;
615
- font-feature-settings: "kern" on;
616
- color: #5D5C5C;
617
- margin-right: 8px;
618
- }
619
-
620
- :deep(.ant-pagination .ant-pagination-item:last-child) {
621
- margin-right: 0;
622
- }
623
-
624
- /* 当前页码样式 */
625
- :deep(.ant-pagination .ant-pagination-item-active) {
626
- background: #0057FE !important;
627
- border: 1px solid #1890ff;
628
- color: #FFFFFF !important;
629
- }
630
-
631
- /* 确保选中页码文字颜色生效 */
632
- :deep(.ant-pagination .ant-pagination-item-active a) {
633
- color: #FFFFFF !important;
634
- }
635
-
636
- /* 禁用状态样式 */
637
- :deep(.pagination-extras .ant-btn:disabled) {
638
- opacity: 0.5;
639
- cursor: not-allowed;
640
- }
641
-
642
- /* 移除所有可能导致截断的固定高度 */
643
- :deep(.ant-collapse-item) .ant-collapse-content .ant-collapse-content-box > * {
644
- max-height: none !important; /* 移除可能的最大高度限制 */
645
- height: auto !important; /* 使用自动高度 */
646
- }
647
-
648
- // 基于根容器类进行样式整合:x-collapse-wrapper.xcollapse-style1
649
- .x-collapse-wrapper {
650
- // 检查结果样式
651
- &.xcollapse-check-result {
652
- height: auto; /* 允许根据内容自适应高度,避免滚动被限制 */
653
- min-height: 600px;
654
- // 让每个面板成为独立卡片:去掉 antd 默认的分隔线,增加间距与圆角
655
- :deep(.ant-collapse) {
656
- background: transparent;
657
- border: 0;
658
- }
659
-
660
- :deep(.ant-collapse > .ant-collapse-item) {
661
- width: 555px;
662
- min-height: auto;
663
- height: auto;
664
- margin-bottom:10px;
665
- background: #FFFFFF; // 独立白底
666
- box-sizing: border-box;
667
- border: 1px solid #E5E9F0; // 每个面板自身边框
668
- }
669
-
670
- :deep(.ant-collapse > .ant-collapse-item:first-child) { margin-top: 0; }
671
- :deep(.ant-collapse > .ant-collapse-item:last-child) { margin-bottom: 0; }
672
-
673
- :deep(.ant-collapse-content > .ant-collapse-content-box) {
674
- background: #FFFFFF;
675
- padding: 0px !important;
676
- }
677
-
678
- // 表头:恢复合适的上下内边距,去掉顶部额外空白
679
- :deep(.ant-collapse-header) {
680
- background: #FFFFFF;
681
- padding: 0px 0px !important;
682
- height: 39px !important;
683
- border-bottom: none !important; // 移除标题处下边线,避免与外边框连为一体
684
- border: 1px solid #E5E9F0; // 每个面板自身边框
685
- }
686
-
687
- /* 将右侧留白转移到标题与第一项之间 */
688
- .header-content { padding-right: 0px; gap: 5px; }
689
- .header-content .info-item:first-of-type { margin-left: 24px !important; }
690
- .header-content .time-item:first-of-type { margin-left: 24px !important; }
691
-
692
- .info-item {
693
- height: 20px;
694
- opacity: 1;
695
- font-family: "Source Han Sans";
696
- font-size: 14px;
697
- font-weight: 400;
698
- line-height: 20px;
699
- text-align: right;
700
- letter-spacing: 0em;
701
- font-feature-settings: "kern" on;
702
- color: #313131 !important;
703
- }
704
-
705
- .header-text {
706
- height: 23px;
707
- opacity: 1;
708
- font-family: "Source Han Sans";
709
- font-size: 16px;
710
- font-weight: 700;
711
- line-height: 23px;
712
- letter-spacing: 0em;
713
- padding-right: 40px;
714
- font-feature-settings: "kern" on;
715
- color: #313131 !important;
716
- }
717
- }
718
- // 历史病历样式
719
- &.xcollapse-style1 {
720
- height: auto; /* 允许根据内容自适应高度,避免滚动被限制 */
721
- min-height: 600px;
722
- .header-text {
723
- font-family: "Source Han Sans";
724
- font-size: 16px;
725
- font-weight: 700;
726
- line-height: 23px;
727
- letter-spacing: 0em;
728
- color: #313131;
729
- margin-top: 8px;
730
- margin-bottom: 8px;
731
- margin-right: 0 !important;
732
- }
733
-
734
- .info-item {
735
- font-family: "Source Han Sans";
736
- font-size: 16px;
737
- font-weight: 700;
738
- line-height: 23px;
739
- text-align: right;
740
- color: #313131;
741
- margin-top: 9px;
742
- margin-bottom: 7px;
743
- margin-left: 28.14px;
744
- letter-spacing: 0em
745
- }
746
-
747
- .time-item {
748
- font-family: "Source Han Sans";
749
- font-size: 16px;
750
- font-weight: 400;
751
- line-height: 23px;
752
- text-align: right;
753
- margin-top: 9px;
754
- margin-bottom: 7px;
755
- color: #313131;
756
- letter-spacing: 0em;
757
- }
758
-
759
- // 让每个面板成为独立卡片:去掉 antd 默认的分隔线,增加间距与圆角
760
- :deep(.ant-collapse) {
761
- background: transparent;
762
- border: 0;
763
- }
764
-
765
- :deep(.ant-collapse > .ant-collapse-item) {
766
- width: 555px;
767
- min-height: auto;
768
- height: auto;
769
- margin-bottom:10px;
770
- background: #FFFFFF; // 独立白底
771
- box-sizing: border-box;
772
- border: 1px solid #E5E9F0; // 每个面板自身边框
773
- }
774
-
775
- :deep(.ant-collapse > .ant-collapse-item:first-child) { margin-top: 0; }
776
- :deep(.ant-collapse > .ant-collapse-item:last-child) { margin-bottom: 0; }
777
-
778
- :deep(.ant-collapse-content > .ant-collapse-content-box) {
779
- background: #FFFFFF;
780
- padding: 0px !important;
781
- }
782
-
783
- // 表头:恢复合适的上下内边距,去掉顶部额外空白
784
- :deep(.ant-collapse-header) {
785
- background: #FFFFFF;
786
- padding: 0px 0px !important;
787
- height: 41px !important;
788
- border-bottom: none !important; // 移除标题处下边线,避免与外边框连为一体
789
- border: 1px solid #E5E9F0; // 每个面板自身边框
790
- }
791
- }
792
-
793
- // 医学词条样式
794
- &.xcollapse-medical-entry {
795
- height: auto;
796
- min-height: 600px;
797
- :deep(.ant-collapse) { background: transparent; border: 0; }
798
- :deep(.ant-collapse > .ant-collapse-item) {
799
- width: 564px;
800
- min-height: auto;
801
- height: auto;
802
- margin-bottom: 14px;
803
- background: #FFFFFF;
804
- box-sizing: border-box;
805
- border: 1px solid #E5E9F0;
806
- }
807
- :deep(.ant-collapse > .ant-collapse-item:first-child) { margin-top: 0; }
808
- :deep(.ant-collapse > .ant-collapse-item:last-child) { margin-bottom: 0; }
809
- :deep(.ant-collapse-content > .ant-collapse-content-box) { background: #FFFFFF; padding: 0px !important; }
810
- :deep(.ant-collapse-header) {
811
- background: #FFFFFF;
812
- padding: 0px 0px !important;
813
- height: 39px !important;
814
- border-bottom: none !important;
815
- border: 1px solid #E5E9F0;
816
- }
817
- .header-text {
818
- font-family: "Source Han Sans";
819
- font-size: 16px;
820
- font-weight: 700;
821
- line-height: 23px;
822
- letter-spacing: 0em;
823
- color: #313131;
824
- margin-top: 7px;
825
- margin-bottom: 7px;
826
- margin-right: 0 !important;
827
- }
828
- }
829
- }
830
- </style>
1
+ <template>
2
+ <div class="x-collapse-wrapper" :class="wrapperClassObject">
3
+ <div class="collapse-content-wrapper" :class="{ 'with-pagination': shouldShowPagination }">
4
+ <a-collapse
5
+ :activeKey="activeKey"
6
+ @change="handleChange"
7
+ :bordered="config.bordered || true"
8
+ :expand-icon-position="config.expandIconPosition || 'right'"
9
+ :style="config.style || ''"
10
+ >
11
+ <a-collapse-panel
12
+ v-for="(panel, panelIndex) in pagedPanels"
13
+ :key="panelIndex.toString()"
14
+ :show-arrow="config.showArrow || false"
15
+ :disabled="config.collapsible">
16
+ <template #header>
17
+ <div class="header-content">
18
+ <!-- 新增蓝色圆点图标,根据配置显示 -->
19
+ <div
20
+ v-if="config.showCircleIcon"
21
+ class="blue-circle-icon"
22
+ :style="config.circleIconStyle || {}"></div>
23
+ <span
24
+ class="header-text"
25
+ :style="config.titleStyle">
26
+ {{ getPanelTitle(panel) }}
27
+ </span>
28
+ <!-- 当有 title2 数据时显示信息项 -->
29
+ <template v-if="panel.title2 && panel.title2.length">
30
+ <span
31
+ v-for="(item, headerIndex) in panel.title2"
32
+ :key="headerIndex"
33
+ class="info-item"
34
+ :style="config.title2Style">
35
+ <!-- 根据showTitle是否显示键名 -->
36
+ <span v-if="item.showTitle">{{ item.key }}:</span>
37
+ <span>{{ item.value }}</span>
38
+ </span>
39
+ </template>
40
+ <!-- 当有 title3 数据时显示时间项(与 title2 一致:支持数组/单项) -->
41
+ <template v-if="panel.title3 && Array.isArray(panel.title3) && panel.title3.length">
42
+ <span
43
+ v-for="(item, t3Index) in panel.title3"
44
+ :key="t3Index"
45
+ :class="['time-item', { 'time-first': t3Index === 0 }]"
46
+ :style="config.title3Style">
47
+ <span v-if="item.showTitle">{{ item.key }}:</span>
48
+ <span>{{ item.value }}</span>
49
+ </span>
50
+ </template>
51
+ <span
52
+ v-else-if="panel.title3"
53
+ class="time-item time-first"
54
+ :style="config.title3Style">
55
+ {{ panel.title3 }}
56
+ </span>
57
+ <!-- 修改搜索框的显示条件 -->
58
+ <a-input-search
59
+ v-if="panel.search"
60
+ v-model="searchText[panelIndex]"
61
+ :placeholder="panel.searchPlace"
62
+ class="search-input"
63
+ @search="(value) => onSearch(value, panelIndex)"
64
+ @click.stop/>
65
+ </div>
66
+ </template>
67
+
68
+ <!-- 新增设置图标,根据配置显示 -->
69
+ <template #extra v-if="config.showSettingIcon">
70
+ <a-icon
71
+ v-if="activeKey.includes(panelIndex.toString())"
72
+ :type="config.settingIconType || 'setting'"
73
+ class="setting-icon"
74
+ @click.stop="handleSettingClick(panel, panelIndex)"/>
75
+ </template>
76
+
77
+ <!-- 根据类型显示不同内容 -->
78
+ <template v-if="panel.type === 'picture'">
79
+ <img :src="panel.configName" alt="图片" style="width: 100%; max-width: 500px;"/>
80
+ </template>
81
+ <template v-else-if="['x-image-report','x-form-table','x-simple-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse','x-h-descriptions', 'x-sidebar', 'x-list','x-input','x-time-line', 'x-radio', 'x-text-card','x-tree-rows'].includes(panel.type)">
82
+ <component
83
+ :is="getComponentName(panel.type)"
84
+ :ref="`dynamicComponent_${ panel.type }_${ panelIndex }`"
85
+ :serverName="panel.serverName || 'af-his'"
86
+ :queryParamsName="panel.configName"
87
+ :parameter="panel.parameter"
88
+ :countVisible="false"
89
+ :env="env"
90
+ :style="config.componentStyle || ''"
91
+ v-bind="panel.attrs || {}"
92
+ :class="panel.className"
93
+ :ipanelIndex="panelIndex"
94
+ @deleteData="deleteData"
95
+ @add="add"
96
+ @listClick="listClick"
97
+ @click="click"
98
+ @component-mounted="handleMounted"
99
+ @search-complete="handleSearchComplete" />
100
+ </template>
101
+ </a-collapse-panel>
102
+ </a-collapse>
103
+ </div>
104
+ <div v-if="shouldShowPagination" class="xcollapse-pagination">
105
+ <div class="pagination-extras">
106
+ <a-button-group size="small">
107
+ <a-button icon="vertical-right" :disabled="paginationCurrent === 1" @click="goFirstPage"/>
108
+ <a-pagination
109
+ :current="paginationCurrent"
110
+ :pageSize="paginationPageSize"
111
+ :total="paginationTotal"
112
+ :showSizeChanger="false"
113
+ show-less-items
114
+ @change="onPageChange"/>
115
+ <a-button icon="vertical-left" :disabled="paginationCurrent === maxPage" @click="goLastPage"/>
116
+ </a-button-group>
117
+ <span class="pagination-info">共 {{ maxPage }} 页, {{ paginationTotal }} 条</span>
118
+ </div>
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: 'XCollapse',
128
+ components: {
129
+ XFormTable: () => import('@vue2-client/base-client/components/common/XFormTable/XFormTable.vue'),
130
+ XAddNativeForm: () => import('@vue2-client/base-client/components/common/XAddNativeForm/XAddNativeForm.vue'),
131
+ XFormGroup: () => import('@vue2-client/base-client/components/common/XFormGroup/XFormGroup.vue'),
132
+ XTreePro: () => import('@vue2-client/base-client/components/common/XTree/XTreePro.vue'),
133
+ XHisEditor: () => import('@vue2-client/base-client/components/his/XHisEditor/XHisEditor.vue'),
134
+ XTab: () => import('@vue2-client/base-client/components/common/XTab/XTab.vue'),
135
+ XReport: () => import('@vue2-client/base-client/components/common/XReport/XReport.vue'),
136
+ XButtons: () => import('@vue2-client/base-client/components/common/XButtons/XButtons.vue'),
137
+ XLabelSelect: () => import('@vue2-client/base-client/components/common/XLabelSelect/XLabelSelect.vue'),
138
+ XConversation: () => import('@vue2-client/base-client/components/common/XConversation/XConversation.vue'),
139
+ XCheckList: () => import('@vue2-client/base-client/components/common/XCheckList/XCheckList.vue'),
140
+ XCardSet: () => import('@vue2-client/base-client/components/common/XCardSet/XCardSet.vue'),
141
+ XCollapse: () => import('@vue2-client/base-client/components/common/XCollapse/XCollapse.vue'),
142
+ XHDescriptions: () => import('@vue2-client/base-client/components/his/XHDescriptions/XHDescriptions.vue'),
143
+ XImageReport: () => import('@vue2-client/base-client/components/his/XImageReport/XImageReport.vue'),
144
+ XSidebar: () => import('@vue2-client/base-client/components/his/XSidebar/XSidebar.vue'),
145
+ XList: () => import('@vue2-client/base-client/components/his/XList/XList.vue'),
146
+ XInput: () => import('@vue2-client/base-client/components/common/XInput/XInput.vue'),
147
+ XTimeLine: () => import('@vue2-client/base-client/components/common/XTimeline/XTimeline.vue'),
148
+ XRadio: () => import('@vue2-client/base-client/components/his/XRadio/XRadio.vue'),
149
+ XTextCard: () => import('@vue2-client/base-client/components/his/XTextCard/XTextCard.vue'),
150
+ XTreeRows: () => import('@vue2-client/base-client/components/his/XTreeRows/XTreeRows.vue'),
151
+ XSimpleTable: () => import('@vue2-client/base-client/components/his/XSimpleTable/XSimpleTable.vue')
152
+ },
153
+ data () {
154
+ return {
155
+ activeKey: [],
156
+ config: {},
157
+ configName: '',
158
+ searchText: {},
159
+ sonInstances: [], // 存储子组件实例
160
+ paginationCurrent: 1,
161
+ paginationPageSize: 5,
162
+ lastParams: {}, // 缓存最近一次非分页参数
163
+ paginationTotal: 0, // 后端返回的 total(仅分页模式使用)
164
+ }
165
+ },
166
+ props: {
167
+ // 环境
168
+ env: {
169
+ type: String,
170
+ default: 'prod'
171
+ },
172
+ // json名
173
+ queryParamsName: {
174
+ type: Object,
175
+ default: null
176
+ },
177
+ parameter: {
178
+ type: Object,
179
+ default: () => {
180
+ return {}
181
+ }
182
+ }
183
+ },
184
+ created () {
185
+ this.getData(this.queryParamsName, this.parameter)
186
+ },
187
+ beforeDestroy () {},
188
+ computed: {
189
+ // 基于 $attrs 的样式类开关(与 XHDescriptions.vue 思路一致)
190
+ wrapperClassObject () {
191
+ const attrs = this.$attrs || {}
192
+ const classes = {}
193
+ const booleanStyleKeys = [
194
+ 'style1',
195
+ 'check-result',
196
+ 'medical-entry'
197
+ ]
198
+ booleanStyleKeys.forEach(key => {
199
+ const val = attrs[key]
200
+ const truthy = val === true || val === '' || val === 'true'
201
+ if (truthy) classes[`xcollapse-${key}`] = true
202
+ })
203
+ const size = attrs.size
204
+ if (size && typeof size === 'string') classes[`xcollapse-size-${size}`] = true
205
+ if (this.shouldShowPagination) classes['with-pagination'] = true
206
+ return classes
207
+ },
208
+ enablePagination () { return !!this.config?.pagination },
209
+ shouldShowPagination () { return this.enablePagination },
210
+ maxPage () {
211
+ const size = Number(this.paginationPageSize || 1)
212
+ const total = this.paginationTotal
213
+ return Math.max(1, Math.ceil(total / size))
214
+ },
215
+ pagedPanels () {
216
+ const showData = this.config?.showData || []
217
+ if (this.enablePagination) return showData
218
+ const start = (this.paginationCurrent - 1) * this.paginationPageSize
219
+ const end = start + this.paginationPageSize
220
+ return showData.slice(start, end)
221
+ }
222
+ },
223
+ methods: {
224
+ handleMounted (instance) {
225
+ this.sonInstances.push(instance)
226
+ },
227
+ handleSearchComplete ({ hasMatch, panelIndex }) {
228
+ if (hasMatch && !this.activeKey.includes(panelIndex.toString())) {
229
+ // 只展开包含搜索结果的面板
230
+ this.activeKey = [panelIndex.toString()]
231
+ }
232
+ },
233
+ getComponentName (componentName) {
234
+ return componentName
235
+ },
236
+ getPanelTitle (panel) {
237
+ // 兼容数据为纯对象数组(无 title 字段)时的显示
238
+ if (panel && panel.title) return panel.title
239
+ if (panel && panel.name) return panel.name
240
+ if (panel && panel.code) return panel.code
241
+ return ''
242
+ },
243
+ add (data) {
244
+ this.$emit('add', data)
245
+ },
246
+ deleteData (data) {
247
+ this.$emit('deleteData', data)
248
+ },
249
+ listClick (data) {
250
+ this.$emit('listClick', data)
251
+ },
252
+ click (data) {
253
+ this.$emit('click', data)
254
+ },
255
+ getConfigByName (componentName) {
256
+ const refKey = `dynamicComponent_${componentName}`
257
+ return this.$refs[refKey]
258
+ },
259
+ // xTreeRow 组件搜素功能
260
+ searchTreeRows (title) {
261
+ this.$nextTick(() => {
262
+ const instances = this.sonInstances
263
+ instances.forEach(comp => {
264
+ try {
265
+ comp.searchTitleToggle?.(title)
266
+ } catch (e) {
267
+ console.error('调用失败:', e)
268
+ }
269
+ })
270
+ })
271
+ },
272
+ async getData (config, parameter) {
273
+ this.configName = config
274
+ getConfigByName(config, 'af-his', res => {
275
+ // 合并配置,保留已有的 pagination 等开关
276
+ const original = this.config || {}
277
+ this.config = { ...original, ...res }
278
+ // 同步分页初值(仅当配置里提供时)
279
+ const p = this.config?.pagination || null
280
+ if (p && p.pageSize) this.paginationPageSize = Number(p.pageSize)
281
+ // 只在初始化时设置默认页码,避免每次重置
282
+ if (p && p.current && this.paginationCurrent === 1) {
283
+ this.paginationCurrent = Number(p.current)
284
+ }
285
+
286
+ // 组合请求参数,启用分页时传递页码与页大小
287
+ const baseParams = (parameter && Object.keys(parameter).length ? parameter : this.lastParams) || {}
288
+ this.lastParams = { ...baseParams }
289
+ const requestParams = { ...baseParams }
290
+ if (this.enablePagination) {
291
+ requestParams.page = this.paginationCurrent
292
+ requestParams.pageSize = this.paginationPageSize
293
+ }
294
+
295
+ runLogic(res.mainLogic, requestParams, 'af-his').then(result => {
296
+ let showData = []
297
+ let totalCount = 0
298
+
299
+ if (this.enablePagination) {
300
+ // 启用分页:后端固定返回 { total, data: [], page, pageSize }
301
+ showData = result.data
302
+ this.paginationTotal = Number(result.total) || 0
303
+ totalCount = this.paginationTotal
304
+ } else {
305
+ // 未启用分页:直接取数组
306
+ showData = Array.isArray(result && result.data) ? result.data : (Array.isArray(result) ? result : [])
307
+ totalCount = showData.length
308
+ }
309
+
310
+ // 赋值
311
+ this.$set(this.config, 'showData', showData)
312
+ this.$set(this.config, 'totalCount', Number(totalCount))
313
+
314
+ // 后端分页边界保护:当前页超界时回退到最后一页并重拉
315
+ if (this.enablePagination) {
316
+ const total = Number(this.config.totalCount || 0)
317
+ const size = Number(this.paginationPageSize || 1)
318
+ const maxPage = Math.max(1, Math.ceil(total / size))
319
+ if (this.paginationCurrent > maxPage) {
320
+ this.paginationCurrent = maxPage
321
+ this.getData(this.queryParamsName, this.parameter)
322
+ return
323
+ }
324
+ }
325
+
326
+ // 更具timeType更改时间类型
327
+ if (this.config.timeType && this.config.timeType === '.') {
328
+ this.config.showData.forEach(panel => {
329
+ // if (panel.title3) {
330
+ // panel.title3 = this.convertToCustomFormat(panel.title3)
331
+ // }
332
+ })
333
+ this.$forceUpdate()
334
+ }
335
+ // 根据配置决定是否展开面板
336
+ const shouldCollapseAll = this.config.collapseAllByDefault || false
337
+ if (shouldCollapseAll) {
338
+ // 如果配置为默认关闭,直接设置为空数组,避免展开动画
339
+ this.activeKey = []
340
+ } else {
341
+ // 默认展开当前页的所有面板
342
+ this.activeKey = (this.config.showData || []).map((_, i) => i.toString())
343
+ }
344
+ })
345
+ })
346
+ },
347
+ onPageChange (page) {
348
+ this.paginationCurrent = page
349
+ // 后端分页:重新拉数;前端分页:仅切片
350
+ this.getData(this.queryParamsName, this.lastParams)
351
+ },
352
+ goFirstPage () {
353
+ if (this.paginationCurrent === 1) return
354
+ this.onPageChange(1)
355
+ },
356
+ goLastPage () {
357
+ if (this.paginationCurrent === this.maxPage) return
358
+ this.onPageChange(this.maxPage)
359
+ },
360
+ refreshXCollapse () {
361
+ this.getData(this.queryParamsName, this.parameter)
362
+ },
363
+ convertToCustomFormat (dateString) {
364
+ // 创建一个新的 Date 对象
365
+ const date = new Date(dateString)
366
+ // 获取年、月、日
367
+ const year = date.getFullYear()
368
+ const month = date.getMonth() + 1 // 月份从0开始,所以需要加1
369
+ const day = date.getDate()
370
+ // 返回格式化后的字符串
371
+ return `${year}.${month}.${day}`
372
+ },
373
+ handleChange (keys) {
374
+ this.activeKey = keys
375
+ // console.log(this.activeKey)
376
+ },
377
+ onSearch (value, panelIndex) {
378
+ this.$emit('searchChange', { value: value, panelIndex: panelIndex })
379
+ },
380
+ handleSettingClick (panel, panelIndex) {
381
+ this.$emit('settingClick', { panel, panelIndex })
382
+ }
383
+ },
384
+ watch: {
385
+ queryParamsName: {
386
+ handler (newValue) {
387
+ this.getData(newValue, this.parameter)
388
+ },
389
+ deep: true
390
+ }
391
+ }
392
+ }
393
+ </script>
394
+
395
+ <style scoped lang="less">
396
+ .x-collapse-wrapper { position: relative; display: flex; flex-direction: column; min-height: 100%; height: 100%; }
397
+ .collapse-content-wrapper { flex: 1; min-height: 0; overflow: auto; position: relative; max-height: 78vh; }
398
+ .collapse-content-wrapper.with-pagination { padding-bottom: 0px; }
399
+ .header-content {
400
+ display: flex;
401
+ align-items: center;
402
+ justify-content: flex-start; // 左对齐,避免圆点被拉开
403
+ gap: 8px; // 圆点与标题的基础间距
404
+ white-space: nowrap;
405
+ overflow: hidden;
406
+ flex: 1; // 占满可用宽度,便于空间分配
407
+ }
408
+
409
+ .header-text {
410
+ margin-right: 14.17px;
411
+ font-size: 16px;
412
+ font-weight: 800;
413
+ flex-shrink: 0;
414
+ }
415
+
416
+ .info-item {
417
+ display: inline-flex;
418
+ align-items: center;
419
+ gap: 8px;
420
+ font-size: 12px;
421
+ color: #888888;
422
+ flex-shrink: 0;
423
+ }
424
+
425
+ .time-item {
426
+ margin-left: 12px;
427
+ text-align: right;
428
+ flex-shrink: 0;
429
+ }
430
+
431
+ :deep(.ant-collapse-header) {
432
+ display: flex;
433
+ position: relative;
434
+ // border-bottom: v-bind('config.showLine ? "1px solid #000000" : "none"');
435
+ align-items: center !important;
436
+ background-color: #ffffff;
437
+ padding: 12px 16px !important; /* 确保头部有足够的内边距 */
438
+ }
439
+
440
+ :deep(.ant-collapse-header-text) {
441
+ flex: 1;
442
+ }
443
+
444
+ :deep(.ant-collapse-content > .ant-collapse-content-box) {
445
+ padding: 16px !important; /* 确保内容区域有足够的内边距 */
446
+ }
447
+
448
+ .search-input {
449
+ margin-left: 12px;
450
+ width: auto;
451
+ max-width: 40%;
452
+ }
453
+
454
+ // 右侧块定位:首个 info-item 或 time-item 推到右侧
455
+ .header-content .info-item:first-of-type { margin-left: auto; }
456
+ .header-content .time-item:first-of-type { margin-left: auto; }
457
+
458
+ // 右侧块内部兄弟间距统一
459
+ .info-item + .info-item { margin-left: 12px; }
460
+ :deep(.ant-collapse-item-disabled > .ant-collapse-header) {
461
+ cursor: default !important;
462
+ }
463
+
464
+ /* 新增样式 */
465
+ .blue-circle-icon {
466
+ width: 12px;
467
+ height: 12px;
468
+ border-radius: 6px;
469
+ background: #3362DA;
470
+ margin-top: 15px;
471
+ margin-left: 11px;
472
+ margin-bottom: 12px;
473
+ flex-shrink: 0;
474
+ }
475
+
476
+ .setting-icon {
477
+ font-size: 16px;
478
+ cursor: pointer;
479
+ display: inline-flex;
480
+ align-items: center;
481
+ justify-content: center;
482
+ width: 19.47px;
483
+ height: 20px;
484
+ line-height: 20px;
485
+ vertical-align: middle;
486
+ color: #313131; /* 仅设置图标颜色,不设置背景 */
487
+ margin-top: 0; /* 去除向上偏移 */
488
+ margin-right: 47px; /* 与下拉箭头保持 20px 距离 */
489
+ }
490
+
491
+ :deep(.ant-collapse-extra) {
492
+ display: flex !important;
493
+ align-items: center;
494
+ }
495
+
496
+ .configurable-area {
497
+ //padding: 16px;
498
+ min-height: 100px;
499
+ border: 1px dashed #d9d9d9;
500
+ border-radius: 4px;
501
+ background-color: #fafafa;
502
+ }
503
+
504
+ .empty-hint {
505
+ color: #999;
506
+ text-align: center;
507
+ margin: 20px 0;
508
+ }
509
+
510
+ .loading-message {
511
+ text-align: center;
512
+ padding: 20px;
513
+ color: #666;
514
+ background: #f5f5f5;
515
+ border-radius: 4px;
516
+ margin: 10px 0;
517
+ }
518
+
519
+ .empty-state {
520
+ text-align: center;
521
+ padding: 40px 20px;
522
+ color: #999;
523
+ background: #fafafa;
524
+ border-radius: 4px;
525
+ margin: 10px 0;
526
+ flex: 1;
527
+ display: flex;
528
+ align-items: center;
529
+ justify-content: center;
530
+ }
531
+
532
+ /* 分页组件:固定在组件容器底部(不影响全局布局) */
533
+ .with-pagination { padding-bottom: 0; }
534
+ .xcollapse-pagination { /* 二盒子:自然流布局,不覆盖内容 */
535
+ position: static;
536
+ display: flex;
537
+ justify-content: center;
538
+ padding: 12px 0;
539
+ background: #fff;
540
+ border-top: 1px solid #f0f0f0;
541
+ }
542
+ .pagination-extras { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
543
+ .pagination-extras .ant-btn-group { gap: 8px; }
544
+ .pagination-extras .ant-btn-group + .pagination-info { margin-left: 9px; }
545
+ .pagination-info {
546
+ color: #5D5C5C;
547
+ font-family: 'Source Han Sans', sans-serif;
548
+ font-size: 16px;
549
+ font-weight: normal;
550
+ line-height: normal;
551
+ letter-spacing: 0em;
552
+ font-feature-settings: "kern" on;
553
+ }
554
+
555
+ /* 自定义分页按钮样式 */
556
+ :deep(.pagination-extras .ant-btn) {
557
+ font-family: 'Source Han Sans', sans-serif;
558
+ font-size: 16px;
559
+ font-weight: normal;
560
+ line-height: normal;
561
+ letter-spacing: 0em;
562
+ font-feature-settings: "kern" on;
563
+ color: #5D5C5C;
564
+ border-radius: 4px;
565
+ border: 1px solid #D8D8D8;
566
+ background: #FFFFFF;
567
+ box-sizing: border-box;
568
+ margin-right: 8px;
569
+ }
570
+
571
+ :deep(.pagination-extras .ant-btn:last-child) {
572
+ margin-right: 0;
573
+ }
574
+
575
+ /* 直达首页末页按钮样式 */
576
+ :deep(.pagination-extras .ant-btn[icon="vertical-left"]),
577
+ :deep(.pagination-extras .ant-btn[icon="vertical-right"]) {
578
+ position: static; /* 使用常规流布局,避免遮挡分页主体 */
579
+ width: 24px;
580
+ height: 24px;
581
+ border-radius: 4px;
582
+ opacity: 1;
583
+ background: #FFFFFF;
584
+ box-sizing: border-box;
585
+ border: 1px solid #D8D8D8;
586
+ margin-right: 8px;
587
+ }
588
+
589
+ /* 上一页下一页按钮样式 */
590
+ :deep(.ant-pagination .ant-pagination-prev),
591
+ :deep(.ant-pagination .ant-pagination-next) {
592
+ width: 24px;
593
+ height: 24px;
594
+ line-height: 24px;
595
+ border-radius: 4px;
596
+ opacity: 1;
597
+ background: #FFFFFF;
598
+ box-sizing: border-box;
599
+ border: 1px solid #D8D8D8;
600
+ }
601
+
602
+ /* 页码选择按钮样式 */
603
+ :deep(.ant-pagination .ant-pagination-item) {
604
+ width: 24px;
605
+ height: 24px;
606
+ border-radius: 4px;
607
+ border: 1px solid #D8D8D8;
608
+ background: #FFFFFF;
609
+ box-sizing: border-box;
610
+ font-family: 'Source Han Sans', sans-serif;
611
+ font-size: 16px;
612
+ font-weight: normal;
613
+ line-height: normal;
614
+ letter-spacing: 0em;
615
+ font-feature-settings: "kern" on;
616
+ color: #5D5C5C;
617
+ margin-right: 8px;
618
+ }
619
+
620
+ :deep(.ant-pagination .ant-pagination-item:last-child) {
621
+ margin-right: 0;
622
+ }
623
+
624
+ /* 当前页码样式 */
625
+ :deep(.ant-pagination .ant-pagination-item-active) {
626
+ background: #0057FE !important;
627
+ border: 1px solid #1890ff;
628
+ color: #FFFFFF !important;
629
+ }
630
+
631
+ /* 确保选中页码文字颜色生效 */
632
+ :deep(.ant-pagination .ant-pagination-item-active a) {
633
+ color: #FFFFFF !important;
634
+ }
635
+
636
+ /* 禁用状态样式 */
637
+ :deep(.pagination-extras .ant-btn:disabled) {
638
+ opacity: 0.5;
639
+ cursor: not-allowed;
640
+ }
641
+
642
+ /* 移除所有可能导致截断的固定高度 */
643
+ :deep(.ant-collapse-item) .ant-collapse-content .ant-collapse-content-box > * {
644
+ max-height: none !important; /* 移除可能的最大高度限制 */
645
+ height: auto !important; /* 使用自动高度 */
646
+ }
647
+
648
+ // 基于根容器类进行样式整合:x-collapse-wrapper.xcollapse-style1
649
+ .x-collapse-wrapper {
650
+ // 检查结果样式
651
+ &.xcollapse-check-result {
652
+ height: auto; /* 允许根据内容自适应高度,避免滚动被限制 */
653
+ min-height: 600px;
654
+ // 让每个面板成为独立卡片:去掉 antd 默认的分隔线,增加间距与圆角
655
+ :deep(.ant-collapse) {
656
+ background: transparent;
657
+ border: 0;
658
+ }
659
+
660
+ :deep(.ant-collapse > .ant-collapse-item) {
661
+ width: 555px;
662
+ min-height: auto;
663
+ height: auto;
664
+ margin-bottom:10px;
665
+ background: #FFFFFF; // 独立白底
666
+ box-sizing: border-box;
667
+ border: 1px solid #E5E9F0; // 每个面板自身边框
668
+ }
669
+
670
+ :deep(.ant-collapse > .ant-collapse-item:first-child) { margin-top: 0; }
671
+ :deep(.ant-collapse > .ant-collapse-item:last-child) { margin-bottom: 0; }
672
+
673
+ :deep(.ant-collapse-content > .ant-collapse-content-box) {
674
+ background: #FFFFFF;
675
+ padding: 0px !important;
676
+ }
677
+
678
+ // 表头:恢复合适的上下内边距,去掉顶部额外空白
679
+ :deep(.ant-collapse-header) {
680
+ background: #FFFFFF;
681
+ padding: 0px 0px !important;
682
+ height: 39px !important;
683
+ border-bottom: none !important; // 移除标题处下边线,避免与外边框连为一体
684
+ border: 1px solid #E5E9F0; // 每个面板自身边框
685
+ }
686
+
687
+ /* 将右侧留白转移到标题与第一项之间 */
688
+ .header-content { padding-right: 0px; gap: 5px; }
689
+ .header-content .info-item:first-of-type { margin-left: 24px !important; }
690
+ .header-content .time-item:first-of-type { margin-left: 24px !important; }
691
+
692
+ .info-item {
693
+ height: 20px;
694
+ opacity: 1;
695
+ font-family: "Source Han Sans";
696
+ font-size: 14px;
697
+ font-weight: 400;
698
+ line-height: 20px;
699
+ text-align: right;
700
+ letter-spacing: 0em;
701
+ font-feature-settings: "kern" on;
702
+ color: #313131 !important;
703
+ }
704
+
705
+ .header-text {
706
+ height: 23px;
707
+ opacity: 1;
708
+ font-family: "Source Han Sans";
709
+ font-size: 16px;
710
+ font-weight: 700;
711
+ line-height: 23px;
712
+ letter-spacing: 0em;
713
+ padding-right: 40px;
714
+ font-feature-settings: "kern" on;
715
+ color: #313131 !important;
716
+ }
717
+ }
718
+ // 历史病历样式
719
+ &.xcollapse-style1 {
720
+ height: auto; /* 允许根据内容自适应高度,避免滚动被限制 */
721
+ min-height: 600px;
722
+ .header-text {
723
+ font-family: "Source Han Sans";
724
+ font-size: 16px;
725
+ font-weight: 700;
726
+ line-height: 23px;
727
+ letter-spacing: 0em;
728
+ color: #313131;
729
+ margin-top: 8px;
730
+ margin-bottom: 8px;
731
+ margin-right: 0 !important;
732
+ }
733
+
734
+ .info-item {
735
+ font-family: "Source Han Sans";
736
+ font-size: 16px;
737
+ font-weight: 700;
738
+ line-height: 23px;
739
+ text-align: right;
740
+ color: #313131;
741
+ margin-top: 9px;
742
+ margin-bottom: 7px;
743
+ margin-left: 28.14px;
744
+ letter-spacing: 0em
745
+ }
746
+
747
+ .time-item {
748
+ font-family: "Source Han Sans";
749
+ font-size: 16px;
750
+ font-weight: 400;
751
+ line-height: 23px;
752
+ text-align: right;
753
+ margin-top: 9px;
754
+ margin-bottom: 7px;
755
+ color: #313131;
756
+ letter-spacing: 0em;
757
+ }
758
+
759
+ // 让每个面板成为独立卡片:去掉 antd 默认的分隔线,增加间距与圆角
760
+ :deep(.ant-collapse) {
761
+ background: transparent;
762
+ border: 0;
763
+ }
764
+
765
+ :deep(.ant-collapse > .ant-collapse-item) {
766
+ width: 555px;
767
+ min-height: auto;
768
+ height: auto;
769
+ margin-bottom:10px;
770
+ background: #FFFFFF; // 独立白底
771
+ box-sizing: border-box;
772
+ border: 1px solid #E5E9F0; // 每个面板自身边框
773
+ }
774
+
775
+ :deep(.ant-collapse > .ant-collapse-item:first-child) { margin-top: 0; }
776
+ :deep(.ant-collapse > .ant-collapse-item:last-child) { margin-bottom: 0; }
777
+
778
+ :deep(.ant-collapse-content > .ant-collapse-content-box) {
779
+ background: #FFFFFF;
780
+ padding: 0px !important;
781
+ }
782
+
783
+ // 表头:恢复合适的上下内边距,去掉顶部额外空白
784
+ :deep(.ant-collapse-header) {
785
+ background: #FFFFFF;
786
+ padding: 0px 0px !important;
787
+ height: 41px !important;
788
+ border-bottom: none !important; // 移除标题处下边线,避免与外边框连为一体
789
+ border: 1px solid #E5E9F0; // 每个面板自身边框
790
+ }
791
+ }
792
+
793
+ // 医学词条样式
794
+ &.xcollapse-medical-entry {
795
+ height: auto;
796
+ min-height: 600px;
797
+ :deep(.ant-collapse) { background: transparent; border: 0; }
798
+ :deep(.ant-collapse > .ant-collapse-item) {
799
+ width: 564px;
800
+ min-height: auto;
801
+ height: auto;
802
+ margin-bottom: 14px;
803
+ background: #FFFFFF;
804
+ box-sizing: border-box;
805
+ border: 1px solid #E5E9F0;
806
+ }
807
+ :deep(.ant-collapse > .ant-collapse-item:first-child) { margin-top: 0; }
808
+ :deep(.ant-collapse > .ant-collapse-item:last-child) { margin-bottom: 0; }
809
+ :deep(.ant-collapse-content > .ant-collapse-content-box) { background: #FFFFFF; padding: 0px !important; }
810
+ :deep(.ant-collapse-header) {
811
+ background: #FFFFFF;
812
+ padding: 0px 0px !important;
813
+ height: 39px !important;
814
+ border-bottom: none !important;
815
+ border: 1px solid #E5E9F0;
816
+ }
817
+ .header-text {
818
+ font-family: "Source Han Sans";
819
+ font-size: 16px;
820
+ font-weight: 700;
821
+ line-height: 23px;
822
+ letter-spacing: 0em;
823
+ color: #313131;
824
+ margin-top: 7px;
825
+ margin-bottom: 7px;
826
+ margin-right: 0 !important;
827
+ }
828
+ }
829
+ }
830
+ </style>