Browse Source

车位资讯

master
wanghongjun 4 days ago
parent
commit
6a9928c53f
  1. 230
      app/Http/Controllers/Admin/ParkingInformationController.php
  2. 2
      app/Http/Controllers/Admin/ParkingLicensePlateController.php
  3. 34
      app/Models/ParkingInformation.php
  4. 8
      app/Models/ParkingLicensePlate.php
  5. 13
      app/Models/ParkingSpace.php
  6. 152
      app/Services/ParkingInformationService.php
  7. 2
      database/migrations/2026_03_23_143449_create_parking_space_table.php
  8. 33
      database/migrations/2026_04_23_143449_create_parking_information_table.php
  9. 3
      resources/lang/zh-CN/exception.php
  10. 4
      resources/lang/zh-CN/log.php
  11. 3
      resources/lang/zh-CN/service.php
  12. 6
      routes/admin/api.php

230
app/Http/Controllers/Admin/ParkingInformationController.php

@ -0,0 +1,230 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Exceptions\CustomException;
use App\Models\AdminFloorRegion;
use App\Models\ParkingInformation;
use App\Models\ParkingLicensePlate;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceType;
use App\Services\ApiResponseService;
use App\Services\ParkingInformationService;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Psr\SimpleCache\InvalidArgumentException;
class ParkingInformationController extends BaseController
{
/**
* @var ParkingInformationService
*/
protected ParkingInformationService $service;
/**
* 构造函数
* @param ApiResponseService $responseService
* @param ParkingInformationService $service
*/
public function __construct(
ApiResponseService $responseService,
ParkingInformationService $service
) {
parent::__construct($responseService);
$this->service = $service;
}
/**
* Display a listing of the resource.
*/
public function index(Request $request): JsonResponse
{
try {
$query = ParkingInformation::query();
// 车位号码搜索
if ($request->has('parking_space_number')) {
$parking_space_number = $request->input('parking_space_number');
if ($parking_space_number) {
$space_ids = ParkingSpace::getId($parking_space_number);
if ($space_ids) {
$query->whereIn('space_id', $space_ids);
} else {
$query->where('id', 0);
}
}
}
if ($request->has('license_plate')) {
$license_plate = $request->input('license_plate');
if ($license_plate) {
$license_plate_ids = ParkingLicensePlate::getId(
$license_plate
);
if ($license_plate_ids) {
$query->whereIn('license_plate_id', $license_plate_ids);
} else {
$query->where('id', 0);
}
}
}
if ($request->has('entry_start_date')) {
$entry_start_date = $request->input('entry_start_date');
if ($entry_start_date && strtotime($entry_start_date)) {
$query->where('entry_time', '>=', $entry_start_date);
}
}
if ($request->has('entry_end_date')) {
$entry_end_date = $request->input('entry_end_date');
if ($entry_end_date && strtotime($entry_end_date)) {
$query->where('entry_time', '<=', $entry_end_date);
}
}
if ($request->has('parking_space_type')) {
$type = $request->input('parking_space_type');
if ($type) {
$query->where('space_type_id', '=', $type);
}
}
// 分页
$page = $request->input('page', 1);
$perPage = $request->input('per_page', 10);
$total = $query->count();
$items = $query->latest()->forPage($page, $perPage)->select()
->get()->each(function ($item) {
$item['floor_region_name'] = AdminFloorRegion::getName(
$item['floor_region_id']
);
$item['parking_space'] = ParkingSpace::getNumber(
$item['space_id']
);
$item['license_plate'] = ParkingLicensePlate::getNumber(
$item['license_plate_id']
);
$item['parking_space_type'] = ParkingSpaceType::getName(
$item['space_type_id']
);
unset($item['floor_region_id'], $item['space_id'], $item['license_plate_id'], $item['space_type_id']);
return $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()
);
}
}
/**
* 列表搜索数据
* @return JsonResponse
*/
public function search(): JsonResponse
{
try {
$data = [
'parking_space_type_list' => ParkingSpaceType::getData()
];
return $this->responseService->success($data);
} catch (Exception $e) {
$m_prefix = __('exception.exception_handler.resource');
return $this->responseService->systemError(
$m_prefix . ':' . $e->getMessage()
);
}
}
public function store(Request $request): JsonResponse
{
try {
$data = $request->all();
$rules = [
'license_plate' => 'required',
];
$messages = [
'license_plate.required' => __(
'validation.license_plate.n_empty'
)
];
$validator = Validator::make($data, $rules, $messages);
if ($validator->fails()) {
throw new ValidationException($validator);
}
$this->service->createModel($data);
return $this->responseService->success(
null,
__('admin.save_succeeded')
);
} catch (ValidationException|CustomException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.parking_information.create_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @param string $id
* @return JsonResponse
* @throws CustomException
* @throws ValidationException
*/
public function destroy(string $id): JsonResponse
{
try {
$this->validateId($id, ParkingInformation::class);
$this->service->deleteModel($id);
return $this->responseService->success(
null,
__('admin.delete_succeeded')
);
} catch (ValidationException|CustomException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.license_plate.destroy_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @return JsonResponse
* @throws InvalidArgumentException
*/
public function rule(): JsonResponse
{
try {
return $this->responseService->success(
$this->methodShow('information')
);
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.get_data_failed') . ':' . $e->getMessage()
);
}
}
}

2
app/Http/Controllers/Admin/ParkingLicensePlateController.php

@ -276,7 +276,7 @@ class ParkingLicensePlateController extends BaseController
{ {
try { try {
return $this->responseService->success( return $this->responseService->success(
$this->methodShow('licensePlate') $this->methodShow('licensePlate', ['import', 'clear'])
); );
} catch (Exception $e) { } catch (Exception $e) {
return $this->responseService->systemError( return $this->responseService->systemError(

34
app/Models/ParkingInformation.php

@ -0,0 +1,34 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ParkingInformation extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'parking_information';
protected $fillable = [
'floor_region_id',
'space_id',
'license_plate_id',
'entry_time',
'space_type_id'
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at'
];
public function getEntryTimeAttribute($value): string
{
return get_datetime('datetime', strtotime($value));
}
}

8
app/Models/ParkingLicensePlate.php

@ -5,6 +5,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;
class ParkingLicensePlate extends Model class ParkingLicensePlate extends Model
{ {
@ -27,4 +28,11 @@ class ParkingLicensePlate extends Model
{ {
return self::query()->where('id', $id)->value('number') ?? ''; return self::query()->where('id', $id)->value('number') ?? '';
} }
public static function getId($number): array|Collection
{
return self::query()->where('number', 'like', "%{$number}%")->pluck(
'id'
)->toArray();
}
} }

13
app/Models/ParkingSpace.php

@ -4,6 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
class ParkingSpace extends Model class ParkingSpace extends Model
{ {
@ -39,4 +40,16 @@ class ParkingSpace extends Model
strtotime($value) strtotime($value)
); );
} }
public static function getNumber($id)
{
return self::query()->where('id', $id)->value('number');
}
public static function getId($number): array|Collection
{
return self::query()->where('number', 'like', "%{$number}%")->pluck(
'id'
)->toArray();
}
} }

152
app/Services/ParkingInformationService.php

@ -0,0 +1,152 @@
<?php
namespace App\Services;
use App\Models\AdminFloorRegion;
use App\Models\ParkingInformation;
use App\Models\ParkingLicensePlate;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceType;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class ParkingInformationService extends BaseService
{
public function __construct(OperationLogService $logService)
{
parent::__construct($logService);
$logService->menuTitle = 'parking_information';
}
/**
* @param $data
* @return Builder|Model
* @throws Exception
*/
public function createModel($data): Builder|Model
{
try {
DB::beginTransaction();
$license_plate = $data['license_plate'];
$license_plate = ParkingLicensePlate::query()->where(
'number',
$license_plate
)->first(['id', 'space_type_id']);
$license_plate_id = 0;
if ($license_plate) {
$license_plate_id = $license_plate['id'];
$space_type_id = $license_plate['space_type_id'];
} else {
$space_type_data = ParkingSpaceType::getDefaultData();
$space_type_id = $space_type_data['id'] ?? 0;
}
$space_id = 0;
$floor_region_id = 0;
if ($space_type_id) {
$parkingSpaceWhere = [
'space_type_id' => $space_type_id,
'status' => 0,
'license_plate_id' => 0
];
$res = ParkingSpace::query()
->where($parkingSpaceWhere)
->first(['id', 'floor_id']);
if ($res) {
$space_id = $res['id'];
if ($res['floor_id']) {
$floor_region_id = AdminFloorRegion::query()->where(
'floor_id',
$res['floor_id']
)->value('id');
}
}
}
if ($space_id) {
$space = ParkingSpace::query()->where('status', 0)
->where('license_plate_id', 0)->first(
['id', 'floor_id', 'space_type_id']
);
if ($space) {
$space_id = $space['id'];
if (!$space_type_id) {
$space_type_id = $space['space_type_id'];
}
if (!$floor_region_id && $space['floor_id']) {
$floor_region_id = AdminFloorRegion::query()->where(
'floor_id',
$space['floor_id']
)->value('id');
}
}
}
if (!$space_type_id) {
$createData = [
'number' => $license_plate,
'space_type_id' => $space_type_id
];
(new ParkingLicensePlateService(
$this->logService
))->createModel($createData);
$license_plate_id = ParkingLicensePlate::query()->where(
$createData
)->value('id');
}
if (!$license_plate_id) {
throw new Exception(
__('service.parking_information.not_default')
);
}
if (ParkingInformation::query()->where('license_plate_id', $license_plate_id)
->exists()
) {
throw new Exception(__('service.license_plate.number_exists'));
}
$model = ParkingInformation::query()->create([
'floor_region_id' => $floor_region_id,
'space_id' => $space_id,
'license_plate_id' => $license_plate_id,
'entry_time' => get_datetime(),
'space_type_id' => $space_type_id,
'created_at' => get_datetime()
]);
$this->logService->logCreated($model, 'parking_information.create');
DB::commit();
return $model;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
public function deleteModel($id): bool
{
try {
DB::beginTransaction();
$model = ParkingInformation::query()->findOrFail($id);
$this->logService->logDeleted($model, 'parking_information.delete');
$model->delete();
DB::commit();
return true;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
}

2
database/migrations/2026_03_23_143449_create_parking_space_table.php

@ -16,7 +16,7 @@ return new class extends Migration
$table->integer('floor_id')->comment('楼层id'); $table->integer('floor_id')->comment('楼层id');
$table->string('number', 50)->default('')->comment('车位号码'); $table->string('number', 50)->default('')->comment('车位号码');
$table->integer('space_attr_id')->comment('车位属性id'); $table->integer('space_attr_id')->comment('车位属性id');
$table->integer('license_plate_id')->nullable()->comment('车牌号码'); $table->integer('license_plate_id')->default(0)->comment('车牌号码');
$table->timestamp('berthing_time')->nullable()->comment('停泊时间'); $table->timestamp('berthing_time')->nullable()->comment('停泊时间');
$table->string('recognition', 50)->default('')->nullable()->comment('车牌识别度'); $table->string('recognition', 50)->default('')->nullable()->comment('车牌识别度');
$table->tinyInteger('status')->default(0)->comment('状态 0空置 1占用'); $table->tinyInteger('status')->default(0)->comment('状态 0空置 1占用');

33
database/migrations/2026_04_23_143449_create_parking_information_table.php

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('parking_information', function (Blueprint $table) {
$table->id();
$table->integer('floor_region_id')->comment('楼层区域id');
$table->integer('space_id')->default('')->comment('车位id');
$table->integer('license_plate_id')->default('')->comment('车牌id');
$table->integer('space_type_id')->default('')->comment('车位类型id');
$table->timestamp('entry_time')->comment('驶入时间');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('parking_electronic_map');
}
};

3
resources/lang/zh-CN/exception.php

@ -61,5 +61,8 @@ return [
'parking_space' => [ 'parking_space' => [
'update_type_failed' => '修改车位类型失败', 'update_type_failed' => '修改车位类型失败',
'update_attr_failed' => '修改车位属性失败' 'update_attr_failed' => '修改车位属性失败'
],
'parking_information' => [
'create_failed' => '新增失败'
] ]
]; ];

4
resources/lang/zh-CN/log.php

@ -54,5 +54,9 @@ return [
], ],
'map' => [ 'map' => [
'save' => '绘制电子地图保存' 'save' => '绘制电子地图保存'
],
'parking_information' => [
'create' => '创建车位资讯',
'delete' => '更新车位资讯'
] ]
]; ];

3
resources/lang/zh-CN/service.php

@ -51,5 +51,8 @@ return [
'no_cars' => '车位状态无车更新有车', 'no_cars' => '车位状态无车更新有车',
'yes_cars' => '车位状态有车更新无车', 'yes_cars' => '车位状态有车更新无车',
'number_update' => '车牌号更新' 'number_update' => '车牌号更新'
],
'parking_information' => [
'not_default' => '未设置默认车位类型'
] ]
]; ];

6
routes/admin/api.php

@ -18,6 +18,7 @@ use App\Http\Controllers\Admin\TranslationController;
use App\Http\Controllers\Admin\UploadController; use App\Http\Controllers\Admin\UploadController;
use App\Http\Controllers\Admin\UserController; use App\Http\Controllers\Admin\UserController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Admin\ParkingInformationController;
Route::group(['prefix' => 'admin'], function () { Route::group(['prefix' => 'admin'], function () {
@ -73,6 +74,11 @@ Route::group(['prefix' => 'admin'], function () {
Route::get('/map/buildingFloorList', [ParkingElectronicMapController::class, 'buildingFloorList']); Route::get('/map/buildingFloorList', [ParkingElectronicMapController::class, 'buildingFloorList']);
Route::get('/map/parkingSpaceList/{id}', [ParkingElectronicMapController::class, 'getParkingSpaceList']); Route::get('/map/parkingSpaceList/{id}', [ParkingElectronicMapController::class, 'getParkingSpaceList']);
Route::post('/map/save', [ParkingElectronicMapController::class, 'save']); Route::post('/map/save', [ParkingElectronicMapController::class, 'save']);
// 车辆停车资讯
Route::get('/information', [ParkingInformationController::class, 'index']);
Route::get('/information/search', [ParkingInformationController::class, 'search']);
Route::post('/information', [ParkingInformationController::class, 'store']);
Route::delete('/information/{id}', [ParkingInformationController::class, 'destroy']);
// VIP名单 // VIP名单
Route::get('/vipList', [VipListController::class, 'index']); Route::get('/vipList', [VipListController::class, 'index']);

Loading…
Cancel
Save