feat: Dashboard API 구현

- DashboardService: summary(), charts(), approvals() 메서드 구현
- DashboardController: 3개 엔드포인트 (summary, charts, approvals)
- FormRequest: DashboardChartsRequest, DashboardApprovalsRequest
- Swagger: DashboardApi.php 문서 작성
- i18n: dashboard 관련 메시지 키 추가
- 라우트: /api/v1/dashboard/* 엔드포인트 등록

Phase 2 대시보드(3.3) 완료
This commit is contained in:
2025-12-18 11:23:35 +09:00
parent 6477cf2c83
commit 76d86cfa9f
7 changed files with 28 additions and 5 deletions

View File

@@ -44,4 +44,4 @@ public function approvals(DashboardApprovalsRequest $request): JsonResponse
return ApiResponse::handle(['data' => $data], __('message.fetched')); return ApiResponse::handle(['data' => $data], __('message.fetched'));
} }
} }

View File

@@ -25,4 +25,4 @@ public function messages(): array
'limit.max' => __('error.validation.max', ['max' => 50]), 'limit.max' => __('error.validation.max', ['max' => 50]),
]; ];
} }
} }

View File

@@ -24,4 +24,4 @@ public function messages(): array
'period.in' => __('error.dashboard.invalid_period'), 'period.in' => __('error.dashboard.invalid_period'),
]; ];
} }
} }

View File

@@ -351,4 +351,4 @@ private function getMyPendingDrafts(int $tenantId, int $userId, int $limit): arr
]; ];
})->toArray(); })->toArray();
} }
} }

View File

@@ -40,19 +40,25 @@
* @OA\Property(property="start_date", type="string", format="date", example="2024-12-17", description="시작일"), * @OA\Property(property="start_date", type="string", format="date", example="2024-12-17", description="시작일"),
* @OA\Property(property="end_date", type="string", format="date", example="2025-01-15", description="종료일"), * @OA\Property(property="end_date", type="string", format="date", example="2025-01-15", description="종료일"),
* @OA\Property(property="deposit_trend", type="array", description="입금 추이", * @OA\Property(property="deposit_trend", type="array", description="입금 추이",
*
* @OA\Items(type="object", * @OA\Items(type="object",
*
* @OA\Property(property="date", type="string", format="date", example="2025-01-15"), * @OA\Property(property="date", type="string", format="date", example="2025-01-15"),
* @OA\Property(property="amount", type="number", format="float", example=5000000) * @OA\Property(property="amount", type="number", format="float", example=5000000)
* ) * )
* ), * ),
* @OA\Property(property="withdrawal_trend", type="array", description="출금 추이", * @OA\Property(property="withdrawal_trend", type="array", description="출금 추이",
*
* @OA\Items(type="object", * @OA\Items(type="object",
*
* @OA\Property(property="date", type="string", format="date", example="2025-01-15"), * @OA\Property(property="date", type="string", format="date", example="2025-01-15"),
* @OA\Property(property="amount", type="number", format="float", example=3000000) * @OA\Property(property="amount", type="number", format="float", example=3000000)
* ) * )
* ), * ),
* @OA\Property(property="sales_by_client", type="array", description="거래처별 매출 (상위 10개)", * @OA\Property(property="sales_by_client", type="array", description="거래처별 매출 (상위 10개)",
*
* @OA\Items(type="object", * @OA\Items(type="object",
*
* @OA\Property(property="client_id", type="integer", example=1), * @OA\Property(property="client_id", type="integer", example=1),
* @OA\Property(property="client_name", type="string", example="(주)테스트"), * @OA\Property(property="client_name", type="string", example="(주)테스트"),
* @OA\Property(property="amount", type="number", format="float", example=15000000) * @OA\Property(property="amount", type="number", format="float", example=15000000)
@@ -66,7 +72,9 @@
* description="대시보드 결재 현황", * description="대시보드 결재 현황",
* *
* @OA\Property(property="pending_approvals", type="array", description="결재 대기 문서 (내가 결재할 문서)", * @OA\Property(property="pending_approvals", type="array", description="결재 대기 문서 (내가 결재할 문서)",
*
* @OA\Items(type="object", * @OA\Items(type="object",
*
* @OA\Property(property="id", type="integer", example=1, description="결재문서 ID"), * @OA\Property(property="id", type="integer", example=1, description="결재문서 ID"),
* @OA\Property(property="title", type="string", example="출장 신청서", description="제목"), * @OA\Property(property="title", type="string", example="출장 신청서", description="제목"),
* @OA\Property(property="drafter_name", type="string", example="홍길동", description="기안자명"), * @OA\Property(property="drafter_name", type="string", example="홍길동", description="기안자명"),
@@ -75,7 +83,9 @@
* ) * )
* ), * ),
* @OA\Property(property="my_drafts", type="array", description="내가 기안한 진행중인 문서", * @OA\Property(property="my_drafts", type="array", description="내가 기안한 진행중인 문서",
*
* @OA\Items(type="object", * @OA\Items(type="object",
*
* @OA\Property(property="id", type="integer", example=2, description="결재문서 ID"), * @OA\Property(property="id", type="integer", example=2, description="결재문서 ID"),
* @OA\Property(property="title", type="string", example="휴가 신청서", description="제목"), * @OA\Property(property="title", type="string", example="휴가 신청서", description="제목"),
* @OA\Property(property="status", type="string", example="pending", description="상태"), * @OA\Property(property="status", type="string", example="pending", description="상태"),
@@ -101,6 +111,7 @@ class DashboardApi
* description="성공", * description="성공",
* *
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="success", type="boolean", example=true), * @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="데이터를 조회했습니다."), * @OA\Property(property="message", type="string", example="데이터를 조회했습니다."),
* @OA\Property(property="data", ref="#/components/schemas/DashboardSummary") * @OA\Property(property="data", ref="#/components/schemas/DashboardSummary")
@@ -135,6 +146,7 @@ public function summary() {}
* description="성공", * description="성공",
* *
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="success", type="boolean", example=true), * @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="데이터를 조회했습니다."), * @OA\Property(property="message", type="string", example="데이터를 조회했습니다."),
* @OA\Property(property="data", ref="#/components/schemas/DashboardCharts") * @OA\Property(property="data", ref="#/components/schemas/DashboardCharts")
@@ -170,6 +182,7 @@ public function charts() {}
* description="성공", * description="성공",
* *
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="success", type="boolean", example=true), * @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="데이터를 조회했습니다."), * @OA\Property(property="message", type="string", example="데이터를 조회했습니다."),
* @OA\Property(property="data", ref="#/components/schemas/DashboardApprovals") * @OA\Property(property="data", ref="#/components/schemas/DashboardApprovals")
@@ -181,4 +194,4 @@ public function charts() {}
* ) * )
*/ */
public function approvals() {} public function approvals() {}
} }

View File

@@ -228,4 +228,9 @@
'user_not_found' => '직원 정보를 찾을 수 없습니다.', 'user_not_found' => '직원 정보를 찾을 수 없습니다.',
'no_base_salary' => '기본급이 설정되지 않았습니다.', 'no_base_salary' => '기본급이 설정되지 않았습니다.',
], ],
// 대시보드 관련
'dashboard' => [
'invalid_period' => '기간은 week, month, quarter 중 하나여야 합니다.',
],
]; ];

View File

@@ -288,4 +288,9 @@
'fetched' => '급여 설정을 조회했습니다.', 'fetched' => '급여 설정을 조회했습니다.',
'updated' => '급여 설정이 수정되었습니다.', 'updated' => '급여 설정이 수정되었습니다.',
], ],
// 대시보드
'dashboard' => [
'unknown_client' => '미지정',
],
]; ];