UNPKG

vxe-pc-ui

Version:
594 lines (564 loc) 21.1 kB
import { ref, PropType, defineComponent, inject, h, createCommentVNode, TransitionGroup, computed, nextTick } from 'vue' import { VxeUI, renderer, getIcon, getI18n } from '@vxe-ui/core' import XEUtils from 'xe-utils' import { hasFormDesignLayoutType } from '../src/util' import { WidgetSubtableFormObjVO } from './subtable-data' import { getSlotVNs } from '../../ui/src/vn' import { useWidgetName } from '../../form-design/src/use' import VxeFormItemComponent from '../../form/src/form-item' import VxeButtonComponent from '../../button/src/button' import VxeCheckboxComponent from '../../checkbox/src/checkbox' import type { VxeGlobalRendererHandles, VxeFormDesignConstructor, VxeFormDesignDefines, VxeFormDesignPrivateMethods, VxeFormViewConstructor, VxeFormViewPrivateMethods } from '../../../types' import type { VxeGridComponent, VxeGridPropTypes, VxeGridProps, VxeGridInstance } from '../../../types/components/grid' import type { VxeTableDefines } from '../../../types/components/table' import type { VxeColumnPropTypes } from '../../../types/components/column' const ViewSubItemComponent = defineComponent({ props: { parentWidget: { type: Object as PropType<VxeFormDesignDefines.WidgetObjItem<WidgetSubtableFormObjVO>>, default: () => ({}) }, widget: { type: Object as PropType<VxeFormDesignDefines.WidgetObjItem<WidgetSubtableFormObjVO>>, default: () => ({}) }, childIndex: { type: Number, default: 0 } }, emits: [], setup (props) { const $xeFormDesign = inject<(VxeFormDesignConstructor & VxeFormDesignPrivateMethods) | null>('$xeFormDesign', null) const $xeFormView = inject<(VxeFormViewConstructor & VxeFormViewPrivateMethods) | null>('$xeFormView', null) if (!$xeFormDesign) { return () => [] } const { reactData: formDesignReactData } = $xeFormDesign const sortDragstartSubItemEvent = (evnt: DragEvent) => { evnt.stopPropagation() const divEl = evnt.currentTarget as HTMLDivElement const dataTransfer = evnt.dataTransfer const widgetId = divEl.getAttribute('data-widget-id') || '' const dragWidget = $xeFormDesign.getWidgetById(widgetId) if (dataTransfer) { dataTransfer.setData('text/plain', widgetId) } formDesignReactData.sortWidget = dragWidget formDesignReactData.dragWidget = null } const sortDragenterSubItemEvent = (evnt: DragEvent) => { const { parentWidget, childIndex } = props const { widgetObjList, sortWidget } = formDesignReactData const targetWidget = parentWidget.children[childIndex] const formDesignInternalData = $xeFormDesign.internalData const { lastDragTime } = formDesignInternalData evnt.stopPropagation() if (lastDragTime && lastDragTime > Date.now() - 300) { evnt.preventDefault() return } if (sortWidget && targetWidget && parentWidget) { if (sortWidget.id === parentWidget.id) { return } if (sortWidget.id === targetWidget.id) { return } if (hasFormDesignLayoutType(sortWidget)) { return } if (targetWidget && !hasFormDesignLayoutType(targetWidget)) { const currRest = XEUtils.findTree(widgetObjList, item => item.id === sortWidget.id, { children: 'children' }) if (currRest) { const { item, index, items, parent } = currRest // 如果是 subtable 内移动 if (parent && parent.id === parentWidget.id) { parentWidget.children[childIndex] = item parentWidget.children[index] = targetWidget } else { parentWidget.children.splice(childIndex, 0, item) items.splice(index, 1) } formDesignInternalData.lastDragTime = Date.now() $xeFormDesign.dispatchEvent('drag-widget', { widget: item }, evnt) } } } } return () => { const { widget } = props const { dragWidget, activeWidget, sortWidget } = formDesignReactData const name = widget ? widget.name : '' const compConf = renderer.get(name) || {} const renderSubtableView = compConf.renderFormDesignWidgetSubtableEditView || compConf.renderFormDesignWidgetSubtableCellView || compConf.renderFormDesignWidgetSubtableDefaultView const renderWidgetDesignView = compConf.renderFormDesignWidgetEdit || compConf.renderFormDesignWidgetView const renderOpts: VxeGlobalRendererHandles.RenderFormDesignWidgetViewOptions = widget || { name } const isEditMode = !!$xeFormDesign const defParams: VxeGlobalRendererHandles.RenderFormDesignWidgetViewParams = { widget, readonly: false, disabled: false, isEditMode, isViewMode: !isEditMode, $formDesign: $xeFormDesign, $formView: $xeFormView } const isActive = activeWidget && widget && activeWidget.id === widget.id const subOpts = { name } const subParams = { $table: null, $grid: null, seq: '', column: { field: widget.field, title: widget.title } as VxeTableDefines.ColumnInfo, columnIndex: 0, $columnIndex: 0, _columnIndex: 0, rowid: '', row: {}, rowIndex: 0, $rowIndex: 0, _rowIndex: 0, isEdit: false, isHidden: false, fixed: null, type: '', level: 1, visibleData: [], items: [], data: [], widget: widget } return h('div', { class: ['vxe-form-design--widget-subtable-view-item', { 'is--active': isActive, 'is--sort': sortWidget && widget && sortWidget.id === widget.id, 'is--drag': dragWidget && widget && dragWidget.id === widget.id }], draggable: true, 'data-widget-id': widget.id, onDragstart: sortDragstartSubItemEvent, onDragenter: sortDragenterSubItemEvent, onClick (evnt: KeyboardEvent) { if (widget) { $xeFormDesign.handleClickWidget(evnt, widget) } } }, [ h('div', { class: 'vxe-form-design--widget-subtable-view-item-wrapper' }, [ h('div', { class: 'vxe-form-design--widget-subtable-view-item-box vxe-form--item-row' }, renderSubtableView ? h(VxeFormItemComponent, { class: ['vxe-form-design--widget-render-form-item'], title: widget.title, field: widget.field, itemRender: {} }, { default () { return getSlotVNs(renderSubtableView(subOpts, subParams)) } }) : (renderWidgetDesignView ? getSlotVNs(renderWidgetDesignView(renderOpts, defParams)) : [])), isActive ? h('div', { class: 'vxe-form-design--preview-item-operate' }, [ h(VxeButtonComponent, { icon: getIcon().FORM_DESIGN_WIDGET_COPY, status: 'primary', size: 'mini', circle: true, onClick (params) { $xeFormDesign.handleCopyWidget(params.$event, widget) } }), h(VxeButtonComponent, { icon: getIcon().FORM_DESIGN_WIDGET_DELETE, status: 'danger', size: 'mini', circle: true, onClick (params) { $xeFormDesign.handleRemoveWidget(params.$event, widget) } }) ]) : createCommentVNode() ]) ]) } } }) export const WidgetSubtableEditComponent = defineComponent({ props: { renderOpts: { type: Object as PropType<VxeGlobalRendererHandles.RenderFormDesignWidgetEditOptions>, default: () => ({}) }, renderParams: { type: Object as PropType<VxeGlobalRendererHandles.RenderFormDesignWidgetEditParams<WidgetSubtableFormObjVO>>, default: () => ({}) } }, emits: [], setup (props) { const $xeFormDesign = inject<(VxeFormDesignConstructor & VxeFormDesignPrivateMethods) | null>('$xeFormDesign', null) if (!$xeFormDesign) { return () => [] } const { reactData: formDesignReactData } = $xeFormDesign const handleDragoverWrapperEvent = (evnt: DragEvent) => { const { sortWidget, widgetObjList } = formDesignReactData const { renderParams } = props const { widget } = renderParams evnt.stopPropagation() if (!sortWidget || !widget || widget.id === sortWidget.id) { return } if (hasFormDesignLayoutType(sortWidget)) { if (VxeUI.modal) { VxeUI.modal.message({ content: getI18n('vxe.formDesign.widgetProp.subtableProp.errSubDrag'), status: 'error', id: 'errSubDrag' }) } return } // 如果控件不在当前子表中,则拖进去 if (widget.name && !widget.children.some(item => item.id === sortWidget.id)) { const rest = XEUtils.findTree(widgetObjList, item => item.id === sortWidget.id, { children: 'children' }) if (rest) { const { item, index, items } = rest formDesignReactData.sortWidget = null formDesignReactData.activeWidget = item widget.children.push(item) items.splice(index, 1) formDesignReactData.sortWidget = item } } } const handleDragenterWrapperEvent = (evnt: DragEvent) => { evnt.stopPropagation() } return () => { const { renderParams } = props const { widget } = renderParams const { title, children, options } = widget const { showCheckbox } = options return h(VxeFormItemComponent, { title, className: 'vxe-form-design--widget-subtable-form-item' }, { default () { return h('div', { class: 'vxe-form-design--widget-subtable-view', onDragenter: handleDragenterWrapperEvent, onDragover: handleDragoverWrapperEvent }, [ h('div', { class: 'vxe-form-design--widget-subtable-view-left' }, [ showCheckbox ? h('div', { class: 'vxe-form-design--widget-subtable-col' }, [ h('div', { class: 'vxe-form-design--widget-subtable-head' }, [ h(VxeCheckboxComponent) ]), h('div', { class: 'vxe-form-design--widget-subtable-body' }, [ h(VxeCheckboxComponent) ]) ]) : createCommentVNode(), h('div', { class: 'vxe-form-design--widget-subtable-col' }, [ h('div', { class: 'vxe-form-design--widget-subtable-head' }, getI18n('vxe.formDesign.widgetProp.subtableProp.seqTitle')), h('div', { class: 'vxe-form-design--widget-subtable-body' }, '1') ]) ]), h('div', { class: 'vxe-form-design--widget-subtable-view-right' }, [ h('div', { class: 'vxe-form-design--widget-subtable-view-wrapper' }, [ h(TransitionGroup, { class: 'vxe-form-design--widget-subtable-view-list', tag: 'div', name: 'vxe-form-design--widget-subtable-view-list' }, { default: () => { return children ? children.map((childWidget, childIndex) => { return h(ViewSubItemComponent, { key: childWidget.id, parentWidget: widget, widget: childWidget, childIndex }) }) : [] } }), h('div', { key: 'empty', class: 'vxe-form-design--widget-subtable-view-empty' }, getI18n('vxe.formDesign.widgetProp.subtableProp.colPlace')) ]) ]) ]) } }) } } }) export const WidgetSubtableViewComponent = defineComponent({ props: { renderOpts: { type: Object as PropType<VxeGlobalRendererHandles.RenderFormDesignWidgetViewOptions>, default: () => ({}) }, renderParams: { type: Object as PropType<VxeGlobalRendererHandles.RenderFormDesignWidgetViewParams<WidgetSubtableFormObjVO>>, default: () => ({}) } }, emits: [], setup (props) { const VxeTableGridComponent = VxeUI.getComponent<VxeGridComponent>('VxeGrid') const $xeFormView = inject<(VxeFormViewConstructor & VxeFormViewPrivateMethods) | null>('$xeFormView', null) const { computeKebabCaseName } = useWidgetName(props) const refGrid = ref<VxeGridInstance>() const defaultDataList = ref([ {} ]) const computeFormReadonly = computed(() => { if ($xeFormView) { return $xeFormView.props.readonly } return false }) const computeSubtableColumns = computed(() => { const { renderParams } = props const { widget } = renderParams const { children, options } = widget const formReadonly = computeFormReadonly.value const columns: VxeGridPropTypes.Columns = [] if (options.showCheckbox) { columns.push({ type: 'checkbox', width: 60, fixed: 'left' }) } columns.push({ type: 'seq', width: 60, fixed: 'left' }) if (children) { children.forEach(childWidget => { const { name } = childWidget const compConf = renderer.get(name) || {} const parseSubtableColumn = compConf.parseFormDesignWidgetSubtableColumn let colConf: VxeGridPropTypes.Column = { field: childWidget.field, title: childWidget.title } if (parseSubtableColumn) { colConf = Object.assign(colConf, parseSubtableColumn({ $formView: $xeFormView, name: childWidget.name, widget: childWidget, readonly: !!formReadonly })) } else { if (formReadonly) { colConf.cellRender = { name: childWidget.name, props: childWidget.options } } else { colConf.editRender = { name: childWidget.name, props: childWidget.options } } } const renderSubtableDefaultView = compConf.renderFormDesignWidgetSubtableDefaultView const renderSubtableCellView = compConf.renderFormDesignWidgetSubtableCellView || renderSubtableDefaultView const renderSubtableEditView = compConf.renderFormDesignWidgetSubtableEditView const colSlots: VxeColumnPropTypes.Slots = {} if (renderSubtableDefaultView || renderSubtableCellView) { colSlots.default = (slotParams) => { const { isEdit, column } = slotParams const { editRender, cellRender } = column const params = Object.assign({ widget: childWidget }, slotParams) if (isEdit && editRender) { if (renderSubtableCellView) { return getSlotVNs(renderSubtableCellView(editRender, params)) } } if (renderSubtableDefaultView) { return getSlotVNs(renderSubtableDefaultView(cellRender || {}, params)) } return [] } } if (renderSubtableEditView) { colSlots.edit = (slotParams) => { const { column } = slotParams const { editRender } = column const params = Object.assign({ widget: childWidget }, slotParams) return getSlotVNs(renderSubtableEditView(editRender, params)) } } colConf.slots = colSlots columns.push(colConf) }) } if (!formReadonly) { columns.push({ field: 'action', title: '操作', fixed: 'right', width: 80, slots: { default ({ row }) { return h(VxeButtonComponent, { mode: 'text', icon: 'vxe-icon-delete', status: 'error', onClick () { removeSubRow(row) } }) } } }) } return columns }) const computeGridOptions = computed(() => { const { renderParams } = props const { widget, isEditMode } = renderParams const subtableColumns = computeSubtableColumns.value const formReadonly = computeFormReadonly.value const gridConf: VxeGridProps & Required<Pick<VxeGridProps, 'toolbarConfig'>> = { border: true, showOverflow: true, height: 300, columnConfig: { resizable: true, minWidth: 140 }, rowConfig: { keyField: '_id' }, data: isEditMode ? defaultDataList.value : $xeFormView ? $xeFormView.getItemValue(widget) : null, columns: subtableColumns, toolbarConfig: { zoom: true, custom: false, slots: { buttons: 'toolbarButtons' } } } if (!formReadonly) { gridConf.keepSource = true gridConf.editConfig = { mode: 'row', trigger: 'click', showStatus: true } } return gridConf }) const getSubRecord = () => { const { renderParams } = props const { widget } = renderParams const record: Record<string, any> = { _id: Date.now() } XEUtils.each(widget.children, childWidget => { record[childWidget.field] = null }) return record } const addSubRowEvent = () => { const { renderParams } = props const { widget } = renderParams if ($xeFormView) { let list: any[] = $xeFormView.getItemValue(widget) if (!XEUtils.isArray(list)) { list = [] } const newRow = getSubRecord() list.unshift(newRow) $xeFormView.setItemValue(widget, list.slice(0)).then(() => { return nextTick().then(() => { const $grid = refGrid.value if ($grid) { $grid.setEditRow(newRow) } }) }) } } const removeSubRow = (row: any) => { const { renderParams } = props const { widget } = renderParams if ($xeFormView) { const list: any[] = $xeFormView.getItemValue(widget) if (list) { $xeFormView.setItemValue(widget, list.filter(item => item._id !== row._id)) } } } return () => { const { renderParams } = props const { widget } = renderParams const kebabCaseName = computeKebabCaseName.value const gridOptions = computeGridOptions.value const formReadonly = computeFormReadonly.value return h(VxeFormItemComponent, { class: ['vxe-form-design--widget-render-form-item', `widget-${kebabCaseName}`], title: widget.title, field: widget.field, span: 24 }, { default () { return VxeTableGridComponent ? h(VxeTableGridComponent, { ...gridOptions, ref: refGrid }, { toolbarButtons () { return formReadonly ? [] : [ h(VxeButtonComponent, { content: '新增', icon: 'vxe-icon-add', status: 'primary', onClick: addSubRowEvent }) ] } }) : createCommentVNode() } }) } } })