1
This commit is contained in:
parent
3315114522
commit
1cd09a9501
@ -3,8 +3,7 @@ import type { WorkflowDefinition, WorkflowDefinitionQuery, WorkflowCategory } fr
|
||||
import type { Page } from '@/types/base';
|
||||
|
||||
// API 基础路径
|
||||
const DEFINITION_URL = '/api/v1/workflow-definitions';
|
||||
const CATEGORY_URL = '/api/v1/workflow-categories';
|
||||
const DEFINITION_URL = '/api/v1/workflow/definition';
|
||||
|
||||
/**
|
||||
* 获取工作流定义列表
|
||||
@ -19,9 +18,15 @@ export const getDefinitionDetail = (id: number) =>
|
||||
request.get<WorkflowDefinition>(`${DEFINITION_URL}/${id}`);
|
||||
|
||||
/**
|
||||
* 创建工作流定义
|
||||
* 获取已发布的工作流定义
|
||||
*/
|
||||
export const createDefinition = (data: Partial<WorkflowDefinition>) =>
|
||||
export const getPublishedDefinitions = () =>
|
||||
request.get<WorkflowDefinition[]>(`${DEFINITION_URL}/published`);
|
||||
|
||||
/**
|
||||
* 保存工作流定义(创建)
|
||||
*/
|
||||
export const saveDefinition = (data: WorkflowDefinition) =>
|
||||
request.post<WorkflowDefinition>(DEFINITION_URL, data);
|
||||
|
||||
/**
|
||||
@ -40,23 +45,28 @@ export const deleteDefinition = (id: number) =>
|
||||
* 发布工作流定义
|
||||
*/
|
||||
export const publishDefinition = (id: number) =>
|
||||
request.post<void>(`${DEFINITION_URL}/${id}/publish`);
|
||||
request.post<void>(`${DEFINITION_URL}/${id}/published`);
|
||||
|
||||
/**
|
||||
* 部署工作流定义
|
||||
*/
|
||||
export const deployDefinition = (id: number) =>
|
||||
request.post<void>(`${DEFINITION_URL}/${id}/deploy`);
|
||||
|
||||
/**
|
||||
* 启动工作流实例
|
||||
*/
|
||||
export const startWorkflowInstance = (key: string, category: string, variables?: Record<string, any>) =>
|
||||
request.post<void>(`/api/v1/workflow-instances/start`, {
|
||||
definitionKey: key,
|
||||
category,
|
||||
variables
|
||||
export const startWorkflowInstance = (processKey: string, categoryCode: string) =>
|
||||
request.post<void>(`/api/v1/workflow/instance/start`, {
|
||||
processKey,
|
||||
businessKey: `${categoryCode}_${Date.now()}`,
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取工作流分类
|
||||
*/
|
||||
export const getWorkflowCategories = () =>
|
||||
request.get<WorkflowCategory[]>(CATEGORY_URL);
|
||||
request.get<WorkflowCategory[]>(`${DEFINITION_URL}/categories`);
|
||||
|
||||
/**
|
||||
* 保存工作流图形数据
|
||||
|
||||
@ -1,21 +1,26 @@
|
||||
import { BaseResponse, BaseQuery } from '@/types/base';
|
||||
|
||||
// 复用现有的工作流定义类型,保持API兼容性
|
||||
export interface WorkflowDefinition extends BaseResponse {
|
||||
export interface WorkflowDefinition {
|
||||
id: number;
|
||||
createTime: string | null;
|
||||
createBy: string | null;
|
||||
updateTime: string | null;
|
||||
updateBy: string | null;
|
||||
version: number;
|
||||
deleted: boolean;
|
||||
extraData: any;
|
||||
name: string;
|
||||
key: string;
|
||||
description?: string;
|
||||
flowVersion?: number;
|
||||
status?: string;
|
||||
description: string;
|
||||
category: string;
|
||||
triggers: string[];
|
||||
flowVersion: number;
|
||||
bpmnXml: string | null;
|
||||
status: string;
|
||||
graph: {
|
||||
nodes: WorkflowDefinitionNode[];
|
||||
edges: any[];
|
||||
};
|
||||
formConfig: {
|
||||
formItems: any[];
|
||||
edges: WorkflowDefinitionEdge[];
|
||||
};
|
||||
formVariablesSchema?: {
|
||||
type: string;
|
||||
@ -36,17 +41,31 @@ export interface WorkflowDefinition extends BaseResponse {
|
||||
};
|
||||
};
|
||||
};
|
||||
bpmnXml?: string;
|
||||
}
|
||||
|
||||
export interface WorkflowDefinitionNode {
|
||||
id: number;
|
||||
id: string;
|
||||
nodeCode: string;
|
||||
nodeType: string;
|
||||
nodeName: string;
|
||||
uiVariables: JSON;
|
||||
panelVariables: JSON;
|
||||
localVariables: JSON;
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
configs: Record<string, any>;
|
||||
inputMapping: Record<string, any>;
|
||||
outputMapping: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface WorkflowDefinitionEdge {
|
||||
id: string;
|
||||
from: string;
|
||||
to: string;
|
||||
name: string;
|
||||
config: {
|
||||
type: string;
|
||||
};
|
||||
vertices: any[];
|
||||
}
|
||||
|
||||
export interface WorkflowDefinitionQuery extends BaseQuery {
|
||||
|
||||
@ -3,6 +3,7 @@ import { message } from 'antd';
|
||||
import * as definitionService from '../../Definition/service';
|
||||
import type { FlowNode, FlowEdge } from '../types';
|
||||
import type { WorkflowDefinition } from '../../Definition/types';
|
||||
import { NODE_DEFINITIONS } from '../nodes/definitions';
|
||||
|
||||
interface LoadedWorkflowData {
|
||||
nodes: FlowNode[];
|
||||
@ -16,40 +17,39 @@ export const useWorkflowLoad = () => {
|
||||
|
||||
// 从后端数据转换为React Flow格式
|
||||
const convertToFlowFormat = useCallback((definition: WorkflowDefinition): LoadedWorkflowData => {
|
||||
const nodes: FlowNode[] = (definition.graph?.nodes || []).map(node => ({
|
||||
const nodes: FlowNode[] = (definition.graph?.nodes || []).map(node => {
|
||||
// 根据nodeType查找对应的节点定义
|
||||
const nodeDefinition = NODE_DEFINITIONS.find(def => def.nodeType === node.nodeType);
|
||||
|
||||
return {
|
||||
id: node.id.toString(),
|
||||
type: node.nodeType,
|
||||
position: node.uiVariables?.position || { x: 100, y: 100 },
|
||||
position: node.position || { x: 100, y: 100 },
|
||||
data: {
|
||||
label: node.nodeName,
|
||||
nodeType: node.nodeType as any,
|
||||
category: 'TASK' as any, // 默认分类,可以根据nodeType推导
|
||||
icon: getNodeIcon(node.nodeType),
|
||||
color: getNodeColor(node.nodeType),
|
||||
configs: node.panelVariables || {},
|
||||
inputMapping: node.localVariables?.inputMapping || {},
|
||||
outputMapping: node.localVariables?.outputMapping || {},
|
||||
nodeDefinition: {
|
||||
nodeCode: node.nodeCode,
|
||||
nodeName: node.nodeName,
|
||||
nodeType: node.nodeType as any,
|
||||
category: 'TASK' as any,
|
||||
icon: getNodeIcon(node.nodeType),
|
||||
color: getNodeColor(node.nodeType)
|
||||
}
|
||||
category: getNodeCategory(node.nodeType) as any,
|
||||
icon: nodeDefinition?.uiConfig.style.icon || getNodeIcon(node.nodeType),
|
||||
color: nodeDefinition?.uiConfig.style.fill || getNodeColor(node.nodeType),
|
||||
configs: node.configs || {},
|
||||
inputMapping: node.inputMapping || {},
|
||||
outputMapping: node.outputMapping || {},
|
||||
// 添加节点定义引用,用于配置弹窗
|
||||
nodeDefinition
|
||||
},
|
||||
selected: node.uiVariables?.selected || false,
|
||||
dragging: node.uiVariables?.dragging || false
|
||||
}));
|
||||
selected: false,
|
||||
dragging: false
|
||||
};
|
||||
});
|
||||
|
||||
const edges: FlowEdge[] = (definition.graph?.edges || []).map(edge => ({
|
||||
id: edge.id,
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
type: edge.type || 'default',
|
||||
animated: edge.animated || true,
|
||||
data: edge.data || {
|
||||
label: '连接',
|
||||
source: edge.from, // 后端使用from字段作为source
|
||||
target: edge.to, // 后端使用to字段作为target
|
||||
type: 'default',
|
||||
animated: true,
|
||||
data: {
|
||||
label: edge.name || '连接',
|
||||
condition: {
|
||||
type: 'DEFAULT',
|
||||
priority: 0
|
||||
@ -64,32 +64,49 @@ export const useWorkflowLoad = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 根据节点类型获取图标
|
||||
// 根据节点类型获取分类
|
||||
const getNodeCategory = (nodeType: string): string => {
|
||||
const categoryMap: Record<string, string> = {
|
||||
'START_EVENT': 'EVENT',
|
||||
'END_EVENT': 'EVENT',
|
||||
'USER_TASK': 'TASK',
|
||||
'SERVICE_TASK': 'TASK',
|
||||
'SCRIPT_TASK': 'TASK',
|
||||
'DEPLOY_NODE': 'TASK',
|
||||
'JENKINS_BUILD': 'TASK',
|
||||
'GATEWAY_NODE': 'GATEWAY',
|
||||
'SUB_PROCESS': 'CONTAINER',
|
||||
'CALL_ACTIVITY': 'CONTAINER'
|
||||
};
|
||||
return categoryMap[nodeType] || 'TASK';
|
||||
};
|
||||
|
||||
// 根据节点类型获取图标(图标名称格式)
|
||||
const getNodeIcon = (nodeType: string): string => {
|
||||
const iconMap: Record<string, string> = {
|
||||
'START_EVENT': '▶️',
|
||||
'END_EVENT': '⏹️',
|
||||
'USER_TASK': '👤',
|
||||
'SERVICE_TASK': '⚙️',
|
||||
'SCRIPT_TASK': '📜',
|
||||
'DEPLOY_NODE': '🚀',
|
||||
'JENKINS_BUILD': '🔨',
|
||||
'GATEWAY_NODE': '◇',
|
||||
'SUB_PROCESS': '📦',
|
||||
'CALL_ACTIVITY': '📞'
|
||||
'START_EVENT': 'play-circle',
|
||||
'END_EVENT': 'stop-circle',
|
||||
'USER_TASK': 'user',
|
||||
'SERVICE_TASK': 'api',
|
||||
'SCRIPT_TASK': 'code',
|
||||
'DEPLOY_NODE': 'build',
|
||||
'JENKINS_BUILD': 'jenkins',
|
||||
'GATEWAY_NODE': 'gateway',
|
||||
'SUB_PROCESS': 'container',
|
||||
'CALL_ACTIVITY': 'phone'
|
||||
};
|
||||
return iconMap[nodeType] || '📋';
|
||||
return iconMap[nodeType] || 'api';
|
||||
};
|
||||
|
||||
// 根据节点类型获取颜色
|
||||
const getNodeColor = (nodeType: string): string => {
|
||||
const colorMap: Record<string, string> = {
|
||||
'START_EVENT': '#10b981',
|
||||
'END_EVENT': '#ef4444',
|
||||
'USER_TASK': '#6366f1',
|
||||
'SERVICE_TASK': '#f59e0b',
|
||||
'START_EVENT': '#52c41a',
|
||||
'END_EVENT': '#ff4d4f',
|
||||
'USER_TASK': '#722ed1',
|
||||
'SERVICE_TASK': '#fa8c16',
|
||||
'SCRIPT_TASK': '#8b5cf6',
|
||||
'DEPLOY_NODE': '#06b6d4',
|
||||
'DEPLOY_NODE': '#1890ff',
|
||||
'JENKINS_BUILD': '#f97316',
|
||||
'GATEWAY_NODE': '#84cc16',
|
||||
'SUB_PROCESS': '#ec4899',
|
||||
@ -123,18 +140,24 @@ export const useWorkflowLoad = () => {
|
||||
const createNewWorkflow = useCallback((): LoadedWorkflowData => {
|
||||
const emptyDefinition: WorkflowDefinition = {
|
||||
id: 0,
|
||||
createTime: null,
|
||||
createBy: null,
|
||||
updateTime: null,
|
||||
updateBy: null,
|
||||
version: 1,
|
||||
deleted: false,
|
||||
extraData: null,
|
||||
name: '新建工作流',
|
||||
key: `workflow_${Date.now()}`,
|
||||
description: '',
|
||||
category: 'GENERAL',
|
||||
triggers: ['MANUAL'],
|
||||
triggers: [],
|
||||
flowVersion: 1,
|
||||
bpmnXml: null,
|
||||
status: 'DRAFT',
|
||||
graph: {
|
||||
nodes: [],
|
||||
edges: []
|
||||
},
|
||||
formConfig: {
|
||||
formItems: []
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@ import { useCallback, useState } from 'react';
|
||||
import { message } from 'antd';
|
||||
import * as definitionService from '../../Definition/service';
|
||||
import type { FlowNode, FlowEdge } from '../types';
|
||||
import type { WorkflowDefinition } from '../../Definition/types';
|
||||
|
||||
interface WorkflowSaveData {
|
||||
nodes: FlowNode[];
|
||||
@ -10,6 +9,7 @@ interface WorkflowSaveData {
|
||||
workflowId?: number;
|
||||
name?: string;
|
||||
description?: string;
|
||||
definitionData?: any; // 原始工作流定义数据
|
||||
}
|
||||
|
||||
export const useWorkflowSave = () => {
|
||||
@ -25,57 +25,53 @@ export const useWorkflowSave = () => {
|
||||
// 转换节点和边数据为后端格式
|
||||
const graph = {
|
||||
nodes: data.nodes.map(node => ({
|
||||
id: parseInt(node.id) || 0,
|
||||
nodeCode: `node_${node.id}`,
|
||||
id: node.id, // 使用React Flow的节点ID
|
||||
nodeCode: node.id, // nodeCode与ID相同
|
||||
nodeType: node.data.nodeType,
|
||||
nodeName: node.data.label,
|
||||
uiVariables: {
|
||||
position: node.position,
|
||||
selected: node.selected || false,
|
||||
dragging: node.dragging || false
|
||||
position: {
|
||||
x: Math.round(node.position.x),
|
||||
y: Math.round(node.position.y)
|
||||
},
|
||||
panelVariables: node.data.configs || {},
|
||||
localVariables: {
|
||||
configs: node.data.configs || {},
|
||||
inputMapping: node.data.inputMapping || {},
|
||||
outputMapping: node.data.outputMapping || {}
|
||||
}
|
||||
})),
|
||||
edges: data.edges.map(edge => ({
|
||||
id: edge.id,
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
type: edge.type || 'default',
|
||||
animated: edge.animated || false,
|
||||
data: edge.data || {}
|
||||
from: edge.source, // 后端使用from字段
|
||||
to: edge.target, // 后端使用to字段
|
||||
name: edge.data?.label || "", // 边的名称
|
||||
config: {
|
||||
type: "sequence" // 固定为sequence类型
|
||||
},
|
||||
vertices: [] // 暂时为空数组
|
||||
}))
|
||||
};
|
||||
|
||||
const workflowData: Partial<WorkflowDefinition> = {
|
||||
name: data.name || '未命名工作流',
|
||||
description: data.description || '',
|
||||
graph,
|
||||
// 生成简单的表单配置
|
||||
formConfig: {
|
||||
formItems: []
|
||||
// 构建保存数据 - 完全模仿原始系统的逻辑
|
||||
const workflowData = data.definitionData
|
||||
? {
|
||||
// 如果有原始定义数据,展开它并覆盖 graph
|
||||
...data.definitionData,
|
||||
graph
|
||||
}
|
||||
};
|
||||
|
||||
let result: WorkflowDefinition;
|
||||
|
||||
if (data.workflowId) {
|
||||
// 更新现有工作流
|
||||
result = await definitionService.updateDefinition(data.workflowId, workflowData);
|
||||
message.success('工作流保存成功');
|
||||
} else {
|
||||
// 创建新工作流
|
||||
result = await definitionService.createDefinition({
|
||||
...workflowData,
|
||||
: {
|
||||
// 如果没有原始定义数据,创建新的工作流
|
||||
name: data.name || '新建工作流',
|
||||
description: data.description || '',
|
||||
key: `workflow_${Date.now()}`,
|
||||
category: 'GENERAL',
|
||||
triggers: ['MANUAL']
|
||||
} as any);
|
||||
message.success('工作流创建成功');
|
||||
}
|
||||
triggers: [],
|
||||
flowVersion: 1,
|
||||
bpmnXml: null,
|
||||
status: 'DRAFT',
|
||||
graph
|
||||
};
|
||||
|
||||
// 无论新建还是更新,都调用 saveDefinition (POST 请求)
|
||||
await definitionService.saveDefinition(workflowData as any);
|
||||
message.success('工作流保存成功');
|
||||
|
||||
setLastSaved(new Date());
|
||||
setHasUnsavedChanges(false);
|
||||
|
||||
@ -158,7 +158,8 @@ const WorkflowDesignInner: React.FC = () => {
|
||||
edges,
|
||||
workflowId: currentWorkflowId,
|
||||
name: workflowTitle,
|
||||
description: workflowDefinition?.description || ''
|
||||
description: workflowDefinition?.description || '',
|
||||
definitionData: workflowDefinition // 传递原始定义数据
|
||||
});
|
||||
|
||||
if (success) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user