# Plugin-Workflow 开发文档

> 审批王插件 - 提供完整的流程审批管理系统

## 目录

1. [插件概述](#插件概述)
2. [核心概念](#核心概念)
3. [文件结构](#文件结构)
4. [核心对象](#核心对象)
5. [队列系统](#队列系统)
6. [API接口](#api接口)
7. [触发器](#触发器)
8. [开发指南](#开发指南)

---

## 插件概述

### 基本信息

- **包名**: `@steedos-labs/plugin-workflow`
- **版本**: 3.0.12
- **许可证**: MIT
- **主入口**: `package.service.js`

### 功能描述

审批王是一款创新的流程自动化解决方案，提供:

1. **流程设计器**: 可视化流程设计工具
2. **审批单管理**: 完整的审批单生命周期管理
3. **表单设计**: 动态表单设计和渲染
4. **实例同步**: 审批单与业务对象的双向同步
5. **Webhook集成**: 支持外部系统集成
6. **历史记录**: 完整的审批历史追踪

### 许可证要求

```yaml
license:
  - platform-professional
  - platform-enterprise
```

需要专业版或企业版许可证才能使用。

### 技术栈

- JavaScript/Node.js
- Moleculer微服务
- MongoDB
- Redis队列
- AMIS表单引擎

### 核心依赖

```json
{
  "graphql-parse-resolve-info": "^4.12.3",
  "he": "^1.2.0",
  "lodash": "^4.17.21",
  "node-schedule": "^2.0.0",
  "formidable": "^2.1.5",
  "jszip": "^3.10.1"
}
```

---

## 核心概念

### 1. 流程 (Flow)

流程是审批过程的模板定义，包含:
- 流程步骤 (Steps)
- 审批人规则
- 字段权限
- 触发条件

### 2. 审批单 (Instance)

审批单是流程的具体执行实例，包含:
- 表单数据
- 当前状态
- 审批历史
- 附件信息

### 3. 审批任务 (Instance Task)

每个审批步骤对应一个或多个审批任务，分配给具体审批人。

### 4. 表单 (Form)

表单定义审批单的数据结构和UI布局:
- 使用AMIS Schema定义
- 支持动态字段
- 支持复杂布局

### 5. 对象流程关联 (Object Workflow)

将流程与业务对象关联，实现:
- 从对象发起流程
- 审批单数据同步到对象
- 对象变更触发流程

---

## 文件结构

```
plugin-workflow/
├── package.json              # NPM包配置
├── package.service.js        # Moleculer服务入口
├── package.service.yml       # 服务元数据
├── README.md                # 说明文档
│
├── src/                     # 源代码
│   ├── instance_record_queue.js    # 实例记录队列
│   ├── webhook_queue.js            # Webhook队列
│   ├── rests/                      # REST API
│   │   ├── updateFormFields.js
│   │   ├── getInstanceServiceSchema.js
│   │   ├── flow_copy.js
│   │   └── ...
│   ├── schema/                     # Schema定义
│   │   ├── steedos_form_schema.amis.js
│   │   ├── instance_form_schema.amis.js
│   │   └── ...
│   └── util/                       # 工具函数
│
├── main/default/           # Steedos元数据
│   ├── objects/            # 对象定义
│   │   ├── instances.object.yml           # 审批单
│   │   ├── instance_tasks/                # 审批任务
│   │   ├── forms/                         # 表单
│   │   ├── flows/                         # 流程
│   │   ├── object_workflows.object.yml    # 对象流程关联
│   │   └── ...
│   ├── triggers/           # 触发器
│   │   ├── instances.trigger.js
│   │   ├── instance_tasks.trigger.js
│   │   ├── flows.trigger.js
│   │   └── amis_form_design.trigger.js
│   ├── routes/             # 路由
│   │   ├── api_workflow_redirect.router.js
│   │   ├── api_workflow_approve_save.router.js
│   │   └── ...
│   ├── applications/       # 应用
│   ├── tabs/               # 选项卡
│   ├── translations/       # 国际化
│   └── ...
│
└── public/                # 静态资源
    ├── applications/      # 流程设计器应用
    │   └── designer/
    └── workflow/         # 工作流相关资源
```

---

## 核心对象

### 1. flows (流程)

流程定义对象。

**核心字段**:
```yaml
name:              # 流程名称
  type: text
  required: true

form:              # 关联表单
  type: lookup
  reference_to: forms

is_valid:          # 是否有效
  type: boolean

current_version:   # 当前版本
  type: number

steps:             # 流程步骤
  type: grid
  # 步骤定义包括审批人、字段权限等

perms:             # 流程权限
  type: grid
  # 可以发起流程的用户/组织
```

**文件位置**: `main/default/objects/flows/`

---

### 2. forms (表单)

表单定义对象。

**核心字段**:
```yaml
name:              # 表单名称
  type: text

amis_schema:       # AMIS表单Schema
  type: object
  # JSON格式的AMIS配置

fields:            # 表单字段
  type: grid
  # 字段定义数组

current:           # 是否当前版本
  type: boolean
```

**AMIS Schema结构**:
```javascript
{
  type: "page",
  body: [
    {
      type: "form",
      body: [
        {
          type: "input-text",
          name: "field_name",
          label: "字段标签",
          required: true
        }
      ]
    }
  ]
}
```

**文件位置**: `main/default/objects/forms/`

---

### 3. instances (审批单)

审批单实例对象。

**核心字段**:
```yaml
name:              # 审批单标题
  type: text

applicant:         # 申请人
  type: lookup
  reference_to: users

applicant_name:    # 申请人姓名
  type: text

applicant_organization: # 申请人部门
  type: lookup
  reference_to: organizations

flow:              # 关联流程
  type: lookup
  reference_to: flows

flow_version:      # 流程版本
  type: number

form:              # 关联表单
  type: lookup
  reference_to: forms

form_version:      # 表单版本
  type: number

state:             # 审批状态
  type: select
  options:
    - draft        # 草稿
    - pending      # 进行中
    - completed    # 已完成
    - canceled     # 已取消

values:            # 表单数据
  type: object
  # JSON格式存储表单填写的值

traces:            # 审批历史
  type: grid
  # 审批步骤记录

attachments:       # 附件
  type: grid

cc:                # 抄送人
  type: lookup
  multiple: true
  reference_to: users

inbox_users:       # 待办人
  type: lookup
  multiple: true
  reference_to: users

outbox_users:      # 已办人
  type: lookup
  multiple: true
  reference_to: users

record_ids:        # 关联业务对象记录
  type: grid
  # [{o: "objectName", ids: ["recordId1", "recordId2"]}]
```

**文件位置**: `main/default/objects/instances/`

---

### 4. instance_tasks (审批任务)

审批任务对象。

**核心字段**:
```yaml
instance:          # 关联审批单
  type: master_detail
  reference_to: instances

name:              # 任务名称
  type: text

assignee:          # 审批人
  type: lookup
  reference_to: users

due_date:          # 截止日期
  type: date

state:             # 任务状态
  type: select
  options:
    - pending      # 待处理
    - approved     # 已批准
    - rejected     # 已拒绝

description:       # 审批意见
  type: textarea

is_read:           # 是否已读
  type: boolean
```

**文件位置**: `main/default/objects/instance_tasks/`

---

### 5. object_workflows (对象流程关联)

对象与流程的关联配置。

**核心字段**:
```yaml
object_name:       # 对象API名称
  type: text

flow_id:           # 关联流程
  type: lookup
  reference_to: flows

field_map:         # 字段映射
  type: grid
  # [{workflow_field: "申请金额", object_field: "amount"}]

sync_direction:    # 同步方向
  type: select
  options:
    - "both"       # 双向同步
    - "obj_to_ins" # 对象到实例
    - "ins_to_obj" # 实例到对象

sync_type:         # 同步类型
  type: select
  options:
    - "every_step" # 每步同步
    - "end_step"   # 结束时同步
```

**文件位置**: `main/default/objects/object_workflows.object.yml`

---

## 队列系统

### 1. Instance Record Queue (实例记录队列)

**文件**: `src/instance_record_queue.js`

**功能**: 将审批单数据同步到业务对象记录。

**队列表**: `instance_record_queue`

**队列记录结构**:
```javascript
{
  instance_id: "审批单ID",
  record_id: "业务对象记录ID",
  object_name: "业务对象名称",
  operation: "insert|update|delete",
  data: { /* 字段映射后的数据 */ },
  state: "pending|processing|completed|failed",
  error: "错误信息",
  created: "创建时间",
  modified: "修改时间"
}
```

**处理流程**:

1. **触发条件**:
   - 审批单状态变更
   - 审批单字段更新
   - 对象流程关联配置的同步规则

2. **数据映射**:
   ```javascript
   const getObjectFields = async function (objectApiName) {
       return await objectql.getObject(objectApiName).getFields()
   }
   
   // 根据field_map映射数据
   const mappedData = {};
   for (const mapping of fieldMappings) {
       mappedData[mapping.object_field] = 
           instanceValues[mapping.workflow_field];
   }
   ```

3. **执行同步**:
   ```javascript
   const objectInsert = async function (objectApiName, data) {
       return await objectql.getObject(objectApiName).insert(data)
   }
   
   const objectUpdate = async function (objectApiName, id, data) {
       return await objectql.getObject(objectApiName).update(id, data);
   }
   ```

4. **公式和汇总字段更新**:
   ```javascript
   var runQuoted = async function (objectName, recordId) {
       await objectql.runQuotedByObjectFieldFormulas(objectName, recordId);
       await objectql.runQuotedByObjectFieldSummaries(objectName, recordId);
   }
   ```

**定时任务配置**:
```bash
# .env文件
STEEDOS_CRON_ENABLED=true
STEEDOS_CRON_INSTANCERECORDQUEUE_INTERVAL=1000  # 毫秒
```

---

### 2. Webhook Queue (Webhook队列)

**文件**: `src/webhook_queue.js`

**功能**: 向外部系统发送审批单事件通知。

**使用场景**:
- 审批完成后通知第三方系统
- 实时推送审批状态变更
- 集成外部业务系统

**Webhook配置**:
在流程或对象流程中配置:
```yaml
webhooks:
  - url: "https://example.com/api/webhook"
    method: "POST"
    trigger_when: "completed"  # draft|pending|completed|rejected
    headers:
      Authorization: "Bearer token"
```

**推送数据格式**:
```javascript
{
  event: "instance.completed",
  instance_id: "审批单ID",
  instance: {
    name: "审批单标题",
    state: "completed",
    applicant: "申请人ID",
    values: { /* 表单数据 */ }
  },
  timestamp: "2026-01-09T06:00:00Z"
}
```

---

## API接口

### 1. 流程相关API

#### 复制流程

**路由**: `POST /api/workflow/flows/copy`

**文件**: `src/rests/flow_copy.js`

**功能**: 复制现有流程创建新版本或新流程。

**请求参数**:
```javascript
{
  flowId: "源流程ID",
  name: "新流程名称",
  copyVersion: true  // 是否作为新版本
}
```

---

#### 获取流程权限

**路由**: `GET /api/workflow/flows/:flowId/permissions`

**文件**: `main/default/routes/api_flow_permission.router.js`

**功能**: 检查当前用户是否有权限发起该流程。

---

### 2. 审批单相关API

#### 提交审批

**路由**: `POST /api/workflow/instances/:instanceId/submit`

**文件**: `main/default/routes/api_workflow_approve_save.router.js`

**功能**: 提交审批意见(批准/拒绝)。

**请求参数**:
```javascript
{
  action: "approve|reject",
  description: "审批意见",
  next_steps: [{
    step: "步骤ID",
    users: ["用户ID1", "用户ID2"]
  }]
}
```

---

#### 传阅/抄送

**路由**: `POST /api/workflow/instances/:instanceId/cc`

**文件**: `main/default/routes/api_cc_submit.router.js`

**功能**: 提交传阅意见。

---

#### 批量删除审批单

**路由**: `POST /api/workflow/instances/batch-remove`

**文件**: `src/rests/api_workflow_instance_batch_remove.js`

**功能**: 批量删除审批单。

---

#### 导出审批单

**路由**: `GET /api/workflow/instances/:instanceId/export`

**文件**: `main/default/routes/api_workflow_export.router.js`

**功能**: 导出审批单为PDF或其他格式。

---

### 3. 表单相关API

#### 更新表单字段

**路由**: `POST /api/workflow/forms/:formId/updateFields`

**文件**: `src/rests/updateFormFields.js`

**功能**: 动态更新表单字段定义。

**请求参数**:
```javascript
{
  fields: [
    {
      code: "field_name",
      name: "字段标签",
      type: "text",
      required: true
    }
  ]
}
```

---

#### 获取实例Service Schema

**路由**: `GET /api/workflow/instances/:instanceId/service-schema`

**文件**: `src/rests/getInstanceServiceSchema.js`

**功能**: 获取审批单的AMIS Service Schema用于前端渲染。

---

### 4. 文件相关API

**路由**: `/api/workflow/files/*`

**文件**: `main/default/routes/api_files.router.js`

**功能**: 处理审批单附件的上传和下载。

---

## 触发器

### 1. instances.trigger.js

**文件**: `main/default/triggers/instances.trigger.js`

**监听对象**: `instances`

**功能**:
- 审批单状态变更时触发队列同步
- 更新待办人/已办人列表
- 发送通知

**示例**:
```javascript
module.exports = {
    listenTo: 'instances',
    
    afterUpdate: async function() {
        const { doc, previousDoc } = this;
        
        // 状态变更
        if (doc.state !== previousDoc.state) {
            // 触发同步队列
            if (doc.state === 'completed') {
                await addToInstanceRecordQueue(doc._id);
            }
            
            // 发送通知
            await sendNotification(doc);
        }
    }
};
```

---

### 2. instance_tasks.trigger.js

**文件**: `main/default/triggers/instance_tasks.trigger.js`

**监听对象**: `instance_tasks`

**功能**:
- 审批任务创建时发送通知
- 任务完成时更新审批单状态

---

### 3. flows.trigger.js

**文件**: `main/default/triggers/flows.trigger.js`

**监听对象**: `flows`

**功能**:
- 流程版本管理
- 流程启用/停用处理

**示例**:
```javascript
module.exports = {
    listenTo: 'flows',
    
    beforeUpdate: async function() {
        const { doc } = this;
        
        // 停用流程时检查是否有进行中的审批单
        if (doc.is_valid === false) {
            const pendingInstances = await objectql
                .getObject('instances')
                .find({
                    filters: [
                        ['flow', '=', doc._id],
                        ['state', '=', 'pending']
                    ]
                });
            
            if (pendingInstances.length > 0) {
                throw new Error('存在进行中的审批单，无法停用流程');
            }
        }
    }
};
```

---

### 4. amis_form_design.trigger.js

**文件**: `main/default/triggers/amis_form_design.trigger.js`

**监听对象**: `forms`

**功能**:
- AMIS表单Schema验证
- 表单字段同步
- 表单版本管理

**重要**: 这是一个大型触发器(约19000行代码)，包含复杂的表单处理逻辑。

---

## 开发指南

### 本地开发

#### 1. 安装依赖

```bash
cd steedos-packages/plugin-workflow
yarn install
```

#### 2. 启动开发环境

```bash
# 在项目根目录
cd ../..

# 启动数据库
yarn start:db

# 启动服务
yarn start
```

#### 3. 访问流程设计器

打开浏览器访问:
```
http://localhost:5100/app/admin/workflow/designer
```

---

### 添加新流程步骤类型

#### 1. 定义步骤类型

在流程步骤配置中添加新类型:

```javascript
const stepTypes = {
  approval: {
    label: "审批",
    icon: "approval",
    handler: approvalStepHandler
  },
  condition: {
    label: "条件",
    icon: "condition", 
    handler: conditionStepHandler
  },
  custom_new_type: {  // 新步骤类型
    label: "自定义步骤",
    icon: "custom",
    handler: customStepHandler
  }
};
```

#### 2. 实现步骤处理器

```javascript
async function customStepHandler(instance, step, context) {
  // 执行自定义逻辑
  const result = await performCustomAction(instance, step);
  
  // 返回下一步骤
  return {
    nextStep: step.next_step_id,
    data: result
  };
}
```

---

### 自定义审批规则

#### 1. 创建自定义审批人规则

```javascript
// 在流程配置中添加自定义规则
const approverRules = {
  manager: {
    label: "直属主管",
    handler: async (applicant) => {
      const user = await getUser(applicant);
      return user.manager_id;
    }
  },
  custom_rule: {  // 新规则
    label: "自定义规则",
    handler: async (applicant, context) => {
      // 实现自定义逻辑
      // 返回审批人ID数组
      return ["userId1", "userId2"];
    }
  }
};
```

---

### 扩展字段映射

#### 1. 添加自定义字段映射函数

```javascript
const fieldMappers = {
  // 简单映射
  simple: (value) => value,
  
  // 日期格式转换
  dateFormat: (value, format) => {
    return moment(value).format(format);
  },
  
  // 自定义映射
  custom: (value, context) => {
    // 实现转换逻辑
    return transformedValue;
  }
};
```

#### 2. 在对象流程关联中使用

```yaml
field_map:
  - workflow_field: "申请日期"
    object_field: "apply_date"
    mapper: "dateFormat"
    mapper_params: "YYYY-MM-DD"
```

---

### 调试技巧

#### 1. 查看队列状态

```javascript
// 在MongoDB中查询队列
db.instance_record_queue.find({
  state: "failed"
}).sort({ modified: -1 });
```

#### 2. 手动触发队列处理

```javascript
// 通过Moleculer调用
const result = await broker.call('workflow.processQueue', {
  queueId: "队列记录ID"
});
```

#### 3. 调试审批单同步

```bash
# 启用详细日志
STEEDOS_LOG_LEVEL=debug yarn start

# 查看同步日志
tail -f logs/workflow.log | grep "instance_record_queue"
```

---

## 注意事项

### 1. 性能优化

- 大量审批单时考虑分页加载
- 队列处理使用批量操作
- 定期清理已完成的队列记录

### 2. 数据一致性

- 使用事务处理关键操作
- 队列失败时需要重试机制
- 记录详细的错误日志

### 3. 安全性

- 验证用户权限
- 防止SQL注入和XSS攻击
- 敏感数据加密存储

### 4. 兼容性

- 确保与Steedos平台版本兼容
- 测试不同浏览器的兼容性
- 向后兼容旧版本流程数据

---

**文档版本**: 1.0
**最后更新**: 2026-01-09
