magic-page-designer
Version:
magic-page-designer 是一个基于 vue 的在线页面快速开发平台,主要把所有的 vue 代码都改为在线配置,最终获得一个 json 格式的页面,你可以把它存放到服务器的任何地方:数据库、静态文件、redis 等。最方便的是可以在线修改页面,再也不用担心生产出问题了,还得打开 IDE,修改测试打包,直接在线编码,所见即所得。还可以配合 [magic-api](https://gitee.com/ssssssss-team/magic-api) 使用,完全抛弃 IDE,随时随地 code w
285 lines (283 loc) • 10.3 kB
text/typescript
import { isArray, uuid } from './utils'
import { isCssVariableName } from './regexUtil'
import Vue from 'vue'
import library from '../library'
import { PageDom, ComponentItemExt, MpdConfig, ConfigDetailType } from '../library/page-object'
import { mpdMessage } from './messageUtil'
import _ from 'lodash'
/**
* 一维数组转对象
* @param arr 需要转换的数组对象
* @param keyField 作为key的字段名
* @param valueField 作为value的字段名
* @returns
*/
export const arrayToObj = function (
arr: Array<{ [key: string]: any }>,
keyField: string = 'key',
valueField: string = 'value'
): { [key: string]: any } {
if (!isArray(arr)) {
return {}
}
const obj: { [key: string]: any } = {}
arr.forEach((item) => {
if (isCssVariableName(item[keyField]) && item[valueField]) {
obj[item[keyField]] = item[valueField]
}
})
return obj
}
/**
* 初始化dom对象的默认值
* @param {PageDom} domItem
*/
export const initDomValue = function (domItem: PageDom) {
// 节点名称
Vue.set(domItem, 'title', domItem.title || '')
// 组件配置:页面dom配置
if (domItem.mpdConfig) {
// 组件配置:使用的组件名
Vue.set(domItem.mpdConfig, 'component', domItem.mpdConfig.component || domItem.id)
// 组件配置:双向绑定属性
Vue.set(domItem.mpdConfig, 'model', domItem.mpdConfig.model || {})
// 组件配置:传递的属性
Vue.set(domItem.mpdConfig, 'attr', domItem.mpdConfig.attr || {})
// 组件配置:class
Vue.set(domItem.mpdConfig, 'class', domItem.mpdConfig.class || '')
// 组件配置:style
Vue.set(domItem.mpdConfig, 'style', domItem.mpdConfig.style || [])
// 组件配置:v-on绑定的事件
Vue.set(domItem.mpdConfig, 'event', domItem.mpdConfig.event || {})
// 组件配置:text内容
Vue.set(domItem.mpdConfig, 'text', domItem.mpdConfig.text || '')
// 组件配置:slot内容
if (!domItem.mpdConfig.slot) {
const comConfig: PageDom = <PageDom>library.getLibraryDataMap(domItem.mpdConfig.component)
if (comConfig && comConfig.mpdConfig && comConfig.mpdConfig.slot) {
Vue.set(domItem.mpdConfig, 'slot', _.cloneDeep(comConfig.mpdConfig.slot))
}
} else if (domItem.mpdConfig.slot.length > 0) {
domItem.mpdConfig.slot.forEach((item) => {
initDomValue(item)
})
}
// 组件配置:记录一些属性用的配置,用于设计器配置
Vue.set(domItem.mpdConfig, 'configTmp', domItem.mpdConfig.configTmp || {})
} else {
const mpdConfig: MpdConfig = {
component: domItem.id,
model: {},
attr: {},
class: '',
style: [],
event: {},
configTmp: {}
}
Vue.set(domItem, 'mpdConfig', mpdConfig)
}
// 子节点
Vue.set(domItem, 'children', domItem.children || [])
// id唯一标识,由uuid生成
if (!domItem.id || domItem.id.length !== 36) {
Vue.set(domItem, 'id', uuid())
}
// 将componentConfig的配置转换一下
transformComponentConfig(domItem)
// 移除扩展参数
delete domItem.ext
// 继续初始化子节点
initArrayDomValue(domItem.children)
}
/**
* 初始化数组dom对象的默认值
* @param {Array} arrayDomItem
*/
export const initArrayDomValue = function (arrayDomItem?: Array<PageDom>): void {
if (arrayDomItem && isArray(arrayDomItem) && arrayDomItem.length > 0) {
arrayDomItem.forEach((item) => {
initDomValue(item)
})
}
}
/**
* 转换组件配置
* @param {PageDom} domItem
*/
export const transformComponentConfig = function (domItem: PageDom): void {
if (domItem.ext && domItem.ext.componentConfig) {
domItem.ext.componentConfig.forEach((item) => {
if (domItem.mpdConfig && item.defaultValue !== undefined) {
Vue.set(domItem.mpdConfig[item.type] as object, item.name, item.defaultValue)
}
})
}
}
/**
* 是否含有对应的配置属性
* @param domItem
* @returns boolean
*/
export const hasConfigAttr = function (domItem: PageDom, attr: string): boolean {
if (domItem.mpdConfig) {
return domItem.mpdConfig.hasOwnProperty(attr)
}
return false
}
/**
* 是否可以添加到子列表
* @param {PageDom} parent 父元素
* @param {PageDom} item 要判断的元素
* @returns {Boolean}
*/
export const isCanPushChildren = function (parent: PageDom, item: PageDom): Boolean {
const parentMpdConfig: MpdConfig = parent.mpdConfig || {}
const foundParentData: PageDom = <PageDom>library.getLibraryDataMap(parentMpdConfig.component || parent.id)
const foundItemData: PageDom = <PageDom>(
library.getLibraryDataMap(item.mpdConfig ? item.mpdConfig.component || item.id : item.id)
)
let msg: string = ''
const itemMpdConfig: MpdConfig = item.mpdConfig || {}
if (!foundParentData) {
msg = `没有在组件库中找到【${parent.title}(${parentMpdConfig.component})】的配置`
} else if (!foundItemData) {
msg = `没有在组件库中找到【${item.title}(${itemMpdConfig.component})】的配置`
} else if (foundParentData.ext && foundParentData.ext.hasOwnProperty('childrenComponent')) {
// 判断子元素配置
const extData: ComponentItemExt = foundParentData.ext
if (
extData.childrenComponent &&
extData.childrenComponent.length > 0 &&
!extData.childrenComponent.includes(item.id) &&
!(itemMpdConfig.component && extData.childrenComponent.includes(itemMpdConfig.component))
) {
msg = `只能放入以下组件【${extData.childrenComponent.join(',')}】`
}
} else {
msg = `没有配置属性【mpdConfig.childrenComponent】`
}
// 判断父元素配置
if (
!msg &&
foundItemData.ext &&
foundItemData.ext.hasOwnProperty('parentComponent') &&
(foundItemData.ext.parentComponent as string[]).length > 0
) {
const extData: ComponentItemExt = foundItemData.ext
if (
extData.parentComponent &&
!extData.parentComponent.includes(parent.id) &&
!extData.parentComponent.includes(<string>parentMpdConfig.component)
) {
msg = `子元素只能放入到以下组件【${extData.parentComponent.join(',')}】`
}
}
if (msg) {
const msgPrefix = `目标元素【${parent.title}(${parentMpdConfig.component})】不能拖入子元素【${item.title}】,原因:`
mpdMessage.error(msgPrefix + msg)
}
return !msg
}
/**
* 删除单个配置对象
* @param item 需要删除的对象
* @param configArray 需要删除的数组元素
* @param field 比较的字段
* @returns
*/
export const deleteItem = function (item: any, configArray: Array<any> = [], field: string = 'id'): boolean {
for (const index in configArray) {
if (configArray[index][field] === item[field]) {
configArray.splice(index as unknown as number, 1)
return true
}
if (configArray[index].mpdConfig.slot && configArray[index].mpdConfig.slot.length > 0) {
if (deleteItem(item, configArray[index].mpdConfig.slot, field)) {
return true
}
}
if (configArray[index].children && configArray[index].children.length > 0) {
if (deleteItem(item, configArray[index].children, field)) {
return true
}
}
}
return false
}
/**
* 选中item,如果不传则是取消选中
* @param selectPageNodeDom 选中的缓存对象
* @param item 选中节点的item
* @param slotItem 选中节点的slotItem
*/
export const selectItem = function (selectPageNodeDom: any, item: PageDom, slotItem: PageDom) {
if (item) {
selectPageNodeDom.item = item
selectPageNodeDom.slotItem = slotItem || {}
} else {
selectPageNodeDom.item = {}
selectPageNodeDom.slotItem = {}
}
}
/**
* 优化mpdPageConfig json结构,主要删除无用的属性,让保存的json体积更小
* @param mpdPageConfig 页面配置
* @returns
*/
export const optimizeMpdPageConfig = function (mpdPageConfig: PageDom): PageDom {
if (mpdPageConfig.mpdConfig) {
if (!mpdPageConfig.mpdConfig.model || Object.keys(mpdPageConfig.mpdConfig.model).length === 0) {
delete mpdPageConfig.mpdConfig.model
}
if (!mpdPageConfig.mpdConfig.attr || Object.keys(mpdPageConfig.mpdConfig.attr).length === 0) {
delete mpdPageConfig.mpdConfig.attr
}
if (!mpdPageConfig.mpdConfig.class) {
delete mpdPageConfig.mpdConfig.class
}
if (!mpdPageConfig.mpdConfig.style || mpdPageConfig.mpdConfig.style.length === 0) {
delete mpdPageConfig.mpdConfig.style
}
if (!mpdPageConfig.mpdConfig.event || Object.keys(mpdPageConfig.mpdConfig.event).length === 0) {
delete mpdPageConfig.mpdConfig.event
}
if (!mpdPageConfig.mpdConfig.text) {
delete mpdPageConfig.mpdConfig.text
}
if (!mpdPageConfig.mpdConfig.slot || mpdPageConfig.mpdConfig.slot.length === 0) {
delete mpdPageConfig.mpdConfig.slot
} else {
mpdPageConfig.mpdConfig.slot.forEach((item) => {
optimizeMpdPageConfig(item)
})
}
// 整理slot配置
const comConfig: PageDom = <PageDom>library.getLibraryDataMap(mpdPageConfig.mpdConfig.component)
if (comConfig.ext && comConfig.ext.componentConfig && comConfig.ext.componentConfig.length > 0) {
comConfig.ext.componentConfig.forEach((item) => {
if (mpdPageConfig.mpdConfig && mpdPageConfig.mpdConfig.configTmp) {
const key = `${item.type}.${item.name}`
if (
!item.inputList ||
item.inputList.length === 0 ||
item.inputList[0].component === mpdPageConfig.mpdConfig.configTmp[key]
) {
delete mpdPageConfig.mpdConfig.configTmp[key]
}
}
})
}
if (!mpdPageConfig.mpdConfig.configTmp || Object.keys(mpdPageConfig.mpdConfig.configTmp).length === 0) {
delete mpdPageConfig.mpdConfig.configTmp
}
}
if (mpdPageConfig.children && mpdPageConfig.children.length > 0) {
mpdPageConfig.children.forEach((item) => {
optimizeMpdPageConfig(item)
})
} else {
delete mpdPageConfig.children
}
delete mpdPageConfig.ext
return mpdPageConfig
}