import { immutable, circular, action, excludedInJSON } from '../decorators'; import { config, history, LEVEL_ENUM, Vertex, MicroService, ProcessComponent, ProcessParam, ProcessReturn, ProcessProperty, ProcessInterface, vertexsMap, LogicItem, typeCheck, ActionOptions } from '..'; import processService from '../../service/process'; /** * 流程类 */ export class Process extends Vertex { /** * 概念类型 */ @immutable() public readonly level: LEVEL_ENUM = LEVEL_ENUM.process; /** * 流程 Id */ @immutable() public readonly id: string = undefined; /** * 流程名称 */ @immutable() public readonly name: string = undefined; /** * 流程标题 */ @immutable() public readonly title: string = undefined; /** * 流程描述 */ @immutable() public readonly description: string = undefined; /** * 流程组件集合 */ @immutable() public readonly childShapes: Array = []; /** * 流程输入参数 */ @immutable() public readonly params: Array = []; /** * 流程输出参数 */ @immutable() public readonly returns: Array = []; /** * 流程内置参数 */ @immutable() public readonly properties: Array = []; /** * 启动流程接口 */ @immutable() public readonly launchProcessInterface: ProcessInterface = undefined; /** * 后端服务类型 */ @immutable() public readonly serviceType: string = 'MICROSERVICE'; /** * 所属后端服务 Id */ @immutable() public readonly serviceId: string = undefined; /** * 所属后端服务 */ @circular() @immutable() public readonly service: MicroService = undefined; /** * 树组件的子节点字段 */ @excludedInJSON() @immutable() public readonly childrenField: string = 'childShapes'; /** * 树组件的子节点字段 */ @excludedInJSON() @immutable() public readonly moreChildrenFields: Array = ['params', 'returns', 'properties', 'interfaces']; /** * 已存在名称集合 */ @excludedInJSON() @immutable() public readonly existingNames: Array = []; /** * 接口列表,单纯用于 tree 展示 */ @excludedInJSON() @immutable() public readonly interfaces: Array = []; /** * @param source 需要合并的部分参数 */ constructor(source?: Partial) { super(); this.assign(source); } /** * 添加流程 */ @action('添加流程') async create(none?: void, actionOptions?: ActionOptions) { config.defaultApp?.emit('saving'); this.assign({ editing: false, loading: true }); const body = this.toJSON(); const result = await processService.add({ headers: { appId: config.defaultApp?.id, operationAction: actionOptions?.actionName || 'Process.create', operationDesc: actionOptions?.actionDesc || `添加流程"${this.name}${this.title ? `(${this.title})` : ''}"`, }, body, }); this.assign(Process.from(result, this.service)); this.service.emit('interfacesChange'); await config.defaultApp?.history.load(); config.defaultApp?.emit('saved'); return this; } /** * 删除流程 */ @action('删除流程') async delete(none?: void, actionOptions?: ActionOptions) { config.defaultApp?.emit('saving'); await processService.delete({ headers: { appId: config.defaultApp?.id, operationAction: actionOptions?.actionName || 'Process.delete', operationDesc: actionOptions?.actionDesc || `删除流程"${this.name}${this.title ? `(${this.title})` : ''}"`, }, path: { id: this.id, }, }); typeCheck.deleteByProcess(this.id); const index = this.service.processes.indexOf(this); ~index && this.service.processes.splice(index, 1); this.destroy(); this.service.emit('interfacesChange'); await config.defaultApp?.history.load(); config.defaultApp?.emit('saved'); } /** * 修改流程 */ async update(deep?: boolean, actionOptions?: ActionOptions, then?: () => Promise) { config.defaultApp?.emit('saving'); const body = this.toPlainJSON(); const result = await processService.update({ headers: { appId: config.defaultApp?.id, operationAction: actionOptions?.actionName || 'Process.update', operationDesc: actionOptions?.actionDesc || `修改流程"${this.name}${this.title ? `(${this.title})` : ''}"`, }, body, }); // 深度更新,需要同步更新 流程接口 和 UserTask 中的 完成任务接口 if (deep && result) { const { childShapes = [], launchProcessInterface } = result; const { name, path, method } = launchProcessInterface; this.launchProcessInterface.assign({ name, path, method }); this.launchProcessInterface.logic.assign({ name }); this.childShapes.forEach((childShape) => { const { type, completeTaskInterface } = childShape; if (type === 'UserTask') { const newUserTask = childShapes.find((cShape: ProcessComponent) => cShape.id === childShape.id); const { name, path, method } = newUserTask.completeTaskInterface; completeTaskInterface.assign({ name, path, method }); completeTaskInterface.logic.assign({ name }); } }); this.service.emit('interfacesChange'); } await then?.(); await config.defaultApp?.history.load(); config.defaultApp?.emit('saved'); return this; } /** * 批量修改流程组件 */ async batchComponents(body: any, actionOptions?: ActionOptions) { config.defaultApp?.emit('saving'); const result = await processService.batchComponents({ headers: { appId: config.defaultApp?.id, operationAction: actionOptions?.actionName || 'Process.batchComponents', operationDesc: `批量修改流程组件"${this.name}${this.title ? `(${this.title})` : ''}"`, }, body, }); let childShapes: Array = []; this.childShapes.forEach((processComponent) => { const isDeleted = result.delete.find((node: any) => node.id === processComponent.id); if (isDeleted) { return; } const isUpdatedComp = result.update.find((node: any) => node.id === processComponent.id); if (isUpdatedComp) { childShapes.push(ProcessComponent.from(isUpdatedComp, this)); return; } childShapes.push(processComponent); }); childShapes = childShapes.concat((result.add).map((childShape: any) => ProcessComponent.from(childShape, this))); this.assign({ childShapes }); this.service.emit('interfacesChange'); this.checkType(); await config.defaultApp?.history.load(); config.defaultApp?.emit('saved'); } /** * 流程级别的类型检查 */ async checkType() { const result = await processService.checkTypeProcess({ path: { id: this.id }, }); typeCheck.deleteByProcess(this.id); typeCheck.pushAll(result); result.forEach((typeCheckResult: any) => { if (typeCheckResult.processComponentId) { const processComponent = vertexsMap.get(typeCheckResult.processComponentId); ProcessComponent.assignTypeCheckResult(processComponent as ProcessComponent, typeCheckResult); } if (typeCheckResult.logicId) { const logicItem = vertexsMap.get(typeCheckResult.id); LogicItem.assignTypeCheckResult(logicItem as LogicItem, typeCheckResult); } }); } /** * 设置流程名称 * @param name 名称 */ @action('设置流程名称') async setName(name: string) { const oldName = this.name; this.assign({ name }); await this.update(true, { actionDesc: `设置流程"${oldName}"的名称为"${name}"`, }); } /** * 设置流程标题 * @param title 标题 */ @action('设置流程标题') async setTitle(title: string) { this.assign({ title }); await this.update(false, { actionDesc: `设置流程"${this.name}"的标题为"${title}"`, }); } /** * 设置流程描述 * @param description 描述 */ @action('设置流程描述') async setDescription(description: string) { this.assign({ description }); await this.update(false, { actionDesc: `设置流程"${this.name}"的描述为"${description}"`, }); } /** * 从后端 JSON 生成规范的 Param 对象 */ public static from(source: any, service: MicroService) { const process = new Process(source); process.assign({ service }); if (source) { const { params = [], returns = [], properties = [], childShapes = [], launchProcessInterface } = source; process.assign({ params: params.map((param: any) => ProcessParam.from(param, process)), returns: returns.map((rn: any) => ProcessReturn.from(rn, process)), properties: properties.map((property: any) => ProcessProperty.from(property, process)), childShapes: childShapes.map((childShape: ProcessComponent) => ProcessComponent.from(childShape, process)), }); if (launchProcessInterface) { const ifce = ProcessInterface.from(launchProcessInterface, process); process.assign({ launchProcessInterface: ifce, interfaces: [ifce], }); } } return process; } } export default Process;