Skip to content

项目完整指南

面向开发者与运维人员的综合参考:简介、快速开始、核心概念、模块详解与 FAQ。

目录

  1. 项目简介
  2. 快速开始
  3. 核心概念
  4. 技术架构
  5. 模块详解
  6. 工作流设计
  7. 节点开发指南
  8. API 开发指南
  9. 数据库设计
  10. 常见问题

1. 项目简介

1.1 什么是 Automa Agent?

Automa Agent 是一款企业级桌面自动化工具,专为企业 ERP 数据采集与流程自动化设计,主要能力包括:

  • 网页数据采集:页面 DOM 与接口数据的自动化抓取
  • 用户操作模拟:鼠标点击、键盘输入、表单填写
  • Excel 数据处理:读取、写入与批量转换
  • 可视化流程编排:拖拽式工作流设计,降低使用门槛
  • 定时调度:支持 Cron 表达式的无人值守执行
  • AI 工作台:多模型对话、BizApi 自动执行、钉钉/飞书通道、截图分析与自定义 OpenAI Provider

1.2 核心优势

特性说明
脚本驱动脚本可以直接调用网站功能,如直接请求接口
流程隔离每个流程在独立的浏览器窗口中执行,互不干扰
并发执行支持多个流程同时运行
可视化编排拖拽式工作流设计,无需编程基础
原生能力基于 Rust 的原生模块,性能优异

1.3 应用场景

  • 电商平台数据采集(生意参谋、店铺数据等)
  • ERP 系统数据同步
  • 批量表单填写
  • 定时报表下载
  • 网页自动化测试

2. 快速开始

2.1 环境要求

  • Node.js: >= 18.x
  • pnpm: >= 8.x
  • 操作系统: Windows 10+, macOS 10.15+, Linux

2.2 安装依赖

bash
# 克隆项目
git clone git@codeup.aliyun.com:6627798cd833774c93cc0790/erp_automa.git

# 进入目录
cd erp_automa

# 安装依赖
pnpm install

# 重建原生模块(如果需要)
npm rebuild better-sqlite3 --runtime=electron --target=30.5.1

2.3 开发启动

bash
# 启动开发服务器
pnpm dev

2.4 构建发布

bash
# Windows
pnpm build:win

# macOS
pnpm build:mac

# Linux
pnpm build:linux

3. 核心概念

3.1 工作流 (Workflow)

工作流是一系列自动化操作的集合,由节点连线组成。

text
┌─────────┐     ┌─────────┐     ┌─────────┐
│ 触发器  │ ──▶ │ 打开窗口 │ ──▶ │ 点击按钮 │
└─────────┘     └─────────┘     └─────────┘


┌─────────┐     ┌─────────┐     ┌─────────┐
│  结束   │ ◀── │ 保存数据 │ ◀── │ 获取数据 │
└─────────┘     └─────────┘     └─────────┘

3.2 节点 (Node)

节点是工作流的基本执行单元,每个节点完成一个特定的操作。

节点分类:

分类说明示例
触发器工作流的入口手动触发、定时触发
鼠标键盘模拟用户输入鼠标点击、键盘输入
窗口自动化浏览器窗口操作打开窗口、执行脚本
数据处理数据转换和处理JSON解析、变量设置
流程控制控制执行流程条件判断、循环
文件操作文件读写读取文件、写入文件
网络请求HTTP 请求GET请求、POST请求

3.3 变量 (Variable)

变量用于在节点之间传递数据。

javascript
// 设置变量
await setVariable('userName', '张三');

// 使用变量(在配置中)
${userName}  // 输出: 张三

// 访问对象属性
${user.name}  // 访问嵌套属性
${list[0]}    // 访问数组元素

3.4 执行上下文 (ExecutionContext)

执行上下文包含工作流运行时的所有状态信息:

typescript
interface ExecutionContext {
    workflowId: string;      // 工作流 ID
    workerId: string;        // 执行器 ID
    variables: Record<string, unknown>;  // 变量存储
    logs: ExecutionLog[];    // 执行日志
    startTime: Date;         // 开始时间
}

4. 技术架构

4.1 整体架构

text
┌────────────────────────────────────────────────────────────┐
│                     渲染进程 (Renderer)                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │ 工作流设计器  │  │   配置面板   │  │   节点组件   │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└────────────────────────────┬───────────────────────────────┘
                             │ IPC
┌────────────────────────────┴───────────────────────────────┐
│                      预加载脚本 (Preload)                    │
│                    contextBridge / ipcRenderer              │
└────────────────────────────┬───────────────────────────────┘
                             │ IPC
┌────────────────────────────┴───────────────────────────────┐
│                      主进程 (Main)                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   控制器层   │  │   引擎层     │  │   Bean 层    │      │
│  │ Controllers  │  │ WorkflowEngine│ │ DesktopNative│      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└────────────────────────────┬───────────────────────────────┘

┌────────────────────────────┴───────────────────────────────┐
│                     原生模块 (Native)                       │
│                  Rust: desktop-selection-native             │
└────────────────────────────────────────────────────────────┘

4.2 进程模型

进程职责技术
主进程应用生命周期、窗口管理、工作流执行Node.js + Electron
渲染进程UI 界面、工作流设计器Vue 3 + TypeScript
预加载脚本进程通信桥接、安全 API 暴露contextBridge
BrowserWindow自动化目标窗口Chromium

4.3 IoC 容器 (Summer)

项目使用自研的 IoC 容器框架,提供依赖注入能力:

typescript
// 定义 Bean
@Bean()
export class MyService {
    @Autowired()
    private readonly db: Db;
    
    @PreConstruct()
    async init() {
        // 初始化逻辑
    }
}

// 使用 Bean
@Bean()
export class MyController {
    @Autowired()
    private readonly myService: MyService;
}

5. 模块详解

5.1 工作流引擎 (WorkflowEngine)

位置: src/main/engine/WorkflowEngine.ts

工作流引擎负责解析和执行工作流定义。

核心方法:

typescript
class WorkflowEngine {
    // 注册节点执行器
    registerExecutor(executor: INodeExecutor): void;
    
    // 执行工作流
    async execute(workflow: WorkflowDefinition, input?: Record<string, unknown>): Promise<WorkflowExecutionResult>;
    
    // 暂停执行
    pause(): void;
    
    // 继续执行
    resume(): void;
    
    // 停止执行
    stop(): void;
}

执行流程:

  1. 查找 Trigger 节点作为入口
  2. 初始化执行上下文
  3. 循环执行节点,直到没有下一个节点
  4. 返回执行结果

5.2 节点执行器 (BaseNodeExecutor)

位置: src/main/engine/BaseNodeExecutor.ts

所有节点执行器的基类,提供通用功能。

核心 API:

方法说明
execute(node, context)执行节点(抽象方法)
success(output?, nextNodeId?)创建成功结果
failure(error)创建失败结果
getConfig<T>(node, key, defaultValue?)获取节点配置
getVariable<T>(context, name, defaultValue?)获取变量
setVariable(context, name, value)设置变量
resolveExpression(expression, context)解析变量表达式
delay(ms)延时

5.3 原生功能 (DesktopNative)

位置: src/main/beans/DesktopNative.ts

封装 Rust 原生模块,提供桌面自动化能力。

主要功能:

typescript
class DesktopNative {
    // 截图
    captureScreen(rect?: Rect): ScreenshotResult;
    captureRegion(rect: Rect): ScreenshotResult;
    
    // 鼠标操作
    mouseMove(x: number, y: number): void;
    mouseClick(button: 'left' | 'right' | 'middle'): void;
    mouseScroll(deltaX: number, deltaY: number): void;
    
    // 键盘操作
    keyboardType(text: string): void;
    keyboardPress(key: string, modifiers?: string[]): void;
    
    // 元素定位
    getElementAtPosition(x: number, y: number): AXElement;
    findElementBySelector(selector: string): AXElement[];
}

5.4 数据库 (Db)

位置: src/main/beans/Db.ts

使用 SQLite + TypeORM 进行数据持久化。

实体列表:

实体说明
WorkflowEntity工作流定义
WorkflowWorkerEntity工作流执行实例
WorkflowVariablesEntity工作流变量
WorkflowLogEntity执行日志
CapturedElementEntity捕获的元素
ScreenshotEntity截图
FolderEntity文件夹

5.5 定时任务 (CronManager)

位置: src/main/beans/CronManager.ts

管理定时触发的工作流。

typescript
class CronManager {
    // 启动定时任务管理
    async start(): Promise<void>;
    
    // 添加定时任务
    addJob(workflowId: string, cronExpression: string): void;
    
    // 移除定时任务
    removeJob(workflowId: string): void;
}

6. 工作流设计

6.1 设计器界面

工作流设计器基于 Vue Flow 实现,主要组件:

组件位置说明
WorkflowDesigner.vuesrc/renderer/pages/workflow/设计器主组件
ConfigPanel/src/renderer/pages/workflow/components/配置面板
nodes/src/renderer/pages/workflow/nodes/节点 UI 组件
edges/src/renderer/pages/workflow/edges/连线组件

6.2 节点配置

每个节点都有对应的配置表单,定义在 src/automa/types/node-config.ts

typescript
export const mouseClickFormConfig: DynamicFormI = {
    showSide: false,
    cols: 1,
    fields: [
        {
            label: '点击类型',
            key: 'clickType',
            type: 'select',
            span: 1,
            tooltip: '单击、双击或右键点击',
            options: [
                { label: '单击', value: 'single' },
                { label: '双击', value: 'double' },
                { label: '右键', value: 'right' },
            ],
        },
        // ... 更多字段
    ],
};

6.3 工作流定义

工作流以 JSON 格式存储:

typescript
interface WorkflowDefinition {
    id: string;
    name: string;
    nodes: NodeDefinition[];
    edges: EdgeDefinition[];
    variables?: Record<string, unknown>;
}

interface NodeDefinition {
    id: string;
    type: NodeKey;
    name: string;
    position: { x: number; y: number };
    config: Record<string, unknown>;
}

interface EdgeDefinition {
    id: string;
    source: string;
    target: string;
    sourceHandle?: string;
    targetHandle?: string;
}

7. 节点开发指南

7.1 开发步骤

开发新节点需要完成以下 10 个步骤

步骤 1: 添加命令定义

文件: src/automa/types/command-types.ts

typescript
export const CommandCategories = [
    {
        key: 'custom',
        label: '自定义',
        icon: 'icon-custom',
        commands: [
            {
                id: 'my-node',
                name: '我的节点',
                type: NodeKey.MY_NODE,
                icon: 'icon-custom',
                desc: '节点描述'
            }
        ],
    },
];

步骤 2: 添加节点键

文件: src/automa/types/node-config.ts

typescript
export enum NodeKey {
    // ... 其他节点
    MY_NODE = 'my-node',
}

步骤 3: 添加节点 UI 配置

文件: src/automa/types/node-config.ts

typescript
export const NodeTypesConfig: Record<NodeKey, NodeTypeConfig> = {
    // ... 其他节点
    [NodeKey.MY_NODE]: {
        label: '我的节点',
        icon: 'icon-custom',
        color: '#1890ff',
        category: 'custom',
    },
};

步骤 4: 定义表单配置

文件: src/automa/types/node-config.ts

typescript
export const myNodeFormConfig: DynamicFormI = {
    showSide: false,
    cols: 1,
    fields: [
        {
            label: '参数1',
            key: 'param1',
            type: 'text',
            span: 1,
            required: true,
            tooltip: '参数说明',
        },
    ],
};

步骤 5: 定义节点类型

文件: src/automa/types/node-types.ts

typescript
export interface MyNodeDefinition extends BaseNodeDefinition {
    type: NodeKey.MY_NODE;
    config: {
        param1: string;
        // ... 其他配置
    };
}

步骤 6: 添加到联合类型

文件: src/automa/types/node-types.ts

typescript
export type SpecificNodeDefinition =
    | TriggerNodeDefinition
    | MyNodeDefinition  // 添加这行
    // ... 其他节点
    ;

步骤 7: 添加到映射

文件: src/automa/types/node-types.ts

typescript
export interface NodeDefinitionMap {
    [NodeKey.MY_NODE]: MyNodeDefinition;
    // ... 其他节点
}

步骤 8: 创建执行器

文件: src/main/engine/executors/MyNodeExecutor.ts

typescript
import { BaseNodeExecutor } from '../BaseNodeExecutor';
import type { ExecutionContext, NodeExecutionResult } from '@automa/types/engine-types';
import type { MyNodeDefinition } from '@automa/types/node-types';
import { NodeKey } from '@automa/types/node-config';

export default class MyNodeExecutor extends BaseNodeExecutor {
    type = NodeKey.MY_NODE;

    async execute(node: MyNodeDefinition, context: ExecutionContext): Promise<NodeExecutionResult> {
        try {
            // 获取配置
            const param1 = this.getConfig<string>(node, 'param1', '');
            
            // 解析变量
            const resolvedParam1 = this.resolveExpression(param1, context);
            
            // 执行逻辑
            const result = await this.doSomething(resolvedParam1);
            
            // 保存结果到变量
            await this.setVariable(context, 'myResult', result);
            
            return this.success({ result });
        } catch (error) {
            return this.failure(`执行失败: ${error}`);
        }
    }
    
    private async doSomething(param: string): Promise<string> {
        // 实现具体逻辑
        return `处理结果: ${param}`;
    }
}

步骤 9: 创建节点 UI 组件

文件: src/renderer/pages/workflow/nodes/MyNodeNode.vue

vue
<template>
    <div class="my-node">
        <div class="node-header">
            <i class="erpfont icon-custom"></i>
            <span>{{ data.name || '我的节点' }}</span>
        </div>
        <div class="node-content">
            <div class="param-item">
                <span class="label">参数1:</span>
                <span class="value">{{ data.config?.param1 || '-' }}</span>
            </div>
        </div>
        <Handle type="target" :position="Position.Left" />
        <Handle type="source" :position="Position.Right" />
    </div>
</template>

<script setup lang="ts">
import { Handle, Position } from '@vue-flow/core';

defineProps<{
    data: {
        name?: string;
        config?: {
            param1?: string;
        };
    };
}>();
</script>

<style lang="scss" scoped>
@import './node-styles.scss';
</style>

步骤 10: 注册表单配置

文件: src/renderer/pages/workflow/components/ConfigPanel/ConfigPanel.vue

typescript
import { myNodeFormConfig } from '@automa/types/node-config';

// 在 switch 语句中添加
case NodeKey.MY_NODE:
    return myNodeFormConfig;

7.2 执行器模板

typescript
import { BaseNodeExecutor } from '../BaseNodeExecutor';
import type { ExecutionContext, NodeExecutionResult } from '@automa/types/engine-types';
import type { CustomNodeDefinition } from '@automa/types/node-types';
import { NodeKey } from '@automa/types/node-config';

export default class CustomNodeExecutor extends BaseNodeExecutor {
    type = NodeKey.CUSTOM_NODE;

    async execute(node: CustomNodeDefinition, context: ExecutionContext): Promise<NodeExecutionResult> {
        try {
            // 1. 获取配置
            const config1 = this.getConfig<string>(node, 'config1', '');
            
            // 2. 解析变量表达式
            const resolved = this.resolveExpression(config1, context);
            
            // 3. 获取上下文变量
            const existingVar = await this.getVariable<string>(context, 'someVar', '');
            
            // 4. 执行业务逻辑
            const result = await this.doBusinessLogic(resolved);
            
            // 5. 设置输出变量
            await this.setVariable(context, 'outputVar', result);
            
            // 6. 返回成功结果
            return this.success({ result });
        } catch (error) {
            // 7. 返回失败结果
            return this.failure(`执行失败: ${error}`);
        }
    }
}

8. API 开发指南

8.1 API 架构

text
Renderer (apiService.ts)
    ↓ IPC
Main (Controller)

Service / Bean

Native / Database

8.2 添加新 API

步骤 1: 定义类型

文件: src/main/controller/NativeApiTypes.ts

typescript
export interface MyApiParams {
    param1: string;
    param2: number;
}

export interface MyApiResult {
    success: boolean;
    data?: any;
    error?: string;
}

步骤 2: 实现 Controller 方法

文件: src/main/controller/NativeApiController.ts

typescript
@Bean()
export class NativeApiController {
    @Autowired()
    private readonly myService: MyService;
    
    public myApi(params: MyApiParams): ApiResultType<MyApiResult> {
        return this.wrapAsync(async () => {
            const result = await this.myService.doSomething(params);
            return { success: true, data: result };
        });
    }
}

步骤 3: 渲染进程调用

typescript
import { execNativeCommand } from '@renderer/common/apiService';

const result = await execNativeCommand('myApi', {
    param1: 'value1',
    param2: 123,
});

8.3 API 命名规范

类型命名示例
获取数据getXxxApigetWorkflowApi
执行操作xxxApiexecuteWorkflowApi
启动功能startXxxApistartRecordingApi
停止功能stopXxxApistopRecordingApi

9. 数据库设计

9.1 实体关系

text
FolderEntity (文件夹)

    └── WorkflowEntity (工作流)

            ├── WorkflowWorkerEntity (执行实例)
            │       │
            │       └── WorkflowLogEntity (执行日志)

            ├── WorkflowVariablesEntity (变量)

            ├── WorkflowCookieEntity (Cookie)

            └── WorkflowStatisticsEntity (统计)

CapturedElementEntity (捕获元素) - 独立

ScreenshotEntity (截图) - 独立

9.2 主要实体

WorkflowEntity

typescript
@Entity('workflow')
export class WorkflowEntity extends BaseEntity {
    @Column() name: string;
    @Column() folderId: string;
    @Column('simple-json') definition: WorkflowDefinition;
    @Column() enabled: boolean;
}

WorkflowWorkerEntity

typescript
@Entity('workflow_worker')
export class WorkflowWorkerEntity extends BaseEntity {
    @Column() workflowId: string;
    @Column() status: WorkerStatus;
    @Column() currentNodeId: string;
    @Column('simple-json') variables: Record<string, unknown>;
    @Column() startTime: Date;
    @Column() endTime: Date;
    @Column() error: string;
}

9.3 数据库操作

typescript
// 获取 Repository
const repo = this.db.ds.getRepository(WorkflowEntity);

// 查询
const workflow = await repo.findOne({ where: { id } });
const workflows = await repo.find({ where: { folderId } });

// 保存
await repo.save(workflow);

// 删除
await repo.delete({ id });

10. 常见问题

10.1 开发相关

Q: 如何调试主进程?

A: 在 VSCode 中使用 Electron 调试配置,或在代码中使用 console.log,日志会输出到终端。

Q: 如何调试渲染进程?

A: 使用 Chrome DevTools,在应用窗口中按 Ctrl+Shift+I (Windows) 或 Cmd+Option+I (macOS)。

Q: 原生模块编译失败?

A: 运行以下命令重新编译:

bash
npm rebuild better-sqlite3 --runtime=electron --target=30.5.1

10.2 运行相关

Q: 工作流执行失败怎么排查?

A:

  1. 查看执行日志(数据库 workflow_log 表)
  2. 查看系统日志(config/logs/automa_agent.log
  3. 检查变量值是否正确

Q: 定时任务不执行?

A:

  1. 检查 Cron 表达式是否正确
  2. 确认工作流已启用
  3. 查看 CronManager 日志

Q: 浏览器窗口无法打开?

A:

  1. 检查 URL 是否正确
  2. 检查网络连接
  3. 查看是否有安全策略阻止

10.3 部署相关

Q: 打包后应用无法启动?

A:

  1. 检查原生模块是否正确打包
  2. 检查配置文件路径
  3. 查看应用日志

Q: 如何配置开机自启?

A: 应用默认配置了开机自启,可在代码中修改:

typescript
app.setLoginItemSettings({
    openAtLogin: true,
    openAsHidden: true,
});

附录

A. 组件库文档

B. 相关资源

C. Git 规范

bash
# 查看最近提交
git --no-pager log --oneline -20

# 查看当前分支提交
git --no-pager log $(git merge-base HEAD origin/master)..HEAD --no-merges --oneline

企业级桌面 RPA 自动化平台