feat: [HR/기타] 캘린더/배차/설비/재고 + DB 마이그레이션

- 캘린더 CRUD API, 배차차량 관리 API (CRUD + options)
- 배차정보 다중 행 시스템 (shipment_vehicle_dispatches)
- 설비 다중점검주기 + 부 담당자 스키마 추가
- TodayIssue 날짜 기반 조회, Stock/Client 날짜 필터
- i18n 메시지 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 02:59:30 +09:00
parent 95371fd841
commit 4208ca3010
27 changed files with 799 additions and 15 deletions

View File

@@ -51,4 +51,56 @@ public function summary(Request $request)
);
}, __('message.fetched'));
}
/**
* 일정 등록
*/
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:200',
'description' => 'nullable|string|max:1000',
'start_date' => 'required|date_format:Y-m-d',
'end_date' => 'required|date_format:Y-m-d|after_or_equal:start_date',
'start_time' => 'nullable|date_format:H:i',
'end_time' => 'nullable|date_format:H:i',
'is_all_day' => 'boolean',
'color' => 'nullable|string|max:20',
]);
return ApiResponse::handle(function () use ($validated) {
return $this->calendarService->createSchedule($validated);
}, __('message.created'));
}
/**
* 일정 수정
*/
public function update(Request $request, int $id)
{
$validated = $request->validate([
'title' => 'required|string|max:200',
'description' => 'nullable|string|max:1000',
'start_date' => 'required|date_format:Y-m-d',
'end_date' => 'required|date_format:Y-m-d|after_or_equal:start_date',
'start_time' => 'nullable|date_format:H:i',
'end_time' => 'nullable|date_format:H:i',
'is_all_day' => 'boolean',
'color' => 'nullable|string|max:20',
]);
return ApiResponse::handle(function () use ($id, $validated) {
return $this->calendarService->updateSchedule($id, $validated);
}, __('message.updated'));
}
/**
* 일정 삭제
*/
public function destroy(int $id)
{
return ApiResponse::handle(function () use ($id) {
return $this->calendarService->deleteSchedule($id);
}, __('message.deleted'));
}
}

View File

@@ -29,6 +29,8 @@ public function index(Request $request): JsonResponse
'sort_dir',
'per_page',
'page',
'start_date',
'end_date',
]);
$stocks = $this->service->index($params);

View File

@@ -20,9 +20,10 @@ public function __construct(
public function summary(Request $request): JsonResponse
{
$limit = (int) $request->input('limit', 30);
$date = $request->input('date'); // YYYY-MM-DD (이전 이슈 조회용)
return ApiResponse::handle(function () use ($limit) {
return $this->todayIssueService->summary($limit);
return ApiResponse::handle(function () use ($limit, $date) {
return $this->todayIssueService->summary($limit, null, $date);
}, __('message.fetched'));
}

View File

@@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers\Api\V1;
use App\Helpers\ApiResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\VehicleDispatch\VehicleDispatchUpdateRequest;
use App\Services\VehicleDispatchService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class VehicleDispatchController extends Controller
{
public function __construct(
private readonly VehicleDispatchService $service
) {}
/**
* 배차차량 목록 조회
*/
public function index(Request $request): JsonResponse
{
$params = $request->only([
'search',
'status',
'start_date',
'end_date',
'per_page',
'page',
]);
$dispatches = $this->service->index($params);
return ApiResponse::success($dispatches, __('message.fetched'));
}
/**
* 배차차량 통계 조회
*/
public function stats(): JsonResponse
{
$stats = $this->service->stats();
return ApiResponse::success($stats, __('message.fetched'));
}
/**
* 배차차량 상세 조회
*/
public function show(int $id): JsonResponse
{
try {
$dispatch = $this->service->show($id);
return ApiResponse::success($dispatch, __('message.fetched'));
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
return ApiResponse::error(__('error.not_found'), 404);
}
}
/**
* 배차차량 수정
*/
public function update(VehicleDispatchUpdateRequest $request, int $id): JsonResponse
{
try {
$dispatch = $this->service->update($id, $request->validated());
return ApiResponse::success($dispatch, __('message.updated'));
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
return ApiResponse::error(__('error.not_found'), 404);
}
}
}