vue2-client 1.18.32 → 1.18.33

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 (105) hide show
  1. package/.eslintrc.js +90 -90
  2. package/Components.md +60 -60
  3. package/docs/index.md +30 -30
  4. package/index.js +31 -31
  5. package/jest-transform-stub.js +8 -8
  6. package/jest.setup.js +7 -7
  7. package/package.json +1 -1
  8. package/src/assets/img/querySlotDemo.svg +15 -15
  9. package/src/assets/svg/female.svg +1 -1
  10. package/src/assets/svg/male.svg +1 -1
  11. package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
  12. package/src/base-client/components/common/CitySelect/index.js +3 -3
  13. package/src/base-client/components/common/CitySelect/index.md +109 -109
  14. package/src/base-client/components/common/CreateQuery/CreateQuery.vue +669 -669
  15. package/src/base-client/components/common/CreateQuery/index.js +3 -3
  16. package/src/base-client/components/common/CreateQuery/index.md +42 -42
  17. package/src/base-client/components/common/CreateSimpleFormQuery/index.js +3 -3
  18. package/src/base-client/components/common/CreateSimpleFormQuery/index.md +42 -42
  19. package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
  20. package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
  21. package/src/base-client/components/common/FormGroupQuery/FormGroupQuery.vue +166 -166
  22. package/src/base-client/components/common/FormGroupQuery/index.js +3 -3
  23. package/src/base-client/components/common/FormGroupQuery/index.md +43 -43
  24. package/src/base-client/components/common/HIS/HFormGroup/index.js +3 -3
  25. package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
  26. package/src/base-client/components/common/PersonSetting/PersonSetting.vue +208 -208
  27. package/src/base-client/components/common/PersonSetting/index.js +3 -3
  28. package/src/base-client/components/common/Tree/Tree.vue +149 -149
  29. package/src/base-client/components/common/Tree/index.js +2 -2
  30. package/src/base-client/components/common/Upload/index.js +3 -3
  31. package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
  32. package/src/base-client/components/common/XCard/XCard.vue +64 -64
  33. package/src/base-client/components/common/XCollapse/XCollapse.vue +830 -830
  34. package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
  35. package/src/base-client/components/common/XDataDrawer/index.js +3 -3
  36. package/src/base-client/components/common/XDataDrawer/index.md +41 -41
  37. package/src/base-client/components/common/XDescriptions/index.js +3 -3
  38. package/src/base-client/components/common/XDescriptions/index.md +322 -322
  39. package/src/base-client/components/common/XForm/index.md +178 -178
  40. package/src/base-client/components/common/XReportGrid/XReportTrGroup.vue +6 -3
  41. package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
  42. package/src/base-client/components/common/XStepView/index.js +3 -3
  43. package/src/base-client/components/common/XStepView/index.md +31 -31
  44. package/src/base-client/components/common/XTable/XTable.vue +1715 -1715
  45. package/src/base-client/components/common/XTable/index.md +255 -255
  46. package/src/base-client/components/common/XTimeline/XTimeline.vue +477 -477
  47. package/src/base-client/components/his/XHisEditor/XHisEditor.vue +705 -705
  48. package/src/base-client/components/his/XList/XList.vue +938 -938
  49. package/src/base-client/components/his/XSimpleTable/XSimpleTable.vue +443 -44
  50. package/src/base-client/components/his/XTimeSelect/XTimeSelect.vue +354 -354
  51. package/src/base-client/components/his/XTitle/XTitle.vue +314 -314
  52. package/src/base-client/components/his/XTreeRows/XTreeRows.vue +341 -341
  53. package/src/base-client/components/his/threeTestOrders/editor.vue +113 -113
  54. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
  55. package/src/base-client/plugins/Config.js +19 -19
  56. package/src/base-client/plugins/tabs-page-plugin.js +39 -39
  57. package/src/components/Charts/Bar.vue +62 -62
  58. package/src/components/Charts/ChartCard.vue +134 -134
  59. package/src/components/Charts/Liquid.vue +67 -67
  60. package/src/components/Charts/MiniArea.vue +39 -39
  61. package/src/components/Charts/MiniBar.vue +39 -39
  62. package/src/components/Charts/MiniProgress.vue +75 -75
  63. package/src/components/Charts/MiniSmoothArea.vue +40 -40
  64. package/src/components/Charts/Radar.vue +68 -68
  65. package/src/components/Charts/RankList.vue +77 -77
  66. package/src/components/Charts/TagCloud.vue +113 -113
  67. package/src/components/Charts/TransferBar.vue +64 -64
  68. package/src/components/Charts/Trend.vue +82 -82
  69. package/src/components/Charts/chart.less +12 -12
  70. package/src/components/Charts/smooth.area.less +13 -13
  71. package/src/components/NumberInfo/NumberInfo.vue +54 -54
  72. package/src/components/NumberInfo/index.js +3 -3
  73. package/src/components/NumberInfo/index.less +54 -54
  74. package/src/components/NumberInfo/index.md +43 -43
  75. package/src/components/card/ChartCard.vue +79 -79
  76. package/src/components/chart/Bar.vue +60 -60
  77. package/src/components/chart/MiniArea.vue +67 -67
  78. package/src/components/chart/MiniBar.vue +59 -59
  79. package/src/components/chart/MiniProgress.vue +57 -57
  80. package/src/components/chart/Radar.vue +80 -80
  81. package/src/components/chart/RankingList.vue +60 -60
  82. package/src/components/chart/Trend.vue +79 -79
  83. package/src/components/chart/index.less +9 -9
  84. package/src/components/checkbox/ColorCheckbox.vue +157 -157
  85. package/src/components/input/IInput.vue +66 -66
  86. package/src/components/menu/SideMenu.vue +75 -75
  87. package/src/components/menu/menu.js +273 -273
  88. package/src/components/tool/AStepItem.vue +60 -60
  89. package/src/layouts/CommonLayout.vue +56 -56
  90. package/src/layouts/header/HeaderNotice.vue +177 -177
  91. package/src/lib.js +1 -1
  92. package/src/mock/extend/index.js +84 -84
  93. package/src/mock/goods/index.js +108 -108
  94. package/src/pages/dashboard/workplace/WorkPlace.vue +141 -141
  95. package/src/pages/system/dictionary/index.vue +44 -44
  96. package/src/pages/system/monitor/loginInfor/index.vue +37 -37
  97. package/src/pages/system/monitor/operLog/index.vue +37 -37
  98. package/src/pages/userInfoDetailManage/ExceptionRecordQuery/index.vue +45 -45
  99. package/src/services/api/cas.js +79 -79
  100. package/src/store/modules/setting.js +119 -119
  101. package/src/utils/authority-utils.js +85 -85
  102. package/src/utils/errorCode.js +6 -6
  103. package/src-base-client/components/common/HIS/HForm/HForm.vue +347 -0
  104. package/src-base-client/components/common/XCollapse/XCollapse.vue +0 -0
  105. package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
@@ -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>