From a8d13093496afd09c8ee00a9937167bc1c11d2fa Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Fri, 30 Jan 2026 10:46:54 +0800 Subject: [PATCH] 1 --- app/admin/controller/InvItemController.php | 15 ++ .../controller/InvRequisitionController.php | 3 +- app/admin/service/InvRequisitionService.php | 31 +++ .../service/InvRequisitionApproveService.php | 193 ++++++++++++++++++ .../approval/traits/ApprovalResolverTrait.php | 4 + config/route.php | 4 + 6 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 app/admin/service/InvRequisitionService.php diff --git a/app/admin/controller/InvItemController.php b/app/admin/controller/InvItemController.php index ed8866f..516300a 100644 --- a/app/admin/controller/InvItemController.php +++ b/app/admin/controller/InvItemController.php @@ -52,4 +52,19 @@ class InvItemController extends BaseController $data['manage_user_name'] = User::where('id', $data['manage_user_id'])->value('name'); return $data; } + + public function requisitionList(Request $request){ + try { + $res = $this->service->getList(); + $result = []; + foreach ($res as $value) { + $value['company_name'] = Corp::where('id', $value['company_id'])->value('name'); + $value['manage_user_name'] = User::where('id', $value['manage_user_id'])->value('name'); + $result[] = $value; + } + return $this->success($result, '审核列表'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } } \ No newline at end of file diff --git a/app/admin/controller/InvRequisitionController.php b/app/admin/controller/InvRequisitionController.php index 79b4375..14121f4 100644 --- a/app/admin/controller/InvRequisitionController.php +++ b/app/admin/controller/InvRequisitionController.php @@ -3,8 +3,7 @@ namespace app\admin\controller; use app\common\controller\BaseController; use app\common\traits\crud\CrudControllerTrait; -use app\common\service\InvRequisitionService; -use support\Request; +use app\admin\service\InvRequisitionService; class InvRequisitionController extends BaseController { diff --git a/app/admin/service/InvRequisitionService.php b/app/admin/service/InvRequisitionService.php new file mode 100644 index 0000000..88e84ae --- /dev/null +++ b/app/admin/service/InvRequisitionService.php @@ -0,0 +1,31 @@ +validator; + } +} \ No newline at end of file diff --git a/app/common/service/InvRequisitionApproveService.php b/app/common/service/InvRequisitionApproveService.php index 9c84831..56996db 100644 --- a/app/common/service/InvRequisitionApproveService.php +++ b/app/common/service/InvRequisitionApproveService.php @@ -2,9 +2,12 @@ namespace app\common\service; +use app\common\model\User; use app\common\validate\InvRequisitionApproveValidate; use app\common\traits\crud\CrudServiceTrait; use app\common\model\InvRequisitionApprove; +use support\Db; +use support\exception\BusinessException; class InvRequisitionApproveService { @@ -29,5 +32,195 @@ class InvRequisitionApproveService return new $this->validator; } + /** + * @param string $flowType + * @param string $bizType + * @param string $bizId + * @param array $formData ['manage_user_id'=>23]//物品管理员 + * @param int $initiatorId //申请人id + * @return array + */ + public function start(string $flowType, string $bizType, string $bizId, array $formData, int $initiatorId): array + { + return Db::transaction(function () use ($flowType, $bizType, $bizId, $formData, $initiatorId) { + $flow = Db::table('approval_flows')->where('type', $flowType)->where('is_active', 1)->first(); + if (!$flow) throw new BusinessException("审批流程未找到或已停用: {$flowType}"); + + $steps = json_decode($flow->steps, true); + if (!is_array($steps) || empty($steps)) throw new BusinessException("流程步骤配置错误"); + + // 找首个有效步骤索引(考虑条件) + $firstIndex = $this->getNextStepIndex($steps, $formData, -1); + if ($firstIndex === null) throw new BusinessException("未找到可执行的审批步骤"); + $firstStep = $steps[$firstIndex]; + + //$now = date('Y-m-d H:i:s'); + $now = time(); + + + $service = new \app\common\utils\approval\service\ApprovalFlowService(); + + // 解析首步审批人(支持 role_id 或 roles.name) + $instance = (object)[ + 'initiator_id' => $initiatorId, + 'form_data'=>json_encode($formData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) + ]; + $approverIds = $service->StetApprovers($firstStep, $instance, true); + + if(empty($approverIds)){ + throw new BusinessException('未解析到任何审批人'); + } + $uid = array_shift($approverIds); + $approver = User::where('id', $uid)->first(); + + $approveId = Db::table('inv_requisition_approve')->insertGetId([ + 'requisition_id' => $bizId, //申请单ID + 'node_type' => $bizType, + 'approver_id' => $approver->id, + 'approver_name' => $approver->name, + 'action' => 0, + 'comment' => '', + 'created_at' => $now, + 'updated_at' => $now, + ]); + +// foreach ($approverIds as $uid) { +// $this->insertApprovalRecord($instance, $firstIndex, $uid); +// } + + return ['instance_id' => $approveId]; + }); + } + + /** 执行审批 */ + public function approve(int $requisitionId, int $approverId, string $action, string $comment = '') + { + if (!in_array($action, ['1','2'], true)) { //审批动作:1通过 2驳回 + throw new BusinessException("无效的审批操作"); + } + + return Db::transaction(function () use ($requisitionId, $approverId, $action, $comment) { +// $instance = Db::table('approval_instances')->where('id', $instanceId)->lockForUpdate()->first(); + $requisition = Db::table('inv_requisition')->where('id', $requisitionId)->lockForUpdate()->first(); + if (!$requisition) throw new BusinessException("审批实例未找到"); + if ($requisition->status !== 'processing') { + return ['status' => 'noop', 'msg' => '实例未处理']; + } + + //审批流程 + $flow = Db::table('approval_flows')->where('type', $requisition->flow_type)->first(); + if (!$flow) throw new BusinessException("审批流程定义未找到"); + + $steps = json_decode($flow->steps, true); + //$idx = (int)$requisition->current_step; + //$step = $steps[$idx] ?? null; + //if (!$step) throw new BusinessException("当前步骤配置错误"); + + // 找到该用户在本步的 pending 记录(加锁) + $pendingRecord = Db::table('inv_requisition_approve') + ->where('requisition_id', $requisitionId) + ->where('approver_id', $approverId) + ->where('action', 0) + ->lockForUpdate() + ->first(); + + if (!$pendingRecord) { + // 已处理过? + $anyRecord = Db::table('inv_requisition_approve') + ->where('requisition_id', $requisitionId) + ->where('approver_id', $approverId) + ->first(); + if ($anyRecord && $anyRecord->action > 0) { + return ['status' => 'noop', 'msg' => '已处理']; + } + // 步骤已推进 +// if ((int)$requisition->current_step !== $idx) { +// return ['status' => 'noop', 'msg' => '非当前审批']; +// } + return ['status' => 'noop', 'msg' => '无待处理记录']; + } + + $now = date('Y-m-d H:i:s'); + + // 1) 更新当前人的审批记录 + Db::table('inv_requisition_approve')->where('id', $pendingRecord->id)->update([ + 'action' => $action, + 'comment' => $comment, + 'approved_at' => $now, + 'updated_at' => $now, + ]); + + // 2) 已通过步骤与总步数相等则结束审核流程 + $pass = Db::table('inv_requisition_approve') + ->where('requisition_id', $requisitionId) + ->where('approver_id', $approverId) + ->where('action', 1) + ->count(); + if($action == 1){ + if(count($steps) == $pass){ + $requisition->status = 12; + $requisition->save(); + return ['status' => 'complete', 'msg' => '已通过']; + } + } + + // 3) 拒绝 => 结束 + if($action == 2){ + Db::table('inv_requisition_approve')->where('id', $pendingRecord->id)->update([ + 'action' => $action, + 'comment' => $comment, + 'approved_at' => $now, + 'updated_at' => $now, + ]); + if(count($steps) == $pass){ + $requisition->status = 13; + $requisition->save(); + return ['status' => 'complete', 'msg' => '拒绝']; + } + } + + + // 4) 通过 => 进入下一步或结束 + $formData = ['manage_user_id'=>'']; + + $nextIndex = $pass; + $nextStep = $steps[$nextIndex]; + $service = new \app\common\utils\approval\service\ApprovalFlowService(); + + $instance = (object)[ + 'form_data'=>json_encode($formData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) + ]; + $approverIds = $service->StetApprovers($nextStep, $instance, true); + $approver = User::where('id', array_pop($approverIds))->first(); + Db::table('inv_requisition_approve')->insertGetId([ + 'requisition_id' => $requisitionId, //申请单ID + 'node_type' => $nextStep['approvers']['initiator_leader'], + 'approver_id' => $approver->id, + 'approver_name' => $approver->name, + 'action' => 0, + 'comment' => '', + 'created_at' => $now, + 'updated_at' => $now, + ]);; + + }); + } + +// public function insertApprovalRecord() +// { +// } + + + /** 获取下一个有效步骤索引 */ + private function getNextStepIndex(array $steps, array $formData, int $currentStepIndex): ?int + { + for ($i = $currentStepIndex + 1; $i < count($steps); $i++) { + $s = $steps[$i]; + if (empty($s['condition'])) { + return $i; + } + } + return null; + } } \ No newline at end of file diff --git a/app/common/utils/approval/traits/ApprovalResolverTrait.php b/app/common/utils/approval/traits/ApprovalResolverTrait.php index 475d9ee..c80d15d 100644 --- a/app/common/utils/approval/traits/ApprovalResolverTrait.php +++ b/app/common/utils/approval/traits/ApprovalResolverTrait.php @@ -403,4 +403,8 @@ trait ApprovalResolverTrait return $ids; } + + public function StetApprovers(array $step, object $instance, bool $avoidSelf = true){ + return$this->resolveApprovers($step, $instance, $avoidSelf); + } } diff --git a/config/route.php b/config/route.php index ce61410..dfc9801 100644 --- a/config/route.php +++ b/config/route.php @@ -514,6 +514,10 @@ Route::group('/admin', function () { Route::any('/item/update', [app\admin\controller\InvItemController::class, 'update']); Route::any('/item/show', [app\admin\controller\InvItemController::class, 'show']); Route::any('/item/destroy', [app\admin\controller\InvItemController::class, 'destroy']); + + Route::group('/requisition', function () { + Route::any('/list', [app\admin\controller\InvItemController::class, 'requisitionList']); + }); }); });