diff --git a/app/Http/Controllers/Api/Admin/ProjectManagement/ImportController.php b/app/Http/Controllers/Api/Admin/ProjectManagement/ImportController.php index eec46488..71a3a628 100644 --- a/app/Http/Controllers/Api/Admin/ProjectManagement/ImportController.php +++ b/app/Http/Controllers/Api/Admin/ProjectManagement/ImportController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Api\Admin\ProjectManagement; use App\Http\Controllers\Controller; +use App\Http\Requests\ProjectManagement\ImportIssuesRequest; use App\Http\Requests\ProjectManagement\ImportProjectRequest; use App\Services\ProjectManagement\ImportService; use Illuminate\Http\JsonResponse; @@ -75,6 +76,27 @@ public function importTasks(Request $request, int $projectId): JsonResponse } } + /** + * 기존 작업에 이슈만 추가 + */ + public function importIssues(ImportIssuesRequest $request, int $taskId): JsonResponse + { + try { + $result = $this->importService->importIssuesToTask($taskId, $request->validated()['issues']); + + return response()->json([ + 'success' => true, + 'message' => "이슈가 추가되었습니다. ({$result['issues_count']}개)", + 'data' => $result, + ]); + } catch (\Exception $e) { + return response()->json([ + 'success' => false, + 'message' => '가져오기 실패: '.$e->getMessage(), + ], 500); + } + } + /** * JSON 구조 사전 검증 */ diff --git a/app/Http/Requests/ProjectManagement/ImportIssuesRequest.php b/app/Http/Requests/ProjectManagement/ImportIssuesRequest.php new file mode 100644 index 00000000..d560fca1 --- /dev/null +++ b/app/Http/Requests/ProjectManagement/ImportIssuesRequest.php @@ -0,0 +1,44 @@ + 'required|array|min:1', + 'issues.*.title' => 'required|string|max:255', + 'issues.*.description' => 'nullable|string', + 'issues.*.type' => 'nullable|in:bug,feature,improvement', + 'issues.*.status' => 'nullable|in:open,in_progress,resolved,closed', + // 일정 관련 + 'issues.*.start_date' => 'nullable|date', + 'issues.*.due_date' => 'nullable|date|after_or_equal:issues.*.start_date', + 'issues.*.estimated_hours' => 'nullable|integer|min:0', + 'issues.*.is_urgent' => 'nullable|boolean', + // 팀/담당자/고객사 (하이브리드) + 'issues.*.department_id' => 'nullable|integer|exists:departments,id', + 'issues.*.team' => 'nullable|string|max:100', + 'issues.*.assignee_id' => 'nullable|integer|exists:users,id', + 'issues.*.assignee_name' => 'nullable|string|max:100', + 'issues.*.client' => 'nullable|string|max:100', + ]; + } + + public function messages(): array + { + return [ + 'issues.required' => 'issues 배열은 필수입니다.', + 'issues.min' => '최소 1개 이상의 이슈가 필요합니다.', + 'issues.*.title.required' => '각 이슈의 title은 필수입니다.', + ]; + } +} diff --git a/app/Http/Requests/ProjectManagement/ImportProjectRequest.php b/app/Http/Requests/ProjectManagement/ImportProjectRequest.php index cbd4e4fa..8477fbcd 100644 --- a/app/Http/Requests/ProjectManagement/ImportProjectRequest.php +++ b/app/Http/Requests/ProjectManagement/ImportProjectRequest.php @@ -29,6 +29,9 @@ public function rules(): array 'tasks.*.status' => 'nullable|in:todo,in_progress,done', 'tasks.*.priority' => 'nullable|in:low,medium,high', 'tasks.*.due_date' => 'nullable|date', + 'tasks.*.is_urgent' => 'nullable|boolean', + 'tasks.*.assignee_id' => 'nullable|integer|exists:users,id', + 'tasks.*.assignee_name' => 'nullable|string|max:100', // 작업별 이슈 목록 'tasks.*.issues' => 'nullable|array', diff --git a/app/Services/ProjectManagement/ImportService.php b/app/Services/ProjectManagement/ImportService.php index 1dc5497f..63cef483 100644 --- a/app/Services/ProjectManagement/ImportService.php +++ b/app/Services/ProjectManagement/ImportService.php @@ -139,6 +139,48 @@ public function importTasksToProject(int $projectId, array $tasks): array }); } + /** + * 기존 작업에 이슈만 추가 + */ + public function importIssuesToTask(int $taskId, array $issues): array + { + return DB::transaction(function () use ($taskId, $issues) { + $task = AdminPmTask::findOrFail($taskId); + + $result = [ + 'task_id' => $taskId, + 'task_title' => $task->title, + 'project_id' => $task->project_id, + 'issues_count' => 0, + ]; + + foreach ($issues as $issueData) { + AdminPmIssue::create([ + 'project_id' => $task->project_id, + 'task_id' => $task->id, + 'title' => $issueData['title'], + 'description' => $issueData['description'] ?? null, + 'type' => $issueData['type'] ?? AdminPmIssue::TYPE_FEATURE, + 'status' => $issueData['status'] ?? AdminPmIssue::STATUS_OPEN, + 'start_date' => $issueData['start_date'] ?? null, + 'due_date' => $issueData['due_date'] ?? null, + 'estimated_hours' => $issueData['estimated_hours'] ?? null, + 'is_urgent' => $issueData['is_urgent'] ?? false, + // 팀/담당자/고객사 (하이브리드) + 'department_id' => $issueData['department_id'] ?? null, + 'team' => $issueData['team'] ?? null, + 'assignee_id' => $issueData['assignee_id'] ?? null, + 'assignee_name' => $issueData['assignee_name'] ?? null, + 'client' => $issueData['client'] ?? null, + 'created_by' => auth()->id(), + ]); + $result['issues_count']++; + } + + return $result; + }); + } + /** * JSON 샘플 템플릿 반환 */ diff --git a/ms1-issues.json b/ms1-issues.json new file mode 100644 index 00000000..21362735 --- /dev/null +++ b/ms1-issues.json @@ -0,0 +1,15 @@ +{ + "issues": [ + {"title": "견적관리", "description": "공수: 1.75일", "type": "feature", "start_date": "2025-11-27", "due_date": "2025-11-28", "team": "디자인팀"}, + {"title": "기준정보-견적수식", "description": "공수: 0.3일", "type": "feature", "start_date": "2025-11-28", "due_date": "2025-12-01", "team": "디자인팀"}, + {"title": "수주관리", "description": "공수: 3.25일", "type": "feature", "start_date": "2025-12-01", "due_date": "2025-12-04", "team": "디자인팀"}, + {"title": "생산관리", "description": "공수: 1.95일", "type": "feature", "start_date": "2025-12-04", "due_date": "2025-12-08", "team": "디자인팀"}, + {"title": "기준정보-공정", "description": "공수: 1.45일", "type": "feature", "start_date": "2025-12-08", "due_date": "2025-12-10", "team": "디자인팀"}, + {"title": "출하관리", "description": "공수: 2.25일", "type": "feature", "start_date": "2025-12-10", "due_date": "2025-12-12", "team": "디자인팀"}, + {"title": "거래처관리", "description": "공수: 1.1일", "type": "feature", "start_date": "2025-12-15", "due_date": "2025-12-16", "team": "디자인팀"}, + {"title": "품질관리", "description": "공수: 3.5일", "type": "feature", "start_date": "2025-12-16", "due_date": "2025-12-19", "team": "디자인팀"}, + {"title": "자재관리", "description": "공수: 3.3일", "type": "feature", "start_date": "2025-12-19", "due_date": "2025-12-24", "team": "디자인팀"}, + {"title": "단가관리", "description": "공수: 1일", "type": "feature", "start_date": "2025-12-24", "due_date": "2025-12-24", "team": "디자인팀"}, + {"title": "회계관리", "description": "공수: 1일", "type": "feature", "start_date": "2025-12-26", "due_date": "2025-12-26", "team": "디자인팀"} + ] +} diff --git a/resources/views/project-management/import.blade.php b/resources/views/project-management/import.blade.php index b1dff301..fc773b7a 100644 --- a/resources/views/project-management/import.blade.php +++ b/resources/views/project-management/import.blade.php @@ -24,7 +24,7 @@ {{-- Import 모드 선택 --}}
{
"project": {
- "name": "프로젝트명 (필수)",
- "description": "설명",
- "status": "active|completed|on_hold",
+ "name": "SAM 시스템 개발",
+ "description": "프로젝트 설명입니다",
+ "status": "active",
"start_date": "2025-01-01",
"end_date": "2025-03-31"
},
"tasks": [
{
- "title": "작업 제목 (필수)",
- "description": "작업 설명",
- "status": "todo|in_progress|done",
- "priority": "low|medium|high",
+ "title": "API 개발",
+ "description": "REST API 엔드포인트 구현",
+ "status": "in_progress",
+ "priority": "high",
"is_urgent": false,
"due_date": "2025-01-15",
"assignee_id": null,
+ "assignee_name": "김개발",
"issues": [
{
- "title": "이슈 제목 (필수)",
- "description": "이슈 설명",
- "type": "bug|feature|improvement",
- "status": "open|in_progress|resolved|closed",
+ "title": "사용자 인증 구현",
+ "description": "JWT 기반 인증 시스템",
+ "type": "feature",
+ "status": "open",
"start_date": "2025-01-01",
"due_date": "2025-01-15",
"estimated_hours": 8,
@@ -145,7 +161,7 @@ class="flex-1 px-4 py-2.5 text-sm font-medium text-white bg-indigo-600 rounded-l
"team": "개발팀",
"assignee_id": null,
"assignee_name": "홍길동",
- "client": "고객사명"
+ "client": "내부"
}
]
}
@@ -163,6 +179,30 @@ class="flex-1 px-4 py-2.5 text-sm font-medium text-white bg-indigo-600 rounded-l
}
]
}
+
+ {
+ "issues": [
+ {
+ "title": "Phase 1: 견적관리",
+ "description": "공수: 1.75일",
+ "type": "feature",
+ "status": "open",
+ "start_date": "2024-11-27",
+ "due_date": "2024-11-28",
+ "estimated_hours": 14,
+ "team": "개발팀"
+ },
+ {
+ "title": "Phase 2: 기준정보-견적수식",
+ "description": "공수: 0.3일",
+ "type": "feature",
+ "status": "open",
+ "start_date": "2024-11-28",
+ "due_date": "2024-12-01"
+ }
+ ]
+}