vue2-client 1.15.46 → 1.15.48

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.
@@ -0,0 +1,495 @@
1
+ <template>
2
+ <!-- 列表卡片模式 listMode: card -->
3
+ <div v-if="listMode"
4
+ class="demo-infinite-container"
5
+ ref="listRef"
6
+ @scroll="handleInfiniteOnLoad">
7
+ <a-list :grid="{ gutter: 16, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 4 }"
8
+ :data-source="localData">
9
+ <a-list-item slot="renderItem" slot-scope="item, index">
10
+ <div class="card-a-col">
11
+ <a-row class="card-row">
12
+ <a-col class="id-a-col" :span="4" v-for="(detail,idx) in item.filter(d => d.label == label)" :key="idx">
13
+ {{detail.value}}<span style="font-size: 16px;font-weight: 400 !important;">床</span>
14
+ </a-col>
15
+ <a-col :span="20" class="id-a-col-2">
16
+ <template v-for="(detail,idx) in item">
17
+ <span class="describe-list-a-col" :class="{name: detail.bold}" :key="idx" v-if="detail.type == 'title'">{{detail.value}}</span>
18
+ <span :key="idx" class="component-a-col" v-else-if="detail.type == 'component' && detail.label != label">
19
+ {{`${detail.label}:`}}
20
+ <component
21
+ :is="detail.slotType"
22
+ :key="idx"
23
+ :ref="`dynamicComponent_${ idx.slotType || idx}_${idx}`"
24
+ :serviceName="serviceName"
25
+ v-on="forwardAllEvents"
26
+ :queryParamsName="detail.value"
27
+ :countVisible="false"
28
+ />
29
+ </span>
30
+ <span :key="idx" class="component-a-col" v-else-if="detail.type == 'date'">
31
+ {{`${detail.label}:`}}
32
+ <a-date-picker @change="onChange" />
33
+ </span>
34
+ <span class="describe-list-a-col" :class="{name: detail.bold}" :key="idx" v-else-if="detail.label != label">{{`${detail.label}:${detail.value}`}}</span>
35
+ </template>
36
+ <a-button v-for="(btn, i) in buttonNames"
37
+ :key="i"
38
+ icon="search"
39
+ class="button-a-col"
40
+ @click.stop="click(item, index)">
41
+ {{btn}}
42
+ </a-button>
43
+ </a-col>
44
+ </a-row>
45
+ </div>
46
+ </a-list-item>
47
+ <div v-if="loading" class="demo-loading-container">
48
+ <a-spin />
49
+ </div>
50
+ <div v-if="allLoaded">
51
+ <div class="demo-infinite-list-bottom">
52
+ 已经显示全部数据
53
+ </div>
54
+ </div>
55
+ </a-list>
56
+ </div>
57
+
58
+ <!-- 默认标签模式 -->
59
+ <div class="list-wrapper" v-else>
60
+ <a-list size="large" :data-source="data" itemLayout="horizontal" class="list-container" ref="listRef">
61
+ <a-list-item slot="renderItem"
62
+ slot-scope="item, index"
63
+ class="list-item"
64
+ @click="handleClick(index)"
65
+ @mouseenter="enableHoverOptions && handleMouseEnter(index)"
66
+ @mouseleave="handleMouseLeave"
67
+ :class="{ 'hover-active': enableHoverOptions && hoveredIndex === index }">
68
+ <i v-if="icon"
69
+ class="icon-menu"
70
+ :style="getIconStyle(item)">
71
+ </i>
72
+ <span
73
+ class="item-text">
74
+ {{ item.number }} {{ item.name }}
75
+ </span>
76
+
77
+ <div v-if="button" class="button-group">
78
+ <a-button
79
+ v-for="(name, idx) in buttonNames"
80
+ :key="idx"
81
+ type="link"
82
+ :class="['confirm-btn', buttonMode ? 'hover-btn' : '']"
83
+ @click.stop="click(index, idx)">
84
+ <span :class="{ 'hover-active': enableHoverOptions && hoveredIndex === index }">{{ name }}</span>
85
+ </a-button>
86
+ </div>
87
+
88
+ <!-- 悬浮选项框 -->
89
+ <div v-show="enableHoverOptions && hoveredIndex === index"
90
+ class="hover-options"
91
+ @mouseenter="handleOptionsEnter"
92
+ @mouseleave="handleOptionsLeave">
93
+ <div class="hover-options-content">
94
+ <div v-for="(item, idx) in select_options"
95
+ :key="idx"
96
+ class="option-item"
97
+ @click="handleOptionClick(index, item)">
98
+ {{ item }}
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </a-list-item>
103
+ </a-list>
104
+ </div>
105
+ </template>
106
+
107
+ <script>
108
+
109
+ import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
110
+
111
+ export default {
112
+ name: 'XList',
113
+ components: {
114
+ XReport: () => import('@vue2-client/base-client/components/common/XReport/XReport.vue'),
115
+ XButtons: () => import('@vue2-client/base-client/components/common/XButtons/XButtons.vue'),
116
+ XInput: () => import('@vue2-client/base-client/components/common/XInput/XInput.vue'),
117
+ XRadio: () => import('@vue2-client/base-client/components/his/XRadio/XRadio.vue'),
118
+ XTimeSelect: () => import('@vue2-client/base-client/components/his/XTimeSelect/XTimeSelect.vue'),
119
+ XCheckbox: () => import('@vue2-client/base-client/components/his/XCheckbox/XCheckbox.vue'),
120
+ XTitle: () => import('@vue2-client/base-client/components/his/XTitle/XTitle.vue'),
121
+ XSelect: () => import('@vue2-client/base-client/components/his/XSelect/XSelect.vue')
122
+ },
123
+ props: {
124
+ queryParamsName: {
125
+ type: Object,
126
+ default: null
127
+ },
128
+ fixedQueryForm: {
129
+ type: Object,
130
+ default: { condition: '1=1' }
131
+ },
132
+ enableHoverOptions: {
133
+ type: Boolean,
134
+ default: true
135
+ },
136
+ serviceName: {
137
+ type: String,
138
+ default: 'af-his'
139
+ }
140
+ },
141
+ inject: ['getComponentByName'],
142
+ data () {
143
+ return {
144
+ data: [], // 数据源
145
+ localData: [], // 本地数据源
146
+ loading: false, // 加载中
147
+ busy: false, // 繁忙状态
148
+ button: false,
149
+ icon: false,
150
+ buttonNames: [],
151
+ listMode: undefined, // 列表模式
152
+ buttonMode: true,
153
+ hoveredIndex: -1, // 当前悬浮的索引
154
+ isOptionsHovered: false, // 悬浮选项框是否悬浮
155
+ hoverTimer: null, // 悬浮选项框定时器
156
+ leaveTimer: null, // 离开选项框定时器
157
+ select_options: [], // 悬浮选项框
158
+ logicName: '',
159
+ nowPage: 0, // 当前页
160
+ pageSize: 12,
161
+ allLoaded: false,
162
+ label: 'id'
163
+ }
164
+ },
165
+ created () {
166
+ this.getData(this.queryParamsName, this.fixedQueryForm)
167
+ },
168
+ mounted () {
169
+ this.$nextTick(() => {
170
+ const ref = this.$refs.listRef
171
+ if (ref && ref.addEventListener) {
172
+ ref.addEventListener('scroll', this.handleInfiniteOnLoad)
173
+ }
174
+ })
175
+ },
176
+ computed: {
177
+ forwardAllEvents () {
178
+ return {
179
+ // 监听所有事件并转发给父组件
180
+ '*': (eventName, ...payload) => {
181
+ this.$emit(eventName, ...payload)
182
+ }
183
+ }
184
+ }
185
+ },
186
+ methods: {
187
+ onChange (date, dateString) {
188
+ this.$emit('dateChange', date, dateString)
189
+ },
190
+ handleInfiniteOnLoad (event) {
191
+ const container = event.target // 获取列表容器元素
192
+ const scrollTop = container.scrollTop // 获取滚动条的当前位置
193
+ const scrollHeight = container.scrollHeight // 获取列表容器的总高度
194
+ const clientHeight = container.clientHeight // 获取列表容器的可见高度
195
+ const bottomOffset = 20
196
+ // 判断是否滚动到底部
197
+ if (scrollTop + clientHeight >= scrollHeight - bottomOffset) {
198
+ if (this.busy || this.allLoaded) return // 防止重复加载
199
+ this.busy = true
200
+ this.loading = true
201
+ try {
202
+ this.nowPage = this.nowPage + this.pageSize
203
+ this.fixedQueryForm.condition = `Limit ${this.nowPage}, ${this.pageSize}`
204
+ runLogic(this.logicName, this.fixedQueryForm, 'af-his').then(async (res) => {
205
+ this.localData = [...this.localData, ...res]
206
+ // 如果返回的数据长度小于每页的记录数,则认为已经加载完所有数据
207
+ if (res.length < this.pageSize) {
208
+ this.allLoaded = true
209
+ }
210
+ })
211
+ } catch (e) {
212
+ this.$message.error(e.message)
213
+ } finally {
214
+ this.loading = false
215
+ this.busy = false
216
+ }
217
+ }
218
+ },
219
+ async getData (config, param) {
220
+ const that = this
221
+ getConfigByName(config, 'af-his', async (res) => {
222
+ that.listMode = await res.listMode == 'card'
223
+ that.logicName = await res.data
224
+ that.button = await res.button // 按钮
225
+ that.icon = await res.icon // 图标
226
+ that.label = await res.label // 标签
227
+ that.buttonNames = await res.buttonNames || []// 按钮文本
228
+ that.buttonMode = await res.buttonMode || false// 按钮模式
229
+ this.enableHoverOptions = await res.enableHoverOptions || false// 悬浮选项框
230
+ if (this.enableHoverOptions) {
231
+ this.select_options = await res.select_options
232
+ }
233
+ if (that.listMode) { param.condition = `Limit ${that.nowPage}, ${that.pageSize}` }
234
+ runLogic(res.data, param, 'af-his').then(result => {
235
+ that.data = result
236
+ if (that.nowPage == 0) { this.localData = result }
237
+ })
238
+ })
239
+ },
240
+ // 点击列表项
241
+ handleClick (index) {
242
+ this.$emit('listClick', this.data[index])
243
+ },
244
+ refreshList (param) {
245
+ this.getData(this.queryParamsName, param)
246
+ },
247
+ click (index, buttonIndex) {
248
+ this.$emit('click', { data: this.data[index], name: this.buttonNames[buttonIndex] })
249
+ },
250
+ getIconStyle (item) {
251
+ return item.picture
252
+ ? { backgroundImage: `url(${item.picture})` }
253
+ : {}
254
+ },
255
+ filterData (par) {
256
+ runLogic(this.queryParamsName, par, 'af-his').then(res => {
257
+ this.data = res.data
258
+ })
259
+ },
260
+ // 鼠标进入列表项
261
+ handleMouseEnter (index) {
262
+ this.clearAllTimers()
263
+ this.hoveredIndex = index
264
+ this.isOptionsHovered = true
265
+ },
266
+ // 鼠标离开列表项
267
+ handleMouseLeave () {
268
+ this.clearAllTimers()
269
+ this.leaveTimer = setTimeout(() => {
270
+ this.isOptionsHovered = false
271
+ this.hoveredIndex = -1
272
+ }, 100)
273
+ },
274
+ // 鼠标进入悬浮选项框
275
+ handleOptionsEnter () {
276
+ this.clearAllTimers()
277
+ this.isOptionsHovered = true
278
+ },
279
+ // 鼠标离开悬浮选项框
280
+ handleOptionsLeave () {
281
+ this.clearAllTimers()
282
+ this.leaveTimer = setTimeout(() => {
283
+ this.isOptionsHovered = false
284
+ this.hoveredIndex = -1
285
+ }, 100)
286
+ },
287
+ // 清除所有定时器
288
+ clearAllTimers () {
289
+ if (this.hoverTimer) {
290
+ clearTimeout(this.hoverTimer)
291
+ this.hoverTimer = null
292
+ }
293
+ if (this.leaveTimer) {
294
+ clearTimeout(this.leaveTimer)
295
+ this.leaveTimer = null
296
+ }
297
+ },
298
+ // 选项框点击
299
+ handleOptionClick (index, action) {
300
+ this.$emit('optionClick', { data: this.data[index], action })
301
+ }
302
+ },
303
+ watch: {
304
+ fixedQueryForm: {
305
+ deep: true,
306
+ handler (val) {
307
+ this.refreshList(val)
308
+ }
309
+ }
310
+ },
311
+ beforeDestroy () {
312
+ const ref = this.$refs.listRef
313
+ if (ref && ref.removeEventListener) {
314
+ ref.removeEventListener('scroll', this.handleInfiniteOnLoad)
315
+ }
316
+ this.clearAllTimers()
317
+ }
318
+ }
319
+ </script>
320
+
321
+ <style scoped>
322
+ .list-wrapper {
323
+ max-height: 240px;
324
+ overflow-y: auto;
325
+ padding-right: 2px;
326
+ }
327
+
328
+ .list-container {
329
+ width: 100%;
330
+ }
331
+
332
+ .list-item {
333
+ height: 35px;
334
+ border-radius: 6px;
335
+ background-color: #F4F4F4;
336
+ padding: 8px 15px;
337
+ font-size: 16px;
338
+ display: flex;
339
+ align-items: center;
340
+ width: 100%;
341
+ border: 1px solid #D9D9D9;
342
+ box-sizing: border-box;
343
+ margin-bottom: 8px !important;
344
+ position: relative;
345
+ transition: background-color 0.3s ease;
346
+ }
347
+
348
+ .icon-menu {
349
+ display: inline-block;
350
+ width: 20px;
351
+ height: 20px;
352
+ background-color: #ccc;
353
+ margin-right: 8px;
354
+ }
355
+
356
+ .item-text {
357
+ flex: 1;
358
+ }
359
+
360
+ .confirm-btn {
361
+ margin-left: auto;
362
+ padding: 0 8px;
363
+ }
364
+
365
+ .confirm-btn.hover-btn {
366
+ opacity: 0;
367
+ transition: opacity 0.3s ease;
368
+ }
369
+
370
+ .button-group {
371
+ display: flex;
372
+ gap: 2px; /* 按钮之间的间距 */
373
+ }
374
+
375
+ .list-item:hover .confirm-btn.hover-btn {
376
+ opacity: 1;
377
+ }
378
+
379
+ /* 自定义滚动条样式 */
380
+ .list-wrapper::-webkit-scrollbar {
381
+ width: 6px;
382
+ }
383
+
384
+ .list-wrapper::-webkit-scrollbar-thumb {
385
+ background-color: #d9d9d9;
386
+ border-radius: 3px;
387
+ }
388
+
389
+ .list-wrapper::-webkit-scrollbar-track {
390
+ background-color: #f0f0f0;
391
+ }
392
+
393
+ .hover-active {
394
+ color: white;
395
+ }
396
+
397
+ .list-item.hover-active {
398
+ background-color: rgb(0, 87, 254) !important;
399
+ color: white;
400
+ border: 1px solid black;
401
+ }
402
+
403
+ .hover-options {
404
+ position: absolute;
405
+ left: 0;
406
+ right: 0;
407
+ top: 100%;
408
+ background: white;
409
+ border: 1px solid #d9d9d9;
410
+ border-radius: 4px;
411
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
412
+ z-index: 1000;
413
+ margin-top: 4px;
414
+ width: 100%;
415
+ box-sizing: border-box;
416
+ pointer-events: auto;
417
+ }
418
+
419
+ .hover-options-content {
420
+ padding: 4px 0;
421
+ display: flex;
422
+ flex-direction: column;
423
+ width: 100%;
424
+ }
425
+
426
+ .option-item {
427
+ padding: 8px 12px;
428
+ cursor: pointer;
429
+ transition: all 0.3s ease;
430
+ color: #333;
431
+ font-size: 14px;
432
+ display: flex;
433
+ align-items: center;
434
+ }
435
+
436
+ .option-item:hover {
437
+ background-color: #f5f5f5;
438
+ color: #1890ff;
439
+ }
440
+
441
+ .option-item:active {
442
+ background-color: #e6f7ff;
443
+ }
444
+
445
+ .demo-loading-container {
446
+ position: absolute;
447
+ bottom: 40px;
448
+ width: 100%;
449
+ text-align: center;
450
+ }
451
+
452
+ .demo-infinite-container{
453
+ overflow-x: hidden;
454
+ overflow-y: auto;
455
+ height: 80vh;
456
+ }
457
+ .card-row{
458
+ height: 100%;
459
+ width: 100%;
460
+ border-radius: 6px;
461
+ padding: 6px;
462
+ }
463
+ .id-a-col{
464
+ font-size: 22px;
465
+ font-weight: 700;
466
+ display: flex;
467
+ justify-content: space-evenly;
468
+ align-items: center;
469
+ }
470
+ .id-a-col-2{}
471
+ .describe-list-a-col{
472
+ display: block;
473
+ font-size: 16px;
474
+ }
475
+ .name{
476
+ font-size: 18px;
477
+ font-weight: 700;
478
+ }
479
+ .component-a-col{
480
+ display: flex;
481
+ align-items: center;
482
+ }
483
+ .button-a-col{
484
+ position: absolute;
485
+ top: 245px;
486
+ left: 225px;
487
+ }
488
+ .card-a-col{
489
+ background-color: rgba(247, 249, 252);
490
+ height: 297px;
491
+ width: auto;
492
+ border-radius: 6px;
493
+ border: 1px solid #E5E9F0;
494
+ }
495
+ </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-client",
3
- "version": "1.15.46",
3
+ "version": "1.15.48",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --no-eslint",
@@ -167,7 +167,6 @@ export default {
167
167
  },
168
168
  async getData (config, parameter) {
169
169
  this.configName = config
170
- config = 'collapseTestConfig'
171
170
  getConfigByName(config, 'af-his', res => {
172
171
  this.config = res
173
172
  console.warn(this.config)
@@ -2,13 +2,14 @@
2
2
  <!-- 列表卡片模式 listMode: card -->
3
3
  <div v-if="listMode"
4
4
  class="demo-infinite-container"
5
- ref="listRef">
5
+ ref="listRef"
6
+ @scroll="handleInfiniteOnLoad">
6
7
  <a-list :grid="{ gutter: 16, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 4 }"
7
8
  :data-source="localData">
8
9
  <a-list-item slot="renderItem" slot-scope="item, index">
9
- <div style="background-color: #E5E9F0; height: 297px; width: auto; border-radius: 6px;">
10
+ <div class="card-a-col">
10
11
  <a-row class="card-row">
11
- <a-col class="id-a-col" :span="4" v-for="(detail,idx) in item" :key="idx" v-if="detail.label == label">
12
+ <a-col class="id-a-col" :span="4" v-for="(detail,idx) in item.filter(d => d.label == label)" :key="idx">
12
13
  {{detail.value}}<span style="font-size: 16px;font-weight: 400 !important;">床</span>
13
14
  </a-col>
14
15
  <a-col :span="20" class="id-a-col-2">
@@ -35,7 +36,6 @@
35
36
  <a-button v-for="(btn, i) in buttonNames"
36
37
  :key="i"
37
38
  icon="search"
38
- v-if="1"
39
39
  class="button-a-col"
40
40
  @click.stop="click(item, index)">
41
41
  {{btn}}
@@ -166,8 +166,12 @@ export default {
166
166
  this.getData(this.queryParamsName, this.fixedQueryForm)
167
167
  },
168
168
  mounted () {
169
- // 卡片模式绑定滚动事件
170
- this.$refs.listRef.addEventListener('scroll', this.handleInfiniteOnLoad)
169
+ this.$nextTick(() => {
170
+ const ref = this.$refs.listRef
171
+ if (ref && ref.addEventListener) {
172
+ ref.addEventListener('scroll', this.handleInfiniteOnLoad)
173
+ }
174
+ })
171
175
  },
172
176
  computed: {
173
177
  forwardAllEvents () {
@@ -305,6 +309,10 @@ export default {
305
309
  }
306
310
  },
307
311
  beforeDestroy () {
312
+ const ref = this.$refs.listRef
313
+ if (ref && ref.removeEventListener) {
314
+ ref.removeEventListener('scroll', this.handleInfiniteOnLoad)
315
+ }
308
316
  this.clearAllTimers()
309
317
  }
310
318
  }
@@ -477,4 +485,11 @@ export default {
477
485
  top: 245px;
478
486
  left: 225px;
479
487
  }
488
+ .card-a-col{
489
+ background-color: rgba(247, 249, 252);
490
+ height: 297px;
491
+ width: auto;
492
+ border-radius: 6px;
493
+ border: 1px solid #E5E9F0;
494
+ }
480
495
  </style>