feat: [hr] 직급/직책 인라인 추가 기능 구현

- Position 생성 API 엔드포인트 추가 (POST /admin/hr/positions)
- 직급/직책 select 옆 "+" 버튼으로 모달 열기
- 모달에서 이름 입력 → API 저장 → 드롭다운에 자동 추가 및 선택
- 중복 key 방지 (기존 값이면 그대로 반환)
- create/edit 뷰 모두 적용
This commit is contained in:
김보곤
2026-02-26 17:07:12 +09:00
parent 3ce980a5f7
commit 56e4ce937a
6 changed files with 275 additions and 37 deletions

View File

@@ -170,4 +170,27 @@ public function destroy(Request $request, int $id): JsonResponse|Response
'message' => '퇴직 처리되었습니다.',
]);
}
/**
* 직급/직책 추가
*/
public function storePosition(Request $request): JsonResponse
{
$validated = $request->validate([
'type' => 'required|string|in:rank,title',
'name' => 'required|string|max:50',
]);
$position = $this->employeeService->createPosition($validated['type'], $validated['name']);
return response()->json([
'success' => true,
'message' => ($validated['type'] === 'rank' ? '직급' : '직책').'이 추가되었습니다.',
'data' => [
'id' => $position->id,
'key' => $position->key,
'name' => $position->name,
],
], 201);
}
}

View File

@@ -235,7 +235,7 @@ public function getDepartments(): \Illuminate\Database\Eloquent\Collection
}
/**
* 직급 목록 (드롭다운용)
* 직급/직책 목록 (드롭다운용)
*/
public function getPositions(string $type = 'rank'): \Illuminate\Database\Eloquent\Collection
{
@@ -246,4 +246,41 @@ public function getPositions(string $type = 'rank'): \Illuminate\Database\Eloque
->ordered()
->get(['id', 'key', 'name']);
}
/**
* 직급/직책 추가
*/
public function createPosition(string $type, string $name): Position
{
$tenantId = session('selected_tenant_id');
// key 생성: 이름을 소문자+언더스코어로 변환, 한글은 그대로
$key = str_replace(' ', '_', mb_strtolower(trim($name)));
// 중복 체크 후 존재하면 기존 반환
$existing = Position::query()
->forTenant()
->where('type', $type)
->where('key', $key)
->first();
if ($existing) {
return $existing;
}
// 다음 sort_order
$maxSort = Position::query()
->forTenant()
->where('type', $type)
->max('sort_order') ?? 0;
return Position::create([
'tenant_id' => $tenantId,
'type' => $type,
'key' => $key,
'name' => trim($name),
'sort_order' => $maxSort + 1,
'is_active' => true,
]);
}
}