UNPKG

vxe-pc-ui

Version:
471 lines (470 loc) 18.2 kB
import { defineComponent, ref, h, reactive, provide, watch, nextTick, createCommentVNode } from 'vue'; import { VxeUI, getConfig, getIcon, getI18n, renderer, useSize, createEvent, renderEmptyElement } from '../../ui'; import { toCssUnit } from '../../ui/src/dom'; import { FormDesignWidgetInfo, getWidgetConfig, getWidgetConfigCustomGroup, configToWidget } from './widget-info'; import XEUtils from 'xe-utils'; import VxeButtonComponent from '../../button/src/button'; import LayoutWidgetComponent from './layout-widget'; import LayoutPreviewComponent from './layout-preview'; import LayoutSettingComponent from './layout-setting'; import LayoutStyleComponent from './layout-style'; import { getDefaultSettingFormData } from './default-setting-data'; export default defineComponent({ name: 'VxeFormDesign', props: { size: { type: String, default: () => getConfig().formDesign.size || getConfig().size }, config: Object, height: { type: [String, Number], default: () => getConfig().formDesign.height }, widgets: { type: Array, default: () => XEUtils.clone(getConfig().formDesign.widgets) || [] }, showHeader: { type: Boolean, default: () => getConfig().formDesign.showHeader }, showPc: { type: Boolean, default: () => getConfig().formDesign.showPc }, showMobile: { type: Boolean, default: () => getConfig().formDesign.showMobile }, formRender: Object }, emits: [ 'click-widget', 'add-widget', 'copy-widget', 'remove-widget', 'drag-widget' ], setup(props, context) { const { emit, slots } = context; const xID = XEUtils.uniqueId(); const refElem = ref(); const refLayoutStyle = ref(); const { computeSize } = useSize(props); const reactData = reactive({ formData: {}, widgetConfigs: [], widgetObjList: [], dragWidget: null, sortWidget: null, activeWidget: null }); const internalData = reactive({}); const refMaps = { refElem }; const computeMaps = { computeSize }; const $xeFormDesign = { xID, props, context, reactData, internalData, getRefMaps: () => refMaps, getComputeMaps: () => computeMaps }; const createWidget = (name) => { return new FormDesignWidgetInfo($xeFormDesign, name, reactData.widgetObjList); }; const createEmptyWidget = () => { return new FormDesignWidgetInfo($xeFormDesign, '', reactData.widgetObjList); }; const loadConfig = (config) => { if (config) { const { formConfig, widgetData } = config; if (formConfig) { loadFormConfig(formConfig); } if (widgetData) { loadWidgetData(widgetData); } } const { activeWidget, widgetObjList } = reactData; if (activeWidget) { const rest = XEUtils.findTree(widgetObjList, item => item.id === activeWidget.id, { children: 'children' }); if (rest) { reactData.activeWidget = rest.item; } else { reactData.activeWidget = widgetObjList[0] || null; } } else { reactData.activeWidget = widgetObjList[0] || null; } return nextTick(); }; const reloadConfig = (config) => { clearConfig(); return loadConfig(config); }; const getFormConfig = () => { return XEUtils.clone(reactData.formData, true); }; const loadFormConfig = (data) => { reactData.formData = Object.assign({}, createSettingForm(), data); return nextTick(); }; const getWidgetById = (id) => { const { widgetObjList } = reactData; if (id) { const widgetId = XEUtils.toNumber(id); const rest = XEUtils.findTree(widgetObjList, item => item && item.id === widgetId, { children: 'children' }); if (rest) { return rest.item; } } return null; }; const getWidgetData = () => { const objList = XEUtils.clone(reactData.widgetObjList, true); XEUtils.eachTree(objList, item => { item.model.value = null; }, { children: 'children' }); return objList; }; const loadWidgetData = (widgetData) => { reactData.widgetObjList = (widgetData || []).map(item => configToWidget(item)); return nextTick(); }; const openStyleSetting = () => { const $layoutStyle = refLayoutStyle.value; if ($layoutStyle) { $layoutStyle.openStylePreview(); } return nextTick(); }; const clearConfig = () => { reactData.widgetObjList = []; initSettingForm(); return nextTick(); }; const formDesignMethods = { dispatchEvent(type, params, evnt) { emit(type, createEvent(evnt, { $xeFormDesign }, params)); }, createWidget, createEmptyWidget, getConfig() { return { formConfig: getFormConfig(), widgetData: getWidgetData() }; }, clearConfig, loadConfig, reloadConfig, getFormConfig, loadFormConfig, getWidgetById, getFormData() { const { widgetObjList } = reactData; const formData = {}; XEUtils.eachTree(widgetObjList, widget => { formData[widget.field] = null; }, { children: 'children' }); return formData; }, getWidgetData, loadWidgetData, refreshPreviewView() { const $layoutStyle = refLayoutStyle.value; if ($layoutStyle) { $layoutStyle.updatePreviewView(); } return nextTick(); }, openStyleSetting }; const updateWidgetConfigs = () => { const { widgets } = props; const widgetConfs = []; const baseWidgets = []; const layoutWidgets = []; const advancedWidgets = []; const customGroups = []; renderer.forEach((item, name) => { const { createFormDesignWidgetConfig } = item; if (createFormDesignWidgetConfig) { const widthItem = createWidget(name); const widgetConf = getWidgetConfig(name); const widgetCustomGroup = getWidgetConfigCustomGroup(name, $xeFormDesign); // 如果自定义组 if (widgetCustomGroup) { const cusGroup = customGroups.find(item => item.title === widgetCustomGroup); if (cusGroup) { cusGroup.children.push(widthItem); } else { customGroups.push({ title: widgetCustomGroup, children: [widthItem] }); } } else { switch (widgetConf.group) { case 'layout': layoutWidgets.push(widthItem); break; case 'advanced': advancedWidgets.push(widthItem); break; default: // 已废弃 title if (!['title'].includes(widthItem.name)) { baseWidgets.push(widthItem); } break; } } } }); if (baseWidgets.length) { widgetConfs.push({ group: 'base', children: baseWidgets }); } if (layoutWidgets.length) { widgetConfs.push({ group: 'layout', children: layoutWidgets }); } if (advancedWidgets.length) { widgetConfs.push({ group: 'advanced', children: advancedWidgets }); } if (customGroups.length) { widgetConfs.push(...customGroups); } if (widgets && widgets.length) { reactData.widgetConfigs = props.widgets.map(config => { return { title: config.customGroup, group: config.group, children: config.children ? config.children.map(name => { const widthItem = createWidget(name); return widthItem; }) : [] }; }); } else { reactData.widgetConfigs = widgetConfs; } }; const validWidgetUnique = (widgetName) => { const { widgetObjList } = reactData; const widgetConf = getWidgetConfig(widgetName); if (widgetConf.unique) { const existWidgetList = []; XEUtils.eachTree(widgetObjList, obj => { if (obj.name === widgetName) { existWidgetList.push(obj); } }, { children: 'children' }); const status = existWidgetList.length < 1; if (!status) { if (VxeUI.modal) { VxeUI.modal.message({ content: getI18n('vxe.formDesign.error.wdFormUni'), status: 'error', id: 'wdFormUni' }); } } return status; } return true; }; const formDesignPrivateMethods = { validWidgetUnique, handleClickWidget(evnt, item) { if (item && item.name) { evnt.stopPropagation(); reactData.activeWidget = item; formDesignMethods.dispatchEvent('click-widget', { widget: item }, evnt); } }, handleCopyWidget(evnt, widget) { const { widgetObjList } = reactData; const rest = XEUtils.findTree(widgetObjList, obj => obj.id === widget.id, { children: 'children' }); if (rest) { evnt.stopPropagation(); if (validWidgetUnique(widget.name)) { const { path } = rest; const rootIndex = Number(path[0]); const newWidget = createWidget(widget.name); // 标题副本 if (newWidget.title) { newWidget.title = getI18n('vxe.formDesign.widget.copyTitle', [`${widget.title}`.replace(getI18n('vxe.formDesign.widget.copyTitle', ['']), '')]); } if (rootIndex >= widgetObjList.length - 1) { widgetObjList.push(newWidget); } else { widgetObjList.splice(rootIndex + 1, 0, newWidget); } reactData.activeWidget = newWidget; reactData.widgetObjList = [...widgetObjList]; formDesignMethods.dispatchEvent('copy-widget', { widget, newWidget }, evnt); } } }, handleRemoveWidget(evnt, widget) { const { widgetObjList } = reactData; const rest = XEUtils.findTree(widgetObjList, obj => obj.id === widget.id, { children: 'children' }); if (rest) { const { index, parent, items } = rest; evnt.stopPropagation(); if (index >= items.length - 1) { reactData.activeWidget = items[index - 1]; } else { reactData.activeWidget = items[index + 1] || null; } // 如果是行控件,使用空的控件占位 if (parent && parent.name === 'row') { items[index] = createEmptyWidget(); } else { items.splice(index, 1); } reactData.widgetObjList = [...widgetObjList]; formDesignMethods.dispatchEvent('remove-widget', { widget }, evnt); } } }; const createSettingForm = () => { const { formRender, showPc, showMobile } = props; let conf = getDefaultSettingFormData({ pcVisible: showPc, mobileVisible: showMobile }); // 如果为自定义渲染 if (formRender) { const compConf = renderer.get(formRender.name); const createFormConfig = compConf ? compConf.createFormDesignSettingFormConfig : null; conf = (createFormConfig ? createFormConfig({}) : {}) || {}; } return conf; }; const initSettingForm = () => { reactData.formData = createSettingForm(); }; const openStylePreviewEvent = () => { openStyleSetting(); }; Object.assign($xeFormDesign, formDesignMethods, formDesignPrivateMethods); const renderLayoutHeader = () => { const extraSlot = slots.extra; return h('div', { class: 'vxe-form-design--header-wrapper' }, [ h('div', { class: 'vxe-form-design--header-left' }), h('div', { class: 'vxe-form-design--header-middle' }), h('div', { class: 'vxe-form-design--header-right' }, [ extraSlot ? h('div', { class: 'vxe-form-design--header-extra' }, extraSlot({})) : renderEmptyElement($xeFormDesign), h('div', { class: 'vxe-form-design--header-setting' }, [ h(VxeButtonComponent, { mode: 'text', status: 'primary', icon: getIcon().FORM_DESIGN_STYLE_SETTING, content: getI18n('vxe.formDesign.styleSetting.btn'), onClick: openStylePreviewEvent }) ]) ]) ]); }; const renderVN = () => { const { height, showHeader } = props; const vSize = computeSize.value; const headerSlot = slots.header; const footerSlot = slots.footer; return h('div', { ref: refElem, class: ['vxe-form-design', { [`size--${vSize}`]: vSize }], style: height ? { height: toCssUnit(height) } : null }, [ showHeader || headerSlot ? h('div', { class: 'vxe-form-design--header' }, headerSlot ? headerSlot({}) : renderLayoutHeader()) : createCommentVNode(), h('div', { class: 'vxe-form-design--body' }, [ h(LayoutWidgetComponent), h(LayoutPreviewComponent), h(LayoutSettingComponent), h(LayoutStyleComponent, { ref: refLayoutStyle }) ]), footerSlot ? h('div', { class: 'vxe-form-design--footer' }, footerSlot ? footerSlot({}) : []) : createCommentVNode() ]); }; $xeFormDesign.renderVN = renderVN; watch(() => props.widgets, () => { updateWidgetConfigs(); }); watch(() => props.widgets, () => { updateWidgetConfigs(); }); watch(() => props.config, (value) => { loadConfig(value || {}); }); initSettingForm(); updateWidgetConfigs(); if (props.config) { loadConfig(props.config); } provide('$xeFormDesign', $xeFormDesign); return $xeFormDesign; }, render() { return this.renderVN(); } });