Files
x-server-mobile/backend/app/service/ApprovalService.php
T
root ea7f0f8820 feat: 添加"抄送我的"审批列表选项
后端修改:
- ApprovalService::getList 添加 'cc' 类型查询
- 从 form_data.cc_users 中查找包含当前用户的订单
- 兼容两种数据格式:[{id:29}] 或 [29]

前端修改:
- 添加"抄送我的"标签页
- 更新类型定义支持 'cc' 类型
- approvalListParams 类型添加 'cc' 选项

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 18:33:53 +08:00

358 lines
12 KiB
PHP
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.
<?php
namespace app\service;
use app\model\ApprovalFlow;
use app\model\ApprovalNode;
use app\model\ApprovalOrder;
use app\model\ApprovalRecord;
use app\model\User;
use support\Db;
use Illuminate\Database\Connection;
class ApprovalService
{
private Connection $db;
public function __construct()
{
$this->db = Db::connection();
}
/**
* 提交审批
*/
public function submit(array $data): ApprovalOrder
{
return $this->db->transaction(function () use ($data) {
// 1. 获取审批流程
$flow = ApprovalFlow::active()
->byBusinessType($data['business_type'])
->with('nodes')
->findOrFail($data['flow_id']);
// 2. 创建审批单
$order = ApprovalOrder::create([
'business_type' => $data['business_type'],
'business_id' => $data['business_id'],
'title' => $data['title'],
'applicant_id' => $data['applicant_id'],
'status' => ApprovalOrder::STATUS_PENDING,
'current_nodes' => $this->getFirstNodeIds($flow),
'flow_id' => $flow->id,
'form_data' => $data['form_data'] ?? [],
'attachments' => $data['attachments'] ?? [],
]);
// 3. 记录提交操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => $flow->nodes->first()->id ?? 0,
'node_type' => 'submit',
'approver_id' => $data['applicant_id'],
'action' => ApprovalRecord::ACTION_SUBMIT,
'comment' => $data['comment'] ?? null,
]);
return $order->load(['flow', 'applicant']);
});
}
/**
* 审批通过
*/
public function approve(int $orderId, int $approverId, ?string $comment = null): ApprovalOrder
{
return $this->db->transaction(function () use ($orderId, $approverId, $comment) {
$order = ApprovalOrder::with(['flow.nodes'])->findOrFail($orderId);
if (!$order->canApprove()) {
throw new \Exception('当前状态无法审批');
}
$currentNodeIds = $order->current_nodes ?? [];
$currentNode = ApprovalNode::whereIn('id', $currentNodeIds)->first();
if (!$currentNode) {
throw new \Exception('当前节点不存在');
}
// 记录审批操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => $currentNode->id,
'node_type' => $currentNode->type,
'approver_id' => $approverId,
'action' => ApprovalRecord::ACTION_APPROVE,
'comment' => $comment,
]);
// 判断节点是否完成
if ($this->isNodeCompleted($order->id, $currentNode->id)) {
// 移动到下一节点
$nextNodes = $this->getNextNodes($order->flow, $currentNode->order);
if (empty($nextNodes)) {
// 审批完成
$order->status = ApprovalOrder::STATUS_APPROVED;
$order->current_nodes = [];
} else {
$order->current_nodes = collect($nextNodes)->pluck('id')->toArray();
}
$order->save();
}
return $order->fresh(['flow', 'applicant', 'records']);
});
}
/**
* 审批拒绝
*/
public function reject(int $orderId, int $approverId, ?string $comment = null): ApprovalOrder
{
return $this->db->transaction(function () use ($orderId, $approverId, $comment) {
$order = ApprovalOrder::findOrFail($orderId);
if (!$order->canApprove()) {
throw new \Exception('当前状态无法审批');
}
$currentNodeIds = $order->current_nodes ?? [];
$currentNode = ApprovalNode::whereIn('id', $currentNodeIds)->first();
// 记录拒绝操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => $currentNode->id ?? 0,
'node_type' => $currentNode->type ?? 'unknown',
'approver_id' => $approverId,
'action' => ApprovalRecord::ACTION_REJECT,
'comment' => $comment,
]);
// 更新状态为已拒绝
$order->status = ApprovalOrder::STATUS_REJECTED;
$order->current_nodes = [];
$order->save();
return $order->fresh(['flow', 'applicant', 'records']);
});
}
/**
* 撤销申请
*/
public function cancel(int $orderId, int $userId): ApprovalOrder
{
$order = ApprovalOrder::findOrFail($orderId);
if ($order->applicant_id !== $userId) {
throw new \Exception('只有申请人可以撤销');
}
if (!$order->canEdit() && !$order->canApprove()) {
throw new \Exception('当前状态无法撤销');
}
// 记录撤销操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => 0,
'node_type' => 'cancel',
'approver_id' => $userId,
'action' => ApprovalRecord::ACTION_CANCEL,
'comment' => '申请人撤销',
]);
$order->status = ApprovalOrder::STATUS_CANCELLED;
$order->current_nodes = [];
$order->save();
return $order->fresh(['flow', 'applicant', 'records']);
}
/**
* 获取审批列表
*/
public function getList(int $userId, string $type = 'my', int $page = 1, int $pageSize = 20): array
{
$query = ApprovalOrder::with(['flow', 'applicant']);
switch ($type) {
case 'my':
$query->where('applicant_id', $userId);
error_log("🔍 Debug 'my' query: userId={$userId}");
break;
case 'pending':
// 获取用户待审批的订单
$pendingOrderIds = $this->getPendingOrderIds($userId);
error_log("🔍 Debug 'pending' query: userId={$userId}, pendingOrderIds=" . json_encode($pendingOrderIds));
$query->whereIn('id', $pendingOrderIds);
break;
case 'approved':
// 获取用户已审批的订单(只显示已完成的:approved、rejected、cancelled)
$approvedOrderIds = ApprovalRecord::where('approver_id', $userId)
->where('action', '!=', ApprovalRecord::ACTION_SUBMIT)
->whereIn('action', [ApprovalRecord::ACTION_APPROVE, ApprovalRecord::ACTION_REJECT])
->pluck('order_id')
->unique()
->toArray();
error_log("🔍 Debug 'approved' query: userId={$userId}, approvedOrderIds=" . json_encode($approvedOrderIds));
$query->whereIn('id', $approvedOrderIds)
->whereIn('status', [ApprovalOrder::STATUS_APPROVED, ApprovalOrder::STATUS_REJECTED, ApprovalOrder::STATUS_CANCELLED]);
break;
case 'cc':
// 获取抄送给我的订单
$allOrders = ApprovalOrder::where('status', '!=', ApprovalOrder::STATUS_DRAFT)->get();
$ccOrderIds = [];
foreach ($allOrders as $order) {
$formData = $order->form_data ?? [];
$ccUsers = $formData['cc_users'] ?? [];
// 兼容两种格式:[{id:29, name:'...'}] 或 [29] 或 [{id:29}]
if (!empty($ccUsers)) {
if (is_array($ccUsers[0] ?? null) && isset($ccUsers[0]['id'])) {
// 对象数组格式: [{id:29, name:'...'}]
$ccUserIds = array_column($ccUsers, 'id');
} else if (is_numeric($ccUsers[0] ?? null)) {
// ID数组格式: [29, 30]
$ccUserIds = $ccUsers;
} else {
$ccUserIds = [];
}
if (in_array($userId, $ccUserIds)) {
$ccOrderIds[] = $order->id;
}
}
}
error_log("🔍 Debug 'cc' query: userId={$userId}, ccOrderIds=" . json_encode($ccOrderIds));
$query->whereIn('id', $ccOrderIds);
break;
}
$total = $query->count();
error_log("🔍 Debug total count: type={$type}, total={$total}");
$list = $query->orderBy('created_at', 'desc')
->offset(($page - 1) * $pageSize)
->limit($pageSize)
->get();
error_log("🔍 Debug list count: type={$type}, page={$page}, count=" . $list->count());
// 转换为数组避免序列化问题
$listArray = $list->map(function ($item) {
return [
'id' => $item->id,
'title' => $item->title,
'business_type' => $item->business_type,
'status' => $item->status,
'created_at' => $item->created_at ? $item->created_at->toDateTimeString() : null,
'applicant' => $item->applicant ? [
'id' => $item->applicant->id,
'name' => $item->applicant->name,
] : null,
'flow' => $item->flow ? [
'id' => $item->flow->id,
'name' => $item->flow->name,
] : null,
];
})->toArray();
return [
'list' => $listArray,
'total' => $total,
'page' => $page,
'page_size' => $pageSize,
];
}
/**
* 获取第一个节点ID列表
*/
private function getFirstNodeIds(ApprovalFlow $flow): array
{
return $flow->nodes
->where('order', 0)
->pluck('id')
->toArray();
}
/**
* 判断节点是否完成
*/
private function isNodeCompleted(int $orderId, int $nodeId): bool
{
$node = ApprovalNode::findOrFail($nodeId);
$records = ApprovalRecord::where('order_id', $orderId)
->where('node_id', $nodeId)
->where('action', 'approve')
->get();
$approvers = $node->approvers ?? [];
if ($node->type === ApprovalNode::TYPE_AND_APPROVE) {
// 会签:需要所有人通过
return count($records) >= count($approvers);
} elseif ($node->type === ApprovalNode::TYPE_OR_APPROVE) {
// 或签:任一人通过即可
return count($records) >= 1;
} else {
// 单人审批:需要一人通过
return count($records) >= 1;
}
}
/**
* 获取下一节点
*/
private function getNextNodes(ApprovalFlow $flow, int $currentOrder): array
{
return $flow->nodes
->where('order', '>', $currentOrder)
->sortBy('order')
->values()
->toArray();
}
/**
* 获取用户待审批的订单ID列表
*/
private function getPendingOrderIds(int $userId): array
{
// 获取用户参与的待审批订单
$pendingOrders = ApprovalOrder::where('status', ApprovalOrder::STATUS_PENDING)
->whereNotNull('current_nodes')
->get();
$result = [];
foreach ($pendingOrders as $order) {
$currentNodeIds = $order->current_nodes ?? [];
$nodes = ApprovalNode::whereIn('id', $currentNodeIds)->get();
foreach ($nodes as $node) {
$approvers = $node->approvers ?? [];
if (in_array($userId, $approvers)) {
// 检查是否已审批
$hasApproved = ApprovalRecord::where('order_id', $order->id)
->where('node_id', $node->id)
->where('approver_id', $userId)
->exists();
if (!$hasApproved) {
$result[] = $order->id;
break;
}
}
}
}
return $result;
}
}