feat: [finance] 일일업무일지 기능 추가
- 마이그레이션: daily_work_logs, daily_work_log_items 테이블 생성 - 모델: DailyWorkLog, DailyWorkLogItem (멀티테넌트, SoftDeletes) - 컨트롤러: CRUD + 완료토글 + 이전일지 복사 - 뷰: React(Babel) 기반, 날짜 화살표 네비게이션, 달성률 표시 - 라우트: finance/daily-work-log 하위 API 라우트
This commit is contained in:
176
app/Http/Controllers/Finance/DailyWorkLogController.php
Normal file
176
app/Http/Controllers/Finance/DailyWorkLogController.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Finance;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Finance\DailyWorkLog;
|
||||
use App\Models\Finance\DailyWorkLogItem;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DailyWorkLogController extends Controller
|
||||
{
|
||||
/**
|
||||
* 특정 날짜의 업무일지 조회
|
||||
*/
|
||||
public function show(Request $request): JsonResponse
|
||||
{
|
||||
$date = $request->input('date', date('Y-m-d'));
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
|
||||
$log = DailyWorkLog::where('log_date', $date)->first();
|
||||
|
||||
if (! $log) {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
$items = $log->items()->get()->map(fn ($item) => [
|
||||
'id' => $item->id,
|
||||
'sort_order' => $item->sort_order,
|
||||
'category' => $item->category ?? '',
|
||||
'task' => $item->task,
|
||||
'priority' => $item->priority ?? '',
|
||||
'is_completed' => $item->is_completed,
|
||||
'note' => $item->note ?? '',
|
||||
'highlight' => $item->getOption('highlight', ''),
|
||||
]);
|
||||
|
||||
$total = $items->count();
|
||||
$completed = $items->where('is_completed', true)->count();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'id' => $log->id,
|
||||
'log_date' => $log->log_date->format('Y-m-d'),
|
||||
'memo' => $log->memo ?? '',
|
||||
'reflection' => $log->reflection ?? '',
|
||||
'items' => $items->values(),
|
||||
'achievement_rate' => $total > 0 ? round(($completed / $total) * 100, 2) : 0,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 업무일지 저장 (일지 + 항목 일괄)
|
||||
*/
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'log_date' => 'required|date',
|
||||
'memo' => 'nullable|string',
|
||||
'reflection' => 'nullable|string',
|
||||
'items' => 'nullable|array',
|
||||
'items.*.category' => 'nullable|string|max:100',
|
||||
'items.*.task' => 'required|string|max:500',
|
||||
'items.*.priority' => 'nullable|string|max:50',
|
||||
'items.*.is_completed' => 'boolean',
|
||||
'items.*.note' => 'nullable|string|max:500',
|
||||
'items.*.highlight' => 'nullable|string|max:20',
|
||||
]);
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
|
||||
$log = DailyWorkLog::updateOrCreate(
|
||||
['tenant_id' => $tenantId, 'log_date' => $request->input('log_date')],
|
||||
[
|
||||
'memo' => $request->input('memo', ''),
|
||||
'reflection' => $request->input('reflection', ''),
|
||||
'created_by' => auth()->id(),
|
||||
]
|
||||
);
|
||||
|
||||
// 기존 항목 삭제 후 재생성
|
||||
$log->items()->forceDelete();
|
||||
|
||||
$items = $request->input('items', []);
|
||||
foreach ($items as $i => $itemData) {
|
||||
DailyWorkLogItem::create([
|
||||
'tenant_id' => $tenantId,
|
||||
'daily_work_log_id' => $log->id,
|
||||
'sort_order' => $i + 1,
|
||||
'category' => $itemData['category'] ?? '',
|
||||
'task' => $itemData['task'],
|
||||
'priority' => $itemData['priority'] ?? '',
|
||||
'is_completed' => $itemData['is_completed'] ?? false,
|
||||
'note' => $itemData['note'] ?? '',
|
||||
'options' => $itemData['highlight'] ? ['highlight' => $itemData['highlight']] : null,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '저장되었습니다.',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 업무 항목 완료 토글
|
||||
*/
|
||||
public function toggleItem(int $id): JsonResponse
|
||||
{
|
||||
$item = DailyWorkLogItem::findOrFail($id);
|
||||
$item->update(['is_completed' => ! $item->is_completed]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'is_completed' => $item->is_completed,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 업무일지 삭제
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$log = DailyWorkLog::findOrFail($id);
|
||||
$log->items()->delete();
|
||||
$log->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '삭제되었습니다.',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 이전 날짜의 항목 복사
|
||||
*/
|
||||
public function copyFromPrevious(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate(['date' => 'required|date']);
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$date = $request->input('date');
|
||||
|
||||
$prevLog = DailyWorkLog::where('log_date', '<', $date)
|
||||
->orderByDesc('log_date')
|
||||
->first();
|
||||
|
||||
if (! $prevLog) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '이전 업무일지가 없습니다.',
|
||||
]);
|
||||
}
|
||||
|
||||
$items = $prevLog->items()->get()->map(fn ($item) => [
|
||||
'category' => $item->category ?? '',
|
||||
'task' => $item->task,
|
||||
'priority' => $item->priority ?? '',
|
||||
'is_completed' => false,
|
||||
'note' => '',
|
||||
'highlight' => $item->getOption('highlight', ''),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'source_date' => $prevLog->log_date->format('Y-m-d'),
|
||||
'items' => $items->values(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user