deploy-ease-platform/backend/docs/frontend-guide.md
2024-12-23 17:00:35 +08:00

869 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 工作流前端对接文档
## 一、系统架构
### 1.1 整体架构
```typescript
// 系统分层
interface SystemArchitecture {
presentation: {
views: '页面组件', // 负责页面展示和用户交互
components: '通用组件', // 可复用的UI组件
hooks: '业务钩子', // 封装业务逻辑的Hooks
};
domain: {
models: '数据模型', // 核心业务模型定义
services: '领域服务', // 业务逻辑封装
stores: '状态管理', // 全局状态管理
};
infrastructure: {
api: 'API封装', // 后端接口调用
utils: '工具函数', // 通用工具方法
constants: '常量定义', // 系统常量
};
}
```
### 1.2 核心模块
1. **工作流设计器**
- 负责工作流的可视化设计
- 节点拖拽和连线
- 属性配置面板
- 数据验证和保存
2. **表单设计器**
- 工作流表单的可视化设计
- 字段配置和验证规则
- 布局设计
- 表单预览
3. **工作流引擎**
- 工作流实例管理
- 节点状态控制
- 变量管理
- 日志记录
## 二、数据模型
### 2.1 工作流定义
```typescript
interface WorkflowDefinition {
// 基本信息
id: number; // 工作流定义ID
code: string; // 工作流编码(唯一标识)
name: string; // 工作流名称
description: string; // 工作流描述
version: number; // 版本号
status: WorkflowStatus; // 状态DRAFT/PUBLISHED/DISABLED
enabled: boolean; // 是否启用
// 节点定义
nodes: Array<{
id: number; // 节点定义ID
nodeId: string; // 节点标识(在图中的唯一标识)
name: string; // 节点名称
type: NodeType; // 节点类型START/END/TASK/GATEWAY
config: string; // 节点配置JSON字符串
description: string; // 节点描述
orderNum: number; // 排序号
}>;
// 配置数据
nodeConfig: string; // 节点关系配置JSON字符串
transitionConfig: string; // 流转配置JSON字符串
formDefinition: string; // 表单定义JSON字符串
graphDefinition: string; // 图形布局JSON字符串
}
// 节点配置示例JSON格式
interface NodeConfig {
// 开始节点配置
startNode: {
type: 'START';
name: string;
config?: Record<string, any>;
};
// 任务节点配置
taskNodes: Array<{
id: string;
type: 'TASK';
name: string;
executor?: string; // 执行器类型
config: {
// Shell执行器配置
script?: string; // 脚本内容
timeout?: number; // 超时时间
workingDir?: string; // 工作目录
// Jenkins执行器配置
jenkinsJob?: string; // Jenkins任务名
parameters?: Record<string, any>; // 构建参数
};
}>;
// 网关节点配置
gatewayNodes: Array<{
id: string;
type: 'GATEWAY';
name: string;
gatewayType: 'EXCLUSIVE' | 'PARALLEL' | 'INCLUSIVE'; // 网关类型
conditions?: Array<{
expression: string; // 条件表达式
description: string; // 条件描述
}>;
}>;
// 结束节点配置
endNode: {
type: 'END';
name: string;
config?: Record<string, any>;
};
}
// 流转配置示例
interface TransitionConfig {
transitions: Array<{
from: string; // 源节点ID
to: string; // 目标节点ID
condition?: string; // 流转条件(网关节点使用)
priority?: number; // 优先级(条件分支使用)
}>;
}
// 图形布局示例
interface GraphDefinition {
nodes: Array<{
id: string; // 节点ID
type: string; // 节点类型
x: number; // X坐标
y: number; // Y坐标
properties?: { // 节点属性
width?: number;
height?: number;
color?: string;
icon?: string;
};
}>;
edges: Array<{
source: string; // 源节点ID
target: string; // 目标节点ID
points?: Array<{ // 连线控制点
x: number;
y: number;
}>;
properties?: { // 连线属性
style?: string;
arrow?: string;
label?: string;
};
}>;
}
```
### 2.2 工作流实例
```typescript
interface WorkflowInstance {
id: number; // 实例ID
definitionId: number; // 工作流定义ID
businessKey: string; // 业务标识
status: InstanceStatus; // 状态
startTime: string; // 开始时间
endTime: string; // 结束时间
variables: string; // 工作流变量JSON字符串
error: string; // 错误信息
}
interface NodeInstance {
id: number; // 实例ID
workflowInstanceId: number; // 工作流实例ID
nodeId: string; // 节点ID
nodeType: NodeType; // 节点类型
status: NodeStatus; // 节点状态
startTime: string; // 开始时间
endTime: string; // 结束时间
input: string; // 输入参数JSON字符串
output: string; // 输出结果JSON字符串
error: string; // 错误信息
}
```
## 三、接口定义
### 3.1 工作流定义接口
```typescript
interface WorkflowDefinitionAPI {
// 基础CRUD
create: {
url: '/api/v1/workflow-definitions',
method: 'POST',
data: WorkflowDefinitionDTO,
response: Response<WorkflowDefinitionDTO>
};
update: {
url: '/api/v1/workflow-definitions/{id}',
method: 'PUT',
data: WorkflowDefinitionDTO,
response: Response<WorkflowDefinitionDTO>
};
delete: {
url: '/api/v1/workflow-definitions/{id}',
method: 'DELETE',
response: Response<void>
};
getById: {
url: '/api/v1/workflow-definitions/{id}',
method: 'GET',
response: Response<WorkflowDefinitionDTO>
};
page: {
url: '/api/v1/workflow-definitions/page',
method: 'GET',
params: PageQuery,
response: Response<Page<WorkflowDefinitionDTO>>
};
// 特殊操作
publish: {
url: '/api/v1/workflow-definitions/{id}/publish',
method: 'POST',
response: Response<WorkflowDefinitionDTO>
};
disable: {
url: '/api/v1/workflow-definitions/{id}/disable',
method: 'POST',
response: Response<WorkflowDefinitionDTO>
};
enable: {
url: '/api/v1/workflow-definitions/{id}/enable',
method: 'POST',
response: Response<WorkflowDefinitionDTO>
};
}
```
### 3.2 工作流实例接口
```typescript
interface WorkflowInstanceAPI {
// 实例操作
start: {
url: '/api/v1/workflow-instances/start',
method: 'POST',
data: {
workflowCode: string; // 工作流编码
businessKey: string; // 业务标识
variables?: Record<string, any>; // 工作流变量
},
response: Response<WorkflowInstanceDTO>
};
terminate: {
url: '/api/v1/workflow-instances/{id}/terminate',
method: 'POST',
data: {
reason?: string; // 终止原因
},
response: Response<void>
};
pause: {
url: '/api/v1/workflow-instances/{id}/pause',
method: 'POST',
response: Response<void>
};
resume: {
url: '/api/v1/workflow-instances/{id}/resume',
method: 'POST',
response: Response<void>
};
// 查询接口
getById: {
url: '/api/v1/workflow-instances/{id}',
method: 'GET',
response: Response<WorkflowInstanceDTO>
};
page: {
url: '/api/v1/workflow-instances/page',
method: 'GET',
params: PageQuery & {
status?: InstanceStatus;
startTime?: string;
endTime?: string;
keyword?: string;
},
response: Response<Page<WorkflowInstanceDTO>>
};
}
```
## 四、组件设计
### 4.1 工作流设计器
```typescript
// 1. 设计器组件
interface WorkflowDesigner {
// 属性定义
props: {
value?: WorkflowDefinition; // 工作流定义数据
readOnly?: boolean; // 是否只读
onChange?: (value: WorkflowDefinition) => void; // 数据变更回调
};
// 子组件
components: {
ToolBar: '工具栏', // 撤销、重做、缩放等操作
NodePanel: '节点面板', // 可用节点列表
Canvas: '画布', // 节点拖拽和连线
ConfigPanel: '配置面板', // 节点和连线配置
MiniMap: '小地图' // 导航缩略图
};
// 核心方法
methods: {
// 初始化设计器
initialize(definition: WorkflowDefinition): void;
// 添加节点
addNode(nodeData: NodeData): void;
// 连接节点
connect(source: string, target: string): void;
// 更新节点配置
updateNodeConfig(nodeId: string, config: any): void;
// 更新连线配置
updateEdgeConfig(edgeId: string, config: any): void;
// 验证数据
validate(): ValidationResult;
// 导出数据
exportData(): WorkflowDefinition;
};
}
// 2. 节点配置面板
interface NodeConfigPanel {
props: {
node: NodeData; // 节点数据
nodeType: NodeType; // 节点类型
onChange: (config: any) => void; // 配置变更回调
};
// 配置表单定义
forms: {
// 基础配置(所有节点都有)
BaseConfig: {
name: string; // 节点名称
description?: string; // 节点描述
};
// 任务节点配置
TaskConfig: {
executor: string; // 执行器类型
config: Record<string, any>; // 执行器配置
};
// 网关节点配置
GatewayConfig: {
type: 'EXCLUSIVE' | 'PARALLEL' | 'INCLUSIVE';
conditions?: Array<{
expression: string;
description: string;
}>;
};
};
}
// 3. 连线配置面板
interface EdgeConfigPanel {
props: {
edge: EdgeData; // 连线数据
sourceNode: NodeData; // 源节点
targetNode: NodeData; // 目标节点
onChange: (config: any) => void; // 配置变更回调
};
// 配置表单定义
forms: {
condition?: string; // 流转条件
priority?: number; // 优先级
description?: string; // 说明
};
}
```
### 4.2 表单设计器
```typescript
interface FormDesigner {
props: {
value?: FormDefinition; // 表单定义数据
onChange?: (value: FormDefinition) => void; // 数据变更回调
};
// 可用的字段类型
fieldTypes: {
input: '单行文本',
textarea: '多行文本',
number: '数字',
select: '下拉选择',
radio: '单选',
checkbox: '多选',
date: '日期',
datetime: '日期时间',
file: '文件上传'
};
// 字段属性定义
fieldProperties: {
name: string; // 字段名
label: string; // 字段标签
type: string; // 字段类型
required?: boolean; // 是否必填
defaultValue?: any; // 默认值
placeholder?: string; // 占位提示
description?: string; // 字段描述
options?: Array<{ // 选项用于select/radio/checkbox
label: string;
value: any;
}>;
validation?: Array<{ // 验证规则
type: string; // 规则类型
message: string; // 错误消息
params?: any; // 规则参数
}>;
};
}
```
## 五、状态管理
### 5.1 工作流设计器状态
```typescript
interface DesignerState {
// 画布状态
canvas: {
scale: number; // 缩放比例
position: { // 画布位置
x: number;
y: number;
};
selectedElements: { // 选中的元素
nodes: string[]; // 节点ID列表
edges: string[]; // 连线ID列表
};
};
// 历史记录
history: {
undoStack: HistoryItem[]; // 撤销栈
redoStack: HistoryItem[]; // 重做栈
canUndo: boolean; // 是否可撤销
canRedo: boolean; // 是否可重做
};
// 节点数据
nodes: Record<string, NodeData>; // 节点数据映射
edges: Record<string, EdgeData>; // 连线数据映射
// 配置面板
configPanel: {
visible: boolean; // 是否显示
type: 'node' | 'edge'; // 配置类型
elementId?: string; // 当前配置的元素ID
};
}
```
### 5.2 工作流实例状态
```typescript
interface InstanceState {
// 实例数据
instance: {
current?: WorkflowInstance; // 当前实例
nodes: NodeInstance[]; // 节点实例列表
variables: Record<string, any>; // 工作流变量
};
// 操作权限
permissions: {
canTerminate: boolean; // 是否可终止
canPause: boolean; // 是否可暂停
canResume: boolean; // 是否可恢复
};
// 日志数据
logs: {
workflow: WorkflowLog[]; // 工作流日志
nodes: Record<string, NodeLog[]>; // 节点日志
};
}
```
## 六、工作流设计器使用示例
### 6.1 基础使用
```typescript
// 1. 创建工作流
const createWorkflow = async (definition: WorkflowDefinition) => {
try {
// 验证数据
const validationResult = workflowDesigner.validate();
if (!validationResult.valid) {
message.error('工作流数据验证失败:' + validationResult.errors.join(', '));
return;
}
// 提交数据
const response = await WorkflowDefinitionAPI.create(definition);
if (response.code === 200) {
message.success('工作流创建成功');
return response.data;
} else {
message.error('工作流创建失败:' + response.message);
}
} catch (error) {
message.error('系统错误:' + error.message);
}
};
// 2. 加载工作流
const loadWorkflow = async (id: number) => {
try {
const response = await WorkflowDefinitionAPI.getById(id);
if (response.code === 200) {
// 初始化设计器
workflowDesigner.initialize(response.data);
return response.data;
} else {
message.error('加载工作流失败:' + response.message);
}
} catch (error) {
message.error('系统错误:' + error.message);
}
};
// 3. 保存工作流
const saveWorkflow = async (id: number) => {
try {
// 获取设计器数据
const definition = workflowDesigner.exportData();
// 验证数据
const validationResult = workflowDesigner.validate();
if (!validationResult.valid) {
message.error('工作流数据验证失败:' + validationResult.errors.join(', '));
return;
}
// 提交数据
const response = await WorkflowDefinitionAPI.update(id, definition);
if (response.code === 200) {
message.success('工作流保存成功');
return response.data;
} else {
message.error('工作流保存失败:' + response.message);
}
} catch (error) {
message.error('系统错误:' + error.message);
}
};
```
### 6.2 节点配置示例
```typescript
// 1. Shell节点配置
const ShellNodeConfig = {
type: 'TASK',
name: 'Shell脚本',
executor: 'SHELL',
config: {
script: '#!/bin/bash\necho "Hello World"',
timeout: 300,
workingDir: '/tmp'
}
};
// 2. Jenkins节点配置
const JenkinsNodeConfig = {
type: 'TASK',
name: 'Jenkins构建',
executor: 'JENKINS',
config: {
jenkinsJob: 'my-projectGroup-build',
parameters: {
BRANCH: 'master',
ENV: 'prod'
}
}
};
// 3. 网关节点配置
const GatewayNodeConfig = {
type: 'GATEWAY',
name: '条件分支',
gatewayType: 'EXCLUSIVE',
conditions: [
{
expression: '${status} == "SUCCESS"',
description: '执行成功'
},
{
expression: '${status} == "FAILED"',
description: '执行失败'
}
]
};
```
### 6.3 数据验证示例
```typescript
// 1. 节点配置验证
const validateNodeConfig = (node: NodeData): ValidationResult => {
const errors: string[] = [];
// 基础验证
if (!node.name) {
errors.push('节点名称不能为空');
}
// 任务节点特殊验证
if (node.type === 'TASK') {
if (!node.executor) {
errors.push('请选择执行器');
}
// Shell执行器验证
if (node.executor === 'SHELL') {
if (!node.config.script) {
errors.push('脚本内容不能为空');
}
}
// Jenkins执行器验证
if (node.executor === 'JENKINS') {
if (!node.config.jenkinsJob) {
errors.push('Jenkins任务名不能为空');
}
}
}
// 网关节点特殊验证
if (node.type === 'GATEWAY') {
if (!node.gatewayType) {
errors.push('请选择网关类型');
}
if (node.gatewayType === 'EXCLUSIVE' && (!node.conditions || node.conditions.length === 0)) {
errors.push('请配置分支条件');
}
}
return {
valid: errors.length === 0,
errors
};
};
// 2. 流程验证
const validateWorkflow = (definition: WorkflowDefinition): ValidationResult => {
const errors: string[] = [];
// 1. 基础信息验证
if (!definition.name) {
errors.push('工作流名称不能为空');
}
if (!definition.code) {
errors.push('工作流编码不能为空');
}
// 2. 节点验证
const nodes = JSON.parse(definition.nodeConfig);
// 验证开始节点
if (!nodes.startNode) {
errors.push('必须有一个开始节点');
}
// 验证结束节点
if (!nodes.endNode) {
errors.push('必须有一个结束节点');
}
// 验证任务节点
if (!nodes.taskNodes || nodes.taskNodes.length === 0) {
errors.push('至少需要一个任务节点');
}
// 3. 连线验证
const transitions = JSON.parse(definition.transitionConfig).transitions;
// 验证是否有孤立节点
const connectedNodes = new Set<string>();
transitions.forEach(t => {
connectedNodes.add(t.from);
connectedNodes.add(t.to);
});
const allNodes = [
nodes.startNode,
...nodes.taskNodes,
...(nodes.gatewayNodes || []),
nodes.endNode
];
allNodes.forEach(node => {
if (!connectedNodes.has(node.id)) {
errors.push(`节点 ${node.name}(${node.id}) 未连接`);
}
});
// 4. 验证是否有环
if (hasCircle(transitions)) {
errors.push('流程中存在循环');
}
return {
valid: errors.length === 0,
errors
};
};
```
## 七、最佳实践
### 7.1 性能优化
1. **大数据量处理**
- 使用虚拟滚动
- 分页加载数据
- 按需渲染节点
2. **状态管理**
- 合理使用缓存
- 避免频繁更新
- 使用不可变数据
3. **渲染优化**
- 组件懒加载
- 合理使用memo
- 避免不必要的重渲染
### 7.2 错误处理
1. **前端验证**
- 实时验证
- 提供错误提示
- 防止无效操作
2. **异常捕获**
- 全局错误处理
- 友好的错误提示
- 错误日志记录
3. **数据恢复**
- 自动保存
- 本地缓存
- 操作回滚
### 7.3 用户体验
1. **交互设计**
- 拖拽操作流畅
- 实时预览效果
- 快捷键支持
2. **反馈机制**
- 操作提示
- 加载状态
- 成功/失败反馈
3. **辅助功能**
- 自动布局
- 查找/替换
- 导入/导出
## 八、常见问题
### 8.1 配置相关
1. **节点配置问题**
- Q: 如何处理不同类型节点的配置?
- A: 使用统一的配置接口,通过类型区分不同的配置表单
2. **数据同步问题**
- Q: 如何保持前端展示数据与后端数据一致?
- A: 实现定期自动保存和加载机制
3. **验证问题**
- Q: 如何确保工作流数据的正确性?
- A: 实现多层次的验证机制,包括实时验证和提交验证
### 8.2 性能相关
1. **大型工作流**
- Q: 如何处理节点数量很多的工作流?
- A: 实现分区渲染和虚拟滚动
2. **频繁操作**
- Q: 如何处理频繁的拖拽和连线操作?
- A: 使用节流和防抖优化性能
3. **数据量大**
- Q: 如何处理大量的历史数据?
- A: 实现分页加载和懒加载机制
## 九、开发规范
### 9.1 代码规范
1. **命名规范**
- 组件使用大驼峰命名
- 方法使用小驼峰命名
- 常量使用大写下划线
2. **注释规范**
- 组件必须有文档注释
- 复杂逻辑需要注释
- 保持注释的及时更新
3. **类型规范**
- 使用TypeScript
- 定义清晰的接口
- 避免any类型
### 9.2 提交规范
1. **提交信息**
- feat: 新功能
- fix: 修复bug
- docs: 文档更新
- style: 代码格式
- refactor: 重构
- test: 测试
- chore: 构建过程或辅助工具的变动
2. **分支管理**
- master: 主分支
- develop: 开发分支
- feature: 功能分支
- hotfix: 紧急修复分支
### 9.3 测试规范
1. **单元测试**
- 组件测试
- 方法测试
- 工具函数测试
2. **集成测试**
- 流程测试
- 接口测试
- 兼容性测试
3. **E2E测试**
- 用户操作测试
- 场景测试
- 性能测试