where('name', 'like', '%门岗%'); })->get(); return $this->success($admin); } /** * @OA\Get( * path="/api/gate/visits", * tags={"门岗端接口"}, * summary="拜访信息列表", * description="获取门岗端拜访信息列表", * @OA\Parameter(name="date", in="query", @OA\Schema(type="string"), required=false, description="查询日期,格式:Y-m-d,默认今天"), * @OA\Parameter(name="status", in="query", @OA\Schema(type="string"), required=false, description="状态筛选:1通过(待进厂)3已进厂4已离厂"), * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=false, description="类型筛选:1访客2访客车辆3物流车辆"), * @OA\Parameter(name="keyword", in="query", @OA\Schema(type="string"), required=false, description="关键词搜索(人牌,身份证,核销码)"), * @OA\Parameter(name="page", in="query", @OA\Schema(type="integer"), required=false, description="页码,默认1"), * @OA\Parameter(name="page_size", in="query", @OA\Schema(type="integer"), required=false, description="每页数量,默认20"), * @OA\Response( * response="200", * description="成功获取拜访信息列表", * @OA\JsonContent( * @OA\Property(property="code", type="integer", example=200), * @OA\Property(property="message", type="string", example="success"), * @OA\Property(property="data", type="object", * @OA\Property(property="current_page", type="integer"), * @OA\Property(property="data", type="array", @OA\Items(type="object")), * @OA\Property(property="total", type="integer") * ) * ) * ) * ) */ public function visits(Request $request) { try { $date = $request->input('date', Carbon::today()->format('Y-m-d')); $status = $request->input('status'); $type = $request->input('type'); $keyword = $request->input('keyword'); $page = $request->input('page', 1); $pageSize = $request->input('page_size', 20); $query = Visit::with([ 'visitArea', 'visitTime', 'acceptDepartment', 'acceptAdmin', 'visitAudits', 'acceptAdminSign' ])->whereDate('date', $date); // 状态筛选 if ($status) { $query->where('audit_status', $status); } else { // 默认显示待进厂和已进厂的记录 $query->whereIn('audit_status', [Visit::AUDIT_STATUS_APPROVED, Visit::AUDIT_STATUS_ENTERED, Visit::AUDIT_STATUS_LEFT]); } // 类型筛选 if ($type) { $query->where('type', $type); } // 关键词搜索 if ($keyword) { $query->where(function ($q) use ($keyword) { $q->where('person_no', "{$keyword}") ->orWhere('idcard', "{$keyword}") ->orWhere('code', "{$keyword}"); }); } $visits = $query->orderBy('created_at', 'desc') ->paginate($pageSize, ['*'], 'page', $page); return $this->success($visits); } catch (\Exception $e) { Log::error('门岗端获取拜访列表失败:' . $e->getMessage()); return $this->fail([ResponseCode::ERROR_INSIDE, __('gate.get_visit_list_failed')]); } } /** * @OA\Post( * path="/api/gate/visits/detail", * tags={"门岗端接口"}, * summary="拜访详情信息", * description="获取指定拜访的详细信息", * @OA\RequestBody( * required=true, * @OA\JsonContent( * @OA\Property(property="id", type="integer", description="拜访ID") * ) * ), * @OA\Response( * response="200", * description="成功获取拜访详情", * @OA\JsonContent( * @OA\Property(property="code", type="integer", example=200), * @OA\Property(property="message", type="string", example="success"), * @OA\Property(property="data", type="object") * ) * ) * ) */ public function visitDetail(Request $request) { try { $id = $request->input('id'); if (!$id) { return $this->fail([ResponseCode::ERROR_PARAMETER, __('gate.visit_id_required')]); } $visit = Visit::with([ 'visitArea', 'visitTime', 'acceptDepartment', 'acceptAdmin', 'acceptGoodsAdmin', 'accompany', 'visitAudits', 'logs', 'acceptAdminSign' ])->find($id); if (!$visit) { return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.visit_not_found')]); } return $this->success($visit); } catch (\Exception $e) { Log::error('门岗端获取拜访详情失败:' . $e->getMessage()); return $this->fail([ResponseCode::ERROR_INSIDE, __('gate.get_visit_detail_failed')]); } } /** * @OA\Post( * path="/api/gate/visits/update", * tags={"门岗端接口"}, * summary="更新拜访信息", * description="门岗端更新拜访信息(绑定ID卡、修改状态、上传货车图片等)", * @OA\RequestBody( * required=true, * @OA\JsonContent( * @OA\Property(property="id", type="integer", description="拜访ID"), * @OA\Property(property="action", type="string", description="操作类型:bind_card绑定ID卡,enter进厂,leave离厂,upload_vehicle上传货车图片"), * @OA\Property(property="person_no", type="string", description="人牌号(绑定ID卡时必填)"), * @OA\Property(property="car_no", type="string", description="停车牌号(绑定ID卡时必填)"), * @OA\Property(property="vehicle_images", type="array", description="货车图片ID数组(上传货车图片时必填)", @OA\Items(type="integer")), * @OA\Property(property="remark", type="string", description="备注信息") * ) * ), * @OA\Response( * response="200", * description="更新成功", * @OA\JsonContent( * @OA\Property(property="code", type="integer", example=200), * @OA\Property(property="message", type="string", example="操作成功"), * @OA\Property(property="data", type="object") * ) * ) * ) */ public function updateVisit(Request $request) { try { $id = $request->input('id'); if (!$id) { return $this->fail([ResponseCode::ERROR_PARAMETER, __('gate.visit_id_required')]); } $visit = Visit::find($id); if (!$visit) { return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.visit_not_found')]); } $action = $request->input('action'); $remark = $request->input('remark', ''); DB::beginTransaction(); switch ($action) { case 'bind_card': // 绑定ID卡 $personNo = $request->input('person_no'); $carNo = $request->input('car_no'); if (!$personNo) { return $this->fail([ResponseCode::ERROR_PARAMETER, __('gate.person_no_required')]); } $visit->person_no = $personNo; if ($carNo) { $visit->car_no = $carNo; } $visit->save(); // 记录日志 $this->createVisitLog($visit, VisitLog::TYPE_ENTER, __('gate.bind_card_log', ['person_no' => $personNo, 'car_no' => $carNo ?: ''])); break; case 'enter': // 进厂 if ($visit->audit_status != Visit::AUDIT_STATUS_APPROVED) { return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.only_approved_visits_can_enter')]); } $visit->audit_status = Visit::AUDIT_STATUS_ENTERED; $visit->save(); // 记录日志 $this->createVisitLog($visit, VisitLog::TYPE_ENTER, __('gate.enter_log') . ($remark ? ':' . $remark : '')); // 记录门岗日志 $this->createGateLog($visit, 'enter', $remark); break; case 'leave': // 离厂 if ($visit->audit_status != Visit::AUDIT_STATUS_ENTERED) { return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.only_entered_visitors_can_leave')]); } $visit->audit_status = Visit::AUDIT_STATUS_LEFT; $visit->save(); // 记录日志 $this->createVisitLog($visit, VisitLog::TYPE_LEAVE, __('gate.leave_log') . ($remark ? ':' . $remark : '')); // 记录门岗日志 $this->createGateLog($visit, 'leave', $remark); break; case 'upload_vehicle': // 上传货车图片 if ($visit->type != Visit::TYPE_LOGISTICS_CAR) { return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.only_logistics_cars_can_upload_images')]); } $vehicleImages = $request->input('vehicle_images', []); if (empty($vehicleImages)) { return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.vehicle_images_required')]); } // 验证图片ID是否存在于uploads表中 $existingImages = Upload::whereIn('id', $vehicleImages)->pluck('id')->toArray(); if (count($existingImages) !== count($vehicleImages)) { return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.invalid_vehicle_images')]); } // 存储货车图片ID数组到vehicle_images字段 $visit->vehicle_images = $vehicleImages; $visit->save(); // 记录日志 $this->createVisitLog($visit, VisitLog::TYPE_ENTER, __('gate.upload_vehicle_images_log', ['count' => count($vehicleImages)])); break; default: return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.invalid_action_type')]); } DB::commit(); return $this->success($visit); } catch (\Exception $e) { DB::rollBack(); Log::error('门岗端更新拜访信息失败:' . $e->getMessage()); return $this->fail([ResponseCode::ERROR_INSIDE, __('gate.operation_failed') . ':' . $e->getMessage()]); } } /** * 创建拜访日志 */ private function createVisitLog($visit, $type, $remark = '') { VisitLog::log($visit->id, $type, $remark); } /** * 创建门岗日志 */ private function createGateLog($visit, $action, $remark = '') { $personNo = $visit->person_no ? [$visit->person_no] : []; $carNo = $visit->car_no ? [$visit->car_no] : []; GateLog::create([ 'code' => $visit->code, 'remark' => $remark, 'person_no' => $personNo, 'car_no' => $carNo, 'created_at' => now(), 'updated_at' => now(), ]); } /** * @OA\Get( * path="/api/gate/visits/use-code", * tags={"门岗端接口"}, * summary="核销", * description="", * @OA\Parameter(name="admin_id", in="query", @OA\Schema(type="string"), required=false, description="管理员id"), * @OA\Parameter(name="keyword", in="query", @OA\Schema(type="string"), required=false, description="关键词(人牌,身份证,核销码)"), * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=false, description="1进厂2离厂"), * @OA\Response( * response="200", * description="暂无" * ) * ) */ public function useCode() { $all = \request()->all(); $messages = [ 'keyword.required' => __('gate.validation.keyword_required'), 'type.required' => __('gate.validation.type_required'), 'admin_id.required' => __('gate.validation.admin_id_required') ]; $validator = Validator::make($all, [ 'keyword' => 'required', 'type' => 'required', 'admin_id' => 'required' ], $messages); if ($validator->fails()) { return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } $code = \request('code'); $idcard = \request('idcard'); if (empty($idcard) && empty($code)) { return $this->fail([ResponseCode::ERROR_PARAMETER, __('gate.validation.code_or_idcard_required')]); } $check = Visit::where(function ($query) use ($all) { $query->where('person_no', "{$all['keyword']}") ->orWhere('idcard', "{$all['keyword']}") ->orWhere('code', "{$all['keyword']}"); })->first(); if (empty($check)) { return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.business.visit_not_found')]); } $remark = __('gate.operation.enter_factory'); if ($all['type'] == 2) { $remark = __('gate.operation.leave_factory'); } $gateLog = GateLog::add($all['admin_id'], $all['code'], $all['person_no'] ?? [], $all['car_no'] ?? [], $remark); if ($all['type'] == 1) { // 入场 Visit::where('code', $all['code'])->update(['audit_status' => 3, 'person_no' => $all['person_no'] ?? '', 'car_no' => $all['car_no'] ?? '']); } if ($all['type'] == 2) { Visit::where('code', $all['code'])->update(['audit_status' => 4]); } return $this->success($gateLog); } }