Browse Source

停车历史导出优化

master
wanghongjun 3 weeks ago
parent
commit
471f7acac7
  1. 62
      app/Exports/UtilizationRateExport.php
  2. 138
      app/Http/Controllers/Admin/UtilizationRateController.php
  3. 4
      app/Models/ParkingAccessRecord.php
  4. 30
      app/Models/ParkingUtilizationRate.php
  5. 91
      app/Services/UtilizationRateService.php
  6. 2
      database/migrations/2026_03_04_160517_create_parking_vip_access_record_table.php
  7. 34
      database/migrations/2026_08_21_143449_create_parking_utilization_rate_table.php
  8. 3
      resources/lang/en/exports.php
  9. 3
      resources/lang/zh-CN/exports.php
  10. 3
      resources/lang/zh-TW/exports.php
  11. 9
      routes/admin/api.php

62
app/Exports/UtilizationRateExport.php

@ -0,0 +1,62 @@
<?php
namespace App\Exports;
use App\Services\OperationLogService;
use App\Services\UtilizationRateService;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithHeadings;
class UtilizationRateExport implements FromArray, WithHeadings
{
public array $parents = [];
public UtilizationRateService $service;
public function __construct($parents)
{
$this->parents = $parents;
$this->service = new UtilizationRateService(
new OperationLogService()
);
}
public function array(): array
{
$data = [];
$index = 1;
$query = $this->service->searchQuery($this->parents);
$list = $query->select()->get()->toArray();
foreach ($list as $item) {
$item = $this->service->getItem($item);
$data[] = [
'index' => $index,
'start_time' => $item['start_time'],
'end_time' => $item['end_time'],
'floor' => $item['floor'],
'number' => $item['number'],
'space_type' => $item['space_type'],
'space_attr' => $item['space_attr'],
'rate' => $item['rate']
];
$index += 1;
}
return $data;
}
/**
* @return array
*/
public function headings(): array
{
return [
__('exports.global.index'),
__('exports.event_calendar.export3'),
__('exports.event_calendar.export5'),
__('exports.parking_space.floor'),
__('exports.parking_space.number'),
__('exports.parking_space.space_type'),
__('exports.parking_space.space_attr'),
__('exports.utilization_rate.rate'),
];
}
}

138
app/Http/Controllers/Admin/UtilizationRateController.php

@ -0,0 +1,138 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Exports\UtilizationRateExport;
use App\Models\AdminFloor;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceType;
use App\Models\ParkingUtilizationRate;
use App\Services\ApiResponseService;
use App\Services\UtilizationRateService;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
class UtilizationRateController extends BaseController
{
protected string $menuUri = 'utilizationRate';
/**
* @var UtilizationRateService
*/
protected UtilizationRateService $service;
/**
* 构造函数
* @param ApiResponseService $responseService
* @param UtilizationRateService $service
*/
public function __construct(
ApiResponseService $responseService,
UtilizationRateService $service
) {
parent::__construct($responseService);
$this->service = $service;
}
public function index(Request $request): JsonResponse
{
try {
$query = $this->service->searchQuery($request->all());
// 分页
$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) {
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 illustration(Request $request): JsonResponse
{
try {
$data = [];
$query = $this->service->searchQuery($request->all());
$list = $query->select()->get()->toArray();
$tempData = [];
foreach ($list as $item) {
$date_type = $item['date_type'];
$format = 'H:i';
if ($date_type == 2) {
$format = 'm/d';
}
$key = date($format, strtotime($item['end_time']));
$tempData[$key][] = $item['rate'];
}
foreach ($tempData as $date => $value) {
$count = count($value);
$sum = 0;
foreach ($value as $val) {
$sum += $val;
}
$rate = 0;
if ($sum > 0) {
$rate = round($sum / $count, 2);
}
$data[] = [
'time' => $date,
'rate' => $rate
];
}
return $this->responseService->success($data);
} catch (Exception $e) {
$m_prefix = __('exception.exception_handler.resource');
return $this->responseService->systemError(
$m_prefix . ':' . $e->getMessage()
);
}
}
public function search(): JsonResponse
{
try {
$data = [
'floor_list' => AdminFloor::getData(),
'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()
);
}
}
/**
* @param Request $request
* @return BinaryFileResponse
*/
public function export(Request $request): BinaryFileResponse
{
return Excel::download(
new UtilizationRateExport($request->all()),
set_space_underline(__('exports.access_record.list'))
. get_datetime('date_')
. '.xlsx'
);
}
}

4
app/Models/ParkingAccessRecord.php

@ -30,12 +30,12 @@ class ParkingAccessRecord extends Model
public function getEnterTimeAttribute($value): string
{
return get_datetime('datetime', $value);
return date('Y-m-d H:i:s', $value);
}
public function getLeaveTimeAttribute($value): string
{
return $value ? get_datetime('datetime', $value) : '';
return $value ? date('Y-m-d H:i:s', $value) : '';
}
}

30
app/Models/ParkingUtilizationRate.php

@ -0,0 +1,30 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ParkingUtilizationRate extends Model
{
use HasFactory;
protected $table = 'parking_utilization_rate';
public $timestamps = false;
protected $fillable
= [
'space_id',
'start_time',
'end_time',
'date_type',
'rate'
];
protected $hidden
= [
'created_at',
'updated_at'
];
}

91
app/Services/UtilizationRateService.php

@ -0,0 +1,91 @@
<?php
namespace App\Services;
use App\Models\AdminFloor;
use App\Models\ParkingSpace;
use App\Models\ParkingSpaceAttributes;
use App\Models\ParkingSpaceType;
use App\Models\ParkingUtilizationRate;
use Illuminate\Database\Eloquent\Builder;
class UtilizationRateService extends BaseService
{
protected string $menuTitle = 'utilization_rate';
public function getItem($item)
{
$item['floor'] = '';
$item['number'] = '';
$item['space_type'] = '';
$item['space_attr'] = '';
$parkingSpace = ParkingSpace::query()->find(
$item['space_id']
);
if ($parkingSpace) {
$item['floor'] = AdminFloor::getName(
$parkingSpace['floor_id']
);
$item['number'] = $parkingSpace['number'];
$item['space_type'] = ParkingSpaceType::getName(
$parkingSpace['space_type_id']
);
$item['space_attr'] = ParkingSpaceAttributes::getAttr(
$parkingSpace['space_attr_id']
);
}
$item['rate'] = rtrim($item['rate'], ' ') . '%';
$format = $item['date_type'] == 1 ? 'Y/m/d H:i' : 'Y/m/d';
$item['start_time'] = date($format, strtotime($item['start_time']));
$item['end_time'] = date($format, strtotime($item['end_time']));
unset($item['space_id'], $item['date_type']);
return $item;
}
/**
* @param $parents
* @return Builder
*/
public function searchQuery($parents): Builder
{
$query = ParkingUtilizationRate::query();
$start_time = $parents['start_time'] ??
get_datetime('date') . ' 00:00:00';
$ent_time = $parents['end_time'] ??
get_datetime('date') . ' 23:59:59';
$start_date = get_datetime('date', strtotime($start_time));
$end_date = get_datetime('date', strtotime($ent_time));
$date_type = $start_date == $end_date ? 1 : 2;
$query->where('date_type', $date_type);
$query->where('start_time', '>=', $start_time);
$query->where('end_time', '<', $ent_time);
$spaceIdsWhere = [];
if (isset($parents['floor_id']) && $parents['floor_id']) {
$spaceIdsWhere['floor_id'] = $parents['floor_id'];
}
if (isset($parents['number']) && $parents['number']) {
$spaceIdsWhere['number'] = $parents['number'];
}
if (isset($parents['parking_space_type'])
&& $parents['parking_space_type']
) {
$spaceIdsWhere['space_type_id'] = $parents['parking_space_type'];
}
if ($spaceIdsWhere) {
$spaceIds = ParkingSpace::query()->where($spaceIdsWhere)->pluck(
'id'
);
if ($spaceIds) {
$query->whereIn('space_id', $spaceIds);
} else {
$query->where('id', 0);
}
}
return $query;
}
}

2
database/migrations/2026_03_04_160517_create_parking_vip_access_record_table.php

@ -29,6 +29,6 @@ return new class extends Migration
*/
public function down(): void
{
Schema::dropIfExists('admin_vip_access_record');
Schema::dropIfExists('parking_vip_access_record');
}
};

34
database/migrations/2026_08_21_143449_create_parking_utilization_rate_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_utilization_rate', function (Blueprint $table) {
$table->id();
$table->integer('space_id')->comment('车位id');
$table->dateTime('start_time')->comment('开始时间');
$table->dateTime('end_time')->comment('结束时间');
$table->tinyInteger('date_type')->default(1)->comment('类型 1小时 2天');
$table->float('rate', 5)->comment('使用率');
$table->timestamp('created_at');
$table->index('space_id', 'space_id');
$table->comment('车位使用率');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('parking_utilization_rate');
}
};

3
resources/lang/en/exports.php

@ -120,5 +120,8 @@ return [
'leave_time' => 'Leave Time',
'duration' => 'Parking duration (mins)',
'status' => 'Vehicle status (entering/exiting)'
],
'utilization_rate' => [
'rate' => 'Usage Rate'
]
];

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

@ -120,5 +120,8 @@ return [
'leave_time' => '离开车位时间',
'duration' => '停车时长(mins)',
'status' => '车辆状态(入/出)'
],
'utilization_rate' => [
'rate' => '使用率'
]
];

3
resources/lang/zh-TW/exports.php

@ -120,5 +120,8 @@ return [
'leave_time' => '離開車位時間',
'duration' => '停車時長(mins)',
'status' => '車輛狀態(入/出)'
],
'utilization_rate' => [
'rate' => '使用率'
]
];

9
routes/admin/api.php

@ -43,6 +43,7 @@ use App\Http\Controllers\Admin\ParkingSpaceRepairController;
use App\Http\Controllers\Admin\ParkingGateControlController;
use App\Http\Controllers\Admin\ProhibitedPassageController;
use App\Http\Controllers\Admin\ParkingAccessRecordController;
use App\Http\Controllers\Admin\UtilizationRateController;
Route::group(['prefix' => 'admin'], function () {
@ -251,11 +252,17 @@ Route::group(['prefix' => 'admin'], function () {
Route::get('/parkingBehavior', [ParkingBehaviorController::class, 'index']);
Route::get('/parkingBehavior/rule', [ParkingBehaviorController::class, 'rule']);
Route::get('/parkingBehavior/export', [ParkingBehaviorController::class, 'export']);
// 停车行为
// 停车历史
Route::get('/accessRecord', [ParkingAccessRecordController::class, 'index']);
Route::get('/accessRecord/search', [ParkingAccessRecordController::class, 'search']);
Route::get('/accessRecord/rule', [ParkingAccessRecordController::class, 'rule']);
Route::get('/accessRecord/export', [ParkingAccessRecordController::class, 'export']);
// 车位使用率
Route::get('/utilizationRate', [UtilizationRateController::class, 'index']);
Route::get('/utilizationRate/index', [UtilizationRateController::class, 'illustration']);
Route::get('/utilizationRate/search', [UtilizationRateController::class, 'search']);
Route::get('/utilizationRate/rule', [UtilizationRateController::class, 'rule']);
Route::get('/utilizationRate/export', [UtilizationRateController::class, 'export']);
// 系统日志
Route::get('/operationLog/index', [OperationLogController::class, 'index']);

Loading…
Cancel
Save