11 changed files with 375 additions and 4 deletions
@ -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'), |
|||
]; |
|||
} |
|||
} |
|||
@ -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' |
|||
); |
|||
} |
|||
} |
|||
@ -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' |
|||
]; |
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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'); |
|||
} |
|||
}; |
|||
Loading…
Reference in new issue