From ade4d684afdb14e932c7560fc555c3d4ab7a5918 Mon Sep 17 00:00:00 2001 From: wanghongjun <1445693971@qq.com> Date: Fri, 5 Jun 2026 14:46:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=82=E5=B8=B8=E5=8D=A0=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Admin/ParkingAbnormalController.php | 177 ++++++++++++++++++ .../Admin/ParkingSpaceController.php | 16 +- app/Models/ParkingAbnormal.php | 46 +++++ app/Models/ParkingReservation.php | 5 + app/Services/ParkingAbnormalService.php | 177 ++++++++++++++++++ app/common.php | 23 +++ ...4_143449_create_parking_abnormal_table.php | 40 ++++ database/seeders/AdminMenuSeeder.php | 4 +- resources/lang/en/log.php | 3 + resources/lang/en/menu.php | 4 +- resources/lang/en/service.php | 16 ++ resources/lang/zh-CN/log.php | 3 + resources/lang/zh-CN/menu.php | 4 +- resources/lang/zh-CN/service.php | 16 ++ resources/lang/zh-TW/log.php | 3 + resources/lang/zh-TW/menu.php | 4 +- resources/lang/zh-TW/service.php | 16 ++ routes/admin/api.php | 5 + 18 files changed, 543 insertions(+), 19 deletions(-) create mode 100644 app/Http/Controllers/Admin/ParkingAbnormalController.php create mode 100644 app/Models/ParkingAbnormal.php create mode 100644 app/Services/ParkingAbnormalService.php create mode 100644 database/migrations/2026_06_04_143449_create_parking_abnormal_table.php diff --git a/app/Http/Controllers/Admin/ParkingAbnormalController.php b/app/Http/Controllers/Admin/ParkingAbnormalController.php new file mode 100644 index 0000000..deb4fc1 --- /dev/null +++ b/app/Http/Controllers/Admin/ParkingAbnormalController.php @@ -0,0 +1,177 @@ +service = $service; + } + + /** + * @param Request $request + * @return JsonResponse + */ + public function index(Request $request): JsonResponse + { + try { + $query = ParkingAbnormal::query(); + + if ($request->has('parking_id')) { + $parking_id = $request->input('parking_id'); + if ($parking_id) { + $query->where('parking_id', $parking_id); + } + } + + if ($request->has('date_type')) { + $date_type = $request->input('date_type'); + $start_date = ''; + if ($date_type == 1) { + $start_date = date('Y-m-d 00:00:00', time()); + } else { + if ($date_type == 2) { + $start_date = date( + 'Y-m-d 00:00:00', + strtotime('-3 day') + ); + } else { + if ($date_type == 3) { + $start_date = date( + 'Y-m-d 00:00:00', + strtotime('-7 day') + ); + } else { + if ($date_type == 4) { + $start_date = date( + 'Y-m-d 00:00:00', + strtotime('-1 month') + ); + } else { + if ($date_type == 5) { + $start_date = date( + 'Y-m-d 00:00:00', + strtotime('-3 month') + ); + } + } + } + } + } + if ($start_date) { + $end_date = date('Y-m-d 23:59:59', time()); + $query->whereBetween('enter_at', [$start_date, $end_date]); + } + } + + if ($request->has('status')) { + $status = $request->input('status'); + if ($status) { + $query->where('status', $status); + } + } + + if ($request->has('operation_type')) { + $operation_type = $request->input('operation_type'); + if ($operation_type) { + $query->where('operation_type', $operation_type); + } + } + + // 分页 + $page = $request->input('page', 1); + $perPage = $request->input('per_page', 10); + $total = $query->count(); + $items = $query->latest()->forPage($page, $perPage)->get()->each( + function ($item) { + return $this->service->getItem($item); + } + ); + + return $this->responseService->success([ + 'items' => $items, + 'total' => $total, + 'page' => $page, + 'per_page' => $perPage, + 'last_page' => ceil($total / $perPage), + ]); + } catch (Exception $e) { + $m_prefix = __('exception.exception_handler.resource'); + return $this->responseService->systemError( + $m_prefix . ':' . $e->getMessage() + ); + } + } + + public function handle(Request $request): JsonResponse + { + try { + $data = $request->all(); + $this->validateId($data['id'] ?? 0, ParkingAbnormal::class); + $this->service->updateOperationType( + $data['id'], + $data['reason'] ?? '' + ); + return $this->responseService->success( + null, + __('admin.operation_successful') + ); + } catch (ValidationException|CustomException $e) { + throw $e; + } catch (Exception $e) { + return $this->responseService->systemError( + __('admin.operation_failed') . ':' + . $e->getMessage() + ); + } + } + + public function ignore(Request $request): JsonResponse + { + try { + $data = $request->all(); + $this->validateId($data['id'] ?? 0, ParkingAbnormal::class); + $this->service->updateOperationType( + $data['id'], + $data['reason'] ?? '', + 2 + ); + return $this->responseService->success( + null, + __('admin.operation_successful') + ); + } catch (ValidationException|CustomException $e) { + throw $e; + } catch (Exception $e) { + return $this->responseService->systemError( + __('admin.operation_failed') . ':' + . $e->getMessage() + ); + } + } +} diff --git a/app/Http/Controllers/Admin/ParkingSpaceController.php b/app/Http/Controllers/Admin/ParkingSpaceController.php index 83544f5..16a52f4 100644 --- a/app/Http/Controllers/Admin/ParkingSpaceController.php +++ b/app/Http/Controllers/Admin/ParkingSpaceController.php @@ -308,21 +308,7 @@ class ParkingSpaceController extends BaseController $data['parking_space_type'] = ParkingSpaceType::getName($item['space_type_id']); $data['berthing_time_str'] = ''; if ($item['berthing_time']) { - $difference = get_time_difference($item['berthing_time']); - if (!isset($difference['error'])) { - if (!empty($difference['days'])) { - $data['berthing_time_str'] .= $difference['days'] . __('controller.parking_space.days'); - } - if (!empty($difference['hours']) || !empty($data['berthing_time_str'])) { - $data['berthing_time_str'] .= $difference['hours'] . __('controller.parking_space.hours'); - } - if (!empty($difference['minutes']) || !empty($data['berthing_time_str'])) { - $data['berthing_time_str'] .= $difference['minutes'] . __('controller.parking_space.minutes'); - } - if (!empty($difference['seconds']) || !empty($data['berthing_time_str'])) { - $data['berthing_time_str'] .= $difference['seconds'] . __('controller.parking_space.seconds'); - } - } + $data['berthing_time_str'] = get_time_difference_str($item['berthing_time']); } $data['recognition_rate'] = $item['recognition']; $data['recognition'] = $this->service->getRecognition( diff --git a/app/Models/ParkingAbnormal.php b/app/Models/ParkingAbnormal.php new file mode 100644 index 0000000..d6e7c44 --- /dev/null +++ b/app/Models/ParkingAbnormal.php @@ -0,0 +1,46 @@ +where('id', $id)->value('reserve_id'); + } } diff --git a/app/Services/ParkingAbnormalService.php b/app/Services/ParkingAbnormalService.php new file mode 100644 index 0000000..2764379 --- /dev/null +++ b/app/Services/ParkingAbnormalService.php @@ -0,0 +1,177 @@ + 'occupancy', + ]; + public array $statusArr + = [ + 'unprocessed', + 'processed' + ]; + public array $operationTypeArr + = [ + 1 => 'handle', + 2 => 'ignore' + ]; + public array $reasonArr + = [ + 1 => 'reason1', + 2 => 'reason2', + 3 => 'reason3', + 4 => 'reason4' + ]; + public array $dateArr + = [ + 1 => 'today', + 2 => 'days3', + 3 => 'week', + 4 => 'month', + 5 => 'month3' + ]; + protected string $menuTitle = 'abnormal_resource_usage'; + + /** + * @return array|string[] + */ + public function getDateArr(): array + { + $dateArr = $this->dateArr; + foreach ($dateArr as $key => $value) { + $dateArr[$key] = __service($this->menuTitle . '.' . $value); + } + return $dateArr; + } + + public function getItem($item) + { + $item['parking'] = Parking::getName($item['parking_id']); + $ParkingSpace = ParkingSpace::query()->find($item['space_id']); + $item['floor'] = AdminFloor::getName($ParkingSpace['floor_id']); + $item['parking_space_number'] = $ParkingSpace['number']; + $item['parking_space_type'] = ParkingSpaceType::getName( + $ParkingSpace['space_type_id'] + ); + $item['parking_space_attr'] = ParkingSpaceAttributes::getAttr( + $ParkingSpace['space_attr_id'] + ); + $item['license_plate'] = ParkingLicensePlate::getNumber( + $item['license_plate_id'] + ); + $item['duration'] = get_time_difference_str($item['enter_at']); + $typeArr = $this->getType(); + $item['type'] = $typeArr[$item['type']]; + $statusArr = $this->getStatus(); + $item['status'] = $statusArr[$item['status']]; + $operationTypeArr = $this->getOperationType(); + $item['operation_type'] = $operationTypeArr[$item['operation_type']] ?? + ''; + $reasonArr = $this->getReason(); + $item['reason'] = $reasonArr[$item['reason']] ?? ''; + $item['reservation_id'] = ParkingReservation::getReserveId( + $item['reservation_id'] + ); + + unset( + $item['parking_id'], + $item['space_id'], + $item['license_plate_id'] + ); + return $item; + } + + /** + * @return array|string[] + */ + public function getType(): array + { + $typeArr = $this->typeArr; + foreach ($typeArr as $key => $value) { + $typeArr[$key] = __service($this->menuTitle . '.' . $value); + } + return $typeArr; + } + + /** + * @return array|string[] + */ + public function getStatus(): array + { + $typeArr = $this->statusArr; + foreach ($typeArr as $key => $value) { + $typeArr[$key] = __service($this->menuTitle . '.' . $value); + } + return $typeArr; + } + + /** + * @return array|string[] + */ + public function getOperationType(): array + { + $operationTypeArr = $this->operationTypeArr; + foreach ($operationTypeArr as $key => $value) { + $operationTypeArr[$key] = __service( + $this->menuTitle . '.' . $value + ); + } + return $operationTypeArr; + } + + /** + * @return array|string[] + */ + public function getReason(): array + { + $reasonArr = $this->reasonArr; + foreach ($reasonArr as $key => $value) { + $reasonArr[$key] = __service($this->menuTitle . '.' . $value); + } + return $reasonArr; + } + + public function updateOperationType($id, $reason, $operation_type = 1) + { + try { + DB::beginTransaction(); + + $model = ParkingAbnormal::query()->findOrFail($id); + $oldValue = $model->toArray(); + + $model->update([ + 'operation_type' => $operation_type, + 'handle_reason' => $reason, + 'operation_at' => get_datetime(), + 'updated_at' => get_datetime() + ]); + + $this->logService->logUpdated( + $model, + $oldValue, + $this->menuTitle . '.operation' + ); + + DB::commit(); + return $model; + } catch (Exception $e) { + DB::rollBack(); + throw $e; + } + } + +} diff --git a/app/common.php b/app/common.php index 421b2ca..fff5b77 100644 --- a/app/common.php +++ b/app/common.php @@ -151,6 +151,29 @@ if (!function_exists('get_time_difference')) { } } +if (!function_exists('get_time_difference_str')) { + function get_time_difference_str($date): string + { + $value = ''; + $difference = get_time_difference($date); + if (!isset($difference['error'])) { + if (!empty($difference['days'])) { + $value .= $difference['days'] . __('controller.parking_space.days'); + } + if (!empty($difference['hours']) || !empty($value)) { + $value .= $difference['hours'] . __('controller.parking_space.hours'); + } + if (!empty($difference['minutes']) || !empty($value)) { + $value .= $difference['minutes'] . __('controller.parking_space.minutes'); + } + if (!empty($difference['seconds']) || !empty($value)) { + $value .= $difference['seconds'] . __('controller.parking_space.seconds'); + } + } + return $value; + } +} + if (!function_exists('get_image_url')) { function get_image_url($image_url): string { diff --git a/database/migrations/2026_06_04_143449_create_parking_abnormal_table.php b/database/migrations/2026_06_04_143449_create_parking_abnormal_table.php new file mode 100644 index 0000000..e08d56f --- /dev/null +++ b/database/migrations/2026_06_04_143449_create_parking_abnormal_table.php @@ -0,0 +1,40 @@ +id(); + $table->integer('space_id')->comment('车位id'); + $table->integer('parking_id')->comment('停车场ID'); + $table->integer('license_plate_id')->comment('车牌号码'); + $table->timestamp('enter_at')->comment('入场时间'); + $table->tinyInteger('type')->default(1)->comment('异常类型'); + $table->tinyInteger('status')->default(0)->comment('异常状态'); + $table->tinyInteger('operation_type')->default(0)->comment('操作类型'); + $table->string('handle_reason', 255)->default('')->comment('处理原因'); + $table->tinyInteger('reason')->default(1)->comment('异常原因'); + $table->timestamp('operation_at')->nullable()->comment('操作时间'); + $table->integer('reservation_id')->nullable()->comment('预约id'); + $table->timestamps(); + $table->innoDb(); + $table->comment('白名单'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('parking_abnormal'); + } +}; diff --git a/database/seeders/AdminMenuSeeder.php b/database/seeders/AdminMenuSeeder.php index 7e11240..ebabfe6 100644 --- a/database/seeders/AdminMenuSeeder.php +++ b/database/seeders/AdminMenuSeeder.php @@ -261,7 +261,9 @@ class AdminMenuSeeder extends Seeder 'uri' => 'abnormalResourceUsage', 'page_uri' => '/info/abnormalResourceUsage', 'child' => [ - 'read_only' => 'abnormalResourceUsage.index' + 'read_only' => 'abnormalResourceUsage.index', + 'abnormal_handle' => 'abnormalResourceUsage.handle', + 'abnormal_ignore' => 'abnormalResourceUsage.ignore' ] ] ], diff --git a/resources/lang/en/log.php b/resources/lang/en/log.php index 23344ed..d09ed1b 100644 --- a/resources/lang/en/log.php +++ b/resources/lang/en/log.php @@ -131,5 +131,8 @@ return [ 'create' => 'Create whitelist', 'update' => 'Update whitelist', 'delete' => 'Remove from whitelist' + ], + 'abnormal_resource_usage' => [ + 'operation' => 'Update operation type' ] ]; diff --git a/resources/lang/en/menu.php b/resources/lang/en/menu.php index 2dba93d..8a1a799 100644 --- a/resources/lang/en/menu.php +++ b/resources/lang/en/menu.php @@ -91,5 +91,7 @@ return [ 'region_list' => 'region list', 'synchronize_list' => 'Synchronize List', 'batch_parking_repair' => 'Batch import of maintenance parking spaces', - 'batch_update_attr' => 'Batch modify attributes' + 'batch_update_attr' => 'Batch modify attributes', + 'abnormal_handle' => 'handle exceptions', + 'abnormal_ignore' => 'Ignore exceptions' ]; diff --git a/resources/lang/en/service.php b/resources/lang/en/service.php index ea4a4be..1229bb7 100644 --- a/resources/lang/en/service.php +++ b/resources/lang/en/service.php @@ -131,5 +131,21 @@ return [ ], 'whitelist' => [ 'number_exists' => 'The license plate number already exists' + ], + 'abnormal_resource_usage' => [ + 'occupancy' => 'Abnormal occupancy', + 'unprocessed' => 'unprocessed', + 'processed' => 'Processed', + 'handle' => 'handle', + 'ignore' => 'ignore', + 'reason1' => 'Unpredited vehicle parking', + 'reason2' => 'Inconsistent with reserved parking space attributes', + 'reason3' => 'Inconsistent with the reserved parking space type', + 'reason4' => 'Inconsistent type', + 'today' => 'that day', + 'days3' => 'Over the past three days', + 'week' => 'the past week', + 'month' => 'Last month', + 'month3' => 'Last March' ] ]; diff --git a/resources/lang/zh-CN/log.php b/resources/lang/zh-CN/log.php index 3714048..f26b338 100644 --- a/resources/lang/zh-CN/log.php +++ b/resources/lang/zh-CN/log.php @@ -131,5 +131,8 @@ return [ 'create' => '创建白名单', 'update' => '更新白名单', 'delete' => '删除白名单' + ], + 'abnormal_resource_usage' => [ + 'operation' => '更新操作类型' ] ]; diff --git a/resources/lang/zh-CN/menu.php b/resources/lang/zh-CN/menu.php index 59df05a..0a6a3d9 100644 --- a/resources/lang/zh-CN/menu.php +++ b/resources/lang/zh-CN/menu.php @@ -91,5 +91,7 @@ return [ 'region_list' => '区域列表', 'synchronize_list' => '同步列表', 'batch_parking_repair' => '批量导入维修车位', - 'batch_update_attr' => '批量修改属性' + 'batch_update_attr' => '批量修改属性', + 'abnormal_handle' => '处理异常', + 'abnormal_ignore' => '忽略异常' ]; diff --git a/resources/lang/zh-CN/service.php b/resources/lang/zh-CN/service.php index d7f947e..50e3dc1 100644 --- a/resources/lang/zh-CN/service.php +++ b/resources/lang/zh-CN/service.php @@ -131,5 +131,21 @@ return [ ], 'whitelist' => [ 'number_exists' => '车牌号码已存在' + ], + 'abnormal_resource_usage' => [ + 'occupancy' => '异常占用', + 'unprocessed' => '未处理', + 'processed' => '已处理', + 'handle' => '处理', + 'ignore' => '忽略', + 'reason1' => '未预约车辆停车', + 'reason2' => '与预约车位属性不一致', + 'reason3' => '与预约车位类型不一致', + 'reason4' => '类型不一致', + 'today' => '当天', + 'days3' => '过去三天', + 'week' => '过去一周', + 'month' => '过去一月', + 'month3' => '过去三月' ] ]; diff --git a/resources/lang/zh-TW/log.php b/resources/lang/zh-TW/log.php index 4df3292..8b69b57 100644 --- a/resources/lang/zh-TW/log.php +++ b/resources/lang/zh-TW/log.php @@ -131,5 +131,8 @@ return [ 'create' => '創建白名單', 'update' => '更新白名單', 'delete' => '删除白名單' + ], + 'abnormal_resource_usage' => [ + 'operation' => '更新操作類型' ] ]; diff --git a/resources/lang/zh-TW/menu.php b/resources/lang/zh-TW/menu.php index 13cb141..7f8c8ac 100644 --- a/resources/lang/zh-TW/menu.php +++ b/resources/lang/zh-TW/menu.php @@ -91,5 +91,7 @@ return [ 'region_list' => '區域清單', 'synchronize_list' => '同步清單', 'batch_parking_repair' => '批量導入維修車位', - 'batch_update_attr' => '批量修改内容' + 'batch_update_attr' => '批量修改内容', + 'abnormal_handle' => '處理异常', + 'abnormal_ignore' => '忽略异常' ]; diff --git a/resources/lang/zh-TW/service.php b/resources/lang/zh-TW/service.php index 40a543b..ce50c46 100644 --- a/resources/lang/zh-TW/service.php +++ b/resources/lang/zh-TW/service.php @@ -131,5 +131,21 @@ return [ ], 'whitelist' => [ 'number_exists' => '車牌號碼已存在' + ], + 'abnormal_resource_usage' => [ + 'occupancy' => '异常佔用', + 'unprocessed' => '未處理', + 'processed' => '已處理', + 'handle' => '處理', + 'ignore' => '忽略', + 'reason1' => '未預約車輛停車', + 'reason2' => '與預約車位内容不一致', + 'reason3' => '與預約車位類型不一致', + 'reason4' => '類型不一致', + 'today' => '當天', + 'days3' => '過去三天', + 'week' => '過去一周', + 'month' => '過去一月', + 'month3' => '過去三月' ] ]; diff --git a/routes/admin/api.php b/routes/admin/api.php index 81d6165..a9c784a 100644 --- a/routes/admin/api.php +++ b/routes/admin/api.php @@ -37,6 +37,7 @@ use App\Http\Controllers\Admin\ParkingDepartureReasonController; use App\Http\Controllers\Admin\ChannelPermissionsController; use App\Http\Controllers\Admin\ParkingEquipmentController; use App\Http\Controllers\Admin\ParkingWhitelistController; +use App\Http\Controllers\Admin\ParkingAbnormalController; Route::group(['prefix' => 'admin'], function () { @@ -186,6 +187,10 @@ Route::group(['prefix' => 'admin'], function () { Route::get('/notice/setting', [NoticeController::class, 'create']); Route::post('/notice/setting', [NoticeController::class, 'setting']); Route::get('/notice/show/{id}', [NoticeController::class, 'show']); + // 异常占用 + Route::get('/abnormalResourceUsage', [ParkingAbnormalController::class, 'index']); + Route::post('/abnormalResourceUsage/handle', [ParkingAbnormalController::class, 'handle']); + Route::post('/abnormalResourceUsage/ignore', [ParkingAbnormalController::class, 'ignore']); // 车牌识别率 Route::get('/licensePlateRecognition', [LicensePlateRecognitionController::class, 'index']); Route::get('/licensePlateRecognition/curveGraph', [LicensePlateRecognitionController::class, 'curveGraph']);