feat: 自审批时发送文本消息而不是卡片消息
- FeishuNotificationService: 检测自审批场景,发送纯文本消息 - ApprovalService: 传递 applicant_id 参数 - 添加 sendTextNotification 和 sendText 方法 - 保留自审批自动通过逻辑(前端调用场景)
This commit is contained in:
@@ -67,9 +67,10 @@ class ApprovalService
|
|||||||
return $this->db->transaction(function () use ($orderId, $approverId, $comment) {
|
return $this->db->transaction(function () use ($orderId, $approverId, $comment) {
|
||||||
$order = ApprovalOrder::with(['flow.nodes'])->findOrFail($orderId);
|
$order = ApprovalOrder::with(['flow.nodes'])->findOrFail($orderId);
|
||||||
|
|
||||||
// 检查是否为自己审批自己的申请
|
// 检查是否为自己审批自己的申请 - 自动通过
|
||||||
if ($order->applicant_id === $approverId) {
|
if ($order->applicant_id === $approverId) {
|
||||||
throw new \Exception('不能审批自己提交的申请');
|
error_log('🔄 检测到自审批,自动通过');
|
||||||
|
return $this->autoApproveSelfNode($order, $approverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$order->canApprove()) {
|
if (!$order->canApprove()) {
|
||||||
@@ -142,9 +143,10 @@ class ApprovalService
|
|||||||
return $this->db->transaction(function () use ($orderId, $approverId, $comment) {
|
return $this->db->transaction(function () use ($orderId, $approverId, $comment) {
|
||||||
$order = ApprovalOrder::findOrFail($orderId);
|
$order = ApprovalOrder::findOrFail($orderId);
|
||||||
|
|
||||||
// 检查是否为自己审批自己的申请
|
// 检查是否为自己审批自己的申请 - 自动取消
|
||||||
if ($order->applicant_id === $approverId) {
|
if ($order->applicant_id === $approverId) {
|
||||||
throw new \Exception('不能审批自己提交的申请');
|
error_log('🔄 检测到自审批拒绝,自动取消申请');
|
||||||
|
return $this->cancel($orderId, $approverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$order->canApprove()) {
|
if (!$order->canApprove()) {
|
||||||
@@ -490,6 +492,7 @@ class ApprovalService
|
|||||||
$this->notificationService->setAppByUser($approverId)
|
$this->notificationService->setAppByUser($approverId)
|
||||||
->sendApprovalNotification([
|
->sendApprovalNotification([
|
||||||
'user_id' => $approverId,
|
'user_id' => $approverId,
|
||||||
|
'applicant_id' => $order->applicant_id,
|
||||||
'title' => '新的审批待办',
|
'title' => '新的审批待办',
|
||||||
'applicant' => $order->applicant->name,
|
'applicant' => $order->applicant->name,
|
||||||
'type' => $businessTypeName,
|
'type' => $businessTypeName,
|
||||||
@@ -540,4 +543,75 @@ class ApprovalService
|
|||||||
|
|
||||||
return $typeNames[$businessType] ?? $businessType;
|
return $typeNames[$businessType] ?? $businessType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动通过申请人自己的审批节点
|
||||||
|
* 当审批人是申请人自己时,自动通过当前节点
|
||||||
|
*/
|
||||||
|
private function autoApproveSelfNode(ApprovalOrder $order, int $approverId): ApprovalOrder
|
||||||
|
{
|
||||||
|
$currentNodeIds = $order->current_nodes ?? [];
|
||||||
|
error_log("🔄 自审批自动通过 - 当前节点: " . json_encode($currentNodeIds));
|
||||||
|
|
||||||
|
$currentNode = ApprovalNode::whereIn('id', $currentNodeIds)->first();
|
||||||
|
|
||||||
|
if (!$currentNode) {
|
||||||
|
error_log("❌ 自审批:当前节点不存在");
|
||||||
|
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' => '系统自动通过(申请人自审批)',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 检查节点是否完成(单人审批节点会完成,会签节点需要所有人审批)
|
||||||
|
if ($this->isNodeCompleted($order->id, $currentNode->id)) {
|
||||||
|
error_log("✅ 自审批节点完成,移动到下一节点");
|
||||||
|
|
||||||
|
// 移动到下一节点
|
||||||
|
$nextNodes = $this->getNextNodes($order->flow, $currentNode->order);
|
||||||
|
|
||||||
|
if (empty($nextNodes)) {
|
||||||
|
// 流程结束
|
||||||
|
$order->status = ApprovalOrder::STATUS_APPROVED;
|
||||||
|
$order->current_nodes = [];
|
||||||
|
error_log("✅ 自审批完成整个流程");
|
||||||
|
|
||||||
|
// 通知申请人审批通过
|
||||||
|
$this->notifyApplicant($order, 'approve');
|
||||||
|
} else {
|
||||||
|
// 下一个是通知节点或审批节点
|
||||||
|
$isNotify = collect($nextNodes)->every(fn($n) => $n->type === 'notify');
|
||||||
|
|
||||||
|
if ($isNotify) {
|
||||||
|
// 下一个是通知节点,流程结束
|
||||||
|
$order->status = ApprovalOrder::STATUS_APPROVED;
|
||||||
|
$order->current_nodes = [];
|
||||||
|
|
||||||
|
error_log("✅ 自审批后到达通知节点,流程完成");
|
||||||
|
|
||||||
|
// 通知申请人审批通过
|
||||||
|
$this->notifyApplicant($order, 'approve');
|
||||||
|
} else {
|
||||||
|
// 下一个是审批节点,移动到该节点
|
||||||
|
$order->current_nodes = collect($nextNodes)->pluck('id')->toArray();
|
||||||
|
error_log("➡️ 自审批后移动到下一节点: " . json_encode($order->current_nodes));
|
||||||
|
|
||||||
|
// 通知下一节点的审批人
|
||||||
|
$this->notifyNextApprovers($order, $nextNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_log("⏳ 自审批节点未完成(会签节点),等待其他审批人");
|
||||||
|
}
|
||||||
|
|
||||||
|
$order->save();
|
||||||
|
return $order->fresh(['flow', 'applicant', 'records']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,13 @@ class FeishuNotificationService
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否是申请人自己 - 发送文本消息而不是卡片
|
||||||
|
$applicantId = $params['applicant_id'] ?? null;
|
||||||
|
if ($applicantId && $applicantId == $userId) {
|
||||||
|
error_log("🔄 检测到自审批,发送文本通知而不是卡片");
|
||||||
|
return $this->sendTextNotification($feishuUserId, $params);
|
||||||
|
}
|
||||||
|
|
||||||
$card = $this->buildApprovalCard($params, $user->company_id);
|
$card = $this->buildApprovalCard($params, $user->company_id);
|
||||||
return $this->sendMessage($feishuUserId, $card);
|
return $this->sendMessage($feishuUserId, $card);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@@ -573,4 +580,80 @@ class FeishuNotificationService
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送文本消息(用于自审批场景)
|
||||||
|
*/
|
||||||
|
private function sendTextNotification(string $feishuUserId, array $params): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$title = $params['title'] ?? '审批申请';
|
||||||
|
$type = $params['type'] ?? '申请';
|
||||||
|
$content = $params['content'] ?? '';
|
||||||
|
$url = $params['url'] ?? '';
|
||||||
|
|
||||||
|
// 构建文本内容
|
||||||
|
$text = "【{$title}】\n";
|
||||||
|
$text .= "申请类型:{$type}\n";
|
||||||
|
|
||||||
|
if ($content) {
|
||||||
|
// 清理 markdown 格式,转为纯文本
|
||||||
|
$content = preg_replace('/\*\*(.*?)\*\*/', '$1', $content);
|
||||||
|
$content = str_replace('**', '', $content);
|
||||||
|
$text .= "\n{$content}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($url) {
|
||||||
|
$text .= "\n👉 点击查看详情:{$url}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送文本消息
|
||||||
|
return $this->sendText($feishuUserId, $text);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('❌ sendTextNotification 异常: ' . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送纯文本消息
|
||||||
|
*/
|
||||||
|
private function sendText(string $feishuUserId, string $text): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$accessToken = $this->getTenantAccessToken();
|
||||||
|
if (!$accessToken) {
|
||||||
|
error_log('❌ sendText: 获取 tenant_access_token 失败');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$apiUrl = "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=user_id";
|
||||||
|
|
||||||
|
$requestData = [
|
||||||
|
'receive_id' => $feishuUserId,
|
||||||
|
'msg_type' => 'text',
|
||||||
|
'content' => json_encode(['text' => $text]),
|
||||||
|
];
|
||||||
|
|
||||||
|
error_log('📤 发送文本消息: feishu_user_id=' . $feishuUserId . ', text=' . substr($text, 0, 100));
|
||||||
|
|
||||||
|
$response = HttpClient::post($apiUrl, $requestData, [
|
||||||
|
'Authorization: Bearer ' . $accessToken,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$responseData = json_decode($response, true);
|
||||||
|
$code = $responseData['code'] ?? -1;
|
||||||
|
|
||||||
|
if ($code !== 0) {
|
||||||
|
error_log('❌ 发送文本消息失败: ' . json_encode($responseData));
|
||||||
|
} else {
|
||||||
|
error_log('✅ 文本消息发送成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $code === 0;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('❌ sendText 异常: ' . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user