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

11 months ago
<?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;
11 months ago
/**
* @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);
}
11 months ago
/**
* @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物流车辆"),
11 months ago
* @OA\Parameter(name="keyword", in="query", @OA\Schema(type="string"), required=false, description="关键词搜索(人牌,身份证,核销码)"),
11 months ago
* @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) {
11 months ago
$q->where('person_no', "{$keyword}")
->orWhere('idcard', "{$keyword}")
->orWhere('code', "{$keyword}");
11 months ago
});
}
$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')]);
}
}
/**
11 months ago
* @OA\Post(
* path="/api/gate/visits/detail",
11 months ago
* tags={"门岗端接口"},
* summary="拜访详情信息",
* description="获取指定拜访的详细信息",
11 months ago
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* @OA\Property(property="id", type="integer", description="拜访ID")
* )
* ),
11 months ago
* @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")
* )
* )
* )
*/
11 months ago
public function visitDetail(Request $request)
11 months ago
{
try {
11 months ago
$id = $request->input('id');
if (!$id) {
return $this->fail([ResponseCode::ERROR_PARAMETER, __('gate.visit_id_required')]);
}
11 months ago
$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(
11 months ago
* path="/api/gate/visits/update",
11 months ago
* tags={"门岗端接口"},
* summary="更新拜访信息",
* description="门岗端更新拜访信息绑定ID卡、修改状态、上传货车图片等",
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
11 months ago
* @OA\Property(property="id", type="integer", description="拜访ID"),
11 months ago
* @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")
* )
* )
* )
*/
11 months ago
public function updateVisit(Request $request)
11 months ago
{
try {
11 months ago
$id = $request->input('id');
if (!$id) {
return $this->fail([ResponseCode::ERROR_PARAMETER, __('gate.visit_id_required')]);
}
11 months ago
$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"),
11 months ago
* @OA\Parameter(name="keyword", in="query", @OA\Schema(type="string"), required=false, description="关键词(人牌,身份证,核销码)"),
11 months ago
* @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 = [
11 months ago
'keyword.required' => __('gate.validation.keyword_required'),
11 months ago
'type.required' => __('gate.validation.type_required'),
'admin_id.required' => __('gate.validation.admin_id_required')
];
$validator = Validator::make($all, [
11 months ago
'keyword' => 'required',
11 months ago
'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')]);
}
11 months ago
$check = Visit::where(function ($query) use ($all) {
$query->where('person_no', "{$all['keyword']}")
->orWhere('idcard', "{$all['keyword']}")
->orWhere('code', "{$all['keyword']}");
11 months ago
})->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);
}
}