UNPKG

vxe-design

Version:

A PC-based visual designer based on Vxe UI, used for building zero-code and low-code platforms

588 lines (587 loc) 18.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _vue = require("vue"); var _comp = require("../../ui/src/comp"); var _core = require("@vxe-ui/core"); var _dom = require("../../ui/src/dom"); var _utils = require("../../ui/src/utils"); var _widgetInfo = require("./widget-info"); var _xeUtils = _interopRequireDefault(require("xe-utils")); var _layoutWidget = _interopRequireDefault(require("./layout-widget")); var _layoutPreview = _interopRequireDefault(require("./layout-preview")); var _layoutSetting = _interopRequireDefault(require("./layout-setting")); var _layoutStyle = _interopRequireDefault(require("./layout-style")); var _defaultSettingData = require("./default-setting-data"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const { menus, getConfig, getIcon, getI18n, renderer, createEvent, renderEmptyElement, useFns } = _core.VxeUI; const { useSize } = useFns; var _default = exports.default = (0, _comp.defineVxeComponent)({ 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.default.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 }, showStyleSetting: { type: Boolean, default: () => getConfig().formDesign.showStyleSetting }, formRender: Object, menuConfig: Object }, emits: ['widget-click', 'widget-add', 'widget-copy', 'widget-remove', 'widget-drag', 'widget-menu', 'menu-click', // 已废弃 'click-widget', 'add-widget', 'copy-widget', 'remove-widget', 'drag-widget'], setup(props, context) { const VxeUIButtonComponent = _core.VxeUI.getComponent('vxe-button'); const { emit, slots } = context; const xID = _xeUtils.default.uniqueId(); const refElem = (0, _vue.ref)(); const refLayoutStyle = (0, _vue.ref)(); const { computeSize } = useSize(props); const reactData = (0, _vue.reactive)({ formData: {}, widgetConfigs: [], widgetObjList: [], dragWidget: null, sortWidget: null, activeWidget: null }); const internalData = (0, _vue.reactive)({}); const refMaps = { refElem }; const computeMenuOpts = (0, _vue.computed)(() => { return Object.assign({}, getConfig().calendar.menuConfig, props.menuConfig); }); const computeMaps = { computeSize }; const $xeFormDesign = { xID, props, context, reactData, internalData, getRefMaps: () => refMaps, getComputeMaps: () => computeMaps }; const createWidget = name => { return new _widgetInfo.FormDesignWidgetInfo($xeFormDesign, name, reactData.widgetObjList); }; const createEmptyWidget = () => { return new _widgetInfo.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.default.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 (0, _vue.nextTick)(); }; const reloadConfig = config => { clearConfig(); return loadConfig(config); }; const getFormConfig = () => { return _xeUtils.default.clone(reactData.formData, true); }; const loadFormConfig = data => { reactData.formData = Object.assign({}, createSettingForm(), data); return (0, _vue.nextTick)(); }; const getWidgetById = id => { const { widgetObjList } = reactData; if (id) { const widgetId = _xeUtils.default.toNumber(id); const rest = _xeUtils.default.findTree(widgetObjList, item => item && item.id === widgetId, { children: 'children' }); if (rest) { return rest.item; } } return null; }; const getWidgetData = () => { const objList = _xeUtils.default.clone(reactData.widgetObjList, true); _xeUtils.default.eachTree(objList, item => { item.model.value = null; }, { children: 'children' }); return objList; }; const loadWidgetData = widgetData => { reactData.widgetObjList = (widgetData || []).map(item => (0, _widgetInfo.configToWidget)(item)); return (0, _vue.nextTick)(); }; const openStyleSetting = () => { const $layoutStyle = refLayoutStyle.value; if ($layoutStyle) { $layoutStyle.openStylePreview(); } return (0, _vue.nextTick)(); }; const clearConfig = () => { reactData.widgetObjList = []; initSettingForm(); return (0, _vue.nextTick)(); }; const dispatchEvent = (type, params, evnt) => { emit(type, createEvent(evnt, { $formDesign: $xeFormDesign }, params)); }; const formDesignMethods = { dispatchEvent, createWidget, createEmptyWidget, getConfig() { return { formConfig: getFormConfig(), widgetData: getWidgetData() }; }, clearConfig, loadConfig, reloadConfig, getFormConfig, loadFormConfig, getWidgetById, getFormData() { const { widgetObjList } = reactData; const formData = {}; _xeUtils.default.eachTree(widgetObjList, widget => { formData[widget.field] = null; }, { children: 'children' }); return formData; }, getWidgetData, loadWidgetData, refreshPreviewView() { const $layoutStyle = refLayoutStyle.value; if ($layoutStyle) { $layoutStyle.updatePreviewView(); } return (0, _vue.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 = (0, _widgetInfo.getWidgetConfig)(name); const widgetCustomGroup = (0, _widgetInfo.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 = (0, _widgetInfo.getWidgetConfig)(widgetName); if (widgetConf.unique) { const existWidgetList = []; _xeUtils.default.eachTree(widgetObjList, obj => { if (obj.name === widgetName) { existWidgetList.push(obj); } }, { children: 'children' }); const status = existWidgetList.length < 1; if (!status) { if (_core.VxeUI.modal) { _core.VxeUI.modal.message({ content: getI18n('vxe.formDesign.error.wdFormUni'), status: 'error', id: 'wdFormUni' }); } } return status; } return true; }; const formDesignPrivateMethods = { validWidgetUnique, handleContextmenuWidget(evnt, item) { const { menuConfig } = props; const menuOpts = computeMenuOpts.value; if (menuConfig ? (0, _utils.isEnableConf)(menuOpts) : menuOpts.enabled) { const { options, visibleMethod } = menuOpts; if (!visibleMethod || visibleMethod({ $formDesign: $xeFormDesign, widget: item, options })) { if (_core.VxeUI.contextMenu) { _core.VxeUI.contextMenu.openByEvent(evnt, { options, events: { optionClick(eventParams) { const { option } = eventParams; const gMenuOpts = menus.get(option.code); const fdmMethod = gMenuOpts ? gMenuOpts.formDesignMenuMethod : null; const params = { menu: option, widget: item, $event: evnt, $formDesign: $xeFormDesign }; if (fdmMethod) { fdmMethod(params, evnt); } dispatchEvent('menu-click', params, eventParams.$event); } } }); } } } dispatchEvent('widget-menu', { widget: item }, evnt); }, handleClickWidget(evnt, item) { if (item && item.name) { evnt.stopPropagation(); reactData.activeWidget = item; dispatchEvent('widget-click', { widget: item }, evnt); // click-widget 已废弃 dispatchEvent('click-widget', { widget: item }, evnt); } }, handleCopyWidget(evnt, widget) { const { widgetObjList } = reactData; const rest = _xeUtils.default.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]; dispatchEvent('widget-copy', { widget, newWidget }, evnt); // copy-widget 已废弃 dispatchEvent('copy-widget', { widget: newWidget }, evnt); } } }, handleRemoveWidget(evnt, widget) { const { widgetObjList } = reactData; const rest = _xeUtils.default.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]; dispatchEvent('widget-remove', { widget }, evnt); // remove-widget 已废弃 dispatchEvent('remove-widget', { widget }, evnt); } } }; const createSettingForm = () => { const { formRender, showPc, showMobile } = props; const defConf = (0, _defaultSettingData.getDefaultSettingFormData)({ pcVisible: showPc, mobileVisible: showMobile }); let customConf = {}; // 如果为自定义渲染 if (formRender) { const compConf = renderer.get(formRender.name); const createFormConfig = compConf ? compConf.createFormDesignSettingFormConfig : null; customConf = (createFormConfig ? createFormConfig({}) : {}) || {}; } return Object.assign({}, defConf, customConf); }; const initSettingForm = () => { reactData.formData = createSettingForm(); }; const openStylePreviewEvent = () => { openStyleSetting(); }; Object.assign($xeFormDesign, formDesignMethods, formDesignPrivateMethods); const renderLayoutHeader = () => { const { showStyleSetting } = props; const titleSlot = slots.title; const titlePrefixSlot = slots.titlePrefix || slots['title-prefix']; const titleSuffixSlot = slots.titleSuffix || slots['title-suffix'] || slots.extra; if (!(titlePrefixSlot || titleSlot || titleSuffixSlot || showStyleSetting)) { return renderEmptyElement($xeFormDesign); } return (0, _vue.h)('div', { class: 'vxe-form-design--header-wrapper' }, [(0, _vue.h)('div', { class: 'vxe-form-design--header-left' }, titlePrefixSlot ? titlePrefixSlot({}) : []), (0, _vue.h)('div', { class: 'vxe-form-design--header-middle' }, titleSlot ? titleSlot({}) : []), (0, _vue.h)('div', { class: 'vxe-form-design--header-right' }, [titleSuffixSlot ? (0, _vue.h)('div', { class: 'vxe-form-design--header-extra' }, titleSuffixSlot({})) : renderEmptyElement($xeFormDesign), showStyleSetting ? (0, _vue.h)('div', { class: 'vxe-form-design--header-setting' }, [(0, _vue.h)(VxeUIButtonComponent, { mode: 'text', status: 'primary', icon: getIcon().FORM_DESIGN_STYLE_SETTING, content: getI18n('vxe.formDesign.styleSetting.btn'), onClick: openStylePreviewEvent })]) : renderEmptyElement($xeFormDesign)])]); }; const renderVN = () => { const { height, showHeader } = props; const vSize = computeSize.value; const headerSlot = slots.header; const footerSlot = slots.footer; return (0, _vue.h)('div', { ref: refElem, class: ['vxe-form-design', { [`size--${vSize}`]: vSize }], style: height ? { height: (0, _dom.toCssUnit)(height) } : null }, [showHeader || headerSlot ? (0, _vue.h)('div', { class: 'vxe-form-design--header' }, headerSlot ? headerSlot({}) : renderLayoutHeader()) : (0, _vue.createCommentVNode)(), (0, _vue.h)('div', { class: 'vxe-form-design--body' }, [(0, _vue.h)(_layoutWidget.default), (0, _vue.h)(_layoutPreview.default), (0, _vue.h)(_layoutSetting.default), (0, _vue.h)(_layoutStyle.default, { ref: refLayoutStyle })]), footerSlot ? (0, _vue.h)('div', { class: 'vxe-form-design--footer' }, footerSlot ? footerSlot({}) : []) : (0, _vue.createCommentVNode)()]); }; $xeFormDesign.renderVN = renderVN; (0, _vue.watch)(() => props.widgets, () => { updateWidgetConfigs(); }); (0, _vue.watch)(() => props.widgets, () => { updateWidgetConfigs(); }); (0, _vue.watch)(() => props.config, value => { loadConfig(value || {}); }); initSettingForm(); updateWidgetConfigs(); if (props.config) { loadConfig(props.config); } (0, _vue.provide)('$xeFormDesign', $xeFormDesign); return $xeFormDesign; }, render() { return this.renderVN(); } });