|
|
<?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="start_date", in="query", @OA\Schema(type="string"), required=false, description="查询日期,格式:Y-m-d,开始日期"),
|
|
|
* @OA\Parameter(name="end_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 {
|
|
|
$startDate = $request->input('start_date', date('Y-m-d'));
|
|
|
$endDate = $request->input('end_date', date('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'
|
|
|
])->whereBetween('date', [$startDate, $endDate]);
|
|
|
|
|
|
// 状态筛选
|
|
|
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/admin/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/admin/gate/visits/update",
|
|
|
* tags={"门岗端接口"},
|
|
|
* summary="更新拜访信息",
|
|
|
* description="门岗端更新拜访信息(按字段进行更新:绑定ID卡、修改进/离厂状态、上传货车图片等)",
|
|
|
* @OA\RequestBody(
|
|
|
* required=true,
|
|
|
* @OA\JsonContent(
|
|
|
* @OA\Property(property="id", type="integer", description="拜访ID"),
|
|
|
* @OA\Property(property="person_no", type="string", description="人牌号(提供则更新并记录绑定日志)"),
|
|
|
* @OA\Property(property="car_no", type="string", description="停车牌号(提供则更新)"),
|
|
|
* @OA\Property(property="audit_status", type="integer", enum={3,4}, description="审核状态:3进厂(需当前为已通过),4离厂(需当前为已进厂)"),
|
|
|
* @OA\Property(property="vehicle_images", type="array", description="货车图片ID数组(仅物流车辆可提供,需为有效上传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')]);
|
|
|
}
|
|
|
|
|
|
$remark = $request->input('remark', '');
|
|
|
$personNo = $request->input('person_no');
|
|
|
$carNo = $request->input('car_no');
|
|
|
$vehicleImages = $request->input('vehicle_images'); // null 表示未尝试更新
|
|
|
$newAuditStatus = $request->input('audit_status'); // 可选:3进厂,4离厂
|
|
|
|
|
|
DB::beginTransaction();
|
|
|
|
|
|
$hasAnyChange = false;
|
|
|
|
|
|
// 绑定/更新人牌、车牌
|
|
|
if (!is_null($personNo) || !is_null($carNo)) {
|
|
|
if (!is_null($personNo)) {
|
|
|
$visit->person_no = $personNo;
|
|
|
}
|
|
|
if (!is_null($carNo)) {
|
|
|
$visit->car_no = $carNo;
|
|
|
}
|
|
|
$visit->save();
|
|
|
$hasAnyChange = true;
|
|
|
|
|
|
$this->createVisitLog(
|
|
|
$visit,
|
|
|
VisitLog::TYPE_ENTER,
|
|
|
__('gate.bind_card_log', [
|
|
|
'person_no' => $visit->person_no ?: '',
|
|
|
'car_no' => $visit->car_no ?: ''
|
|
|
])
|
|
|
);
|
|
|
}
|
|
|
|
|
|
// 审核状态变更:支持进厂(Approved -> Entered) 与 离厂(Entered -> Left)
|
|
|
if (!is_null($newAuditStatus)) {
|
|
|
if ((int) $newAuditStatus === Visit::AUDIT_STATUS_ENTERED) {
|
|
|
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();
|
|
|
$hasAnyChange = true;
|
|
|
|
|
|
$this->createVisitLog($visit, VisitLog::TYPE_ENTER, __('gate.enter_log') . ($remark ? ':' . $remark : ''));
|
|
|
$this->createGateLog($visit, 'enter', $remark);
|
|
|
} elseif ((int) $newAuditStatus === Visit::AUDIT_STATUS_LEFT) {
|
|
|
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();
|
|
|
$hasAnyChange = true;
|
|
|
|
|
|
$this->createVisitLog($visit, VisitLog::TYPE_LEAVE, __('gate.leave_log') . ($remark ? ':' . $remark : ''));
|
|
|
$this->createGateLog($visit, 'leave', $remark);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 货车图片更新(仅物流车辆)
|
|
|
if (!is_null($vehicleImages)) {
|
|
|
if ($visit->type != Visit::TYPE_LOGISTICS_CAR) {
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.only_logistics_cars_can_upload_images')]);
|
|
|
}
|
|
|
|
|
|
if (!is_array($vehicleImages) || empty($vehicleImages)) {
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, __('gate.vehicle_images_required')]);
|
|
|
}
|
|
|
|
|
|
$visit->vehicle_images = $vehicleImages;
|
|
|
$visit->save();
|
|
|
$hasAnyChange = true;
|
|
|
|
|
|
$this->createVisitLog($visit, VisitLog::TYPE_ENTER, __('gate.upload_vehicle_images_log', ['count' => count($vehicleImages)]));
|
|
|
}
|
|
|
|
|
|
if (!$hasAnyChange) {
|
|
|
DB::rollBack();
|
|
|
return $this->fail([ResponseCode::ERROR_PARAMETER, __('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/admin/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);
|
|
|
}
|
|
|
|
|
|
}
|