Browse Source

车位列表、车位预定列表接口

master
wanghongjun 1 month ago
parent
commit
191c10e7a1
  1. 16
      app/Exports/ParkingLicensePlateImportTemplateExport.php
  2. 59
      app/Exports/ParkingSpaceExport.php
  3. 205
      app/Http/Controllers/Admin/ParkingReservationController.php
  4. 247
      app/Http/Controllers/Admin/ParkingSpaceController.php
  5. 50
      app/Imports/ParkingLicensePlateImport.php
  6. 10
      app/Models/AdminFloor.php
  7. 4
      app/Models/AdminFloorRegion.php
  8. 8
      app/Models/AdminOperationLog.php
  9. 5
      app/Models/ParkingLicensePlate.php
  10. 43
      app/Models/ParkingReservation.php
  11. 42
      app/Models/ParkingSpace.php
  12. 10
      app/Models/ParkingSpaceAttributes.php
  13. 11
      app/Models/ParkingSpaceType.php
  14. 20
      app/Services/BaseService.php
  15. 73
      app/Services/ParkingReservationService.php
  16. 150
      app/Services/ParkingSpaceService.php
  17. 1
      app/common.php
  18. 38
      database/migrations/2026_03_20_162930_create_parking_reservation_table.php
  19. 36
      database/migrations/2026_03_23_143449_create_parking_space_table.php
  20. 4
      resources/lang/zh-CN/exception.php
  21. 13
      resources/lang/zh-CN/exports.php
  22. 17
      resources/lang/zh-CN/service.php
  23. 8
      resources/lang/zh-CN/validation.php
  24. 12
      routes/admin/api.php

16
app/Exports/ParkingLicensePlateImportTemplateExport.php

@ -0,0 +1,16 @@
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromArray;
class ParkingLicensePlateImportTemplateExport implements FromArray
{
public function array(): array
{
return [
[__('exports.global.index'), __('exports.vip_list.license')],
['1', '测A88888']
];
}
}

59
app/Exports/ParkingSpaceExport.php

@ -0,0 +1,59 @@
<?php
namespace App\Exports;
use App\Models\ParkingSpace;
use App\Services\OperationLogService;
use App\Services\ParkingSpaceService;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ParkingSpaceExport implements FromArray, WithHeadings
{
public function array(): array
{
$data = [];
ParkingSpace::all()->each(
function ($item) use (&$data) {
$oldItem = (new ParkingSpaceService(
new OperationLogService()
))->optionItems($item);
$data[] = [
'id' => $oldItem['id'],
'floor' => $oldItem['floor'],
'number' => $oldItem['number'],
'space_attr' => $oldItem['space_attr'],
'license_plate' => $oldItem['license_plate'],
'berthing_time' => $oldItem['berthing_time'],
'recognition' => $oldItem['recognition'],
'status' => $oldItem['status'],
'space_type' => $oldItem['space_type'],
'operation_type' => $oldItem['operation_type'],
'updated_at' => $oldItem['updated_at']
];
}
);
return $data;
}
/**
* @return array
*/
public function headings(): array
{
return [
__('exports.global.index'),
__('exports.parking_space.floor'),
__('exports.parking_space.number'),
__('exports.parking_space.space_attr'),
__('exports.parking_space.license_plate'),
__('exports.parking_space.berthing_time'),
__('exports.parking_space.recognition'),
__('exports.parking_space.status'),
__('exports.parking_space.space_type'),
__('exports.parking_space.operation_type'),
__('exports.parking_space.updated_at')
];
}
}

205
app/Http/Controllers/Admin/ParkingReservationController.php

@ -0,0 +1,205 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\AdminFloor;
use App\Models\AdminFloorRegion;
use App\Models\ParkingLicensePlate;
use App\Models\ParkingReservation;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceAttributes;
use App\Models\ParkingSpaceType;
use App\Services\ApiResponseService;
use App\Services\ParkingReservationService;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ParkingReservationController extends Controller
{
/**
* @var ApiResponseService
*/
protected ApiResponseService $responseService;
/**
* @var ParkingReservationService
*/
protected ParkingReservationService $service;
/**
* @param ApiResponseService $responseService
* @param ParkingReservationService $service
*/
public function __construct(
ApiResponseService $responseService,
ParkingReservationService $service
) {
$this->responseService = $responseService;
$this->service = $service;
}
public function index(Request $request): JsonResponse
{
try {
$query = ParkingReservation::query();
// 车牌号码搜索
if ($request->has('license_plate')) {
$license_plate = $request->input('license_plate');
if (!empty($license_plate)) {
$license_plate_id_arr = ParkingLicensePlate::query()->where(
'number',
'like',
"%{$license_plate}%"
)->pluck('id');
$license_plate_id_arr ? $query->whereIn(
'license_plate_id',
$license_plate_id_arr
) : $query->where('id', 0);
}
}
// 楼层
if ($request->has('floor_id')) {
$floor_id = $request->input('floor_id');
if (!empty($floor_id)) {
$query->where('floor_id', $floor_id);
}
}
if ($request->has('space_number')) {
$space_number = $request->input('space_number');
if (!empty($space_number)) {
$license_plate_id_arr = ParkingSpace::query()->where(
'number',
$space_number
)->pluck('license_plate_id');
$license_plate_id_arr ? $query->whereIn(
'license_plate_id',
$license_plate_id_arr
) : $query->where('id', 0);
}
}
if ($request->has('space_type_id')) {
$space_type_id = $request->input('space_type_id');
if (!empty($space_type_id)) {
$query->where('space_type_id', $space_type_id);
}
}
if ($request->has('space_attr_id')) {
$space_attr_id = $request->input('space_attr_id');
if (!empty($space_attr_id)) {
}
}
if ($request->has('status')) {
$status = $request->input('status');
if (!empty($status)) {
$query->where('status', $status);
}
}
// 分页
$page = $request->input('page', 1);
$perPage = $request->input('per_page', 10);
$total = $query->count();
$items = $query->latest()->forPage($page, $perPage)->get()->each(
function ($item) {
$item['status'] = $this->service->getStatusStr(
$item['status']
);
$item['space_type'] = ParkingSpaceType::getName(
$item['space_type_id']
);
$item['license_plate'] = ParkingLicensePlate::getNumber(
$item['license_plate_id']
);
$item['is_driver'] = $this->service->getIsDriver(
$item['is_driver']
);
$item['floor'] = AdminFloor::getName($item['floor_id']);
$item['floor_region'] = AdminFloorRegion::getName($item['floor_region_id']);
unset(
$item['space_type_id'],
$item['license_plate_id'],
$item['floor_id'],
$item['floor_region_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()
);
}
}
public function search(): JsonResponse
{
try {
$data = [
'floor_data' => AdminFloor::getData(),
'space_type_data' => ParkingSpaceType::getData(),
'space_attr_data' => ParkingSpaceAttributes::getData(),
'status_data' => get_select_data(
$this->service->getStatusArr()
)
];
return $this->responseService->success($data);
} catch (Exception $e) {
$m_prefix = __('exception.exception_handler.resource');
return $this->responseService->systemError(
$m_prefix . ':' . $e->getMessage()
);
}
}
public function statistics(Request $request): JsonResponse
{
try {
$start_at = date("Y-m-d 00:00:00");
$end_at = date("Y-m-d 23:59:59");
if ($request->has('appointment_date')) {
$appointment_date = $request->input('appointment_date');
if (!empty($appointment_date)) {
$start_at = date(
"Y-m-d 00:00:00",
strtotime($appointment_date)
);
$end_at = date(
"Y-m-d 23:59:59",
strtotime($appointment_date)
);
}
}
$today_count = $this->service->getCount($start_at, $end_at);
$present_count = $this->service->getBePresentCount(
$start_at,
$end_at
);
$absent_count = $today_count - $present_count;
$data = [
'today_count' => $today_count,
'present_count' => $present_count,
'absent_count' => max($absent_count, 0)
];
return $this->responseService->success($data);
} catch (Exception $e) {
$m_prefix = __('exception.exception_handler.resource');
return $this->responseService->systemError(
$m_prefix . ':' . $e->getMessage()
);
}
}
}

247
app/Http/Controllers/Admin/ParkingSpaceController.php

@ -0,0 +1,247 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Exports\ParkingSpaceExport;
use App\Http\Controllers\Controller;
use App\Models\AdminFloor;
use App\Models\ParkingLicensePlate;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceAttributes;
use App\Models\ParkingSpaceType;
use App\Services\ApiResponseService;
use App\Services\ParkingSpaceService;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Facades\Excel;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
class ParkingSpaceController extends Controller
{
/**
* @var ApiResponseService
*/
protected ApiResponseService $responseService;
/**
* @var ParkingSpaceService
*/
protected ParkingSpaceService $service;
/**
* @param ApiResponseService $responseService
* @param ParkingSpaceService $service
*/
public function __construct(
ApiResponseService $responseService,
ParkingSpaceService $service
) {
$this->responseService = $responseService;
$this->service = $service;
}
/**
* Display a listing of the resource.
*/
public function index(Request $request): JsonResponse
{
try {
$query = ParkingSpace::query();
if ($request->has('license_plate')) {
$license_plate = $request->input('license_plate');
if (!empty($license_plate)) {
$license_plate_id_arr = ParkingLicensePlate::query()->where(
'number',
'like',
"%{$license_plate}%"
)->pluck('id');
$license_plate_id_arr ? $query->whereIn(
'license_plate_id',
$license_plate_id_arr
) : $query->where('id', 0);
}
}
if ($request->has('floor')) {
$floor = $request->input('floor');
if (!empty($floor)) {
$query->where('floor_id', $floor);
}
}
if ($request->has('number')) {
$number = $request->input('number');
if (!empty($number)) {
$query->where('number', 'like', "%{$number}%");
}
}
if ($request->has('space_type')) {
$space_type = $request->input('space_type');
if (!empty($space_type)) {
$query->where('space_type_id', $space_type);
}
}
if ($request->has('space_attr')) {
$space_attr = $request->input('space_attr');
if (!empty($space_attr)) {
$query->where('space_attr_id', $space_attr);
}
}
if ($request->has('status')) {
$status = $request->input('status');
if (!empty($status)) {
$query->where('status', $status);
}
}
// 分页
$page = $request->input('page', 1);
$perPage = $request->input('per_page', 10);
$query->orderBy('id');
$total = $query->count();
$_this = $this;
$items = $query->latest()->forPage($page, $perPage)->get()->each(
function ($item) use ($_this) {
return $_this->service->optionItems($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 = [
'floor_data' => AdminFloor::query()->select(['id', 'name'])
->get()->toArray(),
'space_type_data' => ParkingSpaceType::query()->select(
['id', 'name']
)->get()->toArray(),
'space_attr_data' => ParkingSpaceAttributes::query()->select(
['id', 'attributes']
)->get()->toArray(),
'status_data' => get_select_data(
$this->service->getStatusArr()
)
];
return $this->responseService->success($data);
} catch (Exception $e) {
$m_prefix = __('exception.exception_handler.resource');
return $this->responseService->systemError(
$m_prefix . ':' . $e->getMessage()
);
}
}
public function updateType(Request $request): JsonResponse
{
try {
$rules = [
'space_type_id' => 'required|numeric',
'space_ids' => 'required|array'
];
$messages = [
'space_type_id.required' => __(
'validation.parking_space.type_id_empty'
),
'space_type_id.numeric' => __(
'validation.parking_space.type_id_numeric'
),
'space_ids.required' => __(
'validation.parking_space.ids_empty'
),
'space_ids.array' => __(
'validation.parking_space.ids_array'
)
];
$validator = Validator::make($request->all(), $rules, $messages);
if ($validator->fails()) {
throw new ValidationException($validator);
}
$this->service->updateData($request->all());
return $this->responseService->success(
null,
__('admin.update_succeeded')
);
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.parking_space.update_type_failed') . ':'
. $e->getMessage()
);
}
}
public function updateAttr(Request $request): JsonResponse
{
try {
$rules = [
'space_attr_id' => 'required|numeric',
'space_ids' => 'required|array'
];
$messages = [
'space_attr_id.required' => __(
'validation.parking_space.attr_id_empty'
),
'space_attr_id.numeric' => __(
'validation.parking_space.attr_id_numeric'
),
'space_ids.required' => __(
'validation.parking_space.ids_empty'
),
'space_ids.array' => __(
'validation.parking_space.ids_array'
)
];
$validator = Validator::make($request->all(), $rules, $messages);
if ($validator->fails()) {
throw new ValidationException($validator);
}
$this->service->updateData($request->all(), 'space_attr_id');
return $this->responseService->success(
null,
__('admin.update_succeeded')
);
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.parking_space.update_attr_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @return BinaryFileResponse
*/
public function export(): BinaryFileResponse
{
return Excel::download(
new ParkingSpaceExport(),
__('exports.parking_space.list') . time() . '.xlsx'
);
}
}

50
app/Imports/ParkingLicensePlateImport.php

@ -0,0 +1,50 @@
<?php
namespace App\Imports;
use App\Models\ParkingLicensePlate;
use App\Services\OperationLogService;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class ParkingLicensePlateImport implements ToModel, WithHeadingRow
{
/**
* @var OperationLogService
*/
private OperationLogService $logService;
public function __construct()
{
$this->logService = new OperationLogService();
}
/**
* @param array $row
* @return ParkingLicensePlate
*/
public function model(array $row): ParkingLicensePlate
{
$data = [];
foreach ($row as $value) {
$data[] = $value;
}
$where = [
'number' => $data[0],
'space_type_id' => $data[1]
];
if (!ParkingLicensePlate::query()->where($where)
->exists()
) {
$model = new ParkingLicensePlate([
'number' => $data[0],
'space_type_id' => $data[1],
'created_at' => get_datetime()
]);
$this->logService->logCreated($model, '创建车牌号码');
return $model;
}
return new ParkingLicensePlate();
}
}

10
app/Models/AdminFloor.php

@ -24,5 +24,13 @@ class AdminFloor extends Model
'deleted_at'
];
public static function getName($id)
{
return self::query()->where('id', $id)->value('name') ?? '';
}
public static function getData(): array
{
return self::query()->select(['id', 'name'])->get()->toArray();
}
}

4
app/Models/AdminFloorRegion.php

@ -38,4 +38,8 @@ class AdminFloorRegion extends Model
return $count != $existsCount;
}
public static function getName($id)
{
return self::query()->where('id', $id)->value('name') ?? '';
}
}

8
app/Models/AdminOperationLog.php

@ -41,14 +41,6 @@ class AdminOperationLog extends Model
'updated_at'
];
/**
* 获取进行此操作的用户
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* 获取关联的模型
*/

5
app/Models/ParkingLicensePlate.php

@ -22,4 +22,9 @@ class ParkingLicensePlate extends Model
'updated_at',
'deleted_at'
];
public static function getNumber($id)
{
return self::query()->where('id', $id)->value('number') ?? '';
}
}

43
app/Models/ParkingReservation.php

@ -0,0 +1,43 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ParkingReservation extends Model
{
use HasFactory;
protected $table = 'parking_reservation';
protected $fillable
= [
'reserve_id',
'space_type_id',
'license_plate_type',
'license_plate_id',
'is_driver',
'floor_id',
'floor_region_id',
'status',
'confirm_at'
];
protected $hidden
= [
'updated_at'
];
public function getCreatedAtAttribute($value): string
{
return get_datetime('date_time', strtotime($value));
}
public function getConfirmAtAttribute($value): string
{
return is_null($value)
? ''
: get_datetime('date_time', strtotime($value));
}
}

42
app/Models/ParkingSpace.php

@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ParkingSpace extends Model
{
use HasFactory;
protected $table = 'parking_space';
protected $fillable
= [
'floor_id',
'number',
'space_attr_id',
'license_plate_id',
'berthing_time',
'recognition',
'status',
'space_type_id',
'operation_type'
];
protected $hidden
= [
'created_at'
];
public function getUpdatedAtAttribute($value): string
{
return is_null($value)
? ''
: get_datetime(
'date_time',
strtotime($value)
);
}
}

10
app/Models/ParkingSpaceAttributes.php

@ -32,4 +32,14 @@ class ParkingSpaceAttributes extends Model
['id', 'attributes']
)->toArray();
}
public static function getAttr($id)
{
return self::query()->where('id', $id)->value('attributes') ?? '';
}
public static function getData(): array
{
return self::query()->select(['id', 'attributes'])->get()->toArray();
}
}

11
app/Models/ParkingSpaceType.php

@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
class ParkingSpaceType extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'parking_space_type';
protected $fillable
= [
@ -31,4 +32,14 @@ class ParkingSpaceType extends Model
'updated_at',
'deleted_at'
];
public static function getName($id)
{
return self::query()->where('id', $id)->value('name') ?? '';
}
public static function getData(): array
{
return self::query()->select(['id', 'name'])->get()->toArray();
}
}

20
app/Services/BaseService.php

@ -0,0 +1,20 @@
<?php
namespace App\Services;
class BaseService
{
/**
* @var OperationLogService
*/
protected OperationLogService $logService;
/**
* 构造函数
* @param OperationLogService $logService
*/
public function __construct(OperationLogService $logService)
{
$this->logService = $logService;
}
}

73
app/Services/ParkingReservationService.php

@ -0,0 +1,73 @@
<?php
namespace App\Services;
use App\Models\ParkingReservation;
use App\Models\ParkingSpace;
class ParkingReservationService extends BaseService
{
/**
* @var string[]
*/
public array $statusArr = ['undetermined', 'confirmed', 'canceled'];
public array $isDriver = ['no', 'yes'];
/**
* 返回翻译后的状态
* @param $status
* @return string
*/
public function getStatusStr($status): string
{
$value = $this->statusArr[$status] ?? '';
if ($value) {
return __('service.reservation.' . $value);
}
return $value;
}
public function getStatusArr(): array
{
$arr = [];
foreach ($this->statusArr as $key => $value) {
$arr[$key] = __('service.reservation.' . $value);
}
return $arr;
}
public function getIsDriver($is_driver): string
{
$value = $this->isDriver[$is_driver] ?? '';
if ($value) {
return __('service.reservation.' . $value);
}
return $value;
}
/**
* @param string $start
* @param string $end
* @return int
*/
public function getCount(string $start, string $end): int
{
return ParkingReservation::query()->whereBetween(
'confirm_at',
[$start, $end]
)->where('status', 1)->count();
}
public function getBePresentCount(string $start, string $end): int
{
$license_plate_id_arr = ParkingReservation::query()->whereBetween(
'confirm_at',
[$start, $end]
)->where('status', 1)->pluck('license_plate_id');
return ParkingSpace::query()->whereIn(
'license_plate_id',
$license_plate_id_arr
)->count();
}
}

150
app/Services/ParkingSpaceService.php

@ -0,0 +1,150 @@
<?php
namespace App\Services;
use App\Models\AdminFloor;
use App\Models\ParkingLicensePlate;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceAttributes;
use App\Models\ParkingSpaceType;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
class ParkingSpaceService extends BaseService
{
/**
* @var string[]
*/
protected array $statusArr = ['vacant', 'occupy'];
protected array $operationType
= [
'',
'no_cars',
'yes_cars',
'number_update'
];
public function __construct(OperationLogService $logService)
{
parent::__construct($logService);
}
/**
* 返回翻译后的状态
* @param $status
* @return string
*/
public function getStatusStr($status): string
{
$value = $this->statusArr[$status] ?? '';
if ($value) {
return __('service.parking_space.' . $value);
}
return $value;
}
public function getRecognition($recognition): string
{
if ($recognition) {
return __('service.parking_space.' . $recognition);
}
return '-';
}
public function getOperationType($operation_type): string
{
$value = $this->operationType[$operation_type] ?? '';
if ($value) {
return __('service.parking_space.' . $value);
}
return '-';
}
public function getStatusArr(): array
{
$arr = [];
foreach ($this->statusArr as $key => $value) {
$arr[$key] = __('service.parking_space.' . $value);
}
return $arr;
}
public function optionItems($item)
{
$item['floor'] = AdminFloor::getName($item['floor_id']);
$item['space_attr'] = ParkingSpaceAttributes::getAttr(
$item['space_attr_id']
);
$item['space_type'] = ParkingSpaceType::getName(
$item['space_type_id']
);
$license_plate = ParkingLicensePlate::getNumber(
$item['license_plate_id']
);
$item['license_plate'] = $license_plate ?: '-';
$item['berthing_time'] = is_null($item['berthing_time'])
? '-' : $item['berthing_time'];
$item['recognition'] = $this->getRecognition(
$item['recognition']
);
$item['status'] = $this->getStatusStr(
$item['status']
);
$item['operation_type'] = $this->getOperationType(
$item['operation_type']
);
unset(
$item['floor_id'], $item['space_attr_id'],
$item['space_type_id'], $item['license_plate_id']
);
return $item;
}
/**
* 更新车位数据
* @param array $data
* @param string $key
* @return Builder
* @throws Exception
*/
public function updateData(
array $data,
string $key = 'space_type_id'
): Builder {
try {
DB::beginTransaction();
$ids = $data['space_ids'];
$data_id = $data[$key];
$model = ParkingSpace::query()->whereIn('id', $ids)->select();
$oldValues = $model->get()->toArray();
$updateData = [
$key => $data_id,
'updated_at' => get_datetime()
];
$model->update($updateData);
$str = $key == 'space_type_id' ? '类型' : '属性';
$newValue = $oldValues;
$newValue[$key] = $data_id;
$newValue['updated_at'] = $updateData['updated_at'];
$this->logService->logUpdatedData(
new ParkingSpace(),
$oldValues,
"更新车位" . $str,
$newValue
);
DB::commit();
return $model;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
}

1
app/common.php

@ -35,6 +35,7 @@ if (!function_exists('get_datetime')) {
$format = match ($type) {
'date' => 'Y-m-d',
'datetime' => 'Y-m-d H:i:s',
'date_time' => 'Y-m-d H:i'
};
return date($format, $times);
}

38
database/migrations/2026_03_20_162930_create_parking_reservation_table.php

@ -0,0 +1,38 @@
<?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_reservation', function (Blueprint $table) {
$table->id();
$table->string('reserve_id', 12)->comment('预定编号');
$table->integer('space_type_id')->comment('车位类型');
$table->integer('license_plate_type')->comment('车牌类型');
$table->integer('license_plate_id')->comment('车牌号码ID');
$table->tinyInteger('is_driver')->default(0)->comment('是否登记司机');
$table->integer('floor_id')->nullable()->comment('楼层ID');
$table->integer('floor_region_id')->nullable()->comment('楼层区域ID');
$table->tinyInteger('status')->default(0)->comment('状态 0待确定 1已确定 2已取消');
$table->timestamp('confirm_at')->nullable()->comment('确定时间');
$table->timestamps();
$table->comment('车位预定列表');
$table->innoDb();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('parking_reservation');
}
};

36
database/migrations/2026_03_23_143449_create_parking_space_table.php

@ -0,0 +1,36 @@
<?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_space', function (Blueprint $table) {
$table->id();
$table->integer('floor_id')->comment('楼层id');
$table->string('number', 50)->default('')->comment('车位号码');
$table->integer('space_attr_id')->comment('车位属性id');
$table->integer('license_plate_id')->nullable()->comment('车牌号码');
$table->timestamp('berthing_time')->nullable()->comment('停泊时间');
$table->string('recognition', 50)->default('')->nullable()->comment('车牌识别度');
$table->tinyInteger('status')->default(0)->comment('状态 0空置 1占用');
$table->integer('space_type_id')->comment('车位类型id');
$table->tinyInteger('operation_type')->default(0)->comment('操作类型');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('parking_space');
}
};

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

@ -57,5 +57,9 @@ return [
'update_failed' => '更新车牌号码失败',
'destroy_failed' => '删除车牌号码失败',
'clear_failed' => '清除车牌号码失败'
],
'parking_space' => [
'update_type_failed' => '修改车位类型失败',
'update_attr_failed' => '修改车位属性失败'
]
];

13
resources/lang/zh-CN/exports.php

@ -11,5 +11,18 @@ return [
],
'license_plate' => [
'import_template' => '车牌管理导入模板'
],
'parking_space' => [
'list' => '车位列表',
'floor' => '楼层',
'number' => '车位号码',
'space_attr' => '车位属性',
'license_plate' => '车牌号码',
'berthing_time' => '停泊时间',
'recognition' => '车牌识别度',
'status' => '状态',
'space_type' => '车位类型',
'operation_type' => '操作类型',
'updated_at' => '最后更新时间',
]
];

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

@ -34,5 +34,22 @@ return [
'license_plate' => [
'number_exists' => '车牌号码已存在',
'not_clear' => '没有车牌需要清除'
],
'reservation' => [
'undetermined' => '待确定',
'confirmed' => '已确定',
'canceled' => '已取消',
'yes' => '是',
'no' => '否'
],
'parking_space' => [
'vacant' => '空置',
'occupy' => '占用',
'high' => '高',
'middle' => '中',
'land' => '低',
'no_cars' => '车位状态无车更新有车',
'yes_cars' => '车位状态有车更新无车',
'number_update' => '车牌号更新'
]
];

8
resources/lang/zh-CN/validation.php

@ -68,5 +68,13 @@ return [
'license_plate' => [
'n_empty' => '车牌号码不能为空',
'type_empty' => '车位类型不能为空'
],
'type_id_empty' => [
'type_id_empty' => '车位类型数据不能为空',
'type_id_numeric' => '车位类型数据必须是数字',
'attr_id_empty' => '车位属性数据不能为空',
'attr_id_numeric' => '车位属性数据必须是数字',
'ids_empty' => '车位数据不能为空',
'ids_array' => '车位数据必须是数组',
]
];

12
routes/admin/api.php

@ -8,6 +8,8 @@ use App\Http\Controllers\Admin\VipAccessRecordController;
use App\Http\Controllers\Admin\VipListController;
use App\Http\Controllers\Admin\OperationLogController;
use App\Http\Controllers\Admin\ParkingLicensePlateController;
use App\Http\Controllers\Admin\ParkingReservationController;
use App\Http\Controllers\Admin\ParkingSpaceController;
use App\Http\Controllers\Admin\ParkingSpaceAttributesController;
use App\Http\Controllers\Admin\ParkingSpaceTypeController;
use App\Http\Controllers\Admin\RolesController;
@ -31,6 +33,15 @@ Route::group(['prefix' => 'admin'], function () {
// 首页
Route::get('/index', [IndexController::class, 'index']);
Route::get('/menu', [IndexController::class, 'menu']);
// 车位预定列表
Route::get('/parkingReservation', [ParkingReservationController::class, 'index']);
Route::get('/parkingReservation/search', [ParkingReservationController::class, 'search']);
Route::get('/parkingReservation/statistics', [ParkingReservationController::class, 'statistics']);
// 车位列表
Route::get('/parkingSpace', [ParkingSpaceController::class, 'index']);
Route::get('/parkingSpace/search', [ParkingSpaceController::class, 'search']);
Route::post('parkingSpace/updateType', [ParkingSpaceController::class, 'updateType']);
Route::post('parkingSpace/updateAttr', [ParkingSpaceController::class, 'updateAttr']);
//车位类型管理
Route::get('/spaceType', [ParkingSpaceTypeController::class, 'index']);
Route::get('/spaceType/create', [ParkingSpaceTypeController::class, 'create']);
@ -112,4 +123,5 @@ Route::group(['prefix' => 'admin'], function () {
Route::get('/vipList/import_template', [VipListController::class, 'importTemplate']);
Route::get('/vipList/export', [VipListController::class, 'export']);
Route::get('/licensePlate/import_template', [ParkingLicensePlateController::class, 'importTemplate']);
Route::get('/parkingSpace/export', [ParkingSpaceController::class, 'export']);
});

Loading…
Cancel
Save