import { immutable, excludedInJSON, circular, action } from '../decorators';
import { config, history, utils, Vertex, LEVEL_ENUM, Interface, Param, Return, Variable, vertexsMap, typeCheck, ProcessComponent, ProcessInterface, Process, ActionOptions } from '..';
import { logicService, paramService } from '../../service/logic';
import View from '../page/View';
import { ExpressionNode, LogicItem, LogicNode } from './LogicItem';
import { convert2SchemaType } from '../data/dataTypeUtils';
import { isPlainObject, throttle } from 'lodash';
/**
* 逻辑类
*/
export class Logic extends Vertex {
/**
* 概念类型
*/
@immutable()
public readonly level: LEVEL_ENUM = LEVEL_ENUM.logic;
/**
* Id
*/
@immutable()
public readonly id: string = undefined;
/**
* 名称
*/
@immutable()
public readonly name: string = undefined;
/**
* 描述
*/
@immutable()
public readonly description: string = undefined;
/**
* serviceId 或者 viewId
*/
@immutable()
public readonly moduleId: string = undefined;
/**
* 值为 view 或者 microService 或者 processComponent
*/
@immutable()
public readonly moduleType: 'view' | 'microService' | 'process' = undefined;
/**
* serviceId 或者 viewId
*/
@immutable()
public readonly serviceId: string = undefined;
/**
* 值为 view 或者 microService
*/
@immutable()
public readonly serviceType: 'view' | 'entity' | 'microService' = undefined;
/**
* 所属实体 Id
*/
@immutable()
public readonly entityId: string = undefined;
/**
* 输入参数列表
*/
@immutable()
public readonly params: Array = [];
/**
* 输出参数列表
*/
@immutable()
public readonly returns: Array = [];
/**
* 局部变量列表
*/
@immutable()
public readonly variables: Array = [];
/**
* 逻辑体
*/
@immutable()
public readonly body: Array = [];
/**
* 画布
*/
@immutable()
public readonly playgroundId: string = undefined;
/**
* 画布
*/
@immutable()
public readonly playground: Array = [];
/**
* 接口
*/
@circular()
@immutable()
public readonly interface: Interface = undefined;
/**
* 视图
*/
@circular()
@immutable()
public readonly view: View = undefined;
/**
* 流程组件
*/
@circular()
@immutable()
public readonly processComponent: ProcessComponent = undefined;
/**
* 流程组件
*/
@circular()
@immutable()
public readonly process: Process = undefined;
/**
* 正在请求的 Promise
* 前端 UI 状态
*/
@excludedInJSON()
public contentPromise: Promise = undefined;
/**
* 树组件的子节点字段
*/
@immutable()
public readonly moreChildrenFields: Array = ['params', 'returns', 'variables'];
/**
* @param source 需要合并的部分参数
*/
constructor(source?: Partial) {
super();
source && this.assign(source);
this.on('change', throttle(
this._onChange.bind(this),
config.throttleWait,
{ leading: true, trailing: true },
));
}
/**
* 添加逻辑
*/
@action('添加逻辑')
async create(none?: void, actionOptions?: ActionOptions) {
config.defaultApp?.emit('saving');
const body = this.toJSON();
// body.params.forEach((param: any) => convert2SchemaType(param.schema));
// body.returns.forEach((ret: any) => convert2SchemaType(ret.schema));
// body.variables.forEach((variable: any) => convert2SchemaType(variable.schema));
utils.logger.debug('添加逻辑', body);
const result: Logic = await logicService.create({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Logic.create',
operationDesc: actionOptions?.actionDesc || `添加逻辑"${this.name}"`,
},
body,
});
this.deepPick(result, ['id']);
this.pick(result, ['playgroundId']);
this.assign({ body: result.body.map((logicNode) => LogicNode.from(logicNode, this, null)) });
this.params.forEach((param) => {
param.assign({ code: `ID_${param.id}` });
});
this.returns.forEach((returns) => {
returns.assign({ code: `ID_${returns.id}` });
});
this.variables.forEach((variable) => {
variable.assign({ code: `ID_${variable.id}` });
});
if (this.view) {
this.view.page.service.emit('pageTreeChange');
this.emit('change');
}
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
return this;
}
/**
* 删除逻辑
*/
@action('删除逻辑')
async delete(none?: void, actionOptions?: ActionOptions) {
config.defaultApp?.emit('saving');
if (this.id) {
const body = this.toPlainJSON();
if (this.view) {
body.moduleId = this.view.id;
body.moduleType = 'view';
} else {
body.moduleId = this.interface.service.id;
body.moduleType = 'microService';
}
try {
await logicService.delete({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Logic.delete',
operationDesc: actionOptions?.actionDesc || `删除逻辑"${this.name}"`,
},
body,
});
} catch (err) {
await config.defaultApp?.history.load();
throw err;
}
if (this.view) {
const { logics } = this.view.$def;
const pos = logics.indexOf(this);
if (pos >= 0)
logics.splice(pos, 1);
}
[...this.body, ...this.playground].forEach((node) => {
typeCheck.delete(node.id);
});
// const index =
this.destroy();
if (this.view) {
this.view.page.service.emit('pageTreeChange');
this.emit('change');
}
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
} else {
if (this.view) {
const { logics } = this.view.$def;
const pos = logics.indexOf(this);
if (pos >= 0)
logics.splice(pos, 1);
}
}
}
/**
* 修改逻辑
*/
async update(none?: void, actionOptions?: ActionOptions, then?: () => Promise) {
config.defaultApp?.emit('saving');
const body = this.toPlainJSON();
utils.logger.debug('修改逻辑', body);
const result = await logicService.update({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Logic.update',
operationDesc: actionOptions?.actionDesc || `修改逻辑"${this.name}"`,
},
body,
});
await then?.();
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
return this;
}
/**
* 设置逻辑名称
*/
@action('设置逻辑名称')
async setName(name: string) {
const oldName = this.name;
this.assign({ name });
await this.update(undefined, {
actionDesc: `设置逻辑"${oldName}"的名称为"${name}"`,
});
if (this.view) {
this.view.page.service.emit('pageTreeChange');
this.emit('change');
}
return this;
}
/**
* 设置逻辑描述
*/
@action('设置逻辑描述')
async setDescription(description: string) {
this.assign({ description });
await this.update(undefined, {
actionDesc: `设置逻辑"${this.name}"的描述为"${description}"`,
});
if (this.view) {
this.view.page.service.emit('pageTreeChange');
this.emit('change');
}
return this;
}
_onChange() {
this.view && this.view.emit('change');
}
/**
* 按当前 id 加载逻辑数据
*/
async load() {
if (!this.id)
return;
// 如果有正在进行的 Promise,则直接返回它
if (this.contentPromise)
return this.contentPromise;
return this.contentPromise = (async () => {
try {
const result = await logicService.loadDetail({
query: {
moduleId: this.moduleId,
moduleType: this.moduleType,
id: this.id,
},
});
const newLogic = Logic.from(result, this.interface || this.view || this.processComponent, this);
this.assign(newLogic);
} catch (err) {}
return this;
})().finally(() => this.contentPromise = undefined);
}
isContentLoaded() {
return !!this.body.length;
}
/**
* 批量添加参数
*/
async addParamList(params: Array) {
const body = params.map((param) => {
param = param.toJSON();
convert2SchemaType(param.schema);
return param;
});
const results = await paramService.addList({
body,
});
params.forEach((param, index) => param.pick(results[index], ['id']));
this.params.push(...params);
}
/**
* 添加逻辑节点
* @param item
*/
addItem(item: LogicItem, actionOptions?: ActionOptions) {
if (isPlainObject(item)) {
item = LogicItem.from(item, this, null);
}
// if (!this.children.includes(child)) {
// const index = child._posIndex === undefined ? this.children.length : child._posIndex;
// this.children.splice(index, 0, child);
// }
const parent = item.parentAttr ? vertexsMap.get(item.parentId) as LogicItem : undefined;
return item.create({
parent,
parentId: item.parentId,
parentAttr: item.parentAttr,
_posIndex: item._posIndex,
cache: false,
}, actionOptions);
}
/**
* 删除逻辑节点
* @param item
*/
removeItem(item: LogicItem, actionOptions?: ActionOptions) {
if (isPlainObject(item)) {
item = vertexsMap.get(item.id) as LogicItem;
}
return item.delete(undefined, actionOptions);
}
/**
*
* @param type
* @returns
*/
public findLogicItemByType(type: string) {
let result: any;
utils.traverse((current) => {
if ((current.node as any).type === type)
return result = current.node;
}, { node: this }, {
mode: 'anyObject',
excludedKeySet: this.JSON_EXCLUDED_KEYS,
});
return result as LogicItem;
}
/**
* 从后端 JSON 生成规范的 Logic 对象
*/
public static from(source: any, parent: Interface | View | ProcessComponent | ProcessInterface, currentLogic?: Logic) {
const logic = new Logic(source);
currentLogic = currentLogic || logic;
logic.assign({ params: logic.params.map((param) => Param.from(param, currentLogic)) });
logic.assign({ returns: logic.returns.map((ret) => Return.from(ret, currentLogic)) });
logic.assign({ variables: logic.variables.map((variable) => Variable.from(variable, currentLogic)) });
logic.body.forEach((node, index) => {
if (node.level === LEVEL_ENUM.logicNode)
node = logic.body[index] = LogicNode.from(node, currentLogic, null);
else if (node.level === LEVEL_ENUM.expressionNode)
node = logic.body[index] = ExpressionNode.from(node, currentLogic, null);
});
logic.playground.forEach((node, index) => {
if (node.level === LEVEL_ENUM.logicNode)
node = logic.playground[index] = LogicNode.from(node, currentLogic, null);
else if (node.level === LEVEL_ENUM.expressionNode)
node = logic.playground[index] = ExpressionNode.from(node, currentLogic, null);
});
if (parent instanceof Interface)
logic.assign({
interface: parent,
moduleType: 'microService',
moduleId: parent.id,
});
else if (parent instanceof View)
logic.assign({
view: parent,
moduleType: 'view',
moduleId: parent.id,
});
else if (parent instanceof ProcessComponent)
logic.assign({
processComponent: parent,
moduleType: 'process',
moduleId: parent.id,
});
else if (parent instanceof ProcessInterface) {
logic.assign({
process: parent,
});
}
return logic;
}
}
export default Logic;