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
JavaScript
;
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();
}
});