You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

409 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Http\Controllers;
use App\Models\Admin;
use App\Models\Visit;
use App\Models\VisitLog;
use App\Models\GateLog;
use App\Models\Upload;
use App\Helpers\ApiResponse;
use App\Helpers\ResponseCode;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
use Illuminate\Support\Facades\Validator;
/**
* @OA\Tag(
* name="门岗端接口",
* description="门岗端相关接口,无需鉴权"
* )
*/
class GateController extends Controller
{
use ApiResponse;
/**
* @OA\Get(
* path="/api/admin/gate/user-list",
* tags={"门岗端接口"},
* summary="门岗用户列表",
* description="",
* @OA\Response(
* response="200",
* description="暂无"
* )
* )
*/
public function uerList()
{
$admin = Admin::whereHas('role', function ($query) {
$query->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);
}
}