agilebuilder-ui 1.1.12 → 1.1.13-tmp2

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