docs: 添加审批与消息模块架构文档

This commit is contained in:
root
2026-02-28 22:57:48 +08:00
parent 5bbed98cf0
commit 254f0073dc
+548
View File
@@ -0,0 +1,548 @@
# 审批与消息模块架构文档
**版本**: 1.0.0
**更新时间**: 2026-02-28
**状态**: 设计中
---
## 📋 概述
系统采用**模块化设计**,审批模块和消息模块是两个独立但可联合使用的核心模块。
### 设计原则
1. **模块独立**:各模块可独立部署和使用
2. **松耦合**:模块间通过接口通信,不直接依赖
3. **可扩展**:支持新增业务场景(如请假、采购、报销等)
4. **统一协议**:所有业务场景遵循相同的审批和消息协议
---
## 🏗️ 模块架构
```
┌─────────────────────────────────────────────────────────────┐
│ 业务场景层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 出差审批 │ │ 请假审批 │ │ 采购审批 │ │ 费用报销 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 审批引擎层(ApprovalService) │
│ - 流程管理 - 节点管理 - 订单管理 - 记录管理 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 消息服务层(FeishuNotificationService) │
│ - 消息发送 - 卡片构建 - 消息更新 - 日志记录 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 飞书平台 │
│ - 消息推送 - 卡片交互 - 回调处理 │
└─────────────────────────────────────────────────────────────┘
```
---
## 🔧 审批模块(Approval Module)
### 核心模型
| 模型 | 说明 | 关键字段 |
|------|------|----------|
| `ApprovalFlow` | 审批流程模板 | business_type, name, status |
| `ApprovalNode` | 审批节点 | type, approvers, order |
| `ApprovalOrder` | 审批订单实例 | business_type, business_id, form_data, current_nodes, status |
| `ApprovalRecord` | 审批操作记录 | order_id, node_id, approver_id, action |
### 节点类型
```php
const TYPE_APPROVER = 'approver'; // 单人审批:1人通过即可
const TYPE_AND_APPROVE = 'and_approve'; // 会签:所有人通过
const TYPE_OR_APPROVE = 'or_approve'; // 或签:1人通过即可
const TYPE_NOTIFY = 'notify'; // 通知节点:无需审批
```
### 审批状态流转
```
draft(草稿)
↓ submit
pending(审批中)
↓
├─→ approved(已通过)
├─→ rejected(已拒绝)
└─→ cancelled(已撤销)
```
### 核心方法
| 方法 | 说明 |
|------|------|
| `submit()` | 提交审批 |
| `approve()` | 审批通过 |
| `reject()` | 审批拒绝 |
| `cancel()` | 撤销申请 |
| `isNodeCompleted()` | 判断节点是否完成 |
### 扩展新业务场景
**步骤:**
1. **创建业务模型**(如 `LeaveRequest`)
2. **定义流程类型**(`business_type = 'leave'`)
3. **实现审批逻辑**
- 调用 `ApprovalService::submit()` 创建审批订单
- 在 `form_data` 中存储业务数据
4. **实现业务逻辑**
- 审批通过后的业务处理
- 审批拒绝后的业务处理
**示例:**
```php
// 请假审批
$approvalOrder = $approvalService->submit([
'business_type' => 'leave',
'business_id' => $leaveRequest->id,
'title' => '请假申请 - ' . $user->name,
'applicant_id' => $user->id,
'flow_id' => $flow->id,
'form_data' => [
'reason' => $leaveRequest->reason,
'start_date' => $leaveRequest->start_date,
'end_date' => $leaveRequest->end_date,
'approvers' => $selectedApprovers,
'cc_users' => $selectedCcUsers,
],
]);
```
---
## 📨 消息模块(Notification Module)
### 核心模型
| 模型 | 说明 | 关键字段 |
|------|------|----------|
| `FeishuMessage` | 消息映射表 | order_id, node_id, user_id, message_id, status |
| `FeishuMessageLog` | 消息日志表 | action, order_id, message_id, status, request_data, response_data |
### 消息类型
| 类型 | 场景 | 卡片样式 |
|------|------|----------|
| 审批通知 | 发送给审批人 | 带通过/拒绝按钮 |
| 系统通知 | 发送给抄送人 | 带查看详情按钮 |
| 文本通知 | 自审批场景 | 纯文本,无按钮 |
| 结果通知 | 审批结果通知 | 显示操作结果 |
### 核心方法
| 方法 | 说明 |
|------|------|
| `sendApprovalNotification()` | 发送审批通知(带操作按钮) |
| `sendSystemNotification()` | 发送系统通知(只读) |
| `updateMessageCards()` | 更新消息卡片(移除按钮) |
| `buildApprovalCard()` | 构建审批卡片 |
| `buildSystemCard()` | 构建系统通知卡片 |
### 消息生命周期
```
1. 发送消息
- 调用飞书 API
- 获取 message_id
- 保存映射到 feishu_message
- 记录日志到 feishu_message_log
2. 用户操作
- 点击卡片按钮
- 飞书回调处理
- 执行审批逻辑
3. 更新消息(或签/单人场景)
- 节点完成后触发
- 更新其他审批人的卡片
- 移除操作按钮
- 记录日志
```
### 扩展新消息类型
**步骤:**
1. **定义卡片构建方法**
```php
private function buildXXXCard(array $params): array
{
// 返回卡片数据结构
}
```
2. **添加发送方法**
```php
public function sendXXXNotification(array $params): bool
{
// 构建卡片
$card = $this->buildXXXCard($params);
// 发送消息
return $this->sendMessage($feishuUserId, $card);
}
```
3. **添加更新方法**(如需要)
```php
public function updateXXXCards(...): bool
{
// 更新逻辑
}
```
---
## 🔗 模块协作
### 协作流程
```
┌─────────────────────────────────────────────────────────────┐
│ 业务场景(如出差申请) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 调用 ApprovalService::submit() │
│ - 创建审批订单 │
│ - 返回 approval_order │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 调用 FeishuNotificationService │
│ - 发送消息给审批人 │
│ - 保存消息映射 │
│ - 记录日志 │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 用户点击消息卡片操作 │
│ - 飞书回调到后端 │
│ - 调用 ApprovalService::approve() │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 审批完成后 │
│ - 判断是否需要更新其他人的消息 │
│ - 或签/单人:调用 updateMessageCards │
│ - 会签:等待其他人审批 │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 流程结束 │
│ - 通知申请人结果 │
└──────────────────────────────────────┘
```
### 接口定义
**审批模块 → 消息模块**
```php
// 发送审批通知
$notificationService->sendApprovalNotification([
'user_id' => $approverId,
'applicant_id' => $applicantId,
'title' => '新的审批待办',
'content' => '...',
'url' => $detailUrl,
'order_id' => $orderId,
'node_id' => $nodeId,
]);
// 更新消息卡片(或签/单人场景)
$notificationService->updateMessageCards(
$orderId,
$nodeId,
$excludeUserId,
'approved',
$operatorName
);
```
---
## 🚧 扩展指南
### 添加新的审批业务场景
**示例:添加采购审批**
1. **创建数据库表**
```sql
CREATE TABLE purchase_request (
id bigint unsigned PRIMARY KEY,
user_id bigint unsigned NOT NULL,
reason varchar(500),
amount decimal(10,2),
status enum('draft', 'pending', 'approved', 'rejected'),
approval_order_id bigint unsigned,
...
);
```
2. **创建模型**
```php
class PurchaseRequest extends Model
{
public function approvalOrder()
{
return $this->belongsTo(ApprovalOrder::class);
}
}
```
3. **创建服务**
```php
class PurchaseService
{
private $approvalService;
public function submit(array $data): PurchaseRequest
{
return DB::transaction(function () use ($data) {
// 创建采购申请
$purchase = PurchaseRequest::create($data);
// 创建审批订单
$approvalOrder = $this->approvalService->submit([
'business_type' => 'purchase',
'business_id' => $purchase->id,
'title' => '采购申请 - ' . $data['item_name'],
'applicant_id' => $data['user_id'],
'flow_id' => $this->getFlowId(),
'form_data' => [
'item_name' => $data['item_name'],
'amount' => $data['amount'],
'approvers' => $data['approvers'],
'cc_users' => $data['cc_users'],
],
]);
// 关联审批订单
$purchase->approval_order_id = $approvalOrder->id;
$purchase->status = 'pending';
$purchase->save();
// 发送通知
$this->sendNotifications($purchase, $approvalOrder);
return $purchase;
});
}
}
```
4. **创建控制器**
```php
class PurchaseController
{
public function submit(Request $request): Response
{
$result = $this->service->submit($request->post());
return $this->success($result);
}
}
```
### 添加新的消息类型
**示例:添加催办通知**
```php
class FeishuNotificationService
{
/**
* 发送催办通知
*/
public function sendReminderNotification(array $params): bool
{
$userId = $params['user_id'];
$card = $this->buildReminderCard($params);
// 保存消息映射(如需要)
if (isset($params['order_id']) && isset($params['node_id'])) {
\app\model\FeishuMessage::saveMessage(
$params['order_id'],
$params['node_id'],
$userId,
$messageId
);
}
return $this->sendMessage($feishuUserId, $card);
}
private function buildReminderCard(array $params): array
{
return [
'header' => [
'title' => ['content' => '⏰ 审批催办', 'tag' => 'plain_text'],
'template' => 'orange',
],
'elements' => [
[
'tag' => 'div',
'text' => [
'content' => $params['content'],
'tag' => 'lark_md',
],
],
[
'tag' => 'action',
'actions' => [
[
'tag' => 'button',
'text' => ['content' => '立即处理', 'tag' => 'plain_text'],
'type' => 'default',
'url' => $params['url'],
],
],
],
],
];
}
}
```
---
## 📊 数据流向图
### 完整审批流程数据流
```
用户提交申请
↓
┌───────────────────────────────────────────────────────┐
│ 1. 业务表(business_trip) │
│ - 创建业务记录 │
│ - status = 'draft' │
└───────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────┐
│ 2. 审批订单(approval_order) │
│ - business_type = 'business_trip' │
│ - business_id = 业务记录ID │
│ - form_data = { │
│ approvers: [用户选择的审批人], │
│ cc_users: [用户选择的抄送人], │
│ ...业务数据 │
│ } │
│ - current_nodes = [第一个节点ID] │
│ - status = 'pending' │
└───────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────┐
│ 3. 消息映射(feishu_message) │
│ - order_id + node_id + user_id → message_id │
│ - 每个审批人一条记录 │
└───────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────┐
│ 4. 飞书平台 │
│ - 发送卡片消息给审批人 │
└───────────────────────────────────────────────────────┘
↓
审批人操作
↓
┌───────────────────────────────────────────────────────┐
│ 5. 审批记录(approval_record) │
│ - order_id, node_id, approver_id │
│ - action = 'approve' 或 'reject' │
└───────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────┐
│ 6. 节点完成判断 │
│ - 检查 form_data.approvers(实际选择的审批人) │
│ - 节点类型决定完成条件 │
│ - 或签/单人:立即完成,触发消息更新 │
│ - 会签:等待所有人 │
└───────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────┐
│ 7. 消息更新(或签/单人场景) │
│ - 更新其他审批人的消息卡片 │
│ - 移除操作按钮 │
│ - 标记消息状态 = 'updated' │
└───────────────────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────┐
│ 8. 流程流转 │
│ - 移动到下一节点 或 完成流程 │
│ - 通知下一节点审批人 / 通知申请人结果 │
└───────────────────────────────────────────────────────┘
```
---
## 🔍 调试与监控
### 消息日志查询
```bash
# 查看最近50条日志
curl "http://localhost:8787/debug/message-logs?debug=1&limit=50"
# 查看指定订单的日志
curl "http://localhost:8787/debug/message-logs?debug=1&order_id=123"
# 直接查询数据库
docker exec 1Panel-mysql-409s mysql -uroot -pmysql_xEsdPa xserver -e "
SELECT * FROM feishu_message_log
WHERE order_id = 123
ORDER BY created_at DESC;
"
```
### 日志字段说明
| 字段 | 说明 |
|------|------|
| `action` | send(发送)、update(更新)、update_card(更新卡片) |
| `status` | success(成功)、failed(失败) |
| `request_data` | 发送的数据(JSON) |
| `response_data` | 飞书返回的数据(JSON) |
| `error_message` | 错误信息(如有) |
---
## 📝 注意事项
1. **审批人来源**:始终从 `form_data.approvers` 获取,不是从 `node.approvers`
2. **消息更新**:仅在或签/单人审批完成时触发
3. **防止重复**:审批前检查是否已操作过
4. **事务处理**:业务逻辑和审批创建在同一事务中
5. **异常处理**:记录所有失败日志,方便排查问题
---
## 📚 相关文档
- [数据库结构文档](./DATABASE_SCHEMA.md)
- [项目文档](./PROJECT.md)
---
**维护人**: 开发团队
**最后更新**: 2026-02-28