Files
fdesk/app/common/utils/approval/traits/ApprovalTransferTrait.php
T
2026-01-07 17:23:03 +08:00

131 lines
5.4 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\common\utils\approval\traits;
use support\Db;
use support\exception\BusinessException;
trait ApprovalTransferTrait
{
/** 查看某个实例的转交流水(按时间升序) */
public function listTransfers(int $instanceId): array
{
$rows = Db::table('approval_transfers')
->where('instance_id', $instanceId)
->orderBy('id', 'asc')
->get()
->toArray();
return array_map(function($r){
return [
'id' => (int)$r->id,
'instance_id' => (int)$r->instance_id,
'step_index' => (int)$r->step_index,
'record_id' => (int)$r->record_id,
'from_user_id' => (int)$r->from_user_id,
'to_user_id' => (int)$r->to_user_id,
'reason' => $r->reason,
'created_at' => $r->created_at,
];
}, $rows);
}
/** 转交当前待办给他人 */
public function transferApproval(
int $instanceId,
int $stepIndex,
int $fromUserId,
int $toUserId,
string $reason = '',
?string $userNameColumn = null
): array {
if ($fromUserId === $toUserId) {
return ['status' => 'noop', 'msg' => '目标与来源相同,无需转交'];
}
return \support\Db::transaction(function () use ($instanceId, $stepIndex, $fromUserId, $toUserId, $reason, $userNameColumn) {
// 锁实例,避免并发推进
$instance = Db::table('approval_instances')->where('id', $instanceId)->lockForUpdate()->first();
if (!$instance) throw new BusinessException('审批实例未找到');
if ($instance->status !== 'processing') throw new BusinessException('流程非进行中,无法转交');
// 锁定来源人的 pending 记录
$record = Db::table('approval_records')
->where('instance_id', $instanceId)
->where('round', (int)$instance->round)
->where('step_index', $stepIndex)
->where('approver_id', $fromUserId)
->where('status', 'pending')
->lockForUpdate()
->first();
if (!$record) throw new BusinessException('未找到可转交的待办或已处理');
$now = date('Y-m-d H:i:s');
// 若目标已有 pending:合并(本记录置为 skipped)
$target = Db::table('approval_records')
->where('instance_id', $instanceId)
->where('round', (int)$instance->round)
->where('step_index', $stepIndex)
->where('approver_id', $toUserId)
->where('status', 'pending')
->lockForUpdate()
->first();
if ($target) {
Db::table('approval_records')->where('id', $record->id)->update([
'status' => 'skipped',
'approved_at' => $now,
'updated_at' => $now,
'comment' => trim(($record->comment ?? '')."\n[转交给 {$toUserId},目标已有待办,已合并]"),
]);
$effectiveRecordId = (int)$target->id;
} else {
// 原地替换 approver_id
Db::table('approval_records')->where('id', $record->id)->update([
'approver_id' => $toUserId,
'updated_at' => $now,
'comment' => trim(($record->comment ?? '')."\n[自 {$fromUserId} 转交]"),
]);
$effectiveRecordId = (int)$record->id;
}
// 组织“转交来源/原因”文案(优先姓名)
$fromLabel = (string)$fromUserId;
$toLabel = (string)$toUserId;
if ($userNameColumn) {
$fromName = Db::table('user')->where('id', $fromUserId)->value($userNameColumn);
$toName = Db::table('user')->where('id', $toUserId)->value($userNameColumn);
if ($fromName) $fromLabel = $fromName;
if ($toName) $toLabel = $toName;
}
$note = "【转交】{$fromLabel} → {$toLabel}";
$r = trim($reason);
if ($r !== '') $note .= ",原因:{$r}";
// 通知被转交人(在内容里追加 note)
$this->sendNotification([$toUserId], (object)[
'id' => (int)$instance->id,
'flow_type' => (string)$instance->flow_type,
'biz_type' => (string)$instance->biz_type,
'biz_id' => (string)$instance->biz_id,
'initiator_id' => (int)$instance->initiator_id,
'form_data' => $instance->form_data,
], 'pending', false, ['note' => $note]);
// 记转交流水
Db::table('approval_transfers')->insert([
'instance_id' => (int)$instanceId,
'step_index' => (int)$stepIndex,
'record_id' => $effectiveRecordId,
'from_user_id' => (int)$fromUserId,
'to_user_id' => (int)$toUserId,
'reason' => $reason,
'created_at' => $now,
]);
$this->pushTodoChanged([$fromUserId, $toUserId]);
return ['status' => 'ok', 'record_id' => $effectiveRecordId];
});
}
}