vue2-client 1.16.38 → 1.16.39

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-client",
3
- "version": "1.16.38",
3
+ "version": "1.16.39",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --no-eslint",
@@ -287,8 +287,6 @@ defineExpose({
287
287
  // button25样式 用于会诊申请侧边栏按钮样式
288
288
  &.h-buttons-button25 {
289
289
  :deep(.x-buttons) {
290
- margin: -20px 3px -20px 3px;
291
-
292
290
  .ant-btn-group {
293
291
  width: 173px;
294
292
  justify-content: space-between;
@@ -328,8 +328,11 @@ export default {
328
328
  value = config.data[cell.dataIndex]
329
329
  }
330
330
 
331
- // 检查值是否为空
332
- if (!value || (typeof value === 'string' && value.trim() === '')) {
331
+ // 检查值是否为空(允许 0 和 false)
332
+ const isEmptyString = typeof value === 'string' && value.trim() === ''
333
+ const isEmptyArray = Array.isArray(value) && value.length === 0
334
+ const isNullish = value === null || value === undefined
335
+ if (isNullish || isEmptyString || isEmptyArray) {
333
336
  const message = cell.requiredMessage || this.getDefaultRequiredMessage(cell.type)
334
337
  errors.push({
335
338
  dataIndex: cell.dataIndex,
@@ -819,12 +822,18 @@ export default {
819
822
  this.getConfigAndJoin(this.config, lock)
820
823
 
821
824
  // 用定时器循环查看锁状态
825
+ // 先清理可能存在的旧轮询,避免重复打印与重复初始化
826
+ if (this.timer) {
827
+ clearInterval(this.timer)
828
+ this.timer = undefined
829
+ }
822
830
  this.timer = setInterval(() => {
823
831
  if (!lock.status) {
824
832
  clearInterval(this.timer)
833
+ this.timer = undefined
825
834
  console.log('拼接完成', this.config)
826
835
  // 将初始化好的配置拷贝一份留存
827
- this.originalConfig = Object.assign({}, this.config)
836
+ this.originalConfig = JSON.parse(JSON.stringify(this.config))
828
837
  if (!this.dontFormat) {
829
838
  // 扫描配置文件中有没有rowSpan,进行格式化调整
830
839
  this.formatConfigRow(this.config)
@@ -864,8 +873,8 @@ export default {
864
873
  if (this.configData === undefined) {
865
874
  console.error('未找到数据!')
866
875
  } else {
867
- this.originalConfig = Object.assign({}, this.config)
868
- this.originalConfig.data = Object.assign(this.originalConfig.data, JSON.parse(JSON.stringify(this.configData)))
876
+ this.originalConfig = JSON.parse(JSON.stringify(this.config))
877
+ this.originalConfig.data = Object.assign({}, this.originalConfig.data, JSON.parse(JSON.stringify(this.configData)))
869
878
  this.type = 'display'
870
879
  // this.onlyDisplay = true
871
880
  this.showSkeleton = false
@@ -879,12 +888,12 @@ export default {
879
888
  this.config = res
880
889
  if (this.config.designMode === 'json') {
881
890
  if (this.configData !== undefined) {
882
- this.config.data = Object.assign({}, this.config.data, this.configData)
891
+ this.config.data = Object.assign({}, this.config.data, JSON.parse(JSON.stringify(this.configData)))
883
892
  }
884
893
  this.jsonConfigInit()
885
894
  } else {
886
895
  if (this.configData !== undefined) {
887
- this.config.data = Object.assign(this.config.data, this.configData)
896
+ this.config.data = Object.assign({}, this.config.data, JSON.parse(JSON.stringify(this.configData)))
888
897
  }
889
898
  if (this.config.data.images === undefined) {
890
899
  this.config.data.images = {}
@@ -917,14 +926,14 @@ export default {
917
926
  if (this.localConfig.designMode === 'json') {
918
927
  this.config = this.localConfig
919
928
  if (this.configData !== undefined) {
920
- this.config.data = Object.assign(this.config.data, this.configData)
929
+ this.config.data = Object.assign({}, this.config.data, JSON.parse(JSON.stringify(this.configData)))
921
930
  }
922
931
  this.jsonConfigInit()
923
932
  } else {
924
933
  // 如果配置是普通渲染器
925
934
  this.config = this.localConfig
926
935
  if (this.configData !== undefined) {
927
- this.config.data = Object.assign(this.config.data, this.configData)
936
+ this.config.data = Object.assign({}, this.config.data, JSON.parse(JSON.stringify(this.configData)))
928
937
  }
929
938
  if (this.config.data.images === undefined) {
930
939
  this.config.data.images = {}
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <div id="xreport-hosp-demo">
3
+ <a-space style="margin-bottom: 12px;">
4
+ <a-button type="primary" @click="doInit">手动初始化</a-button>
5
+ </a-space>
6
+ <XReport
7
+ ref="reportRef"
8
+ :edit-mode="true"
9
+ :show-save-button="true"
10
+ :show-img-in-cell="false"
11
+ :use-oss-for-img="false"
12
+ server-name="af-his"
13
+ @updateImg="onUpdateImg"/>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup>
18
+ import { ref } from 'vue'
19
+ import XReport from '@vue2-client/base-client/components/common/XReport'
20
+
21
+ const reportRef = ref(null)
22
+
23
+ const payload = {
24
+ arr: [
25
+ { BQ: '病房区', RY: 0, CY: 0, CW: 0, SW: 0, SS: 0, ZC: 0, ZR: 0, ZY: 0 },
26
+ { BQ: '感染科', RY: 0, CY: 0, CW: 0, SW: 0, SS: 0, ZC: 0, ZR: 0, ZY: 0 },
27
+ { BQ: '骨科病区', RY: 0, CY: 0, CW: 0, SW: 0, SS: 0, ZC: 0, ZR: 0, ZY: 0 },
28
+ { BQ: '呼吸科病区', RY: 0, CY: 0, CW: 0, SW: 0, SS: 0, ZC: 0, ZR: 0, ZY: 0 },
29
+ { BQ: '急症科病区', RY: 0, CY: 0, CW: 0, SW: 0, SS: 0, ZC: 0, ZR: 0, ZY: 0 },
30
+ { BQ: '内科二病区', RY: 0, CY: 0, CW: 0, SW: 0, SS: 0, ZC: 0, ZR: 0, ZY: 0 }
31
+ ]
32
+ }
33
+
34
+ const doInit = async () => {
35
+ if (!reportRef.value || !reportRef.value.init) return
36
+ await reportRef.value.init({
37
+ configName: 'hospitalizationStatsReport',
38
+ configData: payload
39
+ })
40
+ }
41
+
42
+ const onUpdateImg = data => {
43
+ console.warn('updateImg:', data)
44
+ }
45
+ </script>
@@ -0,0 +1,149 @@
1
+ // 测试配置 - 用于演示混合支付功能
2
+ export const testChargeConfig = {
3
+ "amountFields": [
4
+ {
5
+ "field": 'f_amount',
6
+ "disabled": false,
7
+ "label": '费用总额'
8
+ },
9
+ {
10
+ "field": 'f_insurance_amount',
11
+ "disabled": true,
12
+ "label": '医保支付'
13
+ },
14
+ {
15
+ "field": 'f_self_amount',
16
+ "disabled": true,
17
+ "label": '自费金额'
18
+ },
19
+ {
20
+ "field": 'out_of_pocket_amount',
21
+ "disabled": true,
22
+ "label": '自付金额'
23
+ },
24
+ {
25
+ "field": 'biscount_amount',
26
+ "disabled": true,
27
+ "label": '折扣金额'
28
+ },
29
+ {
30
+ "field": 'billing_amount',
31
+ "disabled": true,
32
+ "label": '记账金额'
33
+ }
34
+ ],
35
+ "paymentMethods": [
36
+ {
37
+ "key": '医保卡',
38
+ "label": '医保卡'
39
+ },
40
+ {
41
+ "key": '微信/支付宝',
42
+ "label": '微信/支付宝'
43
+ },
44
+ {
45
+ "key": '银行卡',
46
+ "label": '银行卡'
47
+ },
48
+ {
49
+ "key": '现金',
50
+ "label": '现金'
51
+ }
52
+ ],
53
+ "bottomFields": [
54
+ {
55
+ "field": 'f_balance',
56
+ "label": '账户余额',
57
+ "disabled": false
58
+ },
59
+ {
60
+ "field": 'received',
61
+ "label": '实收',
62
+ "disabled": false
63
+ },
64
+ {
65
+ "field": 'change',
66
+ "label": '找零',
67
+ "disabled": false
68
+ }
69
+ ],
70
+ "actionButtons": [
71
+ {
72
+ "key": 'charge',
73
+ "label": '收费',
74
+ "icon": 'check'
75
+ },
76
+ {
77
+ "key": 'refund',
78
+ "label": '退费',
79
+ "icon": 'undo'
80
+ },
81
+ {
82
+ "key": 'print',
83
+ "label": '打印',
84
+ "icon": 'printer'
85
+ }
86
+ ],
87
+ "enableMixedPayment": true, // 启用混合支付
88
+ // 可配置事件名,参考 fronImport 风格
89
+ "eventNames": {
90
+ "method": 'method',
91
+ "methods": 'methods',
92
+ "totalPaymentAmount": 'totalPaymentAmount',
93
+ "action": 'action'
94
+ },
95
+ "dataSourceConfig": 'testChargeLogic'
96
+ }
97
+
98
+ // 单选模式测试配置
99
+ export const testSingleChargeConfig = {
100
+ "amountFields": [
101
+ {
102
+ "field": 'f_amount',
103
+ "disabled": false,
104
+ "label": '费用总额'
105
+ },
106
+ {
107
+ "field": 'f_insurance_amount',
108
+ "disabled": true,
109
+ "label": '医保支付'
110
+ }
111
+ ],
112
+ "paymentMethods": [
113
+ {
114
+ "key": '医保卡',
115
+ "label": '医保卡'
116
+ },
117
+ {
118
+ "key": '现金',
119
+ "label": '现金'
120
+ }
121
+ ],
122
+ "bottomFields": [
123
+ {
124
+ "field": 'received',
125
+ "label": '实收',
126
+ "disabled": false
127
+ },
128
+ {
129
+ "field": 'change',
130
+ "label": '找零',
131
+ "disabled": false
132
+ }
133
+ ],
134
+ "actionButtons": [
135
+ {
136
+ "key": 'charge',
137
+ "label": '收费',
138
+ "icon": 'check'
139
+ }
140
+ ],
141
+ "enableMixedPayment": false, // 禁用混合支付(单选模式)
142
+ "eventNames": {
143
+ "method": 'method',
144
+ "methods": 'methods',
145
+ "totalPaymentAmount": 'totalPaymentAmount',
146
+ "action": 'action'
147
+ },
148
+ "dataSourceConfig": 'testChargeLogic'
149
+ }
@@ -1,23 +1,23 @@
1
1
  <template>
2
- <div class="patient-info-descriptions">
2
+ <div class="patient-info-descriptions" :class="wrapperClassObject">
3
3
  <div class="descriptions-container">
4
4
  <!-- 详情/收起按钮 -->
5
5
  <div v-if="hasMoreItems" class="detail-button-wrapper">
6
6
  <a-button
7
- :type="config?.detailsConfig?.buttonType || 'link'"
7
+ :type="(config && config.detailsConfig && config.detailsConfig.buttonType) || 'link'"
8
8
  @click="toggleDetails"
9
9
  >
10
10
  <a-icon :type="showAllItems ? 'up' : 'down'" />
11
- {{ showAllItems ? '收起' : (config?.detailsConfig?.buttonText || '详情') }}
11
+ {{ showAllItems ? '收起' : ((config && config.detailsConfig && config.detailsConfig.buttonText) || '详情') }}
12
12
  </a-button>
13
13
  </div>
14
14
 
15
15
  <!-- 当有 layout 配置时使用 a-descriptions -->
16
- <template v-if="config?.layout">
16
+ <template v-if="config && config.layout">
17
17
  <a-descriptions
18
18
  :column="config.layout"
19
- :size="config?.style?.size"
20
- :bordered="config?.style?.bordered"
19
+ :size="(config && config.style && config.style.size)"
20
+ :bordered="(config && config.style && config.style.bordered)"
21
21
  layout="horizontal">
22
22
  <template v-if="data">
23
23
  <!-- 显示前N个标签 -->
@@ -151,14 +151,34 @@ export default {
151
151
  }
152
152
  },
153
153
  computed: {
154
+ // 动态样式开关(与 HForm 思路一致):布尔开关 + size 派生类
155
+ wrapperClassObject () {
156
+ const attrs = this.$attrs || {}
157
+ const classes = {}
158
+
159
+ const booleanStyleKeys = [
160
+ 'query-conditions',
161
+ 'padding-50',
162
+ 'label-text-horizontal',
163
+ 'description'
164
+ ]
165
+ booleanStyleKeys.forEach(key => {
166
+ const val = attrs[key]
167
+ const truthy = val === true || val === '' || val === 'true'
168
+ if (truthy) classes[`xhdesc-${key}`] = true
169
+ })
170
+ const size = attrs.size
171
+ if (size && typeof size === 'string') classes[`xhdesc-size-${size}`] = true
172
+ return classes
173
+ },
154
174
  // 获取详情按钮应该显示在第几个标签后
155
175
  detailsAfterIndex () {
156
- return this.config?.detailsConfig?.showAfterIndex || 999
176
+ return (this.config && this.config.detailsConfig && this.config.detailsConfig.showAfterIndex) || 999
157
177
  },
158
178
  // 判断是否有更多标签需要显示
159
179
  hasMoreItems () {
160
- if (!this.config?.detailsConfig) return false
161
- if (!this.data || !this.config?.items || !Array.isArray(this.config.items)) return false
180
+ if (!(this.config && this.config.detailsConfig)) return false
181
+ if (!this.data || !(this.config && this.config.items) || !Array.isArray(this.config.items)) return false
162
182
  const hiddenStartIndex = this.detailsAfterIndex || 0
163
183
  if (hiddenStartIndex >= this.config.items.length) return false
164
184
  for (let i = hiddenStartIndex; i < this.config.items.length; i++) {
@@ -171,15 +191,15 @@ export default {
171
191
  },
172
192
  // 获取应该显示的标签
173
193
  visibleItems () {
174
- if (!this.config?.items) return []
175
- if (!this.config?.detailsConfig) return this.config.items
194
+ if (!(this.config && this.config.items)) return []
195
+ if (!(this.config && this.config.detailsConfig)) return this.config.items
176
196
  if (this.showAllItems) return this.config.items.slice(0, this.detailsAfterIndex)
177
197
  return this.config.items.slice(0, this.detailsAfterIndex)
178
198
  },
179
199
  // 获取隐藏的标签(保持原有逻辑)
180
200
  hiddenItems () {
181
- if (!this.config?.items) return []
182
- if (!this.config?.detailsConfig) return []
201
+ if (!(this.config && this.config.items)) return []
202
+ if (!(this.config && this.config.detailsConfig)) return []
183
203
  return this.config.items.slice(this.detailsAfterIndex)
184
204
  }
185
205
  },
@@ -192,7 +212,7 @@ export default {
192
212
  this.showAllItems = false
193
213
  getConfigByName(data, 'af-his', res => {
194
214
  this.config = res
195
- const hiddenConfig = this.config?.hiddenConfig ?? 0 === 1
215
+ const hiddenConfig = (this.config && this.config.hiddenConfig) || (0 === 1)
196
216
  const parameter = { ...res.parameter, ...this.parameter, ...parameterData }
197
217
  runLogic(res.logicName, parameter, 'af-his').then(result => {
198
218
  if (hiddenConfig) {
@@ -272,7 +292,7 @@ export default {
272
292
  align-items: center;
273
293
  gap: 8px;
274
294
  color: rgba(0, 0, 0, 0.65);
275
- font-size: v-bind('config?.style?.fontSize');
295
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
276
296
  white-space: nowrap;
277
297
  }
278
298
 
@@ -288,7 +308,7 @@ export default {
288
308
  display: inline-flex;
289
309
  align-items: center;
290
310
  margin-left: 4px;
291
- font-size: v-bind('config?.style?.fontSize');
311
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
292
312
  color: rgba(0, 0, 0, 0.85);
293
313
  max-width: 300px;
294
314
  overflow: hidden;
@@ -336,17 +356,17 @@ export default {
336
356
  color: rgba(0, 0, 0, 0.65);
337
357
  padding: 0 !important;
338
358
  margin: 0 !important;
339
- font-size: v-bind('config?.style?.fontSize || "14px"');
359
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
340
360
  display: inline-flex !important;
341
361
  align-items: center !important;
342
362
  white-space: nowrap !important;
343
- min-width: v-bind('config?.style?.labelWidth || "80px"');
363
+ min-width: v-bind('(config && config.style && config.style.labelWidth) || "80px"');
344
364
  justify-content: flex-start;
345
365
  padding-right: 2px !important;
346
366
  }
347
367
 
348
368
  :deep(.ant-descriptions-item-content) {
349
- font-size: v-bind('config?.style?.fontSize || "14px"');
369
+ font-size: v-bind('(config && config.style && config.style.fontSize) || "14px"');
350
370
  display: inline-flex !important;
351
371
  align-items: center !important;
352
372
  padding: 0 !important;
@@ -426,4 +446,26 @@ export default {
426
446
  height: 0;
427
447
  border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
428
448
  }
449
+ /* 加边框 */
450
+ .xhdesc-description {
451
+ padding: 4px 4px 4px 4px;
452
+
453
+ /* 作用域内 *patient-info-descriptions */
454
+ &.patient-info-descriptions,
455
+ .patient-info-descriptions {
456
+ border: 1px solid #E5E9F0;
457
+ border-radius: 6px;
458
+ padding: 6.5px 12px;
459
+
460
+ /* *ant-btn-link */
461
+ :deep(.ant-btn-link) {
462
+ border: none;
463
+ }
464
+
465
+ /* *ant-descriptions-item-content */
466
+ :deep(.ant-descriptions-item-content) {
467
+ font-weight: bold;
468
+ }
469
+ }
470
+ }
429
471
  </style>
@@ -1,15 +1,16 @@
1
1
  <template>
2
2
  <!-- 列表卡片模式 listMode: card -->
3
3
  <div
4
+ class="x-list-wrapper"
5
+ :class="wrapperClassObject"
4
6
  v-if="listMode"
5
- class="demo-infinite-container"
6
7
  ref="listRef"
7
8
  @scroll="handleInfiniteOnLoad">
8
9
  <a-list
9
10
  :grid="{ gutter: 16, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 4 }"
10
11
  :data-source="localData">
11
12
  <a-list-item slot="renderItem" slot-scope="item, index">
12
- <div class="card-a-col">
13
+ <div class="card-a-col" :class="{ 'selected-active': enableSelectRow && currentSelectedIndex === index }" @click="handleCardClick(index)">
13
14
  <a-row class="card-row">
14
15
  <a-col class="id-a-col" :span="4" v-for="(detail,idx) in item.filter(d => d.label == label)" :key="idx">
15
16
  {{ detail.value }}<span style="font-size: 16px;font-weight: 400 !important;">床</span>
@@ -59,7 +60,7 @@
59
60
  </div>
60
61
 
61
62
  <!-- 默认标签模式 -->
62
- <div class="list-wrapper" v-else>
63
+ <div class="list-wrapper x-list-wrapper" :class="wrapperClassObject" v-else>
63
64
  <a-list size="large" :data-source="data" itemLayout="horizontal" class="list-container" ref="listRef">
64
65
  <a-list-item
65
66
  slot="renderItem"
@@ -68,7 +69,7 @@
68
69
  @click="handleClick(index)"
69
70
  @mouseenter="enableHoverOptions && handleMouseEnter(index)"
70
71
  @mouseleave="handleMouseLeave"
71
- :class="{ 'hover-active': enableHoverOptions && hoveredIndex === index }">
72
+ :class="{ 'hover-active': enableHoverOptions && hoveredIndex === index, 'selected-active': enableSelectRow && currentSelectedIndex === index }">
72
73
  <i
73
74
  v-if="icon"
74
75
  class="icon-menu"
@@ -143,6 +144,16 @@ export default {
143
144
  serviceName: {
144
145
  type: String,
145
146
  default: 'af-his'
147
+ },
148
+ // 点击是否触发选中(默认不通过点击选中,仅手动控制)
149
+ selectOnClick: {
150
+ type: Boolean,
151
+ default: false
152
+ },
153
+ // 受控选中索引;不传则内部维护
154
+ selectedIndex: {
155
+ type: Number,
156
+ default: undefined
146
157
  }
147
158
  },
148
159
  inject: ['getComponentByName'],
@@ -167,7 +178,9 @@ export default {
167
178
  pageSize: 12,
168
179
  allLoaded: false,
169
180
  label: 'id',
170
- scrollTimer: null
181
+ scrollTimer: null,
182
+ // 内部选中索引(非受控时使用)
183
+ localSelectedIndex: -1
171
184
  }
172
185
  },
173
186
  created () {
@@ -175,6 +188,30 @@ export default {
175
188
  },
176
189
  mounted () {},
177
190
  computed: {
191
+ // 参考 HForm 的 wrapperClassObject 规则,支持通过组件属性动态控制样式
192
+ wrapperClassObject () {
193
+ const a = this.$attrs || {}
194
+ const classes = {}
195
+ // 多个布尔型样式开关(存在且为真则生效)
196
+ const booleanStyleKeys = [
197
+ ''
198
+ ]
199
+ booleanStyleKeys.forEach(key => {
200
+ const val = a[key]
201
+ const truthy = val === true || val === '' || val === 'true'
202
+ if (truthy) classes[`x-list-${key}`] = true
203
+ })
204
+ return classes
205
+ },
206
+ // 选择控制:受控优先
207
+ currentSelectedIndex () {
208
+ return typeof this.selectedIndex === 'number' ? this.selectedIndex : this.localSelectedIndex
209
+ },
210
+ enableSelectRow () {
211
+ const a = this.$attrs || {}
212
+ const val = a.enableSelection
213
+ return val === true || val === '' || val === 'true'
214
+ },
178
215
  forwardAllEvents () {
179
216
  return {
180
217
  // 监听所有事件并转发给父组件
@@ -239,14 +276,62 @@ export default {
239
276
  },
240
277
  // 点击列表项
241
278
  handleClick (index) {
279
+ if (this.enableSelectRow && this.selectOnClick) this.setSelectedIndex(index)
242
280
  this.$emit('listClick', this.data[index])
243
281
  },
282
+ // 卡片模式点击卡片
283
+ handleCardClick (index) {
284
+ if (this.enableSelectRow && this.selectOnClick) this.setSelectedIndex(index)
285
+ this.$emit('listClick', this.localData[index])
286
+ },
287
+ // 外部可调用:设置选中索引
288
+ setSelectedIndex (index) {
289
+ const next = typeof index === 'number' ? index : -1
290
+ if (typeof this.selectedIndex === 'number') {
291
+ // 受控:仅派发事件
292
+ this.$emit('update:selectedIndex', next)
293
+ } else {
294
+ // 非受控:更新内部并派发事件
295
+ this.localSelectedIndex = next
296
+ this.$emit('update:selectedIndex', next)
297
+ }
298
+ },
299
+ // 外部可调用:清空选中
300
+ clearSelected () { this.setSelectedIndex(-1) },
244
301
  refreshList (param) {
245
302
  this.getData(this.queryParamsName, param)
246
303
  },
247
304
  click (index, buttonIndex) {
248
305
  this.$emit('click', { data: this.data[index], name: this.buttonNames[buttonIndex] })
249
306
  },
307
+ // 根据对象字段匹配选中(默认按 id 字段)
308
+ setSelectedById (id, field = 'id') {
309
+ const list = this.listMode ? this.localData : this.data
310
+ if (!Array.isArray(list)) return
311
+ const index = list.findIndex(item => {
312
+ if (Array.isArray(item)) {
313
+ const f = item.find(d => d && d.label === field)
314
+ return f && f.value === id
315
+ }
316
+ return item && item[field] === id
317
+ })
318
+ if (index >= 0) this.setSelectedIndex(index)
319
+ },
320
+ // 根据 label/value(卡片数组数据场景)匹配选中
321
+ setSelectedByLabelValue (label, value) {
322
+ const list = this.listMode ? this.localData : this.data
323
+ if (!Array.isArray(list)) return
324
+ const index = list.findIndex(item => Array.isArray(item) && item.some(d => d && d.label === label && d.value === value))
325
+ if (index >= 0) this.setSelectedIndex(index)
326
+ },
327
+ // 通用:传入谓词函数决定选中项
328
+ setSelectedBy (predicate) {
329
+ if (typeof predicate !== 'function') return
330
+ const list = this.listMode ? this.localData : this.data
331
+ if (!Array.isArray(list)) return
332
+ const index = list.findIndex(predicate)
333
+ if (index >= 0) this.setSelectedIndex(index)
334
+ },
250
335
  getIconStyle (item) {
251
336
  return item.picture
252
337
  ? { backgroundImage: `url(${item.picture})` }
@@ -301,6 +386,13 @@ export default {
301
386
  }
302
387
  },
303
388
  watch: {
389
+ // 同步受控值变化
390
+ selectedIndex (val) {
391
+ if (typeof val === 'number') {
392
+ // 允许受控值影响内部显示
393
+ this.localSelectedIndex = val
394
+ }
395
+ },
304
396
  fixedQueryForm: {
305
397
  deep: true,
306
398
  handler (val) {
@@ -400,6 +492,26 @@ export default {
400
492
  border: 1px solid black;
401
493
  }
402
494
 
495
+ /* 选中态样式(通过 selectRow 开启) */
496
+ .selected-active { color: white; }
497
+ .list-item.selected-active {
498
+ background-color: #0057FE !important;
499
+ color: white;
500
+ border: none !important;
501
+ }
502
+ .list-item.selected-active .confirm-btn,
503
+ .list-item.selected-active .confirm-btn span,
504
+ .list-item.selected-active .ant-btn,
505
+ .list-item.selected-active .ant-btn > span { color: #ffffff !important; }
506
+ .card-a-col.selected-active {
507
+ background-color: #0057FE !important;
508
+ color: white;
509
+ border: none !important;
510
+ }
511
+ .card-a-col.selected-active .button-a-col,
512
+ .card-a-col.selected-active .button-a-col .ant-btn,
513
+ .card-a-col.selected-active .button-a-col .ant-btn > span { color: #ffffff !important; }
514
+
403
515
  .hover-options {
404
516
  position: absolute;
405
517
  left: 0;
@@ -60,12 +60,15 @@ path: 'example',
60
60
  // component: () => import('@vue2-client/base-client/components/common/XAddNativeForm/demo.vue'),
61
61
  // component: () => import('@vue2-client/base-client/components/common/XFormGroup/demo.vue'),
62
62
  // component: () => import('@vue2-client/base-client/components/common/XReport/XReportDemo.vue'),
63
- component: () => import('@vue2-client/base-client/components/common/HIS/demo.vue'),
63
+ // component: () => import('@vue2-client/base-client/components/common/HIS/demo.vue'),
64
+ // component: () => import('@vue2-client/base-client/components/common/XFormTable/demo.vue'),
64
65
  // component: () => import('@vue2-client/base-client/components/common/XDatePicker/demo.vue'),
65
66
  // component: () => import('@vue2-client/base-client/components/common/XTab/XTabDemo.vue'),
66
67
  // component: () => import('@vue2-client/base-client/components/common/XRate/demo.vue'),
68
+ component: () => import('@vue2-client/base-client/components/common/XReport/XReportHospitalizationDemo.vue'),
67
69
  // component: () => import('@vue2-client/base-client/components/common/XForm/demo.vue'),
68
70
  // component: () => import('@vue2-client/base-client/components/his/XTimeSelect/XTimeSelectDemo.vue'),
71
+ // component: () => import('@vue2-client/base-client/components/his/XCharge/XChargeDemo.vue'),
69
72
  // component: () => import('@vue2-client/base-client/components/his/XImportExcelButton/XFrontImportExcelDemo.vue'),
70
73
  // component: () => import('@vue2-client/pages/WorkflowDetail/WorkFlowDemo.vue'),
71
74
  // component: () => import('@vue2-client/pages/WorkflowDetail/WorkFlowDemo.vue'),
@@ -83,6 +83,7 @@ export function getConfig (content, configName, serviceName = process.env.VUE_AP
83
83
  apiPre = '/devApi/'
84
84
  }
85
85
  const getConfigUrl = apiPre + serviceName + '/' + commonApi.getConfig
86
+ console.log('getConfigUrl', getConfigUrl)
86
87
  indexedDB.getByWeb(configName, getConfigUrl, { configName: configName }, callback)
87
88
  }
88
89