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;