agilebuilder-ui 1.1.12-tmp2 → 1.1.13-tmp1

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,453 @@
1
+ /** @jsxImportSource vue */
2
+ import { defineComponent, ref, computed, watch, defineEmits } from 'vue';
3
+ import { ElCard, ElDrawer, ElTag,ElDescriptions, ElDescriptionsItem, ElButton, ElIcon, ElCheckbox, ElCheckboxGroup, ElBreadcrumb, ElLink, ElEmpty, ElDivider } from 'element-plus';
4
+ import NormalColumnContent from '../normal-column-content.vue';
5
+ import store from '../store';
6
+ import { ArrowLeft, Bottom, Loading, Tickets } from '@element-plus/icons-vue';
7
+ // import { $emit, $off, $on } from '@/utils/gogocodeTransfer'
8
+
9
+ export default defineComponent({
10
+ name: 'MobileTableCard',
11
+ components: {
12
+ NormalColumnContent
13
+ },
14
+ props: {
15
+ // 展示字段限制
16
+ showFieldCount: {
17
+ type: [Number, undefined],
18
+ default: () => 5
19
+ },
20
+ // 是否使用弹窗功能
21
+ isDetailsDrawer: {
22
+ type: Boolean,
23
+ default: () => false
24
+ },
25
+ // 列字段数据
26
+ columns: {
27
+ type: Array,
28
+ default: () => []
29
+ },
30
+ // 表格数据
31
+ data: {
32
+ type: Array,
33
+ default: () => []
34
+ },
35
+ // 字段事件 v-bind 与 v-on 集成
36
+ getColumnComponentData: {
37
+ type: [Function, undefined],
38
+ default: undefined
39
+ },
40
+ // 选中页
41
+ currentPage: {
42
+ type: [Number],
43
+ default: 1
44
+ },
45
+ // 一页展示数量
46
+ pageSize: {
47
+ type: [Number],
48
+ default: 20
49
+ },
50
+ // 一页展示数量
51
+ pageTotal: {
52
+ type: [Number],
53
+ default: 0
54
+ },
55
+ // 是否开启 堆积分页数据
56
+ isStackingPaginatedData: {
57
+ type: Boolean,
58
+ default: () => false
59
+ },
60
+ },
61
+ setup(props, setupData) {
62
+ const $emits = defineEmits(['currentChange', 'update:current-page', 'select']);
63
+
64
+ const { attrs, emit } = setupData
65
+ console.log('*mobile-table-card.JSX**********************************************=>', props, attrs, setupData)
66
+
67
+ // 分页加载状态
68
+ const isPaginationLoading = ref(false)
69
+
70
+ const paginationList = ref([])
71
+ // 选中数据
72
+ const checkedList = ref([]);
73
+ // 是否打开弹窗
74
+ const isDetailsDrawer = ref(false);
75
+ // 当前选中数据
76
+ const isCheckedIndex = ref(undefined);
77
+ // 展开更多字段
78
+ const isColumnExpandMore = ref(undefined);
79
+
80
+ // 是否打开子表弹窗
81
+ const isChildrenDrawer = ref(false);
82
+
83
+ // 子表打开历史数据
84
+ const childrenBreadcrumbData = ref([]);
85
+
86
+ const setPaginationList = (data) => {
87
+ if (props.isStackingPaginatedData) {
88
+ paginationList.value[(props.currentPage ?? 1) - 1] = data
89
+ } else {
90
+ paginationList.value[0] = data
91
+ }
92
+ isPaginationLoading.value = false
93
+ }
94
+
95
+ setPaginationList(props.data)
96
+
97
+ // 列表数据
98
+ const dataList = computed(() => {
99
+ if (props.isStackingPaginatedData) {
100
+ return paginationList.value.flatMap((data, index) => index + 1 <= props.currentPage ? data : [] )
101
+ } else {
102
+ return paginationList.value[0] ?? []
103
+ }
104
+ });
105
+
106
+ // 面包屑数据
107
+ const childrenList = computed(() => {
108
+ return childrenBreadcrumbData.value[childrenBreadcrumbData.value.length - 1]?.children ?? []
109
+ });
110
+
111
+ const componentDatas = computed(() => {
112
+ const getChildrenData = (data) => {
113
+ return data?.flatMap(item => {
114
+ if (item?.children?.length) return getChildrenData(item.children)
115
+ return [item]
116
+ }) ?? []
117
+ }
118
+ return getChildrenData(props.columns.filter((column) => !column ? false : !['$selection', '$index'].includes(column?.prop)))
119
+ });
120
+
121
+ const layoutData = computed(() => {
122
+ const contentData = componentDatas.value.map((data, index) => {
123
+ if (data.operations) {
124
+ data.layoutModelType = 'footer'
125
+ } else {
126
+ data.layoutModelType = 'content'
127
+ }
128
+ return data
129
+ });
130
+ const content = contentData.filter(({ layoutModelType}) => ['content'].includes(layoutModelType))
131
+ return {
132
+ header: content[0] ? [content[0]] : [],
133
+ content,
134
+ footer: contentData.filter(({ layoutModelType}) => ['footer'].includes(layoutModelType))
135
+ };
136
+ });
137
+
138
+ // 获取最大 label 字符长度
139
+ const getLongestStringLength = (strArray) => {
140
+ return strArray.reduce((maxLen, str) => {
141
+ return Math.max(maxLen, [...str].reduce((len, char) => /[\u4e00-\u9fff]/.test(char) ? len + 2 : len + 1, 0));
142
+ }, 0);
143
+ };
144
+
145
+ // 分页数量
146
+ const pagesNumber = computed(() => {
147
+ if (!props.pageTotal) return 0
148
+ return Math.ceil(props.pageTotal / props.pageSize)
149
+ })
150
+
151
+ // 字段更多 是否开启
152
+ const isShowDetailsMore = computed(() => {
153
+ if (!isShowDetailsDrawer.value && props.showFieldCount && layoutData.value.content.length > props.showFieldCount) return true
154
+ return false
155
+ })
156
+
157
+ // 是否显示卡片底部控件
158
+ const isShowFooter = computed(() => {
159
+ return !props.isDetailsDrawer && layoutData.value.footer.length > 0
160
+ })
161
+
162
+ // 是否开启弹窗 展示
163
+ const isShowDetailsDrawer = computed(() => {
164
+ return !!props.isDetailsDrawer
165
+ })
166
+
167
+ const maxLabelWidth = computed(() => {
168
+ return getLongestStringLength(layoutData.value.content.map((column) => column?.label ?? 0)) * 7 + 15
169
+ })
170
+
171
+ const isCheck = computed(() => {
172
+ return props.columns.some((column) => ['$selection'].includes(column?.prop));
173
+ });
174
+
175
+ const isIndex = computed(() => {
176
+ return props.columns.some((column) => ['$index'].includes(column?.prop));
177
+ });
178
+
179
+ const detailsFormData = computed(() => {
180
+ return dataList.value[isCheckedIndex.value]
181
+ });
182
+
183
+ // 写入选中
184
+ const setCheckedList = (value) => {
185
+ if (!isCheck.value) return
186
+ if (checkedList.value.includes(value)) {
187
+ checkedList.value = checkedList.value.filter(v => v !== value)
188
+ } else {
189
+ checkedList.value = [...new Set([...checkedList.value, value])]
190
+ }
191
+ }
192
+
193
+ /**
194
+ * 字段渲染展示
195
+ * @param {当前字段数据} columnData
196
+ * @param {当前行的数据} columnFormData
197
+ * @param {所在行的$index} columnIndex
198
+ * @param {是否只显示文本} isViewText
199
+ * @returns
200
+ */
201
+ const columnViewDom = (columnData, columnFormData, columnIndex, isViewText = false) => {
202
+ const {$bind = {}, $on = {}} = props.getColumnComponentData?.(columnData) ?? {}
203
+ const gridParams = store.get($bind['list-code'])
204
+ const options = gridParams?.options
205
+ const lineEdit = gridParams.lineEdit ?? false
206
+ const attrs = {
207
+ ...$bind,
208
+ options,
209
+ row: columnFormData,
210
+ rowIndex: columnIndex,
211
+ 'right-click-menu-arr': options?.rightClickMenuArr,
212
+ 'line-edit': lineEdit
213
+ }
214
+ const onAttrs = {
215
+ ...Object.fromEntries(Object.keys($on).map(key => [`on${key.charAt(0).toUpperCase()}${key.slice(1).replace(/-([a-z])/g, (match, letter) => letter.toUpperCase())}`, $on[key]]))
216
+ }
217
+ return <div overflow-wrap>
218
+ <NormalColumnContent isContentViewText={isViewText} {...attrs} {...onAttrs} />
219
+ </div>
220
+ }
221
+
222
+ /**
223
+ *
224
+ * @param {字段columns List} layoutDatas
225
+ * @param {当前行的数据} columnFormData
226
+ * @param {所在行的$index} columnIndex
227
+ * @param {限制显示字段} showFieldCount
228
+ * @returns .filter((_, index) => !props.showFieldCount || props.showFieldCount > index + 1)
229
+ */
230
+ const getElDescriptions = (layoutDatas, columnFormData = detailsFormData.value, columnIndex = isCheckedIndex.value, showFieldCount = undefined) => {
231
+ return <ElDescriptions column={1} label-width={maxLabelWidth.value} align="right" direction="horizontal" layout='form'>
232
+ {(showFieldCount ? layoutDatas?.slice?.(0, showFieldCount) : layoutDatas)?.map((columnCol, index) => (
233
+ <ElDescriptionsItem
234
+ key={columnCol.label + index}
235
+ v-slots={
236
+ {
237
+ label: () => <div v-html={columnCol.label ? `${columnCol.label}:` : ''} />
238
+ }
239
+ }
240
+ >
241
+ {columnViewDom(columnCol, columnFormData, columnIndex) || '-'}
242
+ </ElDescriptionsItem>
243
+ ))}
244
+ </ElDescriptions>
245
+ }
246
+
247
+ watch(() => attrs.selection, (newValue) => {
248
+ console.log('表格勾选数据监听', newValue)
249
+ checkedList.value = newValue.map(({ $rowDataGuId }) => $rowDataGuId)
250
+ }, { deep: true });
251
+
252
+ // 勾选监听
253
+ watch(checkedList, (newValue) => {
254
+ if (attrs.selection.length === newValue.length) {
255
+ if (attrs.selection.every(({ $rowDataGuId }) => newValue.includes($rowDataGuId ) )) return
256
+ }
257
+ const selectData = dataList.value.filter(({ $rowDataGuId }) => newValue?.includes($rowDataGuId))
258
+ console.log('选中数据+++mobile-table-card+++++++++++++++++++++++++++++>', newValue, selectData)
259
+ emit('selectionChange', selectData)
260
+ }, { deep: true });
261
+
262
+ // 滚动数据加载监听
263
+ watch(() => props.data, (newValue) => {
264
+ console.log('props.data =======================> 更新', newValue)
265
+ setPaginationList(newValue)
266
+ }, { deep: true });
267
+
268
+ // 滚动到底部监听
269
+ const scrollLoad = () => {
270
+ console.log('分页', pagesNumber.value, props.currentPage)
271
+ if (pagesNumber.value > 1 && pagesNumber.value > props.currentPage) {
272
+ // paginationList.value[props.currentPage - 1]?.length ||
273
+ console.log(dataList.value.length, props.pageSize * props.currentPage)
274
+ if (dataList.value.length === props.pageSize * props.currentPage ) {
275
+ isPaginationLoading.value = true
276
+ const currentPage = props.currentPage + 1
277
+ console.log('开始滚动了', currentPage, pagesNumber.value)
278
+ emit('update:current-page', currentPage)
279
+ emit('currentChange', currentPage)
280
+ } else {
281
+ console.log('等待数据加载')
282
+ }
283
+ } else {
284
+ console.log('到底了')
285
+ }
286
+ }
287
+
288
+ const load = () => {
289
+ // 这里可以实现加载更多的逻辑
290
+ };
291
+
292
+ return () => (
293
+ <div v-infinite-scroll={scrollLoad} style={{ overflow: 'auto', maxHeight: 'calc(100vh - 132px)', marginBottom: '15px' }}>
294
+ {/* { paginationList.value.length}, {paginationList.value[props.currentPage - 1]?.length} */}
295
+ {/* <div overflow-wrap>{JSON.stringify(props.columns)}</div> */}
296
+ {isShowDetailsDrawer.value && (<ElDrawer v-model={isDetailsDrawer.value} with-header={true} direction="btt" append-to-body size='90vh'>
297
+ <div class="yx-flex-wrap" vertical style={{ 'height': 'calc(100vh - 218px)', gap: '10px'}}>
298
+ <ElScrollbar scrollable-main height='calc(100vh - 258px)' style={{ 'flex': '1 1 auto'}}>
299
+ { detailsFormData.value && getElDescriptions(layoutData.value.content, detailsFormData.value, isCheckedIndex.value, undefined)}
300
+ </ElScrollbar>
301
+ { detailsFormData.value && (<div class="yx-flex-wrap" wrap style={{gap: '15px'}}>
302
+ {layoutData.value.footer?.map((columnCol) => columnViewDom(columnCol))}
303
+ </div>)}
304
+ </div>
305
+ </ElDrawer>)}
306
+
307
+ {(<ElDrawer v-model={isChildrenDrawer.value} with-header={true} direction="btt" append-to-body size='90vh' v-slots={{
308
+ header: () => (<div class="yx-flex-wrap" style={{gap: '10px'}}>
309
+ {layoutData.value.header[0] && `${layoutData.value.header[0].label}: `}
310
+ <ElBreadcrumb separator-icon={<ArrowRight></ArrowRight>}>
311
+ {childrenBreadcrumbData.value.map((columnFormData, i) => {
312
+ const label = columnViewDom(layoutData.value.header[0], columnFormData, undefined, true)
313
+ return (
314
+ <ElBreadcrumbItem>
315
+ {
316
+ childrenBreadcrumbData.value.length - 1 === i ? label : <ElLink onClick={() => childrenBreadcrumbData.value = childrenBreadcrumbData.value.slice(0, i + 1)}>{ label }</ElLink>
317
+ }
318
+ </ElBreadcrumbItem>
319
+ )
320
+
321
+ })}
322
+ </ElBreadcrumb>
323
+ </div>)
324
+ }}
325
+ onClosed={() => childrenBreadcrumbData.value = []}
326
+ >
327
+
328
+ <div class="yx-flex-wrap" vertical style={{ 'maxHeight': 'calc(100vh - 218px)', gap: '10px'}}>
329
+ <ElScrollbar scrollable-main height='100%' style={{ 'flex': '1 1 auto'}}>
330
+ <div class="yx-flex-wrap" vertical style={{ gap: '15px'}}>
331
+ { childrenList.value.map((columnFormData, columnIndex) => {
332
+ const isColumnExpand = columnIndex === isColumnExpandMore.value
333
+ // 是否是子表
334
+ const isChildren = !!(columnFormData?.children?.length ?? false)
335
+ return <ElCard key={`card_children_${columnFormData?.id}_${columnIndex}`} header-padding body-padding shadow="hover" class='yx-card-main' v-slots={{
336
+ header: () => (
337
+ <div class="yx-flex-wrap" justify='space-between' align='center' style={{gap: '10px', "min-height": '50px', padding: '5px var(--el-card-padding)'}}>
338
+ <div class="yx-flex-wrap" align='center' style={{gap: '10px'}}>
339
+ { isIndex && <ElTag type="primary" size='small'>{columnIndex + 1}</ElTag>}
340
+ { layoutData.value.header?.map((columnCol) => columnViewDom(columnCol, columnFormData, columnIndex, true)) }
341
+ </div>
342
+ <div class="yx-flex-wrap" align='center' style={{gap: '10px'}}>
343
+ { isChildren && <ElButton text icon={<ElIcon><Tickets /></ElIcon>} onClick={event => {
344
+ event.stopPropagation()
345
+ childrenBreadcrumbData.value =[...childrenBreadcrumbData.value, columnFormData];
346
+ }} /> }
347
+ </div>
348
+ </div>
349
+ )
350
+ }}>
351
+ <div class="yx-flex-wrap" vertical style={{gap: '0', height: '100%'}}>
352
+ <ElScrollbar scrollable-main height={isShowDetailsMore.value && (isColumnExpand || columnFormData.$editing) ? '40vh' : '100%'}>
353
+ <div style={{ padding: 'var(--el-card-padding)' }}>
354
+ { getElDescriptions(layoutData.value.content, columnFormData, columnIndex, isColumnExpand || columnFormData.$editing ? undefined : props.showFieldCount) }
355
+ </div>
356
+ </ElScrollbar>
357
+ </div>
358
+ </ElCard>
359
+ }) }
360
+ </div>
361
+ </ElScrollbar>
362
+ </div>
363
+ </ElDrawer>)}
364
+
365
+ {/* <ElCheckboxGroup value={checkedList} onChange={value => checkedList.value = value}> */}
366
+ <div
367
+ class="yx-flex-wrap"
368
+ vertical
369
+ style="overflow: auto; gap: 15px;"
370
+ onInfiniteScroll={load}
371
+ >
372
+ {dataList.value.length === 0 && <ElEmpty />}
373
+
374
+ {dataList.value.map((columnFormData, columnIndex) => {
375
+ const isColumnExpand = columnIndex === isColumnExpandMore.value
376
+
377
+ // 开启编辑后禁止选中
378
+ const onChecked = () => !columnFormData.$editing && setCheckedList(columnFormData.$rowDataGuId)
379
+
380
+ const isChecked = checkedList.value.includes(columnFormData.$rowDataGuId)
381
+
382
+ // 是否有子表
383
+ const isChildren = !!(columnFormData?.children?.length ?? false)
384
+ return (
385
+ <ElCard key={`card_${columnFormData?.id}_${columnIndex}`} header-padding body-padding shadow="hover" class={{ 'yx-card-main': true, 'is-checked': isChecked}} v-slots={{
386
+ header: () => (
387
+ <div class="yx-flex-wrap" justify='space-between' align='center' style={{gap: '10px', "min-height": '50px', padding: '5px var(--el-card-padding)'}} onClick={onChecked}>
388
+ <div class="yx-flex-wrap" align='center' style={{gap: '10px'}}>
389
+ { isIndex && <ElTag type="primary" size='small'>{columnIndex + 1}</ElTag>}
390
+ { layoutData.value.header?.map((columnCol) => columnViewDom(columnCol, columnFormData, columnIndex, true)) }
391
+ </div>
392
+ <div class="yx-flex-wrap" align='center' style={{gap: '10px'}}>
393
+ { isChildren && <ElButton text icon={<ElIcon><Tickets /></ElIcon>} onClick={event => {
394
+ event.stopPropagation()
395
+ // isCheckedIndex.value = columnIndex;
396
+ childrenBreadcrumbData.value =[columnFormData];
397
+ isChildrenDrawer.value = true
398
+ }} /> }
399
+ { isCheck.value && <ElCheckbox model-value={isChecked} disabled={!!columnFormData.$editing} style="height: auto;" onClick={(event) => {
400
+ event.stopPropagation()
401
+ }} onChange={onChecked} /> }
402
+ </div>
403
+ </div>
404
+ ),
405
+ ...(isShowFooter.value ? {
406
+ footer: () => (
407
+ <div class="yx-flex-wrap" wrap style={{gap: '15px'}}>
408
+ {layoutData.value.footer?.map((columnCol) => columnViewDom(columnCol, columnFormData, columnIndex))}
409
+ </div>
410
+ )
411
+ } : {})
412
+ }}>
413
+ <div class="yx-flex-wrap" vertical style={{gap: '0', height: '100%'}} onClick={onChecked}>
414
+ <ElScrollbar scrollable-main style={{ maxHeight: isShowDetailsMore.value && (isColumnExpand || columnFormData.$editing) ? '50vh' : '100%'}}>
415
+ {/* <div>{JSON.stringify(columnFormData)}</div> */}
416
+ <div style={{ padding: 'var(--el-card-padding)' }}>
417
+ { getElDescriptions(layoutData.value.content, columnFormData, columnIndex, isColumnExpand || columnFormData.$editing ? undefined : props.showFieldCount) }
418
+ </div>
419
+ </ElScrollbar>
420
+ {
421
+ isShowDetailsDrawer.value && (<ElButton text icon={<ElIcon><Tickets /></ElIcon>} onClick={(event) => {
422
+ event.stopPropagation()
423
+ isCheckedIndex.value = columnIndex;
424
+ isDetailsDrawer.value = true;
425
+ }}>More</ElButton>)
426
+ }
427
+ {
428
+ isShowDetailsMore.value && !columnFormData.$editing && (<ElButton text icon={<ElIcon>{isColumnExpand ? <Top /> : <Bottom /> }</ElIcon>} onClick={(event) => {
429
+ event.stopPropagation()
430
+ isColumnExpandMore.value = isColumnExpand ? undefined : columnIndex
431
+ // isCheckedIndex.value = columnIndex;
432
+ // isDetailsDrawer.value = true;
433
+ }}>{ isColumnExpand ? 'Less' : 'More'}</ElButton>)
434
+ }
435
+
436
+ </div>
437
+ </ElCard>
438
+ )
439
+ })}
440
+ {
441
+ dataList.value.length > 0 && pagesNumber.value > 1 && (<ElDivider>
442
+ { (pagesNumber.value > props.currentPage || isPaginationLoading.value) && (<ElIcon loading-rotate size={25} color="#409eff" style={{ margin: '15px auto' }}><Loading></Loading></ElIcon>) }
443
+ { (pagesNumber.value <= props.currentPage) && 'END' }
444
+ </ElDivider>)
445
+ }
446
+
447
+
448
+ </div>
449
+ {/* </ElCheckboxGroup> */}
450
+ </div>
451
+ );
452
+ }
453
+ });
@@ -2,7 +2,7 @@
2
2
  <div style="width: 100%">
3
3
  <!--添加:key="column.prop+'_'+rowIndex"是为了解决多行是行编辑状态时新建的记录的文本框内有值的问题-->
4
4
  <dynamic-input
5
- v-if="(lineEdit.editable && isEditable && row.$editing) || isShowForm"
5
+ v-if="(lineEdit.editable && isEditable && row.$editing && !isContentViewText) || isShowForm"
6
6
  v-model:value="row[column.prop]"
7
7
  :class="requiredClass"
8
8
  :column="column"
@@ -388,6 +388,11 @@ export default {
388
388
  },
389
389
  name: 'NormalColumnContent',
390
390
  props: {
391
+ // 强制文案方式展示
392
+ isContentViewText: {
393
+ type: Boolean,
394
+ default: false
395
+ },
391
396
  column: {
392
397
  type: Object,
393
398
  default: null