mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-06-02 13:41:01 +00:00
feat: 重构renderer
This commit is contained in:
parent
71b55298ef
commit
630d3201ff
@ -32,28 +32,9 @@
|
|||||||
"build": "build-scripts build"
|
"build": "build-scripts build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ali/b3-one": "^0.0.17",
|
"@ali/lowcode-renderer-core": "^1.0.33",
|
||||||
"@ali/bzb-request": "2.6.1",
|
|
||||||
"@ali/lib-mtop": "^2.5.1",
|
|
||||||
"@ali/lowcode-datasource-engine": "^1.0.22",
|
|
||||||
"@ali/lowcode-utils": "^1.0.33",
|
"@ali/lowcode-utils": "^1.0.33",
|
||||||
"@ali/ui-table": "^1.0.1-beta.6",
|
"rax-find-dom-node": "^1.0.1"
|
||||||
"classnames": "^2.2.6",
|
|
||||||
"debug": "^4.1.1",
|
|
||||||
"events": "^3.0.0",
|
|
||||||
"fetch-jsonp": "^1.1.3",
|
|
||||||
"fs-extra": "^9.0.1",
|
|
||||||
"intl-messageformat": "^9.3.1",
|
|
||||||
"jsonuri": "^2.1.2",
|
|
||||||
"keymaster": "^1.6.2",
|
|
||||||
"lodash": "^4.17.11",
|
|
||||||
"moment": "^2.24.0",
|
|
||||||
"rax-find-dom-node": "^1.0.1",
|
|
||||||
"rax-text": "^1.1.6",
|
|
||||||
"rax-view": "^1.0.0",
|
|
||||||
"react-is": "^16.10.1",
|
|
||||||
"serialize-javascript": "^1.7.0",
|
|
||||||
"whatwg-fetch": "^3.0.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@alib/build-scripts": "^0.1.0",
|
"@alib/build-scripts": "^0.1.0",
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
import { createElement, PureComponent } from 'rax';
|
|
||||||
|
|
||||||
export default class DivView extends PureComponent {
|
|
||||||
static displayName = 'Div';
|
|
||||||
|
|
||||||
static version = '0.0.0';
|
|
||||||
|
|
||||||
render(): any {
|
|
||||||
return createElement('div', this.props);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { Component } from 'rax';
|
|
||||||
import './index.css';
|
|
||||||
|
|
||||||
export default class VisualDom extends Component {
|
|
||||||
static displayName = 'VisualDom';
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
children: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { children, title, label, text, __componentName } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="visual-dom">
|
|
||||||
<div className="panel-container">
|
|
||||||
<span className="title">{title || label || text || __componentName}</span>
|
|
||||||
<div className="content">{children}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
import { createContext } from 'rax';
|
|
||||||
|
|
||||||
const context = createContext({});
|
|
||||||
export default context;
|
|
||||||
@ -1,634 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { Component, createElement } from 'rax';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import { create as createDataSourceEngine } from '@ali/lowcode-datasource-engine/interpret';
|
|
||||||
import DataHelper from '../utils/dataHelper';
|
|
||||||
import {
|
|
||||||
forEach,
|
|
||||||
getValue,
|
|
||||||
parseData,
|
|
||||||
parseExpression,
|
|
||||||
isEmpty,
|
|
||||||
isSchema,
|
|
||||||
isFileSchema,
|
|
||||||
isJSExpression,
|
|
||||||
isJSSlot,
|
|
||||||
isJSFunction,
|
|
||||||
transformArrayToMap,
|
|
||||||
checkPropTypes,
|
|
||||||
generateI18n,
|
|
||||||
acceptsRef,
|
|
||||||
getFileCssName,
|
|
||||||
} from '../utils';
|
|
||||||
import VisualDom from '../comp/visualDom';
|
|
||||||
import Div from '../comp/Div';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
|
|
||||||
import compWrapper from '../hoc/compWrapper';
|
|
||||||
|
|
||||||
const debug = Debug('engine:base');
|
|
||||||
const DESIGN_MODE = {
|
|
||||||
EXTEND: 'extend',
|
|
||||||
BORDER: 'border',
|
|
||||||
PREVIEW: 'preview',
|
|
||||||
};
|
|
||||||
const OVERLAY_LIST = ['Dialog', 'Overlay'];
|
|
||||||
let scopeIdx = 0;
|
|
||||||
|
|
||||||
export default class BaseEngine extends Component {
|
|
||||||
static dislayName = 'base-engine';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
locale: PropTypes.string,
|
|
||||||
messages: PropTypes.object,
|
|
||||||
__appHelper: PropTypes.object,
|
|
||||||
__components: PropTypes.object,
|
|
||||||
// eslint-disable-next-line react/no-unused-prop-types
|
|
||||||
__componentsMap: PropTypes.object,
|
|
||||||
__ctx: PropTypes.object,
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextType = AppContext;
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.appHelper = props.__appHelper;
|
|
||||||
this.__compScopes = {};
|
|
||||||
this.__instanceMap = {};
|
|
||||||
const { locale, messages } = props;
|
|
||||||
this.i18n = generateI18n(locale, messages);
|
|
||||||
this.__bindCustomMethods(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
this.__setLifeCycleMethods('getSnapshotBeforeUpdate', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
this.reloadDataSource();
|
|
||||||
this.__setLifeCycleMethods('componentDidMount', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
this.__setLifeCycleMethods('componentDidUpdate', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
this.__setLifeCycleMethods('componentWillUnmount', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch(e) {
|
|
||||||
this.__setLifeCycleMethods('componentDidCatch', arguments);
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadDataSource = () => new Promise((resolve, reject) => {
|
|
||||||
debug('reload data source');
|
|
||||||
if (!this.__dataHelper) {
|
|
||||||
this.__showPlaceholder = false;
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
this.__dataHelper
|
|
||||||
.getInitData()
|
|
||||||
.then((res) => {
|
|
||||||
this.__showPlaceholder = false;
|
|
||||||
if (isEmpty(res)) {
|
|
||||||
this.forceUpdate();
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
this.setState(res, resolve);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (this.__showPlaceholder) {
|
|
||||||
this.__showPlaceholder = false;
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
__setLifeCycleMethods = (method, args) => {
|
|
||||||
const lifeCycleMethods = getValue(this.props.__schema, 'lifeCycles', {});
|
|
||||||
if (lifeCycleMethods[method]) {
|
|
||||||
try {
|
|
||||||
return lifeCycleMethods[method].apply(this, args);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`[${this.props.__schema.componentName}]生命周期${method}出错`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
__bindCustomMethods = (props = this.props) => {
|
|
||||||
const { __schema } = props;
|
|
||||||
const customMethodsList = Object.keys(__schema.methods || {}) || [];
|
|
||||||
this.__customMethodsList
|
|
||||||
&& this.__customMethodsList.forEach((item) => {
|
|
||||||
if (!customMethodsList.includes(item)) {
|
|
||||||
delete this[item];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.__customMethodsList = customMethodsList;
|
|
||||||
forEach(__schema.methods, (val, key) => {
|
|
||||||
this[key] = val.bind(this);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
__generateCtx = (ctx) => {
|
|
||||||
const { pageContext, compContext } = this.context;
|
|
||||||
const obj = {
|
|
||||||
page: pageContext,
|
|
||||||
component: compContext,
|
|
||||||
...ctx,
|
|
||||||
};
|
|
||||||
forEach(obj, (val, key) => {
|
|
||||||
this[key] = val;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
__parseData = (data, ctx) => {
|
|
||||||
const { __ctx } = this.props;
|
|
||||||
return parseData(data, ctx || __ctx || this);
|
|
||||||
};
|
|
||||||
|
|
||||||
__initDataSource = (props = this.props) => {
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
const dataSource = (schema && schema.dataSource) || {};
|
|
||||||
// requestHandlersMap 存在才走数据源引擎方案
|
|
||||||
if (props?.__appHelper?.requestHandlersMap) {
|
|
||||||
const { dataSourceMap, reloadDataSource } = createDataSourceEngine(dataSource, this, {
|
|
||||||
requestHandlersMap: props.__appHelper.requestHandlersMap,
|
|
||||||
});
|
|
||||||
this.dataSourceMap = dataSourceMap;
|
|
||||||
this.reloadDataSource = () => new Promise((resolve, reject) => {
|
|
||||||
debug('reload data source');
|
|
||||||
// this.__showPlaceholder = true;
|
|
||||||
reloadDataSource().then(() => {
|
|
||||||
// this.__showPlaceholder = false;
|
|
||||||
// @TODO 是否需要 forceUpate
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const appHelper = props.__appHelper;
|
|
||||||
this.__dataHelper = new DataHelper(this, dataSource, appHelper, (config) => this.__parseData(config));
|
|
||||||
this.dataSourceMap = this.__dataHelper.dataSourceMap;
|
|
||||||
this.reloadDataSource = () => new Promise((resolve, reject) => {
|
|
||||||
debug('reload data source');
|
|
||||||
if (!this.__dataHelper) {
|
|
||||||
// this.__showPlaceholder = false;
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
this.__dataHelper
|
|
||||||
.getInitData()
|
|
||||||
.then((res) => {
|
|
||||||
// this.__showPlaceholder = false;
|
|
||||||
if (isEmpty(res)) {
|
|
||||||
this.forceUpdate();
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
this.setState(res, resolve);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (this.__showPlaceholder) {
|
|
||||||
this.__showPlaceholder = false;
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 设置容器组件占位,若设置占位则在初始异步请求完成之前用loading占位且不渲染容器组件内部内容
|
|
||||||
// @TODO __showPlaceholder 的逻辑一旦开启就关不掉,先注释掉了
|
|
||||||
/* if (this.__parseData(schema.props && schema.props.autoLoading)) {
|
|
||||||
this.__showPlaceholder = (dataSource.list || []).some((item) => !!this.__parseData(item.isInit));
|
|
||||||
} */
|
|
||||||
};
|
|
||||||
|
|
||||||
__render = () => {
|
|
||||||
const schema = this.props.__schema;
|
|
||||||
this.__setLifeCycleMethods('render');
|
|
||||||
|
|
||||||
const { engine } = this.context;
|
|
||||||
if (engine) {
|
|
||||||
engine.props.onCompGetCtx(schema, this);
|
|
||||||
// 画布场景才需要每次渲染bind自定义方法
|
|
||||||
if (engine.props.designMode) {
|
|
||||||
this.__bindCustomMethods();
|
|
||||||
this.dataSourceMap = this.__dataHelper && this.__dataHelper.updateConfig(schema.dataSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
__getRef = (ref) => {
|
|
||||||
const { engine } = this.context;
|
|
||||||
const { __schema } = this.props;
|
|
||||||
engine && engine.props.onCompGetRef(__schema, ref);
|
|
||||||
this.__ref = ref;
|
|
||||||
};
|
|
||||||
|
|
||||||
__createDom = () => {
|
|
||||||
const { __schema, __ctx, __components = {} } = this.props;
|
|
||||||
const self = {};
|
|
||||||
self.__proto__ = __ctx || this;
|
|
||||||
return this.__createVirtualDom(__schema.children, self, {
|
|
||||||
schema: __schema,
|
|
||||||
Comp: __components[__schema.componentName],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 将模型结构转换成react Element
|
|
||||||
// schema 模型结构
|
|
||||||
// self 为每个渲染组件构造的上下文,self是自上而下继承的
|
|
||||||
// parentInfo 父组件的信息,包含schema和Comp
|
|
||||||
// idx 若为循环渲染的循环Index
|
|
||||||
__createVirtualDom = (schema, self, parentInfo, idx) => {
|
|
||||||
const { engine } = this.context || {};
|
|
||||||
try {
|
|
||||||
if (!schema) return null;
|
|
||||||
if (schema.componentName === 'Text') { // 这个是不是不应该在这里处理
|
|
||||||
if (typeof schema.props.text === 'string') {
|
|
||||||
schema = { ...schema };
|
|
||||||
schema.children = [schema.props.text];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { __appHelper: appHelper, __components: components = {} } = this.props || {};
|
|
||||||
|
|
||||||
if (isJSExpression(schema)) {
|
|
||||||
return parseExpression(schema, self);
|
|
||||||
}
|
|
||||||
if (isJSSlot(schema)) {
|
|
||||||
return this.__createVirtualDom(schema.value, self, parentInfo);
|
|
||||||
}
|
|
||||||
if (typeof schema === 'string') return schema;
|
|
||||||
if (typeof schema === 'number' || typeof schema === 'boolean') {
|
|
||||||
return schema.toString();
|
|
||||||
}
|
|
||||||
if (Array.isArray(schema)) {
|
|
||||||
if (schema.length === 1) return this.__createVirtualDom(schema[0], self, parentInfo);
|
|
||||||
return schema.map((item, idy) => this.__createVirtualDom(item, self, parentInfo, item && item.__ctx && item.__ctx.lunaKey ? '' : idy));
|
|
||||||
}
|
|
||||||
// FIXME
|
|
||||||
const _children = this.getSchemaChildren(schema);
|
|
||||||
// 解析占位组件
|
|
||||||
if (schema.componentName === 'Flagment' && _children) {
|
|
||||||
const tarChildren = isJSExpression(_children) ? parseExpression(_children, self) : _children;
|
|
||||||
return this.__createVirtualDom(tarChildren, self, parentInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.$$typeof) {
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
if (!isSchema(schema)) return null;
|
|
||||||
let Comp = components[schema.componentName] || engine.getNotFoundComponent();
|
|
||||||
|
|
||||||
if (schema.hidden) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.loop != null) {
|
|
||||||
const loop = parseData(schema.loop, self);
|
|
||||||
if ((Array.isArray(loop) && loop.length > 0) || isJSExpression(loop)) {
|
|
||||||
return this.__createLoopVirtualDom(
|
|
||||||
{
|
|
||||||
...schema,
|
|
||||||
loop,
|
|
||||||
},
|
|
||||||
self,
|
|
||||||
parentInfo,
|
|
||||||
idx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const condition = schema.condition == null ? true : parseData(schema.condition, self);
|
|
||||||
if (!condition) return null;
|
|
||||||
|
|
||||||
let scopeKey = '';
|
|
||||||
// 判断组件是否需要生成scope,且只生成一次,挂在this.__compScopes上
|
|
||||||
if (Comp.generateScope) {
|
|
||||||
const key = parseExpression(schema.props.key, self);
|
|
||||||
if (key) {
|
|
||||||
// 如果组件自己设置key则使用组件自己的key
|
|
||||||
scopeKey = key;
|
|
||||||
} else if (!schema.__ctx) {
|
|
||||||
// 在生产环境schema没有__ctx上下文,需要手动生成一个lunaKey
|
|
||||||
schema.__ctx = {
|
|
||||||
lunaKey: `luna${++scopeIdx}`,
|
|
||||||
};
|
|
||||||
scopeKey = schema.__ctx.lunaKey;
|
|
||||||
} else {
|
|
||||||
// 需要判断循环的情况
|
|
||||||
scopeKey = schema.__ctx.lunaKey + (idx !== undefined ? `_${idx}` : '');
|
|
||||||
}
|
|
||||||
if (!this.__compScopes[scopeKey]) {
|
|
||||||
this.__compScopes[scopeKey] = Comp.generateScope(this, schema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果组件有设置scope,需要为组件生成一个新的scope上下文
|
|
||||||
if (scopeKey && this.__compScopes[scopeKey]) {
|
|
||||||
const compSelf = { ...this.__compScopes[scopeKey] };
|
|
||||||
compSelf.__proto__ = self;
|
|
||||||
self = compSelf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 容器类组件的上下文通过props传递,避免context传递带来的嵌套问题
|
|
||||||
const otherProps = isFileSchema(schema)
|
|
||||||
? {
|
|
||||||
__schema: schema,
|
|
||||||
__appHelper: appHelper,
|
|
||||||
__components: components,
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
if (engine && engine.props.designMode) {
|
|
||||||
otherProps.__designMode = engine.props.designMode;
|
|
||||||
}
|
|
||||||
const componentInfo = {};
|
|
||||||
const props =
|
|
||||||
this.__parseProps(schema.props, self, '', {
|
|
||||||
schema,
|
|
||||||
Comp,
|
|
||||||
componentInfo: {
|
|
||||||
...componentInfo,
|
|
||||||
props: transformArrayToMap(componentInfo.props, 'name'),
|
|
||||||
},
|
|
||||||
}) || {};
|
|
||||||
// 对于可以获取到ref的组件做特殊处理
|
|
||||||
if (!acceptsRef(Comp)) {
|
|
||||||
Comp = compWrapper(Comp);
|
|
||||||
}
|
|
||||||
// if (acceptsRef(Comp)) {
|
|
||||||
otherProps.ref = (ref) => {
|
|
||||||
this.$(props.fieldId, ref); // 收集ref
|
|
||||||
const refProps = props.ref;
|
|
||||||
if (refProps && typeof refProps === 'string') {
|
|
||||||
this[refProps] = ref;
|
|
||||||
}
|
|
||||||
ref && engine && engine.props.onCompGetRef(schema, ref);
|
|
||||||
};
|
|
||||||
// }
|
|
||||||
// scope需要传入到组件上
|
|
||||||
if (scopeKey && this.__compScopes[scopeKey]) {
|
|
||||||
props.__scope = this.__compScopes[scopeKey];
|
|
||||||
}
|
|
||||||
// FIXME 这里清除 key 是为了避免循环渲染中更改 key 导致的渲染重复
|
|
||||||
props.key = '';
|
|
||||||
if (schema.__ctx && schema.__ctx.lunaKey) {
|
|
||||||
if (!isFileSchema(schema)) {
|
|
||||||
engine && engine.props.onCompGetCtx(schema, self);
|
|
||||||
}
|
|
||||||
props.key = props.key || `${schema.__ctx.lunaKey}_${schema.__ctx.idx || 0}_${idx !== undefined ? idx : ''}`;
|
|
||||||
} else if (typeof idx === 'number' && !props.key) {
|
|
||||||
props.key = idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
props.__id = schema.id;
|
|
||||||
if (!props.key) {
|
|
||||||
props.key = props.__id;
|
|
||||||
}
|
|
||||||
|
|
||||||
let child = null;
|
|
||||||
if (/*!isFileSchema(schema) && */!!_children) {
|
|
||||||
child = this.__createVirtualDom(
|
|
||||||
isJSExpression(_children) ? parseExpression(_children, self) : _children,
|
|
||||||
self,
|
|
||||||
{
|
|
||||||
schema,
|
|
||||||
Comp,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const renderComp = (props) => engine.createElement(Comp, props, child);
|
|
||||||
// 设计模式下的特殊处理
|
|
||||||
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
|
|
||||||
// 对于overlay,dialog等组件为了使其在设计模式下显示,外层需要增加一个div容器
|
|
||||||
if (OVERLAY_LIST.includes(schema.componentName)) {
|
|
||||||
const { ref, ...overlayProps } = otherProps;
|
|
||||||
return (
|
|
||||||
<Div ref={ref} __designMode={engine.props.designMode}>
|
|
||||||
{renderComp({ ...props, ...overlayProps })}
|
|
||||||
</Div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// 虚拟dom显示
|
|
||||||
if (componentInfo && componentInfo.parentRule) {
|
|
||||||
const parentList = componentInfo.parentRule.split(',');
|
|
||||||
const { schema: parentSchema, Comp: parentComp } = parentInfo;
|
|
||||||
if (
|
|
||||||
!parentList.includes(parentSchema.componentName) ||
|
|
||||||
parentComp !== components[parentSchema.componentName]
|
|
||||||
) {
|
|
||||||
props.__componentName = schema.componentName;
|
|
||||||
Comp = VisualDom;
|
|
||||||
} else {
|
|
||||||
// 若虚拟dom在正常的渲染上下文中,就不显示设计模式了
|
|
||||||
props.__disableDesignMode = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return renderComp({ ...props, ...otherProps });
|
|
||||||
} catch (e) {
|
|
||||||
return engine.createElement(engine.getFaultComponent(), {
|
|
||||||
error: e,
|
|
||||||
schema,
|
|
||||||
self,
|
|
||||||
parentInfo,
|
|
||||||
idx,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getSchemaChildren = (schema) => {
|
|
||||||
if (!schema || !schema.props) {
|
|
||||||
return schema?.children;
|
|
||||||
}
|
|
||||||
if (!schema.children) return schema.props.children;
|
|
||||||
if (!schema.props.children) return schema.children;
|
|
||||||
let _children = [].concat(schema.children);
|
|
||||||
if (Array.isArray(schema.props.children)) {
|
|
||||||
_children = _children.concat(schema.props.children);
|
|
||||||
} else {
|
|
||||||
_children.push(schema.props.children);
|
|
||||||
}
|
|
||||||
return _children;
|
|
||||||
};
|
|
||||||
|
|
||||||
__createLoopVirtualDom = (schema, self, parentInfo, idx) => {
|
|
||||||
if (isFileSchema(schema)) {
|
|
||||||
console.warn('file type not support Loop');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!Array.isArray(schema.loop)) return null;
|
|
||||||
const itemArg = (schema.loopArgs && schema.loopArgs[0]) || 'item';
|
|
||||||
const indexArg = (schema.loopArgs && schema.loopArgs[1]) || 'index';
|
|
||||||
return schema.loop.map((item, i) => {
|
|
||||||
const loopSelf = {
|
|
||||||
[itemArg]: item,
|
|
||||||
[indexArg]: i,
|
|
||||||
};
|
|
||||||
loopSelf.__proto__ = self;
|
|
||||||
return this.__createVirtualDom(
|
|
||||||
{
|
|
||||||
...schema,
|
|
||||||
loop: undefined,
|
|
||||||
},
|
|
||||||
loopSelf,
|
|
||||||
parentInfo,
|
|
||||||
idx ? `${idx}_${i}` : i,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
__createContextDom = (childCtx, currCtx, props) => (
|
|
||||||
<AppContext.Consumer>
|
|
||||||
{(context) => {
|
|
||||||
this.context = context;
|
|
||||||
this.__generateCtx(currCtx);
|
|
||||||
this.__render();
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
...childCtx,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{context.engine.createElement(
|
|
||||||
props.__components.Page,
|
|
||||||
{
|
|
||||||
...props,
|
|
||||||
ref: this.__getRef,
|
|
||||||
className: classnames(getFileCssName(props.__schema.fileName), props.className),
|
|
||||||
__id: props.__schema.id,
|
|
||||||
},
|
|
||||||
this.__createDom(),
|
|
||||||
)}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</AppContext.Consumer>
|
|
||||||
);
|
|
||||||
|
|
||||||
__parseProps = (props, self, path, info) => {
|
|
||||||
const { schema, Comp, componentInfo = {} } = info;
|
|
||||||
const propInfo = getValue(componentInfo.props, path);
|
|
||||||
const propType = propInfo && propInfo.extra && propInfo.extra.propType;
|
|
||||||
const ignoreParse = schema.__ignoreParse || [];
|
|
||||||
const checkProps = (value) => {
|
|
||||||
if (!propType) return value;
|
|
||||||
return checkPropTypes(value, path, propType, componentInfo.name) ? value : undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseReactNode = (data, params) => {
|
|
||||||
if (isEmpty(params)) {
|
|
||||||
return checkProps(this.__createVirtualDom(data, self, { schema, Comp }));
|
|
||||||
}
|
|
||||||
return checkProps(function () {
|
|
||||||
const args = {};
|
|
||||||
if (Array.isArray(params) && params.length) {
|
|
||||||
params.forEach((item, idx) => {
|
|
||||||
if (typeof item === 'string') {
|
|
||||||
args[item] = arguments[idx];
|
|
||||||
} else if (item && typeof item === 'object') {
|
|
||||||
args[item.name] = arguments[idx];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
args.__proto__ = self;
|
|
||||||
return self.__createVirtualDom(data, args, { schema, Comp });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 判断是否需要解析变量
|
|
||||||
if (
|
|
||||||
ignoreParse.some((item) => {
|
|
||||||
if (item instanceof RegExp) {
|
|
||||||
return item.test(path);
|
|
||||||
}
|
|
||||||
return item === path;
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
return checkProps(props);
|
|
||||||
}
|
|
||||||
if (isJSExpression(props)) {
|
|
||||||
props = parseExpression(props, self);
|
|
||||||
// 只有当变量解析出来为模型结构的时候才会继续解析
|
|
||||||
if (!isSchema(props) && !isJSSlot(props)) return checkProps(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isJSFunction(props)) {
|
|
||||||
props = props.value;
|
|
||||||
}
|
|
||||||
if (isJSSlot(props)) {
|
|
||||||
const { params, value } = props;
|
|
||||||
if (!isSchema(value) || isEmpty(value)) return undefined;
|
|
||||||
return parseReactNode(value, params);
|
|
||||||
}
|
|
||||||
// 兼容通过componentInfo判断的情况
|
|
||||||
if (isSchema(props)) {
|
|
||||||
return parseReactNode(props);
|
|
||||||
}
|
|
||||||
if (Array.isArray(props)) {
|
|
||||||
return checkProps(props.map((item, idx) => this.__parseProps(item, self, path ? `${path}.${idx}` : idx, info)));
|
|
||||||
}
|
|
||||||
if (typeof props === 'function') {
|
|
||||||
return checkProps(props.bind(self));
|
|
||||||
}
|
|
||||||
if (props && typeof props === 'object') {
|
|
||||||
if (props.$$typeof) return checkProps(props);
|
|
||||||
const res = {};
|
|
||||||
forEach(props, (val, key) => {
|
|
||||||
if (key.startsWith('__')) {
|
|
||||||
res[key] = val;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res[key] = this.__parseProps(val, self, path ? `${path}.${key}` : key, info);
|
|
||||||
});
|
|
||||||
return checkProps(res);
|
|
||||||
}
|
|
||||||
if (typeof props === 'string') {
|
|
||||||
return checkProps(props.trim());
|
|
||||||
}
|
|
||||||
return checkProps(props);
|
|
||||||
};
|
|
||||||
|
|
||||||
$(filedId, instance) {
|
|
||||||
this.__instanceMap = this.__instanceMap || {};
|
|
||||||
if (!filedId) {
|
|
||||||
return this.__instanceMap;
|
|
||||||
}
|
|
||||||
if (instance) {
|
|
||||||
this.__instanceMap[filedId] = instance;
|
|
||||||
}
|
|
||||||
return this.__instanceMap[filedId];
|
|
||||||
}
|
|
||||||
|
|
||||||
get utils() {
|
|
||||||
return this.appHelper && this.appHelper.utils;
|
|
||||||
}
|
|
||||||
|
|
||||||
get constants() {
|
|
||||||
return this.appHelper && this.appHelper.constants;
|
|
||||||
}
|
|
||||||
|
|
||||||
get history() {
|
|
||||||
return this.appHelper && this.appHelper.history;
|
|
||||||
}
|
|
||||||
|
|
||||||
get location() {
|
|
||||||
return this.appHelper && this.appHelper.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
get match() {
|
|
||||||
return this.appHelper && this.appHelper.match;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { createElement } from 'rax';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import { isSchema, getFileCssName } from '../utils';
|
|
||||||
import BaseEngine from './base';
|
|
||||||
|
|
||||||
const debug = Debug('engine:block');
|
|
||||||
|
|
||||||
export default class BlockEngine extends BaseEngine {
|
|
||||||
static dislayName = 'block-engine';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
|
||||||
debug('block.getDerivedStateFromProps');
|
|
||||||
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
|
||||||
if (func) {
|
|
||||||
return func(props, state);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.__generateCtx();
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
this.state = this.__parseData(schema.state || {});
|
|
||||||
this.__initDataSource(props);
|
|
||||||
this.__setLifeCycleMethods('constructor', arguments);
|
|
||||||
debug(`block.constructor - ${schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
super.getSnapshotBeforeUpdate(...arguments);
|
|
||||||
debug(`block.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
super.componentDidMount(...arguments);
|
|
||||||
debug(`block.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
super.componentDidUpdate(...arguments);
|
|
||||||
debug(`block.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
super.componentWillUnmount(...arguments);
|
|
||||||
debug(`block.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch() {
|
|
||||||
await super.componentDidCatch(...arguments);
|
|
||||||
debug(`block.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema } = this.props;
|
|
||||||
|
|
||||||
if (!isSchema(__schema, true) || __schema.componentName !== 'Block') {
|
|
||||||
return '区块schema结构异常!';
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(`block.render - ${__schema.fileName}`);
|
|
||||||
|
|
||||||
const { id, className, style } = this.__parseData(__schema.props);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
// ref={this.__getRef}
|
|
||||||
className={classnames('luna-block', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
id={id}
|
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
{this.__createContextDom({
|
|
||||||
blockContext: this,
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,144 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
import { createElement } from 'rax';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import { isSchema, getFileCssName } from '../utils';
|
|
||||||
import BaseEngine from './base';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
|
|
||||||
const debug = Debug('engine:comp');
|
|
||||||
|
|
||||||
export default class CompEngine extends BaseEngine {
|
|
||||||
static dislayName = 'comp-engine';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
|
||||||
debug('comp.getDerivedStateFromProps');
|
|
||||||
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
|
||||||
if (func) {
|
|
||||||
return func(props, state);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.__generateCtx({
|
|
||||||
component: this,
|
|
||||||
});
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
this.state = this.__parseData(schema.state || {});
|
|
||||||
this.__initDataSource(props);
|
|
||||||
this.__setLifeCycleMethods('constructor', arguments);
|
|
||||||
debug(`comp.constructor - ${schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
super.getSnapshotBeforeUpdate(...arguments);
|
|
||||||
debug(`comp.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
super.componentDidMount(...arguments);
|
|
||||||
debug(`comp.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
super.componentDidUpdate(...arguments);
|
|
||||||
debug(`comp.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
super.componentWillUnmount(...arguments);
|
|
||||||
debug(`comp.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch() {
|
|
||||||
super.componentDidCatch(...arguments);
|
|
||||||
debug(`comp.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
__createContextDom = (childCtx, currCtx, props) => (
|
|
||||||
<AppContext.Consumer>
|
|
||||||
{(context) => {
|
|
||||||
this.context = context;
|
|
||||||
this.__generateCtx(currCtx);
|
|
||||||
this.__render();
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
...childCtx,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{context.engine.createElement(
|
|
||||||
props.__components.Component,
|
|
||||||
{
|
|
||||||
...props,
|
|
||||||
ref: this.__getRef,
|
|
||||||
className: classnames(getFileCssName(props.__schema.fileName), props.className),
|
|
||||||
__id: props.__schema.id,
|
|
||||||
},
|
|
||||||
this.__createDom(),
|
|
||||||
)}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</AppContext.Consumer>
|
|
||||||
);
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema } = this.props;
|
|
||||||
|
|
||||||
if (!isSchema(__schema, true) || __schema.componentName !== 'Component') {
|
|
||||||
return '自定义组件schema结构异常!';
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(`comp.render - ${__schema.fileName}`);
|
|
||||||
|
|
||||||
const {
|
|
||||||
id, className, style, noContainer,
|
|
||||||
} = this.__parseData(__schema.props);
|
|
||||||
|
|
||||||
if (noContainer) {
|
|
||||||
return this.__createContextDom(
|
|
||||||
{
|
|
||||||
compContext: this,
|
|
||||||
blockContext: this,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
component: this,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
// ref={this.__getRef}
|
|
||||||
className={classnames('luna-comp', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
id={this.props.id || id}
|
|
||||||
style={{ ...style, ...this.props.style }}
|
|
||||||
>
|
|
||||||
{this.__createContextDom(
|
|
||||||
{
|
|
||||||
compContext: this,
|
|
||||||
blockContext: this,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
component: this,
|
|
||||||
},
|
|
||||||
this.props,
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,205 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
/* eslint-disable */
|
|
||||||
import { Component, createElement } from 'rax';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import isEmpty from 'lodash/isEmpty';
|
|
||||||
import findDOMNode from 'rax-find-dom-node';
|
|
||||||
import { isFileSchema, goldlog } from '../utils';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import PageEngine from './pageEngine';
|
|
||||||
import ComponentEngine from './compEngine';
|
|
||||||
import BlockEngine from './blockEngine';
|
|
||||||
import TempEngine from './tempEngine';
|
|
||||||
import BaseEngine from './base';
|
|
||||||
import compWrapper from '../hoc/compWrapper';
|
|
||||||
|
|
||||||
const debug = Debug('engine:entry');
|
|
||||||
const ENGINE_COMPS = {
|
|
||||||
PageEngine,
|
|
||||||
ComponentEngine,
|
|
||||||
BlockEngine,
|
|
||||||
TempEngine,
|
|
||||||
};
|
|
||||||
|
|
||||||
const raxCreateElement = createElement;
|
|
||||||
|
|
||||||
class FaultComponent extends Component {
|
|
||||||
render() {
|
|
||||||
// FIXME: errorlog
|
|
||||||
console.error('render error', this.props);
|
|
||||||
return <div>RenderError</div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotFoundComponent extends Component {
|
|
||||||
render() {
|
|
||||||
console.error('component not found', this.props);
|
|
||||||
return <div {...this.props} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Engine extends Component {
|
|
||||||
static dislayName = 'engine';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
appHelper: PropTypes.object,
|
|
||||||
components: PropTypes.object,
|
|
||||||
componentsMap: PropTypes.object,
|
|
||||||
// 数据源请求处理
|
|
||||||
requestHandlersMap: PropTypes.object,
|
|
||||||
designMode: PropTypes.string,
|
|
||||||
suspended: PropTypes.bool,
|
|
||||||
schema: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
|
||||||
onCompGetRef: PropTypes.func,
|
|
||||||
onCompGetCtx: PropTypes.func,
|
|
||||||
customCreateElement: PropTypes.func,
|
|
||||||
notFoundComponent: PropTypes.element,
|
|
||||||
faultComponent: PropTypes.element,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
appHelper: null,
|
|
||||||
components: {},
|
|
||||||
componentsMap: {},
|
|
||||||
// 数据源请求处理
|
|
||||||
requestHandlersMap: null,
|
|
||||||
designMode: '',
|
|
||||||
suspended: false,
|
|
||||||
schema: {},
|
|
||||||
onCompGetRef: () => {},
|
|
||||||
onCompGetCtx: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.state = {};
|
|
||||||
debug(`entry.constructor - ${props.schema && props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
goldlog(
|
|
||||||
'EXP',
|
|
||||||
{
|
|
||||||
action: 'appear',
|
|
||||||
value: !!this.props.designMode,
|
|
||||||
},
|
|
||||||
'engine',
|
|
||||||
);
|
|
||||||
debug(`entry.componentDidMount - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
debug(`entry.componentDidUpdate - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
debug(`entry.componentWillUnmount - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch(e) {
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
return !nextProps.suspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
getNotFoundComponent() {
|
|
||||||
const { notFoundComponent } = this.props;
|
|
||||||
return notFoundComponent || NotFoundComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFaultComponent() {
|
|
||||||
const { faultComponent } = this.props;
|
|
||||||
return faultComponent || FaultComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
__getRef = (ref) => {
|
|
||||||
const { schema, onCompGetRef } = this.props;
|
|
||||||
this.__ref = ref;
|
|
||||||
if (ref) {
|
|
||||||
onCompGetRef(schema, ref, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
patchDidCatch(Comp) {
|
|
||||||
if (Comp.patchedCatch) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Comp.patchedCatch = true;// eslint-disable-line
|
|
||||||
Comp.getDerivedStateFromError = (error) => ({ engineRenderError: true, error });// eslint-disable-line
|
|
||||||
// const engine = this;
|
|
||||||
const originRender = Comp.prototype.render;
|
|
||||||
Comp.prototype.render = function() {
|
|
||||||
if (this.state && this.state.engineRenderError) {
|
|
||||||
this.state.engineRenderError = false;
|
|
||||||
return engine.createElement(engine.getFaultComponent(), {
|
|
||||||
...this.props,
|
|
||||||
error: this.state.error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return originRender.call(this);
|
|
||||||
};
|
|
||||||
const originShouldComponentUpdate = Comp.prototype.shouldComponentUpdate;
|
|
||||||
Comp.prototype.shouldComponentUpdate = (nextProps, nextState) => {// eslint-disable-line
|
|
||||||
if (nextState && nextState.engineRenderError) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true;// eslint-disable-line
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
createElement(Comp, props, children) {
|
|
||||||
const { customCreateElement } = this.props;
|
|
||||||
// TODO: enable in runtime mode?
|
|
||||||
this.patchDidCatch(Component);
|
|
||||||
return (customCreateElement || raxCreateElement)(Comp, props, children);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { schema, designMode, appHelper, components } = this.props;
|
|
||||||
if (isEmpty(schema)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!isFileSchema(schema)) {
|
|
||||||
return '模型结构异常';
|
|
||||||
}
|
|
||||||
debug('entry.render');
|
|
||||||
const allComponents = { ...ENGINE_COMPS, ...components };
|
|
||||||
const { componentName } = schema;
|
|
||||||
// const Comp = allComponents[schema.componentName];
|
|
||||||
let Comp = allComponents[componentName] || ENGINE_COMPS[`${componentName}Engine`];
|
|
||||||
if (Comp && Comp.prototype) {
|
|
||||||
// const proto = Comp.prototype;
|
|
||||||
if (!(Comp.prototype instanceof BaseEngine)) {
|
|
||||||
Comp = ENGINE_COMPS[`${componentName}Engine`];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
Comp
|
|
||||||
? <AppContext.Provider
|
|
||||||
value={{
|
|
||||||
appHelper,
|
|
||||||
components: allComponents,
|
|
||||||
engine: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Comp
|
|
||||||
key={schema.__ctx && `${schema.__ctx.lunaKey}_${schema.__ctx.idx || '0'}`}
|
|
||||||
ref={this.__getRef}
|
|
||||||
__appHelper={appHelper}
|
|
||||||
__components={allComponents}
|
|
||||||
__schema={schema}
|
|
||||||
__designMode={designMode}
|
|
||||||
// __id={schema.id}
|
|
||||||
{...this.props}
|
|
||||||
/>
|
|
||||||
</AppContext.Provider>
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine.findDOMNode = findDOMNode;
|
|
||||||
@ -1,158 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { createElement } from 'rax';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import { isSchema, getFileCssName } from '../utils';
|
|
||||||
import BaseEngine from './base';
|
|
||||||
|
|
||||||
const debug = Debug('engine:page');
|
|
||||||
|
|
||||||
export default class PageEngine extends BaseEngine {
|
|
||||||
static dislayName = 'page-engine';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextType = AppContext;
|
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
|
||||||
debug('page.getDerivedStateFromProps');
|
|
||||||
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
|
||||||
if (func) {
|
|
||||||
return func(props, state);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.__generateCtx({
|
|
||||||
page: this,
|
|
||||||
});
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
this.state = this.__parseData(schema.state || {});
|
|
||||||
|
|
||||||
this.__initDataSource(props);
|
|
||||||
this.__setLifeCycleMethods('constructor', arguments);
|
|
||||||
|
|
||||||
debug(`page.constructor - ${schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
super.getSnapshotBeforeUpdate(...arguments);
|
|
||||||
debug(`page.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
super.componentDidMount(...arguments);
|
|
||||||
debug(`page.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
super.componentDidUpdate(...arguments);
|
|
||||||
debug(`page.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
super.componentWillUnmount(...arguments);
|
|
||||||
debug(`page.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch() {
|
|
||||||
await super.componentDidCatch(...arguments);
|
|
||||||
debug(`page.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema, __components } = this.props;
|
|
||||||
if (!isSchema(__schema, true) || __schema.componentName !== 'Page') {
|
|
||||||
return '页面schema结构异常!';
|
|
||||||
}
|
|
||||||
debug(`page.render - ${__schema.fileName}`);
|
|
||||||
|
|
||||||
const {
|
|
||||||
id, className, style,
|
|
||||||
} = this.__parseData(__schema.props);
|
|
||||||
|
|
||||||
const { Page } = __components;
|
|
||||||
if (Page) {
|
|
||||||
// const { engine } = this.context || {};
|
|
||||||
return (
|
|
||||||
<AppContext.Consumer>
|
|
||||||
{(context) => {
|
|
||||||
this.context = context;
|
|
||||||
this.__render();
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
pageContext: this,
|
|
||||||
blockContext: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.context.engine.createElement(
|
|
||||||
Page,
|
|
||||||
{
|
|
||||||
...this.props,
|
|
||||||
ref: this.__getRef,
|
|
||||||
className: classnames(getFileCssName(__schema.fileName), className, this.props.className),
|
|
||||||
__id: __schema.id,
|
|
||||||
},
|
|
||||||
this.__createDom(),
|
|
||||||
)}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</AppContext.Consumer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderContent = () => (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
pageContext: this,
|
|
||||||
blockContext: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.__createDom()}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
|
|
||||||
// if (autoLoading || loading !== undefined) {
|
|
||||||
// return (
|
|
||||||
// <Loading
|
|
||||||
// size="medium"
|
|
||||||
// visible={!!(this.__showPlaceholder || loading)}
|
|
||||||
// style={{
|
|
||||||
// height: this.__showPlaceholder ? defaultHeight : 'auto',
|
|
||||||
// display: 'block',
|
|
||||||
// ...style,
|
|
||||||
// }}
|
|
||||||
// className={classnames('luna-page', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
// id={id}
|
|
||||||
// >
|
|
||||||
// {!this.__showPlaceholder && renderContent()}
|
|
||||||
// </Loading>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={this.__getRef}
|
|
||||||
className={classnames('luna-page', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
id={id}
|
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
{renderContent()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
import { createElement } from 'rax';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import { isSchema } from '../utils';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import BaseEngine from './base';
|
|
||||||
|
|
||||||
const debug = Debug('engine:temp');
|
|
||||||
export default class TempEngine extends BaseEngine {
|
|
||||||
static dislayName = 'temp-engine';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
__ctx: PropTypes.object,
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__ctx: {},
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.state = {};
|
|
||||||
this.cacheSetState = {};
|
|
||||||
debug(`temp.constructor - ${props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const ctx = this.props.__ctx;
|
|
||||||
if (!ctx) return;
|
|
||||||
const { setState } = ctx;
|
|
||||||
this.cacheSetState = setState;
|
|
||||||
ctx.setState = (...args) => {
|
|
||||||
setState.call(ctx, ...args);
|
|
||||||
setTimeout(() => this.forceUpdate(), 0);
|
|
||||||
};
|
|
||||||
debug(`temp.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
debug(`temp.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
const ctx = this.props.__ctx;
|
|
||||||
if (!ctx || !this.cacheSetState) return;
|
|
||||||
ctx.setState = this.cacheSetState;
|
|
||||||
delete this.cacheSetState;
|
|
||||||
debug(`temp.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidCatch(e) {
|
|
||||||
console.warn(e);
|
|
||||||
debug(`temp.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema, __ctx } = this.props;
|
|
||||||
if (!isSchema(__schema, true) || __schema.componentName !== 'Temp') {
|
|
||||||
return '下钻编辑schema结构异常!';
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(`temp.render - ${__schema.fileName}`);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
// ref={this.__getRef}
|
|
||||||
className="luna-temp"
|
|
||||||
>
|
|
||||||
<AppContext.Provider value={{ ...this.context, ...__ctx }}>{this.__createDom()}</AppContext.Provider>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,16 +3,18 @@
|
|||||||
import { Component, createElement, forwardRef } from 'rax';
|
import { Component, createElement, forwardRef } from 'rax';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { AppHelper } from '@ali/lowcode-utils';
|
import { AppHelper } from '@ali/lowcode-utils';
|
||||||
import { forEach, isFileSchema } from '../utils';
|
import { utils } from '@ali/lowcode-renderer-core';
|
||||||
import CompEngine from '../engine/compEngine';
|
import CompEngine from '../engine/compEngine';
|
||||||
import BlockEngine from '../engine/blockEngine';
|
import BlockEngine from '../engine/blockEngine';
|
||||||
import AppContext from '../context/appContext';
|
import AppContext from '../context/appContext';
|
||||||
|
|
||||||
|
const { forEach, isFileSchema } = utils;
|
||||||
|
|
||||||
export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) {
|
export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) {
|
||||||
// 自定义组件需要有自己独立的appHelper
|
// 自定义组件需要有自己独立的appHelper
|
||||||
const appHelper = new AppHelper(config);
|
const appHelper = new AppHelper(config);
|
||||||
class LNCompView extends Component {
|
class LNCompView extends Component {
|
||||||
static dislayName = 'luna-comp-factory';
|
static dislayName = 'lce-comp-factory';
|
||||||
|
|
||||||
static version = config.version || '0.0.0';
|
static version = config.version || '0.0.0';
|
||||||
|
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { createElement, Component, forwardRef } from 'rax';
|
|
||||||
|
|
||||||
export default function (Comp) {
|
|
||||||
class compWrapper extends Component {
|
|
||||||
// eslint-disable-next-line no-useless-constructor
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { forwardRef } = this.props;
|
|
||||||
return createElement(Comp, {
|
|
||||||
...this.props,
|
|
||||||
ref: forwardRef,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return forwardRef((props, ref) => {
|
|
||||||
return createElement(compWrapper, { ...props, forwardRef: ref });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
52
packages/rax-renderer/src/index.ts
Normal file
52
packages/rax-renderer/src/index.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { Component, PureComponent, createElement, createContext, forwardRef } from 'rax';
|
||||||
|
import findDOMNode from 'rax-find-dom-node';
|
||||||
|
import {
|
||||||
|
adapter,
|
||||||
|
addonRendererFactory,
|
||||||
|
tempRendererFactory,
|
||||||
|
rendererFactory
|
||||||
|
} from '@ali/lowcode-renderer-core';
|
||||||
|
import pageRendererFactory from './renderer/page';
|
||||||
|
import componentRendererFactory from './renderer/component';
|
||||||
|
import blockRendererFactory from './renderer/block';
|
||||||
|
import CompFactory from './hoc/compFactory';
|
||||||
|
|
||||||
|
adapter.setRuntime({
|
||||||
|
Component,
|
||||||
|
PureComponent,
|
||||||
|
createContext,
|
||||||
|
createElement,
|
||||||
|
forwardRef,
|
||||||
|
findDOMNode,
|
||||||
|
});
|
||||||
|
|
||||||
|
adapter.setRenderers({
|
||||||
|
PageRenderer: pageRendererFactory(),
|
||||||
|
ComponentRenderer: componentRendererFactory(),
|
||||||
|
BlockRenderer: blockRendererFactory(),
|
||||||
|
AddonRenderer: addonRendererFactory(),
|
||||||
|
TempRenderer: tempRendererFactory(),
|
||||||
|
});
|
||||||
|
|
||||||
|
function factory() {
|
||||||
|
const Renderer = rendererFactory();
|
||||||
|
return class extends Renderer {
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidComponent(obj: any) {
|
||||||
|
return obj?.prototype?.setState || obj?.prototype instanceof Component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const RaxRenderer = factory();
|
||||||
|
const Engine = RaxRenderer;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Engine,
|
||||||
|
CompFactory,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RaxRenderer;
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import Engine from './engine';
|
|
||||||
|
|
||||||
export { default as Engine } from './engine';
|
|
||||||
export { default as CompFactory } from './hoc/compFactory';
|
|
||||||
export default Engine;
|
|
||||||
24
packages/rax-renderer/src/renderer/block.tsx
Normal file
24
packages/rax-renderer/src/renderer/block.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { blockRendererFactory, types } from '@ali/lowcode-renderer-core';
|
||||||
|
|
||||||
|
export default function raxBlockRendererFactory() {
|
||||||
|
const OriginBlock = blockRendererFactory();
|
||||||
|
return class BlockRenderer extends OriginBlock {
|
||||||
|
render() {
|
||||||
|
// @ts-ignore
|
||||||
|
const that: types.IRenderer = this;
|
||||||
|
const { __schema, __components } = that.props;
|
||||||
|
if (that.__checkSchema(__schema)) {
|
||||||
|
return '区块 schema 结构异常!';
|
||||||
|
}
|
||||||
|
that.__debug(`render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
const children = ((context) => {
|
||||||
|
that.context = context;
|
||||||
|
that.__generateCtx({});
|
||||||
|
that.__render();
|
||||||
|
return that.__renderComp((__components as any)?.Block, { blockContext: that });
|
||||||
|
});
|
||||||
|
return that.__renderContextConsumer(children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
packages/rax-renderer/src/renderer/component.tsx
Normal file
36
packages/rax-renderer/src/renderer/component.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { componentRendererFactory, types } from '@ali/lowcode-renderer-core';
|
||||||
|
|
||||||
|
export default function raxComponentRendererFactory() {
|
||||||
|
const OriginComponent = componentRendererFactory();
|
||||||
|
return class ComponentRenderer extends OriginComponent {
|
||||||
|
render() {
|
||||||
|
// @ts-ignore
|
||||||
|
const that: types.IRenderer = this;
|
||||||
|
const { __schema, __components } = that.props;
|
||||||
|
if (that.__checkSchema(__schema)) {
|
||||||
|
return '自定义组件 schema 结构异常!';
|
||||||
|
}
|
||||||
|
that.__debug(`render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
const { noContainer } = that.__parseData(__schema.props);
|
||||||
|
|
||||||
|
const children = ((context) => {
|
||||||
|
that.context = context;
|
||||||
|
that.__generateCtx({ component: that });
|
||||||
|
that.__render();
|
||||||
|
// 传 null,使用内置的 div 来渲染,解决在页面中渲染 vc-component 报错的问题
|
||||||
|
return that.__renderComp(null, {
|
||||||
|
compContext: that,
|
||||||
|
blockContext: that,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const content = that.__renderContextConsumer(children);
|
||||||
|
|
||||||
|
if (noContainer) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return that.__renderContent(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
packages/rax-renderer/src/renderer/page.tsx
Normal file
33
packages/rax-renderer/src/renderer/page.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { pageRendererFactory, types } from '@ali/lowcode-renderer-core';
|
||||||
|
|
||||||
|
export default function raxPageRendererFactory() {
|
||||||
|
const OriginPage = pageRendererFactory();
|
||||||
|
return class PageRenderer extends OriginPage {
|
||||||
|
async componentDidUpdate() {
|
||||||
|
// @ts-ignore
|
||||||
|
super.componentDidUpdate(...arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// @ts-ignore
|
||||||
|
const that: types.IRenderer = this;
|
||||||
|
const { __schema, __components } = that.props;
|
||||||
|
if (that.__checkSchema(__schema)) {
|
||||||
|
return '页面 schema 结构异常!';
|
||||||
|
}
|
||||||
|
that.__debug(`render - ${__schema?.fileName}`);
|
||||||
|
|
||||||
|
const { Page } = __components as any;
|
||||||
|
if (Page) {
|
||||||
|
const children = ((context) => {
|
||||||
|
that.context = context;
|
||||||
|
that.__render();
|
||||||
|
return that.__renderComp(Page, { pageContext: that });
|
||||||
|
});
|
||||||
|
return that.__renderContextConsumer(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return that.__renderContent(that.__renderContextProvider({ pageContext: that }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,302 +0,0 @@
|
|||||||
/* eslint-disable object-curly-newline */
|
|
||||||
// @ts-nocheck
|
|
||||||
import { transformArrayToMap, isJSFunction, transformStringToFunction, clone, comboSkeletonConfig } from './index';
|
|
||||||
import { jsonp, mtop, request, get, post, bzb, webTableProxy } from './request';
|
|
||||||
|
|
||||||
const DS_STATUS = {
|
|
||||||
INIT: 'init',
|
|
||||||
LOADING: 'loading',
|
|
||||||
LOADED: 'loaded',
|
|
||||||
ERROR: 'error',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class DataHelper {
|
|
||||||
constructor(comp, config = {}, appHelper, parser) {
|
|
||||||
this.host = comp;
|
|
||||||
this.config = config;
|
|
||||||
this.parser = parser;
|
|
||||||
this.ajaxList = (config && config.list) || [];
|
|
||||||
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
|
||||||
this.dataSourceMap = this.generateDataSourceMap();
|
|
||||||
this.appHelper = appHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置config,dataSourceMap状态会被重置;
|
|
||||||
resetConfig(config = {}) {
|
|
||||||
this.config = config;
|
|
||||||
this.ajaxList = (config && config.list) || [];
|
|
||||||
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
|
||||||
this.dataSourceMap = this.generateDataSourceMap();
|
|
||||||
return this.dataSourceMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新config,只会更新配置,状态保存;
|
|
||||||
updateConfig(config = {}) {
|
|
||||||
this.config = config;
|
|
||||||
this.ajaxList = (config && config.list) || [];
|
|
||||||
const ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
|
||||||
// 删除已经移除的接口
|
|
||||||
Object.keys(this.ajaxMap).forEach((key) => {
|
|
||||||
if (!ajaxMap[key]) {
|
|
||||||
delete this.dataSourceMap[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.ajaxMap = ajaxMap;
|
|
||||||
// 添加未加入到dataSourceMap中的接口
|
|
||||||
this.ajaxList.forEach((item) => {
|
|
||||||
if (!this.dataSourceMap[item.id]) {
|
|
||||||
this.dataSourceMap[item.id] = {
|
|
||||||
status: DS_STATUS.INIT,
|
|
||||||
load: (...args) => this.getDataSource(item.id, ...args),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return this.dataSourceMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
generateDataSourceMap() {
|
|
||||||
const res = {};
|
|
||||||
this.ajaxList.forEach((item) => {
|
|
||||||
item.id = item.id || item.name;
|
|
||||||
res[item.id] = {
|
|
||||||
status: DS_STATUS.INIT,
|
|
||||||
load: (...args) => this.getDataSource(item.id, ...args),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDataSourceMap(id, data, error) {
|
|
||||||
this.dataSourceMap[id].error = error || undefined;
|
|
||||||
this.dataSourceMap[id].data = data;
|
|
||||||
this.dataSourceMap[id].status = error ? DS_STATUS.ERROR : DS_STATUS.LOADED;
|
|
||||||
}
|
|
||||||
|
|
||||||
getInitData() {
|
|
||||||
const initSyncData = this.parser(this.ajaxList).filter((item) => {
|
|
||||||
if (item.isInit) {
|
|
||||||
this.dataSourceMap[item.id].status = DS_STATUS.LOADING;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
return this.asyncDataHandler(initSyncData).then((res) => {
|
|
||||||
let { dataHandler } = this.config;
|
|
||||||
if (isJSFunction(dataHandler)) {
|
|
||||||
dataHandler = transformStringToFunction(dataHandler.value);
|
|
||||||
}
|
|
||||||
if (!dataHandler || typeof dataHandler !== 'function') return res;
|
|
||||||
try {
|
|
||||||
return dataHandler.call(this.host, res);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('请求数据处理函数运行出错', e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getDataSource(id, params, otherOptions, callback) {
|
|
||||||
console.log('load',id);
|
|
||||||
const req = this.parser(this.ajaxMap[id]);
|
|
||||||
const options = req.options || {};
|
|
||||||
if (typeof otherOptions === 'function') {
|
|
||||||
callback = otherOptions;
|
|
||||||
otherOptions = {};
|
|
||||||
}
|
|
||||||
const { headers, ...otherProps } = otherOptions || {};
|
|
||||||
if (!req) {
|
|
||||||
console.warn(`getDataSource API named ${id} not exist`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.asyncDataHandler([
|
|
||||||
{
|
|
||||||
...req,
|
|
||||||
options: {
|
|
||||||
...options,
|
|
||||||
// 支持参数为array的情况,当参数为array时,不做参数合并
|
|
||||||
params:
|
|
||||||
Array.isArray(options.params) || Array.isArray(params)
|
|
||||||
? params || options.params
|
|
||||||
: {
|
|
||||||
...options.params,
|
|
||||||
...params,
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
...options.headers,
|
|
||||||
...headers,
|
|
||||||
},
|
|
||||||
...otherProps,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.then(res => {
|
|
||||||
try {
|
|
||||||
callback && callback(res && res[id]);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('load请求回调函数报错', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res && res[id];
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
try {
|
|
||||||
callback && callback(null, err);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('load请求回调函数报错', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
asyncDataHandler(asyncDataList) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const allReq = [];
|
|
||||||
const doserReq = [];
|
|
||||||
const doserList = [];
|
|
||||||
const beforeRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.beforeRequest;
|
|
||||||
const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest;
|
|
||||||
const csrfInput = document.getElementById('_csrf_token');
|
|
||||||
const _tb_token_ = csrfInput && csrfInput.value;
|
|
||||||
asyncDataList.forEach(req => {
|
|
||||||
const { id, type, options } = req;
|
|
||||||
if (!id || !type) return;
|
|
||||||
if (type === 'doServer') {
|
|
||||||
const { uri, params } = options || {};
|
|
||||||
if (!uri) return;
|
|
||||||
doserList.push(id);
|
|
||||||
doserReq.push({ name: uri, package: 'cms', params });
|
|
||||||
} else {
|
|
||||||
allReq.push(req);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (doserReq.length > 0) {
|
|
||||||
allReq.push({
|
|
||||||
type: 'doServer',
|
|
||||||
options: {
|
|
||||||
uri: '/nrsService.do',
|
|
||||||
cors: true,
|
|
||||||
method: 'POST',
|
|
||||||
params: {
|
|
||||||
data: JSON.stringify(doserReq),
|
|
||||||
_tb_token_,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (allReq.length === 0) resolve({});
|
|
||||||
const res = {};
|
|
||||||
Promise.all(
|
|
||||||
allReq.map(
|
|
||||||
(item) =>
|
|
||||||
new Promise((resolve) => {
|
|
||||||
const { type, id, dataHandler, options } = item;
|
|
||||||
const fetchHandler = async (data, error) => {
|
|
||||||
if (type === 'doServer') {
|
|
||||||
if (!Array.isArray(data)) {
|
|
||||||
data = [data];
|
|
||||||
}
|
|
||||||
doserList.forEach(async (id, idx) => {
|
|
||||||
const req = this.ajaxMap[id];
|
|
||||||
if (req) {
|
|
||||||
res[id] = await this.dataHandler(id, req.dataHandler, data && data[idx], error);
|
|
||||||
this.updateDataSourceMap(id, res[id], error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res[id] = await this.dataHandler(id, dataHandler, data, error);
|
|
||||||
this.updateDataSourceMap(id, res[id], error);
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
const doFetch = (type, req) => {
|
|
||||||
this.fetchOne(type, req)
|
|
||||||
.then(async (data) => {
|
|
||||||
console.log(data)
|
|
||||||
if (afterRequest) {
|
|
||||||
this.appHelper.utils.afterRequest(item, data, undefined, async (data, error) => {
|
|
||||||
await fetchHandler(data, error);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await fetchHandler(data, undefined);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(async (err) => {
|
|
||||||
if (afterRequest) {
|
|
||||||
// 必须要这么调用,否则beforeRequest中的this会丢失
|
|
||||||
this.appHelper.utils.afterRequest(item, undefined, err, async (data, error) => {
|
|
||||||
await fetchHandler(data, error);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await fetchHandler(undefined, err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
if (type === 'doServer') {
|
|
||||||
doserList.forEach(item => {
|
|
||||||
this.dataSourceMap[item].status = DS_STATUS.LOADING;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.dataSourceMap[id].status = DS_STATUS.LOADING;
|
|
||||||
}
|
|
||||||
// 请求切片
|
|
||||||
if (beforeRequest) {
|
|
||||||
// 必须要这么调用,否则beforeRequest中的this会丢失
|
|
||||||
this.appHelper.utils.beforeRequest(item, clone(options), () => doFetch(type, item));
|
|
||||||
} else {
|
|
||||||
doFetch(type, item);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
),
|
|
||||||
).then(() => {
|
|
||||||
resolve(res);
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async dataHandler(id, dataHandler, data, error) {
|
|
||||||
if (isJSFunction(dataHandler)) {
|
|
||||||
dataHandler = transformStringToFunction(dataHandler.value);
|
|
||||||
}
|
|
||||||
if (!dataHandler || typeof dataHandler !== 'function') return data;
|
|
||||||
try {
|
|
||||||
return await dataHandler.call(this.host, data, error);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`[${id}]单个请求数据处理函数运行出错`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchOne(type, req) {
|
|
||||||
const { options } = req;
|
|
||||||
// eslint-disable-next-line prefer-const
|
|
||||||
let { uri, method = 'GET', headers, params, ...otherProps } = options;
|
|
||||||
otherProps = otherProps || {};
|
|
||||||
switch (type) {
|
|
||||||
case 'mtop':
|
|
||||||
method && (otherProps.method = method);
|
|
||||||
return mtop(uri, params, otherProps);
|
|
||||||
case 'jsonp':
|
|
||||||
return jsonp(uri, params, otherProps);
|
|
||||||
case 'bzb':
|
|
||||||
return bzb(uri, params, {
|
|
||||||
method,
|
|
||||||
headers,
|
|
||||||
...otherProps,
|
|
||||||
});
|
|
||||||
case 'legao':
|
|
||||||
return webTableProxy(req);
|
|
||||||
default:
|
|
||||||
method = method.toUpperCase();
|
|
||||||
if (method === 'GET') {
|
|
||||||
return get(uri || otherProps.url, params, headers, otherProps);
|
|
||||||
}
|
|
||||||
if (method === 'POST') {
|
|
||||||
return post(uri, params, headers, otherProps);
|
|
||||||
}
|
|
||||||
return request(uri, method, params, headers, otherProps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,725 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
import Debug from 'debug';
|
|
||||||
import _keymaster from 'keymaster';
|
|
||||||
import { forEach as _forEach, shallowEqual as _shallowEqual } from '@ali/b3-one/lib/obj';
|
|
||||||
import { serialize as serializeParams } from '@ali/b3-one/lib/url';
|
|
||||||
import _moment from 'moment';
|
|
||||||
import 'moment/locale/zh-cn';
|
|
||||||
import _pick from 'lodash/pick';
|
|
||||||
import _deepEqual from 'lodash/isEqualWith';
|
|
||||||
import _clone from 'lodash/cloneDeep';
|
|
||||||
import _isEmpty from 'lodash/isEmpty';
|
|
||||||
import _throttle from 'lodash/throttle';
|
|
||||||
import _debounce from 'lodash/debounce';
|
|
||||||
import _serialize from 'serialize-javascript';
|
|
||||||
import * as _jsonuri from 'jsonuri';
|
|
||||||
import IntlMessageFormat from 'intl-messageformat';
|
|
||||||
|
|
||||||
const sdkVersion = (require('../../package.json')).version;
|
|
||||||
|
|
||||||
window.sdkVersion = sdkVersion;
|
|
||||||
|
|
||||||
export const moment = _moment;
|
|
||||||
moment.locale('zh-cn');
|
|
||||||
export const forEach = _forEach;
|
|
||||||
export const shallowEqual = _shallowEqual;
|
|
||||||
export const keymaster = _keymaster;
|
|
||||||
export const pick = _pick;
|
|
||||||
export const deepEqual = _deepEqual;
|
|
||||||
export const clone = _clone;
|
|
||||||
export const isEmpty = _isEmpty;
|
|
||||||
export const throttle = _throttle;
|
|
||||||
export const debounce = _debounce;
|
|
||||||
export const serialize = _serialize;
|
|
||||||
export const jsonuri = _jsonuri;
|
|
||||||
export {
|
|
||||||
get, post, jsonp, mtop, request,
|
|
||||||
} from './request';
|
|
||||||
|
|
||||||
const ReactIs = require('react-is');
|
|
||||||
|
|
||||||
const ReactPropTypesSecret = require('prop-types/lib/ReactPropTypesSecret');
|
|
||||||
|
|
||||||
const factoryWithTypeCheckers = require('prop-types/factoryWithTypeCheckers');
|
|
||||||
|
|
||||||
const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true);
|
|
||||||
|
|
||||||
const EXPRESSION_TYPE = {
|
|
||||||
JSEXPRESSION: 'JSExpression',
|
|
||||||
JSFUNCTION: 'JSFunction',
|
|
||||||
JSSLOT: 'JSSlot',
|
|
||||||
};
|
|
||||||
const EXPRESSION_REG = /^\{\{(\{.*\}|.*?)\}\}$/;
|
|
||||||
const debug = Debug('utils:index');
|
|
||||||
|
|
||||||
const ENV = {
|
|
||||||
TBE: 'TBE',
|
|
||||||
WEBIDE: 'WEB-IDE',
|
|
||||||
VSCODE: 'VSCODE',
|
|
||||||
WEB: 'WEB',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name isSchema
|
|
||||||
* @description 判断是否是模型结构
|
|
||||||
*/
|
|
||||||
export function isSchema(schema, ignoreArr) {
|
|
||||||
if (isEmpty(schema)) return false;
|
|
||||||
if (!ignoreArr && Array.isArray(schema)) return schema.every((item) => isSchema(item));
|
|
||||||
return !!(schema.componentName && schema.props && (typeof schema.props === 'object' || isJSExpression(schema.props)));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isFileSchema(schema) {
|
|
||||||
if (isEmpty(schema)) return false;
|
|
||||||
return ['Page', 'Block', 'Component', 'Addon', 'Temp'].includes(schema.componentName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断当前页面是否被嵌入到同域的页面中
|
|
||||||
export function inSameDomain() {
|
|
||||||
try {
|
|
||||||
return window.parent !== window && window.parent.location.host === window.location.host;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getFileCssName(fileName) {
|
|
||||||
if (!fileName) return;
|
|
||||||
const name = fileName.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
||||||
return `luna-${name}`
|
|
||||||
.split('-')
|
|
||||||
.filter((p) => !!p)
|
|
||||||
.join('-');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isJSSlot(obj) {
|
|
||||||
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSSLOT === obj.type;
|
|
||||||
}
|
|
||||||
export function isJSFunction(obj) {
|
|
||||||
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSFUNCTION === obj.type;
|
|
||||||
}
|
|
||||||
export function isJSExpression(obj) {
|
|
||||||
// 兼容两种写法,有js构造表达式的情况
|
|
||||||
const isJSExpressionObj = obj && typeof obj === 'object' && EXPRESSION_TYPE.JSEXPRESSION === obj.type && typeof obj.value === 'string';
|
|
||||||
const isJSExpressionStr = typeof obj === 'string' && EXPRESSION_REG.test(obj.trim());
|
|
||||||
return isJSExpressionObj || isJSExpressionStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name wait
|
|
||||||
* @description 等待函数
|
|
||||||
*/
|
|
||||||
export function wait(ms) {
|
|
||||||
return new Promise((resolve) => setTimeout(() => resolve(true), ms));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function curry(Comp, hocs = []) {
|
|
||||||
return hocs.reverse().reduce((pre, cur) => cur(pre), Comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取parent window上的值,需要做同域判断
|
|
||||||
* @param {string} key
|
|
||||||
*/
|
|
||||||
export function getParentWinValue(key) {
|
|
||||||
if (inSameDomain()) {
|
|
||||||
return window.parent && window.parent[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getValue(obj, path, defaultValue) {
|
|
||||||
if (isEmpty(obj) || typeof obj !== 'object') return defaultValue;
|
|
||||||
const res = path.split('.').reduce((pre, cur) => pre && pre[cur], obj);
|
|
||||||
if (res === undefined) return defaultValue;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseObj(schemaStr) {
|
|
||||||
if (typeof schemaStr !== 'string') return schemaStr;
|
|
||||||
// 默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
|
||||||
try {
|
|
||||||
if (inSameDomain() && window.parent.__newFunc) {
|
|
||||||
return window.parent.__newFunc(`"use strict"; return ${schemaStr}`)();
|
|
||||||
}
|
|
||||||
return new Function(`"use strict"; return ${schemaStr}`)();
|
|
||||||
} catch (err) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseSearch(search) {
|
|
||||||
if (!search || typeof search !== 'string') {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const str = search.replace(/^\?/, '');
|
|
||||||
const paramStr = str.split('&');
|
|
||||||
const res = {};
|
|
||||||
paramStr.forEach((item) => {
|
|
||||||
const regRes = item.split('=');
|
|
||||||
if (regRes[0] && regRes[1]) {
|
|
||||||
res[regRes[0]] = decodeURIComponent(regRes[1]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fastClone(obj) {
|
|
||||||
return parseObj(serialize(obj, { unsafe: true }));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新obj的内容但不改变obj的指针
|
|
||||||
export function fillObj(receiver = {}, ...suppliers) {
|
|
||||||
Object.keys(receiver).forEach((item) => {
|
|
||||||
delete receiver[item];
|
|
||||||
});
|
|
||||||
Object.assign(receiver, ...suppliers);
|
|
||||||
return receiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 中划线转驼峰
|
|
||||||
export function toHump(name) {
|
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
return name.replace(/\-(\w)/g, (all, letter) => letter.toUpperCase());
|
|
||||||
}
|
|
||||||
// 驼峰转中划线
|
|
||||||
export function toLine(name) {
|
|
||||||
return name.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前环境
|
|
||||||
export function getEnv() {
|
|
||||||
const { userAgent } = navigator;
|
|
||||||
const isVscode = /Electron\//.test(userAgent);
|
|
||||||
if (isVscode) return ENV.VSCODE;
|
|
||||||
const isTheia = window.is_theia === true;
|
|
||||||
if (isTheia) return ENV.WEBIDE;
|
|
||||||
return ENV.WEB;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 合并skeleton配置
|
|
||||||
* @param {*} 骨架默认配置
|
|
||||||
* @param {*} 用户自定义配置
|
|
||||||
*/
|
|
||||||
export function comboSkeletonConfig(defaultConfig = {}, customConfig) {
|
|
||||||
const {
|
|
||||||
skeleton, theme, addons, hooks, shortCuts, extensions, constants, utils, i18n,
|
|
||||||
} = customConfig || {};
|
|
||||||
|
|
||||||
if (skeleton && skeleton.handler && typeof skeleton.handler === 'function') {
|
|
||||||
return skeleton.handler({
|
|
||||||
skeleton,
|
|
||||||
...defaultConfig,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultShortCuts = transformArrayToMap(defaultConfig.shortCuts || [], 'keyboard');
|
|
||||||
const customShortCuts = transformArrayToMap(shortCuts || [], 'keyboard');
|
|
||||||
const localeList = ['zh-CN', 'zh-TW', 'en-US', 'ja-JP'];
|
|
||||||
const i18nConfig = {};
|
|
||||||
localeList.forEach((key) => {
|
|
||||||
i18nConfig[key] = {
|
|
||||||
...(defaultConfig.i18n && defaultConfig.i18n[key]),
|
|
||||||
...(i18n && i18n[key]),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
skeleton,
|
|
||||||
theme: {
|
|
||||||
...defaultConfig.theme,
|
|
||||||
...theme,
|
|
||||||
},
|
|
||||||
addons: {
|
|
||||||
...defaultConfig.addons,
|
|
||||||
...addons,
|
|
||||||
},
|
|
||||||
hooks: [...(defaultConfig.hooks || []), ...(hooks || [])],
|
|
||||||
shortCuts: Object.values({
|
|
||||||
...defaultShortCuts,
|
|
||||||
...customShortCuts,
|
|
||||||
}),
|
|
||||||
extensions: {
|
|
||||||
...defaultConfig.extensions,
|
|
||||||
...extensions,
|
|
||||||
},
|
|
||||||
constants: {
|
|
||||||
...defaultConfig.constants,
|
|
||||||
...constants,
|
|
||||||
},
|
|
||||||
utils: [...(defaultConfig.utils || []), ...(utils || [])],
|
|
||||||
i18n: i18nConfig,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用于构造国际化字符串处理函数
|
|
||||||
* @param {*} locale 国际化标识,例如 zh-CN、en-US
|
|
||||||
* @param {*} messages 国际化语言包
|
|
||||||
*/
|
|
||||||
export function generateI18n(locale = 'zh-CN', messages = {}) {
|
|
||||||
return (key, values = {}) => {
|
|
||||||
if (!messages || !messages[key]) return '';
|
|
||||||
const formater = new IntlMessageFormat(messages[key], locale);
|
|
||||||
return formater.format(values);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断当前组件是否能够设置ref
|
|
||||||
* @param {*} Comp 需要判断的组件
|
|
||||||
*/
|
|
||||||
export function acceptsRef(Comp) {
|
|
||||||
return Comp && Comp.prototype && Comp.prototype.setState;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 黄金令箭埋点
|
|
||||||
* @param {String} gmKey 为黄金令箭业务类型
|
|
||||||
* @param {Object} params 参数
|
|
||||||
* @param {String} logKey 属性串
|
|
||||||
*/
|
|
||||||
export function goldlog(gmKey, params = {}, logKey = 'other') {
|
|
||||||
// vscode 黄金令箭API
|
|
||||||
const sendIDEMessage = window.sendIDEMessage || getParentWinValue('sendIDEMessage');
|
|
||||||
const goKey = serializeParams({
|
|
||||||
sdkVersion,
|
|
||||||
env: getEnv(),
|
|
||||||
...params,
|
|
||||||
});
|
|
||||||
if (sendIDEMessage) {
|
|
||||||
sendIDEMessage({
|
|
||||||
action: 'goldlog',
|
|
||||||
data: {
|
|
||||||
logKey: `/iceluna.core.${logKey}`,
|
|
||||||
gmKey,
|
|
||||||
goKey,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
window.goldlog && window.goldlog.record(`/iceluna.core.${logKey}`, gmKey, goKey, 'POST');
|
|
||||||
}
|
|
||||||
|
|
||||||
// utils为编辑器打包生成的utils文件内容,utilsConfig为数据库存放的utils配置
|
|
||||||
export function generateUtils(utils, utilsConfig) {
|
|
||||||
if (!Array.isArray(utilsConfig)) return { ...utils };
|
|
||||||
const res = {};
|
|
||||||
utilsConfig.forEach((item) => {
|
|
||||||
if (!item.name || !item.type || !item.content) return;
|
|
||||||
if (item.type === 'function' && typeof item.content === 'function') {
|
|
||||||
res[item.name] = item.content;
|
|
||||||
} else if (item.type === 'npm' && utils[item.name]) {
|
|
||||||
res[item.name] = utils[item.name];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
// 复制到粘贴板
|
|
||||||
export function setClipboardData(str) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (typeof str !== 'string') reject('不支持拷贝');
|
|
||||||
if (navigator.clipboard) {
|
|
||||||
navigator.clipboard
|
|
||||||
.writeText(str)
|
|
||||||
.then(() => {
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
reject('复制失败,请重试!', err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const textArea = document.createElement('textarea');
|
|
||||||
textArea.value = str;
|
|
||||||
document.body.appendChild(textArea);
|
|
||||||
textArea.focus();
|
|
||||||
textArea.select();
|
|
||||||
try {
|
|
||||||
const successful = document.execCommand('copy');
|
|
||||||
if (successful) {
|
|
||||||
document.body.removeChild(textArea);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
document.body.removeChild(textArea);
|
|
||||||
reject('复制失败,请重试!', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 获取粘贴板数据
|
|
||||||
export function getClipboardData() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (window.clipboardData) {
|
|
||||||
resolve(window.clipboardData.getData('text'));
|
|
||||||
} else if (navigator.clipboard) {
|
|
||||||
return navigator.clipboard
|
|
||||||
.readText()
|
|
||||||
.then((res) => {
|
|
||||||
resolve(res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
reject('粘贴板获取失败', err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reject('粘贴板获取失败');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 将函数返回结果转成promise形式,如果函数有返回值则根据返回值的bool类型判断是reject还是resolve,若函数无返回值默认执行resolve
|
|
||||||
export function transformToPromise(input) {
|
|
||||||
if (input instanceof Promise) return input;
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (input || input === undefined) {
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function moveArrayItem(arr, sourceIdx, distIdx, direction) {
|
|
||||||
if (
|
|
||||||
!Array.isArray(arr)
|
|
||||||
|| sourceIdx === distIdx
|
|
||||||
|| sourceIdx < 0
|
|
||||||
|| sourceIdx >= arr.length
|
|
||||||
|| distIdx < 0
|
|
||||||
|| distIdx >= arr.length
|
|
||||||
) {
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
const item = arr[sourceIdx];
|
|
||||||
if (direction === 'after') {
|
|
||||||
arr.splice(distIdx + 1, 0, item);
|
|
||||||
} else {
|
|
||||||
arr.splice(distIdx, 0, item);
|
|
||||||
}
|
|
||||||
if (sourceIdx < distIdx) {
|
|
||||||
arr.splice(sourceIdx, 1);
|
|
||||||
} else {
|
|
||||||
arr.splice(sourceIdx + 1, 1);
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformArrayToMap(arr, key, overwrite = true) {
|
|
||||||
if (isEmpty(arr) || !Array.isArray(arr)) return {};
|
|
||||||
const res = {};
|
|
||||||
arr.forEach((item) => {
|
|
||||||
const curKey = item[key];
|
|
||||||
if (item[key] === undefined) return;
|
|
||||||
if (res[curKey] && !overwrite) return;
|
|
||||||
res[curKey] = item;
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function checkPropTypes(value, name, rule, componentName) {
|
|
||||||
if (typeof rule === 'string') {
|
|
||||||
rule = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2);
|
|
||||||
}
|
|
||||||
if (!rule || typeof rule !== 'function') {
|
|
||||||
console.warn('checkPropTypes should have a function type rule argument');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const err = rule(
|
|
||||||
{
|
|
||||||
[name]: value,
|
|
||||||
},
|
|
||||||
name,
|
|
||||||
componentName,
|
|
||||||
'prop',
|
|
||||||
null,
|
|
||||||
ReactPropTypesSecret,
|
|
||||||
);
|
|
||||||
if (err) {
|
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
return !err;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformSchemaToPure(obj) {
|
|
||||||
const pureObj = (obj) => {
|
|
||||||
if (Array.isArray(obj)) {
|
|
||||||
return obj.map((item) => pureObj(item));
|
|
||||||
}
|
|
||||||
if (typeof obj === 'object') {
|
|
||||||
// 对于undefined及null直接返回
|
|
||||||
if (!obj) return obj;
|
|
||||||
const res = {};
|
|
||||||
forEach(obj, (val, key) => {
|
|
||||||
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
|
||||||
res[key] = pureObj(val);
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
return pureObj(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformSchemaToStandard(obj) {
|
|
||||||
const standardObj = (obj) => {
|
|
||||||
if (Array.isArray(obj)) {
|
|
||||||
return obj.map((item) => standardObj(item));
|
|
||||||
}
|
|
||||||
if (typeof obj === 'object') {
|
|
||||||
// 对于undefined及null直接返回
|
|
||||||
if (!obj) return obj;
|
|
||||||
const res = {};
|
|
||||||
forEach(obj, (val, key) => {
|
|
||||||
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
|
||||||
if (isSchema(val) && key !== 'children' && obj.type !== 'JSSlot') {
|
|
||||||
res[key] = {
|
|
||||||
type: 'JSSlot',
|
|
||||||
value: standardObj(val),
|
|
||||||
};
|
|
||||||
// table特殊处理
|
|
||||||
if (key === 'cell') {
|
|
||||||
res[key].params = ['value', 'index', 'record'];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res[key] = standardObj(val);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (typeof obj === 'function') {
|
|
||||||
return {
|
|
||||||
type: 'JSFunction',
|
|
||||||
value: obj.toString(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (typeof obj === 'string' && EXPRESSION_REG.test(obj.trim())) {
|
|
||||||
const regRes = obj.trim().match(EXPRESSION_REG);
|
|
||||||
return {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: (regRes && regRes[1]) || '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
return standardObj(obj, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformStringToFunction(str) {
|
|
||||||
if (typeof str !== 'string') return str;
|
|
||||||
if (inSameDomain() && window.parent.__newFunc) {
|
|
||||||
return window.parent.__newFunc(`"use strict"; return ${str}`)();
|
|
||||||
}
|
|
||||||
return new Function(`"use strict"; return ${str}`)();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addCssTag(id, content) {
|
|
||||||
let styleTag = document.getElementById(id);
|
|
||||||
if (styleTag) {
|
|
||||||
styleTag.innerHTML = content;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
styleTag = document.createElement('style');
|
|
||||||
styleTag.id = id;
|
|
||||||
styleTag.class = 'luna-style';
|
|
||||||
styleTag.innerHTML = content;
|
|
||||||
document.head.appendChild(styleTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册快捷
|
|
||||||
export function registShortCuts(config, appHelper) {
|
|
||||||
keymaster.filter = (event) => {
|
|
||||||
const eTarget = event.target || event.srcElement;
|
|
||||||
const { tagName } = eTarget;
|
|
||||||
const isInput = !!(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
|
|
||||||
const isContenteditable = (target) => {
|
|
||||||
while (target) {
|
|
||||||
if (target.contentEditable === 'true') return true;
|
|
||||||
target = target.parentNode;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
if (isInput || isContenteditable(eTarget)) {
|
|
||||||
if (event.metaKey === true && [70, 83].includes(event.keyCode)) event.preventDefault(); // 禁止触发chrome原生的页面保存或查找
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
const keyboardFilter = keymaster.filter;
|
|
||||||
|
|
||||||
const ideMessage = appHelper.utils && appHelper.utils.ideMessage;
|
|
||||||
|
|
||||||
// 复制
|
|
||||||
if (!document.copyListener) {
|
|
||||||
document.copyListener = (e) => {
|
|
||||||
if (!keyboardFilter(e) || appHelper.isCopying) return;
|
|
||||||
const schema = appHelper.schemaHelper && appHelper.schemaHelper.schemaMap[appHelper.activeKey];
|
|
||||||
if (!schema || !isSchema(schema)) return;
|
|
||||||
appHelper.isCopying = true;
|
|
||||||
const schemaStr = serialize(transformSchemaToPure(schema), {
|
|
||||||
unsafe: true,
|
|
||||||
});
|
|
||||||
setClipboardData(schemaStr)
|
|
||||||
.then(() => {
|
|
||||||
ideMessage && ideMessage('success', '当前内容已复制到剪贴板,请使用快捷键Command+v进行粘贴');
|
|
||||||
appHelper.emit('schema.copy', schemaStr, schema);
|
|
||||||
appHelper.isCopying = false;
|
|
||||||
})
|
|
||||||
.catch((errMsg) => {
|
|
||||||
ideMessage && ideMessage('error', errMsg);
|
|
||||||
appHelper.isCopying = false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
document.addEventListener('copy', document.copyListener);
|
|
||||||
if (getParentWinValue('vscode')) {
|
|
||||||
keymaster('command+c', document.copyListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 粘贴
|
|
||||||
if (!document.pasteListener) {
|
|
||||||
const doPaste = (e, text) => {
|
|
||||||
if (!keyboardFilter(e) || appHelper.isPasting) return;
|
|
||||||
const { schemaHelper } = appHelper;
|
|
||||||
let targetKey = appHelper.activeKey;
|
|
||||||
let direction = 'after';
|
|
||||||
const topKey = schemaHelper.schema && schemaHelper.schema.__ctx && schemaHelper.schema.__ctx.lunaKey;
|
|
||||||
if (!targetKey || topKey === targetKey) {
|
|
||||||
const { schemaHelper } = appHelper;
|
|
||||||
const topKey = schemaHelper.schema && schemaHelper.schema.__ctx && schemaHelper.schema.__ctx.lunaKey;
|
|
||||||
if (!topKey) return;
|
|
||||||
targetKey = topKey;
|
|
||||||
direction = 'in';
|
|
||||||
}
|
|
||||||
appHelper.isPasting = true;
|
|
||||||
const schema = parseObj(text);
|
|
||||||
if (!isSchema(schema)) {
|
|
||||||
appHelper.emit('illegalSchema.paste', text);
|
|
||||||
// ideMessage && ideMessage('error', '当前内容不是模型结构,不能粘贴进来!');
|
|
||||||
console.warn('paste schema illegal');
|
|
||||||
appHelper.isPasting = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
appHelper.emit('material.add', {
|
|
||||||
schema,
|
|
||||||
targetKey,
|
|
||||||
direction,
|
|
||||||
});
|
|
||||||
appHelper.isPasting = false;
|
|
||||||
appHelper.emit('schema.paste', schema);
|
|
||||||
};
|
|
||||||
document.pasteListener = (e) => {
|
|
||||||
const clipboardData = e.clipboardData || window.clipboardData;
|
|
||||||
const text = clipboardData && clipboardData.getData('text');
|
|
||||||
doPaste(e, text);
|
|
||||||
};
|
|
||||||
document.addEventListener('paste', document.pasteListener);
|
|
||||||
if (getParentWinValue('vscode')) {
|
|
||||||
keymaster('command+v', (e) => {
|
|
||||||
const sendIDEMessage = getParentWinValue('sendIDEMessage');
|
|
||||||
sendIDEMessage
|
|
||||||
&& sendIDEMessage({
|
|
||||||
action: 'readClipboard',
|
|
||||||
})
|
|
||||||
.then((text) => {
|
|
||||||
doPaste(e, text);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.warn(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(config || []).forEach((item) => {
|
|
||||||
keymaster(item.keyboard, (ev) => {
|
|
||||||
ev.preventDefault();
|
|
||||||
item.handler(ev, appHelper, keymaster);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消注册快捷
|
|
||||||
export function unRegistShortCuts(config) {
|
|
||||||
(config || []).forEach((item) => {
|
|
||||||
keymaster.unbind(item.keyboard);
|
|
||||||
});
|
|
||||||
if (getParentWinValue('vscode')) {
|
|
||||||
keymaster.unbind('command+c');
|
|
||||||
keymaster.unbind('command+v');
|
|
||||||
}
|
|
||||||
if (document.copyListener) {
|
|
||||||
document.removeEventListener('copy', document.copyListener);
|
|
||||||
delete document.copyListener;
|
|
||||||
}
|
|
||||||
if (document.pasteListener) {
|
|
||||||
document.removeEventListener('paste', document.pasteListener);
|
|
||||||
delete document.pasteListener;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseData(schema, self) {
|
|
||||||
if (isJSExpression(schema)) {
|
|
||||||
return parseExpression(schema, self);
|
|
||||||
}
|
|
||||||
if (typeof schema === 'string') {
|
|
||||||
return schema.trim();
|
|
||||||
}
|
|
||||||
if (Array.isArray(schema)) {
|
|
||||||
return schema.map((item) => parseData(item, self));
|
|
||||||
}
|
|
||||||
if (typeof schema === 'function') {
|
|
||||||
return schema.bind(self);
|
|
||||||
}
|
|
||||||
if (typeof schema === 'object') {
|
|
||||||
// 对于undefined及null直接返回
|
|
||||||
if (!schema) return schema;
|
|
||||||
const res = {};
|
|
||||||
forEach(schema, (val, key) => {
|
|
||||||
if (key.startsWith('__')) return;
|
|
||||||
res[key] = parseData(val, self);
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 全匹配{{开头,}}结尾的变量表达式,或者对象类型JSExpression,且均不支持省略this */
|
|
||||||
// todo:
|
|
||||||
export function parseExpression(str, self) {
|
|
||||||
try {
|
|
||||||
const contextArr = ['"use strict";', 'var __self = arguments[0];'];
|
|
||||||
contextArr.push('return ');
|
|
||||||
let tarStr;
|
|
||||||
// 向前兼容,支持标准协议新格式
|
|
||||||
if (typeof str === 'string') {
|
|
||||||
const regRes = str.trim().match(EXPRESSION_REG);
|
|
||||||
tarStr = regRes[1];
|
|
||||||
} else {
|
|
||||||
tarStr = (str.value || '').trim();
|
|
||||||
}
|
|
||||||
tarStr = tarStr.replace(/this(\W|$)/g, (a, b) => `__self${b}`);
|
|
||||||
tarStr = contextArr.join('\n') + tarStr;
|
|
||||||
// 默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
|
||||||
if (inSameDomain() && window.parent.__newFunc) {
|
|
||||||
return window.parent.__newFunc(tarStr)(self);
|
|
||||||
}
|
|
||||||
return new Function(tarStr)(self);
|
|
||||||
} catch (err) {
|
|
||||||
debug('parseExpression.error', err, str, self);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断组件配置中是否有reactNode且type为function的props
|
|
||||||
* @param {*} componentInfo
|
|
||||||
*/
|
|
||||||
export function hasReactNodeFuncProps(componentInfo) {
|
|
||||||
const isReactNodeFuncProps = (config) => {
|
|
||||||
if (config.type === 'ReactNode') {
|
|
||||||
return config.props && config.props.type === 'function';
|
|
||||||
}
|
|
||||||
if (config.type === 'Mixin') {
|
|
||||||
return config.props && config.props.reactNodeProps && config.props.reactNodeProps.type === 'function';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return componentInfo && (componentInfo.props || []).some((item) => isReactNodeFuncProps(item));
|
|
||||||
}
|
|
||||||
@ -1,199 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
import 'whatwg-fetch';
|
|
||||||
import fetchMtop from '@ali/lib-mtop';
|
|
||||||
import fetchJsonp from 'fetch-jsonp';
|
|
||||||
import bzbRequest from '@ali/bzb-request';
|
|
||||||
import { serialize, buildUrl, parseUrl } from '@ali/b3-one/lib/url';
|
|
||||||
|
|
||||||
export function get(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
|
||||||
headers = {
|
|
||||||
Accept: 'application/json',
|
|
||||||
...headers,
|
|
||||||
};
|
|
||||||
dataAPI = buildUrl(dataAPI, params);
|
|
||||||
return request(dataAPI, 'GET', null, headers, otherProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function post(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
|
||||||
headers = {
|
|
||||||
Accept: 'application/json',
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
...headers,
|
|
||||||
};
|
|
||||||
return request(
|
|
||||||
dataAPI,
|
|
||||||
'POST',
|
|
||||||
headers['Content-Type'].indexOf('application/json') > -1 || Array.isArray(params)
|
|
||||||
? JSON.stringify(params)
|
|
||||||
: serialize(params),
|
|
||||||
headers,
|
|
||||||
otherProps,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function request(dataAPI, method = 'GET', data, headers = {}, otherProps = {}) {
|
|
||||||
switch (method) {
|
|
||||||
case 'PUT':
|
|
||||||
case 'DELETE':
|
|
||||||
headers = {
|
|
||||||
Accept: 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
...headers,
|
|
||||||
};
|
|
||||||
data = JSON.stringify(data || {});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (otherProps.timeout) {
|
|
||||||
setTimeout(() => {
|
|
||||||
reject(new Error('timeout'));
|
|
||||||
}, otherProps.timeout);
|
|
||||||
}
|
|
||||||
fetch(dataAPI, {
|
|
||||||
method,
|
|
||||||
credentials: 'include',
|
|
||||||
headers,
|
|
||||||
body: data,
|
|
||||||
...otherProps,
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
switch (response.status) {
|
|
||||||
case 200:
|
|
||||||
case 201:
|
|
||||||
case 202:
|
|
||||||
return response.json();
|
|
||||||
case 204:
|
|
||||||
if (method === 'DELETE') {
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
__success: false,
|
|
||||||
code: response.status,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 400:
|
|
||||||
case 401:
|
|
||||||
case 403:
|
|
||||||
case 404:
|
|
||||||
case 406:
|
|
||||||
case 410:
|
|
||||||
case 422:
|
|
||||||
case 500:
|
|
||||||
return response
|
|
||||||
.json()
|
|
||||||
.then(res => {
|
|
||||||
return {
|
|
||||||
__success: false,
|
|
||||||
code: response.status,
|
|
||||||
data: res,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
return {
|
|
||||||
__success: false,
|
|
||||||
code: response.status,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.then(json => {
|
|
||||||
if (json && json.__success !== false) {
|
|
||||||
resolve(json);
|
|
||||||
} else {
|
|
||||||
delete json.__success;
|
|
||||||
reject(json);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function jsonp(dataAPI, params = {}, otherProps = {}) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
otherProps = {
|
|
||||||
timeout: 5000,
|
|
||||||
...otherProps,
|
|
||||||
};
|
|
||||||
fetchJsonp(buildUrl(dataAPI, params), otherProps)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(json => {
|
|
||||||
if (json) {
|
|
||||||
resolve(json);
|
|
||||||
} else {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mtop(dataAPI, params, otherProps = {}) {
|
|
||||||
fetchMtop.config.subDomain = otherProps.subDomain || 'm';
|
|
||||||
return fetchMtop.request({
|
|
||||||
api: dataAPI,
|
|
||||||
v: '1.0',
|
|
||||||
data: params,
|
|
||||||
ecode: otherProps.ecode || 0,
|
|
||||||
type: otherProps.method || 'GET',
|
|
||||||
dataType: otherProps.dataType || 'jsonp',
|
|
||||||
AntiFlood: true, // 防刷
|
|
||||||
timeout: otherProps.timeout || 20000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bzb(apiCode, params, otherProps = {}) {
|
|
||||||
// 通过url参数设置小二工作台请求环境
|
|
||||||
const getUrlEnv = () => {
|
|
||||||
try {
|
|
||||||
if (window.parent && window.parent.location.host === window.location.host) {
|
|
||||||
const urlInfo = parseUrl(window.parent && window.parent.location.href);
|
|
||||||
return urlInfo && urlInfo.params && urlInfo.params._env;
|
|
||||||
}
|
|
||||||
const urlInfo = parseUrl(window.location.href);
|
|
||||||
return urlInfo && urlInfo.params && urlInfo.params._env;
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
otherProps.method = otherProps.method || 'GET';
|
|
||||||
otherProps.env = getUrlEnv() || otherProps.env || 'prod';
|
|
||||||
return bzbRequest(apiCode, {
|
|
||||||
data: params,
|
|
||||||
...otherProps,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function webTableProxy(req) {
|
|
||||||
const { _table } = window.parent;
|
|
||||||
const { VisualEngine } = window;
|
|
||||||
const { Bus } = VisualEngine;
|
|
||||||
if (_table) {
|
|
||||||
const { options } = req;
|
|
||||||
const { params, oneAPIConfig } = options;
|
|
||||||
const { code } = oneAPIConfig;
|
|
||||||
const sheetId = oneAPIConfig['x-model'];
|
|
||||||
const sheet = await _table.find({ id: sheetId });
|
|
||||||
const result = await sheet.instance.fetch({ code }, params);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
Bus.emitter.on('table.ready', async (table) => {
|
|
||||||
const { options } = req;
|
|
||||||
const { params, oneAPIConfig } = options;
|
|
||||||
const { code } = oneAPIConfig;
|
|
||||||
const sheetId = oneAPIConfig['x-model'];
|
|
||||||
const sheet = await table.find({ id: sheetId });
|
|
||||||
const result = await sheet.instance.fetch({ code }, params);
|
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import RaxEngine from '@ali/lowcode-rax-renderer/lib/index';
|
import RaxRenderer from '@ali/lowcode-rax-renderer';
|
||||||
import { History } from 'history';
|
import { History } from 'history';
|
||||||
import { Component, createElement, Fragment } from 'rax';
|
import { Component, createElement, Fragment } from 'rax';
|
||||||
import { useRouter } from './rax-use-router';
|
import { useRouter } from './rax-use-router';
|
||||||
@ -175,7 +175,7 @@ class Renderer extends Component<{
|
|||||||
const { designMode, device } = container;
|
const { designMode, device } = container;
|
||||||
const { rendererContainer: renderer } = this.props;
|
const { rendererContainer: renderer } = this.props;
|
||||||
return (
|
return (
|
||||||
<RaxEngine
|
<RaxRenderer
|
||||||
schema={documentInstance.schema}
|
schema={documentInstance.schema}
|
||||||
components={renderer.components}
|
components={renderer.components}
|
||||||
appHelper={renderer.context}
|
appHelper={renderer.context}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { BuiltinSimulatorRenderer, Component, DocumentModel, Node, NodeInstance } from '@ali/lowcode-designer';
|
import { BuiltinSimulatorRenderer, Component, DocumentModel, Node, NodeInstance } from '@ali/lowcode-designer';
|
||||||
import { ComponentSchema, NodeSchema, NpmInfo, RootSchema, TransformStage } from '@ali/lowcode-types';
|
import { ComponentSchema, NodeSchema, NpmInfo, RootSchema, TransformStage } from '@ali/lowcode-types';
|
||||||
import { Asset, cursor, isElement, isESModule, isReactComponent, setNativeSelection } from '@ali/lowcode-utils';
|
import { Asset, cursor, isElement, isESModule, isReactComponent, setNativeSelection } from '@ali/lowcode-utils';
|
||||||
|
import LowCodeRenderer from '@ali/lowcode-rax-renderer';
|
||||||
import { computed, obx } from '@recore/obx';
|
import { computed, obx } from '@recore/obx';
|
||||||
import DriverUniversal from 'driver-universal';
|
import DriverUniversal from 'driver-universal';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
@ -412,8 +413,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
|||||||
}
|
}
|
||||||
instance = Instance.get(dom);
|
instance = Instance.get(dom);
|
||||||
while (instance && instance[INTERNAL]) {
|
while (instance && instance[INTERNAL]) {
|
||||||
// 剔除低代码组件的内部组件
|
if (isValidDesignModeRaxComponentInstance(instance)) {
|
||||||
if (isValidDesignModeRaxComponentInstance(instance) && !findComponentCreator(instance)) {
|
|
||||||
// if (instance && SYMBOL_VNID in instance) {
|
// if (instance && SYMBOL_VNID in instance) {
|
||||||
// const docId = (instance.props as any).schema.docId;
|
// const docId = (instance.props as any).schema.docId;
|
||||||
return {
|
return {
|
||||||
@ -509,15 +509,38 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
|||||||
doc.getElementsByTagName('head')[0].appendChild(s);
|
doc.getElementsByTagName('head')[0].appendChild(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const node = host.currentDocument?.createNode(_schema);
|
|
||||||
// _schema = node?.export(TransformStage.Render) || {};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const renderer = this;
|
const renderer = this;
|
||||||
const { componentsMap } = renderer;
|
const { componentsMap: components } = renderer;
|
||||||
|
|
||||||
return getComponentController(schema, componentsMap);
|
class LowCodeComp extends Rax.Component {
|
||||||
|
render() {
|
||||||
|
// @ts-ignore
|
||||||
|
return createElement(LowCodeRenderer, {
|
||||||
|
schema: _schema,
|
||||||
|
components,
|
||||||
|
designMode: renderer.designMode,
|
||||||
|
device: renderer.device,
|
||||||
|
appHelper: renderer.context,
|
||||||
|
customCreateElement: (Comp: any, props: any, children: any) => {
|
||||||
|
const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName);
|
||||||
|
if (componentMeta?.isModal) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { __id, __designMode, ...viewProps } = props;
|
||||||
|
// mock _leaf,减少性能开销
|
||||||
|
const _leaf = {
|
||||||
|
isEmpty: () => false,
|
||||||
|
};
|
||||||
|
viewProps._leaf = _leaf;
|
||||||
|
return createElement(Comp, viewProps, children);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LowCodeComp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _running = false;
|
private _running = false;
|
||||||
@ -599,101 +622,4 @@ function findComponent(libraryMap: LibraryMap, componentName: string, npm?: NpmI
|
|||||||
return getSubComponent(library, paths);
|
return getSubComponent(library, paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
const processPropsSchema = (propsSchema: any, propsMap: any, componentsMap: any): any => {
|
|
||||||
if (!propsSchema) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = { ...propsSchema };
|
|
||||||
const reg = /^(?:this\.props|props)\.(\S+)$/;
|
|
||||||
Object.keys(result).map((key: string) => {
|
|
||||||
if (result[key]?.type === 'JSExpression') {
|
|
||||||
const { value } = result[key];
|
|
||||||
const matched = reg.exec(value);
|
|
||||||
if (matched) {
|
|
||||||
const propName = matched[1];
|
|
||||||
result[key] = propsMap[propName];
|
|
||||||
}
|
|
||||||
} else if (result[key]?.type === 'JSSlot') {
|
|
||||||
const schema = result[key].value;
|
|
||||||
result[key] = createElement(ComponentCreator, { schema, propsMap: {}, componentsMap });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
function findComponentCreator(instance: any) {
|
|
||||||
let isComponentCreator = false;
|
|
||||||
while (instance && !isComponentCreator) {
|
|
||||||
instance = instance[INTERNAL]?.__parentInstance;
|
|
||||||
isComponentCreator = instance instanceof ComponentCreator;
|
|
||||||
}
|
|
||||||
return isComponentCreator;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComponentCreator extends Rax.Component<{ schema: any; propsMap: any, componentsMap: any }> {
|
|
||||||
private isModal: boolean;
|
|
||||||
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
const componentMeta = host.currentDocument?.getComponentMeta(props.schema.componentName);
|
|
||||||
if (componentMeta?.prototype?.isModal()) {
|
|
||||||
this.isModal = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.isModal) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const { schema, propsMap, componentsMap } = this.props;
|
|
||||||
const ComponentClass = componentsMap[schema.componentName];
|
|
||||||
if (!ComponentClass) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let children = null;
|
|
||||||
if (schema.children && schema.children.length > 0) {
|
|
||||||
children = schema.children.map((item: any, index: number) => createElement(ComponentCreator, { schema: item, propsMap, componentsMap, key: item?.id || index }));
|
|
||||||
}
|
|
||||||
const props = processPropsSchema(schema.props, propsMap, componentsMap);
|
|
||||||
const _leaf = host.currentDocument?.createNode(schema);
|
|
||||||
|
|
||||||
return createElement(ComponentClass, { ...props, _leaf }, children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getComponentController(schema: NodeSchema, componentsMap: any) {
|
|
||||||
class ComponentController extends Rax.Component<{ schema: any }> {
|
|
||||||
renderSchema: any;
|
|
||||||
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
const node = host.currentDocument?.createNode(schema);
|
|
||||||
this.renderSchema = node?.export(TransformStage.Render) || {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 暂时解决性能问题
|
|
||||||
shouldComponentUpdate() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { renderSchema } = this;
|
|
||||||
const { componentName } = renderSchema;
|
|
||||||
if (componentName === 'Component') {
|
|
||||||
let children = [] as any;
|
|
||||||
const propsMap = this.props || {};
|
|
||||||
if (renderSchema.children && Array.isArray(renderSchema.children)) {
|
|
||||||
children = renderSchema.children.map((item: any, index: number) => createElement(ComponentCreator, { schema: item, propsMap, componentsMap, key: item?.id || index }));
|
|
||||||
}
|
|
||||||
return createElement('div', {}, children);
|
|
||||||
} else {
|
|
||||||
return createElement(ComponentCreator, { schema, propsMap: {}, componentsMap });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ComponentController;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new SimulatorRendererContainer();
|
export default new SimulatorRendererContainer();
|
||||||
|
|||||||
6
packages/react-renderer/build.test.json
Normal file
6
packages/react-renderer/build.test.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"build-plugin-component",
|
||||||
|
"@ali/lowcode-test-mate/plugin/index.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
20
packages/react-renderer/jest.config.js
Normal file
20
packages/react-renderer/jest.config.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const esModules = ['@recore/obx-react'].join('|');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// transform: {
|
||||||
|
// '^.+\\.[jt]sx?$': 'babel-jest',
|
||||||
|
// // '^.+\\.(ts|tsx)$': 'ts-jest',
|
||||||
|
// // '^.+\\.(js|jsx)$': 'babel-jest',
|
||||||
|
// },
|
||||||
|
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
|
||||||
|
transformIgnorePatterns: [
|
||||||
|
`/node_modules/(?!${esModules})/`,
|
||||||
|
],
|
||||||
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
|
||||||
|
collectCoverage: true,
|
||||||
|
collectCoverageFrom: [
|
||||||
|
'src/**/*.{ts,tsx}',
|
||||||
|
'!**/node_modules/**',
|
||||||
|
'!**/vendor/**',
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -9,7 +9,7 @@
|
|||||||
"es"
|
"es"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
"test": "build-scripts test --config build.test.json",
|
||||||
"start": "build-scripts start",
|
"start": "build-scripts start",
|
||||||
"build": "build-scripts build --skip-demo",
|
"build": "build-scripts build --skip-demo",
|
||||||
"prepublishOnly": "npm run build"
|
"prepublishOnly": "npm run build"
|
||||||
@ -24,32 +24,19 @@
|
|||||||
"react"
|
"react"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ali/b3-one": "^0.0.17",
|
"@ali/lowcode-renderer-core": "^1.0.33",
|
||||||
"@ali/bzb-request": "^2.6.0-beta.13",
|
"@alifd/next": "^1.21.16"
|
||||||
"@ali/lib-mtop": "^2.5.1",
|
|
||||||
"@ali/lowcode-datasource-engine": "^1.0.22",
|
|
||||||
"@alifd/next": "^1.19.17",
|
|
||||||
"debug": "^4.1.1",
|
|
||||||
"events": "^3.0.0",
|
|
||||||
"fetch-jsonp": "^1.1.3",
|
|
||||||
"intl-messageformat": "^9.3.1",
|
|
||||||
"jsonuri": "^2.1.2",
|
|
||||||
"keymaster": "^1.6.2",
|
|
||||||
"lodash": "^4.17.11",
|
|
||||||
"moment": "^2.24.0",
|
|
||||||
"react-is": "^16.10.1",
|
|
||||||
"serialize-javascript": "^1.7.0",
|
|
||||||
"socket.io-client": "^2.2.0",
|
|
||||||
"whatwg-fetch": "^3.0.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@alifd/next": "^1.19.17",
|
||||||
|
"@ali/lowcode-test-mate": "^1.0.1",
|
||||||
"@alib/build-scripts": "^0.1.18",
|
"@alib/build-scripts": "^0.1.18",
|
||||||
"build-plugin-component": "^0.2.10",
|
"build-plugin-component": "^0.2.10",
|
||||||
"build-plugin-fusion": "^0.1.0",
|
"build-plugin-fusion": "^0.1.0",
|
||||||
"build-plugin-moment-locales": "^0.1.0",
|
"build-plugin-moment-locales": "^0.1.0",
|
||||||
"moment": "^2.24.0",
|
|
||||||
"react": "^16.4.1",
|
"react": "^16.4.1",
|
||||||
"react-dom": "^16.4.1"
|
"react-dom": "^16.4.1",
|
||||||
|
"react-test-renderer": "^16"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "http://registry.npm.alibaba-inc.com"
|
"registry": "http://registry.npm.alibaba-inc.com"
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
|
|
||||||
export default class DivView extends PureComponent {
|
|
||||||
static displayName = 'Div';
|
|
||||||
|
|
||||||
static version = '0.0.0';
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <div {...this.props} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
.visual-dom {
|
|
||||||
.panel-container {
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid #e9e9e9;
|
|
||||||
.title {
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #333;
|
|
||||||
background-color: #ebecf0;
|
|
||||||
line-height: 28px;
|
|
||||||
padding: 0 12px;
|
|
||||||
border-bottom: 1px solid #e9e9e9;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
min-height: 20px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import './VisualDom.scss';
|
|
||||||
|
|
||||||
export default class VisualDom extends PureComponent {
|
|
||||||
static displayName = 'VisualDom';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
children: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { children, cell, title, label, text, __componentName } = this.props;
|
|
||||||
let mainContent = children;
|
|
||||||
if (cell && typeof cell === 'function') {
|
|
||||||
mainContent = cell();
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="visual-dom">
|
|
||||||
<div className="panel-container">
|
|
||||||
<span className="title">{title || label || text || __componentName}</span>
|
|
||||||
<div className="content">{mainContent}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { createContext } from 'react';
|
|
||||||
|
|
||||||
const context = createContext({});
|
|
||||||
window.__appContext = context;
|
|
||||||
export default context;
|
|
||||||
@ -1,230 +0,0 @@
|
|||||||
import React, { Component, PureComponent, createElement as reactCreateElement } from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import { isEmpty } from '@ali/b3-one/lib/obj';
|
|
||||||
import Div from '@ali/iceluna-comp-div';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import { isFileSchema, goldlog } from '../utils';
|
|
||||||
import PageEngine from './pageEngine';
|
|
||||||
import ComponentEngine from './compEngine';
|
|
||||||
import BlockEngine from './blockEngine';
|
|
||||||
import AddonEngine from './addonEngine';
|
|
||||||
import TempEngine from './tempEngine';
|
|
||||||
import BaseEngine from './base';
|
|
||||||
|
|
||||||
window.React = React;
|
|
||||||
window.ReactDom = ReactDOM;
|
|
||||||
|
|
||||||
const debug = Debug('engine:entry');
|
|
||||||
const ENGINE_COMPS = {
|
|
||||||
PageEngine,
|
|
||||||
ComponentEngine,
|
|
||||||
BlockEngine,
|
|
||||||
AddonEngine,
|
|
||||||
TempEngine,
|
|
||||||
DivEngine: BlockEngine,
|
|
||||||
};
|
|
||||||
|
|
||||||
class FaultComponent extends PureComponent {
|
|
||||||
render() {
|
|
||||||
// FIXME: errorlog
|
|
||||||
console.error('render error', this.props);
|
|
||||||
const { _componentName: componentName } = this.props;
|
|
||||||
return (
|
|
||||||
<Div
|
|
||||||
style={{
|
|
||||||
backgroundColor: '#DE2710',
|
|
||||||
padding: '15px',
|
|
||||||
fontSize: '18px',
|
|
||||||
textAlign: 'center',
|
|
||||||
color: 'white',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
组件 {componentName} 渲染错误,请打开控制台排查
|
|
||||||
</Div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotFoundComponent extends PureComponent {
|
|
||||||
render() {
|
|
||||||
console.error('component not found:', this.props);
|
|
||||||
const { _componentName: componentName } = this.props;
|
|
||||||
return (
|
|
||||||
<Div
|
|
||||||
{...this.props}
|
|
||||||
style={{
|
|
||||||
backgroundColor: '#3E91C9',
|
|
||||||
padding: '15px',
|
|
||||||
fontSize: '18px',
|
|
||||||
textAlign: 'center',
|
|
||||||
color: 'white',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
组件 {componentName} 无视图,请打开控制台排查
|
|
||||||
</Div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isReactClass(obj) {
|
|
||||||
return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component);
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line react/no-redundant-should-component-update
|
|
||||||
export default class Engine extends PureComponent {
|
|
||||||
static dislayName = 'engine';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
appHelper: PropTypes.object,
|
|
||||||
components: PropTypes.object,
|
|
||||||
designMode: PropTypes.string,
|
|
||||||
suspended: PropTypes.bool,
|
|
||||||
schema: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
|
||||||
onCompGetRef: PropTypes.func,
|
|
||||||
onCompGetCtx: PropTypes.func,
|
|
||||||
customCreateElement: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
appHelper: null,
|
|
||||||
components: {},
|
|
||||||
designMode: '',
|
|
||||||
suspended: false,
|
|
||||||
schema: {},
|
|
||||||
onCompGetRef: () => {},
|
|
||||||
onCompGetCtx: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.state = {};
|
|
||||||
debug(`entry.constructor - ${props.schema && props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
goldlog(
|
|
||||||
'EXP',
|
|
||||||
{
|
|
||||||
action: 'appear',
|
|
||||||
value: !!this.props.designMode,
|
|
||||||
},
|
|
||||||
'engine',
|
|
||||||
);
|
|
||||||
debug(`entry.componentDidMount - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
debug(`entry.componentDidUpdate - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
debug(`entry.componentWillUnmount - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch(e) {
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
return !nextProps.suspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
__getRef = (ref) => {
|
|
||||||
this.__ref = ref;
|
|
||||||
if (ref) {
|
|
||||||
this.props.onCompGetRef(this.props.schema, ref, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
patchDidCatch(SetComponent) {
|
|
||||||
if (!isReactClass(SetComponent)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (SetComponent.patchedCatch) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SetComponent.patchedCatch = true;
|
|
||||||
SetComponent.getDerivedStateFromError = (error) => ({ engineRenderError: true, error });
|
|
||||||
const engine = this;
|
|
||||||
const originRender = SetComponent.prototype.render;
|
|
||||||
SetComponent.prototype.render = function () {
|
|
||||||
if (this.state && this.state.engineRenderError) {
|
|
||||||
this.state.engineRenderError = false;
|
|
||||||
return engine.createElement(engine.getFaultComponent(), {
|
|
||||||
...this.props,
|
|
||||||
error: this.state.error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return originRender.call(this);
|
|
||||||
};
|
|
||||||
const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate;
|
|
||||||
SetComponent.prototype.shouldComponentUpdate = function (nextProps, nextState) {
|
|
||||||
if (nextState && nextState.engineRenderError) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
createElement(SetComponent, props, children) {
|
|
||||||
// TODO: enable in runtime mode?
|
|
||||||
this.patchDidCatch(SetComponent);
|
|
||||||
return (this.props.customCreateElement || reactCreateElement)(SetComponent, props, children);
|
|
||||||
}
|
|
||||||
|
|
||||||
getNotFoundComponent() {
|
|
||||||
return this.props.notFoundComponent || NotFoundComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFaultComponent() {
|
|
||||||
return this.props.faultComponent || FaultComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
schema, designMode, appHelper, components,
|
|
||||||
} = this.props;
|
|
||||||
if (isEmpty(schema)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// 兼容乐高区块模板
|
|
||||||
if (schema.componentName !== 'Div' && !isFileSchema(schema)) {
|
|
||||||
return '模型结构异常';
|
|
||||||
}
|
|
||||||
debug('entry.render');
|
|
||||||
const { componentName } = schema;
|
|
||||||
const allComponents = { ...ENGINE_COMPS, ...components };
|
|
||||||
let Comp = allComponents[componentName] || ENGINE_COMPS[`${componentName}Engine`];
|
|
||||||
if (Comp && Comp.prototype) {
|
|
||||||
if (!(Comp.prototype instanceof BaseEngine)) {
|
|
||||||
Comp = ENGINE_COMPS[`${componentName}Engine`];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Comp) {
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
appHelper,
|
|
||||||
components: allComponents,
|
|
||||||
engine: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Comp
|
|
||||||
key={schema.__ctx && `${schema.__ctx.lunaKey}_${schema.__ctx.idx || '0'}`}
|
|
||||||
ref={this.__getRef}
|
|
||||||
__appHelper={appHelper}
|
|
||||||
__components={allComponents}
|
|
||||||
__schema={schema}
|
|
||||||
__designMode={designMode}
|
|
||||||
{...this.props}
|
|
||||||
/>
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine.findDOMNode = ReactDOM.findDOMNode;
|
|
||||||
50
packages/react-renderer/src/index.ts
Normal file
50
packages/react-renderer/src/index.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import React, { Component, PureComponent, createElement, createContext, forwardRef } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import {
|
||||||
|
adapter,
|
||||||
|
pageRendererFactory,
|
||||||
|
componentRendererFactory,
|
||||||
|
blockRendererFactory,
|
||||||
|
addonRendererFactory,
|
||||||
|
tempRendererFactory,
|
||||||
|
rendererFactory
|
||||||
|
} from '@ali/lowcode-renderer-core';
|
||||||
|
import ConfigProvider from '@alifd/next/lib/config-provider';
|
||||||
|
|
||||||
|
window.React = React;
|
||||||
|
(window as any).ReactDom = ReactDOM;
|
||||||
|
|
||||||
|
adapter.setRuntime({
|
||||||
|
Component,
|
||||||
|
PureComponent,
|
||||||
|
createContext,
|
||||||
|
createElement,
|
||||||
|
forwardRef,
|
||||||
|
findDOMNode: ReactDOM.findDOMNode,
|
||||||
|
});
|
||||||
|
|
||||||
|
adapter.setRenderers({
|
||||||
|
PageRenderer: pageRendererFactory(),
|
||||||
|
ComponentRenderer: componentRendererFactory(),
|
||||||
|
BlockRenderer: blockRendererFactory(),
|
||||||
|
AddonRenderer: addonRendererFactory(),
|
||||||
|
TempRenderer: tempRendererFactory(),
|
||||||
|
DivRenderer: blockRendererFactory(),
|
||||||
|
});
|
||||||
|
|
||||||
|
adapter.setConfigProvider(ConfigProvider);
|
||||||
|
|
||||||
|
function factory() {
|
||||||
|
const Renderer = rendererFactory();
|
||||||
|
return class ReactRenderer extends Renderer {
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidComponent(obj: any) {
|
||||||
|
return obj?.prototype?.isReactComponent || obj?.prototype instanceof Component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default factory();
|
||||||
@ -1,218 +0,0 @@
|
|||||||
import React, { Component, PureComponent, createElement as reactCreateElement } from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import ConfigProvider from '@alifd/next/lib/config-provider';
|
|
||||||
import { isEmpty } from '@ali/b3-one/lib/obj';
|
|
||||||
import AppContext from './context/appContext';
|
|
||||||
import { isFileSchema, goldlog } from './utils';
|
|
||||||
import PageEngine from './renderer/page';
|
|
||||||
import ComponentEngine from './renderer/component';
|
|
||||||
import BlockEngine from './renderer/block';
|
|
||||||
import AddonEngine from './renderer/addon';
|
|
||||||
import TempEngine from './renderer/temp';
|
|
||||||
import BaseEngine from './renderer/base';
|
|
||||||
import Div from './components/Div';
|
|
||||||
|
|
||||||
window.React = React;
|
|
||||||
window.ReactDom = ReactDOM;
|
|
||||||
|
|
||||||
const debug = Debug('renderer:entry');
|
|
||||||
const ENGINE_COMPS = {
|
|
||||||
PageEngine,
|
|
||||||
ComponentEngine,
|
|
||||||
BlockEngine,
|
|
||||||
AddonEngine,
|
|
||||||
TempEngine,
|
|
||||||
DivEngine: BlockEngine,
|
|
||||||
};
|
|
||||||
|
|
||||||
class FaultComponent extends PureComponent {
|
|
||||||
render() {
|
|
||||||
// FIXME: errorlog
|
|
||||||
console.error('render error', this.props);
|
|
||||||
return (
|
|
||||||
<Div style={{
|
|
||||||
width: '100%',
|
|
||||||
height: '50px',
|
|
||||||
lineHeight: '50px',
|
|
||||||
textAlign: 'center',
|
|
||||||
fontSize: '15px',
|
|
||||||
color: '#ff0000',
|
|
||||||
border: '2px solid #ff0000',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
组件渲染异常,请查看控制台日志
|
|
||||||
</Div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotFoundComponent extends PureComponent {
|
|
||||||
render() {
|
|
||||||
console.error('component not found', this.props);
|
|
||||||
return <Div {...this.props} >{this.props.children || 'Component Not Found'}</Div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isReactClass(obj) {
|
|
||||||
return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Renderer extends Component {
|
|
||||||
static dislayName = 'renderer';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
appHelper: PropTypes.object,
|
|
||||||
components: PropTypes.object,
|
|
||||||
designMode: PropTypes.string,
|
|
||||||
suspended: PropTypes.bool,
|
|
||||||
schema: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
|
||||||
onCompGetRef: PropTypes.func,
|
|
||||||
onCompGetCtx: PropTypes.func,
|
|
||||||
customCreateElement: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
appHelper: null,
|
|
||||||
components: {},
|
|
||||||
designMode: '',
|
|
||||||
suspended: false,
|
|
||||||
schema: {},
|
|
||||||
onCompGetRef: () => {},
|
|
||||||
onCompGetCtx: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.state = {};
|
|
||||||
debug(`entry.constructor - ${props.schema && props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
goldlog(
|
|
||||||
'EXP',
|
|
||||||
{
|
|
||||||
action: 'appear',
|
|
||||||
value: !!this.props.designMode,
|
|
||||||
},
|
|
||||||
'engine',
|
|
||||||
);
|
|
||||||
debug(`entry.componentDidMount - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
debug(`entry.componentDidUpdate - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
debug(`entry.componentWillUnmount - ${this.props.schema && this.props.schema.componentName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch(e) {
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
return !nextProps.suspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
__getRef = (ref) => {
|
|
||||||
this.__ref = ref;
|
|
||||||
if (ref) {
|
|
||||||
this.props.onCompGetRef(this.props.schema, ref, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
patchDidCatch(SetComponent) {
|
|
||||||
if (!isReactClass(SetComponent)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (SetComponent.patchedCatch) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SetComponent.patchedCatch = true;
|
|
||||||
SetComponent.getDerivedStateFromError = (error) => {
|
|
||||||
return { engineRenderError: true, error };
|
|
||||||
};
|
|
||||||
const engine = this;
|
|
||||||
const originRender = SetComponent.prototype.render;
|
|
||||||
SetComponent.prototype.render = function () {
|
|
||||||
if (this.state && this.state.engineRenderError) {
|
|
||||||
this.state.engineRenderError = false;
|
|
||||||
return engine.createElement(engine.getFaultComponent(), {
|
|
||||||
...this.props,
|
|
||||||
error: this.state.error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return originRender.call(this);
|
|
||||||
};
|
|
||||||
const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate;
|
|
||||||
SetComponent.prototype.shouldComponentUpdate = function (nextProps, nextState) {
|
|
||||||
if (nextState && nextState.engineRenderError) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
createElement(SetComponent, props, children) {
|
|
||||||
// TODO: enable in runtime mode?
|
|
||||||
this.patchDidCatch(SetComponent);
|
|
||||||
return (this.props.customCreateElement || reactCreateElement)(SetComponent, props, children);
|
|
||||||
}
|
|
||||||
|
|
||||||
getNotFoundComponent() {
|
|
||||||
return this.props.notFoundComponent || NotFoundComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFaultComponent() {
|
|
||||||
return this.props.faultComponent || FaultComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { schema, designMode, appHelper, components } = this.props;
|
|
||||||
if (isEmpty(schema)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// 兼容乐高区块模板
|
|
||||||
if (schema.componentName !== 'Div' && !isFileSchema(schema)) {
|
|
||||||
return '模型结构异常';
|
|
||||||
}
|
|
||||||
debug('entry.render');
|
|
||||||
const { componentName } = schema;
|
|
||||||
const allComponents = { ...ENGINE_COMPS, ...components };
|
|
||||||
let Comp = allComponents[componentName] || ENGINE_COMPS[`${componentName}Engine`];
|
|
||||||
if (Comp && Comp.prototype) {
|
|
||||||
if (!(Comp.prototype instanceof BaseEngine)) {
|
|
||||||
Comp = ENGINE_COMPS[`${componentName}Engine`];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Comp) {
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
appHelper,
|
|
||||||
components: allComponents,
|
|
||||||
engine: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ConfigProvider device={this.props.device}>
|
|
||||||
<Comp
|
|
||||||
key={schema.__ctx && `${schema.__ctx.lunaKey}_${schema.__ctx.idx || '0'}`}
|
|
||||||
ref={this.__getRef}
|
|
||||||
__appHelper={appHelper}
|
|
||||||
__components={allComponents}
|
|
||||||
__schema={schema}
|
|
||||||
__designMode={designMode}
|
|
||||||
{...this.props}
|
|
||||||
/>
|
|
||||||
</ConfigProvider>
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer.findDOMNode = ReactDOM.findDOMNode;
|
|
||||||
@ -1,139 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import BaseRenderer from './base';
|
|
||||||
import { isSchema, getFileCssName, isEmpty, goldlog } from '../utils';
|
|
||||||
|
|
||||||
const debug = Debug('renderer:addon');
|
|
||||||
|
|
||||||
export default class AddonRenderer extends BaseRenderer {
|
|
||||||
static dislayName = 'addon-renderer';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
config: PropTypes.object,
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
config: {},
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
|
||||||
debug('comp.getDerivedStateFromProps');
|
|
||||||
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
|
||||||
if (func) {
|
|
||||||
return func(props, state);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.__generateCtx({
|
|
||||||
component: this,
|
|
||||||
});
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
this.state = this.__parseData(schema.state || {});
|
|
||||||
if (isEmpty(props.config) || !props.config.addonKey) {
|
|
||||||
console.warn('luna addon has wrong config');
|
|
||||||
this.state.__hasError = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 注册插件
|
|
||||||
this.addonKey = props.config.addonKey;
|
|
||||||
this.appHelper.addons = this.appHelper.addons || {};
|
|
||||||
this.appHelper.addons[this.addonKey] = this;
|
|
||||||
this.__initDataSource(props);
|
|
||||||
this.open = this.open || (() => {});
|
|
||||||
this.close = this.close || (() => {});
|
|
||||||
this.__setLifeCycleMethods('constructor', arguments);
|
|
||||||
debug(`addon.constructor - ${schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
super.getSnapshotBeforeUpdate(...arguments);
|
|
||||||
debug(`addon.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
super.componentDidMount(...arguments);
|
|
||||||
debug(`addon.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
super.componentDidUpdate(...arguments);
|
|
||||||
debug(`addon.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
super.componentWillUnmount(...arguments);
|
|
||||||
// 注销插件
|
|
||||||
const config = this.props.config || {};
|
|
||||||
if (config && this.appHelper.addons) {
|
|
||||||
delete this.appHelper.addons[config.addonKey];
|
|
||||||
}
|
|
||||||
debug(`addon.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch() {
|
|
||||||
super.componentDidCatch(...arguments);
|
|
||||||
debug(`addon.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
goldlog = (goKey, params) => {
|
|
||||||
const { addonKey, addonConfig = {} } = this.props.config || {};
|
|
||||||
goldlog(
|
|
||||||
goKey,
|
|
||||||
{
|
|
||||||
addonKey,
|
|
||||||
package: addonConfig.package,
|
|
||||||
version: addonConfig.version,
|
|
||||||
...this.appHelper.logParams,
|
|
||||||
...params,
|
|
||||||
},
|
|
||||||
'addon',
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
get utils() {
|
|
||||||
const { utils = {} } = this.context.config || {};
|
|
||||||
return { ...this.appHelper.utils, ...utils };
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema } = this.props;
|
|
||||||
|
|
||||||
if (!isSchema(__schema, true) || __schema.componentName !== 'Addon') {
|
|
||||||
return '插件schema结构异常!';
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(`addon.render - ${__schema.fileName}`);
|
|
||||||
this.__generateCtx({
|
|
||||||
component: this,
|
|
||||||
});
|
|
||||||
this.__render();
|
|
||||||
|
|
||||||
const { id, className, style } = this.__parseData(__schema.props);
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={this.__getRef}
|
|
||||||
className={classnames('luna-addon', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
id={this.props.id || id}
|
|
||||||
style={{ ...style, ...this.props.style }}
|
|
||||||
>
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
compContext: this,
|
|
||||||
blockContext: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.__createDom()}
|
|
||||||
</AppContext.Provider>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,620 +0,0 @@
|
|||||||
/* eslint-disable no-proto */
|
|
||||||
import React, { PureComponent } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import { create as createDataSourceEngine } from '@ali/lowcode-datasource-engine/interpret';
|
|
||||||
import Div from '../components/Div';
|
|
||||||
import VisualDom from '../components/VisualDom';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import DataHelper from '../utils/dataHelper';
|
|
||||||
import {
|
|
||||||
forEach,
|
|
||||||
getValue,
|
|
||||||
parseData,
|
|
||||||
parseExpression,
|
|
||||||
isEmpty,
|
|
||||||
isSchema,
|
|
||||||
isFileSchema,
|
|
||||||
isJSExpression,
|
|
||||||
isJSSlot,
|
|
||||||
isJSFunction,
|
|
||||||
transformArrayToMap,
|
|
||||||
transformStringToFunction,
|
|
||||||
checkPropTypes,
|
|
||||||
generateI18n,
|
|
||||||
acceptsRef,
|
|
||||||
} from '../utils';
|
|
||||||
|
|
||||||
const debug = Debug('renderer:base');
|
|
||||||
const DESIGN_MODE = {
|
|
||||||
EXTEND: 'extend',
|
|
||||||
BORDER: 'border',
|
|
||||||
PREVIEW: 'preview',
|
|
||||||
};
|
|
||||||
const OVERLAY_LIST = ['Dialog', 'Overlay', 'Animate', 'ConfigProvider'];
|
|
||||||
let scopeIdx = 0;
|
|
||||||
|
|
||||||
export default class BaseRender extends PureComponent {
|
|
||||||
static dislayName = 'base-renderer';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
locale: PropTypes.string,
|
|
||||||
messages: PropTypes.object,
|
|
||||||
__appHelper: PropTypes.object,
|
|
||||||
__components: PropTypes.object,
|
|
||||||
__ctx: PropTypes.object,
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextType = AppContext;
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.appHelper = props.__appHelper;
|
|
||||||
this.__compScopes = {};
|
|
||||||
const { locale, messages } = props;
|
|
||||||
this.i18n = generateI18n(locale, messages);
|
|
||||||
this.__bindCustomMethods(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
this.__setLifeCycleMethods('getSnapshotBeforeUpdate', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
this.reloadDataSource();
|
|
||||||
this.__setLifeCycleMethods('componentDidMount', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
this.__setLifeCycleMethods('componentDidUpdate', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
this.__setLifeCycleMethods('componentWillUnmount', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch(e) {
|
|
||||||
this.__setLifeCycleMethods('componentDidCatch', arguments);
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadDataSource = () => new Promise((resolve, reject) => {
|
|
||||||
debug('reload data source');
|
|
||||||
if (!this.__dataHelper) {
|
|
||||||
this.__showPlaceholder = false;
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
this.__dataHelper
|
|
||||||
.getInitData()
|
|
||||||
.then((res) => {
|
|
||||||
this.__showPlaceholder = false;
|
|
||||||
if (isEmpty(res)) {
|
|
||||||
this.forceUpdate();
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
this.setState(res, resolve);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (this.__showPlaceholder) {
|
|
||||||
this.__showPlaceholder = false;
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
__setLifeCycleMethods = (method, args) => {
|
|
||||||
const lifeCycleMethods = getValue(this.props.__schema, 'lifeCycles', {});
|
|
||||||
let fn = lifeCycleMethods[method];
|
|
||||||
if (fn) {
|
|
||||||
// TODO, cache
|
|
||||||
if (isJSExpression(fn) || isJSFunction(fn)) {
|
|
||||||
fn = parseExpression(fn, this);
|
|
||||||
}
|
|
||||||
if (typeof fn !== 'function') {
|
|
||||||
console.error(`生命周期${method}类型不符`, fn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return fn.apply(this, args);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`[${this.props.__schema.componentName}]生命周期${method}出错`, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
__bindCustomMethods = (props = this.props) => {
|
|
||||||
const { __schema } = props;
|
|
||||||
const customMethodsList = Object.keys(__schema.methods || {}) || [];
|
|
||||||
this.__customMethodsList
|
|
||||||
&& this.__customMethodsList.forEach((item) => {
|
|
||||||
if (!customMethodsList.includes(item)) {
|
|
||||||
delete this[item];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.__customMethodsList = customMethodsList;
|
|
||||||
forEach(__schema.methods, (val, key) => {
|
|
||||||
if (isJSExpression(val) || isJSFunction(val)) {
|
|
||||||
val = parseExpression(val, this);
|
|
||||||
}
|
|
||||||
if (typeof val !== 'function') {
|
|
||||||
console.error(`自定义函数${key}类型不符`, val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this[key] = val.bind(this);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
__generateCtx = (ctx) => {
|
|
||||||
const { pageContext, compContext } = this.context;
|
|
||||||
const obj = {
|
|
||||||
page: pageContext,
|
|
||||||
component: compContext,
|
|
||||||
...ctx,
|
|
||||||
};
|
|
||||||
forEach(obj, (val, key) => {
|
|
||||||
this[key] = val;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
__parseData = (data, ctx) => {
|
|
||||||
const { __ctx } = this.props;
|
|
||||||
return parseData(data, ctx || __ctx || this);
|
|
||||||
};
|
|
||||||
|
|
||||||
__initDataSource = (props = this.props) => {
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
const dataSource = (schema && schema.dataSource) || {};
|
|
||||||
// requestHandlersMap 存在才走数据源引擎方案
|
|
||||||
if (props?.__appHelper?.requestHandlersMap) {
|
|
||||||
const { dataSourceMap, reloadDataSource } = createDataSourceEngine(dataSource, this, {
|
|
||||||
requestHandlersMap: props.__appHelper.requestHandlersMap,
|
|
||||||
});
|
|
||||||
this.dataSourceMap = dataSourceMap;
|
|
||||||
this.reloadDataSource = () => new Promise((resolve) => {
|
|
||||||
debug('reload data source');
|
|
||||||
// this.__showPlaceholder = true;
|
|
||||||
reloadDataSource().then(() => {
|
|
||||||
// this.__showPlaceholder = false;
|
|
||||||
// @TODO 是否需要 forceUpate
|
|
||||||
// this.forceUpdate();
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const appHelper = props.__appHelper;
|
|
||||||
this.__dataHelper = new DataHelper(this, dataSource, appHelper, (config) => this.__parseData(config));
|
|
||||||
this.dataSourceMap = this.__dataHelper.dataSourceMap;
|
|
||||||
this.reloadDataSource = () => new Promise((resolve, reject) => {
|
|
||||||
debug('reload data source');
|
|
||||||
if (!this.__dataHelper) {
|
|
||||||
// this.__showPlaceholder = false;
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
this.__dataHelper
|
|
||||||
.getInitData()
|
|
||||||
.then((res) => {
|
|
||||||
// this.__showPlaceholder = false;
|
|
||||||
if (isEmpty(res)) {
|
|
||||||
this.forceUpdate();
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
this.setState(res, resolve);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (this.__showPlaceholder) {
|
|
||||||
this.__showPlaceholder = false;
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 设置容器组件占位,若设置占位则在初始异步请求完成之前用loading占位且不渲染容器组件内部内容
|
|
||||||
// @TODO __showPlaceholder 的逻辑一旦开启就关不掉,先注释掉了
|
|
||||||
/* this.__showPlaceholder = this.__parseData(schema.props && schema.props.autoLoading) && (dataSource.list || []).some(
|
|
||||||
(item) => !!this.__parseData(item.isInit),
|
|
||||||
); */
|
|
||||||
};
|
|
||||||
|
|
||||||
__render = () => {
|
|
||||||
const schema = this.props.__schema;
|
|
||||||
this.__setLifeCycleMethods('render');
|
|
||||||
|
|
||||||
const { engine } = this.context;
|
|
||||||
if (engine) {
|
|
||||||
engine.props.onCompGetCtx(schema, this);
|
|
||||||
// 画布场景才需要每次渲染bind自定义方法
|
|
||||||
if (engine.props.designMode) {
|
|
||||||
this.__bindCustomMethods();
|
|
||||||
this.dataSourceMap = this.__dataHelper && this.__dataHelper.updateConfig(schema.dataSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
__getRef = (ref) => {
|
|
||||||
this.__ref = ref;
|
|
||||||
};
|
|
||||||
|
|
||||||
getSchemaChildren = (schema) => {
|
|
||||||
if (!schema || !schema.props) {
|
|
||||||
return schema?.children;
|
|
||||||
}
|
|
||||||
if (!schema.children) return schema.props.children;
|
|
||||||
if (!schema.props.children) return schema.children;
|
|
||||||
let _children = [].concat(schema.children);
|
|
||||||
if (Array.isArray(schema.props.children)) {
|
|
||||||
_children = _children.concat(schema.props.children);
|
|
||||||
} else {
|
|
||||||
_children.push(schema.props.children);
|
|
||||||
}
|
|
||||||
return _children;
|
|
||||||
};
|
|
||||||
|
|
||||||
__createDom = () => {
|
|
||||||
const { __schema, __ctx, __components = {} } = this.props;
|
|
||||||
const self = {};
|
|
||||||
self.__proto__ = __ctx || this;
|
|
||||||
const _children = this.getSchemaChildren(__schema);
|
|
||||||
return this.__createVirtualDom(_children, self, {
|
|
||||||
schema: __schema,
|
|
||||||
Comp: __components[__schema.componentName],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 将模型结构转换成react Element
|
|
||||||
// schema 模型结构
|
|
||||||
// self 为每个渲染组件构造的上下文,self是自上而下继承的
|
|
||||||
// parentInfo 父组件的信息,包含schema和Comp
|
|
||||||
// idx 若为循环渲染的循环Index
|
|
||||||
__createVirtualDom = (schema, self, parentInfo, idx) => {
|
|
||||||
const { engine } = this.context || {};
|
|
||||||
try {
|
|
||||||
if (!schema) return null;
|
|
||||||
const { __appHelper: appHelper, __components: components = {} } = this.props || {};
|
|
||||||
|
|
||||||
if (isJSExpression(schema)) {
|
|
||||||
return parseExpression(schema, self);
|
|
||||||
}
|
|
||||||
if (isJSSlot(schema)) {
|
|
||||||
return this.__createVirtualDom(schema.value, self, parentInfo);
|
|
||||||
}
|
|
||||||
if (typeof schema === 'string') return schema;
|
|
||||||
if (typeof schema === 'number' || typeof schema === 'boolean') {
|
|
||||||
return schema.toString();
|
|
||||||
}
|
|
||||||
if (Array.isArray(schema)) {
|
|
||||||
if (schema.length === 1) return this.__createVirtualDom(schema[0], self, parentInfo);
|
|
||||||
return schema.map((item, idy) => this.__createVirtualDom(item, self, parentInfo, item && item.__ctx && item.__ctx.lunaKey ? '' : idy));
|
|
||||||
}
|
|
||||||
// FIXME
|
|
||||||
const _children = this.getSchemaChildren(schema);
|
|
||||||
// 解析占位组件
|
|
||||||
if (schema.componentName === 'Flagment' && _children) {
|
|
||||||
const tarChildren = isJSExpression(_children) ? parseExpression(_children, self) : _children;
|
|
||||||
return this.__createVirtualDom(tarChildren, self, parentInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.$$typeof) {
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
if (!isSchema(schema)) return null;
|
|
||||||
let Comp = components[schema.componentName] || engine.getNotFoundComponent();
|
|
||||||
|
|
||||||
if (schema.hidden) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.loop != null) {
|
|
||||||
const loop = parseData(schema.loop, self);
|
|
||||||
if ((Array.isArray(loop) && loop.length > 0) || isJSExpression(loop)) {
|
|
||||||
return this.__createLoopVirtualDom(
|
|
||||||
{
|
|
||||||
...schema,
|
|
||||||
loop,
|
|
||||||
},
|
|
||||||
self,
|
|
||||||
parentInfo,
|
|
||||||
idx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const condition = schema.condition == null ? true : parseData(schema.condition, self);
|
|
||||||
if (!condition) return null;
|
|
||||||
|
|
||||||
let scopeKey = '';
|
|
||||||
// 判断组件是否需要生成scope,且只生成一次,挂在this.__compScopes上
|
|
||||||
if (Comp.generateScope) {
|
|
||||||
const key = parseExpression(schema.props.key, self);
|
|
||||||
if (key) {
|
|
||||||
// 如果组件自己设置key则使用组件自己的key
|
|
||||||
scopeKey = key;
|
|
||||||
} else if (!schema.__ctx) {
|
|
||||||
// 在生产环境schema没有__ctx上下文,需要手动生成一个lunaKey
|
|
||||||
schema.__ctx = {
|
|
||||||
lunaKey: `luna${++scopeIdx}`,
|
|
||||||
};
|
|
||||||
scopeKey = schema.__ctx.lunaKey;
|
|
||||||
} else {
|
|
||||||
// 需要判断循环的情况
|
|
||||||
scopeKey = schema.__ctx.lunaKey + (idx !== undefined ? `_${idx}` : '');
|
|
||||||
}
|
|
||||||
if (!this.__compScopes[scopeKey]) {
|
|
||||||
this.__compScopes[scopeKey] = Comp.generateScope(this, schema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果组件有设置scope,需要为组件生成一个新的scope上下文
|
|
||||||
if (scopeKey && this.__compScopes[scopeKey]) {
|
|
||||||
const compSelf = { ...this.__compScopes[scopeKey] };
|
|
||||||
compSelf.__proto__ = self;
|
|
||||||
self = compSelf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 容器类组件的上下文通过props传递,避免context传递带来的嵌套问题
|
|
||||||
const otherProps = isFileSchema(schema)
|
|
||||||
? {
|
|
||||||
__schema: schema,
|
|
||||||
__appHelper: appHelper,
|
|
||||||
__components: components,
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
if (engine && engine.props.designMode) {
|
|
||||||
otherProps.__designMode = engine.props.designMode;
|
|
||||||
}
|
|
||||||
const componentInfo = {};
|
|
||||||
const props =
|
|
||||||
this.__parseProps(schema.props, self, '', {
|
|
||||||
schema,
|
|
||||||
Comp,
|
|
||||||
componentInfo: {
|
|
||||||
...componentInfo,
|
|
||||||
props: transformArrayToMap(componentInfo.props, 'name'),
|
|
||||||
},
|
|
||||||
}) || {};
|
|
||||||
// 对于可以获取到ref的组件做特殊处理
|
|
||||||
if (acceptsRef(Comp)) {
|
|
||||||
otherProps.ref = (ref) => {
|
|
||||||
const refProps = props.ref;
|
|
||||||
if (refProps && typeof refProps === 'string') {
|
|
||||||
this[refProps] = ref;
|
|
||||||
}
|
|
||||||
ref && engine && engine.props.onCompGetRef(schema, ref);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// scope需要传入到组件上
|
|
||||||
if (scopeKey && this.__compScopes[scopeKey]) {
|
|
||||||
props.__scope = this.__compScopes[scopeKey];
|
|
||||||
}
|
|
||||||
// FIXME 这里清除 key 是为了避免循环渲染中更改 key 导致的渲染重复
|
|
||||||
props.key = '';
|
|
||||||
if (schema.__ctx && schema.__ctx.lunaKey) {
|
|
||||||
if (!isFileSchema(schema)) {
|
|
||||||
engine && engine.props.onCompGetCtx(schema, self);
|
|
||||||
}
|
|
||||||
props.key = props.key || `${schema.__ctx.lunaKey}_${schema.__ctx.idx || 0}_${idx !== undefined ? idx : ''}`;
|
|
||||||
} else if (typeof idx === 'number' && !props.key) {
|
|
||||||
props.key = idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
props.__id = schema.id;
|
|
||||||
if (!props.key) {
|
|
||||||
props.key = props.__id;
|
|
||||||
}
|
|
||||||
|
|
||||||
let child = null;
|
|
||||||
if (/*!isFileSchema(schema) && */!!_children) {
|
|
||||||
child = this.__createVirtualDom(
|
|
||||||
isJSExpression(_children) ? parseExpression(_children, self) : _children,
|
|
||||||
self,
|
|
||||||
{
|
|
||||||
schema,
|
|
||||||
Comp,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const renderComp = (props) => engine.createElement(Comp, props, child);
|
|
||||||
// 设计模式下的特殊处理
|
|
||||||
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
|
|
||||||
// 对于overlay,dialog等组件为了使其在设计模式下显示,外层需要增加一个div容器
|
|
||||||
if (OVERLAY_LIST.includes(schema.componentName)) {
|
|
||||||
const { ref, ...overlayProps } = otherProps;
|
|
||||||
return (
|
|
||||||
<Div ref={ref} __designMode={engine.props.designMode}>
|
|
||||||
{renderComp({ ...props, ...overlayProps })}
|
|
||||||
</Div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// 虚拟dom显示
|
|
||||||
if (componentInfo && componentInfo.parentRule) {
|
|
||||||
const parentList = componentInfo.parentRule.split(',');
|
|
||||||
const { schema: parentSchema, Comp: parentComp } = parentInfo;
|
|
||||||
if (
|
|
||||||
!parentList.includes(parentSchema.componentName) ||
|
|
||||||
parentComp !== components[parentSchema.componentName]
|
|
||||||
) {
|
|
||||||
props.__componentName = schema.componentName;
|
|
||||||
Comp = VisualDom;
|
|
||||||
} else {
|
|
||||||
// 若虚拟dom在正常的渲染上下文中,就不显示设计模式了
|
|
||||||
props.__disableDesignMode = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return renderComp({ ...props, ...otherProps });
|
|
||||||
} catch (e) {
|
|
||||||
return engine.createElement(engine.getFaultComponent(), {
|
|
||||||
error: e,
|
|
||||||
schema,
|
|
||||||
self,
|
|
||||||
parentInfo,
|
|
||||||
idx,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
__createLoopVirtualDom = (schema, self, parentInfo, idx) => {
|
|
||||||
if (isFileSchema(schema)) {
|
|
||||||
console.warn('file type not support Loop');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!Array.isArray(schema.loop)) return null;
|
|
||||||
const itemArg = (schema.loopArgs && schema.loopArgs[0]) || 'item';
|
|
||||||
const indexArg = (schema.loopArgs && schema.loopArgs[1]) || 'index';
|
|
||||||
return schema.loop.map((item, i) => {
|
|
||||||
const loopSelf = {
|
|
||||||
[itemArg]: item,
|
|
||||||
[indexArg]: i,
|
|
||||||
};
|
|
||||||
loopSelf.__proto__ = self;
|
|
||||||
return this.__createVirtualDom(
|
|
||||||
{
|
|
||||||
...schema,
|
|
||||||
loop: undefined,
|
|
||||||
},
|
|
||||||
loopSelf,
|
|
||||||
parentInfo,
|
|
||||||
idx ? `${idx}_${i}` : i,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
__parseProps = (props, self, path, info) => {
|
|
||||||
const { schema, Comp, componentInfo = {} } = info;
|
|
||||||
const propInfo = getValue(componentInfo.props, path);
|
|
||||||
// FIXME! 将这行逻辑外置,解耦,线上环境不要验证参数,调试环境可以有,通过传参自定义
|
|
||||||
const propType = propInfo && propInfo.extra && propInfo.extra.propType;
|
|
||||||
const ignoreParse = schema.__ignoreParse || [];
|
|
||||||
const checkProps = (value) => {
|
|
||||||
if (!propType) return value;
|
|
||||||
return checkPropTypes(value, path, propType, componentInfo.name) ? value : undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseReactNode = (data, params) => {
|
|
||||||
if (isEmpty(params)) {
|
|
||||||
return checkProps(this.__createVirtualDom(data, self, { schema, Comp }));
|
|
||||||
}
|
|
||||||
return checkProps(function () {
|
|
||||||
const args = {};
|
|
||||||
if (Array.isArray(params) && params.length) {
|
|
||||||
params.forEach((item, idx) => {
|
|
||||||
if (typeof item === 'string') {
|
|
||||||
args[item] = arguments[idx];
|
|
||||||
} else if (item && typeof item === 'object') {
|
|
||||||
args[item.name] = arguments[idx];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
args.__proto__ = self;
|
|
||||||
return self.__createVirtualDom(data, args, { schema, Comp });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 判断是否需要解析变量
|
|
||||||
if (
|
|
||||||
ignoreParse.some((item) => {
|
|
||||||
if (item instanceof RegExp) {
|
|
||||||
return item.test(path);
|
|
||||||
}
|
|
||||||
return item === path;
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
return checkProps(props);
|
|
||||||
}
|
|
||||||
if (isJSExpression(props)) {
|
|
||||||
props = parseExpression(props, self);
|
|
||||||
// 只有当变量解析出来为模型结构的时候才会继续解析
|
|
||||||
if (!isSchema(props) && !isJSSlot(props)) return checkProps(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isJSFunction(props)) {
|
|
||||||
props = transformStringToFunction(props.value);
|
|
||||||
}
|
|
||||||
if (isJSSlot(props)) {
|
|
||||||
const { params, value } = props;
|
|
||||||
if (!isSchema(value) || isEmpty(value)) return undefined;
|
|
||||||
return parseReactNode(value, params);
|
|
||||||
}
|
|
||||||
// 兼容通过componentInfo判断的情况
|
|
||||||
if (isSchema(props)) {
|
|
||||||
const isReactNodeFunction = !!(
|
|
||||||
propInfo
|
|
||||||
&& propInfo.type === 'ReactNode'
|
|
||||||
&& propInfo.props
|
|
||||||
&& propInfo.props.type === 'function'
|
|
||||||
);
|
|
||||||
|
|
||||||
const isMixinReactNodeFunction = !!(
|
|
||||||
propInfo
|
|
||||||
&& propInfo.type === 'Mixin'
|
|
||||||
&& propInfo.props
|
|
||||||
&& propInfo.props.types
|
|
||||||
&& propInfo.props.types.indexOf('ReactNode') > -1
|
|
||||||
&& propInfo.props.reactNodeProps
|
|
||||||
&& propInfo.props.reactNodeProps.type === 'function'
|
|
||||||
);
|
|
||||||
return parseReactNode(
|
|
||||||
props,
|
|
||||||
isReactNodeFunction
|
|
||||||
? propInfo.props.params
|
|
||||||
: isMixinReactNodeFunction
|
|
||||||
? propInfo.props.reactNodeProps.params
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (Array.isArray(props)) {
|
|
||||||
return checkProps(props.map((item, idx) => this.__parseProps(item, self, path ? `${path}.${idx}` : idx, info)));
|
|
||||||
}
|
|
||||||
if (typeof props === 'function') {
|
|
||||||
return checkProps(props.bind(self));
|
|
||||||
}
|
|
||||||
if (props && typeof props === 'object') {
|
|
||||||
if (props.$$typeof) return checkProps(props);
|
|
||||||
const res = {};
|
|
||||||
forEach(props, (val, key) => {
|
|
||||||
if (key.startsWith('__')) {
|
|
||||||
res[key] = val;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res[key] = this.__parseProps(val, self, path ? `${path}.${key}` : key, info);
|
|
||||||
});
|
|
||||||
return checkProps(res);
|
|
||||||
}
|
|
||||||
if (typeof props === 'string') {
|
|
||||||
return checkProps(props.trim());
|
|
||||||
}
|
|
||||||
return checkProps(props);
|
|
||||||
};
|
|
||||||
|
|
||||||
get requestHandlersMap() {
|
|
||||||
return this.appHelper && this.appHelper.requestHandlersMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
get utils() {
|
|
||||||
return this.appHelper && this.appHelper.utils;
|
|
||||||
}
|
|
||||||
|
|
||||||
get constants() {
|
|
||||||
return this.appHelper && this.appHelper.constants;
|
|
||||||
}
|
|
||||||
|
|
||||||
get history() {
|
|
||||||
return this.appHelper && this.appHelper.history;
|
|
||||||
}
|
|
||||||
|
|
||||||
get location() {
|
|
||||||
return this.appHelper && this.appHelper.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
get match() {
|
|
||||||
return this.appHelper && this.appHelper.match;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,146 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
// import Loading from '@alifd/next/lib/loading';
|
|
||||||
// import '@alifd/next/lib/loading/style';
|
|
||||||
import BaseRenderer from './base';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import { isSchema, getFileCssName } from '../utils';
|
|
||||||
|
|
||||||
const debug = Debug('renderer:block');
|
|
||||||
|
|
||||||
export default class BlockRenderer extends BaseRenderer {
|
|
||||||
static dislayName = 'block-renderer';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
|
||||||
debug('block.getDerivedStateFromProps');
|
|
||||||
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
|
||||||
if (func) {
|
|
||||||
return func(props, state);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.__generateCtx();
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
this.state = this.__parseData(schema.state || {});
|
|
||||||
this.__initDataSource(props);
|
|
||||||
this.__setLifeCycleMethods('constructor', arguments);
|
|
||||||
debug(`block.constructor - ${schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
super.getSnapshotBeforeUpdate(...arguments);
|
|
||||||
debug(`block.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
super.componentDidMount(...arguments);
|
|
||||||
debug(`block.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
super.componentDidUpdate(...arguments);
|
|
||||||
debug(`block.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
super.componentWillUnmount(...arguments);
|
|
||||||
debug(`block.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch() {
|
|
||||||
await super.componentDidCatch(...arguments);
|
|
||||||
debug(`block.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema, __components } = this.props;
|
|
||||||
|
|
||||||
if (!isSchema(__schema, true) || (__schema.componentName !== 'Block' && __schema.componentName !== 'Div')) {
|
|
||||||
return '区块schema结构异常!';
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(`block.render - ${__schema.fileName}`);
|
|
||||||
this.__generateCtx();
|
|
||||||
this.__render();
|
|
||||||
|
|
||||||
const props = this.__parseData(__schema.props);
|
|
||||||
const { id, className, style, autoLoading, defaultHeight = 300, loading } = props;
|
|
||||||
|
|
||||||
const { Block } = __components;
|
|
||||||
if (Block) {
|
|
||||||
const { engine } = this.context || {};
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
blockContext: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{engine.createElement(
|
|
||||||
Block,
|
|
||||||
{
|
|
||||||
...props,
|
|
||||||
ref: this.__getRef,
|
|
||||||
className: classnames(getFileCssName(__schema.fileName), className, this.props.className),
|
|
||||||
__id: __schema.id,
|
|
||||||
},
|
|
||||||
this.__createDom(),
|
|
||||||
)}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderContent = () => (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
blockContext: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.__createDom()}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
|
|
||||||
// if (autoLoading || loading !== undefined) {
|
|
||||||
// return (
|
|
||||||
// <Loading
|
|
||||||
// size="medium"
|
|
||||||
// visible={!!(this.__showPlaceholder || loading)}
|
|
||||||
// style={{
|
|
||||||
// height: this.__showPlaceholder ? defaultHeight : 'auto',
|
|
||||||
// display: 'block',
|
|
||||||
// ...style,
|
|
||||||
// }}
|
|
||||||
// className={classnames('luna-block', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
// id={id}
|
|
||||||
// >
|
|
||||||
// {!this.__showPlaceholder && renderContent()}
|
|
||||||
// </Loading>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={this.__getRef}
|
|
||||||
className={classnames('luna-block', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
id={id}
|
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
{renderContent()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,129 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
// import Loading from '@alifd/next/lib/loading';
|
|
||||||
// import '@alifd/next/lib/loading/style';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import BaseRenderer from './base';
|
|
||||||
import { isSchema, getFileCssName } from '../utils';
|
|
||||||
|
|
||||||
const debug = Debug('renderer:comp');
|
|
||||||
|
|
||||||
export default class CompRenderer extends BaseRenderer {
|
|
||||||
static dislayName = 'comp-renderer';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
|
||||||
debug('comp.getDerivedStateFromProps');
|
|
||||||
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
|
||||||
if (func) {
|
|
||||||
return func(props, state);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.__generateCtx({
|
|
||||||
component: this,
|
|
||||||
});
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
this.state = this.__parseData(schema.state || {});
|
|
||||||
this.__initDataSource(props);
|
|
||||||
this.__setLifeCycleMethods('constructor', arguments);
|
|
||||||
debug(`comp.constructor - ${schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
super.getSnapshotBeforeUpdate(...arguments);
|
|
||||||
debug(`comp.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
super.componentDidMount(...arguments);
|
|
||||||
debug(`comp.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate() {
|
|
||||||
super.componentDidUpdate(...arguments);
|
|
||||||
debug(`comp.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
super.componentWillUnmount(...arguments);
|
|
||||||
debug(`comp.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch() {
|
|
||||||
super.componentDidCatch(...arguments);
|
|
||||||
debug(`comp.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema } = this.props;
|
|
||||||
|
|
||||||
if (!isSchema(__schema, true) || __schema.componentName !== 'Component') {
|
|
||||||
return '自定义组件schema结构异常!';
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(`comp.render - ${__schema.fileName}`);
|
|
||||||
this.__generateCtx({
|
|
||||||
component: this,
|
|
||||||
});
|
|
||||||
this.__render();
|
|
||||||
|
|
||||||
const { id, className, style, noContainer, autoLoading, defaultHeight = 300, loading } = this.__parseData(
|
|
||||||
__schema.props,
|
|
||||||
);
|
|
||||||
const renderContent = () => (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
compContext: this,
|
|
||||||
blockContext: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.__createDom()}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (noContainer) {
|
|
||||||
return renderContent();
|
|
||||||
}
|
|
||||||
// if (autoLoading || loading !== undefined) {
|
|
||||||
// return (
|
|
||||||
// <Loading
|
|
||||||
// size="medium"
|
|
||||||
// visible={!!(this.__showPlaceholder || loading)}
|
|
||||||
// style={{
|
|
||||||
// height: this.__showPlaceholder ? defaultHeight : 'auto',
|
|
||||||
// display: 'block',
|
|
||||||
// ...style,
|
|
||||||
// }}
|
|
||||||
// className={classnames('luna-comp', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
// id={this.props.id || id}
|
|
||||||
// >
|
|
||||||
// {!this.__showPlaceholder && renderContent()}
|
|
||||||
// </Loading>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={this.__getRef}
|
|
||||||
className={classnames('luna-comp', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
id={this.props.id || id}
|
|
||||||
style={{ ...style, ...this.props.style }}
|
|
||||||
>
|
|
||||||
{renderContent()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,166 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
// import Loading from '@alifd/next/lib/loading';
|
|
||||||
// import '@alifd/next/lib/loading/style';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import BaseRenderer from './base';
|
|
||||||
import { isSchema, getFileCssName, parseData } from '../utils';
|
|
||||||
|
|
||||||
const debug = Debug('renderer:page');
|
|
||||||
|
|
||||||
export default class PageRenderer extends BaseRenderer {
|
|
||||||
static dislayName = 'page-renderer';
|
|
||||||
static propTypes = {
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
|
||||||
debug('page.getDerivedStateFromProps');
|
|
||||||
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
|
||||||
|
|
||||||
if (func) {
|
|
||||||
return func(props, state);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.__generateCtx({
|
|
||||||
page: this,
|
|
||||||
});
|
|
||||||
const schema = props.__schema || {};
|
|
||||||
this.state = this.__parseData(schema.state || {});
|
|
||||||
this.__initDataSource(props);
|
|
||||||
this.__setLifeCycleMethods('constructor', arguments);
|
|
||||||
|
|
||||||
debug(`page.constructor - ${schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSnapshotBeforeUpdate() {
|
|
||||||
super.getSnapshotBeforeUpdate(...arguments);
|
|
||||||
debug(`page.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
super.componentDidMount(...arguments);
|
|
||||||
debug(`page.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidUpdate(prevProps) {
|
|
||||||
const { __ctx } = this.props;
|
|
||||||
const prevState = parseData(prevProps.__schema.state, __ctx);
|
|
||||||
const newState = parseData(this.props.__schema.state, __ctx);
|
|
||||||
// 当编排的时候修改schema.state值,需要将最新schema.state值setState
|
|
||||||
if (JSON.stringify(newState) != JSON.stringify(prevState)) {
|
|
||||||
this.setState(newState);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.componentDidUpdate(...arguments);
|
|
||||||
debug(`page.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
super.componentWillUnmount(...arguments);
|
|
||||||
debug(`page.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidCatch() {
|
|
||||||
await super.componentDidCatch(...arguments);
|
|
||||||
debug(`page.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema, __components } = this.props;
|
|
||||||
if (!isSchema(__schema, true) || __schema.componentName !== 'Page') {
|
|
||||||
return '页面schema结构异常!';
|
|
||||||
}
|
|
||||||
debug(`page.render - ${__schema.fileName}`);
|
|
||||||
|
|
||||||
this.__bindCustomMethods(this.props);
|
|
||||||
this.__initDataSource(this.props);
|
|
||||||
|
|
||||||
// this.__setLifeCycleMethods('constructor', arguments);
|
|
||||||
|
|
||||||
this.__generateCtx({
|
|
||||||
page: this,
|
|
||||||
});
|
|
||||||
this.__render();
|
|
||||||
|
|
||||||
const props = this.__parseData(__schema.props);
|
|
||||||
const { id, className, style, autoLoading, defaultHeight = 300, loading,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const { Page } = __components;
|
|
||||||
if (Page) {
|
|
||||||
const { engine } = this.context || {};
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
pageContext: this,
|
|
||||||
blockContext: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{engine.createElement(
|
|
||||||
Page,
|
|
||||||
{
|
|
||||||
...props,
|
|
||||||
ref: this.__getRef,
|
|
||||||
className: classnames(getFileCssName(__schema.fileName), className, this.props.className),
|
|
||||||
__id: __schema.id,
|
|
||||||
},
|
|
||||||
this.__createDom(),
|
|
||||||
)}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderContent = () => (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
pageContext: this,
|
|
||||||
blockContext: this,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.__createDom()}
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
|
|
||||||
// if (autoLoading || loading !== undefined) {
|
|
||||||
// return (
|
|
||||||
// <Loading
|
|
||||||
// size="medium"
|
|
||||||
// visible={!!(this.__showPlaceholder || loading)}
|
|
||||||
// style={{
|
|
||||||
// height: this.__showPlaceholder ? defaultHeight : 'auto',
|
|
||||||
// display: 'block',
|
|
||||||
// ...style,
|
|
||||||
// }}
|
|
||||||
// className={classnames('luna-page', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
// id={id}
|
|
||||||
// >
|
|
||||||
// {!this.__showPlaceholder && renderContent()}
|
|
||||||
// </Loading>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={this.__getRef}
|
|
||||||
className={classnames('luna-page', getFileCssName(__schema.fileName), className, this.props.className)}
|
|
||||||
id={id}
|
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
{renderContent()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import BaseRenderer from './base';
|
|
||||||
import { isSchema } from '../utils';
|
|
||||||
|
|
||||||
const debug = Debug('renderer:temp');
|
|
||||||
|
|
||||||
export default class TempRenderer extends BaseRenderer {
|
|
||||||
static dislayName = 'temp-renderer';
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
__ctx: PropTypes.object,
|
|
||||||
__schema: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
__ctx: {},
|
|
||||||
__schema: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.state = {};
|
|
||||||
this.cacheSetState = {};
|
|
||||||
debug(`temp.constructor - ${props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const ctx = this.props.__ctx;
|
|
||||||
if (!ctx) return;
|
|
||||||
const { setState } = ctx;
|
|
||||||
this.cacheSetState = setState;
|
|
||||||
ctx.setState = (...args) => {
|
|
||||||
setState.call(ctx, ...args);
|
|
||||||
setTimeout(() => this.forceUpdate(), 0);
|
|
||||||
};
|
|
||||||
debug(`temp.componentDidMount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
debug(`temp.componentDidUpdate - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
const ctx = this.props.__ctx;
|
|
||||||
if (!ctx || !this.cacheSetState) return;
|
|
||||||
ctx.setState = this.cacheSetState;
|
|
||||||
delete this.cacheSetState;
|
|
||||||
debug(`temp.componentWillUnmount - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidCatch(e) {
|
|
||||||
console.warn(e);
|
|
||||||
debug(`temp.componentDidCatch - ${this.props.__schema.fileName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { __schema, __ctx } = this.props;
|
|
||||||
if (!isSchema(__schema, true) || __schema.componentName !== 'Temp') {
|
|
||||||
return '下钻编辑 schema 结构异常!';
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(`temp.render - ${__schema.fileName}`);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div ref={this.__getRef} className="luna-temp">
|
|
||||||
<AppContext.Provider value={{ ...this.context, ...__ctx }}>{this.__createDom()}</AppContext.Provider>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
865
packages/react-renderer/tests/__snapshots__/index.test.tsx.snap
Normal file
865
packages/react-renderer/tests/__snapshots__/index.test.tsx.snap
Normal file
@ -0,0 +1,865 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`React Renderer render basic case 1`] = `
|
||||||
|
<div
|
||||||
|
className="lce-page luna-test"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"padding": "0 5px 0 5px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
__id="node_dockcy8n9xed"
|
||||||
|
className="next-box"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "rgba(31,56,88,0.1)",
|
||||||
|
"flexDirection": "column",
|
||||||
|
"flexWrap": "nowrap",
|
||||||
|
"msFlexDirection": "column",
|
||||||
|
"msFlexWrap": "none",
|
||||||
|
"padding": "12px 12px 12px 12px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
__id="node_dockcy8n9xee"
|
||||||
|
className="next-box"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"flexDirection": "column",
|
||||||
|
"flexWrap": "nowrap",
|
||||||
|
"msFlexDirection": "column",
|
||||||
|
"msFlexWrap": "none",
|
||||||
|
"padding": "12px 12px 12px 12px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<nav
|
||||||
|
__id="node_dockcy8n9xef"
|
||||||
|
aria-label="Breadcrumb"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"position": "relative",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
className="next-breadcrumb"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
className="next-breadcrumb-item"
|
||||||
|
dir={null}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
__id="node_dockcy8n9xeg"
|
||||||
|
className="next-breadcrumb-text"
|
||||||
|
>
|
||||||
|
首页
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="next-breadcrumb-separator"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep"
|
||||||
|
style={Object {}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
className="next-breadcrumb-item"
|
||||||
|
dir={null}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
__id="node_dockcy8n9xei"
|
||||||
|
className="next-breadcrumb-text"
|
||||||
|
>
|
||||||
|
品质中台
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="next-breadcrumb-separator"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep"
|
||||||
|
style={Object {}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
className="next-breadcrumb-item"
|
||||||
|
dir={null}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
__id="node_dockcy8n9xek"
|
||||||
|
className="next-breadcrumb-text"
|
||||||
|
>
|
||||||
|
商家品质页面管理
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="next-breadcrumb-separator"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="next-icon next-icon-arrow-right next-medium next-breadcrumb-icon-sep"
|
||||||
|
style={Object {}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
className="next-breadcrumb-item"
|
||||||
|
dir={null}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
__id="node_dockcy8n9xem"
|
||||||
|
aria-current="page"
|
||||||
|
className="next-breadcrumb-text activated"
|
||||||
|
>
|
||||||
|
质检知识条配置
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
__id="node_dockcy8n9xeo"
|
||||||
|
className="next-box"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"flexDirection": "column",
|
||||||
|
"flexWrap": "nowrap",
|
||||||
|
"marginTop": "12px",
|
||||||
|
"msFlexDirection": "column",
|
||||||
|
"msFlexWrap": "none",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
__events={Array []}
|
||||||
|
__id="node_dockcy8n9xep"
|
||||||
|
className="next-form next-inline next-medium"
|
||||||
|
onSubmit={[Function]}
|
||||||
|
role="grid"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"marginLeft": "12px",
|
||||||
|
"marginRight": "12px",
|
||||||
|
"marginTop": "12px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
__id="node_dockcy8n9xeq"
|
||||||
|
className="next-form-item next-left next-medium"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"marginBottom": "0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="next-form-item-label"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
类目名:
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="next-form-item-control"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-haspopup={true}
|
||||||
|
className="next-select next-select-trigger next-select-single next-medium next-inactive next-no-search"
|
||||||
|
onClick={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onMouseLeave={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"width": "150px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-input next-medium next-select-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-select-values next-input-text-field"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-select-trigger-search"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
__id="node_dockcy8n9xer"
|
||||||
|
autoComplete="off"
|
||||||
|
disabled={false}
|
||||||
|
height="100%"
|
||||||
|
maxLength={null}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onChange={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
placeholder="请选择"
|
||||||
|
readOnly={true}
|
||||||
|
role="combobox"
|
||||||
|
size="1"
|
||||||
|
tabIndex={0}
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
aria-hidden={true}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
请选择
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="next-input-control"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden={true}
|
||||||
|
className="next-select-arrow"
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="next-icon next-icon-arrow-down next-medium next-select-symbol-fold"
|
||||||
|
style={Object {}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
aria-live="polite"
|
||||||
|
className="next-sr-only"
|
||||||
|
>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
__id="node_dockcy8n9xes"
|
||||||
|
className="next-form-item next-left next-medium"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"marginBottom": "0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="next-form-item-label"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
项目类型:
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="next-form-item-control"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-haspopup={true}
|
||||||
|
className="next-select next-select-trigger next-select-single next-medium next-inactive next-no-search"
|
||||||
|
onClick={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onMouseLeave={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"width": "200px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-input next-medium next-select-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-select-values next-input-text-field"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-select-trigger-search"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
__id="node_dockcy8n9xet"
|
||||||
|
autoComplete="off"
|
||||||
|
disabled={false}
|
||||||
|
height="100%"
|
||||||
|
maxLength={null}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onChange={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
placeholder="请选择"
|
||||||
|
readOnly={true}
|
||||||
|
role="combobox"
|
||||||
|
size="1"
|
||||||
|
tabIndex={0}
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
aria-hidden={true}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
请选择
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="next-input-control"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden={true}
|
||||||
|
className="next-select-arrow"
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="next-icon next-icon-arrow-down next-medium next-select-symbol-fold"
|
||||||
|
style={Object {}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
aria-live="polite"
|
||||||
|
className="next-sr-only"
|
||||||
|
>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
__id="node_dockcy8n9xeu"
|
||||||
|
className="next-form-item next-left next-medium"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"marginBottom": "0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="next-form-item-label"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
项目 ID:
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="next-form-item-control"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-input next-medium"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"width": "200px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
__id="node_dockcy8n9xev"
|
||||||
|
autoComplete="off"
|
||||||
|
disabled={false}
|
||||||
|
height="100%"
|
||||||
|
maxLength={null}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onChange={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
readOnly={false}
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
__id="node_dockcy8n9xew"
|
||||||
|
className="next-btn-group"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
__id="node_dockcy8n9xex"
|
||||||
|
className="next-btn next-medium next-btn-primary"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"margin": "0 5px 0 5px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
搜索
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
__id="node_dockcy8n9xe10"
|
||||||
|
className="next-btn next-medium next-btn-normal"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"margin": "0 5px 0 5px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type="reset"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
清空
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
__id="node_dockcy8n9xe1f"
|
||||||
|
className="next-box"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"display": "flex",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"flexWrap": "nowrap",
|
||||||
|
"justifyContent": "flex-end",
|
||||||
|
"msFlexDirection": "column",
|
||||||
|
"msFlexWrap": "none",
|
||||||
|
"paddingBottom": "24px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
__events={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"name": "onClick",
|
||||||
|
"relatedEventName": "onClick",
|
||||||
|
"type": "componentEvent",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
__id="node_dockd5nrh9p4"
|
||||||
|
className="next-btn next-medium next-btn-primary"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
style={Object {}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
新建配置
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
__id="node_dockd5nrh9p5"
|
||||||
|
className="next-box"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"flexDirection": "column",
|
||||||
|
"flexWrap": "nowrap",
|
||||||
|
"msFlexDirection": "column",
|
||||||
|
"msFlexWrap": "none",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
__id="node_dockjielosj1"
|
||||||
|
actionBar={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"title": "新增",
|
||||||
|
"type": "primary",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"title": "编辑",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
actionColumn={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"callback": [Function],
|
||||||
|
"device": Array [
|
||||||
|
"desktop",
|
||||||
|
],
|
||||||
|
"title": "编辑",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"callback": [Function],
|
||||||
|
"mode": "EDIT",
|
||||||
|
"title": "保存",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
actionFixed="right"
|
||||||
|
actionHidden={false}
|
||||||
|
actionTitle="操作"
|
||||||
|
actionType="link"
|
||||||
|
actionWidth={180}
|
||||||
|
className="next-table next-table-medium"
|
||||||
|
data={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"age": 15000,
|
||||||
|
"email": "aaa@abc.com",
|
||||||
|
"id": "1",
|
||||||
|
"name": "王小",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"age": 25000,
|
||||||
|
"email": "bbb@abc.com",
|
||||||
|
"id": "2",
|
||||||
|
"name": "王中",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"age": 35000,
|
||||||
|
"email": "ccc@abc.com",
|
||||||
|
"id": "3",
|
||||||
|
"name": "王大",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
maxWebShownActionCount={2}
|
||||||
|
showActionBar={true}
|
||||||
|
showMiniPager={true}
|
||||||
|
style={Object {}}
|
||||||
|
>
|
||||||
|
<table
|
||||||
|
role="table"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"width": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<colgroup>
|
||||||
|
<col
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"width": 200,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<col
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"width": 200,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<col
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"width": 200,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</colgroup>
|
||||||
|
<thead
|
||||||
|
className="next-table-header"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
className="next-table-cell next-table-header-node"
|
||||||
|
dataKey="name"
|
||||||
|
editType="text"
|
||||||
|
role="gridcell"
|
||||||
|
rowSpan={1}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"textAlign": "center",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="next-table-cell-wrapper"
|
||||||
|
data-next-table-col={0}
|
||||||
|
>
|
||||||
|
姓名
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="next-table-cell next-table-header-node"
|
||||||
|
dataKey="age"
|
||||||
|
role="gridcell"
|
||||||
|
rowSpan={1}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"textAlign": "center",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="next-table-cell-wrapper"
|
||||||
|
data-next-table-col={1}
|
||||||
|
>
|
||||||
|
年龄
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="next-table-cell next-table-header-node"
|
||||||
|
dataKey="email"
|
||||||
|
role="gridcell"
|
||||||
|
rowSpan={1}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"textAlign": "center",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="next-table-cell-wrapper"
|
||||||
|
data-next-table-col={2}
|
||||||
|
>
|
||||||
|
邮箱
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody
|
||||||
|
className="next-table-body"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan={3}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="next-table-empty"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"left": 0,
|
||||||
|
"overflow": "hidden",
|
||||||
|
"position": "sticky",
|
||||||
|
"width": -2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
没有数据
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
__id="node_dockd5nrh9pg"
|
||||||
|
className="next-box"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"display": "flex",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"flexWrap": "nowrap",
|
||||||
|
"justifyContent": "flex-end",
|
||||||
|
"msFlexDirection": "column",
|
||||||
|
"msFlexWrap": "none",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
__id="node_dockd5nrh9pf"
|
||||||
|
className="next-pagination next-medium next-normal"
|
||||||
|
style={Object {}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="next-pagination-pages"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="上一页,当前第1页"
|
||||||
|
className="next-btn next-medium next-btn-normal next-pagination-item next-prev"
|
||||||
|
disabled={true}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="next-icon next-icon-arrow-left next-xs next-btn-icon next-icon-first next-pagination-icon-prev"
|
||||||
|
style={Object {}}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
上一页
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
className="next-pagination-list"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="第1页,共10页"
|
||||||
|
className="next-btn next-medium next-btn-normal next-pagination-item next-current"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
1
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="第2页,共10页"
|
||||||
|
className="next-btn next-medium next-btn-normal next-pagination-item"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
2
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="第3页,共10页"
|
||||||
|
className="next-btn next-medium next-btn-normal next-pagination-item"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
3
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="第4页,共10页"
|
||||||
|
className="next-btn next-medium next-btn-normal next-pagination-item"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
4
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<i
|
||||||
|
className="next-icon next-icon-ellipsis next-medium next-pagination-ellipsis next-pagination-icon-ellipsis"
|
||||||
|
style={Object {}}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
aria-label="第10页,共10页"
|
||||||
|
className="next-btn next-medium next-btn-normal next-pagination-item"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
10
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
aria-label="下一页,当前第1页"
|
||||||
|
className="next-btn next-medium next-btn-normal next-pagination-item next-next"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
下一页
|
||||||
|
</span>
|
||||||
|
<i
|
||||||
|
className="next-icon next-icon-arrow-right next-xs next-btn-icon next-icon-last next-pagination-icon-next"
|
||||||
|
style={Object {}}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<span
|
||||||
|
className="next-pagination-display"
|
||||||
|
>
|
||||||
|
<em>
|
||||||
|
1
|
||||||
|
</em>
|
||||||
|
/
|
||||||
|
10
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="next-pagination-jump-text"
|
||||||
|
>
|
||||||
|
到第
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="next-input next-medium next-pagination-jump-input"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
aria-label="请输入跳转到第几页"
|
||||||
|
autoComplete="off"
|
||||||
|
disabled={false}
|
||||||
|
height="100%"
|
||||||
|
maxLength={null}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onChange={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
readOnly={false}
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="next-pagination-jump-text"
|
||||||
|
>
|
||||||
|
页
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
className="next-btn next-medium next-btn-normal next-pagination-jump-go"
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="next-btn-helper"
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
__id="node_dockd5nrh9pr"
|
||||||
|
name="error"
|
||||||
|
>
|
||||||
|
Component Not Found
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
567
packages/react-renderer/tests/fixtures/schema/basic.ts
vendored
Normal file
567
packages/react-renderer/tests/fixtures/schema/basic.ts
vendored
Normal file
@ -0,0 +1,567 @@
|
|||||||
|
export default{
|
||||||
|
"componentName": "Page",
|
||||||
|
"id": "node_dockcviv8fo1",
|
||||||
|
"props": {
|
||||||
|
"ref": "outterView",
|
||||||
|
"autoLoading": true,
|
||||||
|
"style": {
|
||||||
|
"padding": "0 5px 0 5px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fileName": "test",
|
||||||
|
"dataSource": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "outter",
|
||||||
|
"isShowDialog": false
|
||||||
|
},
|
||||||
|
"css": "body {font-size: 12px;} .botton{width:100px;color:#ff00ff}",
|
||||||
|
"lifeCycles": {
|
||||||
|
"componentDidMount": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function() {\n console.log('did mount');\n }"
|
||||||
|
},
|
||||||
|
"componentWillUnmount": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function() {\n console.log('will umount');\n }"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"methods": {
|
||||||
|
"testFunc": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function() {\n console.log('test func');\n }"
|
||||||
|
},
|
||||||
|
"onClick": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function() {\n this.setState({\n isShowDialog: true\n })\n }"
|
||||||
|
},
|
||||||
|
"closeDialog": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function() {\n this.setState({\n isShowDialog: false\n })\n }"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Box",
|
||||||
|
"id": "node_dockcy8n9xed",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"backgroundColor": "rgba(31,56,88,0.1)",
|
||||||
|
"padding": "12px 12px 12px 12px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Box",
|
||||||
|
"id": "node_dockcy8n9xee",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"padding": "12px 12px 12px 12px",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Breadcrumb",
|
||||||
|
"id": "node_dockcy8n9xef",
|
||||||
|
"props": {
|
||||||
|
"prefix": "next-",
|
||||||
|
"maxNode": 100,
|
||||||
|
"component": "nav"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Breadcrumb.Item",
|
||||||
|
"id": "node_dockcy8n9xeg",
|
||||||
|
"props": {
|
||||||
|
"prefix": "next-",
|
||||||
|
"children": "首页"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Breadcrumb.Item",
|
||||||
|
"id": "node_dockcy8n9xei",
|
||||||
|
"props": {
|
||||||
|
"prefix": "next-",
|
||||||
|
"children": "品质中台"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Breadcrumb.Item",
|
||||||
|
"id": "node_dockcy8n9xek",
|
||||||
|
"props": {
|
||||||
|
"prefix": "next-",
|
||||||
|
"children": "商家品质页面管理"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Breadcrumb.Item",
|
||||||
|
"id": "node_dockcy8n9xem",
|
||||||
|
"props": {
|
||||||
|
"prefix": "next-",
|
||||||
|
"children": "质检知识条配置"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Box",
|
||||||
|
"id": "node_dockcy8n9xeo",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"marginTop": "12px",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Form",
|
||||||
|
"id": "node_dockcy8n9xep",
|
||||||
|
"props": {
|
||||||
|
"inline": true,
|
||||||
|
"style": {
|
||||||
|
"marginTop": "12px",
|
||||||
|
"marginRight": "12px",
|
||||||
|
"marginLeft": "12px"
|
||||||
|
},
|
||||||
|
"__events": []
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"id": "node_dockcy8n9xeq",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"marginBottom": "0"
|
||||||
|
},
|
||||||
|
"label": "类目名:"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Select",
|
||||||
|
"id": "node_dockcy8n9xer",
|
||||||
|
"props": {
|
||||||
|
"mode": "single",
|
||||||
|
"hasArrow": true,
|
||||||
|
"cacheValue": true,
|
||||||
|
"style": {
|
||||||
|
"width": "150px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"id": "node_dockcy8n9xes",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"marginBottom": "0"
|
||||||
|
},
|
||||||
|
"label": "项目类型:"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Select",
|
||||||
|
"id": "node_dockcy8n9xet",
|
||||||
|
"props": {
|
||||||
|
"mode": "single",
|
||||||
|
"hasArrow": true,
|
||||||
|
"cacheValue": true,
|
||||||
|
"style": {
|
||||||
|
"width": "200px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"id": "node_dockcy8n9xeu",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"marginBottom": "0"
|
||||||
|
},
|
||||||
|
"label": "项目 ID:"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Input",
|
||||||
|
"id": "node_dockcy8n9xev",
|
||||||
|
"props": {
|
||||||
|
"hasBorder": true,
|
||||||
|
"size": "medium",
|
||||||
|
"autoComplete": "off",
|
||||||
|
"style": {
|
||||||
|
"width": "200px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Button.Group",
|
||||||
|
"id": "node_dockcy8n9xew",
|
||||||
|
"props": {},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Button",
|
||||||
|
"id": "node_dockcy8n9xex",
|
||||||
|
"props": {
|
||||||
|
"type": "primary",
|
||||||
|
"style": {
|
||||||
|
"margin": "0 5px 0 5px"
|
||||||
|
},
|
||||||
|
"htmlType": "submit",
|
||||||
|
"children": "搜索"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Button",
|
||||||
|
"id": "node_dockcy8n9xe10",
|
||||||
|
"props": {
|
||||||
|
"type": "normal",
|
||||||
|
"style": {
|
||||||
|
"margin": "0 5px 0 5px"
|
||||||
|
},
|
||||||
|
"htmlType": "reset",
|
||||||
|
"children": "清空"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Box",
|
||||||
|
"id": "node_dockcy8n9xe1f",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"paddingBottom": "24px",
|
||||||
|
"display": "flex",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"justifyContent": "flex-end"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Button",
|
||||||
|
"id": "node_dockd5nrh9p4",
|
||||||
|
"props": {
|
||||||
|
"type": "primary",
|
||||||
|
"size": "medium",
|
||||||
|
"htmlType": "button",
|
||||||
|
"component": "button",
|
||||||
|
"children": "新建配置",
|
||||||
|
"style": {},
|
||||||
|
"__events": [
|
||||||
|
{
|
||||||
|
"type": "componentEvent",
|
||||||
|
"name": "onClick",
|
||||||
|
"relatedEventName": "onClick"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"onClick": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function(){ this.onClick() }"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Box",
|
||||||
|
"id": "node_dockd5nrh9p5",
|
||||||
|
"props": {},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Table",
|
||||||
|
"id": "node_dockjielosj1",
|
||||||
|
"props": {
|
||||||
|
"showMiniPager": true,
|
||||||
|
"showActionBar": true,
|
||||||
|
"actionBar": [
|
||||||
|
{
|
||||||
|
"title": "新增",
|
||||||
|
"type": "primary"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "编辑"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"dataKey": "name",
|
||||||
|
"width": 200,
|
||||||
|
"align": "center",
|
||||||
|
"title": "姓名",
|
||||||
|
"editType": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataKey": "age",
|
||||||
|
"width": 200,
|
||||||
|
"align": "center",
|
||||||
|
"title": "年龄"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataKey": "email",
|
||||||
|
"width": 200,
|
||||||
|
"align": "center",
|
||||||
|
"title": "邮箱"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "王小",
|
||||||
|
"id": "1",
|
||||||
|
"age": 15000,
|
||||||
|
"email": "aaa@abc.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "王中",
|
||||||
|
"id": "2",
|
||||||
|
"age": 25000,
|
||||||
|
"email": "bbb@abc.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "王大",
|
||||||
|
"id": "3",
|
||||||
|
"age": 35000,
|
||||||
|
"email": "ccc@abc.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"actionTitle": "操作",
|
||||||
|
"actionWidth": 180,
|
||||||
|
"actionType": "link",
|
||||||
|
"actionFixed": "right",
|
||||||
|
"actionHidden": false,
|
||||||
|
"maxWebShownActionCount": 2,
|
||||||
|
"actionColumn": [
|
||||||
|
{
|
||||||
|
"title": "编辑",
|
||||||
|
"callback": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "(rowData, action, table) => {\n return table.editRow(rowData).then((row) => {\n console.log(row);\n });\n }"
|
||||||
|
},
|
||||||
|
"device": [
|
||||||
|
"desktop"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "保存",
|
||||||
|
"callback": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "(rowData, action, table) => { \nreturn table.saveRow(rowData).then((row) => { \nconsole.log(row); \n}); \n}"
|
||||||
|
},
|
||||||
|
"mode": "EDIT"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Box",
|
||||||
|
"id": "node_dockd5nrh9pg",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"display": "flex",
|
||||||
|
"flexDirection": "row",
|
||||||
|
"justifyContent": "flex-end"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Pagination",
|
||||||
|
"id": "node_dockd5nrh9pf",
|
||||||
|
"props": {
|
||||||
|
"prefix": "next-",
|
||||||
|
"type": "normal",
|
||||||
|
"shape": "normal",
|
||||||
|
"size": "medium",
|
||||||
|
"defaultCurrent": 1,
|
||||||
|
"total": 100,
|
||||||
|
"pageShowCount": 5,
|
||||||
|
"pageSize": 10,
|
||||||
|
"pageSizePosition": "start",
|
||||||
|
"showJump": true,
|
||||||
|
"style": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Dialog",
|
||||||
|
"id": "node_dockcy8n9xe1h",
|
||||||
|
"props": {
|
||||||
|
"prefix": "next-",
|
||||||
|
"footerAlign": "right",
|
||||||
|
"footerActions": [
|
||||||
|
"ok",
|
||||||
|
"cancel"
|
||||||
|
],
|
||||||
|
"closeable": "esc,close",
|
||||||
|
"hasMask": true,
|
||||||
|
"align": "cc cc",
|
||||||
|
"minMargin": 40,
|
||||||
|
"visible": {
|
||||||
|
"type": "JSExpression",
|
||||||
|
"value": "this.state.isShowDialog"
|
||||||
|
},
|
||||||
|
"title": "标题",
|
||||||
|
"events": [],
|
||||||
|
"__events": [
|
||||||
|
{
|
||||||
|
"type": "componentEvent",
|
||||||
|
"name": "onCancel",
|
||||||
|
"relatedEventName": "closeDialog"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "componentEvent",
|
||||||
|
"name": "onClose",
|
||||||
|
"relatedEventName": "closeDialog"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "componentEvent",
|
||||||
|
"name": "onOk",
|
||||||
|
"relatedEventName": "testFunc"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"onCancel": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function(){ this.closeDialog() }"
|
||||||
|
},
|
||||||
|
"onClose": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function(){ this.closeDialog() }"
|
||||||
|
},
|
||||||
|
"onOk": {
|
||||||
|
"type": "JSFunction",
|
||||||
|
"value": "function(){ this.testFunc() }"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Form",
|
||||||
|
"id": "node_dockd5nrh9pi",
|
||||||
|
"props": {
|
||||||
|
"inline": false,
|
||||||
|
"labelAlign": "top",
|
||||||
|
"labelTextAlign": "right",
|
||||||
|
"size": "medium"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"id": "node_dockd5nrh9pj",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"marginBottom": "0",
|
||||||
|
"minWidth": "200px",
|
||||||
|
"minHeight": "28px"
|
||||||
|
},
|
||||||
|
"label": "商品类目"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Select",
|
||||||
|
"id": "node_dockd5nrh9pk",
|
||||||
|
"props": {
|
||||||
|
"mode": "single",
|
||||||
|
"hasArrow": true,
|
||||||
|
"cacheValue": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"id": "node_dockd5nrh9pl",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"marginBottom": "0",
|
||||||
|
"minWidth": "200px",
|
||||||
|
"minHeight": "28px"
|
||||||
|
},
|
||||||
|
"label": "商品类目"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Select",
|
||||||
|
"id": "node_dockd5nrh9pm",
|
||||||
|
"props": {
|
||||||
|
"mode": "single",
|
||||||
|
"hasArrow": true,
|
||||||
|
"cacheValue": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"id": "node_dockd5nrh9pn",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"marginBottom": "0",
|
||||||
|
"minWidth": "200px",
|
||||||
|
"minHeight": "28px"
|
||||||
|
},
|
||||||
|
"label": "商品类目",
|
||||||
|
"asterisk": true
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Select",
|
||||||
|
"id": "node_dockd5nrh9po",
|
||||||
|
"props": {
|
||||||
|
"mode": "single",
|
||||||
|
"hasArrow": true,
|
||||||
|
"cacheValue": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"id": "node_dockd5nrh9pp",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"marginBottom": "0",
|
||||||
|
"minWidth": "200px",
|
||||||
|
"minHeight": "28px"
|
||||||
|
},
|
||||||
|
"label": "商品类目"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"componentName": "Input",
|
||||||
|
"id": "node_dockd5nrh9pr",
|
||||||
|
"props": {
|
||||||
|
"hasBorder": true,
|
||||||
|
"size": "medium",
|
||||||
|
"autoComplete": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"componentName": "ErrorComponent",
|
||||||
|
"id": "node_dockd5nrh9pr",
|
||||||
|
"props": {
|
||||||
|
"name": "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
31
packages/react-renderer/tests/index.test.tsx
Normal file
31
packages/react-renderer/tests/index.test.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
import { Box, Breadcrumb, Form, Select, Input, Button, Table, Pagination, Dialog } from '@alifd/next';
|
||||||
|
import ReactRenderer from '../src';
|
||||||
|
import schema from './fixtures/schema/basic';
|
||||||
|
|
||||||
|
describe('React Renderer', () => {
|
||||||
|
it('render basic case', () => {
|
||||||
|
const components = {
|
||||||
|
Box,
|
||||||
|
Breadcrumb,
|
||||||
|
'Breadcrumb.Item': Breadcrumb.Item,
|
||||||
|
Form,
|
||||||
|
'Form.Item': Form.Item,
|
||||||
|
Select,
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
'Button.Group': Button.Group,
|
||||||
|
Table,
|
||||||
|
Pagination,
|
||||||
|
Dialog,
|
||||||
|
};
|
||||||
|
const content = (
|
||||||
|
<ReactRenderer
|
||||||
|
schema={schema}
|
||||||
|
components={components}
|
||||||
|
/>);
|
||||||
|
const tree = renderer.create(content).toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -3,22 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
<a name="1.0.33"></a>
|
|
||||||
## [1.0.33](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.33-beta.1...v1.0.33) (2021-01-29)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @ali/lowcode-react-simulator-renderer
|
|
||||||
|
|
||||||
<a name="1.0.33-beta.1"></a>
|
|
||||||
## [1.0.33-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.33-beta.0...v1.0.33-beta.1) (2021-01-28)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @ali/lowcode-react-simulator-renderer
|
|
||||||
|
|
||||||
<a name="1.0.33-beta.0"></a>
|
<a name="1.0.33-beta.0"></a>
|
||||||
## [1.0.33-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.32...v1.0.33-beta.0) (2021-01-28)
|
## [1.0.33-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.32...v1.0.33-beta.0) (2021-01-28)
|
||||||
|
|
||||||
|
|||||||
@ -16,10 +16,10 @@
|
|||||||
"build": "build-scripts build --skip-demo"
|
"build": "build-scripts build --skip-demo"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ali/lowcode-designer": "^1.0.33",
|
"@ali/lowcode-designer": "^1.0.33-beta.0",
|
||||||
"@ali/lowcode-react-renderer": "^1.0.33",
|
"@ali/lowcode-react-renderer": "^1.0.33-beta.0",
|
||||||
"@ali/lowcode-types": "^1.0.33",
|
"@ali/lowcode-types": "^1.0.33-beta.0",
|
||||||
"@ali/lowcode-utils": "^1.0.33",
|
"@ali/lowcode-utils": "^1.0.33-beta.0",
|
||||||
"@ali/vu-css-style": "^1.0.2",
|
"@ali/vu-css-style": "^1.0.2",
|
||||||
"@recore/obx": "^1.0.8",
|
"@recore/obx": "^1.0.8",
|
||||||
"@recore/obx-react": "^1.0.7",
|
"@recore/obx-react": "^1.0.7",
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import { RootSchema, ComponentSchema, TransformStage, NodeSchema } from '@ali/lo
|
|||||||
// import { RootSchema, NpmInfo, ComponentSchema, TransformStage, NodeSchema } from '@ali/lowcode-types';
|
// import { RootSchema, NpmInfo, ComponentSchema, TransformStage, NodeSchema } from '@ali/lowcode-types';
|
||||||
// just use types
|
// just use types
|
||||||
import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel } from '@ali/lowcode-designer';
|
import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel } from '@ali/lowcode-designer';
|
||||||
|
import LowCodeRenderer from '@ali/lowcode-react-renderer';
|
||||||
import { createMemoryHistory, MemoryHistory } from 'history';
|
import { createMemoryHistory, MemoryHistory } from 'history';
|
||||||
import Slot from './builtin-components/slot';
|
import Slot from './builtin-components/slot';
|
||||||
import Leaf from './builtin-components/leaf';
|
import Leaf from './builtin-components/leaf';
|
||||||
@ -392,12 +393,37 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
|||||||
doc.getElementsByTagName('head')[0].appendChild(s);
|
doc.getElementsByTagName('head')[0].appendChild(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const node = host.currentDocument?.createNode(_schema);
|
|
||||||
// _schema = node?.export(TransformStage.Render) || {};
|
|
||||||
|
|
||||||
const renderer = this;
|
const renderer = this;
|
||||||
const { componentsMap } = renderer;
|
const { componentsMap: components } = renderer;
|
||||||
return getComponentController(schema, componentsMap);
|
|
||||||
|
class LowCodeComp extends React.Component {
|
||||||
|
render() {
|
||||||
|
// @ts-ignore
|
||||||
|
return createElement(LowCodeRenderer, {
|
||||||
|
schema: _schema,
|
||||||
|
components,
|
||||||
|
designMode: renderer.designMode,
|
||||||
|
device: renderer.device,
|
||||||
|
appHelper: renderer.context,
|
||||||
|
customCreateElement: (Comp: any, props: any, children: any) => {
|
||||||
|
const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName);
|
||||||
|
if (componentMeta?.isModal) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { __id, __designMode, ...viewProps } = props;
|
||||||
|
// mock _leaf,减少性能开销
|
||||||
|
const _leaf = {
|
||||||
|
isEmpty: () => false,
|
||||||
|
};
|
||||||
|
viewProps._leaf = _leaf;
|
||||||
|
return createElement(Comp, viewProps, children);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LowCodeComp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _running = false;
|
private _running = false;
|
||||||
@ -500,91 +526,4 @@ function checkInstanceMounted(instance: any): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const processPropsSchema = (propsSchema: any, propsMap: any, componentsMap: any): any => {
|
|
||||||
if (!propsSchema) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = { ...propsSchema };
|
|
||||||
const reg = /^(?:this\.props|props)\.(\S+)$/;
|
|
||||||
Object.keys(result).map((key: string) => {
|
|
||||||
if (result[key]?.type === 'JSExpression') {
|
|
||||||
const { value } = result[key];
|
|
||||||
const matched = reg.exec(value);
|
|
||||||
if (matched) {
|
|
||||||
const propName = matched[1];
|
|
||||||
result[key] = propsMap[propName];
|
|
||||||
}
|
|
||||||
} else if (result[key]?.type === 'JSSlot') {
|
|
||||||
const schema = result[key].value;
|
|
||||||
result[key] = createElement(ComponentCreator, { schema, propsMap: {}, componentsMap });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ComponentCreator extends React.Component<{ schema: any; propsMap: any, componentsMap: any }> {
|
|
||||||
private isModal: boolean;
|
|
||||||
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
const componentMeta = host.currentDocument?.getComponentMeta(props.schema.componentName);
|
|
||||||
if (componentMeta?.isModal) {
|
|
||||||
this.isModal = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.isModal) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const { schema, propsMap, componentsMap } = this.props;
|
|
||||||
const ComponentClass = componentsMap[schema.componentName];
|
|
||||||
if (!ComponentClass) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let children = null;
|
|
||||||
if (schema.children && schema.children.length > 0) {
|
|
||||||
children = schema.children.map((item: any) => createElement(ComponentCreator, { schema: item, propsMap, componentsMap }));
|
|
||||||
}
|
|
||||||
const props = processPropsSchema(schema.props, propsMap, componentsMap);
|
|
||||||
const _leaf = host.currentDocument?.createNode(schema);
|
|
||||||
return createElement(ComponentClass, { ...props, _leaf }, children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getComponentController(schema: NodeSchema, componentsMap: any) {
|
|
||||||
class ComponentController extends React.Component<{ schema: any }> {
|
|
||||||
renderSchema: any;
|
|
||||||
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
const node = host.currentDocument?.createNode(schema);
|
|
||||||
this.renderSchema = node?.export(TransformStage.Render) || {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 暂时解决性能问题
|
|
||||||
shouldComponentUpdate() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { renderSchema } = this;
|
|
||||||
const { componentName } = renderSchema;
|
|
||||||
if (componentName === 'Component') {
|
|
||||||
let children = [] as any;
|
|
||||||
const propsMap = this.props || {};
|
|
||||||
if (renderSchema.children && Array.isArray(renderSchema.children)) {
|
|
||||||
children = renderSchema.children.map((item: any) => createElement(ComponentCreator, { schema: item, propsMap, componentsMap }));
|
|
||||||
}
|
|
||||||
return createElement('div', {}, children);
|
|
||||||
} else {
|
|
||||||
return createElement(ComponentCreator, { schema, propsMap: {}, componentsMap });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ComponentController;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new SimulatorRendererContainer();
|
export default new SimulatorRendererContainer();
|
||||||
|
|||||||
14
packages/renderer-core/.eslintrc.js
Normal file
14
packages/renderer-core/.eslintrc.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: 'eslint-config-ali/typescript/react',
|
||||||
|
rules: {
|
||||||
|
'react/no-multi-comp': 1,
|
||||||
|
'no-unused-expressions': 1,
|
||||||
|
'implicit-arrow-linebreak': 1,
|
||||||
|
'no-nested-ternary': 1,
|
||||||
|
'no-mixed-operators': 1,
|
||||||
|
'@typescript-eslint/no-parameter-properties': 1,
|
||||||
|
'@typescript-eslint/ban-types': 1,
|
||||||
|
'no-shadow': 1,
|
||||||
|
'no-prototype-builtins': 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
648
packages/renderer-core/CHANGELOG.md
Normal file
648
packages/renderer-core/CHANGELOG.md
Normal file
@ -0,0 +1,648 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
<a name="1.0.27"></a>
|
||||||
|
## [1.0.27](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.2...v1.0.27) (2020-12-24)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.27-beta.2"></a>
|
||||||
|
## [1.0.27-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.1...v1.0.27-beta.2) (2020-12-23)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.27-beta.1"></a>
|
||||||
|
## [1.0.27-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.27-beta.0...v1.0.27-beta.1) (2020-12-23)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.27-beta.0"></a>
|
||||||
|
## [1.0.27-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26...v1.0.27-beta.0) (2020-12-23)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.26"></a>
|
||||||
|
## [1.0.26](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26-beta.1...v1.0.26) (2020-12-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.26-beta.1"></a>
|
||||||
|
## [1.0.26-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.26-beta.0...v1.0.26-beta.1) (2020-12-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.26-beta.0"></a>
|
||||||
|
## [1.0.26-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.25-beta.1...v1.0.26-beta.0) (2020-12-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.25-beta.1"></a>
|
||||||
|
## [1.0.25-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.4...v1.0.25-beta.1) (2020-12-15)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.24-beta.4"></a>
|
||||||
|
## [1.0.24-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.3...v1.0.24-beta.4) (2020-12-14)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.24-beta.3"></a>
|
||||||
|
## [1.0.24-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.2...v1.0.24-beta.3) (2020-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.24-beta.2"></a>
|
||||||
|
## [1.0.24-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.1...v1.0.24-beta.2) (2020-12-10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.24-beta.1"></a>
|
||||||
|
## [1.0.24-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.24-beta.0...v1.0.24-beta.1) (2020-12-09)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.24-beta.0"></a>
|
||||||
|
## [1.0.24-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23...v1.0.24-beta.0) (2020-12-09)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.23"></a>
|
||||||
|
## [1.0.23](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.2...v1.0.23) (2020-12-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.23-beta.5"></a>
|
||||||
|
## [1.0.23-beta.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.4...v1.0.23-beta.5) (2020-12-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.23-beta.4"></a>
|
||||||
|
## [1.0.23-beta.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.3...v1.0.23-beta.4) (2020-12-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.23-beta.3"></a>
|
||||||
|
## [1.0.23-beta.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.2...v1.0.23-beta.3) (2020-12-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.23-beta.2"></a>
|
||||||
|
## [1.0.23-beta.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v1.0.23-beta.1...v1.0.23-beta.2) (2020-12-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* editor-core 统一版本 ([edd4129](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/edd4129))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 增加 plugin-designer ([8bff207](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8bff207))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.23-beta.1"></a>
|
||||||
|
## [1.0.23-beta.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-29...v1.0.23-beta.1) (2020-12-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复setter设置defaultValue不生效的问题 ([0cf47da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0cf47da))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 合入 trunk-vision 代码 ([ea6bc7a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ea6bc7a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.23-beta.0"></a>
|
||||||
|
## [1.0.23-beta.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/v0.13.1-29...v1.0.23-beta.0) (2020-12-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复setter设置defaultValue不生效的问题 ([0cf47da](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0cf47da))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 合入 trunk-vision 代码 ([ea6bc7a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ea6bc7a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.22"></a>
|
||||||
|
## [1.0.22](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.21...@ali/lowcode-editor-core@1.0.22) (2020-11-16)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.21"></a>
|
||||||
|
## [1.0.21](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.20...@ali/lowcode-editor-core@1.0.21) (2020-11-10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.20"></a>
|
||||||
|
## [1.0.20](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.19...@ali/lowcode-editor-core@1.0.20) (2020-11-10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.19"></a>
|
||||||
|
## [1.0.19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.18...@ali/lowcode-editor-core@1.0.19) (2020-11-05)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.18"></a>
|
||||||
|
## [1.0.18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.17...@ali/lowcode-editor-core@1.0.18) (2020-11-05)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.17"></a>
|
||||||
|
## [1.0.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.16...@ali/lowcode-editor-core@1.0.17) (2020-11-05)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.16"></a>
|
||||||
|
## [1.0.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.15...@ali/lowcode-editor-core@1.0.16) (2020-11-04)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.15"></a>
|
||||||
|
## [1.0.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.13...@ali/lowcode-editor-core@1.0.15) (2020-11-04)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.14"></a>
|
||||||
|
## [1.0.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.13...@ali/lowcode-editor-core@1.0.14) (2020-11-04)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.13"></a>
|
||||||
|
## [1.0.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.12...@ali/lowcode-editor-core@1.0.13) (2020-11-02)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.12"></a>
|
||||||
|
## [1.0.12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.11...@ali/lowcode-editor-core@1.0.12) (2020-10-20)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.11"></a>
|
||||||
|
## [1.0.11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.10...@ali/lowcode-editor-core@1.0.11) (2020-10-19)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.10"></a>
|
||||||
|
## [1.0.10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.9...@ali/lowcode-editor-core@1.0.10) (2020-09-29)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.9"></a>
|
||||||
|
## [1.0.9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.8...@ali/lowcode-editor-core@1.0.9) (2020-09-28)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.8"></a>
|
||||||
|
## [1.0.8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.8-0...@ali/lowcode-editor-core@1.0.8) (2020-09-28)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.8-0"></a>
|
||||||
|
## [1.0.8-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.36...@ali/lowcode-editor-core@1.0.8-0) (2020-09-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 合并master分支 ([bd2c6ad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd2c6ad))
|
||||||
|
* 清理代码依赖及版本 ([0b15d30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0b15d30))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.7-0"></a>
|
||||||
|
## [1.0.7-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.6-0...@ali/lowcode-editor-core@1.0.7-0) (2020-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
<a name="1.0.6-0"></a>
|
||||||
|
## [1.0.6-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.34...@ali/lowcode-editor-core@1.0.6-0) (2020-09-02)
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.36"></a>
|
||||||
|
## [0.8.36](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.35...@ali/lowcode-editor-core@0.8.36) (2020-09-03)
|
||||||
|
|
||||||
|
<a name="0.8.35"></a>
|
||||||
|
## [0.8.35](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.34...@ali/lowcode-editor-core@0.8.35) (2020-09-03)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 合并master分支 ([bd2c6ad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd2c6ad))
|
||||||
|
* 清理代码依赖及版本 ([0b15d30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0b15d30))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.5-0"></a>
|
||||||
|
## [1.0.5-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.4-0...@ali/lowcode-editor-core@1.0.5-0) (2020-08-20)
|
||||||
|
|
||||||
|
<a name="0.8.34"></a>
|
||||||
|
## [0.8.34](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.33...@ali/lowcode-editor-core@0.8.34) (2020-08-27)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.33"></a>
|
||||||
|
## [0.8.33](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.32...@ali/lowcode-editor-core@0.8.33) (2020-08-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 编辑器 hooks 能力实现 ([f3ac23b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f3ac23b))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.32"></a>
|
||||||
|
## [0.8.32](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.30...@ali/lowcode-editor-core@0.8.32) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.4-0"></a>
|
||||||
|
## [1.0.4-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.3-0...@ali/lowcode-editor-core@1.0.4-0) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.3-0"></a>
|
||||||
|
## [1.0.3-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.2-0...@ali/lowcode-editor-core@1.0.3-0) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.2-0"></a>
|
||||||
|
## [1.0.2-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@1.0.1-0...@ali/lowcode-editor-core@1.0.2-0) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.1-0"></a>
|
||||||
|
## [1.0.1-0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.30...@ali/lowcode-editor-core@1.0.1-0) (2020-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="1.0.0"></a>
|
||||||
|
# [1.0.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.13.0...@ali/lowcode-editor-core@1.0.0) (2020-08-17)
|
||||||
|
<a name="0.8.30"></a>
|
||||||
|
## [0.8.30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.29...@ali/lowcode-editor-core@0.8.30) (2020-08-19)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.13.0"></a>
|
||||||
|
# [0.13.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.12.0...@ali/lowcode-editor-core@0.13.0) (2020-08-17)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.12.0"></a>
|
||||||
|
# [0.12.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.10.0...@ali/lowcode-editor-core@0.12.0) (2020-08-17)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.11.0"></a>
|
||||||
|
# [0.11.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.10.0...@ali/lowcode-editor-core@0.11.0) (2020-08-17)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.10.0"></a>
|
||||||
|
# [0.10.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.9.0...@ali/lowcode-editor-core@0.10.0) (2020-08-16)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.9.0"></a>
|
||||||
|
# [0.9.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.28...@ali/lowcode-editor-core@0.9.0) (2020-08-14)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.28"></a>
|
||||||
|
## [0.8.28](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.27...@ali/lowcode-editor-core@0.8.28) (2020-08-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 增加try catch ([6f5d11c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6f5d11c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.27"></a>
|
||||||
|
## [0.8.27](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.25...@ali/lowcode-editor-core@0.8.27) (2020-08-04)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.26"></a>
|
||||||
|
## [0.8.26](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.25...@ali/lowcode-editor-core@0.8.26) (2020-08-04)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.25"></a>
|
||||||
|
## [0.8.25](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.24...@ali/lowcode-editor-core@0.8.25) (2020-07-28)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.24"></a>
|
||||||
|
## [0.8.24](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.23...@ali/lowcode-editor-core@0.8.24) (2020-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.23"></a>
|
||||||
|
## [0.8.23](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.22...@ali/lowcode-editor-core@0.8.23) (2020-07-21)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.22"></a>
|
||||||
|
## [0.8.22](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.21...@ali/lowcode-editor-core@0.8.22) (2020-07-21)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.21"></a>
|
||||||
|
## [0.8.21](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.20...@ali/lowcode-editor-core@0.8.21) (2020-07-13)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.20"></a>
|
||||||
|
## [0.8.20](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.19...@ali/lowcode-editor-core@0.8.20) (2020-07-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 修复删除时,当前组件信息丢失问题 ([3bd1248](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3bd1248))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.19"></a>
|
||||||
|
## [0.8.19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.17...@ali/lowcode-editor-core@0.8.19) (2020-06-23)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.17"></a>
|
||||||
|
## [0.8.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.16...@ali/lowcode-editor-core@0.8.17) (2020-06-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* export Monitor ([51025f0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/51025f0))
|
||||||
|
* 引擎层埋点 ([69de533](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/69de533))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.16"></a>
|
||||||
|
## [0.8.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.15...@ali/lowcode-editor-core@0.8.16) (2020-06-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add Monitor ([f915d19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f915d19))
|
||||||
|
* add URL link for setter titles ([4678408](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4678408))
|
||||||
|
* ve事件埋点 ([700e5b0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/700e5b0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.15"></a>
|
||||||
|
## [0.8.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.14...@ali/lowcode-editor-core@0.8.15) (2020-05-20)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.14"></a>
|
||||||
|
## [0.8.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.13...@ali/lowcode-editor-core@0.8.14) (2020-05-18)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.13"></a>
|
||||||
|
## [0.8.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.12...@ali/lowcode-editor-core@0.8.13) (2020-05-15)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.12"></a>
|
||||||
|
## [0.8.12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.11...@ali/lowcode-editor-core@0.8.12) (2020-05-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* supports ([371b84c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/371b84c))
|
||||||
|
* tip direction ([f51d496](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f51d496))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.11"></a>
|
||||||
|
## [0.8.11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.10...@ali/lowcode-editor-core@0.8.11) (2020-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.10"></a>
|
||||||
|
## [0.8.10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.9...@ali/lowcode-editor-core@0.8.10) (2020-05-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* intl ([8a061ab](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8a061ab))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.9"></a>
|
||||||
|
## [0.8.9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.8...@ali/lowcode-editor-core@0.8.9) (2020-04-27)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.8"></a>
|
||||||
|
## [0.8.8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.7...@ali/lowcode-editor-core@0.8.8) (2020-04-27)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
|
|
||||||
|
<a name="0.8.7"></a>
|
||||||
|
## [0.8.7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-editor-core@0.8.6...@ali/lowcode-editor-core@0.8.7) (2020-04-27)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-editor-core
|
||||||
3
packages/renderer-core/README.md
Normal file
3
packages/renderer-core/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
shared globals
|
||||||
|
|
||||||
|
发 CDN
|
||||||
7
packages/renderer-core/build.json
Normal file
7
packages/renderer-core/build.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"build-plugin-component"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
48
packages/renderer-core/package.json
Normal file
48
packages/renderer-core/package.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/lowcode-renderer-core",
|
||||||
|
"version": "1.0.33",
|
||||||
|
"description": "renderer core",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "es/index.js",
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"es"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "build-scripts build --skip-demo",
|
||||||
|
"cloud-build": "build-scripts build --skip-demo"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/b3-one": "^0.0.17",
|
||||||
|
"@ali/bzb-request": "^2.6.0-beta.13",
|
||||||
|
"@ali/lib-mtop": "^2.5.1",
|
||||||
|
"@ali/lowcode-datasource-engine": "^1.0.22",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"events": "^3.0.0",
|
||||||
|
"fetch-jsonp": "^1.1.3",
|
||||||
|
"intl-messageformat": "^9.3.1",
|
||||||
|
"jsonuri": "^2.1.2",
|
||||||
|
"lodash": "^4.17.11",
|
||||||
|
"moment": "^2.24.0",
|
||||||
|
"react-is": "^16.10.1",
|
||||||
|
"serialize-javascript": "^1.7.0",
|
||||||
|
"socket.io-client": "^2.2.0",
|
||||||
|
"whatwg-fetch": "^3.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@alib/build-scripts": "^0.1.18",
|
||||||
|
"@types/classnames": "^2.2.11",
|
||||||
|
"@types/debug": "^4.1.5",
|
||||||
|
"@types/lodash": "^4.14.167",
|
||||||
|
"@types/node": "^13.7.1",
|
||||||
|
"@types/prop-types": "^15.7.3",
|
||||||
|
"@types/serialize-javascript": "^5.0.0",
|
||||||
|
"build-plugin-component": "^0.2.11"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
89
packages/renderer-core/src/adapter/index.ts
Normal file
89
packages/renderer-core/src/adapter/index.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { IRuntime, IRendererModules } from '../types';
|
||||||
|
|
||||||
|
export enum Env {
|
||||||
|
React = 'react',
|
||||||
|
Rax = 'rax',
|
||||||
|
}
|
||||||
|
|
||||||
|
class Adapter {
|
||||||
|
runtime: IRuntime;
|
||||||
|
builtinModules = ['Component', 'PureComponent', 'createElement', 'createContext', 'forwardRef', 'findDOMNode'];
|
||||||
|
env: Env;
|
||||||
|
renderers: IRendererModules;
|
||||||
|
configProvider: any;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.initRuntime();
|
||||||
|
}
|
||||||
|
|
||||||
|
initRuntime() {
|
||||||
|
const Component = class {};
|
||||||
|
const PureComponent = class {};
|
||||||
|
const createElement = () => {};
|
||||||
|
const createContext = () => {};
|
||||||
|
const forwardRef = () => {};
|
||||||
|
const findDOMNode = () => {};
|
||||||
|
this.runtime = {
|
||||||
|
Component,
|
||||||
|
PureComponent,
|
||||||
|
createElement,
|
||||||
|
createContext,
|
||||||
|
forwardRef,
|
||||||
|
findDOMNode,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setRuntime(runtime: IRuntime) {
|
||||||
|
if (this.isValidRuntime(runtime)) {
|
||||||
|
this.runtime = runtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidRuntime(runtime: IRuntime) {
|
||||||
|
if (typeof runtime !== 'object' || Array.isArray(runtime)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.builtinModules.every(m => {
|
||||||
|
const flag = !!this.runtime[m];
|
||||||
|
if (!flag) {
|
||||||
|
throw new Error(`runtime is inValid, module '${m}' is not existed`);
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getRuntime() {
|
||||||
|
return this.runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEnv(env: Env) {
|
||||||
|
this.env = env;
|
||||||
|
}
|
||||||
|
|
||||||
|
isReact() {
|
||||||
|
return this.env === Env.React;
|
||||||
|
}
|
||||||
|
|
||||||
|
isRax() {
|
||||||
|
return this.env === Env.Rax;
|
||||||
|
}
|
||||||
|
|
||||||
|
setRenderers(renderers: IRendererModules) {
|
||||||
|
this.renderers = renderers;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRenderers() {
|
||||||
|
return this.renderers || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfigProvider(Comp: any) {
|
||||||
|
this.configProvider = Comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfigProvider() {
|
||||||
|
return this.configProvider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Adapter();
|
||||||
14
packages/renderer-core/src/components/Div.tsx
Normal file
14
packages/renderer-core/src/components/Div.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import adapter from '../adapter';
|
||||||
|
|
||||||
|
export default function divFactory() {
|
||||||
|
const { PureComponent, createElement } = adapter.getRuntime();
|
||||||
|
return class Div extends PureComponent {
|
||||||
|
static displayName = 'Div';
|
||||||
|
|
||||||
|
static version = '0.0.0';
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return createElement('div', this.props);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
34
packages/renderer-core/src/components/VisualDom/index.tsx
Normal file
34
packages/renderer-core/src/components/VisualDom/index.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import adapter from '../../adapter';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
export default function visualDomFactory() {
|
||||||
|
const { PureComponent, createElement } = adapter.getRuntime();
|
||||||
|
return class VisualDom extends PureComponent {
|
||||||
|
static displayName = 'VisualDom';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
children: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, cell, title, label, text, __componentName } = this.props;
|
||||||
|
let mainContent = children;
|
||||||
|
if (cell && typeof cell === 'function') {
|
||||||
|
mainContent = cell();
|
||||||
|
}
|
||||||
|
return createElement('div', { className: 'visual-dom' },
|
||||||
|
createElement('div', { className: 'panel-container' },
|
||||||
|
[
|
||||||
|
createElement('span', { className: 'title' }, title || label || text || __componentName),
|
||||||
|
createElement('div', { className: 'content' }, mainContent),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
13
packages/renderer-core/src/context/index.ts
Normal file
13
packages/renderer-core/src/context/index.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import adapter from '../adapter';
|
||||||
|
|
||||||
|
|
||||||
|
export default function contextFactory() {
|
||||||
|
const { createContext } = adapter.getRuntime();
|
||||||
|
|
||||||
|
let context = (window as any).__appContext;
|
||||||
|
if (!context) {
|
||||||
|
context = createContext({});
|
||||||
|
(window as any).__appContext = context;
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
22
packages/renderer-core/src/hoc/index.tsx
Normal file
22
packages/renderer-core/src/hoc/index.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import adapter from '../adapter';
|
||||||
|
|
||||||
|
export function compWrapper(Comp: any) {
|
||||||
|
const { createElement, Component, forwardRef } = adapter.getRuntime();
|
||||||
|
class Wrapper extends Component {
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { forwardRef } = this.props;
|
||||||
|
return createElement(Comp, {
|
||||||
|
...this.props,
|
||||||
|
ref: forwardRef,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return forwardRef((props: any, ref: any) => {
|
||||||
|
return createElement(Wrapper, { ...props, forwardRef: ref });
|
||||||
|
});
|
||||||
|
}
|
||||||
8
packages/renderer-core/src/index.ts
Normal file
8
packages/renderer-core/src/index.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import adapter from './adapter';
|
||||||
|
|
||||||
|
export { adapter };
|
||||||
|
|
||||||
|
export * from './renderer';
|
||||||
|
export * as types from './types';
|
||||||
|
export * as utils from './utils';
|
||||||
|
export * from './hoc';
|
||||||
3
packages/renderer-core/src/module.d.ts
vendored
Normal file
3
packages/renderer-core/src/module.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
declare module '@ali/b3-one/lib/obj';
|
||||||
|
declare module '@ali/b3-one/lib/url';
|
||||||
|
declare module '@ali/lib-mtop';
|
||||||
88
packages/renderer-core/src/renderer/addon.tsx
Normal file
88
packages/renderer-core/src/renderer/addon.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import baseRendererFactory from './base';
|
||||||
|
import { isEmpty, goldlog } from '../utils';
|
||||||
|
import { IRendererProps } from '../types';
|
||||||
|
|
||||||
|
export default function addonRendererFactory() {
|
||||||
|
const BaseRenderer = baseRendererFactory();
|
||||||
|
return class AddonRenderer extends BaseRenderer {
|
||||||
|
static dislayName = 'addon-renderer';
|
||||||
|
__namespace = 'addon';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
config: PropTypes.object,
|
||||||
|
__schema: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
config: {},
|
||||||
|
__schema: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
__afterInit(props: IRendererProps) {
|
||||||
|
this.__generateCtx({
|
||||||
|
component: this,
|
||||||
|
});
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
this.state = this.__parseData(schema.state || {});
|
||||||
|
if (isEmpty(props.config) || !props.config.addonKey) {
|
||||||
|
console.warn('luna addon has wrong config');
|
||||||
|
this.state.__hasError = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 注册插件
|
||||||
|
this.addonKey = props.config.addonKey;
|
||||||
|
this.appHelper.addons = this.appHelper.addons || {};
|
||||||
|
this.appHelper.addons[this.addonKey] = this;
|
||||||
|
this.__initDataSource(props);
|
||||||
|
this.open = this.open || (() => { });
|
||||||
|
this.close = this.close || (() => { });
|
||||||
|
this.__setLifeCycleMethods('constructor', arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentWillUnmount() {
|
||||||
|
super.componentWillUnmount(...arguments);
|
||||||
|
// 注销插件
|
||||||
|
const config = this.props.config || {};
|
||||||
|
if (config && this.appHelper.addons) {
|
||||||
|
delete this.appHelper.addons[config.addonKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goldlog = (goKey: string, params: any) => {
|
||||||
|
const { addonKey, addonConfig = {} } = this.props.config || {};
|
||||||
|
goldlog(
|
||||||
|
goKey,
|
||||||
|
{
|
||||||
|
addonKey,
|
||||||
|
package: addonConfig.package,
|
||||||
|
version: addonConfig.version,
|
||||||
|
...this.appHelper.logParams,
|
||||||
|
...params,
|
||||||
|
},
|
||||||
|
'addon',
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
get utils() {
|
||||||
|
const { utils = {} } = this.context.config || {};
|
||||||
|
return { ...this.appHelper.utils, ...utils };
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema } = this.props;
|
||||||
|
|
||||||
|
if (this.__checkSchema(__schema)) {
|
||||||
|
return '插件 schema 结构异常!';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__debug(`render - ${__schema.fileName}`);
|
||||||
|
this.__generateCtx({
|
||||||
|
component: this,
|
||||||
|
});
|
||||||
|
this.__render();
|
||||||
|
|
||||||
|
return this.__renderContent(this.__renderContextProvider({ compContext: this }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
761
packages/renderer-core/src/renderer/base.tsx
Normal file
761
packages/renderer-core/src/renderer/base.tsx
Normal file
@ -0,0 +1,761 @@
|
|||||||
|
import classnames from 'classnames';
|
||||||
|
import Debug from 'debug';
|
||||||
|
import { create as createDataSourceEngine } from '@ali/lowcode-datasource-engine/interpret';
|
||||||
|
import adapter from '../adapter';
|
||||||
|
import divFactory from '../components/Div';
|
||||||
|
import visualDomFactory from '../components/VisualDom';
|
||||||
|
import contextFactory from '../context';
|
||||||
|
import {
|
||||||
|
forEach,
|
||||||
|
getValue,
|
||||||
|
parseData,
|
||||||
|
parseExpression,
|
||||||
|
isEmpty,
|
||||||
|
isSchema,
|
||||||
|
isFileSchema,
|
||||||
|
isJSExpression,
|
||||||
|
isJSSlot,
|
||||||
|
isJSFunction,
|
||||||
|
transformArrayToMap,
|
||||||
|
transformStringToFunction,
|
||||||
|
checkPropTypes,
|
||||||
|
generateI18n,
|
||||||
|
acceptsRef,
|
||||||
|
getFileCssName,
|
||||||
|
capitalizeFirstLetter,
|
||||||
|
DataHelper,
|
||||||
|
isI18n,
|
||||||
|
isVariable
|
||||||
|
} from '../utils';
|
||||||
|
import { IRendererProps, ISchema, IInfo, ComponentModel, IRenderer } from '../types';
|
||||||
|
import { compWrapper } from '../hoc';
|
||||||
|
|
||||||
|
export default function baseRenererFactory() {
|
||||||
|
const { BaseRenderer: customBaseRenderer } = adapter.getRenderers();
|
||||||
|
|
||||||
|
if (customBaseRenderer) {
|
||||||
|
return customBaseRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { Component, createElement } = adapter.getRuntime();
|
||||||
|
const Div = divFactory();
|
||||||
|
const VisualDom = visualDomFactory();
|
||||||
|
const AppContext = contextFactory();
|
||||||
|
|
||||||
|
const debug = Debug('renderer:base');
|
||||||
|
const DESIGN_MODE = {
|
||||||
|
EXTEND: 'extend',
|
||||||
|
BORDER: 'border',
|
||||||
|
PREVIEW: 'preview',
|
||||||
|
};
|
||||||
|
const OVERLAY_LIST = ['Dialog', 'Overlay', 'Animate', 'ConfigProvider'];
|
||||||
|
let scopeIdx = 0;
|
||||||
|
|
||||||
|
return class BaseRenderer extends Component implements IRenderer {
|
||||||
|
static dislayName = 'base-renderer';
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
__schema: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
static contextType = AppContext;
|
||||||
|
|
||||||
|
__namespace = 'base';
|
||||||
|
|
||||||
|
constructor(props: IRendererProps, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
this.__beforeInit(props);
|
||||||
|
this.__init(props);
|
||||||
|
this.__afterInit(props);
|
||||||
|
this.__initDebug();
|
||||||
|
this.__debug(`constructor - ${props?.__schema?.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
__beforeInit(props: IRendererProps) { }
|
||||||
|
|
||||||
|
__init(props: IRendererProps) {
|
||||||
|
this.appHelper = props.__appHelper;
|
||||||
|
this.__compScopes = {};
|
||||||
|
this.__instanceMap = {};
|
||||||
|
const { locale, messages } = props;
|
||||||
|
this.i18n = generateI18n(locale, messages);
|
||||||
|
this.__bindCustomMethods(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
__afterInit(props: IRendererProps) { }
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props: IRendererProps, state: any) {
|
||||||
|
debug('getDerivedStateFromProps');
|
||||||
|
const func = props?.__schema?.lifeCycles?.getDerivedStateFromProps;
|
||||||
|
|
||||||
|
if (func) {
|
||||||
|
return func(props, state);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSnapshotBeforeUpdate() {
|
||||||
|
this.__setLifeCycleMethods('getSnapshotBeforeUpdate', arguments);
|
||||||
|
this.__debug(`getSnapshotBeforeUpdate - ${this.props?.__schema?.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
this.reloadDataSource();
|
||||||
|
this.__setLifeCycleMethods('componentDidMount', arguments);
|
||||||
|
this.__debug(`componentDidMount - ${this.props?.__schema?.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidUpdate(...args: any) {
|
||||||
|
this.__setLifeCycleMethods('componentDidUpdate', args);
|
||||||
|
this.__debug(`componentDidUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentWillUnmount(...args: any) {
|
||||||
|
this.__setLifeCycleMethods('componentWillUnmount', args);
|
||||||
|
this.__debug(`componentWillUnmount - ${this.props?.__schema?.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidCatch(e: any) {
|
||||||
|
this.__setLifeCycleMethods('componentDidCatch', arguments);
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadDataSource = () => new Promise((resolve, reject) => {
|
||||||
|
this.__debug('reload data source');
|
||||||
|
if (!this.__dataHelper) {
|
||||||
|
this.__showPlaceholder = false;
|
||||||
|
return resolve({});
|
||||||
|
}
|
||||||
|
this.__dataHelper
|
||||||
|
.getInitData()
|
||||||
|
.then((res: any) => {
|
||||||
|
this.__showPlaceholder = false;
|
||||||
|
if (isEmpty(res)) {
|
||||||
|
this.forceUpdate();
|
||||||
|
return resolve({});
|
||||||
|
}
|
||||||
|
this.setState(res, resolve);
|
||||||
|
})
|
||||||
|
.catch((err: Error) => {
|
||||||
|
if (this.__showPlaceholder) {
|
||||||
|
this.__showPlaceholder = false;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
__setLifeCycleMethods = (method: string, args?: any) => {
|
||||||
|
const lifeCycleMethods = getValue(this.props.__schema, 'lifeCycles', {});
|
||||||
|
let fn = lifeCycleMethods[method];
|
||||||
|
if (fn) {
|
||||||
|
// TODO, cache
|
||||||
|
if (isJSExpression(fn) || isJSFunction(fn)) {
|
||||||
|
fn = parseExpression(fn, this);
|
||||||
|
}
|
||||||
|
if (typeof fn !== 'function') {
|
||||||
|
console.error(`生命周期${method}类型不符`, fn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return fn.apply(this, args);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`[${this.props.__schema.componentName}]生命周期${method}出错`, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
__bindCustomMethods = (props = this.props) => {
|
||||||
|
const { __schema } = props;
|
||||||
|
const customMethodsList = Object.keys(__schema.methods || {}) || [];
|
||||||
|
this.__customMethodsList
|
||||||
|
&& this.__customMethodsList.forEach((item: any) => {
|
||||||
|
if (!customMethodsList.includes(item)) {
|
||||||
|
delete this[item];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.__customMethodsList = customMethodsList;
|
||||||
|
forEach(__schema.methods, (val: any, key: string) => {
|
||||||
|
if (isJSExpression(val) || isJSFunction(val)) {
|
||||||
|
val = parseExpression(val, this);
|
||||||
|
}
|
||||||
|
if (typeof val !== 'function') {
|
||||||
|
console.error(`自定义函数${key}类型不符`, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this[key] = val.bind(this);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
__generateCtx = (ctx: object) => {
|
||||||
|
const { pageContext, compContext } = this.context;
|
||||||
|
const obj = {
|
||||||
|
page: pageContext,
|
||||||
|
component: compContext,
|
||||||
|
...ctx,
|
||||||
|
};
|
||||||
|
forEach(obj, (val: any, key: string) => {
|
||||||
|
this[key] = val;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
__parseData = (data: any, ctx?: object) => {
|
||||||
|
const { __ctx } = this.props;
|
||||||
|
return parseData(data, ctx || __ctx || this);
|
||||||
|
};
|
||||||
|
|
||||||
|
__initDataSource = (props = this.props) => {
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
const dataSource = (schema && schema.dataSource) || {};
|
||||||
|
// requestHandlersMap 存在才走数据源引擎方案
|
||||||
|
if (props?.__appHelper?.requestHandlersMap) {
|
||||||
|
const { dataSourceMap, reloadDataSource } = createDataSourceEngine(dataSource, (this as any), {
|
||||||
|
requestHandlersMap: props.__appHelper.requestHandlersMap,
|
||||||
|
});
|
||||||
|
this.dataSourceMap = dataSourceMap;
|
||||||
|
this.reloadDataSource = () => new Promise((resolve) => {
|
||||||
|
this.__debug('reload data source');
|
||||||
|
// this.__showPlaceholder = true;
|
||||||
|
reloadDataSource().then(() => {
|
||||||
|
// this.__showPlaceholder = false;
|
||||||
|
// @TODO 是否需要 forceUpate
|
||||||
|
// this.forceUpdate();
|
||||||
|
resolve({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const appHelper = props.__appHelper;
|
||||||
|
this.__dataHelper = new DataHelper(this, dataSource, appHelper, (config: any) => this.__parseData(config));
|
||||||
|
this.dataSourceMap = this.__dataHelper.dataSourceMap;
|
||||||
|
this.reloadDataSource = () => new Promise((resolve, reject) => {
|
||||||
|
this.__debug('reload data source');
|
||||||
|
if (!this.__dataHelper) {
|
||||||
|
// this.__showPlaceholder = false;
|
||||||
|
return resolve({});
|
||||||
|
}
|
||||||
|
this.__dataHelper
|
||||||
|
.getInitData()
|
||||||
|
.then((res: any) => {
|
||||||
|
// this.__showPlaceholder = false;
|
||||||
|
if (isEmpty(res)) {
|
||||||
|
this.forceUpdate();
|
||||||
|
return resolve({});
|
||||||
|
}
|
||||||
|
this.setState(res, resolve);
|
||||||
|
})
|
||||||
|
.catch((err: Error) => {
|
||||||
|
if (this.__showPlaceholder) {
|
||||||
|
this.__showPlaceholder = false;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 设置容器组件占位,若设置占位则在初始异步请求完成之前用loading占位且不渲染容器组件内部内容
|
||||||
|
// @TODO __showPlaceholder 的逻辑一旦开启就关不掉,先注释掉了
|
||||||
|
/* this.__showPlaceholder = this.__parseData(schema.props && schema.props.autoLoading) && (dataSource.list || []).some(
|
||||||
|
(item) => !!this.__parseData(item.isInit),
|
||||||
|
); */
|
||||||
|
};
|
||||||
|
|
||||||
|
__render = () => {
|
||||||
|
const schema = this.props.__schema;
|
||||||
|
this.__setLifeCycleMethods('render');
|
||||||
|
|
||||||
|
const { engine } = this.context;
|
||||||
|
if (engine) {
|
||||||
|
engine.props.onCompGetCtx(schema, this);
|
||||||
|
// 画布场景才需要每次渲染bind自定义方法
|
||||||
|
if (engine.props.designMode) {
|
||||||
|
this.__bindCustomMethods();
|
||||||
|
this.dataSourceMap = this.__dataHelper && this.__dataHelper.updateConfig(schema.dataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
__getRef = (ref: any) => {
|
||||||
|
const { engine } = this.context;
|
||||||
|
const { __schema } = this.props;
|
||||||
|
ref && engine?.props?.onCompGetRef(__schema, ref);
|
||||||
|
this.__ref = ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
getSchemaChildren = (schema: ISchema) => {
|
||||||
|
if (!schema || !schema.props) {
|
||||||
|
return schema?.children;
|
||||||
|
}
|
||||||
|
if (!schema.children) return schema.props.children;
|
||||||
|
if (!schema.props.children) return schema.children;
|
||||||
|
let _children = ([] as ComponentModel[]).concat(schema.children);
|
||||||
|
if (Array.isArray(schema.props.children)) {
|
||||||
|
_children = _children.concat(schema.props.children);
|
||||||
|
} else {
|
||||||
|
_children.push(schema.props.children);
|
||||||
|
}
|
||||||
|
return _children;
|
||||||
|
};
|
||||||
|
|
||||||
|
__createDom = () => {
|
||||||
|
const { __schema, __ctx, __components = {} } = this.props;
|
||||||
|
const self: any = {};
|
||||||
|
self.__proto__ = __ctx || this;
|
||||||
|
const _children = this.getSchemaChildren(__schema);
|
||||||
|
return this.__createVirtualDom(_children, self, ({
|
||||||
|
schema: __schema,
|
||||||
|
Comp: __components[__schema.componentName],
|
||||||
|
} as IInfo));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 将模型结构转换成react Element
|
||||||
|
// schema 模型结构
|
||||||
|
// self 为每个渲染组件构造的上下文,self是自上而下继承的
|
||||||
|
// parentInfo 父组件的信息,包含schema和Comp
|
||||||
|
// idx 若为循环渲染的循环Index
|
||||||
|
__createVirtualDom = (schema: any, self: any, parentInfo: IInfo, idx: string | number = ''): any => {
|
||||||
|
const { engine } = this.context || {};
|
||||||
|
try {
|
||||||
|
if (!schema) return null;
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
if (schema.componentName === 'Text' && typeof schema.props.text === 'string') {
|
||||||
|
schema = { ...schema };
|
||||||
|
schema.children = [schema.props.text];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { __appHelper: appHelper, __components: components = {} } = this.props || {};
|
||||||
|
|
||||||
|
if (isJSExpression(schema)) {
|
||||||
|
return parseExpression(schema, self);
|
||||||
|
}
|
||||||
|
if (isJSSlot(schema)) {
|
||||||
|
return this.__createVirtualDom(schema.value, self, parentInfo);
|
||||||
|
}
|
||||||
|
if (typeof schema === 'string') return schema;
|
||||||
|
if (typeof schema === 'number' || typeof schema === 'boolean') {
|
||||||
|
return schema.toString();
|
||||||
|
}
|
||||||
|
if (Array.isArray(schema)) {
|
||||||
|
if (schema.length === 1) return this.__createVirtualDom(schema[0], self, parentInfo);
|
||||||
|
return schema.map((item, idy) => this.__createVirtualDom(item, self, parentInfo, item?.__ctx?.lceKey ? '' : idy));
|
||||||
|
}
|
||||||
|
// FIXME
|
||||||
|
const _children = this.getSchemaChildren(schema);
|
||||||
|
// 解析占位组件
|
||||||
|
if (schema.componentName === 'Flagment' && _children) {
|
||||||
|
const tarChildren = isJSExpression(_children) ? parseExpression(_children, self) : _children;
|
||||||
|
return this.__createVirtualDom(tarChildren, self, parentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (schema.$$typeof) {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
if (!isSchema(schema)) return null;
|
||||||
|
let Comp = components[schema.componentName] || engine.getNotFoundComponent();
|
||||||
|
|
||||||
|
if (schema.hidden) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (schema.loop != null) {
|
||||||
|
const loop = parseData(schema.loop, self);
|
||||||
|
if ((Array.isArray(loop) && loop.length > 0) || isJSExpression(loop)) {
|
||||||
|
return this.__createLoopVirtualDom(
|
||||||
|
{
|
||||||
|
...schema,
|
||||||
|
loop,
|
||||||
|
},
|
||||||
|
self,
|
||||||
|
parentInfo,
|
||||||
|
idx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const condition = schema.condition == null ? true : parseData(schema.condition, self);
|
||||||
|
if (!condition) return null;
|
||||||
|
|
||||||
|
let scopeKey = '';
|
||||||
|
// 判断组件是否需要生成scope,且只生成一次,挂在this.__compScopes上
|
||||||
|
if (Comp.generateScope) {
|
||||||
|
const key = parseExpression(schema.props.key, self);
|
||||||
|
if (key) {
|
||||||
|
// 如果组件自己设置key则使用组件自己的key
|
||||||
|
scopeKey = key;
|
||||||
|
} else if (!schema.__ctx) {
|
||||||
|
// 在生产环境schema没有__ctx上下文,需要手动生成一个lceKey
|
||||||
|
schema.__ctx = {
|
||||||
|
lceKey: `lce${++scopeIdx}`,
|
||||||
|
};
|
||||||
|
scopeKey = schema.__ctx.lceKey;
|
||||||
|
} else {
|
||||||
|
// 需要判断循环的情况
|
||||||
|
scopeKey = schema.__ctx.lceKey + (idx !== undefined ? `_${idx}` : '');
|
||||||
|
}
|
||||||
|
if (!this.__compScopes[scopeKey]) {
|
||||||
|
this.__compScopes[scopeKey] = Comp.generateScope(this, schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果组件有设置scope,需要为组件生成一个新的scope上下文
|
||||||
|
if (scopeKey && this.__compScopes[scopeKey]) {
|
||||||
|
const compSelf = { ...this.__compScopes[scopeKey] };
|
||||||
|
compSelf.__proto__ = self;
|
||||||
|
self = compSelf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 容器类组件的上下文通过props传递,避免context传递带来的嵌套问题
|
||||||
|
const otherProps: any = isFileSchema(schema)
|
||||||
|
? {
|
||||||
|
__schema: schema,
|
||||||
|
__appHelper: appHelper,
|
||||||
|
__components: components,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
if (engine?.props?.designMode) {
|
||||||
|
otherProps.__designMode = engine.props.designMode;
|
||||||
|
}
|
||||||
|
const componentInfo: any = {};
|
||||||
|
const props: any =
|
||||||
|
this.__parseProps(schema.props, self, '', {
|
||||||
|
schema,
|
||||||
|
Comp,
|
||||||
|
componentInfo: {
|
||||||
|
...componentInfo,
|
||||||
|
props: transformArrayToMap(componentInfo.props, 'name'),
|
||||||
|
},
|
||||||
|
}) || {};
|
||||||
|
|
||||||
|
// 对于可以获取到ref的组件做特殊处理
|
||||||
|
if (!acceptsRef(Comp)) {
|
||||||
|
Comp = compWrapper(Comp);
|
||||||
|
}
|
||||||
|
otherProps.ref = (ref: any) => {
|
||||||
|
this.$(props.fieldId, ref); // 收集ref
|
||||||
|
const refProps = props.ref;
|
||||||
|
if (refProps && typeof refProps === 'string') {
|
||||||
|
this[refProps] = ref;
|
||||||
|
}
|
||||||
|
ref && engine?.props?.onCompGetRef(schema, ref);
|
||||||
|
};
|
||||||
|
|
||||||
|
// scope需要传入到组件上
|
||||||
|
if (scopeKey && this.__compScopes[scopeKey]) {
|
||||||
|
props.__scope = this.__compScopes[scopeKey];
|
||||||
|
}
|
||||||
|
// FIXME 这里清除 key 是为了避免循环渲染中更改 key 导致的渲染重复
|
||||||
|
props.key = '';
|
||||||
|
if (schema?.__ctx?.lceKey) {
|
||||||
|
if (!isFileSchema(schema)) {
|
||||||
|
engine?.props?.onCompGetCtx(schema, self);
|
||||||
|
}
|
||||||
|
props.key = props.key || `${schema.__ctx.lceKey}_${schema.__ctx.idx || 0}_${idx !== undefined ? idx : ''}`;
|
||||||
|
} else if (typeof idx === 'number' && !props.key) {
|
||||||
|
props.key = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
props.__id = schema.id;
|
||||||
|
if (!props.key) {
|
||||||
|
props.key = props.__id;
|
||||||
|
}
|
||||||
|
|
||||||
|
let child: any = null;
|
||||||
|
if (/*!isFileSchema(schema) && */!!_children) {
|
||||||
|
child = this.__createVirtualDom(
|
||||||
|
isJSExpression(_children) ? parseExpression(_children, self) : _children,
|
||||||
|
self,
|
||||||
|
{
|
||||||
|
schema,
|
||||||
|
Comp,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const renderComp = (props: any) => engine.createElement(Comp, props, child);
|
||||||
|
// 设计模式下的特殊处理
|
||||||
|
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
|
||||||
|
// 对于overlay,dialog等组件为了使其在设计模式下显示,外层需要增加一个div容器
|
||||||
|
if (OVERLAY_LIST.includes(schema.componentName)) {
|
||||||
|
const { ref, ...overlayProps } = otherProps;
|
||||||
|
return createElement(Div, {
|
||||||
|
ref,
|
||||||
|
__designMode: engine.props.designMode,
|
||||||
|
}, renderComp({ ...props, ...overlayProps }));
|
||||||
|
}
|
||||||
|
// 虚拟dom显示
|
||||||
|
if (componentInfo?.parentRule) {
|
||||||
|
const parentList = componentInfo.parentRule.split(',');
|
||||||
|
const { schema: parentSchema, Comp: parentComp } = parentInfo;
|
||||||
|
if (
|
||||||
|
!parentList.includes(parentSchema.componentName) ||
|
||||||
|
parentComp !== components[parentSchema.componentName]
|
||||||
|
) {
|
||||||
|
props.__componentName = schema.componentName;
|
||||||
|
Comp = VisualDom;
|
||||||
|
} else {
|
||||||
|
// 若虚拟dom在正常的渲染上下文中,就不显示设计模式了
|
||||||
|
props.__disableDesignMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return renderComp({ ...props, ...otherProps });
|
||||||
|
} catch (e) {
|
||||||
|
return engine.createElement(engine.getFaultComponent(), {
|
||||||
|
error: e,
|
||||||
|
schema,
|
||||||
|
self,
|
||||||
|
parentInfo,
|
||||||
|
idx,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
__createLoopVirtualDom = (schema: any, self: any, parentInfo: IInfo, idx: number | string) => {
|
||||||
|
if (isFileSchema(schema)) {
|
||||||
|
console.warn('file type not support Loop');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(schema.loop)) return null;
|
||||||
|
const itemArg = (schema.loopArgs && schema.loopArgs[0]) || 'item';
|
||||||
|
const indexArg = (schema.loopArgs && schema.loopArgs[1]) || 'index';
|
||||||
|
return schema.loop.map((item: Array<string>, i: number) => {
|
||||||
|
const loopSelf: any = {
|
||||||
|
[itemArg]: item,
|
||||||
|
[indexArg]: i,
|
||||||
|
};
|
||||||
|
loopSelf.__proto__ = self;
|
||||||
|
return this.__createVirtualDom(
|
||||||
|
{
|
||||||
|
...schema,
|
||||||
|
loop: undefined,
|
||||||
|
},
|
||||||
|
loopSelf,
|
||||||
|
parentInfo,
|
||||||
|
idx ? `${idx}_${i}` : i,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
__parseProps = (props: any, self: any, path: string, info: IInfo): any => {
|
||||||
|
const { schema, Comp, componentInfo = {} } = info;
|
||||||
|
const propInfo = getValue(componentInfo.props, path);
|
||||||
|
// FIXME! 将这行逻辑外置,解耦,线上环境不要验证参数,调试环境可以有,通过传参自定义
|
||||||
|
const propType = propInfo?.extra?.propType;
|
||||||
|
const ignoreParse = schema.__ignoreParse || [];
|
||||||
|
const checkProps = (value: any) => {
|
||||||
|
if (!propType) return value;
|
||||||
|
return checkPropTypes(value, path, propType, componentInfo.name) ? value : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseReactNode = (data: any, params: any) => {
|
||||||
|
if (isEmpty(params)) {
|
||||||
|
return checkProps(this.__createVirtualDom(data, self, ({ schema, Comp } as IInfo)));
|
||||||
|
}
|
||||||
|
return checkProps(function () {
|
||||||
|
const args: any = {};
|
||||||
|
if (Array.isArray(params) && params.length) {
|
||||||
|
params.forEach((item, idx) => {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
args[item] = arguments[idx];
|
||||||
|
} else if (item && typeof item === 'object') {
|
||||||
|
args[item.name] = arguments[idx];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
args.__proto__ = self;
|
||||||
|
return self.__createVirtualDom(data, args, { schema, Comp });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 判断是否需要解析变量
|
||||||
|
if (
|
||||||
|
ignoreParse.some((item: any) => {
|
||||||
|
if (item instanceof RegExp) {
|
||||||
|
return item.test(path);
|
||||||
|
}
|
||||||
|
return item === path;
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
return checkProps(props);
|
||||||
|
}
|
||||||
|
if (isJSExpression(props)) {
|
||||||
|
props = parseExpression(props, self);
|
||||||
|
// 只有当变量解析出来为模型结构的时候才会继续解析
|
||||||
|
if (!isSchema(props) && !isJSSlot(props)) return checkProps(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleI18n = (props: any) => props[props.use || 'zh_CN'];
|
||||||
|
|
||||||
|
// 兼容乐高设计态 i18n 数据
|
||||||
|
if (isI18n(props)) {
|
||||||
|
props = handleI18n(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容乐高设计态的变量绑定
|
||||||
|
if (isVariable(props)) {
|
||||||
|
props = props.value;
|
||||||
|
if (isI18n(props)) {
|
||||||
|
props = handleI18n(props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJSFunction(props)) {
|
||||||
|
props = transformStringToFunction(props.value);
|
||||||
|
}
|
||||||
|
if (isJSSlot(props)) {
|
||||||
|
const { params, value } = props;
|
||||||
|
if (!isSchema(value) || isEmpty(value)) return undefined;
|
||||||
|
return parseReactNode(value, params);
|
||||||
|
}
|
||||||
|
// 兼容通过componentInfo判断的情况
|
||||||
|
if (isSchema(props)) {
|
||||||
|
const isReactNodeFunction = !!(
|
||||||
|
propInfo?.type === 'ReactNode'
|
||||||
|
&& propInfo?.props?.type === 'function'
|
||||||
|
);
|
||||||
|
|
||||||
|
const isMixinReactNodeFunction = !!(
|
||||||
|
propInfo?.type === 'Mixin'
|
||||||
|
&& propInfo?.props?.types?.indexOf('ReactNode') > -1
|
||||||
|
&& propInfo?.props?.reactNodeProps?.type === 'function'
|
||||||
|
);
|
||||||
|
return parseReactNode(
|
||||||
|
props,
|
||||||
|
isReactNodeFunction
|
||||||
|
? propInfo.props.params
|
||||||
|
: isMixinReactNodeFunction
|
||||||
|
? propInfo.props.reactNodeProps.params
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (Array.isArray(props)) {
|
||||||
|
return checkProps(props.map((item, idx) => this.__parseProps(item, self, path ? `${path}.${idx}` : `${idx}`, info)));
|
||||||
|
}
|
||||||
|
if (typeof props === 'function') {
|
||||||
|
return checkProps(props.bind(self));
|
||||||
|
}
|
||||||
|
if (props && typeof props === 'object') {
|
||||||
|
if (props.$$typeof) return checkProps(props);
|
||||||
|
const res: any = {};
|
||||||
|
forEach(props, (val: any, key: string) => {
|
||||||
|
if (key.startsWith('__')) {
|
||||||
|
res[key] = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res[key] = this.__parseProps(val, self, path ? `${path}.${key}` : key, info);
|
||||||
|
});
|
||||||
|
return checkProps(res);
|
||||||
|
}
|
||||||
|
if (typeof props === 'string') {
|
||||||
|
return checkProps(props.trim());
|
||||||
|
}
|
||||||
|
return checkProps(props);
|
||||||
|
};
|
||||||
|
|
||||||
|
$(filedId: string, instance?: any) {
|
||||||
|
this.__instanceMap = this.__instanceMap || {};
|
||||||
|
if (!filedId) {
|
||||||
|
return this.__instanceMap;
|
||||||
|
}
|
||||||
|
if (instance) {
|
||||||
|
this.__instanceMap[filedId] = instance;
|
||||||
|
}
|
||||||
|
return this.__instanceMap[filedId];
|
||||||
|
}
|
||||||
|
|
||||||
|
__initDebug = () => {
|
||||||
|
this.__logger = Debug(`renderer:${this.__namespace || 'base'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
__debug = (msg: string = '') => {
|
||||||
|
if (this.__logger) {
|
||||||
|
this.__logger(`${this.__namespace}.${msg}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__renderContextProvider = (customProps?: object, children?: any) => {
|
||||||
|
customProps = customProps || {};
|
||||||
|
children = children || this.__createDom();
|
||||||
|
return createElement(AppContext.Provider, {
|
||||||
|
value: {
|
||||||
|
...this.context,
|
||||||
|
blockContext: this,
|
||||||
|
...customProps,
|
||||||
|
}, children
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
__renderContextConsumer = (children: any) => {
|
||||||
|
return createElement(AppContext.Consumer, {}, children);
|
||||||
|
}
|
||||||
|
|
||||||
|
__renderComp(Comp: any, ctxProps: object) {
|
||||||
|
const { __schema } = this.props;
|
||||||
|
const data = this.__parseData(__schema?.props);
|
||||||
|
const { className } = data;
|
||||||
|
const { engine } = this.context || {};
|
||||||
|
if (!engine) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const child = engine.createElement(
|
||||||
|
Comp || Div,
|
||||||
|
{
|
||||||
|
...data,
|
||||||
|
...this.props,
|
||||||
|
ref: this.__getRef,
|
||||||
|
className: classnames(getFileCssName(__schema?.fileName), className, this.props.className),
|
||||||
|
__id: __schema?.id,
|
||||||
|
},
|
||||||
|
this.__createDom(),
|
||||||
|
);
|
||||||
|
return this.__renderContextProvider(ctxProps, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
__renderContent(children: any) {
|
||||||
|
const { __schema } = this.props;
|
||||||
|
const props = this.__parseData(__schema.props);
|
||||||
|
const { id, className, style = {} } = props;
|
||||||
|
return createElement('div', {
|
||||||
|
ref: this.__getRef,
|
||||||
|
className: classnames(`lce-${this.__namespace}`, getFileCssName(__schema.fileName), className, this.props.className),
|
||||||
|
id: this.props.id || id,
|
||||||
|
style: { ...style, ...(typeof this.props.style === 'object' ? this.props.style : {}) },
|
||||||
|
}, children);
|
||||||
|
}
|
||||||
|
|
||||||
|
__checkSchema = (schema: ISchema, extraComponents: string | string[] = []) => {
|
||||||
|
if (typeof extraComponents === 'string') {
|
||||||
|
extraComponents = [extraComponents];
|
||||||
|
}
|
||||||
|
|
||||||
|
const buitin = capitalizeFirstLetter(this.__namespace);
|
||||||
|
const componentNames = [buitin, ...extraComponents];
|
||||||
|
return !isSchema(schema, true) || !componentNames.includes(schema.componentName)
|
||||||
|
}
|
||||||
|
|
||||||
|
get requestHandlersMap() {
|
||||||
|
return this.appHelper?.requestHandlersMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
get utils() {
|
||||||
|
return this.appHelper?.utils;
|
||||||
|
}
|
||||||
|
|
||||||
|
get constants() {
|
||||||
|
return this.appHelper?.constants;
|
||||||
|
}
|
||||||
|
|
||||||
|
get history() {
|
||||||
|
return this.appHelper?.history;
|
||||||
|
}
|
||||||
|
|
||||||
|
get location() {
|
||||||
|
return this.appHelper?.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
get match() {
|
||||||
|
return this.appHelper?.match;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
39
packages/renderer-core/src/renderer/block.tsx
Normal file
39
packages/renderer-core/src/renderer/block.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import classnames from 'classnames';
|
||||||
|
import baseRendererFactory from './base';
|
||||||
|
import { IRendererProps } from '../types';
|
||||||
|
import { getFileCssName } from '../utils';
|
||||||
|
|
||||||
|
export default function blockRendererFactory() {
|
||||||
|
const BaseRenderer = baseRendererFactory();
|
||||||
|
return class BlockRenderer extends BaseRenderer {
|
||||||
|
static dislayName = 'block-renderer';
|
||||||
|
__namespace = 'block';
|
||||||
|
|
||||||
|
__afterInit(props: IRendererProps) {
|
||||||
|
this.__generateCtx({});
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
this.state = this.__parseData(schema.state || {});
|
||||||
|
this.__initDataSource(props);
|
||||||
|
this.__setLifeCycleMethods('constructor', arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema, __components } = this.props;
|
||||||
|
|
||||||
|
if (this.__checkSchema(__schema, 'Div')) {
|
||||||
|
return '区块 schema 结构异常!';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__debug(`render - ${__schema.fileName}`);
|
||||||
|
this.__generateCtx({});
|
||||||
|
this.__render();
|
||||||
|
|
||||||
|
const { Block } = __components;
|
||||||
|
if (Block) {
|
||||||
|
return this.__renderComp(Block, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.__renderContent(this.__renderContextProvider());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
41
packages/renderer-core/src/renderer/component.tsx
Normal file
41
packages/renderer-core/src/renderer/component.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import baseRendererFactory from './base';
|
||||||
|
import { IRendererProps } from '../types';
|
||||||
|
|
||||||
|
export default function componentRendererFactory() {
|
||||||
|
const BaseRenderer = baseRendererFactory();
|
||||||
|
return class CompRenderer extends BaseRenderer {
|
||||||
|
static dislayName = 'comp-renderer';
|
||||||
|
__namespace = 'component';
|
||||||
|
|
||||||
|
__afterInit(props: IRendererProps) {
|
||||||
|
this.__generateCtx({
|
||||||
|
component: this,
|
||||||
|
});
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
this.state = this.__parseData(schema.state || {});
|
||||||
|
this.__initDataSource(props);
|
||||||
|
this.__setLifeCycleMethods('constructor', arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema } = this.props;
|
||||||
|
if (this.__checkSchema(__schema)) {
|
||||||
|
return '自定义组件 schema 结构异常!';
|
||||||
|
}
|
||||||
|
this.__debug(`render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
this.__generateCtx({
|
||||||
|
component: this,
|
||||||
|
});
|
||||||
|
this.__render();
|
||||||
|
|
||||||
|
const { noContainer } = this.__parseData(__schema.props);
|
||||||
|
|
||||||
|
if (noContainer) {
|
||||||
|
return this.__renderContextProvider({ compContext: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.__renderContent(this.__renderContextProvider({ compContext: this }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
17
packages/renderer-core/src/renderer/index.ts
Normal file
17
packages/renderer-core/src/renderer/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import baseRendererFactory from './base';
|
||||||
|
import pageRendererFactory from './page';
|
||||||
|
import componentRendererFactory from './component';
|
||||||
|
import blockRendererFactory from './block';
|
||||||
|
import addonRendererFactory from './addon';
|
||||||
|
import tempRendererFactory from './temp';
|
||||||
|
import rendererFactory from './renderer';
|
||||||
|
|
||||||
|
export {
|
||||||
|
baseRendererFactory,
|
||||||
|
pageRendererFactory,
|
||||||
|
componentRendererFactory,
|
||||||
|
blockRendererFactory,
|
||||||
|
addonRendererFactory,
|
||||||
|
tempRendererFactory,
|
||||||
|
rendererFactory,
|
||||||
|
};
|
||||||
59
packages/renderer-core/src/renderer/page.tsx
Normal file
59
packages/renderer-core/src/renderer/page.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import baseRendererFactory from './base';
|
||||||
|
import { parseData } from '../utils';
|
||||||
|
import { IRendererProps } from '../types';
|
||||||
|
|
||||||
|
export default function pageRendererFactory() {
|
||||||
|
const BaseRenderer = baseRendererFactory();
|
||||||
|
return class PageRenderer extends BaseRenderer {
|
||||||
|
static dislayName = 'page-renderer';
|
||||||
|
__namespace = 'page';
|
||||||
|
|
||||||
|
__afterInit(props: IRendererProps) {
|
||||||
|
this.__generateCtx({
|
||||||
|
page: this,
|
||||||
|
});
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
this.state = this.__parseData(schema.state || {});
|
||||||
|
this.__initDataSource(props);
|
||||||
|
this.__setLifeCycleMethods('constructor', arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidUpdate(prevProps: any) {
|
||||||
|
const { __ctx } = this.props;
|
||||||
|
const prevState = parseData(prevProps.__schema.state, __ctx);
|
||||||
|
const newState = parseData(this.props.__schema.state, __ctx);
|
||||||
|
// 当编排的时候修改schema.state值,需要将最新schema.state值setState
|
||||||
|
if (JSON.stringify(newState) != JSON.stringify(prevState)) {
|
||||||
|
this.setState(newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.componentDidUpdate(...arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema, __components } = this.props;
|
||||||
|
if (this.__checkSchema(__schema)) {
|
||||||
|
return '页面schema结构异常!';
|
||||||
|
}
|
||||||
|
this.__debug(`render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
this.__bindCustomMethods(this.props);
|
||||||
|
this.__initDataSource(this.props);
|
||||||
|
|
||||||
|
// this.__setLifeCycleMethods('constructor', arguments);
|
||||||
|
|
||||||
|
this.__generateCtx({
|
||||||
|
page: this,
|
||||||
|
});
|
||||||
|
this.__render();
|
||||||
|
|
||||||
|
|
||||||
|
const { Page } = __components;
|
||||||
|
if (Page) {
|
||||||
|
return this.__renderComp(Page, { pageContext: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.__renderContent(this.__renderContextProvider({ pageContext: this }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
189
packages/renderer-core/src/renderer/renderer.tsx
Normal file
189
packages/renderer-core/src/renderer/renderer.tsx
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import Debug from 'debug';
|
||||||
|
import { isEmpty } from '@ali/b3-one/lib/obj';
|
||||||
|
import adapter from '../adapter';
|
||||||
|
import contextFactory from '../context';
|
||||||
|
import { isFileSchema, goldlog } from '../utils';
|
||||||
|
import baseRendererFactory from './base';
|
||||||
|
import divFactory from '../components/Div';
|
||||||
|
import { IProps } from '../types';
|
||||||
|
|
||||||
|
export default function rendererFactory() {
|
||||||
|
const { createElement, Component, PureComponent, findDOMNode } = adapter.getRuntime();
|
||||||
|
const RENDERER_COMPS: any = adapter.getRenderers();
|
||||||
|
const BaseRenderer = baseRendererFactory();
|
||||||
|
const AppContext = contextFactory();
|
||||||
|
const Div = divFactory();
|
||||||
|
|
||||||
|
const ConfigProvider = adapter.getConfigProvider() || Div;
|
||||||
|
|
||||||
|
const debug = Debug('renderer:entry');
|
||||||
|
|
||||||
|
class FaultComponent extends PureComponent {
|
||||||
|
render() {
|
||||||
|
// FIXME: errorlog
|
||||||
|
console.error('render error', this.props);
|
||||||
|
return createElement(Div, {
|
||||||
|
style: {
|
||||||
|
width: '100%',
|
||||||
|
height: '50px',
|
||||||
|
lineHeight: '50px',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: '15px',
|
||||||
|
color: '#ff0000',
|
||||||
|
border: '2px solid #ff0000',
|
||||||
|
},
|
||||||
|
}, '组件渲染异常,请查看控制台日志');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotFoundComponent extends PureComponent {
|
||||||
|
render() {
|
||||||
|
console.error('component not found', this.props);
|
||||||
|
return createElement(Div, this.props, this.props.children || 'Component Not Found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return class Renderer extends Component {
|
||||||
|
static dislayName = 'renderer';
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
appHelper: null,
|
||||||
|
components: {},
|
||||||
|
designMode: '',
|
||||||
|
suspended: false,
|
||||||
|
schema: {},
|
||||||
|
onCompGetRef: () => { },
|
||||||
|
onCompGetCtx: () => { },
|
||||||
|
};
|
||||||
|
|
||||||
|
static findDOMNode = findDOMNode;
|
||||||
|
|
||||||
|
constructor(props: IProps, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
this.state = {};
|
||||||
|
debug(`entry.constructor - ${props?.schema?.componentName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
goldlog(
|
||||||
|
'EXP',
|
||||||
|
{
|
||||||
|
action: 'appear',
|
||||||
|
value: !!this.props.designMode,
|
||||||
|
},
|
||||||
|
'renderer',
|
||||||
|
);
|
||||||
|
debug(`entry.componentDidMount - ${this.props.schema && this.props.schema.componentName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidUpdate() {
|
||||||
|
debug(`entry.componentDidUpdate - ${this.props?.schema?.componentName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentWillUnmount() {
|
||||||
|
debug(`entry.componentWillUnmount - ${this.props?.schema?.componentName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidCatch(e: any) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps: IProps) {
|
||||||
|
return !nextProps.suspended;
|
||||||
|
}
|
||||||
|
|
||||||
|
__getRef = (ref: any) => {
|
||||||
|
this.__ref = ref;
|
||||||
|
if (ref) {
|
||||||
|
this.props.onCompGetRef(this.props.schema, ref, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
isValidComponent(SetComponent: any) {
|
||||||
|
return SetComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
patchDidCatch(SetComponent: any) {
|
||||||
|
if (!this.isValidComponent(SetComponent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SetComponent.patchedCatch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetComponent.patchedCatch = true;
|
||||||
|
SetComponent.getDerivedStateFromError = (error: Error) => {
|
||||||
|
return { engineRenderError: true, error };
|
||||||
|
};
|
||||||
|
const engine = this;
|
||||||
|
const originRender = SetComponent.prototype.render;
|
||||||
|
SetComponent.prototype.render = function () {
|
||||||
|
if (this.state && this.state.engineRenderError) {
|
||||||
|
this.state.engineRenderError = false;
|
||||||
|
return engine.createElement(engine.getFaultComponent(), {
|
||||||
|
...this.props,
|
||||||
|
error: this.state.error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return originRender.call(this);
|
||||||
|
};
|
||||||
|
const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate;
|
||||||
|
SetComponent.prototype.shouldComponentUpdate = function (nextProps: IProps, nextState: any) {
|
||||||
|
if (nextState && nextState.engineRenderError) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
createElement(SetComponent: any, props: any, children?: any) {
|
||||||
|
// TODO: enable in runtime mode?
|
||||||
|
this.patchDidCatch(SetComponent);
|
||||||
|
return (this.props.customCreateElement || createElement)(SetComponent, props, children);
|
||||||
|
}
|
||||||
|
|
||||||
|
getNotFoundComponent() {
|
||||||
|
return this.props.notFoundComponent || NotFoundComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFaultComponent() {
|
||||||
|
return this.props.faultComponent || FaultComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { schema, designMode, appHelper, components } = this.props;
|
||||||
|
if (isEmpty(schema)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 兼容乐高区块模板
|
||||||
|
if (schema.componentName !== 'Div' && !isFileSchema(schema)) {
|
||||||
|
return '模型结构异常';
|
||||||
|
}
|
||||||
|
debug('entry.render');
|
||||||
|
const { componentName } = schema;
|
||||||
|
const allComponents = { ...RENDERER_COMPS, ...components };
|
||||||
|
let Comp = allComponents[componentName] || RENDERER_COMPS[`${componentName}Renderer`];
|
||||||
|
if (Comp && Comp.prototype) {
|
||||||
|
if (!(Comp.prototype instanceof BaseRenderer)) {
|
||||||
|
Comp = RENDERER_COMPS[`${componentName}Renderer`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Comp) {
|
||||||
|
return createElement(AppContext.Provider, { value: {
|
||||||
|
appHelper,
|
||||||
|
components: allComponents,
|
||||||
|
engine: this,
|
||||||
|
}}, createElement(ConfigProvider, {device: this.props.device}, createElement(Comp, {
|
||||||
|
key: schema.__ctx && `${schema.__ctx.lceKey}_${schema.__ctx.idx || '0'}`,
|
||||||
|
ref: this.__getRef,
|
||||||
|
__appHelper: appHelper,
|
||||||
|
__components: allComponents,
|
||||||
|
__schema: schema,
|
||||||
|
__designMode: designMode,
|
||||||
|
...this.props,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
55
packages/renderer-core/src/renderer/temp.tsx
Normal file
55
packages/renderer-core/src/renderer/temp.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import baseRendererFactory from './base';
|
||||||
|
|
||||||
|
export default function tempRendererFactory() {
|
||||||
|
const BaseRenderer = baseRendererFactory();
|
||||||
|
|
||||||
|
return class TempRenderer extends BaseRenderer {
|
||||||
|
static dislayName = 'temp-renderer';
|
||||||
|
__namespace = 'temp';
|
||||||
|
|
||||||
|
__init() {
|
||||||
|
this.state = {};
|
||||||
|
this.cacheSetState = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
const ctx = this.props.__ctx;
|
||||||
|
if (!ctx) return;
|
||||||
|
const { setState } = ctx;
|
||||||
|
this.cacheSetState = setState;
|
||||||
|
ctx.setState = (...args: any) => {
|
||||||
|
setState.call(ctx, ...args);
|
||||||
|
setTimeout(() => this.forceUpdate(), 0);
|
||||||
|
};
|
||||||
|
this.__debug(`componentDidMount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidUpdate() {
|
||||||
|
this.__debug(`componentDidUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentWillUnmount() {
|
||||||
|
const ctx = this.props.__ctx;
|
||||||
|
if (!ctx || !this.cacheSetState) return;
|
||||||
|
ctx.setState = this.cacheSetState;
|
||||||
|
delete this.cacheSetState;
|
||||||
|
this.__debug(`componentWillUnmount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidCatch(e: any) {
|
||||||
|
console.warn(e);
|
||||||
|
this.__debug(`componentDidCatch - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema, __ctx } = this.props;
|
||||||
|
if (this.__checkSchema(__schema)) {
|
||||||
|
return '下钻编辑 schema 结构异常!';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__debug(`render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
return this.__renderContent(this.__renderContextProvider({ __ctx }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
122
packages/renderer-core/src/types/index.ts
Normal file
122
packages/renderer-core/src/types/index.ts
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
export interface IProps {
|
||||||
|
appHelper: any;
|
||||||
|
components: { [key: string]: any };
|
||||||
|
componentsMap: { [key: string]: any };
|
||||||
|
designMode: string;
|
||||||
|
suspended: boolean;
|
||||||
|
schema: ISchema;
|
||||||
|
onCompGetRef: (schema: ISchema, ref: any) => void;
|
||||||
|
onCompGetCtx: (schema: ISchema, ref: any) => void;
|
||||||
|
customCreateElement: (...args: any) => any;
|
||||||
|
notFoundComponent: any;
|
||||||
|
faultComponent: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRendererProps {
|
||||||
|
locale: string;
|
||||||
|
messages: object;
|
||||||
|
__appHelper: object;
|
||||||
|
__components: object;
|
||||||
|
__ctx: object;
|
||||||
|
__schema: ISchema;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComponentModel {
|
||||||
|
componentName: string;
|
||||||
|
props: any;
|
||||||
|
children: ComponentModel[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISchema {
|
||||||
|
componentName: string;
|
||||||
|
props: any;
|
||||||
|
children: ComponentModel[]
|
||||||
|
dataSource?: any;
|
||||||
|
methods?: any;
|
||||||
|
lifeCycles?: any;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IInfo {
|
||||||
|
schema: any;
|
||||||
|
Comp: any;
|
||||||
|
componentInfo?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JSExpression {
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DataSourceItem {
|
||||||
|
id: string;
|
||||||
|
isInit: boolean;
|
||||||
|
type: string;
|
||||||
|
options: {
|
||||||
|
uri: string;
|
||||||
|
params: object;
|
||||||
|
method: string;
|
||||||
|
shouldFetch?: string;
|
||||||
|
willFetch?: string;
|
||||||
|
fit?: string;
|
||||||
|
didFetch?: string;
|
||||||
|
};
|
||||||
|
dataHandler: JSExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DataSource {
|
||||||
|
list: DataSourceItem[];
|
||||||
|
dataHandler: JSExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Constructor = new(...args: any) => any;
|
||||||
|
|
||||||
|
export interface IRuntime {
|
||||||
|
Component: Constructor;
|
||||||
|
PureComponent: Constructor;
|
||||||
|
createElement: (...args: any) => any;
|
||||||
|
createContext: (...args: any) => any;
|
||||||
|
forwardRef: (...args: any) => any;
|
||||||
|
findDOMNode: (...args: any) => any;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRendererModules {
|
||||||
|
BaseRenderer?: any;
|
||||||
|
PageRenderer: any;
|
||||||
|
ComponentRenderer: any;
|
||||||
|
BlockRenderer?: any,
|
||||||
|
AddonRenderer?: any,
|
||||||
|
TempRenderer?: any,
|
||||||
|
DivRenderer?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRenderer {
|
||||||
|
props?: IRendererProps;
|
||||||
|
context?: any;
|
||||||
|
__beforeInit: (props: IRendererProps) => any;
|
||||||
|
__init: (props: IRendererProps) => any;
|
||||||
|
__afterInit: (props: IRendererProps) => any;
|
||||||
|
reloadDataSource: () => Promise<any>;
|
||||||
|
__setLifeCycleMethods: (method: string, args?: any) => any;
|
||||||
|
__bindCustomMethods: (props: IRendererProps) => any;
|
||||||
|
__generateCtx: (ctx: object) => any;
|
||||||
|
__parseData: (data: any, ctx?: object) => any;
|
||||||
|
__initDataSource: (props: IRendererProps) => any;
|
||||||
|
__render: () => any;
|
||||||
|
__getRef: (ref: any) => any;
|
||||||
|
getSchemaChildren: (schema: ISchema) => any;
|
||||||
|
__createDom: () => any;
|
||||||
|
__createVirtualDom: (schema: any, self: any, parentInfo: IInfo, idx: string | number) => any;
|
||||||
|
__createLoopVirtualDom: (schema: any, self: any, parentInfo: IInfo, idx: number | string) => any;
|
||||||
|
__parseProps: (props: any, self: any, path: string, info: IInfo) => any;
|
||||||
|
__initDebug: () => void;
|
||||||
|
__debug: (msg: string) => void;
|
||||||
|
__renderContextProvider: (customProps?: object, children?: any) => any;
|
||||||
|
__renderContextConsumer: (children: any) => any;
|
||||||
|
__renderContent: (children: any) => any;
|
||||||
|
__checkSchema: (schema: ISchema, extraComponents?: string | string[]) => any;
|
||||||
|
__renderComp: (Comp: any, ctxProps: object) => any;
|
||||||
|
$: (filedId: string, instance?: any) => any;
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
/* eslint-disable no-new-func */
|
/* eslint-disable no-new-func */
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import _keymaster from 'keymaster';
|
|
||||||
import { forEach as _forEach, shallowEqual as _shallowEqual } from '@ali/b3-one/lib/obj';
|
import { forEach as _forEach, shallowEqual as _shallowEqual } from '@ali/b3-one/lib/obj';
|
||||||
import { serialize as serializeParams } from '@ali/b3-one/lib/url';
|
import { serialize as serializeParams } from '@ali/b3-one/lib/url';
|
||||||
// moment对象配置
|
// moment对象配置
|
||||||
@ -20,12 +19,13 @@ import * as _jsonuri from 'jsonuri';
|
|||||||
|
|
||||||
import IntlMessageFormat from 'intl-messageformat';
|
import IntlMessageFormat from 'intl-messageformat';
|
||||||
|
|
||||||
export const keymaster = _keymaster;
|
import { ISchema } from '../types';
|
||||||
|
|
||||||
export const forEach = _forEach;
|
export const forEach = _forEach;
|
||||||
export const shallowEqual = _shallowEqual;
|
export const shallowEqual = _shallowEqual;
|
||||||
export const moment = _moment;
|
export const moment = _moment;
|
||||||
moment.locale('zh-cn');
|
moment.locale('zh-cn');
|
||||||
window.sdkVersion = pkg.version;
|
(window as any).sdkVersion = pkg.version;
|
||||||
|
|
||||||
export const pick = _pick;
|
export const pick = _pick;
|
||||||
export const deepEqual = _deepEqual;
|
export const deepEqual = _deepEqual;
|
||||||
@ -35,7 +35,6 @@ export const throttle = _throttle;
|
|||||||
export const debounce = _debounce;
|
export const debounce = _debounce;
|
||||||
export const serialize = _serialize;
|
export const serialize = _serialize;
|
||||||
export const jsonuri = _jsonuri;
|
export const jsonuri = _jsonuri;
|
||||||
export { get, post, jsonp, mtop, request } from './request';
|
|
||||||
|
|
||||||
const ReactIs = require('react-is');
|
const ReactIs = require('react-is');
|
||||||
const ReactPropTypesSecret = require('prop-types/lib/ReactPropTypesSecret');
|
const ReactPropTypesSecret = require('prop-types/lib/ReactPropTypesSecret');
|
||||||
@ -47,6 +46,7 @@ const EXPRESSION_TYPE = {
|
|||||||
JSEXPRESSION: 'JSExpression',
|
JSEXPRESSION: 'JSExpression',
|
||||||
JSFUNCTION: 'JSFunction',
|
JSFUNCTION: 'JSFunction',
|
||||||
JSSLOT: 'JSSlot',
|
JSSLOT: 'JSSlot',
|
||||||
|
JSBLOCK: 'JSBlock'
|
||||||
};
|
};
|
||||||
const EXPRESSION_REG = /^\{\{(\{.*\}|.*?)\}\}$/;
|
const EXPRESSION_REG = /^\{\{(\{.*\}|.*?)\}\}$/;
|
||||||
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
|
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
|
||||||
@ -64,7 +64,7 @@ const ENV = {
|
|||||||
* @name isSchema
|
* @name isSchema
|
||||||
* @description 判断是否是模型结构
|
* @description 判断是否是模型结构
|
||||||
*/
|
*/
|
||||||
export function isSchema(schema, ignoreArr) {
|
export function isSchema(schema: ISchema, ignoreArr = false): boolean {
|
||||||
if (isEmpty(schema)) return false;
|
if (isEmpty(schema)) return false;
|
||||||
// Leaf 组件也返回 true
|
// Leaf 组件也返回 true
|
||||||
if (schema.componentName === 'Leaf' || schema.componentName === 'Slot') return true;
|
if (schema.componentName === 'Leaf' || schema.componentName === 'Slot') return true;
|
||||||
@ -72,7 +72,7 @@ export function isSchema(schema, ignoreArr) {
|
|||||||
return !!(schema.componentName && schema.props && (typeof schema.props === 'object' || isJSExpression(schema.props)));
|
return !!(schema.componentName && schema.props && (typeof schema.props === 'object' || isJSExpression(schema.props)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFileSchema(schema) {
|
export function isFileSchema(schema: ISchema) {
|
||||||
if (isEmpty(schema)) return false;
|
if (isEmpty(schema)) return false;
|
||||||
return ['Page', 'Block', 'Component', 'Addon', 'Temp'].includes(schema.componentName);
|
return ['Page', 'Block', 'Component', 'Addon', 'Temp'].includes(schema.componentName);
|
||||||
}
|
}
|
||||||
@ -86,22 +86,25 @@ export function inSameDomain() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFileCssName(fileName) {
|
export function getFileCssName(fileName: string) {
|
||||||
if (!fileName) return;
|
if (!fileName) return;
|
||||||
const name = fileName.replace(/([A-Z])/g, '-$1').toLowerCase();
|
const name = fileName.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
return (`luna-${ name}`)
|
return (`luna-${name}`)
|
||||||
.split('-')
|
.split('-')
|
||||||
.filter((p) => !!p)
|
.filter((p) => !!p)
|
||||||
.join('-');
|
.join('-');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isJSSlot(obj) {
|
// 兼容乐高设计态 JSBlock 的老协议
|
||||||
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSSLOT === obj.type;
|
export function isJSSlot(obj: any) {
|
||||||
|
return obj && typeof obj === 'object' && ([EXPRESSION_TYPE.JSSLOT, EXPRESSION_TYPE.JSBLOCK].includes(obj.type));
|
||||||
}
|
}
|
||||||
export function isJSFunction(obj) {
|
|
||||||
|
export function isJSFunction(obj: any) {
|
||||||
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSFUNCTION === obj.type;
|
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSFUNCTION === obj.type;
|
||||||
}
|
}
|
||||||
export function isJSExpression(obj) {
|
|
||||||
|
export function isJSExpression(obj: any) {
|
||||||
// 兼容两种写法,有js构造表达式的情况
|
// 兼容两种写法,有js构造表达式的情况
|
||||||
const isJSExpressionObj =
|
const isJSExpressionObj =
|
||||||
obj && typeof obj === 'object' && EXPRESSION_TYPE.JSEXPRESSION === obj.type && typeof obj.value === 'string';
|
obj && typeof obj === 'object' && EXPRESSION_TYPE.JSEXPRESSION === obj.type && typeof obj.value === 'string';
|
||||||
@ -113,17 +116,17 @@ export function isJSExpression(obj) {
|
|||||||
* @name wait
|
* @name wait
|
||||||
* @description 等待函数
|
* @description 等待函数
|
||||||
*/
|
*/
|
||||||
export function wait(ms) {
|
export function wait(ms: number) {
|
||||||
return new Promise((resolve) => setTimeout(() => resolve(true), ms));
|
return new Promise((resolve) => setTimeout(() => resolve(true), ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function curry(Comp, hocs = []) {
|
export function curry(Comp: any, hocs = []) {
|
||||||
return hocs.reverse().reduce((pre, cur) => {
|
return hocs.reverse().reduce((pre, cur: (pre: any) => any) => {
|
||||||
return cur(pre);
|
return cur(pre);
|
||||||
}, Comp);
|
}, Comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getValue(obj, path, defaultValue) {
|
export function getValue(obj: any, path: string, defaultValue = {}) {
|
||||||
if (isEmpty(obj) || typeof obj !== 'object') return defaultValue;
|
if (isEmpty(obj) || typeof obj !== 'object') return defaultValue;
|
||||||
const res = path.split('.').reduce((pre, cur) => {
|
const res = path.split('.').reduce((pre, cur) => {
|
||||||
return pre && pre[cur];
|
return pre && pre[cur];
|
||||||
@ -132,25 +135,8 @@ export function getValue(obj, path, defaultValue) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseObj(schemaStr) {
|
|
||||||
if (typeof schemaStr !== 'string') return schemaStr;
|
|
||||||
// 默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
|
||||||
try {
|
|
||||||
if (inSameDomain() && window.parent.__newFunc) {
|
|
||||||
return window.parent.__newFunc(`"use strict"; return ${schemaStr}`)();
|
|
||||||
}
|
|
||||||
return new Function(`"use strict"; return ${schemaStr}`)();
|
|
||||||
} catch (err) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fastClone(obj) {
|
|
||||||
return parseObj(serialize(obj, { unsafe: true }));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新obj的内容但不改变obj的指针
|
// 更新obj的内容但不改变obj的指针
|
||||||
export function fillObj(receiver = {}, ...suppliers) {
|
export function fillObj(receiver: any = {}, ...suppliers: any) {
|
||||||
Object.keys(receiver).forEach((item) => {
|
Object.keys(receiver).forEach((item) => {
|
||||||
delete receiver[item];
|
delete receiver[item];
|
||||||
});
|
});
|
||||||
@ -159,14 +145,15 @@ export function fillObj(receiver = {}, ...suppliers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 中划线转驼峰
|
// 中划线转驼峰
|
||||||
export function toHump(name) {
|
export function toHump(name: string) {
|
||||||
// eslint-disable-next-line no-useless-escape
|
// eslint-disable-next-line no-useless-escape
|
||||||
return name.replace(/\-(\w)/g, (all, letter) => {
|
return name.replace(/\-(\w)/g, (_: any, letter: string) => {
|
||||||
return letter.toUpperCase();
|
return letter.toUpperCase();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 驼峰转中划线
|
// 驼峰转中划线
|
||||||
export function toLine(name) {
|
export function toLine(name: string) {
|
||||||
return name.replace(/([A-Z])/g, '-$1').toLowerCase();
|
return name.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +162,7 @@ export function getEnv() {
|
|||||||
const { userAgent } = navigator;
|
const { userAgent } = navigator;
|
||||||
const isVscode = /Electron\//.test(userAgent);
|
const isVscode = /Electron\//.test(userAgent);
|
||||||
if (isVscode) return ENV.VSCODE;
|
if (isVscode) return ENV.VSCODE;
|
||||||
const isTheia = window.is_theia === true;
|
const isTheia = (window as any).is_theia === true;
|
||||||
if (isTheia) return ENV.WEBIDE;
|
if (isTheia) return ENV.WEBIDE;
|
||||||
return ENV.WEB;
|
return ENV.WEB;
|
||||||
}
|
}
|
||||||
@ -185,8 +172,8 @@ export function getEnv() {
|
|||||||
* @param {*} locale 国际化标识,例如 zh-CN、en-US
|
* @param {*} locale 国际化标识,例如 zh-CN、en-US
|
||||||
* @param {*} messages 国际化语言包
|
* @param {*} messages 国际化语言包
|
||||||
*/
|
*/
|
||||||
export function generateI18n(locale = 'zh-CN', messages = {}) {
|
export function generateI18n(locale = 'zh-CN', messages: any = {}) {
|
||||||
return (key, values = {}) => {
|
return (key: string, values = {}) => {
|
||||||
if (!messages || !messages[key]) return '';
|
if (!messages || !messages[key]) return '';
|
||||||
const formater = new IntlMessageFormat(messages[key], locale);
|
const formater = new IntlMessageFormat(messages[key], locale);
|
||||||
return formater.format(values);
|
return formater.format(values);
|
||||||
@ -197,10 +184,8 @@ export function generateI18n(locale = 'zh-CN', messages = {}) {
|
|||||||
* 判断当前组件是否能够设置ref
|
* 判断当前组件是否能够设置ref
|
||||||
* @param {*} Comp 需要判断的组件
|
* @param {*} Comp 需要判断的组件
|
||||||
*/
|
*/
|
||||||
export function acceptsRef(Comp) {
|
export function acceptsRef(Comp: any) {
|
||||||
return (
|
return Comp?.$$typeof === REACT_FORWARD_REF_TYPE || Comp?.prototype?.isReactComponent || Comp?.prototype?.setState;
|
||||||
(Comp.$$typeof && Comp.$$typeof === REACT_FORWARD_REF_TYPE) || (Comp.prototype && Comp.prototype.isReactComponent)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -209,9 +194,9 @@ export function acceptsRef(Comp) {
|
|||||||
* @param {Object} params 参数
|
* @param {Object} params 参数
|
||||||
* @param {String} logKey 属性串
|
* @param {String} logKey 属性串
|
||||||
*/
|
*/
|
||||||
export function goldlog(gmKey, params = {}, logKey = 'other') {
|
export function goldlog(gmKey: string, params = {}, logKey = 'other') {
|
||||||
// vscode 黄金令箭API
|
// vscode 黄金令箭API
|
||||||
const sendIDEMessage = window.sendIDEMessage || (inSameDomain() && window.parent.sendIDEMessage);
|
const sendIDEMessage = (window as any).sendIDEMessage || (inSameDomain() && (window.parent as any).sendIDEMessage);
|
||||||
const goKey = serializeParams({
|
const goKey = serializeParams({
|
||||||
sdkVersion: pkg.version,
|
sdkVersion: pkg.version,
|
||||||
env: getEnv(),
|
env: getEnv(),
|
||||||
@ -221,19 +206,19 @@ export function goldlog(gmKey, params = {}, logKey = 'other') {
|
|||||||
sendIDEMessage({
|
sendIDEMessage({
|
||||||
action: 'goldlog',
|
action: 'goldlog',
|
||||||
data: {
|
data: {
|
||||||
logKey: `/iceluna.core.${logKey}`,
|
logKey: `/lce.core.${logKey}`,
|
||||||
gmKey,
|
gmKey,
|
||||||
goKey,
|
goKey,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.goldlog && window.goldlog.record(`/iceluna.core.${logKey}`, gmKey, goKey, 'POST');
|
(window as any)?.goldlog?.record(`/lce.core.${logKey}`, gmKey, goKey, 'POST');
|
||||||
}
|
}
|
||||||
|
|
||||||
// utils为编辑器打包生成的utils文件内容,utilsConfig为数据库存放的utils配置
|
// utils为编辑器打包生成的utils文件内容,utilsConfig为数据库存放的utils配置
|
||||||
export function generateUtils(utils, utilsConfig) {
|
export function generateUtils(utils: any, utilsConfig: { name: string; type: string; content: any }[]) {
|
||||||
if (!Array.isArray(utilsConfig)) return { ...utils };
|
if (!Array.isArray(utilsConfig)) return { ...utils };
|
||||||
const res = {};
|
const res: any = {};
|
||||||
utilsConfig.forEach((item) => {
|
utilsConfig.forEach((item) => {
|
||||||
if (!item.name || !item.type || !item.content) return;
|
if (!item.name || !item.type || !item.content) return;
|
||||||
if (item.type === 'function' && typeof item.content === 'function') {
|
if (item.type === 'function' && typeof item.content === 'function') {
|
||||||
@ -244,70 +229,20 @@ export function generateUtils(utils, utilsConfig) {
|
|||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// 复制到粘贴板
|
|
||||||
export function setClipboardData(str) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (typeof str !== 'string') reject('不支持拷贝');
|
|
||||||
if (navigator.clipboard) {
|
|
||||||
navigator.clipboard
|
|
||||||
.writeText(str)
|
|
||||||
.then(() => {
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
reject('复制失败,请重试!', err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const textArea = document.createElement('textarea');
|
|
||||||
textArea.value = str;
|
|
||||||
document.body.appendChild(textArea);
|
|
||||||
textArea.focus();
|
|
||||||
textArea.select();
|
|
||||||
try {
|
|
||||||
const successful = document.execCommand('copy');
|
|
||||||
if (successful) {
|
|
||||||
document.body.removeChild(textArea);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
document.body.removeChild(textArea);
|
|
||||||
reject('复制失败,请重试!', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 获取粘贴板数据
|
|
||||||
export function getClipboardData() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (window.clipboardData) {
|
|
||||||
resolve(window.clipboardData.getData('text'));
|
|
||||||
} else if (navigator.clipboard) {
|
|
||||||
return navigator.clipboard
|
|
||||||
.readText()
|
|
||||||
.then((res) => {
|
|
||||||
resolve(res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
reject('粘贴板获取失败', err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reject('粘贴板获取失败');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 将函数返回结果转成promise形式,如果函数有返回值则根据返回值的bool类型判断是reject还是resolve,若函数无返回值默认执行resolve
|
// 将函数返回结果转成promise形式,如果函数有返回值则根据返回值的bool类型判断是reject还是resolve,若函数无返回值默认执行resolve
|
||||||
export function transformToPromise(input) {
|
export function transformToPromise(input: any) {
|
||||||
if (input instanceof Promise) return input;
|
if (input instanceof Promise) return input;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (input || input === undefined) {
|
if (input || input === undefined) {
|
||||||
resolve();
|
resolve({});
|
||||||
} else {
|
} else {
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function moveArrayItem(arr, sourceIdx, distIdx, direction) {
|
export function moveArrayItem(arr: any[], sourceIdx: number, distIdx: number, direction: 'after' | 'before') {
|
||||||
if (
|
if (
|
||||||
!Array.isArray(arr) ||
|
!Array.isArray(arr) ||
|
||||||
sourceIdx === distIdx ||
|
sourceIdx === distIdx ||
|
||||||
@ -330,9 +265,9 @@ export function moveArrayItem(arr, sourceIdx, distIdx, direction) {
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformArrayToMap(arr, key, overwrite = true) {
|
export function transformArrayToMap(arr: any[], key: string, overwrite = true) {
|
||||||
if (isEmpty(arr) || !Array.isArray(arr)) return {};
|
if (isEmpty(arr) || !Array.isArray(arr)) return {};
|
||||||
const res = {};
|
const res: any = {};
|
||||||
arr.forEach((item) => {
|
arr.forEach((item) => {
|
||||||
const curKey = item[key];
|
const curKey = item[key];
|
||||||
if (item[key] === undefined) return;
|
if (item[key] === undefined) return;
|
||||||
@ -342,7 +277,7 @@ export function transformArrayToMap(arr, key, overwrite = true) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkPropTypes(value, name, rule, componentName) {
|
export function checkPropTypes(value: any, name: string, rule: any, componentName: string) {
|
||||||
if (typeof rule === 'string') {
|
if (typeof rule === 'string') {
|
||||||
rule = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2);
|
rule = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2);
|
||||||
}
|
}
|
||||||
@ -366,15 +301,15 @@ export function checkPropTypes(value, name, rule, componentName) {
|
|||||||
return !err;
|
return !err;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformSchemaToPure(obj) {
|
export function transformSchemaToPure(obj: any) {
|
||||||
const pureObj = (obj) => {
|
const pureObj = (obj: any): any => {
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
return obj.map((item) => pureObj(item));
|
return obj.map((item) => pureObj(item));
|
||||||
} else if (typeof obj === 'object') {
|
} else if (typeof obj === 'object') {
|
||||||
// 对于undefined及null直接返回
|
// 对于undefined及null直接返回
|
||||||
if (!obj) return obj;
|
if (!obj) return obj;
|
||||||
const res = {};
|
const res: any = {};
|
||||||
forEach(obj, (val, key) => {
|
forEach(obj, (val: any, key: string) => {
|
||||||
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
||||||
res[key] = pureObj(val);
|
res[key] = pureObj(val);
|
||||||
});
|
});
|
||||||
@ -385,15 +320,15 @@ export function transformSchemaToPure(obj) {
|
|||||||
return pureObj(obj);
|
return pureObj(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformSchemaToStandard(obj) {
|
export function transformSchemaToStandard(obj: any) {
|
||||||
const standardObj = (obj) => {
|
const standardObj = (obj: any): any => {
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
return obj.map((item) => standardObj(item));
|
return obj.map((item) => standardObj(item));
|
||||||
} else if (typeof obj === 'object') {
|
} else if (typeof obj === 'object') {
|
||||||
// 对于undefined及null直接返回
|
// 对于undefined及null直接返回
|
||||||
if (!obj) return obj;
|
if (!obj) return obj;
|
||||||
const res = {};
|
const res: any = {};
|
||||||
forEach(obj, (val, key) => {
|
forEach(obj, (val: any, key: string) => {
|
||||||
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
||||||
if (isSchema(val) && key !== 'children' && obj.type !== 'JSSlot') {
|
if (isSchema(val) && key !== 'children' && obj.type !== 'JSSlot') {
|
||||||
res[key] = {
|
res[key] = {
|
||||||
@ -423,159 +358,19 @@ export function transformSchemaToStandard(obj) {
|
|||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
return standardObj(obj, false);
|
return standardObj(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformStringToFunction(str) {
|
export function transformStringToFunction(str: string) {
|
||||||
if (typeof str !== 'string') return str;
|
if (typeof str !== 'string') return str;
|
||||||
if (inSameDomain() && window.parent.__newFunc) {
|
if (inSameDomain() && (window.parent as any).__newFunc) {
|
||||||
return window.parent.__newFunc(`"use strict"; return ${str}`)();
|
return (window.parent as any).__newFunc(`"use strict"; return ${str}`)();
|
||||||
} else {
|
} else {
|
||||||
return new Function(`"use strict"; return ${str}`)();
|
return new Function(`"use strict"; return ${str}`)();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addCssTag(id, content) {
|
export function parseData(schema: any, self: any): any {
|
||||||
let styleTag = document.getElementById(id);
|
|
||||||
if (styleTag) {
|
|
||||||
styleTag.innerHTML = content;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
styleTag = document.createElement('style');
|
|
||||||
styleTag.id = id;
|
|
||||||
styleTag.class = 'luna-style';
|
|
||||||
styleTag.innerHTML = content;
|
|
||||||
document.head.appendChild(styleTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册快捷
|
|
||||||
export function registShortCuts(config, appHelper) {
|
|
||||||
const keyboardFilter = (event) => {
|
|
||||||
const eTarget = event.target || event.srcElement;
|
|
||||||
const { tagName } = eTarget;
|
|
||||||
const isInput = !!(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
|
|
||||||
const isContenteditable = !!eTarget.getAttribute('contenteditable');
|
|
||||||
if (isInput || isContenteditable) {
|
|
||||||
if (event.metaKey === true && [70, 83].includes(event.keyCode)) event.preventDefault(); // 禁止触发chrome原生的页面保存或查找
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
keymaster.filter = keyboardFilter;
|
|
||||||
|
|
||||||
const ideMessage = appHelper.utils && appHelper.utils.ideMessage;
|
|
||||||
|
|
||||||
// 复制
|
|
||||||
if (!document.copyListener) {
|
|
||||||
document.copyListener = (e) => {
|
|
||||||
if (!keyboardFilter(e) || appHelper.isCopying) return;
|
|
||||||
const schema = appHelper.schemaHelper && appHelper.schemaHelper.schemaMap[appHelper.activeKey];
|
|
||||||
if (!schema || !isSchema(schema)) return;
|
|
||||||
appHelper.isCopying = true;
|
|
||||||
const schemaStr = serialize(transformSchemaToPure(schema), {
|
|
||||||
unsafe: true,
|
|
||||||
});
|
|
||||||
setClipboardData(schemaStr)
|
|
||||||
.then(() => {
|
|
||||||
ideMessage && ideMessage('success', '当前内容已复制到剪贴板,请使用快捷键Command+v进行粘贴');
|
|
||||||
appHelper.emit('schema.copy', schemaStr, schema);
|
|
||||||
appHelper.isCopying = false;
|
|
||||||
})
|
|
||||||
.catch((errMsg) => {
|
|
||||||
ideMessage && ideMessage('error', errMsg);
|
|
||||||
appHelper.isCopying = false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
document.addEventListener('copy', document.copyListener);
|
|
||||||
if (window.parent.vscode) {
|
|
||||||
keymaster('command+c', document.copyListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 粘贴
|
|
||||||
if (!document.pasteListener) {
|
|
||||||
const doPaste = (e, text) => {
|
|
||||||
if (!keyboardFilter(e) || appHelper.isPasting) return;
|
|
||||||
const { schemaHelper } = appHelper;
|
|
||||||
let targetKey = appHelper.activeKey;
|
|
||||||
let direction = 'after';
|
|
||||||
const topKey = schemaHelper.schema && schemaHelper.schema.__ctx && schemaHelper.schema.__ctx.lunaKey;
|
|
||||||
if (!targetKey || topKey === targetKey) {
|
|
||||||
const { schemaHelper } = appHelper;
|
|
||||||
const topKey = schemaHelper.schema && schemaHelper.schema.__ctx && schemaHelper.schema.__ctx.lunaKey;
|
|
||||||
if (!topKey) return;
|
|
||||||
targetKey = topKey;
|
|
||||||
direction = 'in';
|
|
||||||
}
|
|
||||||
appHelper.isPasting = true;
|
|
||||||
const schema = parseObj(text);
|
|
||||||
if (!isSchema(schema)) {
|
|
||||||
appHelper.emit('illegalSchema.paste', text);
|
|
||||||
// ideMessage && ideMessage('error', '当前内容不是模型结构,不能粘贴进来!');
|
|
||||||
console.warn('paste schema illegal');
|
|
||||||
appHelper.isPasting = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
appHelper.emit('material.add', {
|
|
||||||
schema,
|
|
||||||
targetKey,
|
|
||||||
direction,
|
|
||||||
});
|
|
||||||
appHelper.isPasting = false;
|
|
||||||
appHelper.emit('schema.paste', schema);
|
|
||||||
};
|
|
||||||
document.pasteListener = (e) => {
|
|
||||||
const clipboardData = e.clipboardData || window.clipboardData;
|
|
||||||
const text = clipboardData && clipboardData.getData('text');
|
|
||||||
doPaste(e, text);
|
|
||||||
};
|
|
||||||
document.addEventListener('paste', document.pasteListener);
|
|
||||||
if (window.parent.vscode) {
|
|
||||||
keymaster('command+v', (e) => {
|
|
||||||
const { sendIDEMessage } = window.parent;
|
|
||||||
sendIDEMessage &&
|
|
||||||
sendIDEMessage({
|
|
||||||
action: 'readClipboard',
|
|
||||||
})
|
|
||||||
.then((text) => {
|
|
||||||
doPaste(e, text);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.warn(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(config || []).forEach((item) => {
|
|
||||||
keymaster(item.keyboard, (ev) => {
|
|
||||||
ev.preventDefault();
|
|
||||||
item.handler(ev, appHelper, keymaster);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消注册快捷
|
|
||||||
export function unRegistShortCuts(config) {
|
|
||||||
(config || []).forEach((item) => {
|
|
||||||
keymaster.unbind(item.keyboard);
|
|
||||||
});
|
|
||||||
if (window.parent.vscode) {
|
|
||||||
keymaster.unbind('command+c');
|
|
||||||
keymaster.unbind('command+v');
|
|
||||||
}
|
|
||||||
if (document.copyListener) {
|
|
||||||
document.removeEventListener('copy', document.copyListener);
|
|
||||||
delete document.copyListener;
|
|
||||||
}
|
|
||||||
if (document.pasteListener) {
|
|
||||||
document.removeEventListener('paste', document.pasteListener);
|
|
||||||
delete document.pasteListener;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseData(schema, self) {
|
|
||||||
if (isJSExpression(schema)) {
|
if (isJSExpression(schema)) {
|
||||||
return parseExpression(schema, self);
|
return parseExpression(schema, self);
|
||||||
} else if (typeof schema === 'string') {
|
} else if (typeof schema === 'string') {
|
||||||
@ -587,8 +382,8 @@ export function parseData(schema, self) {
|
|||||||
} else if (typeof schema === 'object') {
|
} else if (typeof schema === 'object') {
|
||||||
// 对于undefined及null直接返回
|
// 对于undefined及null直接返回
|
||||||
if (!schema) return schema;
|
if (!schema) return schema;
|
||||||
const res = {};
|
const res: any = {};
|
||||||
forEach(schema, (val, key) => {
|
forEach(schema, (val: any, key: string) => {
|
||||||
if (key.startsWith('__')) return;
|
if (key.startsWith('__')) return;
|
||||||
res[key] = parseData(val, self);
|
res[key] = parseData(val, self);
|
||||||
});
|
});
|
||||||
@ -598,14 +393,14 @@ export function parseData(schema, self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 全匹配{{开头,}}结尾的变量表达式,或者对象类型JSExpression,且均不支持省略this */
|
/* 全匹配{{开头,}}结尾的变量表达式,或者对象类型JSExpression,且均不支持省略this */
|
||||||
export function parseExpression(str, self) {
|
export function parseExpression(str: any, self: any) {
|
||||||
try {
|
try {
|
||||||
const contextArr = ['"use strict";', 'var __self = arguments[0];'];
|
const contextArr = ['"use strict";', 'var __self = arguments[0];'];
|
||||||
contextArr.push('return ');
|
contextArr.push('return ');
|
||||||
let tarStr;
|
let tarStr;
|
||||||
// 向前兼容,支持标准协议新格式
|
// 向前兼容,支持标准协议新格式
|
||||||
if (typeof str === 'string') {
|
if (typeof str === 'string') {
|
||||||
const regRes = str.trim().match(EXPRESSION_REG);
|
const regRes: any = str.trim().match(EXPRESSION_REG);
|
||||||
tarStr = regRes[1];
|
tarStr = regRes[1];
|
||||||
} else {
|
} else {
|
||||||
tarStr = (str.value || '').trim();
|
tarStr = (str.value || '').trim();
|
||||||
@ -613,8 +408,8 @@ export function parseExpression(str, self) {
|
|||||||
tarStr = tarStr.replace(/this(\W|$)/g, (a, b) => `__self${b}`);
|
tarStr = tarStr.replace(/this(\W|$)/g, (a, b) => `__self${b}`);
|
||||||
tarStr = contextArr.join('\n') + tarStr;
|
tarStr = contextArr.join('\n') + tarStr;
|
||||||
// 默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
// 默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
||||||
if (inSameDomain() && window.parent.__newFunc) {
|
if (inSameDomain() && (window.parent as any).__newFunc) {
|
||||||
return window.parent.__newFunc(tarStr)(self);
|
return (window.parent as any).__newFunc(tarStr)(self);
|
||||||
}
|
}
|
||||||
return new Function(tarStr)(self);
|
return new Function(tarStr)(self);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -622,3 +417,16 @@ export function parseExpression(str, self) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 首字母大写
|
||||||
|
export function capitalizeFirstLetter(word: string) {
|
||||||
|
return word[0].toUpperCase() + word.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isI18n(obj: any) {
|
||||||
|
return obj && typeof obj === 'object' && obj?.type === 'i18n';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isVariable(obj: any) {
|
||||||
|
return obj && typeof obj === 'object' && obj?.type === 'variable';
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable object-curly-newline */
|
/* eslint-disable object-curly-newline */
|
||||||
import { transformArrayToMap, isJSFunction, transformStringToFunction, clone } from './index';
|
import { transformArrayToMap, isJSFunction, transformStringToFunction, clone } from './common';
|
||||||
import { jsonp, mtop, request, get, post, bzb } from './request';
|
import { jsonp, mtop, request, get, post, bzb } from './request';
|
||||||
|
import { DataSource, DataSourceItem } from '../types';
|
||||||
|
|
||||||
const DS_STATUS = {
|
const DS_STATUS = {
|
||||||
INIT: 'init',
|
INIT: 'init',
|
||||||
@ -8,12 +9,21 @@ const DS_STATUS = {
|
|||||||
LOADED: 'loaded',
|
LOADED: 'loaded',
|
||||||
ERROR: 'error',
|
ERROR: 'error',
|
||||||
};
|
};
|
||||||
export default class DataHelper {
|
|
||||||
constructor(comp, config = {}, appHelper, parser) {
|
export class DataHelper {
|
||||||
|
host: any;
|
||||||
|
config: DataSource;
|
||||||
|
parser: any;
|
||||||
|
ajaxList: any[];
|
||||||
|
ajaxMap: any;
|
||||||
|
dataSourceMap: any;
|
||||||
|
appHelper: any;
|
||||||
|
|
||||||
|
constructor(comp: any, config: DataSource, appHelper: any, parser: any) {
|
||||||
this.host = comp;
|
this.host = comp;
|
||||||
this.config = config;
|
this.config = config || {};
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
this.ajaxList = (config && config.list) || [];
|
this.ajaxList = config?.list || [];
|
||||||
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||||
this.dataSourceMap = this.generateDataSourceMap();
|
this.dataSourceMap = this.generateDataSourceMap();
|
||||||
this.appHelper = appHelper;
|
this.appHelper = appHelper;
|
||||||
@ -21,8 +31,8 @@ export default class DataHelper {
|
|||||||
|
|
||||||
// 重置config,dataSourceMap状态会被重置;
|
// 重置config,dataSourceMap状态会被重置;
|
||||||
resetConfig(config = {}) {
|
resetConfig(config = {}) {
|
||||||
this.config = config;
|
this.config = config as DataSource;
|
||||||
this.ajaxList = (config && config.list) || [];
|
this.ajaxList = (config as DataSource)?.list || [];
|
||||||
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||||
this.dataSourceMap = this.generateDataSourceMap();
|
this.dataSourceMap = this.generateDataSourceMap();
|
||||||
return this.dataSourceMap;
|
return this.dataSourceMap;
|
||||||
@ -30,9 +40,9 @@ export default class DataHelper {
|
|||||||
|
|
||||||
// 更新config,只会更新配置,状态保存;
|
// 更新config,只会更新配置,状态保存;
|
||||||
updateConfig(config = {}) {
|
updateConfig(config = {}) {
|
||||||
this.config = config;
|
this.config = config as DataSource;
|
||||||
this.ajaxList = (config && config.list) || [];
|
this.ajaxList = (config as DataSource)?.list || [];
|
||||||
const ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
const ajaxMap: any = transformArrayToMap(this.ajaxList, 'id');
|
||||||
// 删除已经移除的接口
|
// 删除已经移除的接口
|
||||||
Object.keys(this.ajaxMap).forEach((key) => {
|
Object.keys(this.ajaxMap).forEach((key) => {
|
||||||
if (!ajaxMap[key]) {
|
if (!ajaxMap[key]) {
|
||||||
@ -45,7 +55,8 @@ export default class DataHelper {
|
|||||||
if (!this.dataSourceMap[item.id]) {
|
if (!this.dataSourceMap[item.id]) {
|
||||||
this.dataSourceMap[item.id] = {
|
this.dataSourceMap[item.id] = {
|
||||||
status: DS_STATUS.INIT,
|
status: DS_STATUS.INIT,
|
||||||
load: (...args) => {
|
load: (...args: any) => {
|
||||||
|
// @ts-ignore
|
||||||
return this.getDataSource(item.id, ...args);
|
return this.getDataSource(item.id, ...args);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -55,11 +66,12 @@ export default class DataHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generateDataSourceMap() {
|
generateDataSourceMap() {
|
||||||
const res = {};
|
const res: any = {};
|
||||||
this.ajaxList.forEach((item) => {
|
this.ajaxList.forEach((item) => {
|
||||||
res[item.id] = {
|
res[item.id] = {
|
||||||
status: DS_STATUS.INIT,
|
status: DS_STATUS.INIT,
|
||||||
load: (...args) => {
|
load: (...args: any) => {
|
||||||
|
// @ts-ignore
|
||||||
return this.getDataSource(item.id, ...args);
|
return this.getDataSource(item.id, ...args);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -67,14 +79,14 @@ export default class DataHelper {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDataSourceMap(id, data, error) {
|
updateDataSourceMap(id: string, data: any, error: any) {
|
||||||
this.dataSourceMap[id].error = error || undefined;
|
this.dataSourceMap[id].error = error || undefined;
|
||||||
this.dataSourceMap[id].data = data;
|
this.dataSourceMap[id].data = data;
|
||||||
this.dataSourceMap[id].status = error ? DS_STATUS.ERROR : DS_STATUS.LOADED;
|
this.dataSourceMap[id].status = error ? DS_STATUS.ERROR : DS_STATUS.LOADED;
|
||||||
}
|
}
|
||||||
|
|
||||||
getInitData() {
|
getInitData() {
|
||||||
const initSyncData = this.parser(this.ajaxList).filter((item) => {
|
const initSyncData = this.parser(this.ajaxList).filter((item: DataSourceItem) => {
|
||||||
if (item.isInit) {
|
if (item.isInit) {
|
||||||
this.dataSourceMap[item.id].status = DS_STATUS.LOADING;
|
this.dataSourceMap[item.id].status = DS_STATUS.LOADING;
|
||||||
return true;
|
return true;
|
||||||
@ -89,14 +101,14 @@ export default class DataHelper {
|
|||||||
}
|
}
|
||||||
if (!dataHandler || typeof dataHandler !== 'function') return res;
|
if (!dataHandler || typeof dataHandler !== 'function') return res;
|
||||||
try {
|
try {
|
||||||
return dataHandler.call(this.host, res);
|
return (dataHandler as any).call(this.host, res);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('请求数据处理函数运行出错', e);
|
console.error('请求数据处理函数运行出错', e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataSource(id, params, otherOptions, callback) {
|
getDataSource(id: string, params: any, otherOptions: any, callback: any) {
|
||||||
const req = this.parser(this.ajaxMap[id]);
|
const req = this.parser(this.ajaxMap[id]);
|
||||||
const options = req.options || {};
|
const options = req.options || {};
|
||||||
if (typeof otherOptions === 'function') {
|
if (typeof otherOptions === 'function') {
|
||||||
@ -129,7 +141,7 @@ export default class DataHelper {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
.then((res) => {
|
.then((res: any) => {
|
||||||
try {
|
try {
|
||||||
callback && callback(res && res[id]);
|
callback && callback(res && res[id]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -149,15 +161,15 @@ export default class DataHelper {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
asyncDataHandler(asyncDataList) {
|
asyncDataHandler(asyncDataList: any[]) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const allReq = [];
|
const allReq = [];
|
||||||
const doserReq = [];
|
const doserReq: {name: string; package: string; params: any }[] = [];
|
||||||
const doserList = [];
|
const doserList: string[] = [];
|
||||||
const beforeRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.beforeRequest;
|
const beforeRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.beforeRequest;
|
||||||
const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest;
|
const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest;
|
||||||
const csrfInput = document.getElementById('_csrf_token');
|
const csrfInput = document.getElementById('_csrf_token');
|
||||||
const _tb_token_ = csrfInput && csrfInput.value;
|
const _tb_token_ = (csrfInput as any)?.value;
|
||||||
asyncDataList.forEach((req) => {
|
asyncDataList.forEach((req) => {
|
||||||
const { id, type, options } = req;
|
const { id, type, options } = req;
|
||||||
if (!id || !type || type === 'legao') return;
|
if (!id || !type || type === 'legao') return;
|
||||||
@ -186,27 +198,27 @@ export default class DataHelper {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (allReq.length === 0) resolve({});
|
if (allReq.length === 0) resolve({});
|
||||||
const res = {};
|
const res: any = {};
|
||||||
// todo:
|
// todo:
|
||||||
Promise.all(
|
Promise.all(
|
||||||
allReq.map((item) => {
|
allReq.map((item: any) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const { type, id, dataHandler, options } = item;
|
const { type, id, dataHandler, options } = item;
|
||||||
const doFetch = (type, options) => {
|
const doFetch = (type: string, options: any) => {
|
||||||
this.fetchOne(type, options)
|
this.fetchOne(type, options)
|
||||||
.then((data) => {
|
.then((data: any) => {
|
||||||
if (afterRequest) {
|
if (afterRequest) {
|
||||||
this.appHelper.utils.afterRequest(item, data, undefined, (data, error) => {
|
this.appHelper.utils.afterRequest(item, data, undefined, (data: any, error: any) => {
|
||||||
fetchHandler(data, error);
|
fetchHandler(data, error);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
fetchHandler(data, undefined);
|
fetchHandler(data, undefined);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err: Error) => {
|
||||||
if (afterRequest) {
|
if (afterRequest) {
|
||||||
// 必须要这么调用,否则beforeRequest中的this会丢失
|
// 必须要这么调用,否则beforeRequest中的this会丢失
|
||||||
this.appHelper.utils.afterRequest(item, undefined, err, (data, error) => {
|
this.appHelper.utils.afterRequest(item, undefined, err, (data: any, error: any) => {
|
||||||
fetchHandler(data, error);
|
fetchHandler(data, error);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -214,13 +226,13 @@ export default class DataHelper {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const fetchHandler = (data, error) => {
|
const fetchHandler = (data: any, error: any) => {
|
||||||
if (type === 'doServer') {
|
if (type === 'doServer') {
|
||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
data = [data];
|
data = [data];
|
||||||
}
|
}
|
||||||
doserList.forEach((id, idx) => {
|
doserList.forEach((id, idx) => {
|
||||||
const req = this.ajaxMap[id];
|
const req: any = this.ajaxMap[id];
|
||||||
if (req) {
|
if (req) {
|
||||||
res[id] = this.dataHandler(id, req.dataHandler, data && data[idx], error);
|
res[id] = this.dataHandler(id, req.dataHandler, data && data[idx], error);
|
||||||
this.updateDataSourceMap(id, res[id], error);
|
this.updateDataSourceMap(id, res[id], error);
|
||||||
@ -230,7 +242,7 @@ export default class DataHelper {
|
|||||||
res[id] = this.dataHandler(id, dataHandler, data, error);
|
res[id] = this.dataHandler(id, dataHandler, data, error);
|
||||||
this.updateDataSourceMap(id, res[id], error);
|
this.updateDataSourceMap(id, res[id], error);
|
||||||
}
|
}
|
||||||
resolve();
|
resolve({});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (type === 'doServer') {
|
if (type === 'doServer') {
|
||||||
@ -243,7 +255,7 @@ export default class DataHelper {
|
|||||||
// 请求切片
|
// 请求切片
|
||||||
if (beforeRequest) {
|
if (beforeRequest) {
|
||||||
// 必须要这么调用,否则beforeRequest中的this会丢失
|
// 必须要这么调用,否则beforeRequest中的this会丢失
|
||||||
this.appHelper.utils.beforeRequest(item, clone(options), (options) => doFetch(type, options));
|
this.appHelper.utils.beforeRequest(item, clone(options), (options: any) => doFetch(type, options));
|
||||||
} else {
|
} else {
|
||||||
doFetch(type, options);
|
doFetch(type, options);
|
||||||
}
|
}
|
||||||
@ -260,7 +272,7 @@ export default class DataHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dataHandler todo:
|
// dataHandler todo:
|
||||||
dataHandler(id, dataHandler, data, error) {
|
dataHandler(id: string, dataHandler: any, data: any, error: any) {
|
||||||
if (isJSFunction(dataHandler)) {
|
if (isJSFunction(dataHandler)) {
|
||||||
dataHandler = transformStringToFunction(dataHandler.value);
|
dataHandler = transformStringToFunction(dataHandler.value);
|
||||||
}
|
}
|
||||||
@ -272,7 +284,7 @@ export default class DataHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchOne(type, options) {
|
fetchOne(type: string, options: any) {
|
||||||
// eslint-disable-next-line prefer-const
|
// eslint-disable-next-line prefer-const
|
||||||
let { uri, url, method = 'GET', headers, params, ...otherProps } = options;
|
let { uri, url, method = 'GET', headers, params, ...otherProps } = options;
|
||||||
otherProps = otherProps || {};
|
otherProps = otherProps || {};
|
||||||
3
packages/renderer-core/src/utils/index.ts
Normal file
3
packages/renderer-core/src/utils/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './common';
|
||||||
|
export * from './dataHelper';
|
||||||
|
export * from './request';
|
||||||
@ -4,7 +4,7 @@ import fetchJsonp from 'fetch-jsonp';
|
|||||||
import bzbRequest from '@ali/bzb-request';
|
import bzbRequest from '@ali/bzb-request';
|
||||||
import { serialize, buildUrl, parseUrl } from '@ali/b3-one/lib/url';
|
import { serialize, buildUrl, parseUrl } from '@ali/b3-one/lib/url';
|
||||||
|
|
||||||
export function get(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
export function get(dataAPI: any, params = {}, headers = {}, otherProps = {}) {
|
||||||
headers = {
|
headers = {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
...headers,
|
...headers,
|
||||||
@ -13,7 +13,7 @@ export function get(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
|||||||
return request(dataAPI, 'GET', null, headers, otherProps);
|
return request(dataAPI, 'GET', null, headers, otherProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function post(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
export function post(dataAPI: any, params = {}, headers: any = {}, otherProps = {}) {
|
||||||
headers = {
|
headers = {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
@ -30,7 +30,7 @@ export function post(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function request(dataAPI, method = 'GET', data, headers = {}, otherProps = {}) {
|
export function request(dataAPI: any, method = 'GET', data: any, headers = {}, otherProps: any = {}) {
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'PUT':
|
case 'PUT':
|
||||||
case 'DELETE':
|
case 'DELETE':
|
||||||
@ -112,7 +112,7 @@ export function request(dataAPI, method = 'GET', data, headers = {}, otherProps
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function jsonp(dataAPI, params = {}, otherProps = {}) {
|
export function jsonp(dataAPI: any, params = {}, otherProps = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
otherProps = {
|
otherProps = {
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
@ -133,7 +133,7 @@ export function jsonp(dataAPI, params = {}, otherProps = {}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mtop(dataAPI, params, otherProps = {}) {
|
export function mtop(dataAPI: any, params: any, otherProps: any = {}) {
|
||||||
fetchMtop.config.subDomain = otherProps.subDomain || 'm';
|
fetchMtop.config.subDomain = otherProps.subDomain || 'm';
|
||||||
return fetchMtop.request({
|
return fetchMtop.request({
|
||||||
api: dataAPI,
|
api: dataAPI,
|
||||||
@ -147,7 +147,7 @@ export function mtop(dataAPI, params, otherProps = {}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bzb(apiCode, params, otherProps = {}) {
|
export function bzb(apiCode: string, params: any, otherProps: any = {}) {
|
||||||
// 通过url参数设置小二工作台请求环境
|
// 通过url参数设置小二工作台请求环境
|
||||||
const getUrlEnv = () => {
|
const getUrlEnv = () => {
|
||||||
try {
|
try {
|
||||||
7
packages/renderer-core/tsconfig.json
Normal file
7
packages/renderer-core/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": ["./src/"],
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user