fastlion-amis
Version:
一种MIS页面生成工具
669 lines (596 loc) • 15.3 kB
text/typescript
/**
* @file 兼容配置,对于一些老的 api 设计的得不合理的地方做一些适配。
* @author fex
*/
import {SchemaNode, Schema} from './types';
import {RendererProps, RendererConfig, addSchemaFilter} from './factory';
import {CheckboxControlRenderer} from './renderers/Form/Checkbox';
import {FormRenderer} from './renderers/Form/index';
import {FieldSetRenderer} from './renderers/Form/FieldSet';
import {CardRenderer} from './renderers/Card';
import {ListItemRenderer} from './renderers/List';
import {ButtonGroupControlRenderer} from './renderers/Form/ButtonGroupSelect';
import {getLevelFromClassName} from './utils/helper';
import {FileControlRenderer} from './renderers/Form/InputFile';
import {ImageControlRenderer} from './renderers/Form/InputImage';
import {RichTextControlRenderer} from './renderers/Form/InputRichText';
import isPlainObject from 'lodash/isPlainObject';
import {GridRenderer} from './renderers/Grid';
import {HBoxRenderer} from './renderers/HBox';
// 兼容老的用法,老用法 label 用在 checkbox 的右侧内容,新用法用 option 来代替。
addSchemaFilter(function CheckboxPropsFilter(schema: Schema, renderer) {
if (renderer.component !== CheckboxControlRenderer) {
return schema;
}
if (schema.label && typeof schema.option === 'undefined') {
schema = {
...schema
};
schema.option = schema.label;
delete schema.label;
}
return schema;
});
function convertFieldSetTabs2Controls(schema: any) {
const toUpdate: any = {};
let flag = false;
toUpdate.controls = Array.isArray(schema.controls)
? schema.controls.concat()
: [];
toUpdate.controls = toUpdate.controls.map((control: any) => {
if (Array.isArray(control)) {
let converted = convertFieldSetTabs2Controls({
type: 'group',
controls: control
});
if (converted !== control) {
flag = true;
}
return converted;
}
return control;
});
schema.fieldSet &&
(Array.isArray(schema.fieldSet)
? schema.fieldSet
: [schema.fieldSet]
).forEach((fieldSet: any) => {
flag = true;
toUpdate.controls.push({
...convertFieldSetTabs2Controls(fieldSet),
type: 'fieldSet',
collapsable: schema.collapsable
});
});
schema.tabs &&
(flag = true) &&
toUpdate.controls.push({
type: 'tabs',
tabs: schema.tabs.map((tab: any) => convertFieldSetTabs2Controls(tab))
});
if (flag) {
schema = {
...schema,
...toUpdate
};
delete schema.fieldSet;
delete schema.tabs;
}
return schema;
}
// Form 中,把 fieldSet 和 tabs 转成 {type: 'fieldSet', controls: []}
// 同时把数组用法转成 {type: 'group', controls: []}
addSchemaFilter(function FormPropsFilter(schema: Schema, renderer) {
if (renderer.component !== FormRenderer) {
return schema;
}
if (schema.fieldSet || schema.tabs) {
// console.warn('Form 下面直接用 fieldSet 或者 tabs 将不支持,请改成在 controls 数组中添加。');
schema = convertFieldSetTabs2Controls(schema);
} else if (Array.isArray(schema.controls)) {
let flag = false;
let converted = schema.controls.map((control: any) => {
if (Array.isArray(control)) {
let converted = convertFieldSetTabs2Controls({
type: 'group',
controls: control
});
if (converted !== control) {
flag = true;
}
return converted;
}
return control;
});
if (flag) {
schema = {
...schema,
controls: converted
};
}
}
return schema;
});
// FieldSet 中把 controls 里面的数组用法转成 {type: 'group', controls: []}
addSchemaFilter(function FormPropsFilter(schema: Schema, renderer) {
if (renderer.component !== FieldSetRenderer) {
return schema;
}
if (Array.isArray(schema.controls)) {
let flag = false;
let converted = schema.controls.map((control: any) => {
if (Array.isArray(control)) {
let converted = convertFieldSetTabs2Controls({
type: 'group',
controls: control
});
if (converted !== control) {
flag = true;
}
return converted;
}
return control;
});
if (flag) {
schema = {
...schema,
controls: converted
};
}
}
return schema;
});
// Form 里面的 Tabs 中把 controls 里面的数组用法转成 {type: 'group', controls: []}
function convertArray2Hbox(arr: Array<any>): any {
let flag = false;
let converted = arr.map((item: any) => {
if (Array.isArray(item)) {
flag = true;
return convertArray2Hbox(item);
}
return item;
});
if (!flag) {
converted = arr;
}
return {
type: 'hbox',
columns: converted
};
}
// CRUD/List 和 CRUD/Card 的 body 中的数组用法转成 hbox
addSchemaFilter(function (schema: Schema, renderer) {
if (
renderer.component !== CardRenderer &&
renderer.component !== ListItemRenderer
) {
return schema;
}
if (Array.isArray(schema.body)) {
let flag = false;
let converted = schema.body.map((item: any) => {
if (Array.isArray(item)) {
flag = true;
return convertArray2Hbox(item);
}
return item;
});
if (flag) {
schema = {
...schema,
body: converted
};
}
}
return schema;
});
// button group 的 btnClassName 和 btnActiveClassName 改成 btnLevel 和 btnActiveLevel 了
addSchemaFilter(function (scheam: Schema, renderer) {
if (renderer.component !== ButtonGroupControlRenderer) {
return scheam;
}
if (scheam.btnClassName || scheam.btnActiveClassName) {
scheam = {
...scheam,
btnLevel: getLevelFromClassName(scheam.btnClassName),
btnActiveLevel: getLevelFromClassName(scheam.btnActiveClassName)
};
delete scheam.btnClassName;
delete scheam.btnActiveClassName;
}
return scheam;
});
// FieldSet className 定制样式方式改成 size 来配置
addSchemaFilter(function (scheam: Schema, renderer) {
if (renderer.component !== FieldSetRenderer) {
return scheam;
}
if (
scheam.className &&
!scheam.size &&
/\bfieldset(?:\-(xs|sm|md|lg))?\b/.test(scheam.className)
) {
scheam = {
...scheam,
size: RegExp.$1 || 'base',
className: scheam.className.replace(
/\bfieldset(?:\-(xs|sm|md|lg))?\b/,
''
)
};
delete scheam.btnClassName;
delete scheam.btnActiveClassName;
}
return scheam;
});
// 原 reciever 错别字改为 receiver
addSchemaFilter(function (scheam: Schema, renderer) {
if (
renderer.component !== FileControlRenderer &&
renderer.component !== ImageControlRenderer &&
renderer.component !== RichTextControlRenderer
) {
return scheam;
}
if (scheam.reciever) {
scheam = {
...scheam,
receiver: scheam.reciever
};
delete scheam.reciever;
}
if (scheam.videoReciever) {
scheam = {
...scheam,
videoReceiver: scheam.reciever
};
delete scheam.reciever;
}
return scheam;
});
// Grid 一些旧格式的兼容
addSchemaFilter(function (scheam: Schema, renderer) {
if (renderer.component !== GridRenderer) {
return scheam;
}
if (
Array.isArray(scheam.columns) &&
scheam.columns.some(item => Array.isArray(item) || item.type)
) {
scheam = {
...scheam,
columns: scheam.columns.map(item => {
if (Array.isArray(item)) {
return {
body: [
{
type: 'grid',
columns: item
}
]
};
} else if (item.type) {
let {xs, sm, md, lg, columnClassName, mobLayout, ...rest} = item;
item = {
xs,
sm,
md,
lg,
columnClassName,
mobLayout,
body: [rest]
};
}
return item;
})
};
}
return scheam;
});
// Hbox 一些旧格式的兼容
addSchemaFilter(function (scheam: Schema, renderer) {
if (renderer.component !== HBoxRenderer) {
return scheam;
}
if (Array.isArray(scheam.columns) && scheam.columns.some(item => item.type)) {
scheam = {
...scheam,
columns: scheam.columns.map(item => {
let {
width,
height,
style,
columnClassName,
visible,
visibleOn,
...rest
} = item;
if (item.type) {
item = {
width,
height,
style,
columnClassName,
visible,
visibleOn,
body: [rest]
};
}
return item;
})
};
}
return scheam;
});
const controlMapping: any = {
'array': 'input-array',
'button-group': 'button-group-select',
'city': 'input-city',
'color': 'input-color',
'date': 'input-date',
'datetime': 'input-datetime',
'time': 'input-time',
'quarter': 'input-quarter',
'month': 'input-month',
'year': 'input-year',
'date-range': 'input-date-range',
'datetime-range': 'input-datetime-range',
'diff': 'diff-editor',
'file': 'input-file',
'image': 'input-image',
'list': 'list-select',
'location': 'location-picker',
'matrix': 'matrix-checkboxes',
'month-range': 'input-month-range',
'quarter-range': 'input-quarter-range',
'number': 'input-number',
'range': 'input-range',
'rating': 'input-rating',
'repeat': 'input-repeat',
'rich-text': 'input-rich-text',
'form': 'input-sub-form',
'table': 'input-table',
'tag': 'input-tag',
'text': 'input-text',
'url': 'input-url',
'password': 'input-password',
'email': 'input-email',
'tree': 'input-tree',
'progress': 'static-progress',
'mapping': 'static-mapping'
};
const maybeFormItem = [
'button',
'submit',
'reset',
'button-group',
'button-toolbar',
'container',
'grid',
'hbox',
'panel',
'anchor-nav',
'qr-code'
];
function wrapControl(item: any) {
if (!item || !item.type) {
return item;
}
let {
label,
description,
name,
required,
remark,
inputOnly,
labelClassName,
caption,
labelRemark,
descriptionClassName,
captionClassName,
hint,
showErrorMsg,
mode,
horizontal,
className,
inputClassName,
columnClassName,
visibleOn,
visible,
...rest
} = item;
rest.name = name;
rest.className = inputClassName;
// 如果是按钮
if (~['button', 'submit', 'reset'].indexOf(rest.type)) {
rest.label = label;
label = '';
}
return {
type: 'control',
label,
description,
name,
required,
remark,
inputOnly,
labelClassName,
caption,
labelRemark,
descriptionClassName,
captionClassName,
hint,
showErrorMsg,
mode,
horizontal,
className,
columnClassName,
visibleOn,
visible,
body: rest
};
}
const maybeStatic = [
'tpl',
'mapping',
'progress',
'status',
'json',
'video',
'qrcode',
'plain',
'each',
'link'
];
function wrapStatic(item: any) {
if (!item || !item.type) {
return item;
}
return {
...item,
type: `static-${item.type}`
};
}
addSchemaFilter(function (schema: Schema, renderer: any, props: any) {
const type =
typeof schema?.type === 'string' ? schema.type.toLowerCase() : '';
// controls 转成 body
if (type === 'combo' && Array.isArray(schema.conditions)) {
schema = {
...schema,
conditions: schema.conditions.map(condition => {
if (Array.isArray(condition.controls)) {
condition = {
...condition,
items: condition.controls.map(controlToNormalRenderer)
};
delete condition.controls;
}
return condition;
})
};
}
if (
schema?.controls &&
schema.type !== 'audio' &&
schema.type !== 'carousel'
) {
schema = {
...schema,
[schema.type === 'combo' ? `items` : 'body']: (Array.isArray(
schema.controls
)
? schema.controls
: [schema.controls]
).map(controlToNormalRenderer)
};
delete schema.controls;
} else if (
schema?.quickEdit?.controls &&
(!schema.quickEdit.type ||
!~['combo', 'group', 'panel', 'fieldSet', 'fieldset'].indexOf(
schema.quickEdit.type
))
) {
schema = {
...schema,
quickEdit: {
...schema.quickEdit,
body: (Array.isArray(schema.quickEdit.controls)
? schema.quickEdit.controls
: [schema.quickEdit.controls]
).map(controlToNormalRenderer)
}
};
delete schema.quickEdit.controls;
} else if (schema?.quickEdit?.type) {
schema = {
...schema,
quickEdit: controlToNormalRenderer(schema.quickEdit)
};
} else if (type === 'tabs' && Array.isArray(schema.tabs)) {
schema = {
...schema,
tabs: schema.tabs.map(tab => {
if (Array.isArray(tab.controls) && !Array.isArray(tab.body)) {
tab = {
...tab,
body: tab.controls.map(controlToNormalRenderer)
};
delete tab.controls;
}
return tab;
})
};
} else if (type === 'anchor-nav' && Array.isArray(schema.links)) {
schema = {
...schema,
links: schema.links.map(link => {
if (Array.isArray(link.controls)) {
link = {
...link,
body: link?.controls.map(controlToNormalRenderer)
};
delete link.controls;
}
return link;
})
};
} else if (type === 'input-array' && schema.items) {
schema = {
...schema,
items: Array.isArray(schema.items)
? schema.items.map(controlToNormalRenderer)
: controlToNormalRenderer(schema.items)
};
} else if (
(type === 'grid' || type === 'hbox') &&
Array.isArray(schema.columns)
) {
schema = {
...schema,
columns: schema.columns.map(column => {
if (Array.isArray(column.controls)) {
column = {
...column,
body: column?.controls.map(controlToNormalRenderer)
};
// 有可能直接外面的grid 或者 bhox 列里面用 form 的。
if (column.type !== 'form') {
delete column.type;
}
delete column.controls;
}
return column;
})
};
} else if (type === 'service' && schema?.body?.controls) {
schema = {
...schema,
body: (Array.isArray(schema.body.controls)
? schema.body.controls
: [schema.body.controls]
).map(controlToNormalRenderer)
};
}
return schema;
function controlToNormalRenderer(item: any) {
if (item?.$ref && props.resolveDefinitions) {
item = {
...props.resolveDefinitions(item.$ref),
...item
};
delete item.$ref;
}
return item && controlMapping[item.type]
? {
...item,
type: controlMapping[item.type]
}
: ~maybeFormItem.indexOf(item?.type)
? wrapControl(item)
: ~maybeStatic.indexOf(item?.type)
? wrapStatic(item)
: item;
}
});