增加审批时间轴&&调整采购单
This commit is contained in:
@@ -808,7 +808,7 @@ class ApprovalFlowService
|
||||
* initiator_name?:?string
|
||||
* }
|
||||
*/
|
||||
public function getSimpleTimeline(int $instanceId, ?string $userNameColumn = null, string $initiatorPlacement = 'prepend'): array
|
||||
public function getSimpleTimeline2(int $instanceId, ?string $userNameColumn = null, string $initiatorPlacement = 'prepend'): array
|
||||
{
|
||||
// 基础数据
|
||||
$instance = Db::table('approval_instances')->where('id', $instanceId)->first();
|
||||
@@ -958,6 +958,193 @@ class ApprovalFlowService
|
||||
}
|
||||
|
||||
|
||||
public function getSimpleTimeline(int $instanceId, ?string $userNameColumn = null, string $initiatorPlacement = 'prepend'): array
|
||||
{
|
||||
// 基础数据
|
||||
$instance = Db::table('approval_instances')->where('id', $instanceId)->first();
|
||||
if (!$instance) throw new BusinessException('审批实例未找到');
|
||||
|
||||
$flow = Db::table('approval_flows')->where('type', $instance->flow_type)->first();
|
||||
if (!$flow) throw new BusinessException('审批流程定义未找到');
|
||||
|
||||
$steps = json_decode($flow->steps, true) ?: [];
|
||||
$formData = json_decode($instance->form_data ?? '{}', true) ?: [];
|
||||
$curStep = (int)$instance->current_step;
|
||||
$round = (int)$instance->round;
|
||||
|
||||
// 申请人
|
||||
$initiatorId = (int)$instance->initiator_id;
|
||||
$initiatorName = null;
|
||||
if ($userNameColumn) {
|
||||
$initiatorName = Db::table('user')->where('id', $initiatorId)->value($userNameColumn);
|
||||
}
|
||||
|
||||
// 审批记录(仅当前轮次)
|
||||
$records = Db::table('approval_records as ar')
|
||||
->where('ar.instance_id', $instanceId)
|
||||
->where('ar.round', $round)
|
||||
->orderBy('ar.step_index')
|
||||
->orderByRaw('COALESCE(ar.approved_at, ar.created_at) asc')
|
||||
->select('ar.*')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
// 一次性拉取姓名,避免 N+1
|
||||
$nameMap = [];
|
||||
if ($userNameColumn && !empty($records)) {
|
||||
$uids = [];
|
||||
foreach ($records as $r) $uids[] = (int)$r->approver_id;
|
||||
$uids = array_values(array_unique($uids));
|
||||
if (!empty($uids)) {
|
||||
$pairs = Db::table('user')->whereIn('id', $uids)->pluck($userNameColumn, 'id')->toArray();
|
||||
foreach ($pairs as $uid => $name) $nameMap[(int)$uid] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
// 记录分组
|
||||
$byStep = [];
|
||||
foreach ($records as $r) {
|
||||
$idx = (int)$r->step_index;
|
||||
$byStep[$idx][] = $r;
|
||||
}
|
||||
|
||||
$timeline = [];
|
||||
|
||||
// 可选:发起申请块
|
||||
if ($initiatorPlacement === 'prepend') {
|
||||
$appliedAt = $instance->created_at ?: null;
|
||||
$timeline[] = [
|
||||
'index' => -1,
|
||||
'name' => '发起申请',
|
||||
'type' => '-',
|
||||
'status' => 'submitted',
|
||||
'started_at' => $appliedAt,
|
||||
'finished_at' => $appliedAt,
|
||||
'duration_seconds' => 0,
|
||||
'initiator_id' => $initiatorId,
|
||||
'initiator_name' => $initiatorName,
|
||||
];
|
||||
}
|
||||
|
||||
// 每一步
|
||||
foreach ($steps as $i => $meta) {
|
||||
$name = $meta['name'] ?? ('Step '.$i);
|
||||
$typeRaw = strtolower($meta['type'] ?? 'all');
|
||||
$type = in_array($typeRaw, ['any','all']) ? $typeRaw : 'all';
|
||||
$condStr = $meta['condition'] ?? null;
|
||||
$condOk = $condStr ? $this->evaluateCondition($condStr, $formData) : true;
|
||||
|
||||
$recs = $byStep[$i] ?? [];
|
||||
$hasRecs = !empty($recs);
|
||||
|
||||
$status = 'pending';
|
||||
$startedAt = null;
|
||||
$finishedAt = null;
|
||||
$durationSec = null;
|
||||
|
||||
// ★ 每一步的“审批意见”(只展示有内容的 comment)
|
||||
$opinions = []; // [{approver_id, approver_name?, action, status, comment, time}...]
|
||||
|
||||
if ($hasRecs) {
|
||||
// 统计时间
|
||||
$minCreated = null;
|
||||
$minApproveAt = null; $maxApproveAt = null;
|
||||
$minRejectAt = null;
|
||||
$maxTimeoutAt = null;
|
||||
$cnt = ['pending'=>0,'approved'=>0,'rejected'=>0,'timeout'=>0];
|
||||
|
||||
foreach ($recs as $rr) {
|
||||
// 收集“审批意见”(非空 comment 都算)
|
||||
$cmt = trim((string)($rr->comment ?? ''));
|
||||
if ($cmt !== '') {
|
||||
$opinions[] = [
|
||||
'approver_id' => (int)$rr->approver_id,
|
||||
'approver_name' => $userNameColumn ? ($nameMap[(int)$rr->approver_id] ?? null) : null,
|
||||
'action' => $rr->action, // approve | reject | null
|
||||
'status' => $rr->status, // approved|rejected|pending|skipped|timeout
|
||||
'comment' => $cmt,
|
||||
'time' => $rr->approved_at ?: $rr->created_at,
|
||||
];
|
||||
}
|
||||
|
||||
if ($rr->created_at && (!$minCreated || $rr->created_at < $minCreated)) $minCreated = $rr->created_at;
|
||||
if ($rr->approved_at) {
|
||||
if ($rr->status === 'approved') {
|
||||
if (!$minApproveAt || $rr->approved_at < $minApproveAt) $minApproveAt = $rr->approved_at;
|
||||
if (!$maxApproveAt || $rr->approved_at > $maxApproveAt) $maxApproveAt = $rr->approved_at;
|
||||
} elseif ($rr->status === 'rejected') {
|
||||
if (!$minRejectAt || $rr->approved_at < $minRejectAt) $minRejectAt = $rr->approved_at;
|
||||
} elseif ($rr->status === 'timeout') {
|
||||
if (!$maxTimeoutAt || $rr->approved_at > $maxTimeoutAt) $maxTimeoutAt = $rr->approved_at;
|
||||
}
|
||||
}
|
||||
if (isset($cnt[$rr->status])) $cnt[$rr->status]++;
|
||||
}
|
||||
|
||||
// 时间升序排序 opinions
|
||||
if (!empty($opinions)) {
|
||||
usort($opinions, function($a, $b) {
|
||||
return strcmp($a['time'] ?? '', $b['time'] ?? '');
|
||||
});
|
||||
}
|
||||
|
||||
$startedAt = $minCreated;
|
||||
|
||||
// 总结果(注意:这里按你现在的签名调用,含 round)
|
||||
$outcome = $this->getStepOutcome($instanceId, $round, $i, $type); // 'pending'|'approve'|'reject'
|
||||
if ($outcome === 'reject') {
|
||||
$status = 'rejected';
|
||||
$finishedAt = $minRejectAt;
|
||||
} elseif ($outcome === 'approve') {
|
||||
$status = 'approved';
|
||||
$finishedAt = ($type === 'any') ? $minApproveAt : $maxApproveAt;
|
||||
} else {
|
||||
if ($cnt['timeout'] > 0 && $cnt['approved'] === 0 && $cnt['rejected'] === 0 && $cnt['pending'] === 0) {
|
||||
$status = 'timeout';
|
||||
$finishedAt = $maxTimeoutAt;
|
||||
} else {
|
||||
$status = 'processing';
|
||||
}
|
||||
}
|
||||
|
||||
if ($startedAt && $finishedAt) {
|
||||
$durationSec = max(0, strtotime($finishedAt) - strtotime($startedAt));
|
||||
}
|
||||
} else {
|
||||
// 无记录:根据位置与条件展示
|
||||
if ($i < $curStep) {
|
||||
$status = $condOk ? 'approved' : 'skipped';
|
||||
} elseif ($i === $curStep && $instance->status === 'processing') {
|
||||
$status = 'processing';
|
||||
} else {
|
||||
$status = $condOk ? 'pending' : 'skipped';
|
||||
}
|
||||
}
|
||||
|
||||
$row = [
|
||||
'index' => (int)$i,
|
||||
'name' => $name,
|
||||
'type' => $type,
|
||||
'status' => $status,
|
||||
'started_at' => $startedAt,
|
||||
'finished_at' => $finishedAt,
|
||||
'duration_seconds' => $durationSec,
|
||||
'opinions' => $opinions, // ★ 这就是每个审批意见
|
||||
];
|
||||
|
||||
// 把申请人信息并到第一步(可选)
|
||||
if ($initiatorPlacement === 'attach' && empty($timeline)) {
|
||||
$row['initiator_id'] = $initiatorId;
|
||||
$row['initiator_name'] = $initiatorName;
|
||||
}
|
||||
|
||||
$timeline[] = $row;
|
||||
}
|
||||
|
||||
return $timeline;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 按业务ID获取“最新进展”的极简状态
|
||||
* - 已完结:直接返回实例最终状态
|
||||
|
||||
Reference in New Issue
Block a user