Browse Source

模式管理

master
wanghongjun 1 day ago
parent
commit
2f6ff5292a
  1. 22
      app/Exports/ParkingPatternModelExport.php
  2. 23
      app/Exports/ParkingPatternSpaceExport.php
  3. 387
      app/Http/Controllers/Admin/ParkingPatternController.php
  4. 304
      app/Http/Controllers/Admin/ParkingPatternSpaceController.php
  5. 3
      app/Imports/ParkingLicensePlateImport.php
  6. 41
      app/Imports/ParkingPatternImport.php
  7. 39
      app/Imports/ParkingPatternSpaceImport.php
  8. 5
      app/Imports/ParkingVipListImport.php
  9. 15
      app/Models/AdminUsers.php
  10. 35
      app/Models/ParkingPattern.php
  11. 34
      app/Models/ParkingPatternSpace.php
  12. 12
      app/Models/ParkingSpace.php
  13. 2
      app/Services/ParkingInformationService.php
  14. 4
      app/Services/ParkingLicensePlateService.php
  15. 245
      app/Services/ParkingPatternService.php
  16. 118
      app/Services/ParkingPatternSpaceService.php
  17. 34
      database/migrations/2026_04_23_143449_create_parking_pattern_space_table.php
  18. 36
      database/migrations/2026_04_23_143449_create_parking_pattern_table.php
  19. 4
      resources/lang/en/admin.php
  20. 4
      resources/lang/zh-CN/admin.php
  21. 5
      resources/lang/zh-CN/exception.php
  22. 6
      resources/lang/zh-CN/service.php
  23. 9
      resources/lang/zh-CN/validation.php
  24. 4
      resources/lang/zh-TW/admin.php
  25. 10
      routes/admin/api.php

22
app/Exports/ParkingPatternModelExport.php

@ -0,0 +1,22 @@
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromArray;
class ParkingPatternModelExport implements FromArray
{
public function array(): array
{
return [
[
'No.',
'Parking Space No.',
'Parking Space Type'
],
['1', 'A0001', 'General'],
['2', 'A0001', 'General'],
['3', 'A0001', 'General'],
];
}
}

23
app/Exports/ParkingPatternSpaceExport.php

@ -0,0 +1,23 @@
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromArray;
class ParkingPatternSpaceExport implements FromArray
{
public function array(): array
{
return [
[
'No.',
'Model Name',
'Parking Space No.',
'Parking Space Type'
],
['1','test_model', 'A0001', 'General'],
['2','test_model', 'A0002', 'General'],
['3','test_model', 'A0003', 'General'],
];
}
}

387
app/Http/Controllers/Admin/ParkingPatternController.php

@ -0,0 +1,387 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Exceptions\CustomException;
use App\Exports\ParkingPatternModelExport;
use App\Exports\ParkingPatternSpaceExport;
use App\Imports\ParkingPatternImport;
use App\Imports\ParkingPatternSpaceImport;
use App\Models\AdminUsers;
use App\Models\ParkingPattern;
use App\Services\ApiResponseService;
use App\Services\ParkingPatternService;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Facades\Excel;
use Psr\SimpleCache\InvalidArgumentException;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
class ParkingPatternController extends BaseController
{
protected ParkingPatternService $service;
/**
* 构造函数
* @param ApiResponseService $responseService
* @param ParkingPatternService $service
*/
public function __construct(
ApiResponseService $responseService,
ParkingPatternService $service
) {
parent::__construct($responseService);
$this->service = $service;
}
public function index(Request $request): JsonResponse
{
try {
$query = ParkingPattern::query();
if ($request->has('model_name')) {
$model_name = $request->input('model_name');
if ($model_name) {
$query->where('name', $model_name);
}
}
if ($request->has('username')) {
$username = $request->input('username');
if ($username) {
$user_ids = AdminUsers::getIds($username);
if ($user_ids) {
$query->whereIn('admin_user_id', $user_ids);
} else {
$query->where('id', 0);
}
}
}
if ($request->has('status')) {
$status = $request->input('status');
if (is_numeric($status)) {
$query->where('status', $status);
}
}
// 分页
$page = $request->input('page', 1);
$perPage = $request->input('per_page', 10);
$columns = [
'id',
'name as model_name',
'admin_user_id',
'status',
'is_default'
];
$statusArr = ParkingPatternService::getStatus();
$isDefaultArr = ParkingPatternService::getIsDefaultArr();
$total = $query->count();
$items = $query->latest()->forPage($page, $perPage)->select(
$columns
)->get()->each(function ($item) use ($statusArr, $isDefaultArr) {
$item['admin_username'] = AdminUsers::getUsername(
$item['admin_user_id']
);
$item['status'] = $statusArr[$item['status']];
$item['is_default'] = $isDefaultArr[$item['is_default']];
unset($item['admin_user_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 = [
'status_list' => get_select_data(
ParkingPatternService::getStatus(),
true
)
];
return $this->responseService->success($data);
} catch (Exception $e) {
$m_prefix = __('exception.exception_handler.resource');
return $this->responseService->systemError(
$m_prefix . ':' . $e->getMessage()
);
}
}
public function edit(string $id): JsonResponse
{
try {
$this->validateId($id, ParkingPattern::class);
$columns = [
'id',
'name as model_name',
'status',
'is_default',
'change',
'release'
];
$item = ParkingPattern::query()->findOrFail($id, $columns);
$data = [
'status_list' => get_select_data(
ParkingPatternService::getStatus()
)
];
$data['item'] = $item;
return $this->responseService->success($data);
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.get_data_failed') . ':' . $e->getMessage()
);
}
}
/**
* @param Request $request
* @param string $id
* @return JsonResponse
* @throws CustomException
* @throws ValidationException
*/
public function update(Request $request, string $id): JsonResponse
{
try {
$data = $request->all();
$rules = [
'model_name' => 'required',
'status' => 'required|in:0,1',
'change' => 'required|in:0,1',
'release' => 'required|in:0,1'
];
$messages = [
'model_name.required' => __(
'validation.parking_pattern.m_empty'
),
'status.required' => __(
'validation.parking_pattern.s_empty'
),
'change.required' => __(
'validation.parking_pattern.c_empty'
),
'release.required' => __(
'validation.parking_pattern.r_empty'
)
];
if ($id) {
$this->validateId($id, ParkingPattern::class);
}
$validator = Validator::make($data, $rules, $messages);
if ($validator->fails()) {
throw new ValidationException($validator);
}
$data['admin_user_id'] = $this->adminUserId;
$this->service->updateModel($data, $id);
return $this->responseService->success(
null,
__('admin.update_succeeded')
);
} catch (ValidationException|CustomException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.parking_pattern.update_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @return BinaryFileResponse
*/
public function importModelTemplate(): BinaryFileResponse
{
return Excel::download(
new ParkingPatternModelExport(),
__('exports.parking_pattern.create_pattern') . time() . '.xlsx'
);
}
/**
* @return BinaryFileResponse
*/
public function importTemplate(): BinaryFileResponse
{
return Excel::download(
new ParkingPatternSpaceExport(),
__('exports.parking_pattern.spaces_pattern') . time() . '.xlsx'
);
}
/**
* 创建导入
* @param Request $request
* @return JsonResponse
* @throws ValidationException
*/
public function import(Request $request): JsonResponse
{
try {
// 1. 验证上传的文件
$data = $request->all();
$request->validate([
'file' => 'required|mimes:xlsx,xls,csv|max:2048', // 限制文件类型和大小
'model_name' => 'required'
]);
$validator = Validator::make($data, [
'file' => 'required|mimes:xlsx,xls,csv|max:2048',
'model_name.required' => __(
'validation.parking_pattern.m_empty'
),
], [
'file.required' => __('validation.admin_list_vip.file_empty'),
'file.mimes' => __('validation.admin_list_vip.file_mimes'),
'file.max' => __('validation.admin_list_vip.file_max'),
]);
if ($validator->fails()) {
throw new ValidationException($validator);
}
$model_name = $data['model_name'];
// 2. 获取上传的文件
$file = $request->file('file');
// 3. 正确的做法:先存储文件,再获取绝对路径进行导入
$path = $file->store('imports');
// 4. 执行导入(使用存储后的绝对路径)
// storage_path('app') 获取 storage/app 的绝对路径
Excel::import(
new ParkingPatternImport($model_name, $this->adminUserId),
storage_path('app/' . $path)
);
// 5. (可选)导入完成后删除临时文件
Storage::delete($path);
return $this->responseService->success(
__('controller.import.success')
);
} catch (ValidationException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.admin_vip_list.import_failed') . ':'
. $e->getMessage()
);
}
}
/**
* 批量导入
* @param Request $request
* @return JsonResponse
* @throws ValidationException
*/
public function batchImport(Request $request): JsonResponse
{
try {
// 1. 验证上传的文件
$data = $request->all();
$request->validate([
'file' => 'required|mimes:xlsx,xls,csv|max:2048' // 限制文件类型和大小
]);
$validator = Validator::make($data, [
'file' => 'required|mimes:xlsx,xls,csv|max:2048'
], [
'file.required' => __('validation.admin_list_vip.file_empty'),
'file.mimes' => __('validation.admin_list_vip.file_mimes'),
'file.max' => __('validation.admin_list_vip.file_max'),
]);
if ($validator->fails()) {
throw new ValidationException($validator);
}
// 2. 获取上传的文件
$file = $request->file('file');
// 3. 正确的做法:先存储文件,再获取绝对路径进行导入
$path = $file->store('imports');
// 4. 执行导入(使用存储后的绝对路径)
// storage_path('app') 获取 storage/app 的绝对路径
Excel::import(
new ParkingPatternSpaceImport($this->adminUserId),
storage_path('app/' . $path)
);
// 5. (可选)导入完成后删除临时文件
Storage::delete($path);
return $this->responseService->success(
__('controller.import.success')
);
} catch (ValidationException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.admin_vip_list.import_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @param string $id
* @return JsonResponse
* @throws ValidationException
*/
public function destroy(string $id): JsonResponse
{
try {
$this->validateId($id, ParkingPattern::class);
$this->service->deleteModel($id);
return $this->responseService->success(
null,
__('admin.delete_succeeded')
);
} catch (ValidationException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.parking_pattern.destroy_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @return JsonResponse
* @throws InvalidArgumentException
*/
public function rule(): JsonResponse
{
try {
return $this->responseService->success(
$this->methodShow('pattern', ['batchImport', 'import'])
);
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.get_data_failed') . ':' . $e->getMessage()
);
}
}
}

304
app/Http/Controllers/Admin/ParkingPatternSpaceController.php

@ -0,0 +1,304 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Exceptions\CustomException;
use App\Models\ParkingPattern;
use App\Models\ParkingPatternSpace;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceType;
use App\Services\ApiResponseService;
use App\Services\ParkingPatternSpaceService;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Psr\SimpleCache\InvalidArgumentException;
class ParkingPatternSpaceController extends BaseController
{
protected ParkingPatternSpaceService $service;
/**
* 构造函数
* @param ApiResponseService $responseService
* @param ParkingPatternSpaceService $service
*/
public function __construct(
ApiResponseService $responseService,
ParkingPatternSpaceService $service
) {
parent::__construct($responseService);
$this->service = $service;
}
public function index(Request $request): JsonResponse
{
try {
$query = ParkingPatternSpace::query();
$pattern_id = $request->input('pattern_id', '');
if ($pattern_id) {
$query->where('pattern_id', $pattern_id);
} else {
throw new Exception('error');
}
if ($request->has('parking_space_number')) {
$parking_space_number = $request->input('parking_space_number');
if ($parking_space_number) {
$space_id = ParkingSpace::getValueId($parking_space_number);
if ($space_id) {
$query->where('space_id', $space_id);
} else {
$query->where('id', 0);
}
}
}
if ($request->has('parking_space_type')) {
$parking_space_type = $request->input('parking_space_type');
if ($parking_space_type) {
$query->where('space_type_id', $parking_space_type);
}
}
// 分页
$page = $request->input('page', 1);
$perPage = $request->input('per_page', 10);
$columns = [
'id',
'space_id',
'space_type_id'
];
$total = $query->count();
$items = $query->latest()->forPage($page, $perPage)->select(
$columns
)->get()->each(function ($item) {
$item['parking_space_number'] = ParkingSpace::getNumber(
$item['space_id']
);
$item['parking_space_type'] = ParkingSpaceType::getName(
$item['space_type_id']
);
unset($item['space_id'], $item['space_type_id']);
return $item;
});
$model_name = ParkingPattern::getName($pattern_id);
$parking_space_count = ParkingSpace::getCount();
$model_parking_space_count = ParkingPatternSpace::getCount(
$pattern_id
);
return $this->responseService->success([
'items' => $items,
'total' => $total,
'page' => $page,
'per_page' => $perPage,
'last_page' => ceil($total / $perPage),
'model_name' => $model_name,
'sum_count' => $parking_space_count,
'use_count' => $model_parking_space_count,
'remaining_count' => $parking_space_count
- $model_parking_space_count,
]);
} catch (Exception $e) {
$m_prefix = __('exception.exception_handler.resource');
return $this->responseService->systemError(
$m_prefix . ':' . $e->getMessage()
);
}
}
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 create(): JsonResponse
{
try {
$data = [
'parking_space_list' => ParkingSpace::getAll(),
'parking_space_type_list' => ParkingSpaceType::getData()
];
return $this->responseService->success($data);
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.get_data_failed') . ':' . $e->getMessage()
);
}
}
/**
* @param Request $request
* @return JsonResponse
* @throws CustomException
* @throws ValidationException
*/
public function store(Request $request): JsonResponse
{
try {
$this->saveValidator($request->all());
$this->service->createModel($request->all());
return $this->responseService->success(
null,
__('admin.save_succeeded')
);
} catch (ValidationException|CustomException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.parking_pattern.create_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @param array $data
* @param int $id
* @return void
* @throws ValidationException
*/
protected function saveValidator(array $data, int $id = 0): void
{
$rules = [
'parking_space_type' => 'required'
];
$messages = [
'parking_space_type.required' => __(
'validation.parking_pattern.type_empty'
),
];
if ($id) {
$this->validateId($id, ParkingPatternSpace::class);
} else {
$rules['pattern_id'] = 'required';
$rules['parking_space_id'] = 'required';
$messages['pattern_id.required'] = __(
'validation.parking_pattern.space_id_empty'
);
$messages['parking_space_id.required'] = __(
'validation.parking_pattern.id_empty'
);
}
$validator = Validator::make($data, $rules, $messages);
if ($validator->fails()) {
throw new ValidationException($validator);
}
}
public function edit($id): JsonResponse
{
try {
$this->validateId($id, ParkingPatternSpace::class);
$columns = [
'id',
'pattern_id',
'space_id as parking_space_id',
'space_type_id as parking_space_type'
];
$item = ParkingPatternSpace::query()->findOrFail($id, $columns);
$data = [
'model_name' => ParkingPattern::getName($item['pattern_id']),
'parking_space_list' => ParkingSpace::getAll(),
'parking_space_type_list' => ParkingSpaceType::getData()
];
$item['parking_space_number'] = ParkingSpace::getNumber(
$item['parking_space_id']
);
$item['parking_space_type_name'] = ParkingSpaceType::getName(
$item['parking_space_type']
);
$data['item'] = $item;
unset($item['pattern_id']);
return $this->responseService->success($data);
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.get_data_failed') . ':' . $e->getMessage()
);
}
}
/**
* @param Request $request
* @param string $id
* @return JsonResponse
* @throws CustomException
* @throws ValidationException
*/
public function update(Request $request, string $id): JsonResponse
{
try {
$data = $request->all();
$this->saveValidator($data, $id);
$this->service->updateModel($data, $id);
return $this->responseService->success(
null,
__('admin.update_succeeded')
);
} catch (ValidationException|CustomException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.parking_pattern.update_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @param string $id
* @return JsonResponse
* @throws ValidationException
*/
public function destroy(string $id): JsonResponse
{
try {
$this->validateId($id, ParkingPatternSpace::class);
$this->service->deleteModel($id);
return $this->responseService->success(
null,
__('admin.delete_succeeded')
);
} catch (ValidationException $e) {
throw $e;
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.parking_pattern.destroy_failed') . ':'
. $e->getMessage()
);
}
}
/**
* @return JsonResponse
* @throws InvalidArgumentException
*/
public function rule(): JsonResponse
{
try {
return $this->responseService->success(
$this->methodShow('patternSpace')
);
} catch (Exception $e) {
return $this->responseService->systemError(
__('exception.get_data_failed') . ':' . $e->getMessage()
);
}
}
}

3
app/Imports/ParkingLicensePlateImport.php

@ -25,7 +25,6 @@ class ParkingLicensePlateImport implements ToModel, WithHeadingRow
/**
* @param array $row
* @return ParkingLicensePlate
*/
public function model(array $row)
{
@ -46,8 +45,6 @@ class ParkingLicensePlateImport implements ToModel, WithHeadingRow
'created_at' => get_datetime()
]);
$this->logService->logCreated($model, 'license_plate.create');
return $model;
}
return new ParkingLicensePlate();
}
}

41
app/Imports/ParkingPatternImport.php

@ -0,0 +1,41 @@
<?php
namespace App\Imports;
use App\Models\ParkingPattern;
use App\Services\OperationLogService;
use App\Services\ParkingPatternService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class ParkingPatternImport implements ToModel, WithHeadingRow
{
protected string $model_name;
protected string $user_id;
public function __construct(string $model_name, string $user_id)
{
$this->model_name = $model_name;
$this->user_id = $user_id;
}
/**
* @param array $row
*/
public function model(array $row)
{
if (!empty($row['parking_space_no']) && !empty($row['parking_space_type'])) {
$data = [
'model_name' => $this->model_name,
'admin_user_id' => $this->user_id,
'parking_space_number' => $row['parking_space_no'],
'parking_space_type' => $row['parking_space_type']
];
$service = new ParkingPatternService(new OperationLogService());
$service->saveModel($data);
}
}
}

39
app/Imports/ParkingPatternSpaceImport.php

@ -0,0 +1,39 @@
<?php
namespace App\Imports;
use App\Models\ParkingPattern;
use App\Services\OperationLogService;
use App\Services\ParkingPatternService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class ParkingPatternSpaceImport implements ToModel, WithHeadingRow
{
protected string $user_id;
public function __construct(string $user_id)
{
$this->user_id = $user_id;
}
/**
* @param array $row
*/
public function model(array $row)
{
if (!empty($row['parking_space_no']) && !empty($row['parking_space_type'])) {
$data = [
'model_name' => $row['model_name'],
'admin_user_id' => $this->user_id,
'parking_space_number' => $row['parking_space_no'],
'parking_space_type' => $row['parking_space_type']
];
$service = new ParkingPatternService(new OperationLogService());
$service->saveModel($data);
}
}
}

5
app/Imports/ParkingVipListImport.php

@ -24,9 +24,8 @@ class ParkingVipListImport implements ToModel, WithHeadingRow
/**
* @param array $row
* @return ParkingVipList
*/
public function model(array $row): ParkingVipList
public function model(array $row)
{
foreach ($row as $license) {
if (!ParkingVipList::query()->where('license', $license)
@ -38,10 +37,8 @@ class ParkingVipListImport implements ToModel, WithHeadingRow
'created_at' => get_datetime()
]);
$this->logService->logCreated($model, 'vip_list.create');
return $model;
}
break;
}
return new ParkingVipList();
}
}

15
app/Models/AdminUsers.php

@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;
use Laravel\Sanctum\HasApiTokens;
class AdminUsers extends Model
@ -65,4 +66,18 @@ class AdminUsers extends Model
{
return self::query()->where('id', $user_id)->value('username');
}
/**
* @param $username
* @return Collection|array
*/
public static function getIds($username): Collection|array
{
$where = [
['status', '=', 1],
['name', 'like', "%{$username}%"]
];
$arr = self::query()->where($where)->pluck('id');
return $arr ?: [];
}
}

35
app/Models/ParkingPattern.php

@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ParkingPattern extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'parking_pattern';
protected $fillable
= [
'name',
'admin_user_id',
'status',
'change',
'release',
'is_default'
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at'
];
public static function getName($id)
{
return self::query()->where('id', $id)->value('name');
}
}

34
app/Models/ParkingPatternSpace.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 ParkingPatternSpace extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'parking_pattern_space';
protected $fillable
= [
'pattern_id',
'space_id',
'space_type_id'
];
protected $hidden
= [
'created_at',
'updated_at',
'deleted_at'
];
public static function getCount($pattern_id)
{
return self::query()->where('pattern_id', $pattern_id)->count();
}
}

12
app/Models/ParkingSpace.php

@ -56,4 +56,16 @@ class ParkingSpace extends Model
{
return self::query()->where('number', $number)->value('id');
}
public static function getCount()
{
return self::query()->count();
}
public static function getAll()
{
return self::query()->orderBy('created_at', 'desc')->select(
['id', 'number']
)->get()->toArray();
}
}

2
app/Services/ParkingInformationService.php

@ -97,7 +97,7 @@ class ParkingInformationService extends BaseService
];
(new ParkingLicensePlateService(
$this->logService
))->create($createData);
))->createModel($createData);
$license_plate_id = ParkingLicensePlate::query()->where(
$createData
)->value('id');

4
app/Services/ParkingLicensePlateService.php

@ -36,7 +36,7 @@ class ParkingLicensePlateService
{
try {
DB::beginTransaction();
$model = $this->create($data);
$model = $this->createData($data);
DB::commit();
return $model;
} catch (Exception $e) {
@ -50,7 +50,7 @@ class ParkingLicensePlateService
* @return Builder|Model
* @throws Exception
*/
public function create($data): Builder|Model
public function createData($data): Builder|Model
{
if (ParkingLicensePlate::query()->where('number', $data['number'])
->exists()

245
app/Services/ParkingPatternService.php

@ -0,0 +1,245 @@
<?php
namespace App\Services;
use App\Models\ParkingPattern as ParkingPatternModel;
use App\Models\ParkingPatternSpace;
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 ParkingPatternService extends BaseService
{
private static array $statusArr = ['disabled', 'enable'];
private static array $isDefaultArr = ['no', 'yes'];
public function __construct(OperationLogService $logService)
{
parent::__construct($logService);
$this->logService->menuTitle = 'model_manage';
}
/**
* @return array|string[]
*/
public static function getStatus(): array
{
$statusArr = self::$statusArr;
foreach ($statusArr as $key => $value) {
$statusArr[$key] = __('admin.' . $value);
}
return $statusArr;
}
/**
* @return array|string[]
*/
public static function getIsDefaultArr(): array
{
$arr = self::$isDefaultArr;
foreach ($arr as $key => $value) {
$arr[$key] = __('service.reservation.' . $value);
}
return $arr;
}
/**
* @param array $data
* @param string $id
* @return Builder|Model
* @throws Exception
*/
public function updateModel(array $data, string $id): Builder|Model
{
try {
DB::beginTransaction();
$existsWhere = [
['name', '=', $data['model_name']],
['id', '<>', $id]
];
if (ParkingPatternModel::query()->where($existsWhere)->exists()) {
throw new Exception(__('service.parking_pattern.name_exists'));
}
$model = $this->updateData($data, $id);
DB::commit();
return $model;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
// 更新
public function updateData($data, $id): Builder|Model
{
$model = ParkingPatternModel::query()->findOrFail($id);
$oldValues = $model->toArray();
$update = [
'name' => $data['model_name'],
'admin_user_id' => $data['admin_user_id'],
'updated_at' => get_datetime()
];
if (isset($data['status']) && is_numeric($data['status'])) {
$update['status'] = $data['status'];
}
if (isset($data['change']) && is_numeric($data['change'])) {
$update['change'] = $data['change'];
}
if (isset($data['release']) && is_numeric($data['release'])) {
$update['release'] = $data['release'];
}
if (isset($data['is_default']) && is_numeric($data['is_default'])) {
$update['is_default'] = $data['is_default'];
}
$model->update($update);
$this->logService->logUpdated(
$model,
$oldValues,
'parking_pattern.update'
);
return $model;
}
/**
* @param array $data
* @return Builder|Model
* @throws Exception
*/
public function createModel(array $data): Builder|Model
{
try {
DB::beginTransaction();
if (ParkingPatternModel::query()->where('name', $data['model_name'])
->exists()
) {
throw new Exception(__('service.parking_pattern.name_exists'));
}
$model = $this->createData($data);
DB::commit();
return $model;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
// 创建
public function createData($data): Model|Builder
{
$model = ParkingPatternModel::query()->create([
'name' => $data['model_name'],
'admin_user_id' => $data['admin_user_id'],
'status' => $data['status'] ?? 1,
'change' => $data['change'] ?? 0,
'release' => $data['release'] ?? 0,
'is_default' => $data['is_default'] ?? 0,
'created_at' => get_datetime(),
'updated_at' => get_datetime()
]);
$this->logService->logCreated($model, 'parking_pattern.create');
return $model;
}
/**
* 保存
* @param $data
* @return bool
*/
public function saveModel($data): bool
{
try {
DB::beginTransaction();
$model_name = $data['model_name'];
$parking_space_number = $data['parking_space_number'];
$parking_space_type = $data['parking_space_type'];
$pattern_id = ParkingPatternModel::query()->where('name', $model_name)->value('id');
if ($pattern_id) {
$this->updateData($data, $pattern_id);
} else {
$this->createData($data);
$pattern_id = ParkingPatternModel::query()->where('name', $model_name)
->value('id');
}
// 验证
$parking_space_id = ParkingSpace::getValueId($parking_space_number);
if (empty($parking_space_id)) {
throw new Exception('');
}
$parking_space_type_id = ParkingSpaceType::getValueId(
$parking_space_type
);
if (empty($parking_space_type_id)) {
throw new Exception('');
}
$pattern_space_id = ParkingPatternSpace::query()->where(
'space_id',
$parking_space_id
)->value('id');
$save = [
'pattern_id' => $pattern_id,
'parking_space_id' => $parking_space_id,
'parking_space_type' => $parking_space_type_id
];
if ($pattern_space_id) {
$ParkingPatternSpace = ParkingPatternSpace::query()->findOrFail($pattern_space_id);
$oldValues = $ParkingPatternSpace->toArray();
$ParkingPatternSpace->update($save);
$this->logService->logUpdated(
$ParkingPatternSpace,
$oldValues,
'parking_pattern_space.update'
);
} else {
(new ParkingPatternSpaceService($this->logService))->createData($save);
}
DB::commit();
return true;
} catch (Exception $e) {
DB::rollBack();
return false;
}
}
public function deleteModel(int $id): bool
{
try {
DB::beginTransaction();
$model = ParkingPatternModel::query()->findOrFail($id);
$this->logService->logDeleted($model, 'parking_pattern.delete');
$model->delete();
$this->delPatternSpace($id);
DB::commit();
return true;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
private function delPatternSpace(int $pattern_id): void
{
$oldAdminRoleMenu = ParkingPatternSpace::getData($pattern_id);
$this->logService->logDeletedData(
new ParkingPatternSpace(),
'parking_pattern_space.delete',
$oldAdminRoleMenu
);
ParkingPatternSpace::query()->where('camera_id', $pattern_id)->delete();
}
}

118
app/Services/ParkingPatternSpaceService.php

@ -0,0 +1,118 @@
<?php
namespace App\Services;
use App\Models\ParkingPatternSpace;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceType;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Model;
class ParkingPatternSpaceService extends BaseService
{
public function __construct(OperationLogService $logService)
{
parent::__construct($logService);
$this->logService->menuTitle = 'model_manage';
}
/**
* @param $data
* @return Builder|Model
* @throws Exception
*/
public function createModel($data): Builder|Model
{
try {
DB::beginTransaction();
if (ParkingPatternSpace::query()->where('space_id', $data['parking_space_id'])
->exists()
) {
throw new Exception(__('service.parking_pattern.space_exists'));
}
if (!ParkingSpace::getNumber($data['parking_space_id'])) {
throw new Exception(__('service.parking_pattern.space_not_exists'));
}
if (!ParkingSpaceType::getName($data['parking_space_type'])) {
throw new Exception(__('service.parking_pattern.type_not_exists'));
}
$model = $this->createData($data);
DB::commit();
return $model;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
/**
* @param $data
* @return Builder|Model
*/
public function createData($data): Builder|Model
{
$save = [
'pattern_id' => $data['pattern_id'],
'space_id' => $data['parking_space_id'],
'space_type_id' => $data['parking_space_type'],
'created_at' => get_datetime(),
'updated_at' => get_datetime()
];
$ParkingPatternSpace = ParkingPatternSpace::query()->create($save);
$this->logService->logCreated(
$ParkingPatternSpace,
'parking_pattern_space.create'
);
return $ParkingPatternSpace;
}
/**
* @param $data
* @param $id
* @return Builder|Builder[]|\Illuminate\Database\Eloquent\Collection|Model|null
* @throws Exception
*/
public function updateModel($data, $id)
{
try {
DB::beginTransaction();
$update = [
'space_type_id' => $data['parking_space_type']
];
$model = ParkingPatternSpace::query()->findOrFail($id);
$oldValues = $model->toArray();
$model->update($update);
$this->logService->logUpdated(
$model,
$oldValues,
'parking_pattern_space.update'
);
DB::commit();
return $model;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
public function deleteModel(int $id): bool
{
try {
DB::beginTransaction();
$model = ParkingPatternSpace::query()->findOrFail($id);
$this->logService->logDeleted($model, 'parking_pattern_space.delete');
$model->delete();
DB::commit();
return true;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
}

34
database/migrations/2026_04_23_143449_create_parking_pattern_space_table.php

@ -0,0 +1,34 @@
<?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_pattern_space', function (Blueprint $table) {
$table->id();
$table->string('name', 50)->comment('活动模式');
$table->integer('pattern_id')->comment('模式id');
$table->integer('space_id')->comment('车位id');
$table->integer('space_type_id')->comment('车位类型id');
$table->timestamps();
$table->softDeletes();
$table->innoDb();
$table->comment('模式管理车位');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('parking_pattern');
}
};

36
database/migrations/2026_04_23_143449_create_parking_pattern_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_pattern', function (Blueprint $table) {
$table->id();
$table->string('name', 50)->comment('活动模式');
$table->integer('admin_user_id')->default(0)->comment('操作员');
$table->tinyInteger('status')->default(1)->comment('状态 0禁用 1启用');
$table->tinyInteger('change')->default(0)->comment('切换离场显示 0显示 1不显示');
$table->tinyInteger('release')->default(0)->comment('释出[优越]车位 0显示 1不显示');
$table->tinyInteger('is_default')->default(0)->comment('默认模式 0否 1是');
$table->timestamps();
$table->softDeletes();
$table->innoDb();
$table->comment('模式管理');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('parking_pattern');
}
};

4
resources/lang/en/admin.php

@ -108,5 +108,7 @@ return [
'next' => 'Next',
'quick_create' => 'Quick create',
'freeze' => 'freeze',
'normal' => 'normal'
'normal' => 'normal',
'enable' => 'enable',
'disabled' => 'disabled'
];

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

@ -107,5 +107,7 @@ return [
'next' => '下一步',
'quick_create' => '快速创建',
'freeze' => '冻结',
'normal' => '正常'
'normal' => '正常',
'enable' => '启用',
'disabled' => '禁用'
];

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

@ -69,5 +69,10 @@ return [
'create_failed' => '新增失败',
'update_failed' => '更新失败',
'destroy_failed' => '删除失败'
],
'parking_pattern' => [
'create_failed' => '新增失败',
'update_failed' => '更新失败',
'destroy_failed' => '删除失败'
]
];

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

@ -59,5 +59,11 @@ return [
'parking_camera' => [
'number_exists' => '设备编号已存在',
'flat_garage' => '平面车库'
],
'parking_pattern' => [
'name_exists' => '活动模式已存在',
'space_exists' => '当前模式车位号已存在',
'space_not_exists' => '当前模式车位号不存在',
'type_not_exists' => '当前模式车位类型不存在'
]
];

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

@ -94,5 +94,14 @@ return [
'p_array' => '车位数据必须是数组',
'lights_ip_empty' => '控灯相机IP不能为空',
'lights_ip_max' => '控灯相机IP最多15个字符'
],
'parking_pattern' => [
'm_empty' => '活动模式不能为空',
's_empty' => '状态不能为空',
'c_empty' => '释放优越车位不能为空',
'r_empty' => '活动模式不能为空',
'id_empty' => '活动模式编号不能为空',
'space_id_empty' => '模式车位号不能为空',
'type_empty' => '模式车位类型不能为空',
]
];

4
resources/lang/zh-TW/admin.php

@ -106,5 +106,7 @@ return [
'next' => '下一步',
'quick_create' => '快速創建',
'freeze' => '凍結',
'normal' => '正常'
'normal' => '正常',
'enable' => '啟用',
'disabled' => '禁用'
];

10
routes/admin/api.php

@ -22,6 +22,7 @@ use App\Http\Controllers\Admin\ParkingInformationController;
use App\Http\Controllers\Admin\ParkingSpaceCatMapController;
use App\Http\Controllers\Admin\ParkingCameraController;
use App\Http\Controllers\Admin\ParkingPatternController;
use App\Http\Controllers\Admin\ParkingPatternSpaceController;
Route::group(['prefix' => 'admin'], function () {
@ -45,6 +46,15 @@ Route::group(['prefix' => 'admin'], function () {
Route::put('/pattern/{id}', [ParkingPatternController::class, 'update']);
Route::post('/pattern/import', [ParkingPatternController::class, 'import']);
Route::post('/pattern/batchImport', [ParkingPatternController::class, 'batchImport']);
Route::get('/pattern/rule', [ParkingPatternController::class, 'rule']);
Route::get('/patternSpace', [ParkingPatternSpaceController::class, 'index']);
Route::get('/patternSpace/search', [ParkingPatternSpaceController::class, 'search']);
Route::get('/patternSpace/create', [ParkingPatternSpaceController::class, 'create']);
Route::post('/patternSpace', [ParkingPatternSpaceController::class, 'store']);
Route::get('/patternSpace/edit/{id}', [ParkingPatternSpaceController::class, 'edit']);
Route::put('/patternSpace/{id}', [ParkingPatternSpaceController::class, 'update']);
Route::delete('/patternSpace/{id}', [ParkingPatternSpaceController::class, 'destroy']);
Route::get('/patternSpace/rule', [ParkingPatternSpaceController::class, 'rule']);
// 车位地图
Route::get('/parkingSpaceMap/search', [ParkingSpaceCatMapController::class, 'search']);

Loading…
Cancel
Save