vxe-pc-ui
Version:
A vue based PC component library
471 lines (470 loc) • 18.2 kB
JavaScript
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();
}
});