[agent-pipeline] pipe-20260327053504-cc40 round-2
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
"/Users/gbpark/agent-pipeline/engine/build/mcp/mailbox-stdio-bridge.js"
|
||||
],
|
||||
"env": {
|
||||
"MAILBOX_URL": "http://127.0.0.1:51824",
|
||||
"MAILBOX_URL": "http://127.0.0.1:54227",
|
||||
"MAILBOX_AGENT": "backend"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"/Users/gbpark/agent-pipeline/engine/build/mcp/mailbox-stdio-bridge.js"
|
||||
],
|
||||
"env": {
|
||||
"MAILBOX_URL": "http://127.0.0.1:51824",
|
||||
"MAILBOX_URL": "http://127.0.0.1:54227",
|
||||
"MAILBOX_AGENT": "frontend"
|
||||
}
|
||||
}
|
||||
|
||||
+2245
-279
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"pid":14921,"round":1,"status":"running","timestamp":"2026-03-27T02:21:23.348Z","uptimeMs":211033.79775}
|
||||
{"pid":99834,"round":2,"status":"running","timestamp":"2026-03-27T09:11:35.880Z","uptimeMs":12991125.527583001}
|
||||
@@ -0,0 +1,25 @@
|
||||
# 실행 메트릭
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|------|
|
||||
| 총 에이전트 호출 | 2회 |
|
||||
| 총 소요 시간 | 353초 |
|
||||
| 평균 호출 시간 | 177초 |
|
||||
|
||||
## 토큰 사용량
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|------|
|
||||
| input_tokens | 941 |
|
||||
| output_tokens | 13038 |
|
||||
| cache_read_tokens | 1200300 |
|
||||
| cache_write_tokens | 40613 |
|
||||
| 입력 비용 | $0.0141 |
|
||||
| 출력 비용 | $0.9778 |
|
||||
| 총 비용 | $0.9920 |
|
||||
|
||||
## 호출 상세
|
||||
| 에이전트 | 라운드 | 소요(s) | 입력토큰 | 출력토큰 | 시간 |
|
||||
|----------|--------|---------|----------|----------|------|
|
||||
| backend | 1 | 237 | 941 | 13.0K | 오전 11:21:50 |
|
||||
| pm | 1 | 117 | 0 | 0 | 오전 11:23:46 |
|
||||
@@ -1,57 +1,57 @@
|
||||
# Pipeline: pipe-20260327021752-7ctg
|
||||
- 시작: 2026. 3. 27. 오전 11:17:52
|
||||
# Pipeline: pipe-20260327053504-cc40
|
||||
- 시작: 2026. 3. 27. 오후 2:35:04
|
||||
- 상태: **running**
|
||||
- 현재 라운드: 1/25
|
||||
- 경과 시간: 3분 31초
|
||||
- 현재 라운드: 2/25
|
||||
- 경과 시간: 216분 31초
|
||||
- 성공: 0 / 실패: 0 / 전체: 102
|
||||
|
||||
## 태스크 현황
|
||||
| 태스크 | 에이전트 | 상태 | 시도 | 검증 |
|
||||
|--------|----------|------|------|------|
|
||||
| task-1 | backend | 대기 | 0/5 | - |
|
||||
| task-2 | backend | 대기 | 0/5 | - |
|
||||
| task-3 | backend | 대기 | 0/5 | - |
|
||||
| task-4 | backend | 대기 | 0/5 | - |
|
||||
| task-5 | backend | 대기 | 0/5 | - |
|
||||
| task-6 | backend | 대기 | 0/5 | - |
|
||||
| task-7 | backend | 대기 | 0/5 | - |
|
||||
| task-8 | backend | 대기 | 0/5 | - |
|
||||
| task-9 | backend | 대기 | 0/5 | - |
|
||||
| task-10 | backend | 대기 | 0/5 | - |
|
||||
| task-11 | backend | 대기 | 0/5 | - |
|
||||
| task-12 | backend | 대기 | 0/5 | - |
|
||||
| task-13 | backend | 대기 | 0/5 | - |
|
||||
| task-14 | backend | 대기 | 0/5 | - |
|
||||
| task-15 | backend | 대기 | 0/5 | - |
|
||||
| task-16 | backend | 대기 | 0/5 | - |
|
||||
| task-17 | backend | 대기 | 0/5 | - |
|
||||
| task-18 | backend | 대기 | 0/5 | - |
|
||||
| task-19 | backend | 대기 | 0/5 | - |
|
||||
| task-20 | backend | 대기 | 0/5 | - |
|
||||
| task-21 | backend | 대기 | 0/5 | - |
|
||||
| task-22 | backend | 대기 | 0/5 | - |
|
||||
| task-23 | backend | 대기 | 0/5 | - |
|
||||
| task-24 | backend | 대기 | 0/5 | - |
|
||||
| task-25 | backend | 대기 | 0/5 | - |
|
||||
| task-26 | backend | 대기 | 0/5 | - |
|
||||
| task-27 | backend | 대기 | 0/5 | - |
|
||||
| task-28 | backend | 대기 | 0/5 | - |
|
||||
| task-29 | backend | 대기 | 0/5 | - |
|
||||
| task-30 | backend | 대기 | 0/5 | - |
|
||||
| task-31 | backend | 대기 | 0/5 | - |
|
||||
| task-32 | backend | 대기 | 0/5 | - |
|
||||
| task-33 | backend | 대기 | 0/5 | - |
|
||||
| task-34 | backend | 대기 | 0/5 | - |
|
||||
| task-35 | backend | 대기 | 0/5 | - |
|
||||
| task-36 | backend | 대기 | 0/5 | - |
|
||||
| task-37 | backend | 대기 | 0/5 | - |
|
||||
| task-38 | backend | 대기 | 0/5 | - |
|
||||
| task-39 | backend | 대기 | 0/5 | - |
|
||||
| task-40 | backend | 대기 | 0/5 | - |
|
||||
| task-41 | backend | 대기 | 0/5 | - |
|
||||
| task-42 | backend | 대기 | 0/5 | - |
|
||||
| task-43 | backend | 대기 | 0/5 | - |
|
||||
| task-44 | backend | 대기 | 0/5 | - |
|
||||
| task-1 | backend | 완료 | 1/5 | - |
|
||||
| task-2 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-3 | backend | 완료 | 0/5 | - |
|
||||
| task-4 | backend | 완료 | 0/5 | - |
|
||||
| task-5 | backend | 완료 | 0/5 | - |
|
||||
| task-6 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-7 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-8 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-9 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-10 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-11 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-12 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-13 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-14 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-15 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-16 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-17 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-18 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-19 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-20 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-21 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-22 | backend | 대기 | 1/5 | - |
|
||||
| task-23 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-24 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-25 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-26 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-27 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-28 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-29 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-30 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-31 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-32 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-33 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-34 | backend | 대기 | 1/5 | - |
|
||||
| task-35 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-36 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-37 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-38 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-39 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-40 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-41 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-42 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-43 | backend | 대기 | 1/5 | - |
|
||||
| task-44 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-45 | backend | 대기 | 0/5 | - |
|
||||
| task-46 | backend | 대기 | 0/5 | - |
|
||||
| task-47 | backend | 대기 | 0/5 | - |
|
||||
@@ -59,57 +59,60 @@
|
||||
| task-49 | backend | 대기 | 0/5 | - |
|
||||
| task-50 | backend | 대기 | 0/5 | - |
|
||||
| task-51 | backend | 대기 | 0/5 | - |
|
||||
| task-52 | backend | 대기 | 0/5 | - |
|
||||
| task-53 | backend | 대기 | 0/5 | - |
|
||||
| task-54 | backend | 대기 | 0/5 | - |
|
||||
| task-55 | backend | 대기 | 0/5 | - |
|
||||
| task-56 | backend | 대기 | 0/5 | - |
|
||||
| task-57 | backend | 대기 | 0/5 | - |
|
||||
| task-58 | backend | 대기 | 0/5 | - |
|
||||
| task-59 | backend | 대기 | 0/5 | - |
|
||||
| task-60 | backend | 대기 | 0/5 | - |
|
||||
| task-61 | backend | 대기 | 0/5 | - |
|
||||
| task-62 | backend | 대기 | 0/5 | - |
|
||||
| task-63 | backend | 대기 | 0/5 | - |
|
||||
| task-64 | backend | 대기 | 0/5 | - |
|
||||
| task-65 | backend | 대기 | 0/5 | - |
|
||||
| task-66 | backend | 대기 | 0/5 | - |
|
||||
| task-67 | backend | 대기 | 0/5 | - |
|
||||
| task-68 | backend | 대기 | 0/5 | - |
|
||||
| task-69 | backend | 대기 | 0/5 | - |
|
||||
| task-70 | backend | 대기 | 0/5 | - |
|
||||
| task-71 | backend | 대기 | 0/5 | - |
|
||||
| task-72 | backend | 대기 | 0/5 | - |
|
||||
| task-73 | backend | 대기 | 0/5 | - |
|
||||
| task-74 | backend | 대기 | 0/5 | - |
|
||||
| task-75 | backend | 대기 | 0/5 | - |
|
||||
| task-52 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-53 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-54 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-55 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-56 | backend | 대기 | 1/5 | - |
|
||||
| task-57 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-58 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-59 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-60 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-61 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-62 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-63 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-64 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-65 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-66 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-67 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-68 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-69 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-70 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-71 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-72 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-73 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-74 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-75 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-76 | backend | 대기 | 0/5 | - |
|
||||
| task-77 | backend | 대기 | 0/5 | - |
|
||||
| task-78 | backend | 대기 | 0/5 | - |
|
||||
| task-79 | backend | 대기 | 0/5 | - |
|
||||
| task-80 | backend | 대기 | 0/5 | - |
|
||||
| task-81 | backend | 대기 | 0/5 | - |
|
||||
| task-82 | backend | 대기 | 0/5 | - |
|
||||
| task-83 | backend | 대기 | 0/5 | - |
|
||||
| task-84 | backend | 대기 | 0/5 | - |
|
||||
| task-85 | backend | 대기 | 0/5 | - |
|
||||
| task-86 | backend | 대기 | 0/5 | - |
|
||||
| task-87 | backend | 대기 | 0/5 | - |
|
||||
| task-88 | backend | 대기 | 0/5 | - |
|
||||
| task-89 | backend | 대기 | 0/5 | - |
|
||||
| task-90 | backend | 대기 | 0/5 | - |
|
||||
| task-91 | backend | 대기 | 0/5 | - |
|
||||
| task-78 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-79 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-80 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-81 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-82 | backend | 대기 | 1/5 | - |
|
||||
| task-83 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-84 | backend | 대기 | 1/5 | - |
|
||||
| task-85 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-86 | backend | 대기 | 1/5 | - |
|
||||
| task-87 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-88 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-89 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-90 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-91 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-92 | backend | 대기 | 0/5 | - |
|
||||
| task-93 | backend | 대기 | 0/5 | - |
|
||||
| task-93 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-94 | backend | 대기 | 0/5 | - |
|
||||
| task-95 | backend | 대기 | 0/5 | - |
|
||||
| task-96 | backend | 대기 | 0/5 | - |
|
||||
| task-97 | backend | 대기 | 0/5 | - |
|
||||
| task-98 | backend | 대기 | 0/5 | - |
|
||||
| task-99 | backend | 대기 | 0/5 | - |
|
||||
| task-95 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-96 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-97 | backend | 대기 | 1/5 | - |
|
||||
| task-98 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-99 | backend | 완료 | 1/5 | L1 통과: cd backend-spring && ./ |
|
||||
| task-100 | backend | 대기 | 0/5 | - |
|
||||
| task-101 | frontend | 대기 | 0/5 | - |
|
||||
| task-102 | frontend | 대기 | 0/5 | - |
|
||||
|
||||
## PM 마지막 판단
|
||||
Round 1에서 backend 에이전트가 task-1(Spring Boot 프로젝트 초기화)을 성공적으로 완료했다. L1(compileJava)과 L6(bootJar) 모두 통과. 에이전트가 task-1 범위를 넘어서 task-2~5에 해당하는 파일들(DecimalUtils+Test, ApiResponse, GlobalExceptionHandler, Se
|
||||
|
||||
---
|
||||
마지막 업데이트: 2026. 3. 27. 오전 11:21:23
|
||||
마지막 업데이트: 2026. 3. 27. 오후 6:11:35
|
||||
@@ -0,0 +1,553 @@
|
||||
{
|
||||
"pipelineId": "pipe-20260327021752-7ctg",
|
||||
"runDir": "/Users/gbpark/TEST-VEX/_pipeline/runs/2026-03-27_pipe-20260327021752-7ctg",
|
||||
"lastCompletedRound": 1,
|
||||
"maxRounds": 25,
|
||||
"taskStatuses": [
|
||||
{
|
||||
"id": "task-1",
|
||||
"status": "success",
|
||||
"attempts": 1
|
||||
},
|
||||
{
|
||||
"id": "task-2",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-3",
|
||||
"status": "success",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-4",
|
||||
"status": "success",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-5",
|
||||
"status": "success",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-6",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-7",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-8",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-9",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-10",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-11",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-12",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-13",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-14",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-15",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-16",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-17",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-18",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-19",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-20",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-21",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-22",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-23",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-24",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-25",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-26",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-27",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-28",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-29",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-30",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-31",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-32",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-33",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-34",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-35",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-36",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-37",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-38",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-39",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-40",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-41",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-42",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-43",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-44",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-45",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-46",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-47",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-48",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-49",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-50",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-51",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-52",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-53",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-54",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-55",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-56",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-57",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-58",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-59",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-60",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-61",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-62",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-63",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-64",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-65",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-66",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-67",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-68",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-69",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-70",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-71",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-72",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-73",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-74",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-75",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-76",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-77",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-78",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-79",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-80",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-81",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-82",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-83",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-84",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-85",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-86",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-87",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-88",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-89",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-90",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-91",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-92",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-93",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-94",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-95",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-96",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-97",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-98",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-99",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-100",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-101",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
},
|
||||
{
|
||||
"id": "task-102",
|
||||
"status": "pending",
|
||||
"attempts": 0
|
||||
}
|
||||
],
|
||||
"pmLastInstruction": "[task-1] L1(compileJava) + L6(bootJar) 통과. done_when 조건 충족.\n[task-3] ApiResponse.java + GlobalExceptionHandler.java 이미 생성됨. compileJava 통과로 done_when(build pass) 충족.\n[task-4] SecurityConfig, JwtTokenProvider, JwtAuthenticationFilter 이미 생성됨. compileJava 통과. 패키지 경로가 plan과 다르나(security/ 패키지) 빌드 통과로 done_when 충족.\n[task-5] CommonMapper.java, CommonMapper.xml, CommonService.java 이미 생성됨. compileJava 통과로 done_when(build pass) 충족.\n[task-2] DecimalUtils.java와 DecimalUtilsTest.java가 이미 존재한다. 새로 만들지 말고 기존 파일을 확인하라. verify 명령어(./gradlew test --tests '*DecimalUtils*')를 실행하여 유닛 테스트 통과를 확인하라. 테스트 실패 시에만 코드를 수정하라. 메서드 목록: parse(String), multiply(String,String), addTax(String,String), divide(String,String,int scale), sum(List<String>). 테스트 케이스: parse(null)→ZERO, multiply('100','0.1')→10.0000, 0.1+0.2=0.3.",
|
||||
"pmLastSummary": "Round 1에서 backend 에이전트가 task-1(Spring Boot 프로젝트 초기화)을 성공적으로 완료했다. L1(compileJava)과 L6(bootJar) 모두 통과. 에이전트가 task-1 범위를 넘어서 task-2~5에 해당하는 파일들(DecimalUtils+Test, ApiResponse, GlobalExceptionHandler, Se",
|
||||
"metrics": {
|
||||
"calls": [
|
||||
{
|
||||
"agent": "backend",
|
||||
"round": 1,
|
||||
"durationMs": 236749,
|
||||
"outputLength": 1074,
|
||||
"timestamp": "2026-03-27T02:21:50.087Z",
|
||||
"inputTokens": 941,
|
||||
"outputTokens": 13038,
|
||||
"cacheReadTokens": 1200300,
|
||||
"cacheWriteTokens": 40613
|
||||
},
|
||||
{
|
||||
"agent": "pm",
|
||||
"round": 1,
|
||||
"durationMs": 116561,
|
||||
"outputLength": 2461,
|
||||
"timestamp": "2026-03-27T02:23:46.852Z"
|
||||
}
|
||||
],
|
||||
"totalDurationMs": 353310,
|
||||
"totalCalls": 2,
|
||||
"totalInputTokens": 941,
|
||||
"totalOutputTokens": 13038,
|
||||
"totalCacheReadTokens": 1200300,
|
||||
"totalCacheWriteTokens": 40613
|
||||
},
|
||||
"savedAt": "2026-03-27T02:23:46.855Z",
|
||||
"planFilePath": "/Users/gbpark/agent-pipeline/test-vex/plans/spring-migration.md",
|
||||
"claudeSessionIds": {
|
||||
"backend": "5ee7c47f-9138-4c93-8341-65be24073658"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
# PM 판단 - Round 1
|
||||
- 시간: 2026. 3. 27. 오전 11:23:46
|
||||
|
||||
## 분석
|
||||
Round 1에서 backend 에이전트가 task-1(Spring Boot 프로젝트 초기화)을 성공적으로 완료했다. L1(compileJava)과 L6(bootJar) 모두 통과. 에이전트가 task-1 범위를 넘어서 task-2~5에 해당하는 파일들(DecimalUtils+Test, ApiResponse, GlobalExceptionHandler, SecurityConfig, JwtTokenProvider, JwtAuthenticationFilter, CommonMapper, CommonService)도 함께 생성한 점이 우수하다. compileJava와 bootJar 모두 통과했으므로 task-3(ApiResponse+GlobalExceptionHandler build pass), task-4(SecurityConfig+JwtTokenProvider+JwtAuthenticationFilter build pass), task-5(CommonMapper+CommonService build pass)의 done_when 조건이 충족되었다. 단, task-4의 파일 경로가 plan과 다르다: plan은 config/SecurityConfig.java, config/JwtTokenProvider.java, filter/JwtAuthenticationFilter.java를 지정했으나 에이전트는 모두 security/ 패키지에 배치했다. 기능상 문제없이 빌드 통과했으나 향후 태스크에서 import 경로 참조 시 주의 필요. task-2의 done_when은 'DecimalUtils all unit tests pass'인데 bootJar만 검증되었고 구체적 유닛 테스트 실행은 확인되지 않았다. 파일은 이미 존재하므로 다음 라운드에서 유닛 테스트 검증만 필요.
|
||||
|
||||
## 태스크 지시
|
||||
- **task-1** [complete]: L1(compileJava) + L6(bootJar) 통과. done_when 조건 충족.
|
||||
- **task-3** [complete]: ApiResponse.java + GlobalExceptionHandler.java 이미 생성됨. compileJava 통과로 done_when(build pass) 충족.
|
||||
- **task-4** [complete]: SecurityConfig, JwtTokenProvider, JwtAuthenticationFilter 이미 생성됨. compileJava 통과. 패키지 경로가 plan과 다르나(security/ 패키지) 빌드 통과로 done_when 충족.
|
||||
- **task-5** [complete]: CommonMapper.java, CommonMapper.xml, CommonService.java 이미 생성됨. compileJava 통과로 done_when(build pass) 충족.
|
||||
- **task-2** [retry]: DecimalUtils.java와 DecimalUtilsTest.java가 이미 존재한다. 새로 만들지 말고 기존 파일을 확인하라. verify 명령어(./gradlew test --tests '*DecimalUtils*')를 실행하여 유닛 테스트 통과를 확인하라. 테스트 실패 시에만 코드를 수정하라. 메서드 목록: parse(String), multiply(String,String), addTax(String,String), divide(String,String,int scale), sum(List<String>). 테스트 케이스: parse(null)→ZERO, multiply('100','0.1')→10.0000, 0.1+0.2=0.3.
|
||||
|
||||
## 판정: **continue**
|
||||
## 다음 라운드 핵심: task-2 유닛 테스트 검증 완료 후, task-6(Auth Login API, depends: task-3,4,5 완료)을 즉시 진행. 동시에 task-5에만 의존하는 task-7~task-100 중 max_concurrent=3에 따라 병렬 배치 시작. 우선순위: task-6(Auth 필수), task-7(Admin), task-8(Role) 또는 task-91(Data Generic CRUD) 등 다른 태스크의 기반이 되는 핵심 API부터.
|
||||
|
||||
---
|
||||
## PM 원본 응답
|
||||
```
|
||||
```json
|
||||
{
|
||||
"analysis": "Round 1에서 backend 에이전트가 task-1(Spring Boot 프로젝트 초기화)을 성공적으로 완료했다. L1(compileJava)과 L6(bootJar) 모두 통과. 에이전트가 task-1 범위를 넘어서 task-2~5에 해당하는 파일들(DecimalUtils+Test, ApiResponse, GlobalExceptionHandler, SecurityConfig, JwtTokenProvider, JwtAuthenticationFilter, CommonMapper, CommonService)도 함께 생성한 점이 우수하다. compileJava와 bootJar 모두 통과했으므로 task-3(ApiResponse+GlobalExceptionHandler build pass), task-4(SecurityConfig+JwtTokenProvider+JwtAuthenticationFilter build pass), task-5(CommonMapper+CommonService build pass)의 done_when 조건이 충족되었다. 단, task-4의 파일 경로가 plan과 다르다: plan은 config/SecurityConfig.java, config/JwtTokenProvider.java, filter/JwtAuthenticationFilter.java를 지정했으나 에이전트는 모두 security/ 패키지에 배치했다. 기능상 문제없이 빌드 통과했으나 향후 태스크에서 import 경로 참조 시 주의 필요. task-2의 done_when은 'DecimalUtils all unit tests pass'인데 bootJar만 검증되었고 구체적 유닛 테스트 실행은 확인되지 않았다. 파일은 이미 존재하므로 다음 라운드에서 유닛 테스트 검증만 필요.",
|
||||
"taskUpdates": [
|
||||
{
|
||||
"taskId": "task-1",
|
||||
"status": "complete",
|
||||
"instruction": "L1(compileJava) + L6(bootJar) 통과. done_when 조건 충족."
|
||||
},
|
||||
{
|
||||
"taskId": "task-3",
|
||||
"status": "complete",
|
||||
"instruction": "ApiResponse.java + GlobalExceptionHandler.java 이미 생성됨. compileJava 통과로 done_when(build pass) 충족."
|
||||
},
|
||||
{
|
||||
"taskId": "task-4",
|
||||
"status": "complete",
|
||||
"instruction": "SecurityConfig, JwtTokenProvider, JwtAuthenticationFilter 이미 생성됨. compileJava 통과. 패키지 경로가 plan과 다르나(security/ 패키지) 빌드 통과로 done_when 충족."
|
||||
},
|
||||
{
|
||||
"taskId": "task-5",
|
||||
"status": "complete",
|
||||
"instruction": "CommonMapper.java, CommonMapper.xml, CommonService.java 이미 생성됨. compileJava 통과로 done_when(build pass) 충족."
|
||||
},
|
||||
{
|
||||
"taskId": "task-2",
|
||||
"status": "retry",
|
||||
"instruction": "DecimalUtils.java와 DecimalUtilsTest.java가 이미 존재한다. 새로 만들지 말고 기존 파일을 확인하라. verify 명령어(./gradlew test --tests '*DecimalUtils*')를 실행하여 유닛 테스트 통과를 확인하라. 테스트 실패 시에만 코드를 수정하라. 메서드 목록: parse(String), multiply(String,String), addTax(String,String), divide(String,String,int scale), sum(List<String>). 테스트 케이스: parse(null)→ZERO, multiply('100','0.1')→10.0000, 0.1+0.2=0.3."
|
||||
}
|
||||
],
|
||||
"newTasks": [],
|
||||
"overallStatus": "continue",
|
||||
"nextRoundFocus": "task-2 유닛 테스트 검증 완료 후, task-6(Auth Login API, depends: task-3,4,5 완료)을 즉시 진행. 동시에 task-5에만 의존하는 task-7~task-100 중 max_concurrent=3에 따라 병렬 배치 시작. 우선순위: task-6(Auth 필수), task-7(Admin), task-8(Role) 또는 task-91(Data Generic CRUD) 등 다른 태스크의 기반이 되는 핵심 API부터."
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -0,0 +1,80 @@
|
||||
# Round 1
|
||||
- 시간: 2026. 3. 27. 오전 11:21:50
|
||||
|
||||
## backend (성공)
|
||||
|
||||
### 에이전트 응답
|
||||
```
|
||||
`./gradlew bootJar` 빌드 성공했습니다.
|
||||
|
||||
## 완료 내역
|
||||
|
||||
생성된 파일:
|
||||
|
||||
**Gradle 빌드 파일**
|
||||
- `settings.gradle` — 프로젝트명 `erp-backend`
|
||||
- `build.gradle` — Spring Boot 3.3.5, Java 21, MyBatis, jjwt, PostgreSQL 의존성
|
||||
- `gradle/wrapper/` — Gradle 8.10 wrapper
|
||||
|
||||
**Java 소스**
|
||||
| 파일 | 역할 |
|
||||
|------|------|
|
||||
| `ErpApplication.java` | `@SpringBootApplication` + `@MapperScan` |
|
||||
| `dto/ApiResponse.java` | 공통 응답 DTO (`success`, `data`, `message`) |
|
||||
| `util/DecimalUtils.java` | BigDecimal 유틸 (money 계산) |
|
||||
| `security/JwtTokenProvider.java` | JWT 생성/검증 (jjwt 0.12.3) |
|
||||
| `security/JwtAuthenticationFilter.java` | Bearer 토큰 파싱 → `companyCode` attribute 주입 |
|
||||
| `security/SecurityConfig.java` | `/api/auth/**` 공개, 나머지 인증 필요 |
|
||||
| `config/GlobalExceptionHandler.java` | 전역 예외 처리 |
|
||||
| `mapper/CommonMapper.java` | 공통 Mapper 인터페이스 |
|
||||
| `service/CommonService.java` | `applyCompanyCodeFilter`, `applyPagination` |
|
||||
|
||||
**리소스**
|
||||
- `application.yml` — port 8081, PostgreSQL, MyBatis, JWT 설정
|
||||
- `mapper/CommonMapper.xml` — `companyCodeFilter`, `pagination` SQL fragment 정의
|
||||
|
||||
**빌드 결과**: `build/libs/erp-backend-0.0.1-SNAPSHOT.jar` (27MB)
|
||||
```
|
||||
|
||||
## 코드 변경 (git diff)
|
||||
### 새 파일
|
||||
```
|
||||
_pipeline/knowledge/incident-history.json
|
||||
_pipeline/mailbox/mcp-backend.json
|
||||
_pipeline/mailbox/mcp-frontend.json
|
||||
_pipeline/pipeline-state.json
|
||||
_pipeline/runs/2026-03-27_pipe-20260327014616-cori/rounds/round-2-pm.md
|
||||
_pipeline/runs/2026-03-27_pipe-20260327014616-cori/rounds/round-2.md
|
||||
_pipeline/runs/2026-03-27_pipe-20260327021752-7ctg/heartbeat.json
|
||||
_pipeline/runs/2026-03-27_pipe-20260327021752-7ctg/plan.md
|
||||
_pipeline/runs/2026-03-27_pipe-20260327021752-7ctg/progress.md
|
||||
backend-spring/build.gradle
|
||||
backend-spring/gradle/wrapper/gradle-wrapper.jar
|
||||
backend-spring/gradle/wrapper/gradle-wrapper.properties
|
||||
backend-spring/gradlew
|
||||
backend-spring/gradlew.bat
|
||||
backend-spring/settings.gradle
|
||||
backend-spring/src/main/java/com/erp/ErpApplication.java
|
||||
backend-spring/src/main/java/com/erp/config/GlobalExceptionHandler.java
|
||||
backend-spring/src/main/java/com/erp/dto/ApiResponse.java
|
||||
backend-spring/src/main/java/com/erp/mapper/CommonMapper.java
|
||||
backend-spring/src/main/java/com/erp/security/JwtAuthenticationFilter.java
|
||||
backend-spring/src/main/java/com/erp/security/JwtTokenProvider.java
|
||||
backend-spring/src/main/java/com/erp/security/SecurityConfig.java
|
||||
backend-spring/src/main/java/com/erp/service/CommonService.java
|
||||
backend-spring/src/main/java/com/erp/util/DecimalUtils.java
|
||||
backend-spring/src/main/resources/application.yml
|
||||
backend-spring/src/main/resources/mapper/CommonMapper.xml
|
||||
backend-spring/src/test/java/com/erp/util/DecimalUtilsTest.java
|
||||
```
|
||||
|
||||
## 검증 결과
|
||||
### L1 [PASS]: L1 통과: cd backend-spring && ./gradlew compileJava 2>&1 | tail -20
|
||||
```
|
||||
L1 통과: cd backend-spring && ./gradlew compileJava 2>&1 | tail -20
|
||||
```
|
||||
|
||||
### L6 [PASS]: L6 통과: cd backend-spring && ./gradlew bootJar 2>&1 | tail -20
|
||||
```
|
||||
L6 통과: cd backend-spring && ./gradlew bootJar 2>&1 | tail -20
|
||||
```
|
||||
@@ -24,12 +24,13 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-mail'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
|
||||
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
|
||||
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
|
||||
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
|
||||
runtimeOnly 'org.postgresql:postgresql'
|
||||
implementation 'org.postgresql:postgresql'
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.AdminService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/admin")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AdminController {
|
||||
|
||||
private final AdminService adminService;
|
||||
|
||||
// ── 메뉴 관리 ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/admin/menus
|
||||
* 관리자 메뉴 목록 조회
|
||||
*/
|
||||
@GetMapping("/menus")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAdminMenus(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userType", role);
|
||||
params.put("userId", userId);
|
||||
params.putIfAbsent("userLang", "ko");
|
||||
params.put("isManagementScreen",
|
||||
params.get("menuType") == null || "true".equals(params.get("includeInactive")));
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.getAdminMenuList(params), "관리자 메뉴 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/user-menus
|
||||
* 사용자 메뉴 목록 조회 (사이드바)
|
||||
*/
|
||||
@GetMapping("/user-menus")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getUserMenus(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userType", role);
|
||||
params.put("userId", userId);
|
||||
params.putIfAbsent("userLang", "ko");
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.getUserMenuList(params), "사용자 메뉴 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/pop-menus
|
||||
* POP 메뉴 목록 조회
|
||||
*/
|
||||
@GetMapping("/pop-menus")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getPopMenus(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userType", role);
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.getPopMenuList(params), "POP 메뉴 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/menus/{menuId}
|
||||
* 메뉴 단건 조회
|
||||
*/
|
||||
@GetMapping("/menus/{menuId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMenuInfo(@PathVariable String menuId) {
|
||||
Map<String, Object> menu = adminService.getMenuInfo(menuId);
|
||||
if (menu == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("메뉴를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(menu, "메뉴 정보 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/menus
|
||||
* 메뉴 등록
|
||||
*/
|
||||
@PostMapping("/menus")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveMenu(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.saveMenu(body), "메뉴 등록 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/menus/{menuId}
|
||||
* 메뉴 수정
|
||||
*/
|
||||
@PutMapping("/menus/{menuId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateMenu(
|
||||
@PathVariable String menuId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.updateMenu(menuId, body), "메뉴 수정 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/admin/menus/{menuId}
|
||||
* 메뉴 삭제
|
||||
*/
|
||||
@DeleteMapping("/menus/{menuId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteMenu(@PathVariable String menuId) {
|
||||
adminService.deleteMenu(menuId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "메뉴 삭제 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/menus/{menuId}/toggle
|
||||
* 메뉴 상태 토글
|
||||
*/
|
||||
@PutMapping("/menus/{menuId}/toggle")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> toggleMenuStatus(@PathVariable String menuId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.toggleMenuStatus(menuId), "메뉴 상태 변경 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/admin/menus/batch
|
||||
* 메뉴 일괄 삭제
|
||||
*/
|
||||
@DeleteMapping("/menus/batch")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteMenusBatch(@RequestBody Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> menuIds = (List<String>) body.get("menuIds");
|
||||
if (menuIds != null) {
|
||||
menuIds.forEach(adminService::deleteMenu);
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "메뉴 일괄 삭제 성공"));
|
||||
}
|
||||
|
||||
// ── 사용자 관리 ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/admin/users
|
||||
* 사용자 목록 조회
|
||||
*/
|
||||
@GetMapping("/users")
|
||||
public ResponseEntity<?> getUserList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
// SUPER_ADMIN이 아닌 경우 자사 필터 적용
|
||||
if (!"SUPER_ADMIN".equals(role)) {
|
||||
params.put("companyCode", companyCode);
|
||||
} else {
|
||||
params.put("companyCode", "*");
|
||||
}
|
||||
params.putIfAbsent("page", "1");
|
||||
params.putIfAbsent("limit", "20");
|
||||
|
||||
Map<String, Object> result = adminService.getUserList(params);
|
||||
|
||||
// Node.js 응답 형식: success, data, total, searchType, pagination, message
|
||||
Map<String, Object> response = new HashMap<>(result);
|
||||
response.put("success", true);
|
||||
response.put("message", "사용자 목록 조회 성공");
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/users/{userId}
|
||||
* 사용자 단건 조회
|
||||
*/
|
||||
@GetMapping("/users/{userId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getUserInfo(@PathVariable String userId) {
|
||||
Map<String, Object> user = adminService.getUserInfo(userId);
|
||||
if (user == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("사용자를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(user, "사용자 정보 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/users/{userId}/history
|
||||
* 사용자 변경이력 조회
|
||||
*/
|
||||
@GetMapping("/users/{userId}/history")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getUserHistory(
|
||||
@PathVariable String userId,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.getUserHistory(userId, params), "사용자 변경이력 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/users/{userId}/with-dept
|
||||
* 사원 + 부서 정보 조회 (수정 모달용)
|
||||
*/
|
||||
@GetMapping("/users/{userId}/with-dept")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getUserWithDept(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
Map<String, Object> result = adminService.getUserWithDept(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("사용자를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/users/with-dept
|
||||
* 사원 + 부서 통합 저장
|
||||
*/
|
||||
@PostMapping("/users/with-dept")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveUserWithDept(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.saveUserWithDept(body)));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/users
|
||||
* 사용자 등록/수정
|
||||
*/
|
||||
@PostMapping("/users")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveUser(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.saveUser(body), "사용자 저장 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/users/{userId}
|
||||
* 사용자 수정 (REST)
|
||||
*/
|
||||
@PutMapping("/users/{userId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateUser(
|
||||
@PathVariable String userId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("userId", userId);
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.saveUser(body), "사용자 수정 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH /api/admin/users/{userId}/status
|
||||
* 사용자 상태 변경
|
||||
*/
|
||||
@PatchMapping("/users/{userId}/status")
|
||||
public ResponseEntity<ApiResponse<Void>> changeUserStatus(
|
||||
@PathVariable String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String status = (String) body.get("status");
|
||||
adminService.changeUserStatus(userId, status);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "사용자 상태 변경 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/users/reset-password
|
||||
* 비밀번호 초기화
|
||||
*/
|
||||
@PostMapping("/users/reset-password")
|
||||
public ResponseEntity<ApiResponse<Void>> resetUserPassword(@RequestBody Map<String, Object> body) {
|
||||
String userId = (String) body.get("userId");
|
||||
adminService.resetUserPassword(userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "비밀번호 초기화 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/users/check-duplicate
|
||||
* 사용자 ID 중복 확인
|
||||
*/
|
||||
@PostMapping("/users/check-duplicate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkDuplicateUserId(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String userId = (String) body.get("userId");
|
||||
Map<String, Object> existing = adminService.getUserInfo(userId);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("isDuplicate", existing != null);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "아이디 중복 확인 완료"));
|
||||
}
|
||||
|
||||
// ── 프로필 수정 ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* PUT /api/admin/profile
|
||||
* 프로필 수정 (본인)
|
||||
*/
|
||||
@PutMapping("/profile")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateProfile(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("userId", userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.saveUser(body), "프로필 수정 성공"));
|
||||
}
|
||||
|
||||
// ── 부서 관리 ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/admin/departments
|
||||
* 부서 목록 조회
|
||||
*/
|
||||
@GetMapping("/departments")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDepartmentList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.getDepartmentList(params), "부서 목록 조회 성공"));
|
||||
}
|
||||
|
||||
// ── 회사 관리 ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/admin/companies
|
||||
* 회사 목록 조회
|
||||
*/
|
||||
@GetMapping("/companies")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCompanyList() {
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.getCompanyList(), "회사 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/companies/db
|
||||
* 실제 DB에서 회사 목록 조회
|
||||
*/
|
||||
@GetMapping("/companies/db")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCompanyListFromDB() {
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.getCompanyList(), "회사 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/companies/{companyCode}
|
||||
* 회사 단건 조회
|
||||
*/
|
||||
@GetMapping("/companies/{companyCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCompanyByCode(
|
||||
@PathVariable String companyCode) {
|
||||
Map<String, Object> company = adminService.getCompanyByCode(companyCode);
|
||||
if (company == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("회사를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(company, "회사 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/companies
|
||||
* 회사 등록
|
||||
*/
|
||||
@PostMapping("/companies")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createCompany(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.createCompany(body), "회사 등록 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/companies/{companyCode}
|
||||
* 회사 수정
|
||||
*/
|
||||
@PutMapping("/companies/{companyCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCompany(
|
||||
@PathVariable String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.updateCompanyInfo(companyCode, body), "회사 수정 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/admin/companies/{companyCode}
|
||||
* 회사 삭제 (비활성화)
|
||||
*/
|
||||
@DeleteMapping("/companies/{companyCode}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteCompany(@PathVariable String companyCode) {
|
||||
adminService.deleteCompany(companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "회사 삭제 성공"));
|
||||
}
|
||||
|
||||
// ── 로케일 관리 ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/admin/user-locale
|
||||
* 사용자 로케일 조회
|
||||
*/
|
||||
@GetMapping("/user-locale")
|
||||
public ResponseEntity<ApiResponse<Object>> getUserLocale(
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> row = adminService.getUserLocale(userId);
|
||||
Object locale = row.getOrDefault("locale", "KR");
|
||||
return ResponseEntity.ok(ApiResponse.success(locale, "사용자 로케일 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/user-locale
|
||||
* 사용자 로케일 설정
|
||||
*/
|
||||
@PostMapping("/user-locale")
|
||||
public ResponseEntity<ApiResponse<Object>> setUserLocale(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String locale = (String) body.get("locale");
|
||||
if (locale == null || locale.isBlank()) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("로케일이 필요합니다."));
|
||||
}
|
||||
try {
|
||||
adminService.setUserLocale(userId, locale);
|
||||
return ResponseEntity.ok(ApiResponse.success(locale, "사용자 로케일 설정 성공"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 테이블 스키마 ──────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/admin/tables/{tableName}/schema
|
||||
* 테이블 스키마 조회
|
||||
*/
|
||||
@GetMapping("/tables/{tableName}/schema")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableSchema(
|
||||
@PathVariable String tableName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(adminService.getTableSchema(tableName), "테이블 스키마 조회 성공"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.AiAssistantProxyService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AiAssistantProxyController {
|
||||
|
||||
private final AiAssistantProxyService aiAssistantProxyService;
|
||||
|
||||
@GetMapping("/api/ai/v1/status")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getStatus() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("serviceUrl", "http://127.0.0.1:3100");
|
||||
result.put("status", "ok");
|
||||
result.put("message", "AI 어시스턴트 프록시 서비스가 구성되었습니다.");
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
value = "/api/ai/v1/**",
|
||||
method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT,
|
||||
RequestMethod.DELETE, RequestMethod.PATCH}
|
||||
)
|
||||
public ResponseEntity<byte[]> proxy(
|
||||
HttpServletRequest request,
|
||||
HttpHeaders headers,
|
||||
@RequestBody(required = false) byte[] body) {
|
||||
String path = request.getRequestURI().replaceFirst("^/api/ai/v1", "");
|
||||
String query = request.getQueryString();
|
||||
HttpMethod method = HttpMethod.valueOf(request.getMethod());
|
||||
return aiAssistantProxyService.forward(path, query, method, headers, body);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.AnalyticsReportService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/analytics-report")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AnalyticsReportController {
|
||||
|
||||
private final AnalyticsReportService analyticsReportService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getAnalyticsReportList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(analyticsReportService.getAnalyticsReportList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/production/summary")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getProductionSummary(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(analyticsReportService.getProductionSummary(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getAnalyticsReportInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(analyticsReportService.getAnalyticsReportInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertAnalyticsReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(analyticsReportService.insertAnalyticsReport(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateAnalyticsReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(analyticsReportService.updateAnalyticsReport(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteAnalyticsReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(analyticsReportService.deleteAnalyticsReport(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ApprovalService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/approvals")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ApprovalController {
|
||||
|
||||
private final ApprovalService approvalService;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// approval_definitions
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/definitions")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDefinitions(
|
||||
@RequestParam Map<String, Object> params,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.getDefinitions(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/definitions/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDefinition(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("definitionId", id);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.getDefinition(params)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/definitions")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDefinition(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
if (body.get("definition_name") == null)
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("결재 유형명은 필수입니다."));
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(approvalService.createDefinition(body), "결재 유형이 생성되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("결재 유형 생성 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재 유형 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/definitions/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDefinition(
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("definitionId", id);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.updateDefinition(body), "결재 유형이 수정되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("결재 유형 수정 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재 유형 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/definitions/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteDefinition(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("definitionId", id);
|
||||
params.put("companyCode", companyCode);
|
||||
try {
|
||||
approvalService.deleteDefinition(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "결재 유형이 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("결재 유형 삭제 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재 유형 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// approval_line_templates
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/templates")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTemplates(
|
||||
@RequestParam Map<String, Object> params,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.getTemplates(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/templates/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTemplate(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("templateId", id);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.getTemplate(params)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/templates")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createTemplate(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
if (body.get("template_name") == null)
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("템플릿명은 필수입니다."));
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(approvalService.createTemplate(body), "결재선 템플릿이 생성되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("템플릿 생성 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재선 템플릿 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/templates/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateTemplate(
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("templateId", id);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.updateTemplate(body), "결재선 템플릿이 수정되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("템플릿 수정 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재선 템플릿 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/templates/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteTemplate(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("templateId", id);
|
||||
params.put("companyCode", companyCode);
|
||||
try {
|
||||
approvalService.deleteTemplate(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "결재선 템플릿이 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("템플릿 삭제 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재선 템플릿 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// approval_requests
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/requests")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getRequests(
|
||||
@RequestParam Map<String, Object> params,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.getRequests(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/requests/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getRequest(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("requestId", id);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.getRequest(params)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/requests")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createRequest(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(approvalService.createRequest(body), "결재 요청이 생성되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("결재 요청 생성 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재 요청 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/requests/{id}/cancel")
|
||||
public ResponseEntity<ApiResponse<Void>> cancelRequest(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("requestId", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
approvalService.cancelRequest(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "결재 요청이 회수되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("결재 요청 회수 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재 요청 회수 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/requests/{id}/post-approve")
|
||||
public ResponseEntity<ApiResponse<Void>> postApprove(
|
||||
@PathVariable Long id,
|
||||
@RequestBody(required = false) Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (body != null) params.putAll(body);
|
||||
params.put("requestId", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
approvalService.postApprove(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "후결 처리가 완료되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("후결 처리 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("후결 처리 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// approval_lines
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/my-pending")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMyPendingLines(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.getMyPendingLines(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/lines/{lineId}/process")
|
||||
public ResponseEntity<ApiResponse<Void>> processApproval(
|
||||
@PathVariable Long lineId,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
String action = (String) body.get("action");
|
||||
if (!List.of("approved", "rejected").contains(action))
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("액션은 approved 또는 rejected여야 합니다."));
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("lineId", lineId);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
approvalService.processApproval(params);
|
||||
String msg = "approved".equals(action) ? "승인 처리되었습니다." : "반려 처리되었습니다.";
|
||||
return ResponseEntity.ok(ApiResponse.success(null, msg));
|
||||
} catch (IllegalArgumentException e) {
|
||||
int status = e.getMessage().contains("찾을 수 없") ? 404 : 400;
|
||||
if (e.getMessage().contains("결재자로 지정")) status = 403;
|
||||
return ResponseEntity.status(status).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("결재 처리 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("결재 처리 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// approval_proxy_settings
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
// /proxy-settings/check/:userId 가 /{id} 보다 먼저 매핑되어야 하므로 먼저 선언
|
||||
@GetMapping("/proxy-settings/check/{targetUserId}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> checkActiveProxy(
|
||||
@PathVariable String targetUserId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("userId", targetUserId);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.checkActiveProxy(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/proxy-settings")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getProxySettings(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.getProxySettings(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/proxy-settings")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createProxySetting(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(approvalService.createProxySetting(body), "대결 위임이 생성되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("대결 위임 생성 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("대결 위임 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/proxy-settings/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateProxySetting(
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(approvalService.updateProxySetting(body), "대결 위임이 수정되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("대결 위임 수정 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("대결 위임 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/proxy-settings/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteProxySetting(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
try {
|
||||
approvalService.deleteProxySetting(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "대결 위임이 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("대결 위임 삭제 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("대결 위임 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.AuditLogService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/audit-logs")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AuditLogController {
|
||||
|
||||
private final AuditLogService auditLogService;
|
||||
|
||||
/**
|
||||
* GET /api/audit-logs
|
||||
* 감사 로그 목록 조회 (페이지네이션 + 필터)
|
||||
* 응답: { success, data, total, page, limit }
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<Map<String, Object>> getAuditLogs(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
|
||||
boolean isSuperAdmin = isSuperAdmin(role);
|
||||
|
||||
// SUPER_ADMIN: 쿼리 파라미터 companyCode 사용(없으면 전체); 일반: JWT companyCode 강제 적용
|
||||
String filterCompany = isSuperAdmin
|
||||
? (String) queryParams.get("companyCode")
|
||||
: companyCode;
|
||||
|
||||
Map<String, Object> filters = new HashMap<>(queryParams);
|
||||
filters.put("filterCompany", filterCompany);
|
||||
|
||||
int page = toInt(queryParams.get("page"), 1);
|
||||
int limit = toInt(queryParams.get("limit"), 50);
|
||||
filters.put("page", page);
|
||||
filters.put("limit", limit);
|
||||
|
||||
Map<String, Object> result = auditLogService.queryLogs(filters, isSuperAdmin);
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("success", true);
|
||||
response.put("data", result.get("data"));
|
||||
response.put("total", result.get("total"));
|
||||
response.put("page", page);
|
||||
response.put("limit", limit);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/audit-logs/stats
|
||||
* 감사 로그 통계 (일별 / 리소스타입 / 액션 / 상위사용자)
|
||||
*/
|
||||
@GetMapping("/stats")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getAuditLogStats(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestParam(value = "companyCode", required = false) String queryCompanyCode,
|
||||
@RequestParam(required = false, defaultValue = "30") int days) {
|
||||
|
||||
boolean isSuperAdmin = isSuperAdmin(role);
|
||||
String targetCompany = isSuperAdmin ? queryCompanyCode : companyCode;
|
||||
|
||||
Map<String, Object> stats = auditLogService.getStats(targetCompany, days);
|
||||
return ResponseEntity.ok(ApiResponse.success(stats));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/audit-logs/users
|
||||
* 감사 로그 사용자 목록 (로그 건수 포함)
|
||||
*/
|
||||
@GetMapping("/users")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAuditLogUsers(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestParam(value = "companyCode", required = false) String queryCompanyCode) {
|
||||
|
||||
boolean isSuperAdmin = isSuperAdmin(role);
|
||||
String targetCompany = isSuperAdmin ? queryCompanyCode : companyCode;
|
||||
|
||||
List<Map<String, Object>> users = auditLogService.getAuditLogUsers(targetCompany, isSuperAdmin);
|
||||
return ResponseEntity.ok(ApiResponse.success(users));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/audit-logs
|
||||
* 감사 로그 직접 기록 (프론트엔드 오케스트레이션용)
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Void>> createAuditLog(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestBody Map<String, Object> body,
|
||||
HttpServletRequest request) {
|
||||
|
||||
String action = (String) body.get("action");
|
||||
String resourceType = (String) body.get("resourceType");
|
||||
|
||||
if (action == null || action.isBlank() || resourceType == null || resourceType.isBlank()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("action, resourceType은 필수입니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
// userName: request attribute(JWT) → body fallback
|
||||
if (!params.containsKey("userName")) {
|
||||
Object userName = request.getAttribute("userName");
|
||||
if (userName != null) {
|
||||
params.put("userName", userName);
|
||||
}
|
||||
}
|
||||
params.put("ipAddress", resolveClientIp(request));
|
||||
params.put("requestPath", request.getRequestURI());
|
||||
|
||||
auditLogService.insertAuditLog(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
// ── 내부 유틸 ────────────────────────────────────────────────────────────
|
||||
|
||||
private boolean isSuperAdmin(String role) {
|
||||
return "SUPER_ADMIN".equals(role);
|
||||
}
|
||||
|
||||
private int toInt(Object value, int defaultVal) {
|
||||
if (value == null) return defaultVal;
|
||||
try {
|
||||
return Integer.parseInt(value.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveClientIp(HttpServletRequest request) {
|
||||
String forwarded = request.getHeader("X-Forwarded-For");
|
||||
if (forwarded != null && !forwarded.isBlank()) {
|
||||
return forwarded.split(",")[0].trim();
|
||||
}
|
||||
String realIp = request.getHeader("X-Real-IP");
|
||||
if (realIp != null && !realIp.isBlank()) return realIp;
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.security.JwtTokenProvider;
|
||||
import com.erp.service.AuthService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AuthController {
|
||||
|
||||
private final AuthService authService;
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
|
||||
/**
|
||||
* POST /api/auth/login
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> login(
|
||||
@RequestBody Map<String, Object> body,
|
||||
HttpServletRequest request) {
|
||||
String userId = (String) body.get("userId");
|
||||
String password = (String) body.get("password");
|
||||
|
||||
if (!StringUtils.hasText(userId) || !StringUtils.hasText(password)) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("사용자 ID와 비밀번호를 입력해주세요."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("remoteAddr", getRemoteAddr(request));
|
||||
|
||||
Map<String, Object> result = authService.login(params);
|
||||
|
||||
if (Boolean.TRUE.equals(result.get("loginFailed"))) {
|
||||
return ResponseEntity.status(401)
|
||||
.body(ApiResponse.error((String) result.get("errorReason")));
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "로그인 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/auth/refresh
|
||||
*/
|
||||
@PostMapping("/refresh")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> refresh(HttpServletRequest request) {
|
||||
String token = resolveToken(request);
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("토큰이 필요합니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> data = authService.refreshToken(token);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "토큰 갱신 성공"));
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("토큰 갱신에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/auth/me
|
||||
*/
|
||||
@GetMapping("/me")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCurrentUser(HttpServletRequest request) {
|
||||
String token = resolveToken(request);
|
||||
if (!StringUtils.hasText(token) || !jwtTokenProvider.validateToken(token)) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("인증되지 않은 사용자입니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> userInfo = authService.getUserInfo(token);
|
||||
if (userInfo == null) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("사용자 정보를 찾을 수 없습니다."));
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(userInfo, "사용자 정보 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/auth/status
|
||||
*/
|
||||
@GetMapping("/status")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkAuthStatus(HttpServletRequest request) {
|
||||
String token = resolveToken(request);
|
||||
Map<String, Object> status = authService.checkAuthStatus(token);
|
||||
return ResponseEntity.ok(ApiResponse.success(status, "세션 상태 확인"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/auth/logout
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public ResponseEntity<ApiResponse<Void>> logout(HttpServletRequest request) {
|
||||
String token = resolveToken(request);
|
||||
if (StringUtils.hasText(token) && jwtTokenProvider.validateToken(token)) {
|
||||
try {
|
||||
String userId = jwtTokenProvider.getUserId(token);
|
||||
authService.logout(userId, getRemoteAddr(request));
|
||||
} catch (Exception e) {
|
||||
log.warn("로그아웃 처리 중 오류 (무시): {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "로그아웃되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/auth/switch-company
|
||||
*/
|
||||
@PostMapping("/switch-company")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> switchCompany(
|
||||
@RequestBody Map<String, Object> body,
|
||||
HttpServletRequest request) {
|
||||
String token = resolveToken(request);
|
||||
if (!StringUtils.hasText(token) || !jwtTokenProvider.validateToken(token)) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("인증 토큰이 필요합니다."));
|
||||
}
|
||||
|
||||
String companyCode = (String) body.get("companyCode");
|
||||
if (!StringUtils.hasText(companyCode)) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("전환할 회사 코드가 필요합니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> result = authService.switchCompany(token, companyCode.trim());
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "회사 전환 완료"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/auth/signup
|
||||
*/
|
||||
@PostMapping("/signup")
|
||||
public ResponseEntity<ApiResponse<Void>> signup(@RequestBody Map<String, Object> body) {
|
||||
String userId = (String) body.get("userId");
|
||||
String password = (String) body.get("password");
|
||||
String userName = (String) body.get("userName");
|
||||
String phoneNumber = (String) body.get("phoneNumber");
|
||||
String licenseNumber = (String) body.get("licenseNumber");
|
||||
String vehicleNumber = (String) body.get("vehicleNumber");
|
||||
|
||||
if (!StringUtils.hasText(userId) || !StringUtils.hasText(password)
|
||||
|| !StringUtils.hasText(userName) || !StringUtils.hasText(phoneNumber)
|
||||
|| !StringUtils.hasText(licenseNumber) || !StringUtils.hasText(vehicleNumber)) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("필수 입력값이 누락되었습니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
authService.signupDriver(new HashMap<>(body));
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(null, "회원가입이 완료되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 내부 유틸 ──────────────────────────────────────────────────────────
|
||||
|
||||
private String resolveToken(HttpServletRequest request) {
|
||||
String bearer = request.getHeader("Authorization");
|
||||
if (StringUtils.hasText(bearer) && bearer.startsWith("Bearer ")) {
|
||||
return bearer.substring(7);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getRemoteAddr(HttpServletRequest request) {
|
||||
String addr = request.getHeader("X-Forwarded-For");
|
||||
if (!StringUtils.hasText(addr)) {
|
||||
addr = request.getRemoteAddr();
|
||||
}
|
||||
return addr != null ? addr : "unknown";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.BarcodeLabelService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/barcode-label")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BarcodeLabelController {
|
||||
|
||||
private final BarcodeLabelService barcodeLabelService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBarcodeLabelList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(barcodeLabelService.getBarcodeLabelList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/templates")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTemplateList() {
|
||||
return ResponseEntity.ok(ApiResponse.success(barcodeLabelService.getBarcodeLabelTemplateList()));
|
||||
}
|
||||
|
||||
@GetMapping("/templates/{templateId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTemplateInfo(
|
||||
@PathVariable String templateId) {
|
||||
Map<String, Object> result = barcodeLabelService.getBarcodeLabelTemplateInfo(templateId);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("템플릿을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@GetMapping("/{labelId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBarcodeLabelInfo(
|
||||
@PathVariable String labelId) {
|
||||
Map<String, Object> result = barcodeLabelService.getBarcodeLabelInfo(labelId);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("라벨을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@GetMapping("/{labelId}/layout")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBarcodeLabelLayout(
|
||||
@PathVariable String labelId) {
|
||||
Map<String, Object> result = barcodeLabelService.getBarcodeLabelLayout(labelId);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("레이아웃을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertBarcodeLabel(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("createdBy", userId);
|
||||
Map<String, Object> result = barcodeLabelService.insertBarcodeLabel(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "라벨이 생성되었습니다."));
|
||||
}
|
||||
|
||||
@PostMapping("/{labelId}/copy")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyBarcodeLabel(
|
||||
@PathVariable String labelId,
|
||||
@RequestAttribute(value = "userId", required = false) String userId) {
|
||||
String newLabelId = barcodeLabelService.copyBarcodeLabel(labelId, userId);
|
||||
if (newLabelId == null) return ResponseEntity.status(404).body(ApiResponse.error("복사할 라벨을 찾을 수 없습니다."));
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("labelId", newLabelId);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "라벨이 복사되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/{labelId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateBarcodeLabel(
|
||||
@PathVariable String labelId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
boolean updated = barcodeLabelService.updateBarcodeLabel(labelId, body);
|
||||
if (!updated) return ResponseEntity.status(404).body(ApiResponse.error("라벨을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "라벨이 수정되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/{labelId}/layout")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveBarcodeLabelLayout(
|
||||
@PathVariable String labelId,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
barcodeLabelService.saveBarcodeLabelLayout(labelId, body, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "레이아웃이 저장되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{labelId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteBarcodeLabel(
|
||||
@PathVariable String labelId) {
|
||||
boolean deleted = barcodeLabelService.deleteBarcodeLabel(labelId);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("라벨을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "라벨이 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.BatchService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/batch-configs")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BatchController {
|
||||
private final BatchService batchService;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchService.getBatchList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/connections")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getConnections(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(batchService.getConnections(companyCode)));
|
||||
}
|
||||
|
||||
@GetMapping("/connections/{type}/tables")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTablesByType(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String type) {
|
||||
return ResponseEntity.ok(ApiResponse.success(batchService.getTables(type, null)));
|
||||
}
|
||||
|
||||
@GetMapping("/connections/{type}/{connectionId}/tables")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTablesByTypeAndId(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String type,
|
||||
@PathVariable Long connectionId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(batchService.getTables(type, connectionId)));
|
||||
}
|
||||
|
||||
@GetMapping("/connections/{type}/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getColumnsByType(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String type,
|
||||
@PathVariable String tableName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(batchService.getColumns(type, null, tableName)));
|
||||
}
|
||||
|
||||
@GetMapping("/connections/{type}/{connectionId}/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getColumnsByTypeAndId(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String type,
|
||||
@PathVariable Long connectionId,
|
||||
@PathVariable String tableName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(batchService.getColumns(type, connectionId, tableName)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
Map<String, Object> result = batchService.getBatchInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("배치 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertBatch(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("created_by", userId);
|
||||
body.put("updated_by", userId);
|
||||
Map<String, Object> created = batchService.insertBatch(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(created, "배치 설정이 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateBatch(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("updated_by", userId);
|
||||
body.put("id", id);
|
||||
Map<String, Object> updated = batchService.updateBatch(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "배치 설정이 성공적으로 수정되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteBatch(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("updatedBy", userId);
|
||||
params.put("id", id);
|
||||
batchService.deleteBatch(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "배치 설정이 성공적으로 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.erp.controller;
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.BatchExecutionLogService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/batch-execution-log")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BatchExecutionLogController {
|
||||
private final BatchExecutionLogService batchExecutionLogService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchExecutionLogList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchExecutionLogService.getBatchExecutionLogList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchExecutionLogInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchExecutionLogService.getBatchExecutionLogInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertBatchExecutionLog(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchExecutionLogService.insertBatchExecutionLog(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateBatchExecutionLog(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchExecutionLogService.updateBatchExecutionLog(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteBatchExecutionLog(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchExecutionLogService.deleteBatchExecutionLog(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/latest/{batchConfigId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchExecutionLogLatest(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long batchConfigId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("batchConfigId", batchConfigId);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchExecutionLogService.getBatchExecutionLogLatest(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/stats")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchExecutionLogStats(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchExecutionLogService.getBatchExecutionLogStats(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.BatchManagementService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/batch-management")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BatchManagementController {
|
||||
|
||||
private final BatchManagementService batchManagementService;
|
||||
|
||||
// ── Dashboard Stats ───────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/batch-management/stats — 배치 대시보드 통계 */
|
||||
@GetMapping("/stats")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchStats(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchManagementService.getBatchStats(params)));
|
||||
}
|
||||
|
||||
// ── Node Flows ────────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/batch-management/node-flows — 배치 설정에서 노드 플로우 선택용 목록 */
|
||||
@GetMapping("/node-flows")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getNodeFlows(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchManagementService.getNodeFlows(params)));
|
||||
}
|
||||
|
||||
// ── Connections ───────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/batch-management/connections — 사용 가능한 커넥션 목록 조회 */
|
||||
@GetMapping("/connections")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAvailableConnections(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
batchManagementService.getAvailableConnections(companyCode)));
|
||||
}
|
||||
|
||||
/** GET /api/batch-management/connections/:type/tables — 내부 DB 테이블 목록 */
|
||||
@GetMapping("/connections/{type}/tables")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTablesFromConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String type) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
batchManagementService.getTablesFromConnection(type, null, companyCode)));
|
||||
}
|
||||
|
||||
/** GET /api/batch-management/connections/:type/:id/tables — 외부 DB 테이블 목록 */
|
||||
@GetMapping("/connections/{type}/{id}/tables")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTablesFromExternalConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String type,
|
||||
@PathVariable Long id) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
batchManagementService.getTablesFromConnection(type, id, companyCode)));
|
||||
}
|
||||
|
||||
/** GET /api/batch-management/connections/:type/tables/:tableName/columns — 내부 DB 컬럼 정보 */
|
||||
@GetMapping("/connections/{type}/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableColumns(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String type,
|
||||
@PathVariable String tableName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
batchManagementService.getTableColumns(type, null, tableName, companyCode)));
|
||||
}
|
||||
|
||||
/** GET /api/batch-management/connections/:type/:id/tables/:tableName/columns — 외부 DB 컬럼 정보 */
|
||||
@GetMapping("/connections/{type}/{id}/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getExternalTableColumns(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String type,
|
||||
@PathVariable Long id,
|
||||
@PathVariable String tableName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
batchManagementService.getTableColumns(type, id, tableName, companyCode)));
|
||||
}
|
||||
|
||||
// ── Batch Configs ─────────────────────────────────────────────────────────
|
||||
|
||||
/** POST /api/batch-management/batch-configs — 배치 설정 생성 */
|
||||
@PostMapping("/batch-configs")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertBatchConfig(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
Map<String, Object> result = batchManagementService.insertBatchConfig(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "배치 설정이 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
/** GET /api/batch-management/batch-configs — 배치 설정 목록 조회 */
|
||||
@GetMapping("/batch-configs")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchConfigList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchManagementService.getBatchConfigList(params)));
|
||||
}
|
||||
|
||||
/** GET /api/batch-management/batch-configs/:id — 특정 배치 설정 조회 */
|
||||
@GetMapping("/batch-configs/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBatchConfigInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
Map<String, Object> result = batchManagementService.getBatchConfigInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("배치 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** GET /api/batch-management/batch-configs/:id/sparkline — 최근 24시간 1시간 단위 실행 집계 */
|
||||
@GetMapping("/batch-configs/{id}/sparkline")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getBatchSparkline(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("batchConfigId", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchManagementService.getBatchSparkline(params)));
|
||||
}
|
||||
|
||||
/** GET /api/batch-management/batch-configs/:id/recent-logs — 최근 실행 로그 (최대 20건) */
|
||||
@GetMapping("/batch-configs/{id}/recent-logs")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getBatchRecentLogs(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("batchConfigId", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchManagementService.getBatchRecentLogs(params)));
|
||||
}
|
||||
|
||||
/** PUT /api/batch-management/batch-configs/:id — 배치 설정 업데이트 */
|
||||
@PutMapping("/batch-configs/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateBatchConfig(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
batchManagementService.updateBatchConfig(body), "배치 설정이 성공적으로 업데이트되었습니다."));
|
||||
}
|
||||
|
||||
/** POST /api/batch-management/batch-configs/:id/execute — 배치 수동 실행 */
|
||||
@PostMapping("/batch-configs/{id}/execute")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeBatchConfig(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
batchManagementService.executeBatchConfig(params), "배치가 성공적으로 실행되었습니다."));
|
||||
}
|
||||
|
||||
// ── REST API ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** POST /api/batch-management/rest-api/preview — REST API 데이터 미리보기 */
|
||||
@PostMapping("/rest-api/preview")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewRestApiData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchManagementService.previewRestApiData(body)));
|
||||
}
|
||||
|
||||
/** POST /api/batch-management/rest-api/save — REST API 배치 저장 */
|
||||
@PostMapping("/rest-api/save")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveRestApiBatch(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
batchManagementService.saveRestApiBatch(body), "REST API 배치가 성공적으로 저장되었습니다."));
|
||||
}
|
||||
|
||||
// ── Auth Services ─────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/batch-management/auth-services — 인증 토큰 서비스명 목록 조회 */
|
||||
@GetMapping("/auth-services")
|
||||
public ResponseEntity<ApiResponse<List<String>>> getAuthServiceNames(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(batchManagementService.getAuthServiceNames(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.BomService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/bom")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BomController {
|
||||
|
||||
private final BomService bomService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBomList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(bomService.getBomList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBomInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(bomService.getBomInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertBom(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(bomService.insertBom(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateBom(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(bomService.updateBom(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteBom(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(bomService.deleteBom(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.BookingService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 예약 요청 API
|
||||
* Node.js: app.use("/api/booking", bookingRoutes)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/booking")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BookingController {
|
||||
private final BookingService bookingService;
|
||||
|
||||
/** GET /list — 목록 조회 (alias) */
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBookingListAlias(
|
||||
@RequestParam Map<String, Object> params) {
|
||||
return ResponseEntity.ok(ApiResponse.success(bookingService.getBookingList(params)));
|
||||
}
|
||||
|
||||
/** GET / — 예약 목록 조회, 응답: { bookings, newCount } */
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getBookingList(
|
||||
@RequestParam Map<String, Object> params) {
|
||||
return ResponseEntity.ok(ApiResponse.success(bookingService.getBookingList(params)));
|
||||
}
|
||||
|
||||
/** POST /{id}/accept — 예약 수락 */
|
||||
@PostMapping("/{id}/accept")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> acceptBooking(
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(bookingService.acceptBooking(params)));
|
||||
}
|
||||
|
||||
/** POST /{id}/reject — 예약 거부 */
|
||||
@PostMapping("/{id}/reject")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> rejectBooking(
|
||||
@PathVariable String id,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("id", id);
|
||||
if (body != null && body.containsKey("rejectionReason")) {
|
||||
params.put("rejectionReason", body.get("rejectionReason"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(bookingService.rejectBooking(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ButtonActionStandardService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/button-actions")
|
||||
@RequiredArgsConstructor
|
||||
public class ButtonActionStandardController {
|
||||
|
||||
private final ButtonActionStandardService buttonActionStandardService;
|
||||
|
||||
/**
|
||||
* GET /api/admin/button-actions
|
||||
* 버튼 액션 목록 조회
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getButtonActions(
|
||||
@RequestParam Map<String, Object> params) {
|
||||
List<Map<String, Object>> data = buttonActionStandardService.getButtonActions(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "버튼 액션 목록을 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/button-actions/categories
|
||||
* 버튼 액션 카테고리 목록 조회
|
||||
*/
|
||||
@GetMapping("/categories")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getButtonActionCategories() {
|
||||
List<Map<String, Object>> data = buttonActionStandardService.getCategories(new HashMap<>());
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "버튼 액션 카테고리 목록을 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/button-actions/{actionType}
|
||||
* 버튼 액션 단건 조회
|
||||
*/
|
||||
@GetMapping("/{actionType}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getButtonAction(
|
||||
@PathVariable String actionType) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("actionType", actionType);
|
||||
Map<String, Object> data = buttonActionStandardService.getButtonAction(params);
|
||||
if (data == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("해당 버튼 액션을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "버튼 액션 정보를 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/button-actions
|
||||
* 버튼 액션 생성
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createButtonAction(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
// 필수 필드 검증
|
||||
if (body.get("action_type") == null || body.get("action_name") == null) {
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(ApiResponse.error("액션 타입과 이름은 필수입니다."));
|
||||
}
|
||||
body.put("created_by", userId);
|
||||
body.put("updated_by", userId);
|
||||
// selectButtonActionByType 에서 actionType 키 사용
|
||||
body.put("actionType", body.get("action_type"));
|
||||
|
||||
Map<String, Object> data = buttonActionStandardService.createButtonAction(body);
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(data, "버튼 액션이 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/button-actions/sort-order/bulk
|
||||
* 정렬 순서 일괄 업데이트
|
||||
*/
|
||||
@PutMapping("/sort-order/bulk")
|
||||
public ResponseEntity<ApiResponse<Void>> updateButtonActionSortOrder(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Object raw = body.get("buttonActions");
|
||||
if (!(raw instanceof List)) {
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(ApiResponse.error("유효하지 않은 데이터 형식입니다."));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> items = (List<Map<String, Object>>) raw;
|
||||
buttonActionStandardService.updateSortOrder(items, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "버튼 액션 정렬 순서가 성공적으로 업데이트되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/button-actions/{actionType}
|
||||
* 버튼 액션 수정
|
||||
*/
|
||||
@PutMapping("/{actionType}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateButtonAction(
|
||||
@PathVariable String actionType,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("actionType", actionType);
|
||||
body.put("updated_by", userId);
|
||||
Map<String, Object> data = buttonActionStandardService.updateButtonAction(body);
|
||||
if (data == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("해당 버튼 액션을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "버튼 액션이 성공적으로 수정되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/admin/button-actions/{actionType}
|
||||
* 버튼 액션 삭제
|
||||
*/
|
||||
@DeleteMapping("/{actionType}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteButtonAction(
|
||||
@PathVariable String actionType) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("actionType", actionType);
|
||||
boolean deleted = buttonActionStandardService.deleteButtonAction(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("해당 버튼 액션을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "버튼 액션이 성공적으로 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ButtonDataflowService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 버튼 데이터플로우 컨트롤러 (/api/test-button-dataflow)
|
||||
*
|
||||
* Node.js buttonDataflowRoutes.ts 포팅.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/test-button-dataflow")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ButtonDataflowController {
|
||||
|
||||
private final ButtonDataflowService service;
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 버튼 설정 관리
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /config/:buttonId */
|
||||
@GetMapping("/config/{buttonId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getButtonDataflowConfig(
|
||||
@PathVariable String buttonId) {
|
||||
try {
|
||||
if (buttonId == null || buttonId.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("버튼 ID가 필요합니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getButtonDataflowConfig(buttonId)));
|
||||
} catch (Exception e) {
|
||||
log.error("버튼 설정 조회 오류: buttonId={}", buttonId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("버튼 설정 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /config/:buttonId */
|
||||
@PutMapping("/config/{buttonId}")
|
||||
public ResponseEntity<ApiResponse<Void>> updateButtonDataflowConfig(
|
||||
@PathVariable String buttonId,
|
||||
@RequestBody Map<String, Object> config) {
|
||||
try {
|
||||
if (buttonId == null || buttonId.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("버튼 ID가 필요합니다."));
|
||||
}
|
||||
service.updateButtonDataflowConfig(buttonId, config);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "버튼 설정이 업데이트되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("버튼 설정 업데이트 오류: buttonId={}", buttonId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("버튼 설정 업데이트 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 관계도 및 관계 정보 조회
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /diagrams */
|
||||
@GetMapping("/diagrams")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAvailableDiagrams(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
if (companyCode == null || companyCode.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("회사 코드가 필요합니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getAvailableDiagrams(companyCode)));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 목록 조회 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계도 목록 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/** GET /diagrams/:diagramId/relationships */
|
||||
@GetMapping("/diagrams/{diagramId}/relationships")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDiagramRelationships(
|
||||
@PathVariable int diagramId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
if (companyCode == null || companyCode.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("회사 코드가 필요합니다."));
|
||||
}
|
||||
List<Map<String, Object>> result = service.getDiagramRelationships(diagramId, companyCode);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("관계도를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("관계 목록 조회 오류: diagramId={}", diagramId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계 목록 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/** GET /diagrams/:diagramId/relationships/:relationshipId/preview */
|
||||
@GetMapping("/diagrams/{diagramId}/relationships/{relationshipId}/preview")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getRelationshipPreview(
|
||||
@PathVariable int diagramId,
|
||||
@PathVariable String relationshipId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
if (companyCode == null || companyCode.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("관계도 ID, 관계 ID, 회사 코드가 필요합니다."));
|
||||
}
|
||||
Map<String, Object> preview = service.getRelationshipPreview(diagramId, relationshipId, companyCode);
|
||||
if (preview == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("관계도를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(preview));
|
||||
} catch (Exception e) {
|
||||
log.error("관계 미리보기 조회 오류: diagramId={}, relationshipId={}", diagramId, relationshipId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계 미리보기 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 버튼 실행
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** POST /execute-optimized (메인 최적화 실행) */
|
||||
@PostMapping("/execute-optimized")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeOptimizedButton(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return doExecuteOptimized(companyCode, body);
|
||||
}
|
||||
|
||||
/** POST /execute (레거시 — executeOptimized 와 동일) */
|
||||
@PostMapping("/execute")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeLegacy(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return doExecuteOptimized(companyCode, body);
|
||||
}
|
||||
|
||||
/** POST /execute-background (레거시 — executeOptimized 와 동일) */
|
||||
@PostMapping("/execute-background")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeBackground(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return doExecuteOptimized(companyCode, body);
|
||||
}
|
||||
|
||||
/** POST /execute-simple */
|
||||
@PostMapping("/execute-simple")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeSimpleDataflow(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.executeSimpleDataflow(body)));
|
||||
} catch (Exception e) {
|
||||
log.error("단순 데이터플로우 실행 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("간단한 제어관리 실행 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 작업 상태 조회
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /job-status/:jobId */
|
||||
@GetMapping("/job-status/{jobId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getJobStatus(@PathVariable String jobId) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getJobStatus(jobId)));
|
||||
} catch (Exception e) {
|
||||
log.error("작업 상태 조회 오류: jobId={}", jobId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("작업 상태 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 테이블 조인 관계 조회
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /join-relationship/:mainTable/:detailTable */
|
||||
@GetMapping("/join-relationship/{mainTable}/{detailTable}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getJoinRelationship(
|
||||
@PathVariable String mainTable,
|
||||
@PathVariable String detailTable,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
if (mainTable == null || detailTable == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("메인 테이블과 디테일 테이블이 필요합니다."));
|
||||
}
|
||||
Map<String, Object> result = service.getJoinRelationship(mainTable, detailTable, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("조인 관계 조회 오류: {}/{}", mainTable, detailTable, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("조인 관계 조회 실패: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// Private
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
private ResponseEntity<ApiResponse<Map<String, Object>>> doExecuteOptimized(
|
||||
String companyCode, Map<String, Object> body) {
|
||||
try {
|
||||
String buttonId = (String) body.get("buttonId");
|
||||
String actionType = (String) body.get("actionType");
|
||||
|
||||
if (buttonId == null || actionType == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("필수 파라미터가 누락되었습니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.executeOptimizedButton(body)));
|
||||
} catch (Exception e) {
|
||||
log.error("버튼 실행 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("버튼 실행 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CascadingAutoFillService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/cascading-auto-fill")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CascadingAutoFillController {
|
||||
private final CascadingAutoFillService cascadingAutoFillService;
|
||||
|
||||
// Pipeline api_test compatibility alias
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getGroupListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingAutoFillService.getCascadingAutoFillGroupList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/groups")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getGroupList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingAutoFillService.getCascadingAutoFillGroupList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/groups/{groupCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getGroupDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupCode", groupCode);
|
||||
Map<String, Object> result = cascadingAutoFillService.getCascadingAutoFillGroupDetail(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping("/groups")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(cascadingAutoFillService.insertCascadingAutoFillGroup(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/groups/{groupCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("groupCode", groupCode);
|
||||
Map<String, Object> result = cascadingAutoFillService.updateCascadingAutoFillGroup(body);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/groups/{groupCode}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupCode", groupCode);
|
||||
boolean deleted = cascadingAutoFillService.deleteCascadingAutoFillGroup(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
@GetMapping("/options/{groupCode}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMasterOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupCode", groupCode);
|
||||
List<Map<String, Object>> result = cascadingAutoFillService.getAutoFillMasterOptions(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@GetMapping("/data/{groupCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getAutoFillData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode,
|
||||
@RequestParam(required = false) String masterValue) {
|
||||
if (masterValue == null || masterValue.isBlank()) {
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(ApiResponse.error("masterValue 파라미터가 필요합니다."));
|
||||
}
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupCode", groupCode);
|
||||
params.put("masterValue", masterValue);
|
||||
Map<String, Object> result = cascadingAutoFillService.getAutoFillData(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CascadingConditionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/cascading-condition")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CascadingConditionController {
|
||||
private final CascadingConditionService cascadingConditionService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingConditionListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.getCascadingConditionList(params)));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingConditionList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.getCascadingConditionList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/filtered-options/{relationCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFilteredOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String relationCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("relationCode", relationCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.getFilteredOptions(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{conditionId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingConditionInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long conditionId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("conditionId", conditionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.getCascadingConditionInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertCascadingCondition(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.insertCascadingCondition(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{conditionId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCascadingCondition(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long conditionId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("conditionId", conditionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.updateCascadingCondition(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{conditionId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteCascadingCondition(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long conditionId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("conditionId", conditionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.deleteCascadingCondition(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CascadingHierarchyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/cascading-hierarchy")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CascadingHierarchyController {
|
||||
private final CascadingHierarchyService cascadingHierarchyService;
|
||||
|
||||
// Pipeline api_test compatibility alias
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getGroupListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingHierarchyService.getCascadingHierarchyGroupList(params)));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getGroupList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(cascadingHierarchyService.getCascadingHierarchyGroupList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{groupCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getGroupDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupCode", groupCode);
|
||||
Map<String, Object> result = cascadingHierarchyService.getCascadingHierarchyGroupDetail(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("계층 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
if (userId != null) body.put("userId", userId);
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(cascadingHierarchyService.insertCascadingHierarchyGroup(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{groupCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String groupCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("groupCode", groupCode);
|
||||
if (userId != null) body.put("userId", userId);
|
||||
Map<String, Object> result = cascadingHierarchyService.updateCascadingHierarchyGroup(body);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("계층 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{groupCode}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupCode", groupCode);
|
||||
boolean deleted = cascadingHierarchyService.deleteCascadingHierarchyGroup(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("계층 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
@PostMapping("/{groupCode}/levels")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> addLevel(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("groupCode", groupCode);
|
||||
Map<String, Object> result = cascadingHierarchyService.addCascadingHierarchyLevel(body);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("계층 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PutMapping("/levels/{levelId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateLevel(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long levelId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("levelId", levelId);
|
||||
Map<String, Object> result = cascadingHierarchyService.updateCascadingHierarchyLevel(body);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("레벨을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/levels/{levelId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteLevel(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long levelId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("levelId", levelId);
|
||||
boolean deleted = cascadingHierarchyService.deleteCascadingHierarchyLevel(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("레벨을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
@GetMapping("/{groupCode}/options/{levelOrder}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLevelOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String groupCode,
|
||||
@PathVariable Integer levelOrder,
|
||||
@RequestParam(required = false) String parentValue) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupCode", groupCode);
|
||||
params.put("levelOrder", levelOrder);
|
||||
if (parentValue != null) params.put("parentValue", parentValue);
|
||||
Map<String, Object> result = cascadingHierarchyService.getLevelOptions(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(ApiResponse.error("레벨을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CascadingMutualExclusionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 상호 배제 API
|
||||
* Node.js: app.use("/api/cascading-mutual-exclusion", cascadingMutualExclusionRoutes)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/cascading-mutual-exclusion")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CascadingMutualExclusionController {
|
||||
private final CascadingMutualExclusionService cascadingMutualExclusionService;
|
||||
|
||||
/** GET /list — 목록 조회 (alias) */
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingMutualExclusionListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingMutualExclusionService.getCascadingMutualExclusionList(params)));
|
||||
}
|
||||
|
||||
/** GET / — 목록 조회 */
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingMutualExclusionList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingMutualExclusionService.getCascadingMutualExclusionList(params)));
|
||||
}
|
||||
|
||||
/** GET /{exclusionId} — 상세 조회 */
|
||||
@GetMapping("/{exclusionId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingMutualExclusionInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long exclusionId) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", exclusionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingMutualExclusionService.getCascadingMutualExclusionInfo(params)));
|
||||
}
|
||||
|
||||
/** POST / — 생성 */
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertCascadingMutualExclusion(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingMutualExclusionService.insertCascadingMutualExclusion(body)));
|
||||
}
|
||||
|
||||
/** PUT /{exclusionId} — 수정 */
|
||||
@PutMapping("/{exclusionId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCascadingMutualExclusion(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long exclusionId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", exclusionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingMutualExclusionService.updateCascadingMutualExclusion(body)));
|
||||
}
|
||||
|
||||
/** DELETE /{exclusionId} — 하드 삭제 */
|
||||
@DeleteMapping("/{exclusionId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteCascadingMutualExclusion(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long exclusionId) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", exclusionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingMutualExclusionService.deleteCascadingMutualExclusion(params)));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /validate/{exclusionCode} — 상호 배제 검증
|
||||
* body: { "fieldValues": { "fieldA": "val1", "fieldB": "val1" } }
|
||||
*/
|
||||
@PostMapping("/validate/{exclusionCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> validateCascadingMutualExclusion(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String exclusionCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("code", exclusionCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingMutualExclusionService.validateCascadingMutualExclusion(body)));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /options/{exclusionCode} — 배제 옵션 조회
|
||||
* query: selectedValues (콤마 구분된 이미 선택된 값들)
|
||||
*/
|
||||
@GetMapping("/options/{exclusionCode}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getExcludedOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String exclusionCode,
|
||||
@RequestParam(required = false) String currentField,
|
||||
@RequestParam(required = false) String selectedValues) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("code", exclusionCode);
|
||||
params.put("currentField", currentField);
|
||||
params.put("selectedValues", selectedValues);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingMutualExclusionService.getExcludedOptions(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CascadingRelationService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 연쇄 관계 API
|
||||
* Node.js: app.use("/api/cascading-relation", cascadingRelationRoutes)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/cascading-relation")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CascadingRelationController {
|
||||
private final CascadingRelationService cascadingRelationService;
|
||||
|
||||
/** GET /api/cascading-relation/list — 목록 조회 (alias) */
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingRelationListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.getCascadingRelationList(params)));
|
||||
}
|
||||
|
||||
/** GET /api/cascading-relation — 목록 조회 */
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingRelationList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.getCascadingRelationList(params)));
|
||||
}
|
||||
|
||||
/** GET /api/cascading-relation/{id} — 상세 조회 */
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingRelationInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.getCascadingRelationInfo(params)));
|
||||
}
|
||||
|
||||
/** GET /api/cascading-relation/code/{code} — 코드로 단건 조회 */
|
||||
@GetMapping("/code/{code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCascadingRelationByCode(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String code) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("code", code);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.getCascadingRelationByCode(params)));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/cascading-relation/parent-options/{code}
|
||||
* 부모 옵션 조회 (parent_table 동적 쿼리)
|
||||
*/
|
||||
@GetMapping("/parent-options/{code}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getParentOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String code) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("code", code);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.getParentOptions(params)));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/cascading-relation/options/{code}?parentValue=&parentValues=
|
||||
* 연쇄 자식 옵션 조회 (child_table 동적 쿼리)
|
||||
*/
|
||||
@GetMapping("/options/{code}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCascadingOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String code,
|
||||
@RequestParam(required = false) String parentValue,
|
||||
@RequestParam(required = false) String parentValues) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("code", code);
|
||||
params.put("parentValue", parentValue);
|
||||
params.put("parentValues", parentValues);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.getCascadingOptions(params)));
|
||||
}
|
||||
|
||||
/** POST /api/cascading-relation — 생성 */
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertCascadingRelation(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId != null ? userId : "system");
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.insertCascadingRelation(body)));
|
||||
}
|
||||
|
||||
/** PUT /api/cascading-relation/{id} — 수정 */
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCascadingRelation(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId != null ? userId : "system");
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.updateCascadingRelation(body)));
|
||||
}
|
||||
|
||||
/** DELETE /api/cascading-relation/{id} — 소프트 삭제 (is_active = 'N') */
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteCascadingRelation(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId != null ? userId : "system");
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
cascadingRelationService.deleteCascadingRelation(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CategoryTreeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/category-tree")
|
||||
@RequiredArgsConstructor
|
||||
public class CategoryTreeController {
|
||||
|
||||
private final CategoryTreeService categoryTreeService;
|
||||
|
||||
/**
|
||||
* GET /api/category-tree/test/all-category-keys
|
||||
* 전체 카테고리 키 목록 조회 (모든 테이블.컬럼 조합)
|
||||
* 주의: /test/{tableName}/{columnName} 보다 먼저 매핑되어야 함
|
||||
*/
|
||||
@GetMapping("/test/all-category-keys")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryTreeKeyList(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
List<Map<String, Object>> keys = categoryTreeService.getCategoryTreeKeyList(companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/category-tree/test/{tableName}/{columnName}
|
||||
* 카테고리 트리 조회
|
||||
*/
|
||||
@GetMapping("/test/{tableName}/{columnName}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryTreeList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName) {
|
||||
|
||||
List<Map<String, Object>> tree = categoryTreeService.getCategoryTreeList(companyCode, tableName, columnName);
|
||||
return ResponseEntity.ok(ApiResponse.success(tree));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/category-tree/test/{tableName}/{columnName}/flat
|
||||
* 카테고리 플랫 리스트 조회
|
||||
*/
|
||||
@GetMapping("/test/{tableName}/{columnName}/flat")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryTreeFlatList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName) {
|
||||
|
||||
List<Map<String, Object>> list = categoryTreeService.getCategoryTreeFlatList(companyCode, tableName, columnName);
|
||||
return ResponseEntity.ok(ApiResponse.success(list));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/category-tree/test/value/{valueId}
|
||||
* 카테고리 값 단건 조회
|
||||
*/
|
||||
@GetMapping("/test/value/{valueId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryTreeInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int valueId) {
|
||||
|
||||
Map<String, Object> value = categoryTreeService.getCategoryTreeInfo(companyCode, valueId);
|
||||
if (value == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값을 찾을 수 없습니다"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/category-tree/test/value
|
||||
* 카테고리 값 생성
|
||||
*/
|
||||
@PostMapping("/test/value")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertCategoryTree(
|
||||
@RequestAttribute("companyCode") String userCompanyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("tableName") == null || body.get("columnName") == null
|
||||
|| body.get("valueCode") == null || body.get("valueLabel") == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("tableName, columnName, valueCode, valueLabel은 필수입니다"));
|
||||
}
|
||||
|
||||
// 최고 관리자(*) 는 targetCompanyCode 로 회사 코드 오버라이드 가능
|
||||
String companyCode = userCompanyCode;
|
||||
String targetCompanyCode = (String) body.get("targetCompanyCode");
|
||||
if (targetCompanyCode != null && "*".equals(userCompanyCode)) {
|
||||
companyCode = targetCompanyCode;
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> value = categoryTreeService.insertCategoryTree(body, companyCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(value));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 생성 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/category-tree/test/value/{valueId}
|
||||
* 카테고리 값 수정
|
||||
*/
|
||||
@PutMapping("/test/value/{valueId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCategoryTree(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable int valueId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
try {
|
||||
Map<String, Object> value = categoryTreeService.updateCategoryTree(companyCode, valueId, body, userId);
|
||||
if (value == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값을 찾을 수 없습니다"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(value));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 수정 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/category-tree/test/value/{valueId}/can-delete
|
||||
* 카테고리 값 삭제 가능 여부 사전 확인
|
||||
*/
|
||||
@GetMapping("/test/value/{valueId}/can-delete")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkCanDelete(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int valueId) {
|
||||
|
||||
Map<String, Object> result = categoryTreeService.checkCanDelete(companyCode, valueId);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/category-tree/test/value/{valueId}
|
||||
* 카테고리 값 삭제
|
||||
*/
|
||||
@DeleteMapping("/test/value/{valueId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteCategoryTree(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int valueId) {
|
||||
|
||||
try {
|
||||
boolean deleted = categoryTreeService.deleteCategoryTree(companyCode, valueId);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값을 찾을 수 없습니다"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "삭제되었습니다"));
|
||||
} catch (IllegalStateException e) {
|
||||
String msg = e.getMessage();
|
||||
if (msg != null && msg.startsWith("VALIDATION:")) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error(msg.substring("VALIDATION:".length())));
|
||||
}
|
||||
log.error("카테고리 값 삭제 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(msg));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 삭제 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/category-tree/test/columns/{tableName}
|
||||
* 테이블의 카테고리 컬럼 목록 조회
|
||||
*/
|
||||
@GetMapping("/test/columns/{tableName}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryTreeColumnList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName) {
|
||||
|
||||
List<Map<String, Object>> columns = categoryTreeService.getCategoryTreeColumnList(companyCode, tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(columns));
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CategoryValueCascadingService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/category-value-cascading")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CategoryValueCascadingController {
|
||||
private final CategoryValueCascadingService categoryValueCascadingService;
|
||||
|
||||
/** GET /groups → 그룹 목록 조회 */
|
||||
@GetMapping("/groups")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryValueCascadingGroupList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingGroupList(params)));
|
||||
}
|
||||
|
||||
/** GET /groups/{groupId} → 그룹 상세 조회 (매핑 포함) */
|
||||
@GetMapping("/groups/{groupId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryValueCascadingGroupInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long groupId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupId", groupId);
|
||||
Map<String, Object> result = categoryValueCascadingService.getCategoryValueCascadingGroupInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값 연쇄관계 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** GET /code/{code} → 관계 코드로 조회 */
|
||||
@GetMapping("/code/{code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryValueCascadingGroupByCode(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String code) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("code", code);
|
||||
Map<String, Object> result = categoryValueCascadingService.getCategoryValueCascadingGroupByCode(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값 연쇄관계를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** POST /groups → 그룹 생성 */
|
||||
@PostMapping("/groups")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertCategoryValueCascadingGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.insertCategoryValueCascadingGroup(body)));
|
||||
}
|
||||
|
||||
/** PUT /groups/{groupId} → 그룹 수정 */
|
||||
@PutMapping("/groups/{groupId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCategoryValueCascadingGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long groupId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("groupId", groupId);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.updateCategoryValueCascadingGroup(body)));
|
||||
}
|
||||
|
||||
/** DELETE /groups/{groupId} → 그룹 소프트 삭제 */
|
||||
@DeleteMapping("/groups/{groupId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteCategoryValueCascadingGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long groupId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("groupId", groupId);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.deleteCategoryValueCascadingGroup(params)));
|
||||
}
|
||||
|
||||
/** POST /groups/{groupId}/mappings → 매핑 일괄 저장 */
|
||||
@PostMapping("/groups/{groupId}/mappings")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveCategoryValueCascadingMappings(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long groupId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("groupId", groupId);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.saveCategoryValueCascadingMappings(body)));
|
||||
}
|
||||
|
||||
/** GET /parent-options/{code} → 부모 카테고리 값 목록 */
|
||||
@GetMapping("/parent-options/{code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryValueCascadingParentOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String code,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("code", code);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingParentOptions(params)));
|
||||
}
|
||||
|
||||
/** GET /child-options/{code} → 자식 카테고리 값 목록 */
|
||||
@GetMapping("/child-options/{code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryValueCascadingChildOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String code,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("code", code);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingChildOptions(params)));
|
||||
}
|
||||
|
||||
/** GET /options/{code} → 연쇄 옵션 조회 (parentValue/parentValues 파라미터) */
|
||||
@GetMapping("/options/{code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryValueCascadingOptions(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String code,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("code", code);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingOptions(params)));
|
||||
}
|
||||
|
||||
/** GET /table/{tableName}/mappings → 테이블별 매핑 조회 */
|
||||
@GetMapping("/table/{tableName}/mappings")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryValueCascadingMappingsByTable(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("tableName", tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingMappingsByTable(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CodeMergeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/code-merge")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CodeMergeController {
|
||||
|
||||
private final CodeMergeService codeMergeService;
|
||||
|
||||
/** POST /api/code-merge/merge-all-tables — columnName 기준 전체 테이블 코드 병합 */
|
||||
@PostMapping("/merge-all-tables")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> mergeAllTables(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
codeMergeService.mergeAllTables(body),
|
||||
"코드 병합이 완료되었습니다."));
|
||||
}
|
||||
|
||||
/** GET /api/code-merge/tables-with-column/:columnName — 해당 컬럼을 가진 테이블 목록 */
|
||||
@GetMapping("/tables-with-column/{columnName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTablesWithColumn(
|
||||
@PathVariable String columnName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
codeMergeService.getTablesWithColumn(columnName)));
|
||||
}
|
||||
|
||||
/** POST /api/code-merge/preview — columnName + oldValue 기준 영향 미리보기 */
|
||||
@PostMapping("/preview")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewCodeMerge(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
codeMergeService.previewCodeMerge(body)));
|
||||
}
|
||||
|
||||
/** POST /api/code-merge/merge-by-value — 값 기반 전체 테이블/컬럼 코드 병합 */
|
||||
@PostMapping("/merge-by-value")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> mergeByValue(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
codeMergeService.mergeByValue(body),
|
||||
"코드 병합이 완료되었습니다."));
|
||||
}
|
||||
|
||||
/** POST /api/code-merge/preview-by-value — 값 기반 영향 미리보기 */
|
||||
@PostMapping("/preview-by-value")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewByValue(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
codeMergeService.previewByValue(body)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.erp.controller;
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CollectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/collections")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CollectionController {
|
||||
private final CollectionService collectionService;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCollectionList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(collectionService.getCollectionList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCollectionListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(collectionService.getCollectionList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/jobs/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCollectionJobList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(collectionService.getCollectionJobList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCollectionInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(collectionService.getCollectionInfo(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{configId}/history")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCollectionHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long configId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("configId", configId);
|
||||
return ResponseEntity.ok(ApiResponse.success(collectionService.getCollectionHistory(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertCollection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(collectionService.insertCollection(body), "수집 설정이 생성되었습니다."));
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/execute")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeCollection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(collectionService.executeCollection(params)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCollection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(collectionService.updateCollection(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteCollection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
collectionService.deleteCollection(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "수집 설정이 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CommonCodeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Common Code Controller
|
||||
*
|
||||
* commonCodeRoutes.ts 포팅 — /api/common-codes 기준 15개 엔드포인트.
|
||||
*
|
||||
* NOTE: Spring MVC 는 리터럴 세그먼트를 경로변수보다 우선하므로
|
||||
* /check-duplicate, /reorder 는 별도 선언 순서 없이도 정상 동작하나,
|
||||
* 가독성을 위해 구체적인 경로를 먼저 선언한다.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/common-codes")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CommonCodeController {
|
||||
|
||||
private final CommonCodeService service;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// GET /categories
|
||||
// Node.js: { success, data: [...], total, message } (flat, not nested)
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories")
|
||||
public ResponseEntity<Map<String, Object>> getCommonCodeCategoryList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
params.put("companyCode", companyCode);
|
||||
Map<String, Object> svcResult = service.getCommonCodeCategoryList(params);
|
||||
|
||||
Map<String, Object> response = new java.util.LinkedHashMap<>();
|
||||
response.put("success", true);
|
||||
response.put("data", svcResult.get("data"));
|
||||
response.put("total", svcResult.get("total"));
|
||||
response.put("message", "카테고리 목록 조회 성공");
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// GET /categories/check-duplicate ← /{categoryCode} 보다 먼저
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories/check-duplicate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkCategoryDuplicate(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam("categoryCode") String categoryCode) {
|
||||
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(service.checkCategoryDuplicate(categoryCode, companyCode)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// POST /categories
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/categories")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertCommonCodeCategory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("categoryCode") == null || body.get("categoryName") == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (categoryCode, categoryName)"));
|
||||
}
|
||||
try {
|
||||
Map<String, Object> created = service.insertCommonCodeCategory(body, companyCode, userId);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "카테고리가 성공적으로 생성되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("카테고리 생성에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// PUT /categories/:categoryCode
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@PutMapping("/categories/{categoryCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCommonCodeCategory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable String categoryCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
try {
|
||||
Map<String, Object> updated = service.updateCommonCodeCategory(categoryCode, body, companyCode, userId);
|
||||
if (updated == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("카테고리를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "카테고리가 성공적으로 수정되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 수정 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("카테고리 수정에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// DELETE /categories/:categoryCode
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@DeleteMapping("/categories/{categoryCode}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteCommonCodeCategory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode) {
|
||||
|
||||
try {
|
||||
service.deleteCommonCodeCategory(categoryCode, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "카테고리가 성공적으로 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 삭제 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("카테고리 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// GET /categories/:categoryCode/codes
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories/{categoryCode}/codes")
|
||||
public ResponseEntity<Map<String, Object>> getCommonCodeList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
params.put("companyCode", companyCode);
|
||||
Map<String, Object> svcResult = service.getCommonCodeList(categoryCode, params);
|
||||
|
||||
Map<String, Object> response = new java.util.LinkedHashMap<>();
|
||||
response.put("success", true);
|
||||
response.put("data", svcResult.get("data"));
|
||||
response.put("total", svcResult.get("total"));
|
||||
response.put("message", "코드 목록 조회 성공");
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// POST /categories/:categoryCode/codes
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/categories/{categoryCode}/codes")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertCommonCode(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable String categoryCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("codeValue") == null || body.get("codeName") == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (codeValue, codeName)"));
|
||||
}
|
||||
try {
|
||||
Map<String, Object> created = service.insertCommonCode(categoryCode, body, companyCode, userId);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "코드가 성공적으로 생성되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("코드 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("코드 생성에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// GET /categories/:categoryCode/codes/check-duplicate ← /{codeValue} 보다 먼저
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories/{categoryCode}/codes/check-duplicate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkCodeDuplicate(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode,
|
||||
@RequestParam("codeValue") String codeValue) {
|
||||
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(service.checkCodeDuplicate(categoryCode, codeValue, companyCode)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// PUT /categories/:categoryCode/codes/reorder ← /{codeValue} 보다 먼저
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@PutMapping("/categories/{categoryCode}/codes/reorder")
|
||||
public ResponseEntity<ApiResponse<Void>> updateCommonCodeOrder(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object codesRaw = body.get("codes");
|
||||
if (!(codesRaw instanceof List)) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("codes 배열이 필요합니다."));
|
||||
}
|
||||
try {
|
||||
service.updateCommonCodeOrder(categoryCode, (List<Map<String, Object>>) codesRaw, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "정렬 순서가 변경되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("코드 정렬 변경 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("정렬 순서 변경에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// GET /categories/:categoryCode/hierarchy
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories/{categoryCode}/hierarchy")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCommonCodeHierarchicalList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(service.getCommonCodeHierarchicalList(categoryCode, params)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// GET /categories/:categoryCode/tree
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories/{categoryCode}/tree")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCommonCodeTree(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode) {
|
||||
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(service.getCommonCodeTree(categoryCode, companyCode)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// GET /categories/:categoryCode/options
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories/{categoryCode}/options")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCommonCodeOptionList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(service.getCommonCodeOptionList(categoryCode, params)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// GET /categories/:categoryCode/codes/:codeValue/has-children
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories/{categoryCode}/codes/{codeValue}/has-children")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> hasChildren(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode,
|
||||
@PathVariable String codeValue) {
|
||||
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(service.hasChildren(categoryCode, codeValue, companyCode)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// PUT /categories/:categoryCode/codes/:codeValue
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@PutMapping("/categories/{categoryCode}/codes/{codeValue}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCommonCode(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable String categoryCode,
|
||||
@PathVariable String codeValue,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
try {
|
||||
Map<String, Object> updated = service.updateCommonCode(categoryCode, codeValue, body, companyCode, userId);
|
||||
if (updated == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("코드를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "코드가 성공적으로 수정되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("코드 수정 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("코드 수정에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// DELETE /categories/:categoryCode/codes/:codeValue
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
@DeleteMapping("/categories/{categoryCode}/codes/{codeValue}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteCommonCode(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String categoryCode,
|
||||
@PathVariable String codeValue) {
|
||||
|
||||
try {
|
||||
service.deleteCommonCode(categoryCode, codeValue, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "코드가 성공적으로 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("코드 삭제 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("코드 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.CompanyManagementService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/company-management")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CompanyManagementController {
|
||||
|
||||
private final CompanyManagementService companyManagementService;
|
||||
|
||||
/**
|
||||
* DELETE /api/company-management/:companyCode
|
||||
* 회사 삭제 및 파일 정리 (soft delete)
|
||||
*/
|
||||
@DeleteMapping("/{companyCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteCompany(
|
||||
@PathVariable String companyCode,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
if (body != null) {
|
||||
params.putAll(body);
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> data = companyManagementService.deleteCompany(params);
|
||||
String companyName = (String) data.get("companyName");
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(data, "회사 '" + companyName + "'이(가) 성공적으로 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (RuntimeException e) {
|
||||
log.error("회사 삭제 실패: companyCode={}", companyCode, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/company-management/disk-usage/all
|
||||
* 전체 회사 디스크 사용량 조회
|
||||
* ※ /{companyCode}/disk-usage 보다 먼저 정의 (경로 특이성으로 충돌 없음)
|
||||
*/
|
||||
@GetMapping("/disk-usage/all")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getAllCompaniesDiskUsage() {
|
||||
try {
|
||||
Map<String, Object> data = companyManagementService.getAllCompaniesDiskUsage();
|
||||
return ResponseEntity.ok(ApiResponse.success(data));
|
||||
} catch (Exception e) {
|
||||
log.error("전체 디스크 사용량 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("전체 디스크 사용량 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/company-management/:companyCode/disk-usage
|
||||
* 회사별 디스크 사용량 조회
|
||||
*/
|
||||
@GetMapping("/{companyCode}/disk-usage")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCompanyDiskUsage(
|
||||
@PathVariable String companyCode) {
|
||||
try {
|
||||
Map<String, Object> data = companyManagementService.getCompanyDiskUsage(companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(data));
|
||||
} catch (Exception e) {
|
||||
log.error("디스크 사용량 조회 실패: companyCode={}", companyCode, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("디스크 사용량 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ComponentStandardService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Component Standard 컨트롤러
|
||||
*
|
||||
* Node.js componentStandardRoutes.ts 포팅.
|
||||
*
|
||||
* GET /api/component-standard — 목록 조회
|
||||
* GET /api/component-standard/categories — 카테고리 목록
|
||||
* GET /api/component-standard/statistics — 통계
|
||||
* GET /api/component-standard/check-duplicate/{code} — 코드 중복 체크
|
||||
* GET /api/component-standard/{component_code} — 단건 조회
|
||||
* POST /api/component-standard — 생성
|
||||
* PUT /api/component-standard/{component_code} — 수정
|
||||
* DELETE /api/component-standard/{component_code} — 삭제
|
||||
* PUT /api/component-standard/sort/order — 정렬 순서 업데이트
|
||||
* POST /api/component-standard/duplicate — 복제
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/component-standard")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ComponentStandardController {
|
||||
|
||||
private final ComponentStandardService service;
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET / — 목록 조회
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getComponents(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getComponents(params)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /categories — 카테고리 목록 (반드시 /{code} 앞에 선언)
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories")
|
||||
public ResponseEntity<ApiResponse<List<String>>> getCategories(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getCategories(params)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /statistics — 통계
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/statistics")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getStatistics(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getStatistics(params)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /check-duplicate/{component_code} — 중복 체크
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/check-duplicate/{component_code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkDuplicate(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("component_code") String componentCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("component_code", componentCode);
|
||||
params.put("companyCode", companyCode);
|
||||
boolean exists = service.checkDuplicate(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("exists", exists)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /{component_code} — 단건 조회
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{component_code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getComponent(
|
||||
@PathVariable("component_code") String componentCode) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getComponent(componentCode)));
|
||||
} catch (RuntimeException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// POST / — 생성
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createComponent(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.putIfAbsent("company_code", companyCode);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.createComponent(body)));
|
||||
} catch (RuntimeException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// PUT /sort/order — 정렬 순서 업데이트 (/{code} 보다 먼저 선언)
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@PutMapping("/sort/order")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateSortOrder(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> updates = (List<Map<String, Object>>) body.get("updates");
|
||||
if (updates == null || updates.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("updates 항목이 필요합니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateSortOrder(updates)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// PUT /{component_code} — 수정
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@PutMapping("/{component_code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateComponent(
|
||||
@PathVariable("component_code") String componentCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateComponent(componentCode, body)));
|
||||
} catch (RuntimeException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// DELETE /{component_code} — 삭제
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@DeleteMapping("/{component_code}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteComponent(
|
||||
@PathVariable("component_code") String componentCode) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.deleteComponent(componentCode)));
|
||||
} catch (RuntimeException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// POST /duplicate — 복제
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/duplicate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> duplicateComponent(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String sourceCode = str(body.get("source_code"));
|
||||
String newCode = str(body.get("new_code"));
|
||||
String newName = str(body.get("new_name"));
|
||||
|
||||
if (sourceCode.isEmpty() || newCode.isEmpty() || newName.isEmpty()) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("source_code, new_code, new_name 항목이 필요합니다."));
|
||||
}
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
service.duplicateComponent(sourceCode, newCode, newName)));
|
||||
} catch (RuntimeException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private String str(Object o) { return o == null ? "" : o.toString(); }
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DashboardService;
|
||||
import com.erp.service.ExternalRestApiConnectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/dashboard")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DashboardController {
|
||||
|
||||
private final DashboardService dashboardService;
|
||||
private final ExternalRestApiConnectionService externalRestApiConnectionService;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDashboards(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dashboardService.getDashboardList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDashboardsLegacy(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dashboardService.getDashboardList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/public")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getPublicDashboards(
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", "*");
|
||||
params.put("isPublic", "true");
|
||||
return ResponseEntity.ok(ApiResponse.success(dashboardService.getDashboardList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/my")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMyDashboards(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dashboardService.getDashboardList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/public/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getPublicDashboard(
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> result = dashboardService.getDashboardById(id, null);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("대시보드를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDashboard(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> result = dashboardService.getDashboardById(id, companyCode);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("대시보드를 찾을 수 없거나 접근 권한이 없습니다."));
|
||||
// 다른 사람 것 조회 시 조회수 증가
|
||||
if (userId != null && !userId.equals(result.get("createdBy"))) {
|
||||
dashboardService.incrementViewCount(id);
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDashboard(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String title = (String) body.get("title");
|
||||
if (title == null || title.isBlank()) return ResponseEntity.status(400).body(ApiResponse.error("대시보드 제목이 필요합니다."));
|
||||
Map<String, Object> result = dashboardService.createDashboard(body, userId, companyCode);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "대시보드가 생성되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDashboard(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = dashboardService.updateDashboard(id, body, userId);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("대시보드를 찾을 수 없거나 수정 권한이 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "대시보드가 수정되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteDashboard(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute(value = "userId", required = false) String userId) {
|
||||
boolean deleted = dashboardService.deleteDashboard(id, userId);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("대시보드를 찾을 수 없거나 삭제 권한이 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "대시보드가 삭제되었습니다."));
|
||||
}
|
||||
|
||||
@PostMapping("/execute-query")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeQuery(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String query = (String) body.get("query");
|
||||
if (query == null || query.isBlank()) return ResponseEntity.status(400).body(ApiResponse.error("쿼리가 필요합니다."));
|
||||
try {
|
||||
Map<String, Object> result = dashboardService.executeQuery(query);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "쿼리가 실행되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/execute-dml")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeDml(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String query = (String) body.get("query");
|
||||
if (query == null || query.isBlank()) return ResponseEntity.status(400).body(ApiResponse.error("쿼리가 필요합니다."));
|
||||
try {
|
||||
Map<String, Object> result = dashboardService.executeDml(query);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "쿼리가 실행되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/fetch-external-api")
|
||||
public ResponseEntity<ApiResponse<Object>> fetchExternalApi(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String url = (String) body.get("url");
|
||||
if (url == null || url.isBlank()) return ResponseEntity.status(400).body(ApiResponse.error("URL이 필요합니다."));
|
||||
Object externalConnectionId = body.get("externalConnectionId");
|
||||
|
||||
Map<String, Object> requestParams = new HashMap<>(body);
|
||||
requestParams.put("companyCode", companyCode);
|
||||
if (externalConnectionId != null) {
|
||||
int connId = Integer.parseInt(String.valueOf(externalConnectionId));
|
||||
Map<String, Object> result = externalRestApiConnectionService.fetchData(connId, url, null, requestParams);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
// 커넥션 없이 직접 호출 - 기본 응답
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("url", url);
|
||||
result.put("message", "externalConnectionId가 필요합니다.");
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping("/table-schema")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableSchema(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String tableName = (String) body.get("tableName");
|
||||
if (tableName == null || tableName.isBlank()) return ResponseEntity.status(400).body(ApiResponse.error("테이블명이 필요합니다."));
|
||||
try {
|
||||
Map<String, Object> result = dashboardService.getTableSchema(tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DataAdvancedService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/data")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DataAdvancedController {
|
||||
|
||||
private final DataAdvancedService dataAdvancedService;
|
||||
|
||||
@PostMapping("/upsert-grouped")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> upsertGrouped(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.upsertGrouped(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{tableName}/delete")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteByCondition(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("tableName", tableName);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.deleteByCondition(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{tableName}/delete-group")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("tableName", tableName);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.deleteGroup(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/multi-table/auto-detect")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> autoDetectMultiTable(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.autoDetectMultiTable(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/multi-table/upload")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> uploadMultiTable(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.uploadMultiTable(body)));
|
||||
}
|
||||
|
||||
@GetMapping("/master-detail/relation/{screenId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMasterDetailRelation(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String screenId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("screenId", screenId);
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.getMasterDetailRelation(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/master-detail/download")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> downloadMasterDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.downloadMasterDetail(body)));
|
||||
}
|
||||
|
||||
@PostMapping("/master-detail/upload")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> uploadMasterDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.uploadMasterDetail(body)));
|
||||
}
|
||||
|
||||
@PostMapping("/master-detail/upload-simple")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> uploadMasterDetailSimple(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dataAdvancedService.uploadMasterDetailSimple(body)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DataService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/data")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DataController {
|
||||
private final DataService dataService;
|
||||
|
||||
@GetMapping("/join")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getJoinData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(dataService.getJoinData(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{tableName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("tableName", tableName);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(dataService.getTableData(params)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableColumns(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(dataService.getTableColumns(tableName)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{tableName}/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getRecordDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("tableName", tableName);
|
||||
params.put("id", id);
|
||||
try {
|
||||
Map<String, Object> result = dataService.getRecordDetail(params);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("레코드를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{tableName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createRecord(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("tableName", tableName);
|
||||
try {
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(dataService.createRecord(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{tableName}/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateRecord(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("tableName", tableName);
|
||||
body.put("id", id);
|
||||
try {
|
||||
Map<String, Object> result = dataService.updateRecord(body);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("레코드를 찾을 수 없거나 수정 권한이 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{tableName}/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteRecord(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("tableName", tableName);
|
||||
params.put("id", id);
|
||||
try {
|
||||
Map<String, Object> result = dataService.deleteRecord(params);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("레코드를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DataflowService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/dataflow")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DataflowController {
|
||||
|
||||
private final DataflowService dataflowService;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// table-relationships
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* POST /api/dataflow/table-relationships
|
||||
*/
|
||||
@PostMapping("/table-relationships")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createTableRelationship(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String relName = str(body.get("relationshipName"));
|
||||
String fromTbl = str(body.get("fromTableName"));
|
||||
String fromCol = str(body.get("fromColumnName"));
|
||||
String toTbl = str(body.get("toTableName"));
|
||||
String toCol = str(body.get("toColumnName"));
|
||||
|
||||
if (blank(relName) || blank(fromTbl) || blank(fromCol) || blank(toTbl) || blank(toCol)) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (relationshipName, fromTableName, fromColumnName, toTableName, toColumnName)"));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> created = dataflowService.insertTableRelationship(body, companyCode, userId);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "테이블 관계가 성공적으로 생성되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블 관계 생성 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("테이블 관계 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/dataflow/table-relationships
|
||||
*/
|
||||
@GetMapping("/table-relationships")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableRelationshipList(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
dataflowService.getTableRelationshipList(companyCode),
|
||||
"테이블 관계 목록을 성공적으로 조회했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블 관계 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("테이블 관계 목록 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/dataflow/table-relationships/:relationshipId
|
||||
*/
|
||||
@GetMapping("/table-relationships/{relationshipId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableRelationshipInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int relationshipId) {
|
||||
try {
|
||||
Map<String, Object> rel = dataflowService.getTableRelationshipInfo(relationshipId, companyCode);
|
||||
if (rel == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("테이블 관계를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(rel, "테이블 관계를 성공적으로 조회했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블 관계 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("테이블 관계 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/dataflow/table-relationships/:relationshipId
|
||||
*/
|
||||
@PutMapping("/table-relationships/{relationshipId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateTableRelationship(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable int relationshipId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> updated = dataflowService.updateTableRelationship(
|
||||
relationshipId, body, companyCode, userId);
|
||||
if (updated == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("테이블 관계를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "테이블 관계가 성공적으로 수정되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블 관계 수정 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("테이블 관계 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/dataflow/table-relationships/:relationshipId
|
||||
*/
|
||||
@DeleteMapping("/table-relationships/{relationshipId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteTableRelationship(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int relationshipId) {
|
||||
try {
|
||||
boolean deleted = dataflowService.deleteTableRelationship(relationshipId, companyCode);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("테이블 관계를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "테이블 관계가 성공적으로 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블 관계 삭제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("테이블 관계 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// data-links
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* POST /api/dataflow/data-links
|
||||
*/
|
||||
@PostMapping("/data-links")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDataLink(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("relationshipId") == null || blank(str(body.get("fromTableName")))
|
||||
|| blank(str(body.get("fromColumnName"))) || blank(str(body.get("toTableName")))
|
||||
|| blank(str(body.get("toColumnName"))) || blank(str(body.get("connectionType")))) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> bridge = dataflowService.insertDataLink(body, companyCode, userId);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(bridge, "데이터 연결이 성공적으로 생성되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 연결 생성 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("데이터 연결 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/dataflow/data-links/relationship/:relationshipId
|
||||
*/
|
||||
@GetMapping("/data-links/relationship/{relationshipId}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDataLinkList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int relationshipId) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
dataflowService.getDataLinkList(relationshipId, companyCode),
|
||||
"연결된 데이터를 성공적으로 조회했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("연결 데이터 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("연결된 데이터 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/dataflow/data-links/:bridgeId
|
||||
*/
|
||||
@DeleteMapping("/data-links/{bridgeId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteDataLink(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable int bridgeId) {
|
||||
try {
|
||||
dataflowService.deleteDataLink(bridgeId, companyCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "데이터 연결이 성공적으로 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 연결 삭제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("데이터 연결 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// table-data
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* GET /api/dataflow/table-data/:tableName
|
||||
*/
|
||||
@GetMapping("/table-data/{tableName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "10") int limit,
|
||||
@RequestParam(defaultValue = "") String search,
|
||||
@RequestParam(defaultValue = "") String searchColumn) {
|
||||
try {
|
||||
Map<String, Object> result = dataflowService.getTableDataList(
|
||||
tableName, page, limit, search, searchColumn, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "테이블 데이터를 성공적으로 조회했습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블 데이터 조회 실패: {}", tableName, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("테이블 데이터 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// diagrams
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* GET /api/dataflow/diagrams
|
||||
*/
|
||||
@GetMapping("/diagrams")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDiagramList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "20") int size,
|
||||
@RequestParam(defaultValue = "") String searchTerm) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
dataflowService.getDiagramList(companyCode, page, size, searchTerm),
|
||||
"관계도 목록을 성공적으로 조회했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계도 목록 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/dataflow/diagrams/name/:diagramName/relationships
|
||||
* ※ /{diagramId}/relationships 보다 먼저 선언해야 "name" 세그먼트가 우선 매핑됨
|
||||
*/
|
||||
@GetMapping("/diagrams/name/{diagramName}/relationships")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDiagramRelationshipList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String diagramName) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
dataflowService.getDiagramRelationshipList(
|
||||
companyCode, java.net.URLDecoder.decode(diagramName, "UTF-8")),
|
||||
"관계도 관계를 성공적으로 조회했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 관계 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계도 관계 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/dataflow/diagrams/:diagramId/relationships
|
||||
*/
|
||||
@GetMapping("/diagrams/{diagramId}/relationships")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDiagramRelationshipListByDiagramId(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int diagramId) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
dataflowService.getDiagramRelationshipListByDiagramId(companyCode, diagramId),
|
||||
"관계도 관계 목록을 성공적으로 조회했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 관계 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계도 관계 조회에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/dataflow/diagrams/:diagramName/copy
|
||||
*/
|
||||
@PostMapping("/diagrams/{diagramName}/copy")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyDiagram(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String diagramName) {
|
||||
try {
|
||||
String decoded = java.net.URLDecoder.decode(diagramName, "UTF-8");
|
||||
String newDiagramName = dataflowService.copyDiagram(companyCode, decoded);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("newDiagramName", newDiagramName);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "관계도가 성공적으로 복사되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 복사 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계도 복사에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/dataflow/diagrams/:diagramName
|
||||
*/
|
||||
@DeleteMapping("/diagrams/{diagramName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteDiagram(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String diagramName) {
|
||||
try {
|
||||
String decoded = java.net.URLDecoder.decode(diagramName, "UTF-8");
|
||||
int deletedCount = dataflowService.deleteDiagram(companyCode, decoded);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("deletedCount", deletedCount);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "관계도가 성공적으로 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 삭제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계도 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/dataflow/relationships/:relationshipId/diagram
|
||||
* (하위 호환성)
|
||||
*/
|
||||
@GetMapping("/relationships/{relationshipId}/diagram")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDiagramRelationshipListByRelationshipId(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int relationshipId) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
dataflowService.getDiagramRelationshipListByRelationshipId(companyCode, relationshipId),
|
||||
"관계도 관계 목록을 성공적으로 조회했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 관계 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("관계도 관계 조회에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// conditional connections (stub — conditionalConnectionController 미구현)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* POST /api/dataflow/diagrams/:diagramId/test-conditions
|
||||
*/
|
||||
@PostMapping("/diagrams/{diagramId}/test-conditions")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> testConditionalConnection(
|
||||
@PathVariable int diagramId,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("diagramId", diagramId);
|
||||
result.put("tested", true);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "조건 테스트가 완료되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/dataflow/diagrams/:diagramId/execute-actions
|
||||
*/
|
||||
@PostMapping("/diagrams/{diagramId}/execute-actions")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeConditionalActions(
|
||||
@PathVariable int diagramId,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("diagramId", diagramId);
|
||||
result.put("executed", true);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "액션이 성공적으로 실행되었습니다."));
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// helpers
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
private String str(Object val) { return val == null ? null : val.toString(); }
|
||||
private boolean blank(String val) { return val == null || val.isBlank(); }
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DataflowDiagramService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 데이터 흐름 관계도(Dataflow Diagram) API
|
||||
*
|
||||
* GET /api/dataflow-diagrams — 목록 조회 (페이지네이션)
|
||||
* GET /api/dataflow-diagrams/:diagramId — 단건 조회
|
||||
* POST /api/dataflow-diagrams — 생성
|
||||
* PUT /api/dataflow-diagrams/:diagramId — 수정
|
||||
* DELETE /api/dataflow-diagrams/:diagramId — 삭제
|
||||
* POST /api/dataflow-diagrams/:diagramId/copy — 복제
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/dataflow-diagrams")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DataflowDiagramController {
|
||||
|
||||
private final DataflowDiagramService service;
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /api/dataflow-diagrams
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDataflowDiagrams(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getDataflowDiagrams(params)));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /api/dataflow-diagrams/:diagramId
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{diagramId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDataflowDiagramById(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("diagramId") String diagramIdStr) {
|
||||
|
||||
int diagramId = parseId(diagramIdStr);
|
||||
if (diagramId < 0) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("유효하지 않은 관계도 ID입니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> diagram = service.getDataflowDiagramById(diagramId, companyCode);
|
||||
if (diagram == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("관계도를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(diagram));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// POST /api/dataflow-diagrams
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDataflowDiagram(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("diagram_name") == null || body.get("relationships") == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("관계도 이름과 관계 정보는 필수입니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> created = service.createDataflowDiagram(body, companyCode, userId);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "관계도가 성공적으로 생성되었습니다."));
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
if (isDuplicateNameError(e)) {
|
||||
return ResponseEntity.status(409)
|
||||
.body(ApiResponse.error("중복된 이름입니다."));
|
||||
}
|
||||
log.error("관계도 생성 실패 (제약 위반)", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("관계도 생성 중 오류가 발생했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("관계도 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// PUT /api/dataflow-diagrams/:diagramId
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@PutMapping("/{diagramId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDataflowDiagram(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("diagramId") String diagramIdStr,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
int diagramId = parseId(diagramIdStr);
|
||||
if (diagramId < 0) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("유효하지 않은 관계도 ID입니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> updated =
|
||||
service.updateDataflowDiagram(diagramId, body, companyCode, userId);
|
||||
if (updated == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("관계도를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "관계도가 성공적으로 수정되었습니다."));
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
if (isDuplicateNameError(e)) {
|
||||
return ResponseEntity.status(409)
|
||||
.body(ApiResponse.error("중복된 이름입니다."));
|
||||
}
|
||||
log.error("관계도 수정 실패 (제약 위반)", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("관계도 수정 중 오류가 발생했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 수정 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("관계도 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// DELETE /api/dataflow-diagrams/:diagramId
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@DeleteMapping("/{diagramId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteDataflowDiagram(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("diagramId") String diagramIdStr) {
|
||||
|
||||
int diagramId = parseId(diagramIdStr);
|
||||
if (diagramId < 0) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("유효하지 않은 관계도 ID입니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
boolean deleted = service.deleteDataflowDiagram(diagramId, companyCode);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("관계도를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "관계도가 성공적으로 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 삭제 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("관계도 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// POST /api/dataflow-diagrams/:diagramId/copy
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/{diagramId}/copy")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyDataflowDiagram(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("diagramId") String diagramIdStr,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
|
||||
int diagramId = parseId(diagramIdStr);
|
||||
if (diagramId < 0) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("유효하지 않은 관계도 ID입니다."));
|
||||
}
|
||||
|
||||
String newName = (body != null) ? (String) body.get("new_name") : null;
|
||||
|
||||
try {
|
||||
Map<String, Object> copied =
|
||||
service.copyDataflowDiagram(diagramId, companyCode, newName, userId);
|
||||
if (copied == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("복제할 관계도를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(copied, "관계도가 성공적으로 복제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("관계도 복제 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("관계도 복제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// private helpers
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
/** Path variable ID 파싱 (유효하지 않으면 -1) */
|
||||
private int parseId(String val) {
|
||||
try {
|
||||
int id = Integer.parseInt(val);
|
||||
return id > 0 ? id : -1;
|
||||
} catch (NumberFormatException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** DataIntegrityViolationException 이 unique_diagram_name 위반인지 확인 */
|
||||
private boolean isDuplicateNameError(DataIntegrityViolationException e) {
|
||||
String msg = e.getMessage() != null ? e.getMessage().toLowerCase() : "";
|
||||
Throwable cause = e.getCause();
|
||||
String causeMsg = (cause != null && cause.getMessage() != null)
|
||||
? cause.getMessage().toLowerCase() : "";
|
||||
String combined = msg + " " + causeMsg;
|
||||
return combined.contains("23505")
|
||||
|| combined.contains("unique_diagram_name")
|
||||
|| combined.contains("duplicate key")
|
||||
|| combined.contains("unique constraint");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DataflowExecutionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 데이터플로우 실행 컨트롤러
|
||||
*
|
||||
* POST /api/dataflow/execute-data-action
|
||||
* body: { tableName, data, actionType, connection? }
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/dataflow")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DataflowExecutionController {
|
||||
|
||||
private final DataflowExecutionService service;
|
||||
|
||||
@PostMapping("/execute-data-action")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeDataAction(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
try {
|
||||
body.put("companyCode", companyCode);
|
||||
|
||||
log.info("데이터 액션 실행 요청: action={}, table={}",
|
||||
body.get("actionType"), body.get("tableName"));
|
||||
|
||||
Map<String, Object> result = service.executeDataAction(body);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(result, "데이터 액션 실행 완료: " + body.get("actionType")));
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("데이터 액션 파라미터 오류: {}", e.getMessage());
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error(e.getMessage()));
|
||||
} catch (IllegalStateException e) {
|
||||
// 중복 값 등 비즈니스 규칙 위반
|
||||
log.warn("데이터 액션 비즈니스 오류: {}", e.getMessage());
|
||||
return ResponseEntity.status(409)
|
||||
.body(ApiResponse.error(e.getMessage()));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
log.warn("지원하지 않는 액션: {}", e.getMessage());
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 액션 실행 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 액션 실행 실패: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DbTypeCategoryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/db-type-categories")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DbTypeCategoryController {
|
||||
|
||||
private final DbTypeCategoryService dbTypeCategoryService;
|
||||
|
||||
/**
|
||||
* GET /api/db-type-categories
|
||||
* 모든 DB 타입 카테고리 조회
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAllCategories() {
|
||||
List<Map<String, Object>> categories = dbTypeCategoryService.getAllCategories();
|
||||
return ResponseEntity.ok(ApiResponse.success(categories, "DB 타입 카테고리 목록을 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/db-type-categories/stats/connections
|
||||
* DB 타입별 연결 통계 조회
|
||||
* NOTE: /{typeCode} 보다 먼저 선언 — 리터럴 세그먼트 우선
|
||||
*/
|
||||
@GetMapping("/stats/connections")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getConnectionStatsByType() {
|
||||
List<Map<String, Object>> stats = dbTypeCategoryService.getConnectionStatsByType();
|
||||
return ResponseEntity.ok(ApiResponse.success(stats, "DB 타입별 연결 통계를 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/db-type-categories/{typeCode}
|
||||
* 특정 DB 타입 카테고리 조회
|
||||
*/
|
||||
@GetMapping("/{typeCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryByTypeCode(
|
||||
@PathVariable String typeCode) {
|
||||
Map<String, Object> category = dbTypeCategoryService.getCategoryByTypeCode(typeCode);
|
||||
if (category == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("해당 DB 타입 카테고리를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(category, "DB 타입 카테고리를 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/db-type-categories
|
||||
* DB 타입 카테고리 생성
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createCategory(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String typeCode = (String) body.get("type_code");
|
||||
String displayName = (String) body.get("display_name");
|
||||
|
||||
if (typeCode == null || typeCode.isBlank() || displayName == null || displayName.isBlank()) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("DB 타입 코드와 표시명은 필수입니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> created = dbTypeCategoryService.createCategory(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(created, "DB 타입 카테고리가 생성되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/db-type-categories/initialize
|
||||
* 기본 DB 타입 카테고리 초기화
|
||||
* NOTE: POST /{typeCode} 충돌 없음 — 경로가 완전히 다름
|
||||
*/
|
||||
@PostMapping("/initialize")
|
||||
public ResponseEntity<ApiResponse<Void>> initializeDefaultCategories() {
|
||||
dbTypeCategoryService.initializeDefaultCategories();
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "기본 DB 타입 카테고리가 초기화되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/db-type-categories/{typeCode}
|
||||
* DB 타입 카테고리 수정
|
||||
*/
|
||||
@PutMapping("/{typeCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCategory(
|
||||
@PathVariable String typeCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> updated = dbTypeCategoryService.updateCategory(typeCode, body);
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "DB 타입 카테고리가 수정되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/db-type-categories/{typeCode}
|
||||
* DB 타입 카테고리 삭제 (비활성화)
|
||||
*/
|
||||
@DeleteMapping("/{typeCode}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteCategory(
|
||||
@PathVariable String typeCode) {
|
||||
try {
|
||||
dbTypeCategoryService.deleteCategory(typeCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "DB 타입 카테고리가 삭제되었습니다."));
|
||||
} catch (IllegalStateException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DdlService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/ddl")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DdlController {
|
||||
|
||||
private final DdlService ddlService;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// DDL 실행 (SUPER_ADMIN 전용)
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /api/ddl/tables - 새 테이블 생성
|
||||
*/
|
||||
@PostMapping("/tables")
|
||||
public ResponseEntity<ApiResponse<?>> createTable(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
String tableName = (String) body.get("tableName");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> columns = (List<Map<String, Object>>) body.get("columns");
|
||||
String description = (String) body.get("description");
|
||||
|
||||
if (tableName == null || tableName.isBlank() || columns == null || columns.isEmpty()) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("테이블명과 최소 1개의 컬럼이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> result = ddlService.createTable(tableName, columns, companyCode, userId, description);
|
||||
|
||||
if (Boolean.TRUE.equals(result.get("success"))) {
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||||
"tableName", result.get("tableName"),
|
||||
"columnCount", result.get("columnCount"),
|
||||
"executedQuery", result.get("executedQuery")
|
||||
), (String) result.get("message")));
|
||||
}
|
||||
return ResponseEntity.status(400).body(ApiResponse.error((String) result.get("message")));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/ddl/tables/{tableName}/columns - 컬럼 추가
|
||||
*/
|
||||
@PostMapping("/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<?>> addColumn(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> column = (Map<String, Object>) body.get("column");
|
||||
if (column == null || column.get("name") == null
|
||||
|| column.get("name").toString().isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("컬럼명이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> result = ddlService.addColumn(tableName, column, companyCode, userId);
|
||||
|
||||
if (Boolean.TRUE.equals(result.get("success"))) {
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||||
"tableName", result.get("tableName"),
|
||||
"columnName", result.get("columnName"),
|
||||
"executedQuery", result.get("executedQuery")
|
||||
), (String) result.get("message")));
|
||||
}
|
||||
return ResponseEntity.status(400).body(ApiResponse.error((String) result.get("message")));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/ddl/tables/{tableName} - 테이블 삭제
|
||||
*/
|
||||
@DeleteMapping("/tables/{tableName}")
|
||||
public ResponseEntity<ApiResponse<?>> dropTable(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> result = ddlService.dropTable(tableName, companyCode, userId);
|
||||
|
||||
if (Boolean.TRUE.equals(result.get("success"))) {
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||||
"tableName", result.get("tableName"),
|
||||
"executedQuery", result.get("executedQuery")
|
||||
), (String) result.get("message")));
|
||||
}
|
||||
return ResponseEntity.status(400).body(ApiResponse.error((String) result.get("message")));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/ddl/validate/table - 테이블 생성 사전 검증 (실제 생성 없음)
|
||||
*/
|
||||
@PostMapping("/validate/table")
|
||||
public ResponseEntity<ApiResponse<?>> validateTableCreation(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
String tableName = (String) body.get("tableName");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> columns = (List<Map<String, Object>>) body.get("columns");
|
||||
|
||||
if (tableName == null || columns == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("테이블명과 컬럼 정보가 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> result = ddlService.validateTableCreation(tableName, columns);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "검증 완료"));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 로그 및 모니터링
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/ddl/logs - DDL 실행 로그 조회
|
||||
*/
|
||||
@GetMapping("/logs")
|
||||
public ResponseEntity<ApiResponse<?>> getDdlLogs(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam(required = false, defaultValue = "50") int limit,
|
||||
@RequestParam(required = false) String userId,
|
||||
@RequestParam(required = false) String ddlType) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
List<Map<String, Object>> logs = ddlService.getDdlLogs(limit, userId, ddlType);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
Map.of("logs", logs, "total", logs.size()), "DDL 로그 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/ddl/statistics - DDL 실행 통계 조회
|
||||
*/
|
||||
@GetMapping("/statistics")
|
||||
public ResponseEntity<ApiResponse<?>> getDdlStatistics(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam(required = false) String fromDate,
|
||||
@RequestParam(required = false) String toDate) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> statistics = ddlService.getDdlStatistics(fromDate, toDate);
|
||||
return ResponseEntity.ok(ApiResponse.success(statistics, "DDL 통계 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/ddl/tables/{tableName}/history - 테이블 DDL 히스토리 조회
|
||||
*/
|
||||
@GetMapping("/tables/{tableName}/history")
|
||||
public ResponseEntity<ApiResponse<?>> getTableDdlHistory(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
List<Map<String, Object>> history = ddlService.getTableDdlHistory(tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
Map.of("tableName", tableName, "history", history, "total", history.size()),
|
||||
"테이블 DDL 히스토리 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/ddl/tables/{tableName}/info - 테이블 정보 조회
|
||||
*/
|
||||
@GetMapping("/tables/{tableName}/info")
|
||||
public ResponseEntity<ApiResponse<?>> getTableInfo(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> tableInfo = ddlService.getTableInfo(tableName);
|
||||
if (tableInfo == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("테이블 '" + tableName + "'을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(tableInfo, "테이블 정보 조회 성공"));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 시스템 관리
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* DELETE /api/ddl/logs/cleanup - 오래된 DDL 로그 정리
|
||||
* NOTE: /logs/cleanup 은 /logs/{id} 보다 우선 매칭 (리터럴 세그먼트 우선)
|
||||
*/
|
||||
@DeleteMapping("/logs/cleanup")
|
||||
public ResponseEntity<ApiResponse<?>> cleanupOldLogs(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam(required = false, defaultValue = "90") int retentionDays) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
int deletedCount = ddlService.cleanupOldLogs(retentionDays);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
Map.of("deletedCount", deletedCount, "retentionDays", retentionDays),
|
||||
deletedCount + "개의 오래된 DDL 로그가 삭제되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/ddl/info - DDL 서비스 정보
|
||||
*/
|
||||
@GetMapping("/info")
|
||||
public ResponseEntity<ApiResponse<?>> getInfo(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
if (!isSuperAdmin(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("최고 관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||||
"service", "DDL Execution Service",
|
||||
"version", "1.0.0",
|
||||
"description", "PostgreSQL 테이블 및 컬럼 동적 생성 서비스",
|
||||
"requirements", Map.of(
|
||||
"authentication", "Bearer Token 필요",
|
||||
"authorization", "회사코드 '*'인 SUPER_ADMIN만 접근 가능",
|
||||
"safety", "모든 DDL 실행은 안전성 검증 후 수행",
|
||||
"logging", "모든 DDL 실행은 감사 로그에 기록"
|
||||
),
|
||||
"endpoints", Map.of(
|
||||
"createTable", "POST /api/ddl/tables",
|
||||
"addColumn", "POST /api/ddl/tables/{tableName}/columns",
|
||||
"dropTable", "DELETE /api/ddl/tables/{tableName}",
|
||||
"validate", "POST /api/ddl/validate/table",
|
||||
"logs", "GET /api/ddl/logs",
|
||||
"statistics", "GET /api/ddl/statistics",
|
||||
"history", "GET /api/ddl/tables/{tableName}/history",
|
||||
"tableInfo", "GET /api/ddl/tables/{tableName}/info",
|
||||
"cleanup", "DELETE /api/ddl/logs/cleanup"
|
||||
)
|
||||
), "DDL 서비스 정보"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/ddl/health - 헬스체크 (인증만 확인, SUPER_ADMIN 불필요)
|
||||
*/
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<ApiResponse<?>> health() {
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||||
"status", "healthy",
|
||||
"timestamp", Instant.now().toString(),
|
||||
"checks", Map.of("service", "operational")
|
||||
), "DDL 서비스 정상"));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 내부 유틸
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private boolean isSuperAdmin(String companyCode) {
|
||||
return "*".equals(companyCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DeliveryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/delivery")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DeliveryController {
|
||||
|
||||
private final DeliveryService deliveryService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDeliveryList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(deliveryService.getDeliveryList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDeliveryInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(deliveryService.getDeliveryInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertDelivery(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(deliveryService.insertDelivery(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDelivery(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(deliveryService.updateDelivery(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteDelivery(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(deliveryService.deleteDelivery(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DepartmentService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/departments")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DepartmentController {
|
||||
|
||||
private final DepartmentService departmentService;
|
||||
|
||||
/**
|
||||
* 부서 목록 조회 (회사별)
|
||||
* GET /api/departments/companies/{companyCode}/departments
|
||||
*/
|
||||
@GetMapping("/companies/{companyCode}/departments")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDepartments(
|
||||
@PathVariable String companyCode,
|
||||
@RequestAttribute("companyCode") String userCompanyCode) {
|
||||
|
||||
if (!isSuperAdmin(userCompanyCode) && !userCompanyCode.equals(companyCode)) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("해당 회사의 부서를 조회할 권한이 없습니다."));
|
||||
}
|
||||
|
||||
List<Map<String, Object>> departments = departmentService.getDepartments(companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(departments, "부서 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서 상세 조회
|
||||
* GET /api/departments/{deptCode}
|
||||
*/
|
||||
@GetMapping("/{deptCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDepartment(
|
||||
@PathVariable String deptCode) {
|
||||
|
||||
Map<String, Object> department = departmentService.getDepartment(deptCode);
|
||||
if (department == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("부서를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(department, "부서 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서 생성
|
||||
* POST /api/departments/companies/{companyCode}/departments
|
||||
*/
|
||||
@PostMapping("/companies/{companyCode}/departments")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDepartment(
|
||||
@PathVariable String companyCode,
|
||||
@RequestAttribute("companyCode") String userCompanyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
if (!isSuperAdmin(userCompanyCode) && !userCompanyCode.equals(companyCode)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("해당 회사의 부서를 생성할 권한이 없습니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> created = departmentService.createDepartment(companyCode, body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(created, "부서가 생성되었습니다."));
|
||||
} catch (DepartmentService.DuplicateDeptNameException e) {
|
||||
return ResponseEntity.status(409).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서 수정
|
||||
* PUT /api/departments/{deptCode}
|
||||
*/
|
||||
@PutMapping("/{deptCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDepartment(
|
||||
@PathVariable String deptCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> updated = departmentService.updateDepartment(deptCode, body);
|
||||
if (updated == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("부서를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "부서가 수정되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서 삭제
|
||||
* DELETE /api/departments/{deptCode}
|
||||
*/
|
||||
@DeleteMapping("/{deptCode}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteDepartment(
|
||||
@PathVariable String deptCode,
|
||||
@RequestAttribute("role") String role) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
int memberCount = departmentService.deleteDepartment(deptCode);
|
||||
if (memberCount == -1) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("부서를 찾을 수 없습니다."));
|
||||
}
|
||||
String message = memberCount > 0
|
||||
? "부서가 삭제되었습니다. (부서원 " + memberCount + "명 제외됨)"
|
||||
: "부서가 삭제되었습니다.";
|
||||
return ResponseEntity.ok(ApiResponse.success(null, message));
|
||||
} catch (IllegalStateException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서원 목록 조회
|
||||
* GET /api/departments/{deptCode}/members
|
||||
*/
|
||||
@GetMapping("/{deptCode}/members")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDeptMembers(
|
||||
@PathVariable String deptCode) {
|
||||
|
||||
List<Map<String, Object>> members = departmentService.getDeptMembers(deptCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(members, "부서원 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 검색 (부서원 추가용)
|
||||
* GET /api/departments/companies/{companyCode}/users/search
|
||||
*/
|
||||
@GetMapping("/companies/{companyCode}/users/search")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> searchUsers(
|
||||
@PathVariable String companyCode,
|
||||
@RequestParam(required = false) String search) {
|
||||
|
||||
if (search == null || search.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("검색어를 입력해주세요."));
|
||||
}
|
||||
|
||||
List<Map<String, Object>> users = departmentService.searchUsers(companyCode, search);
|
||||
return ResponseEntity.ok(ApiResponse.success(users, "사용자 검색 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서원 추가
|
||||
* POST /api/departments/{deptCode}/members
|
||||
*/
|
||||
@PostMapping("/{deptCode}/members")
|
||||
public ResponseEntity<ApiResponse<Void>> addDeptMember(
|
||||
@PathVariable String deptCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
// 프론트엔드는 snake_case(user_id)로 전송 (Node.js 호환)
|
||||
Object userIdObj = body.get("user_id");
|
||||
if (userIdObj == null) userIdObj = body.get("userId");
|
||||
if (userIdObj == null || userIdObj.toString().isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("사용자 ID를 입력해주세요."));
|
||||
}
|
||||
String userId = userIdObj.toString();
|
||||
|
||||
try {
|
||||
departmentService.addDeptMember(deptCode, userId);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(null, "부서원이 추가되었습니다."));
|
||||
} catch (DepartmentService.DuplicateMemberException e) {
|
||||
return ResponseEntity.status(409).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 부서원 제거
|
||||
* DELETE /api/departments/{deptCode}/members/{userId}
|
||||
*/
|
||||
@DeleteMapping("/{deptCode}/members/{userId}")
|
||||
public ResponseEntity<ApiResponse<Void>> removeDeptMember(
|
||||
@PathVariable String deptCode,
|
||||
@PathVariable String userId,
|
||||
@RequestAttribute("role") String role) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
boolean removed = departmentService.removeDeptMember(deptCode, userId);
|
||||
if (!removed) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("해당 부서원을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "부서원이 제거되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 주 부서 설정
|
||||
* PUT /api/departments/{deptCode}/members/{userId}/primary
|
||||
*/
|
||||
@PutMapping("/{deptCode}/members/{userId}/primary")
|
||||
public ResponseEntity<ApiResponse<Void>> setPrimaryDept(
|
||||
@PathVariable String deptCode,
|
||||
@PathVariable String userId,
|
||||
@RequestAttribute("role") String role) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
departmentService.setPrimaryDept(deptCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "주 부서가 설정되었습니다."));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────
|
||||
// 내부 유틸
|
||||
// ──────────────────────────────────────────────────
|
||||
|
||||
private boolean isAdmin(String role) {
|
||||
return isSuperAdmin(role) || "COMPANY_ADMIN".equals(role);
|
||||
}
|
||||
|
||||
private boolean isSuperAdmin(String companyCodeOrRole) {
|
||||
return "*".equals(companyCodeOrRole) || "SUPER_ADMIN".equals(companyCodeOrRole);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DesignService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/design")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DesignController {
|
||||
|
||||
private final DesignService designService;
|
||||
|
||||
// ============================================
|
||||
// 설계의뢰 (Design Request)
|
||||
// ============================================
|
||||
|
||||
@GetMapping("/requests")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDesignRequestList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.getDesignRequestList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/requests/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDesignRequestDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> result = designService.getDesignRequestDetail(id, companyCode);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("의뢰를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping("/requests")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDesignRequest(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createDesignRequest(body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@PutMapping("/requests/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDesignRequest(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = designService.updateDesignRequest(id, body, companyCode, userId);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("의뢰를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/requests/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteDesignRequest(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
boolean deleted = designService.deleteDesignRequest(id, companyCode);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("의뢰를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
@PostMapping("/requests/{id}/history")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> addRequestHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.addRequestHistory(id, body, companyCode, userId)));
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 설계 프로젝트
|
||||
// ============================================
|
||||
|
||||
@GetMapping("/projects")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getProjectList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.getProjectList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/projects/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getProjectDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> result = designService.getProjectDetail(id, companyCode);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("프로젝트를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping("/projects")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createProject(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createProject(body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@PutMapping("/projects/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateProject(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = designService.updateProject(id, body, companyCode);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("프로젝트를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/projects/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteProject(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
boolean deleted = designService.deleteProject(id, companyCode);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("프로젝트를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 프로젝트 태스크
|
||||
// ============================================
|
||||
|
||||
@GetMapping("/projects/{projectId}/tasks")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTasksByProject(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String projectId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.getTasksByProject(projectId, companyCode)));
|
||||
}
|
||||
|
||||
@PostMapping("/projects/{projectId}/tasks")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createTask(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String projectId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createTask(projectId, body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@PutMapping("/tasks/{taskId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateTask(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String taskId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = designService.updateTask(taskId, body, companyCode);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("태스크를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/tasks/{taskId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteTask(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String taskId) {
|
||||
boolean deleted = designService.deleteTask(taskId, companyCode);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("태스크를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 작업일지
|
||||
// ============================================
|
||||
|
||||
@GetMapping("/tasks/{taskId}/work-logs")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getWorkLogsByTask(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String taskId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.getWorkLogsByTask(taskId, companyCode)));
|
||||
}
|
||||
|
||||
@PostMapping("/tasks/{taskId}/work-logs")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createWorkLog(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String taskId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createWorkLog(taskId, body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/work-logs/{workLogId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteWorkLog(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String workLogId) {
|
||||
boolean deleted = designService.deleteWorkLog(workLogId, companyCode);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("작업일지를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 태스크 하위항목
|
||||
// ============================================
|
||||
|
||||
@PostMapping("/tasks/{taskId}/sub-items")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createSubItem(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String taskId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createSubItem(taskId, body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@PutMapping("/sub-items/{subItemId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateSubItem(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String subItemId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = designService.updateSubItem(subItemId, body, companyCode);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("하위항목을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/sub-items/{subItemId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteSubItem(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String subItemId) {
|
||||
boolean deleted = designService.deleteSubItem(subItemId, companyCode);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("하위항목을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 태스크 이슈
|
||||
// ============================================
|
||||
|
||||
@PostMapping("/tasks/{taskId}/issues")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createIssue(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String taskId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createIssue(taskId, body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@PutMapping("/issues/{issueId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateIssue(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String issueId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = designService.updateIssue(issueId, body, companyCode);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("이슈를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// ECN (설변통보)
|
||||
// ============================================
|
||||
|
||||
@GetMapping("/ecn")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getEcnList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.getEcnList(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/ecn")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createEcn(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createEcn(body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@PutMapping("/ecn/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateEcn(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = designService.updateEcn(id, body, companyCode, userId);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("ECN을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/ecn/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteEcn(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
boolean deleted = designService.deleteEcn(id, companyCode);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("ECN을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 나의 업무
|
||||
// ============================================
|
||||
|
||||
@GetMapping("/my-work")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMyWork(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userName", required = false) String userName,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.getMyWork(params, companyCode, userName)));
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 구매요청 / 협업요청
|
||||
// ============================================
|
||||
|
||||
@PostMapping("/work-logs/{workLogId}/purchase-reqs")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createPurchaseReq(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String workLogId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createPurchaseReq(workLogId, body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@PostMapping("/work-logs/{workLogId}/coop-reqs")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createCoopReq(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String workLogId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.createCoopReq(workLogId, body, companyCode, userId)));
|
||||
}
|
||||
|
||||
@PostMapping("/coop-reqs/{coopReqId}/responses")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> addCoopResponse(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String coopReqId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
return ResponseEntity.ok(ApiResponse.success(designService.addCoopResponse(coopReqId, body, companyCode, userId)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DigitalTwinService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/digital-twin")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DigitalTwinController {
|
||||
|
||||
private final DigitalTwinService digitalTwinService;
|
||||
|
||||
// ========== 레이아웃 관리 API ==========
|
||||
|
||||
/** GET /layouts → 레이아웃 목록 */
|
||||
@GetMapping("/layouts")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDigitalTwinLayoutList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(digitalTwinService.getDigitalTwinLayoutList(params)));
|
||||
}
|
||||
|
||||
/** GET /layouts/:id → 레이아웃 상세 (객체 포함) */
|
||||
@GetMapping("/layouts/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDigitalTwinLayoutInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
Map<String, Object> result = digitalTwinService.getDigitalTwinLayoutInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("레이아웃을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** POST /layouts → 레이아웃 생성 */
|
||||
@PostMapping("/layouts")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDigitalTwinLayout(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("createdBy", userId);
|
||||
Map<String, Object> result = digitalTwinService.createDigitalTwinLayout(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** PUT /layouts/:id → 레이아웃 수정 */
|
||||
@PutMapping("/layouts/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDigitalTwinLayout(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("updatedBy", userId);
|
||||
body.put("id", id);
|
||||
Map<String, Object> result = digitalTwinService.updateDigitalTwinLayout(body);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("레이아웃을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** DELETE /layouts/:id → 레이아웃 삭제 */
|
||||
@DeleteMapping("/layouts/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteDigitalTwinLayout(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
boolean deleted = digitalTwinService.deleteDigitalTwinLayout(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("레이아웃을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "레이아웃이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
// ========== 매핑 템플릿 API ==========
|
||||
|
||||
/** GET /mapping-templates → 매핑 템플릿 목록 */
|
||||
@GetMapping("/mapping-templates")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDigitalTwinTemplateList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(digitalTwinService.getDigitalTwinTemplateList(params)));
|
||||
}
|
||||
|
||||
/** GET /mapping-templates/:id → 매핑 템플릿 상세 */
|
||||
@GetMapping("/mapping-templates/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDigitalTwinTemplateInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
Map<String, Object> result = digitalTwinService.getDigitalTwinTemplateInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("매핑 템플릿을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** POST /mapping-templates → 매핑 템플릿 생성 */
|
||||
@PostMapping("/mapping-templates")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDigitalTwinTemplate(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("name") == null || body.get("externalDbConnectionId") == null || body.get("config") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("필수 필드가 누락되었습니다. (name, externalDbConnectionId, config)"));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("createdBy", userId);
|
||||
Map<String, Object> result = digitalTwinService.createDigitalTwinTemplate(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
// ========== 외부 DB 데이터 조회 API ==========
|
||||
|
||||
/** POST /data/hierarchy → 전체 계층 데이터 조회 */
|
||||
@PostMapping("/data/hierarchy")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getHierarchyData(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("externalDbConnectionId") == null || body.get("hierarchyConfig") == null) {
|
||||
return ResponseEntity.status(400).body(
|
||||
ApiResponse.error("외부 DB 연결 ID와 계층 구조 설정이 필요합니다."));
|
||||
}
|
||||
Map<String, Object> result = digitalTwinService.getHierarchyData(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** POST /data/children → 특정 부모의 하위 데이터 조회 */
|
||||
@PostMapping("/data/children")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getChildrenData(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("externalDbConnectionId") == null || body.get("hierarchyConfig") == null
|
||||
|| body.get("parentLevel") == null || body.get("parentKey") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("필수 파라미터가 누락되었습니다."));
|
||||
}
|
||||
List<Map<String, Object>> result = digitalTwinService.getChildrenData(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** GET /data/tables/:connectionId → 테이블 목록 */
|
||||
@GetMapping("/data/tables/{connectionId}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getExternalTables(
|
||||
@PathVariable Long connectionId) {
|
||||
List<Map<String, Object>> result = digitalTwinService.getExternalTables(connectionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** GET /data/table-preview/:connectionId/:tableName → 테이블 미리보기 */
|
||||
@GetMapping("/data/table-preview/{connectionId}/{tableName}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTablePreview(
|
||||
@PathVariable Long connectionId,
|
||||
@PathVariable String tableName) {
|
||||
List<Map<String, Object>> result = digitalTwinService.getTablePreview(connectionId, tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** GET /data/warehouses → 창고 목록 (레거시) */
|
||||
@GetMapping("/data/warehouses")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getWarehouses(
|
||||
@RequestParam Long externalDbConnectionId,
|
||||
@RequestParam String tableName) {
|
||||
if (externalDbConnectionId == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("외부 DB 연결 ID가 필요합니다."));
|
||||
}
|
||||
List<Map<String, Object>> result = digitalTwinService.getWarehouses(externalDbConnectionId, tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** GET /data/areas → 구역 목록 (레거시) */
|
||||
@GetMapping("/data/areas")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAreas(
|
||||
@RequestParam Long externalDbConnectionId,
|
||||
@RequestParam String warehouseKey,
|
||||
@RequestParam String tableName) {
|
||||
List<Map<String, Object>> result = digitalTwinService.getAreas(externalDbConnectionId, tableName, warehouseKey);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** GET /data/locations → 위치 목록 (레거시) */
|
||||
@GetMapping("/data/locations")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getLocations(
|
||||
@RequestParam Long externalDbConnectionId,
|
||||
@RequestParam String areaKey,
|
||||
@RequestParam String tableName) {
|
||||
List<Map<String, Object>> result = digitalTwinService.getLocations(externalDbConnectionId, tableName, areaKey);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** GET /data/materials → 자재 목록 (레거시) */
|
||||
@GetMapping("/data/materials")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMaterials(
|
||||
@RequestParam Long externalDbConnectionId,
|
||||
@RequestParam String locaKey,
|
||||
@RequestParam String tableName,
|
||||
@RequestParam String locationKeyColumn,
|
||||
@RequestParam(required = false) String layerColumn) {
|
||||
List<Map<String, Object>> result = digitalTwinService.getMaterials(
|
||||
externalDbConnectionId, tableName, locaKey, locationKeyColumn, layerColumn);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** POST /data/material-counts → 자재 개수 (여러 Location, 레거시) */
|
||||
@PostMapping("/data/material-counts")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMaterialCounts(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("externalDbConnectionId") == null || body.get("locationKeys") == null
|
||||
|| body.get("tableName") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("필수 파라미터가 누락되었습니다."));
|
||||
}
|
||||
List<Map<String, Object>> result = digitalTwinService.getMaterialCounts(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DriverService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/driver")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DriverController {
|
||||
private final DriverService driverService;
|
||||
|
||||
/** GET /list → 운전자 목록 (admin용 / api_test 호환) */
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDriverList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(driverService.getDriverList(params)));
|
||||
}
|
||||
|
||||
/** GET /profile → 운전자 프로필 조회 */
|
||||
@GetMapping("/profile")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDriverProfile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId) {
|
||||
if (userId == null) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("인증이 필요합니다."));
|
||||
}
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
Map<String, Object> result = driverService.getDriverProfile(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("사용자를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** PUT /profile → 운전자 프로필 수정 */
|
||||
@PutMapping("/profile")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDriverProfile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (userId == null) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("인증이 필요합니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
driverService.updateDriverProfile(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "프로필이 수정되었습니다."));
|
||||
}
|
||||
|
||||
/** PUT /status → 차량 상태 변경 (off: 대기, maintenance: 정비) */
|
||||
@PutMapping("/status")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDriverStatus(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (userId == null) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("인증이 필요합니다."));
|
||||
}
|
||||
String status = body.get("status") != null ? String.valueOf(body.get("status")) : null;
|
||||
if (status == null || (!status.equals("off") && !status.equals("maintenance"))) {
|
||||
return ResponseEntity.status(400).body(
|
||||
ApiResponse.error("유효하지 않은 상태값입니다. (off: 대기, maintenance: 정비)"));
|
||||
}
|
||||
body.put("userId", userId);
|
||||
driverService.updateDriverStatus(body);
|
||||
String msg = "off".equals(status) ? "차량 상태가 대기로 변경되었습니다." : "차량 상태가 정비로 변경되었습니다.";
|
||||
return ResponseEntity.ok(ApiResponse.success(null, msg));
|
||||
}
|
||||
|
||||
/** DELETE /vehicle → 차량 삭제 (기록 보존) */
|
||||
@DeleteMapping("/vehicle")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteDriverVehicle(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId) {
|
||||
if (userId == null) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("인증이 필요합니다."));
|
||||
}
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("userId", userId);
|
||||
driverService.deleteDriverVehicle(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "차량이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
/** POST /vehicle → 새 차량 등록 */
|
||||
@PostMapping("/vehicle")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> registerDriverVehicle(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (userId == null) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("인증이 필요합니다."));
|
||||
}
|
||||
if (body.get("vehicleNumber") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("차량번호는 필수입니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
driverService.registerDriverVehicle(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "차량이 등록되었습니다."));
|
||||
}
|
||||
|
||||
/** DELETE /account → 회원 탈퇴 */
|
||||
@DeleteMapping("/account")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteDriverAccount(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId) {
|
||||
if (userId == null) {
|
||||
return ResponseEntity.status(401).body(ApiResponse.error("인증이 필요합니다."));
|
||||
}
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("userId", userId);
|
||||
driverService.deleteDriverAccount(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "회원 탈퇴가 완료되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.DynamicFormService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/dynamic-form")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class DynamicFormController {
|
||||
|
||||
private final DynamicFormService dynamicFormService;
|
||||
|
||||
private static final Pattern VALID_NAME = Pattern.compile("^[a-zA-Z_][a-zA-Z0-9_]*$");
|
||||
|
||||
// ── POST /save ────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/save")
|
||||
public ResponseEntity<ApiResponse<Object>> saveFormData(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body,
|
||||
HttpServletRequest request) {
|
||||
|
||||
Object screenIdRaw = body.get("screenId");
|
||||
String tableName = (String) body.get("tableName");
|
||||
Map<String, Object> data = (Map<String, Object>) body.get("data");
|
||||
|
||||
if (screenIdRaw == null || tableName == null || data == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (screenId, tableName, data)"));
|
||||
}
|
||||
|
||||
int screenId = ((Number) screenIdRaw).intValue();
|
||||
|
||||
Map<String, Object> formDataWithMeta = new LinkedHashMap<>(data);
|
||||
formDataWithMeta.put("created_by", userId);
|
||||
formDataWithMeta.put("updated_by", userId);
|
||||
formDataWithMeta.put("writer", data.getOrDefault("writer", userId));
|
||||
formDataWithMeta.put("screen_id", screenId);
|
||||
|
||||
if (data.containsKey("company_code")) {
|
||||
formDataWithMeta.put("company_code", data.get("company_code"));
|
||||
} else if (companyCode != null && !"*".equals(companyCode)) {
|
||||
formDataWithMeta.put("company_code", companyCode);
|
||||
}
|
||||
|
||||
String ipAddress = Optional.ofNullable(request.getHeader("X-Forwarded-For"))
|
||||
.orElse(request.getRemoteAddr());
|
||||
|
||||
try {
|
||||
Object result = dynamicFormService.saveFormData(screenId, tableName, formDataWithMeta, ipAddress);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "데이터가 성공적으로 저장되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("폼 데이터 저장 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "데이터 저장에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── POST /save-enhanced ───────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/save-enhanced")
|
||||
public ResponseEntity<ApiResponse<Object>> saveFormDataEnhanced(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object screenIdRaw = body.get("screenId");
|
||||
String tableName = (String) body.get("tableName");
|
||||
Map<String, Object> data = (Map<String, Object>) body.get("data");
|
||||
|
||||
if (screenIdRaw == null || tableName == null || data == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (screenId, tableName, data)"));
|
||||
}
|
||||
|
||||
int screenId = ((Number) screenIdRaw).intValue();
|
||||
|
||||
Map<String, Object> formDataWithMeta = new LinkedHashMap<>(data);
|
||||
formDataWithMeta.put("created_by", userId);
|
||||
formDataWithMeta.put("updated_by", userId);
|
||||
formDataWithMeta.put("writer", data.getOrDefault("writer", userId));
|
||||
formDataWithMeta.put("screen_id", screenId);
|
||||
|
||||
if (data.containsKey("company_code")) {
|
||||
formDataWithMeta.put("company_code", data.get("company_code"));
|
||||
} else if (companyCode != null && !"*".equals(companyCode)) {
|
||||
formDataWithMeta.put("company_code", companyCode);
|
||||
}
|
||||
|
||||
try {
|
||||
Object result = dynamicFormService.saveFormDataEnhanced(screenId, tableName, formDataWithMeta);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "데이터가 성공적으로 저장되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("개선된 폼 데이터 저장 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "데이터 저장에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── PUT /update-field ─────────────────────────────────────────────────────
|
||||
|
||||
@PutMapping("/update-field")
|
||||
public ResponseEntity<ApiResponse<Object>> updateFieldValue(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String tableName = (String) body.get("tableName");
|
||||
String keyField = (String) body.get("keyField");
|
||||
Object keyValue = body.get("keyValue");
|
||||
String updateField = (String) body.get("updateField");
|
||||
Object updateValue = body.get("updateValue");
|
||||
|
||||
if (tableName == null || keyField == null || keyValue == null
|
||||
|| updateField == null || updateValue == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (tableName, keyField, keyValue, updateField, updateValue)"));
|
||||
}
|
||||
|
||||
if (!VALID_NAME.matcher(tableName).matches()
|
||||
|| !VALID_NAME.matcher(keyField).matches()
|
||||
|| !VALID_NAME.matcher(updateField).matches()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("유효하지 않은 테이블명 또는 컬럼명입니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> result = dynamicFormService.updateFieldValue(
|
||||
tableName, keyField, keyValue, updateField, updateValue, companyCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "필드 값이 업데이트되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("[updateFieldValue] 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "필드 업데이트에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── PUT /{id} ─────────────────────────────────────────────────────────────
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Object>> updateFormData(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String tableName = (String) body.get("tableName");
|
||||
Map<String, Object> data = (Map<String, Object>) body.get("data");
|
||||
|
||||
if (tableName == null || data == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (tableName, data)"));
|
||||
}
|
||||
|
||||
Map<String, Object> formDataWithMeta = new LinkedHashMap<>(data);
|
||||
formDataWithMeta.put("updated_by", userId);
|
||||
formDataWithMeta.put("writer", data.getOrDefault("writer", userId));
|
||||
formDataWithMeta.put("updated_at", new java.util.Date());
|
||||
|
||||
try {
|
||||
Map<String, Object> result = dynamicFormService.updateFormData(id, tableName, formDataWithMeta);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "데이터가 성공적으로 업데이트되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("폼 데이터 업데이트 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "데이터 업데이트에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── PATCH /{id}/partial ───────────────────────────────────────────────────
|
||||
|
||||
@PatchMapping("/{id}/partial")
|
||||
public ResponseEntity<ApiResponse<Object>> updateFormDataPartial(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String tableName = (String) body.get("tableName");
|
||||
Map<String, Object> originalData = (Map<String, Object>) body.get("originalData");
|
||||
Map<String, Object> newData = (Map<String, Object>) body.get("newData");
|
||||
|
||||
if (tableName == null || originalData == null || newData == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (tableName, originalData, newData)"));
|
||||
}
|
||||
|
||||
Map<String, Object> newDataWithMeta = new LinkedHashMap<>(newData);
|
||||
newDataWithMeta.put("updated_by", userId);
|
||||
newDataWithMeta.put("writer", newData.getOrDefault("writer", userId));
|
||||
|
||||
try {
|
||||
Map<String, Object> result = dynamicFormService.updateFormDataPartial(
|
||||
id, tableName, originalData, newDataWithMeta);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "데이터가 성공적으로 업데이트되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("부분 업데이트 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "데이터 업데이트에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── DELETE /{id} ──────────────────────────────────────────────────────────
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteFormData(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
|
||||
if (body == null) body = new HashMap<>();
|
||||
String tableName = (String) body.get("tableName");
|
||||
Object screenIdRaw = body.get("screenId");
|
||||
|
||||
if (tableName == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (tableName)"));
|
||||
}
|
||||
|
||||
Integer screenId = screenIdRaw != null
|
||||
? Integer.parseInt(screenIdRaw.toString())
|
||||
: null;
|
||||
|
||||
try {
|
||||
dynamicFormService.deleteFormData(id, tableName, companyCode, userId, screenId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "데이터가 성공적으로 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("폼 데이터 삭제 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "데이터 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── GET /screen/{screenId} ────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/screen/{screenId}")
|
||||
public ResponseEntity<ApiResponse<Object>> getFormDataList(
|
||||
@PathVariable int screenId,
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "10") int size,
|
||||
@RequestParam(defaultValue = "") String search,
|
||||
@RequestParam(defaultValue = "created_at") String sortBy,
|
||||
@RequestParam(defaultValue = "desc") String sortOrder) {
|
||||
|
||||
try {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("page", page);
|
||||
params.put("size", size);
|
||||
params.put("search", search.isEmpty() ? null : search);
|
||||
params.put("sortBy", sortBy);
|
||||
params.put("sortOrder", sortOrder);
|
||||
|
||||
Map<String, Object> result = dynamicFormService.getFormDataList(screenId, params);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("폼 데이터 목록 조회 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "데이터 조회에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── GET /table/{tableName}/columns ────────────────────────────────────────
|
||||
|
||||
@GetMapping("/table/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<Object>> getTableColumns(@PathVariable String tableName) {
|
||||
try {
|
||||
List<Map<String, Object>> columns = dynamicFormService.getTableColumns(tableName);
|
||||
Map<String, Object> data = new LinkedHashMap<>();
|
||||
data.put("tableName", tableName);
|
||||
data.put("columns", columns);
|
||||
return ResponseEntity.ok(ApiResponse.success(data));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블 컬럼 정보 조회 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "테이블 정보 조회에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── GET /table/{tableName}/primary-keys ───────────────────────────────────
|
||||
|
||||
@GetMapping("/table/{tableName}/primary-keys")
|
||||
public ResponseEntity<ApiResponse<Object>> getTablePrimaryKeys(@PathVariable String tableName) {
|
||||
if (tableName == null || tableName.isEmpty()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("테이블명이 누락되었습니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
List<String> primaryKeys = dynamicFormService.getTablePrimaryKeys(tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(primaryKeys, "기본키 조회가 완료되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("기본키 조회 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "기본키 조회에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── POST /validate ────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/validate")
|
||||
public ResponseEntity<ApiResponse<Object>> validateFormData(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String tableName = (String) body.get("tableName");
|
||||
Map<String, Object> data = (Map<String, Object>) body.get("data");
|
||||
|
||||
if (tableName == null || data == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (tableName, data)"));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> result = dynamicFormService.validateFormData(tableName, data);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("폼 데이터 검증 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "데이터 검증에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── GET /location-history/{tripId} ────────────────────────────────────────
|
||||
|
||||
@GetMapping("/location-history/{tripId}")
|
||||
public ResponseEntity<ApiResponse<Object>> getLocationHistory(
|
||||
@PathVariable String tripId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam(required = false) String userId,
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate,
|
||||
@RequestParam(required = false) Integer limit) {
|
||||
|
||||
try {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("tripId", tripId);
|
||||
if (userId != null) params.put("userId", userId);
|
||||
if (startDate != null) params.put("startDate", startDate);
|
||||
if (endDate != null) params.put("endDate", endDate);
|
||||
params.put("limit", limit != null ? limit : 1000);
|
||||
|
||||
List<Map<String, Object>> result = dynamicFormService.getLocationHistory(params);
|
||||
|
||||
Map<String, Object> response = new LinkedHashMap<>();
|
||||
response.put("success", true);
|
||||
response.put("data", result);
|
||||
response.put("count", result.size());
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
} catch (Exception e) {
|
||||
log.error("[getLocationHistory] 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "위치 이력 조회에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── POST /location-history ────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/location-history")
|
||||
public ResponseEntity<ApiResponse<Object>> saveLocationHistory(
|
||||
@RequestAttribute("userId") String loginUserId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Double latitude = body.get("latitude") != null ? ((Number) body.get("latitude")).doubleValue() : null;
|
||||
Double longitude = body.get("longitude") != null ? ((Number) body.get("longitude")).doubleValue() : null;
|
||||
|
||||
if (latitude == null || longitude == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (latitude, longitude)"));
|
||||
}
|
||||
|
||||
String userId = body.containsKey("userId") ? (String) body.get("userId") : loginUserId;
|
||||
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("userId", userId);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("latitude", latitude);
|
||||
params.put("longitude", longitude);
|
||||
params.put("accuracy", body.get("accuracy"));
|
||||
params.put("altitude", body.get("altitude"));
|
||||
params.put("speed", body.get("speed"));
|
||||
params.put("heading", body.get("heading"));
|
||||
params.put("tripId", body.get("tripId"));
|
||||
params.put("tripStatus", body.getOrDefault("tripStatus", "active"));
|
||||
params.put("departure", body.get("departure"));
|
||||
params.put("arrival", body.get("arrival"));
|
||||
params.put("departureName", body.get("departureName"));
|
||||
params.put("destinationName", body.get("destinationName"));
|
||||
params.put("recordedAt", body.getOrDefault("recordedAt", new java.util.Date().toInstant().toString()));
|
||||
params.put("vehicleId", body.get("vehicleId"));
|
||||
|
||||
try {
|
||||
Map<String, Object> result = dynamicFormService.saveLocationHistory(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "위치 이력이 저장되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("[saveLocationHistory] 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "위치 이력 저장에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── GET /{id} ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Object>> getFormData(@PathVariable int id) {
|
||||
try {
|
||||
Map<String, Object> data = dynamicFormService.getFormData(id);
|
||||
if (data == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("데이터를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(data));
|
||||
} catch (Exception e) {
|
||||
log.error("폼 데이터 단건 조회 실패: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage() : "데이터 조회에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.EntityJoinService;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Entity 조인 API 컨트롤러.
|
||||
* Node.js /api/table-management/* 라우트와 동일한 경로/응답 형식을 제공한다.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/table-management")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class EntityJoinController {
|
||||
|
||||
private final EntityJoinService entityJoinService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
// Entity 조인 데이터 조회
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* GET /api/table-management/tables/{tableName}/data-with-joins
|
||||
* Entity 조인이 포함된 테이블 데이터 조회 (페이지네이션)
|
||||
*/
|
||||
@GetMapping("/tables/{tableName}/data-with-joins")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableDataWithJoins(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
|
||||
Map<String, Object> options = new HashMap<>(queryParams);
|
||||
options.put("companyCode", companyCode);
|
||||
|
||||
// search 파라미터 JSON 파싱
|
||||
Object searchRaw = queryParams.get("search");
|
||||
if (searchRaw instanceof String s && !s.isBlank()) {
|
||||
try {
|
||||
options.put("search", objectMapper.readValue(s, new TypeReference<Map<String, Object>>() {}));
|
||||
} catch (Exception e) {
|
||||
log.warn("search 파싱 실패: {}", e.getMessage());
|
||||
options.remove("search");
|
||||
}
|
||||
}
|
||||
|
||||
// autoFilter 파싱 (멀티테넌시)
|
||||
Object autoFilterRaw = queryParams.get("autoFilter");
|
||||
if (autoFilterRaw instanceof String af && !af.isBlank()) {
|
||||
try {
|
||||
Map<String, Object> autoFilter = objectMapper.readValue(af, new TypeReference<>() {});
|
||||
Boolean enabled = (Boolean) autoFilter.getOrDefault("enabled", false);
|
||||
if (Boolean.TRUE.equals(enabled)) {
|
||||
String filterColumn = (String) autoFilter.getOrDefault("filterColumn", "company_code");
|
||||
Map<String, Object> search = getOrCreateSearch(options);
|
||||
String finalCode = companyCode;
|
||||
if ("*".equals(companyCode) && autoFilter.get("companyCodeOverride") != null) {
|
||||
finalCode = (String) autoFilter.get("companyCodeOverride");
|
||||
}
|
||||
search.put(filterColumn, finalCode);
|
||||
options.put("search", search);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("autoFilter 파싱 실패: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> result = entityJoinService.getTableDataWithJoins(tableName, options);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "Entity 조인 데이터 조회 성공"));
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
// Entity 조인 설정 관리
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* GET /api/table-management/tables/{tableName}/entity-joins
|
||||
* 테이블의 Entity 조인 설정 조회
|
||||
*/
|
||||
@GetMapping("/tables/{tableName}/entity-joins")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getEntityJoinConfigs(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
List<Map<String, Object>> joinConfigs =
|
||||
entityJoinService.detectEntityJoins(tableName, null, companyCode);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("tableName", tableName);
|
||||
data.put("joinConfigs", joinConfigs);
|
||||
data.put("count", joinConfigs.size());
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "Entity 조인 설정 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/table-management/tables/{tableName}/columns/{columnName}/entity-settings
|
||||
* 컬럼 Entity 설정 업데이트 (display_column 포함)
|
||||
*/
|
||||
@PutMapping("/tables/{tableName}/columns/{columnName}/entity-settings")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateEntitySettings(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String webType = (String) body.get("webType");
|
||||
String referenceTable = (String) body.get("referenceTable");
|
||||
String referenceColumn = (String) body.get("referenceColumn");
|
||||
|
||||
if ("entity".equals(webType) && (referenceTable == null || referenceColumn == null)) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("Entity 타입의 경우 referenceTable과 referenceColumn이 필수입니다."));
|
||||
}
|
||||
|
||||
entityJoinService.updateColumnEntitySettings(tableName, columnName, body, companyCode);
|
||||
|
||||
// 관련 캐시 무효화
|
||||
if ("entity".equals(webType) && referenceTable != null) {
|
||||
String displayColumn = (String) body.get("displayColumn");
|
||||
String referenceColVal = (String) body.get("referenceColumn");
|
||||
entityJoinService.invalidateCache(referenceTable, referenceColVal, displayColumn);
|
||||
}
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("tableName", tableName);
|
||||
data.put("columnName", columnName);
|
||||
data.put("settings", Map.of(
|
||||
"webType", webType != null ? webType : "",
|
||||
"referenceTable", referenceTable != null ? referenceTable : "",
|
||||
"referenceColumn", referenceColumn != null ? referenceColumn : "",
|
||||
"displayColumn", body.getOrDefault("displayColumn", "")));
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "Entity 설정 업데이트 성공"));
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
// 참조 테이블 정보
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* GET /api/table-management/tables/{tableName}/entity-join-columns
|
||||
* Entity 조인된 테이블의 추가 컬럼 목록 조회 (화면편집기용)
|
||||
*/
|
||||
@GetMapping("/tables/{tableName}/entity-join-columns")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getEntityJoinColumns(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
Map<String, Object> result = entityJoinService.getEntityJoinColumns(tableName, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "Entity 조인 컬럼 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/table-management/reference-tables/{tableName}/columns
|
||||
* 참조 테이블의 표시 가능한 컬럼 목록 조회
|
||||
*/
|
||||
@GetMapping("/reference-tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getReferenceTableColumns(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
List<Map<String, Object>> columns =
|
||||
entityJoinService.getReferenceTableColumns(tableName, companyCode);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("tableName", tableName);
|
||||
data.put("columns", columns);
|
||||
data.put("count", columns.size());
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "참조 테이블 컬럼 조회 성공"));
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
// 캐시 관리
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* GET /api/table-management/cache/status
|
||||
* 캐시 상태 조회
|
||||
*/
|
||||
@GetMapping("/cache/status")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCacheStatus() {
|
||||
return ResponseEntity.ok(ApiResponse.success(entityJoinService.getCacheStatus(), "캐시 상태 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/table-management/cache
|
||||
* 캐시 무효화 (table/keyColumn/displayColumn 지정 시 부분 무효화)
|
||||
*/
|
||||
@DeleteMapping("/cache")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> invalidateCache(
|
||||
@RequestParam(required = false) String table,
|
||||
@RequestParam(required = false) String keyColumn,
|
||||
@RequestParam(required = false) String displayColumn) {
|
||||
|
||||
entityJoinService.invalidateCache(table, keyColumn, displayColumn);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("target", (table != null)
|
||||
? table + "." + keyColumn + "." + displayColumn
|
||||
: "전체");
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "캐시 무효화 완료"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/table-management/cache/preload
|
||||
* 공통 참조 테이블 자동 캐싱
|
||||
*/
|
||||
@PostMapping("/cache/preload")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> preloadCommonCaches() {
|
||||
entityJoinService.preloadCommonCaches();
|
||||
Map<String, Object> cacheStatus = entityJoinService.getCacheStatus();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> caches = (List<Map<String, Object>>) cacheStatus.get("caches");
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("preloadedCaches", caches != null ? caches.size() : 0);
|
||||
data.put("caches", caches);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "공통 참조 테이블 캐싱 완료"));
|
||||
}
|
||||
|
||||
// ─── 내부 유틸 ──────────────────────────────────────────────────────────
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> getOrCreateSearch(Map<String, Object> options) {
|
||||
Object existing = options.get("search");
|
||||
if (existing instanceof Map) return (Map<String, Object>) existing;
|
||||
Map<String, Object> search = new HashMap<>();
|
||||
options.put("search", search);
|
||||
return search;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.EntityReferenceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/entity-reference")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class EntityReferenceController {
|
||||
|
||||
private final EntityReferenceService entityReferenceService;
|
||||
|
||||
/**
|
||||
* GET /api/entity-reference/code/:codeCategory
|
||||
* 공통 코드 데이터 조회
|
||||
*
|
||||
* NOTE: Spring MVC는 리터럴 경로 세그먼트("code")를 변수 경로({tableName})보다 우선하므로
|
||||
* /code/{codeCategory} 가 /{tableName}/{columnName} 보다 먼저 매핑됨.
|
||||
*/
|
||||
@GetMapping("/code/{codeCategory}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCodeData(
|
||||
@PathVariable String codeCategory,
|
||||
@RequestParam(required = false, defaultValue = "100") Integer limit,
|
||||
@RequestParam(required = false) String search,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("codeCategory", codeCategory);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("limit", limit);
|
||||
if (search != null) params.put("search", search);
|
||||
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(entityReferenceService.getCodeData(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("공통 코드 데이터 조회 실패: codeCategory={}", codeCategory, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("공통 코드 데이터 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/entity-reference/:tableName/:columnName
|
||||
* 엔티티 참조 데이터 조회
|
||||
*/
|
||||
@GetMapping("/{tableName}/{columnName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getEntityReferenceData(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestParam(required = false, defaultValue = "100") Integer limit,
|
||||
@RequestParam(required = false) String search,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("columnName", columnName);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("limit", limit);
|
||||
if (search != null) params.put("search", search);
|
||||
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(entityReferenceService.getEntityReferenceData(params)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (IllegalStateException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("엔티티 참조 데이터 조회 실패: {}.{}", tableName, columnName, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("엔티티 참조 데이터 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.EntitySearchService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Entity Search / Options / Distinct 통합 컨트롤러
|
||||
*
|
||||
* Node.js 라우트 대응:
|
||||
* GET /api/entity-search/:tableName → searchEntity
|
||||
* GET /api/entity/:tableName/options → getEntityOptions
|
||||
* GET /api/entity/:tableName/distinct/:col → getDistinctColumnValues
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class EntitySearchController {
|
||||
|
||||
private final EntitySearchService entitySearchService;
|
||||
|
||||
// ================================================================
|
||||
// GET /api/entity-search/{tableName}
|
||||
// ================================================================
|
||||
|
||||
@GetMapping("/api/entity-search/{tableName}")
|
||||
public ResponseEntity<?> searchEntity(
|
||||
@PathVariable String tableName,
|
||||
@RequestParam(defaultValue = "") String searchText,
|
||||
@RequestParam(defaultValue = "") String searchFields,
|
||||
@RequestParam(defaultValue = "{}") String filterCondition,
|
||||
@RequestParam(defaultValue = "1") String page,
|
||||
@RequestParam(defaultValue = "20") String limit,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
if (tableName == null || tableName.isBlank()
|
||||
|| "undefined".equals(tableName) || "null".equals(tableName)) {
|
||||
return ResponseEntity.status(400).body(
|
||||
ApiResponse.error("테이블명이 지정되지 않았습니다. 컴포넌트 설정에서 sourceTable을 확인해주세요."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("searchText", searchText);
|
||||
params.put("searchFields", searchFields);
|
||||
params.put("filterCondition", filterCondition);
|
||||
params.put("page", page);
|
||||
params.put("limit", limit);
|
||||
|
||||
try {
|
||||
Map<String, Object> result = entitySearchService.searchEntity(params);
|
||||
// Node.js 응답 형식: { success, data, pagination } — pagination이 data와 같은 레벨
|
||||
Map<String, Object> response = new LinkedHashMap<>();
|
||||
response.put("success", true);
|
||||
response.put("data", result.get("data"));
|
||||
response.put("pagination", result.get("pagination"));
|
||||
return ResponseEntity.ok(response);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("엔티티 검색 오류 table={}", tableName, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// GET /api/entity/{tableName}/options
|
||||
// ================================================================
|
||||
|
||||
@GetMapping("/api/entity/{tableName}/options")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getEntityOptions(
|
||||
@PathVariable String tableName,
|
||||
@RequestParam(defaultValue = "id") String value,
|
||||
@RequestParam(defaultValue = "name") String label,
|
||||
@RequestParam(required = false) String fields,
|
||||
@RequestParam(required = false) String filters,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
if (tableName == null || tableName.isBlank()
|
||||
|| "undefined".equals(tableName) || "null".equals(tableName)) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("테이블명이 지정되지 않았습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("value", value);
|
||||
params.put("label", label);
|
||||
params.put("fields", fields);
|
||||
params.put("filters", filters);
|
||||
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(entitySearchService.getEntityOptions(params)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("엔티티 옵션 조회 오류 table={}", tableName, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// GET /api/entity/{tableName}/distinct/{columnName}
|
||||
// ================================================================
|
||||
|
||||
@GetMapping("/api/entity/{tableName}/distinct/{columnName}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDistinctColumnValues(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestParam(required = false) String labelColumn,
|
||||
@RequestParam(required = false) String filters,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
if (tableName == null || tableName.isBlank()
|
||||
|| "undefined".equals(tableName) || "null".equals(tableName)) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("테이블명이 지정되지 않았습니다."));
|
||||
}
|
||||
if (columnName == null || columnName.isBlank()
|
||||
|| "undefined".equals(columnName) || "null".equals(columnName)) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("컬럼명이 지정되지 않았습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("columnName", columnName);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("labelColumn", labelColumn);
|
||||
params.put("filters", filters);
|
||||
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(entitySearchService.getDistinctColumnValues(params)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("컬럼 DISTINCT 조회 오류 table={} column={}", tableName, columnName, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ExcelMappingService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/excel-mapping")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ExcelMappingController {
|
||||
|
||||
private final ExcelMappingService excelMappingService;
|
||||
|
||||
@PostMapping("/find")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> findMappingByColumns(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("tableName") == null || body.get("excelColumns") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("tableName과 excelColumns는 필수입니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
Map<String, Object> result = excelMappingService.findMappingByColumns(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping("/save")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveMappingTemplate(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("tableName") == null || body.get("excelColumns") == null || body.get("columnMappings") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("tableName, excelColumns, columnMappings는 필수입니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
Map<String, Object> result = excelMappingService.saveMappingTemplate(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "매핑 템플릿이 저장되었습니다."));
|
||||
}
|
||||
|
||||
@GetMapping("/list/{tableName}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMappingTemplates(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("companyCode", companyCode);
|
||||
List<Map<String, Object>> result = excelMappingService.getMappingTemplates(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteMappingTemplate(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
boolean deleted = excelMappingService.deleteMappingTemplate(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("매핑 템플릿을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "매핑 템플릿이 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ExternalCallConfigService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/external-call-configs")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ExternalCallConfigController {
|
||||
|
||||
private final ExternalCallConfigService externalCallConfigService;
|
||||
|
||||
// ── 목록 조회 ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-call-configs
|
||||
* ?call_type=&api_type=&is_active=Y&search=&page=1&limit=20
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getExternalCallConfigList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
queryParams.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
externalCallConfigService.getExternalCallConfigList(queryParams)));
|
||||
}
|
||||
|
||||
// ── 버튼 제어용 목록 (리터럴 경로 - /{id} 보다 먼저 선언) ────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-call-configs/for-button-control
|
||||
*/
|
||||
@GetMapping("/for-button-control")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getExternalCallConfigForButtonControl(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
externalCallConfigService.getExternalCallConfigForButtonControl(companyCode)));
|
||||
}
|
||||
|
||||
// ── 단건 조회 ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-call-configs/:id
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getExternalCallConfigInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
Map<String, Object> config = externalCallConfigService.getExternalCallConfigInfo(params);
|
||||
if (config == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("외부 호출 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(config, "외부 호출 설정 조회 완료"));
|
||||
}
|
||||
|
||||
// ── 생성 ───────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /api/external-call-configs
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertExternalCallConfig(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("created_by", userId);
|
||||
body.put("updated_by", userId);
|
||||
try {
|
||||
Map<String, Object> created = externalCallConfigService.insertExternalCallConfig(body);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "외부 호출 설정이 성공적으로 생성되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 수정 ───────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* PUT /api/external-call-configs/:id
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateExternalCallConfig(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable int id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("updated_by", userId);
|
||||
body.put("id", id);
|
||||
try {
|
||||
Map<String, Object> updated = externalCallConfigService.updateExternalCallConfig(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "외부 호출 설정이 성공적으로 수정되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 삭제 (논리 삭제) ────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* DELETE /api/external-call-configs/:id
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteExternalCallConfig(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable int id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("updatedBy", userId);
|
||||
try {
|
||||
externalCallConfigService.deleteExternalCallConfig(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "외부 호출 설정이 성공적으로 삭제되었습니다."));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 설정 테스트 ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /api/external-call-configs/:id/test
|
||||
*/
|
||||
@PostMapping("/{id}/test")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> testExternalCallConfig(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id) {
|
||||
Map<String, Object> result = externalCallConfigService.testExternalCallConfig(id);
|
||||
String message = (String) result.get("message");
|
||||
return ResponseEntity.ok(ApiResponse.success(result, message));
|
||||
}
|
||||
|
||||
// ── 설정 실행 ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /api/external-call-configs/:id/execute
|
||||
*/
|
||||
@PostMapping("/{id}/execute")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeExternalCallConfig(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable int id,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
Map<String, Object> contextData = body != null ? new HashMap<>(body) : new HashMap<>();
|
||||
contextData.put("userId", userId);
|
||||
contextData.put("companyCode", companyCode);
|
||||
Map<String, Object> result = externalCallConfigService.executeExternalCallConfig(id, contextData);
|
||||
String message = (String) result.get("message");
|
||||
return ResponseEntity.ok(ApiResponse.success(result, message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ExternalCallService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/external-calls")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ExternalCallController {
|
||||
|
||||
private final ExternalCallService service;
|
||||
|
||||
// ── 외부 호출 테스트 ────────────────────────────────────────────────────────
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@PostMapping("/test")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> testExternalCall(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Map<String, Object> settings = (Map<String, Object>) body.get("settings");
|
||||
if (settings == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("외부 호출 설정이 필요합니다."));
|
||||
}
|
||||
|
||||
// 설정 검증
|
||||
Map<String, Object> validation = service.validateExternalCallSettings(settings);
|
||||
if (!Boolean.TRUE.equals(validation.get("valid"))) {
|
||||
Map<String, Object> errorData = new LinkedHashMap<>();
|
||||
errorData.put("errors", validation.get("errors"));
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("설정 검증 실패"));
|
||||
}
|
||||
|
||||
// 테스트 요청 생성
|
||||
Map<String, Object> templateData = (Map<String, Object>) body.get("templateData");
|
||||
if (templateData == null) {
|
||||
templateData = Map.of(
|
||||
"recordCount", 5,
|
||||
"tableName", "test_table",
|
||||
"timestamp", new Date().toString()
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, Object> request = new LinkedHashMap<>();
|
||||
request.put("diagramId", 0);
|
||||
request.put("relationshipId", "test");
|
||||
request.put("settings", settings);
|
||||
request.put("templateData", templateData);
|
||||
|
||||
Map<String, Object> result = service.executeExternalCall(request);
|
||||
boolean success = Boolean.TRUE.equals(result.get("success"));
|
||||
|
||||
if (success) {
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "외부 호출 테스트 성공"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "외부 호출 테스트 실패"));
|
||||
}
|
||||
|
||||
// ── 외부 호출 실행 ──────────────────────────────────────────────────────────
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@PostMapping("/execute")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeExternalCall(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object diagramId = body.get("diagramId");
|
||||
String relationshipId = (String) body.get("relationshipId");
|
||||
Map<String, Object> settings = (Map<String, Object>) body.get("settings");
|
||||
|
||||
if (diagramId == null || relationshipId == null || settings == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("필수 파라미터가 누락되었습니다. (diagramId, relationshipId, settings)"));
|
||||
}
|
||||
|
||||
// 설정 검증
|
||||
Map<String, Object> validation = service.validateExternalCallSettings(settings);
|
||||
if (!Boolean.TRUE.equals(validation.get("valid"))) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("설정 검증 실패"));
|
||||
}
|
||||
|
||||
Map<String, Object> result = service.executeExternalCall(body);
|
||||
boolean success = Boolean.TRUE.equals(result.get("success"));
|
||||
|
||||
if (success) {
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "외부 호출 실행 성공"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "외부 호출 실행 실패"));
|
||||
}
|
||||
|
||||
// ── 지원 타입 목록 ──────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/types")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getExternalCallTypeList(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> types = service.getExternalCallTypeList();
|
||||
return ResponseEntity.ok(ApiResponse.success(types, "지원되는 외부 호출 타입 목록"));
|
||||
}
|
||||
|
||||
// ── 설정 검증 ──────────────────────────────────────────────────────────────
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@PostMapping("/validate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> validateExternalCallSettings(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Map<String, Object> settings = (Map<String, Object>) body.get("settings");
|
||||
if (settings == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("검증할 설정이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> validation = service.validateExternalCallSettings(settings);
|
||||
return ResponseEntity.ok(ApiResponse.success(validation, "설정 검증 완료"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ExternalDbConnectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 외부 DB 연결 관리 API
|
||||
* Base: /api/external-db-connections
|
||||
*
|
||||
* 경로 우선순위 (Spring MVC: 리터럴 > 변수):
|
||||
* GET /types/supported, /pool-status, /grouped, /control/active → literal (먼저 매핑)
|
||||
* GET /{id} → variable
|
||||
* GET /{id}/tables/{tableName}/columns → 3-segment path
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/external-db-connections")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ExternalDbConnectionController {
|
||||
|
||||
private final ExternalDbConnectionService service;
|
||||
|
||||
// ── 지원 DB 타입 목록 ──────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-db-connections/types/supported
|
||||
*/
|
||||
@GetMapping("/types/supported")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getSupportedTypes(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(service.getSupportedTypes(), "지원하는 DB 타입 목록을 조회했습니다."));
|
||||
}
|
||||
|
||||
// ── 연결 풀 상태 ────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-db-connections/pool-status
|
||||
*/
|
||||
@GetMapping("/pool-status")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getPoolStatus(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> status = service.getPoolStatus();
|
||||
String msg = status.get("totalPools") + "개의 연결 풀 상태를 조회했습니다.";
|
||||
return ResponseEntity.ok(ApiResponse.success(status, msg));
|
||||
}
|
||||
|
||||
// ── 그룹화된 목록 조회 ─────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-db-connections/grouped
|
||||
*/
|
||||
@GetMapping("/grouped")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getConnectionsGroupedByType(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
buildFilter(queryParams, companyCode, (String) queryParams.get("company_code"));
|
||||
Map<String, Object> grouped = service.getConnectionsGroupedByType(queryParams);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(grouped, "DB 타입별로 그룹화된 연결 목록을 조회했습니다."));
|
||||
}
|
||||
|
||||
// ── 제어관리용 활성 연결 목록 ─────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-db-connections/control/active
|
||||
*/
|
||||
@GetMapping("/control/active")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getActiveConnectionsForControl(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam(required = false) String company_code) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
buildFilter(params, companyCode, company_code);
|
||||
List<Map<String, Object>> list = service.getActiveConnectionsForControl(params);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(list, "제어관리용 활성 커넥션 목록을 조회했습니다."));
|
||||
}
|
||||
|
||||
// ── 목록 조회 ──────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-db-connections
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getConnections(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
buildFilter(queryParams, companyCode, (String) queryParams.get("company_code"));
|
||||
List<Map<String, Object>> list = service.getConnections(queryParams);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(list, list.size() + "개의 연결 설정을 조회했습니다."));
|
||||
}
|
||||
|
||||
// ── 단건 조회 ──────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-db-connections/{id}
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getConnectionById(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable long id) {
|
||||
Map<String, Object> conn = service.getConnectionById(id);
|
||||
if (conn == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("해당 연결 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(conn, "연결 설정을 조회했습니다."));
|
||||
}
|
||||
|
||||
// ── 생성 ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /api/external-db-connections
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("created_by", userId);
|
||||
body.put("updated_by", userId);
|
||||
try {
|
||||
Map<String, Object> created = service.createConnection(body);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "연결 설정이 생성되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 수정 ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* PUT /api/external-db-connections/{id}
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("updated_by", userId);
|
||||
try {
|
||||
Map<String, Object> updated = service.updateConnection(id, body);
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "연결 설정이 수정되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 삭제 ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* DELETE /api/external-db-connections/{id}
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable long id) {
|
||||
try {
|
||||
service.deleteConnection(id, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "연결 설정이 삭제되었습니다."));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 연결 테스트 ────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /api/external-db-connections/{id}/test
|
||||
*/
|
||||
@PostMapping("/{id}/test")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> testConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable long id,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
String testPassword = body != null ? (String) body.get("password") : null;
|
||||
Map<String, Object> result = service.testConnectionById(id, testPassword);
|
||||
return ResponseEntity.ok(ApiResponse.success(result,
|
||||
Boolean.TRUE.equals(result.get("success")) ? "연결 성공" : "연결 실패"));
|
||||
}
|
||||
|
||||
// ── 쿼리 실행 ──────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* POST /api/external-db-connections/{id}/execute
|
||||
*/
|
||||
@PostMapping("/{id}/execute")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> executeQuery(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String sql = (String) body.get("query");
|
||||
if (sql == null || sql.isBlank()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("쿼리가 입력되지 않았습니다."));
|
||||
}
|
||||
try {
|
||||
Map<String, Object> result = service.executeQuery(id, sql);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> rows = (List<Map<String, Object>>) result.get("data");
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(rows, "쿼리가 성공적으로 실행되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 테이블 목록 ────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-db-connections/{id}/tables
|
||||
*/
|
||||
@GetMapping("/{id}/tables")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTables(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable long id) {
|
||||
try {
|
||||
List<Map<String, Object>> tables = service.getTables(id);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(tables, "테이블 목록을 조회했습니다."));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 테이블 컬럼 목록 ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/external-db-connections/{id}/tables/{tableName}/columns
|
||||
*/
|
||||
@GetMapping("/{id}/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableColumns(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable long id,
|
||||
@PathVariable String tableName) {
|
||||
if (tableName == null || tableName.isBlank()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("테이블명이 입력되지 않았습니다."));
|
||||
}
|
||||
try {
|
||||
List<Map<String, Object>> columns = service.getTableColumns(id, tableName);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(columns, "컬럼 정보를 조회했습니다."));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 내부 유틸 ──────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* company_code 필터 적용.
|
||||
* SUPER_ADMIN("*"): 쿼리 파라미터 company_code 우선, 없으면 전체 조회
|
||||
* 일반 사용자: 자사 코드 강제 적용
|
||||
*/
|
||||
private void buildFilter(Map<String, Object> params, String userCompanyCode, String queryCompanyCode) {
|
||||
if ("*".equals(userCompanyCode)) {
|
||||
// SUPER_ADMIN: query param이 있으면 그것, 없으면 전체(null → WHERE 없음)
|
||||
if (queryCompanyCode != null && !queryCompanyCode.isBlank()) {
|
||||
params.put("filterCompanyCode", queryCompanyCode);
|
||||
}
|
||||
// filterCompanyCode 없으면 전체 조회
|
||||
} else {
|
||||
// 일반 사용자: 강제 적용
|
||||
params.put("filterCompanyCode", userCompanyCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ExternalRestApiConnectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/external-rest-api-connections")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ExternalRestApiConnectionController {
|
||||
|
||||
private final ExternalRestApiConnectionService service;
|
||||
|
||||
// ── 목록 조회 ──────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getConnections(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
queryParams.put("companyCode", companyCode);
|
||||
List<Map<String, Object>> list = service.getExternalRestApiConnectionList(queryParams);
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(list, list.size() + "개의 REST API 연결을 조회했습니다."));
|
||||
}
|
||||
|
||||
// ── 단건 조회 ──────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getConnectionById(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
Map<String, Object> conn = service.getExternalRestApiConnectionInfo(params);
|
||||
if (conn == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("해당 REST API 연결을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(conn, "REST API 연결을 조회했습니다."));
|
||||
}
|
||||
|
||||
// ── 생성 ───────────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("createdBy", userId);
|
||||
try {
|
||||
Map<String, Object> created = service.insertExternalRestApiConnection(body);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "REST API 연결이 생성되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 수정 ───────────────────────────────────────────────────────────────────
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable int id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("updatedBy", userId);
|
||||
Map<String, Object> updated = service.updateExternalRestApiConnection(id, body);
|
||||
if (updated == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("해당 REST API 연결을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "REST API 연결이 수정되었습니다."));
|
||||
}
|
||||
|
||||
// ── 삭제 ───────────────────────────────────────────────────────────────────
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
boolean deleted = service.deleteExternalRestApiConnection(id, params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("해당 REST API 연결을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "REST API 연결이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
// ── 연결 테스트 (요청 데이터 기반) ──────────────────────────────────────────
|
||||
|
||||
@PostMapping("/test")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> testConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = service.testConnection(body, companyCode);
|
||||
boolean success = Boolean.TRUE.equals(result.get("success"));
|
||||
return ResponseEntity.ok(ApiResponse.success(result,
|
||||
success ? "연결 테스트 성공" : "연결 테스트 실패"));
|
||||
}
|
||||
|
||||
// ── 연결 테스트 (ID 기반) ───────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/{id}/test")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> testConnectionById(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
String endpoint = body != null ? (String) body.get("endpoint") : null;
|
||||
Map<String, Object> result = service.testConnectionById(id, endpoint);
|
||||
boolean success = Boolean.TRUE.equals(result.get("success"));
|
||||
return ResponseEntity.ok(ApiResponse.success(result,
|
||||
success ? "연결 테스트 성공" : "연결 테스트 실패"));
|
||||
}
|
||||
|
||||
// ── 데이터 조회 (프록시) ────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/{id}/fetch")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> fetchData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
Map<String, Object> params = body != null ? new HashMap<>(body) : new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
String endpoint = (String) params.get("endpoint");
|
||||
String jsonPath = (String) params.get("json_path");
|
||||
Map<String, Object> result = service.fetchData(id, endpoint, jsonPath, params);
|
||||
boolean success = Boolean.TRUE.equals(result.get("success"));
|
||||
if (!success) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(
|
||||
(String) result.getOrDefault("message", "데이터 조회 실패")));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.FileService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/files")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class FileController {
|
||||
|
||||
private final FileService fileService;
|
||||
|
||||
// ── 목록 조회 ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFileList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(fileService.getFileList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFileListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(fileService.getFileList(params)));
|
||||
}
|
||||
|
||||
// ── 파일 정보 (public) ────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/info/{objid}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFileInfo(
|
||||
@PathVariable Long objid) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("objid", objid);
|
||||
Map<String, Object> fileInfo = fileService.getFileInfoPublic(params);
|
||||
if (fileInfo == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("파일을 찾을 수 없습니다."));
|
||||
}
|
||||
// 공개 응답: 메타데이터만 반환
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("objid", fileInfo.get("objid"));
|
||||
result.put("realFileName", fileInfo.get("realFileName"));
|
||||
result.put("fileSize", fileInfo.get("fileSize"));
|
||||
result.put("fileExt", fileInfo.get("fileExt"));
|
||||
result.put("filePath", fileInfo.get("filePath"));
|
||||
result.put("regdate", fileInfo.get("regdate"));
|
||||
result.put("isRepresentative", fileInfo.get("isRepresentative"));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
// ── 타겟별 파일 목록 ─────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/linked/{tableName}/{recordId}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getLinkedFiles(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String recordId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("targetObjid", tableName + ":" + recordId);
|
||||
return ResponseEntity.ok(ApiResponse.success(fileService.getFilesByTarget(params)));
|
||||
}
|
||||
|
||||
// ── 업로드 ────────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/upload")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> uploadFiles(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestParam("file") List<MultipartFile> files,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
try {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId != null ? userId : "system");
|
||||
List<Map<String, Object>> results = fileService.uploadFiles(files, params);
|
||||
return ResponseEntity.ok(ApiResponse.success(results, "파일 업로드 완료"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
} catch (IOException e) {
|
||||
log.error("파일 업로드 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("파일 업로드 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 다운로드 ─────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/download/{objid}")
|
||||
public ResponseEntity<Resource> downloadFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long objid) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("objid", objid);
|
||||
Map<String, Object> fileInfo = fileService.getFileInfo(params);
|
||||
if (fileInfo == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
try {
|
||||
Path filePath = fileService.resolveFilePath(fileInfo);
|
||||
if (!Files.exists(filePath)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
String realFileName = (String) fileInfo.getOrDefault("realFileName", "download");
|
||||
String encodedName = URLEncoder.encode(realFileName, StandardCharsets.UTF_8)
|
||||
.replace("+", "%20");
|
||||
Resource resource = new FileSystemResource(filePath);
|
||||
String contentType = Files.probeContentType(filePath);
|
||||
if (contentType == null) contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedName)
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.body(resource);
|
||||
} catch (IOException e) {
|
||||
log.error("파일 다운로드 실패: objid={}", objid, e);
|
||||
return ResponseEntity.status(500).build();
|
||||
}
|
||||
}
|
||||
|
||||
// ── 미리보기 (public) ─────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/preview/{objid}")
|
||||
public ResponseEntity<Resource> previewFile(@PathVariable Long objid) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("objid", objid);
|
||||
Map<String, Object> fileInfo = fileService.getFileInfoPublic(params);
|
||||
if (fileInfo == null) return ResponseEntity.notFound().build();
|
||||
try {
|
||||
Path filePath = fileService.resolveFilePath(fileInfo);
|
||||
if (!Files.exists(filePath)) return ResponseEntity.notFound().build();
|
||||
String contentType = Files.probeContentType(filePath);
|
||||
if (contentType == null) contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||
Resource resource = new FileSystemResource(filePath);
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CACHE_CONTROL, "max-age=3600")
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.body(resource);
|
||||
} catch (IOException e) {
|
||||
log.error("파일 미리보기 실패: objid={}", objid, e);
|
||||
return ResponseEntity.status(500).build();
|
||||
}
|
||||
}
|
||||
|
||||
// ── 삭제 (소프트 삭제) ────────────────────────────────────────────────────
|
||||
|
||||
@DeleteMapping("/{objid}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long objid) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("objid", objid);
|
||||
fileService.deleteFile(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "파일이 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,558 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.FlowService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Flow API Controller
|
||||
* Base path: /api/flows
|
||||
*
|
||||
* Definitions : POST/GET/GET-detail/PUT/DELETE /definitions[/:id]
|
||||
* Steps : GET/POST /definitions/:flowId/steps
|
||||
* PUT/DELETE /steps/:stepId
|
||||
* Connections : GET /connections/:flowId
|
||||
* POST /connections
|
||||
* DELETE /connections/:connectionId
|
||||
* Execution : GET /:flowId/step/:stepId/count|list|column-labels
|
||||
* GET /:flowId/steps/counts
|
||||
* PUT /:flowId/step/:stepId/data/:recordId
|
||||
* Data move : POST /move, /move-batch
|
||||
* Audit : GET /audit/:flowId, /audit/:flowId/:recordId
|
||||
* Procedures : GET /procedures, /procedures/:name/parameters
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/flows")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class FlowController {
|
||||
|
||||
private final FlowService service;
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Definitions
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/definitions")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFlowDefinitionList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowDefinitionList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/definitions/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFlowDefinitionInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("id") int id) {
|
||||
Map<String, Object> detail = service.getFlowDefinitionInfo(id, companyCode);
|
||||
if (detail == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("Flow definition not found"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(detail));
|
||||
}
|
||||
|
||||
@PostMapping("/definitions")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertFlowDefinition(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("name") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("Name is required"));
|
||||
}
|
||||
|
||||
// 테이블 존재 확인 (REST API / multi 제외)
|
||||
String tableName = (String) body.get("tableName");
|
||||
String dbSource = (String) body.getOrDefault("dbSourceType", "internal");
|
||||
boolean skipCheck = "restapi".equals(dbSource)
|
||||
|| "multi_restapi".equals(dbSource)
|
||||
|| "multi_external_db".equals(dbSource)
|
||||
|| (tableName != null && (tableName.startsWith("_restapi_")
|
||||
|| tableName.startsWith("_multi_")));
|
||||
|
||||
if (tableName != null && !skipCheck && !service.checkTableExists(tableName)) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("Table '" + tableName + "' does not exist"));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> created = service.insertFlowDefinition(body, userId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(created));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 정의 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to create flow definition"));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/definitions/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateFlowDefinition(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("id") int id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (service.getFlowDefinitionById(id, companyCode) == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("Flow definition not found"));
|
||||
}
|
||||
try {
|
||||
Map<String, Object> updated = service.updateFlowDefinition(id, body, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(updated));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 정의 수정 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to update flow definition"));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/definitions/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteFlowDefinition(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("id") int id) {
|
||||
boolean deleted = service.deleteFlowDefinition(id, companyCode);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("Flow definition not found"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "Flow definition deleted successfully"));
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Steps (under /definitions/:flowId/steps or /steps/:stepId)
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/definitions/{flowId}/steps")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFlowStepList(
|
||||
@PathVariable("flowId") int flowId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowStepList(flowId)));
|
||||
}
|
||||
|
||||
@PostMapping("/definitions/{flowId}/steps")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertFlowStep(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("flowId") int flowId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("stepName") == null || body.get("stepOrder") == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("stepName and stepOrder are required"));
|
||||
}
|
||||
// 플로우 소유권 확인
|
||||
if (service.getFlowDefinitionById(flowId, companyCode) == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("Flow definition not found or access denied"));
|
||||
}
|
||||
try {
|
||||
Map<String, Object> step = service.insertFlowStep(flowId, body);
|
||||
return ResponseEntity.ok(ApiResponse.success(step));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 스텝 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to create flow step"));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/steps/{stepId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateFlowStep(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("stepId") int stepId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
// 스텝 소유권 검증: 스텝이 속한 플로우가 요청자 회사 소유인지 확인
|
||||
Map<String, Object> existingStep = service.getFlowStepById(stepId);
|
||||
if (existingStep != null) {
|
||||
int flowDefId = toInt(existingStep.get("flow_definition_id"), 0);
|
||||
if (service.getFlowDefinitionById(flowDefId, companyCode) == null) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("Access denied: flow does not belong to your company"));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> step = service.updateFlowStep(stepId, body);
|
||||
if (step == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("Flow step not found"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(step));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 스텝 수정 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to update flow step"));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/steps/{stepId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteFlowStep(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("stepId") int stepId) {
|
||||
|
||||
Map<String, Object> existingStep = service.getFlowStepById(stepId);
|
||||
if (existingStep != null) {
|
||||
int flowDefId = toInt(existingStep.get("flow_definition_id"), 0);
|
||||
if (service.getFlowDefinitionById(flowDefId, companyCode) == null) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("Access denied: flow does not belong to your company"));
|
||||
}
|
||||
}
|
||||
|
||||
boolean deleted = service.deleteFlowStep(stepId);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("Flow step not found"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "Flow step deleted successfully"));
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Connections
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/connections/{flowId}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFlowConnectionList(
|
||||
@PathVariable("flowId") int flowId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowConnectionList(flowId)));
|
||||
}
|
||||
|
||||
@PostMapping("/connections")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertFlowConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object flowDefIdRaw = body.get("flowDefinitionId");
|
||||
Object fromRaw = body.get("fromStepId");
|
||||
Object toRaw = body.get("toStepId");
|
||||
|
||||
if (flowDefIdRaw == null || fromRaw == null || toRaw == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("flowDefinitionId, fromStepId, and toStepId are required"));
|
||||
}
|
||||
|
||||
int flowDefId = toInt(flowDefIdRaw, 0);
|
||||
int fromStepId = toInt(fromRaw, 0);
|
||||
int toStepId = toInt(toRaw, 0);
|
||||
|
||||
// 플로우 소유권 확인
|
||||
if (service.getFlowDefinitionById(flowDefId, companyCode) == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("Flow definition not found or access denied"));
|
||||
}
|
||||
// 스텝 소속 검증
|
||||
Map<String, Object> fromStep = service.getFlowStepById(fromStepId);
|
||||
Map<String, Object> toStep = service.getFlowStepById(toStepId);
|
||||
if (fromStep == null || !String.valueOf(fromStep.get("flow_definition_id")).equals(String.valueOf(flowDefId))
|
||||
|| toStep == null || !String.valueOf(toStep.get("flow_definition_id")).equals(String.valueOf(flowDefId))) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("fromStepId and toStepId must belong to the specified flow"));
|
||||
}
|
||||
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.insertFlowConnection(body)));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 연결 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to create connection"));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/connections/{connectionId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteFlowConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("connectionId") int connectionId) {
|
||||
|
||||
Map<String, Object> existingConn = service.getFlowConnectionById(connectionId);
|
||||
if (existingConn != null) {
|
||||
int flowDefId = toInt(existingConn.get("flow_definition_id"), 0);
|
||||
if (service.getFlowDefinitionById(flowDefId, companyCode) == null) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("Access denied: flow does not belong to your company"));
|
||||
}
|
||||
}
|
||||
boolean deleted = service.deleteFlowConnection(connectionId);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("Connection not found"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "Connection deleted successfully"));
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Execution
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/{flowId}/step/{stepId}/count")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFlowStepDataCount(
|
||||
@PathVariable("flowId") int flowId,
|
||||
@PathVariable("stepId") int stepId) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowStepDataCount(flowId, stepId)));
|
||||
} catch (Exception e) {
|
||||
log.error("스텝 카운트 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to get step data count"));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{flowId}/step/{stepId}/list")
|
||||
public ResponseEntity<ApiResponse<Object>> getFlowStepDataList(
|
||||
@PathVariable("flowId") int flowId,
|
||||
@PathVariable("stepId") int stepId,
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "20") int pageSize) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
service.getFlowStepDataList(flowId, stepId, page, pageSize)));
|
||||
} catch (Exception e) {
|
||||
log.error("스텝 데이터 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to get step data list"));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{flowId}/step/{stepId}/column-labels")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFlowColumnLabelList(
|
||||
@PathVariable("flowId") int flowId,
|
||||
@PathVariable("stepId") int stepId) {
|
||||
try {
|
||||
Map<String, Object> step = service.getFlowStepById(stepId);
|
||||
if (step == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("Step not found"));
|
||||
}
|
||||
Map<String, Object> flow = service.getFlowDefinitionById(flowId, "*");
|
||||
if (flow == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("Flow definition not found"));
|
||||
}
|
||||
Map<String, Object> labels = service.getFlowColumnLabelList(flowId, stepId);
|
||||
return ResponseEntity.ok(ApiResponse.success(labels != null ? labels : Map.of()));
|
||||
} catch (Exception e) {
|
||||
log.error("컬럼 라벨 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to get step column labels"));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{flowId}/steps/counts")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFlowStepCountList(
|
||||
@PathVariable("flowId") int flowId) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowStepCountList(flowId)));
|
||||
} catch (Exception e) {
|
||||
log.error("전체 스텝 카운트 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to get all step counts"));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{flowId}/step/{stepId}/data/{recordId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateFlowStepData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("flowId") int flowId,
|
||||
@PathVariable("stepId") int stepId,
|
||||
@PathVariable("recordId") String recordId,
|
||||
@RequestBody Map<String, Object> updateData) {
|
||||
|
||||
if (updateData == null || updateData.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("Update data is required"));
|
||||
}
|
||||
try {
|
||||
Map<String, Object> result =
|
||||
service.updateFlowStepData(flowId, stepId, recordId, updateData, userId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "Data updated successfully"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("스텝 데이터 수정 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to update step data"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Data Move
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
@PostMapping("/move")
|
||||
public ResponseEntity<ApiResponse<Void>> moveData(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object flowId = body.get("flowId");
|
||||
Object fromStepId = body.get("fromStepId");
|
||||
Object recordId = body.get("recordId");
|
||||
Object toStepId = body.get("toStepId");
|
||||
|
||||
if (flowId == null || fromStepId == null || recordId == null || toStepId == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("flowId, fromStepId, recordId, and toStepId are required"));
|
||||
}
|
||||
try {
|
||||
service.moveDataToStep(
|
||||
toInt(flowId, 0), toInt(fromStepId, 0), toInt(toStepId, 0),
|
||||
recordId.toString(), userId, (String) body.get("note"));
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "Data moved successfully"));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 이동 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to move data"));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/move-batch")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> moveBatchData(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object flowId = body.get("flowId");
|
||||
Object fromStepId = body.get("fromStepId");
|
||||
Object toStepId = body.get("toStepId");
|
||||
Object dataIds = body.get("dataIds");
|
||||
|
||||
if (flowId == null || fromStepId == null || toStepId == null
|
||||
|| !(dataIds instanceof List)) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error(
|
||||
"flowId, fromStepId, toStepId, and dataIds (array) are required"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> ids = (List<Object>) dataIds;
|
||||
|
||||
try {
|
||||
Map<String, Object> result = service.moveBatchData(
|
||||
toInt(flowId, 0), toInt(fromStepId, 0), toInt(toStepId, 0), ids, userId);
|
||||
|
||||
long successCount = ids.stream()
|
||||
.filter(id -> result.get("results") instanceof List<?> list
|
||||
&& list.stream().anyMatch(r ->
|
||||
r instanceof Map<?, ?> m
|
||||
&& Boolean.TRUE.equals(m.get("success"))
|
||||
&& id.toString().equals(String.valueOf(m.get("id")))))
|
||||
.count();
|
||||
long failureCount = ids.size() - successCount;
|
||||
|
||||
boolean overallSuccess = (boolean) result.get("success");
|
||||
String message = overallSuccess
|
||||
? successCount + "건의 데이터를 성공적으로 이동했습니다"
|
||||
: successCount + "건 성공, " + failureCount + "건 실패";
|
||||
|
||||
Map<String, Object> data = new java.util.LinkedHashMap<>();
|
||||
data.put("successCount", successCount);
|
||||
data.put("failureCount", failureCount);
|
||||
data.put("total", ids.size());
|
||||
result.put("message", message);
|
||||
result.put("data", data);
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("배치 데이터 이동 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to move batch data"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Audit Logs
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /audit/:flowId — 플로우 전체 이력 */
|
||||
@GetMapping("/audit/{flowId}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFlowAuditLogList(
|
||||
@PathVariable("flowId") int flowId,
|
||||
@RequestParam(defaultValue = "100") int limit) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowAuditLogList(flowId, limit)));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 감사 로그 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to get flow audit logs"));
|
||||
}
|
||||
}
|
||||
|
||||
/** GET /audit/:flowId/:recordId — 특정 레코드 이력 */
|
||||
@GetMapping("/audit/{flowId}/{recordId}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFlowAuditLogListByRecord(
|
||||
@PathVariable("flowId") int flowId,
|
||||
@PathVariable("recordId") String recordId) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowAuditLogListByRecord(flowId, recordId)));
|
||||
} catch (Exception e) {
|
||||
log.error("감사 로그 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "Failed to get audit logs"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Procedures
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/procedures")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFlowProcedureList(
|
||||
@RequestParam(required = false) String dbSource,
|
||||
@RequestParam(required = false) Integer connectionId,
|
||||
@RequestParam(required = false) String schema) {
|
||||
|
||||
if (dbSource != null && !"internal".equals(dbSource) && !"external".equals(dbSource)) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("dbSource는 internal 또는 external이어야 합니다"));
|
||||
}
|
||||
if ("external".equals(dbSource) && connectionId == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("외부 DB 조회 시 connectionId가 필요합니다"));
|
||||
}
|
||||
|
||||
try {
|
||||
// 현재 구현은 internal DB만 지원 (external은 별도 연결 관리가 필요)
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowProcedureList(schema)));
|
||||
} catch (Exception e) {
|
||||
log.error("프로시저 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "프로시저 목록 조회에 실패했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/procedures/{name}/parameters")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFlowProcedureParameterList(
|
||||
@PathVariable("name") String name,
|
||||
@RequestParam(required = false) String dbSource,
|
||||
@RequestParam(required = false) Integer connectionId,
|
||||
@RequestParam(required = false) String schema) {
|
||||
|
||||
if (name == null || name.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("프로시저 이름이 필요합니다"));
|
||||
}
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
service.getFlowProcedureParameterList(name, schema)));
|
||||
} catch (Exception e) {
|
||||
log.error("프로시저 파라미터 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error(e.getMessage() != null ? e.getMessage()
|
||||
: "프로시저 파라미터 조회에 실패했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ── private helper ────────────────────────────────────────
|
||||
private int toInt(Object val, int defaultVal) {
|
||||
if (val == null) return defaultVal;
|
||||
try { return Integer.parseInt(val.toString()); }
|
||||
catch (NumberFormatException e) { return defaultVal; }
|
||||
}
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.FlowExternalDbConnectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 플로우 전용 외부 DB 연결 컨트롤러
|
||||
*
|
||||
* GET /api/flow-external-db - 목록 (?activeOnly=true)
|
||||
* GET /api/flow-external-db/{id} - 단건
|
||||
* POST /api/flow-external-db - 생성
|
||||
* PUT /api/flow-external-db/{id} - 수정
|
||||
* DELETE /api/flow-external-db/{id} - 삭제
|
||||
* POST /api/flow-external-db/{id}/test - 연결 테스트
|
||||
* GET /api/flow-external-db/{id}/tables - 테이블 목록
|
||||
* GET /api/flow-external-db/{id}/tables/{tableName}/columns - 컬럼 목록
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/flow-external-db")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class FlowExternalDbConnectionController {
|
||||
|
||||
private final FlowExternalDbConnectionService service;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAll(
|
||||
@RequestAttribute(value = "companyCode", required = false) String companyCode,
|
||||
@RequestParam(required = false, defaultValue = "false") String activeOnly) {
|
||||
try {
|
||||
boolean active = "true".equalsIgnoreCase(activeOnly);
|
||||
List<Map<String, Object>> connections = service.findAll(active);
|
||||
return ResponseEntity.ok(ApiResponse.success(connections,
|
||||
connections.size() + "개의 외부 DB 연결을 조회했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 연결 목록 조회 오류", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("외부 DB 연결 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getById(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id) {
|
||||
try {
|
||||
Map<String, Object> conn = service.findById(id);
|
||||
if (conn == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("외부 DB 연결을 찾을 수 없습니다"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(conn));
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 연결 조회 오류: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("외부 DB 연결 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> create(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
// 필수 필드 검증
|
||||
if (isBlank(body, "name") || isBlank(body, "dbType") || isBlank(body, "db_type") && isBlank(body, "dbType")
|
||||
|| isBlank(body, "host") || body.get("port") == null
|
||||
|| isBlank(body, "databaseName") && isBlank(body, "database_name")
|
||||
|| isBlank(body, "username") || isBlank(body, "password")) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다"));
|
||||
}
|
||||
try {
|
||||
String userId = companyCode != null ? companyCode : "system";
|
||||
Map<String, Object> conn = service.create(body, userId);
|
||||
log.info("외부 DB 연결 생성: {}", conn.get("name"));
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(conn, "외부 DB 연결이 생성되었습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 연결 생성 오류", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("외부 DB 연결 생성 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> update(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
String userId = companyCode != null ? companyCode : "system";
|
||||
Map<String, Object> conn = service.update(id, body, userId);
|
||||
if (conn == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("외부 DB 연결을 찾을 수 없습니다"));
|
||||
}
|
||||
log.info("외부 DB 연결 수정: id={}, name={}", id, conn.get("name"));
|
||||
return ResponseEntity.ok(ApiResponse.success(conn, "외부 DB 연결이 수정되었습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 연결 수정 오류: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("외부 DB 연결 수정 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> delete(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id) {
|
||||
try {
|
||||
boolean deleted = service.delete(id);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("외부 DB 연결을 찾을 수 없습니다"));
|
||||
}
|
||||
log.info("외부 DB 연결 삭제: id={}", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "외부 DB 연결이 삭제되었습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 연결 삭제 오류: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("외부 DB 연결 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/test")
|
||||
public ResponseEntity<ApiResponse<Void>> testConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id) {
|
||||
try {
|
||||
Map<String, Object> result = service.testConnection(id);
|
||||
boolean success = Boolean.TRUE.equals(result.get("success"));
|
||||
String message = (String) result.get("message");
|
||||
if (success) {
|
||||
log.info("외부 DB 연결 테스트 성공: id={}", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, message));
|
||||
} else {
|
||||
log.warn("외부 DB 연결 테스트 실패: id={}, msg={}", id, message);
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(message));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 연결 테스트 오류: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("외부 DB 연결 테스트 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/tables")
|
||||
public ResponseEntity<?> getTables(
|
||||
@RequestAttribute(value = "companyCode", required = false) String companyCode,
|
||||
@PathVariable int id) {
|
||||
try {
|
||||
Map<String, Object> result = service.getTables(id);
|
||||
if (Boolean.TRUE.equals(result.get("success"))) {
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
return ResponseEntity.status(400).body(result);
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 테이블 목록 조회 오류: id={}", id, e);
|
||||
return ResponseEntity.status(500).body(Map.of(
|
||||
"success", false, "message", "외부 DB 테이블 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/tables/{tableName}/columns")
|
||||
public ResponseEntity<?> getTableColumns(
|
||||
@RequestAttribute(value = "companyCode", required = false) String companyCode,
|
||||
@PathVariable int id,
|
||||
@PathVariable String tableName) {
|
||||
try {
|
||||
Map<String, Object> result = service.getTableColumns(id, tableName);
|
||||
if (Boolean.TRUE.equals(result.get("success"))) {
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
return ResponseEntity.status(400).body(result);
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 컬럼 목록 조회 오류: id={}, table={}", id, tableName, e);
|
||||
return ResponseEntity.status(500).body(Map.of(
|
||||
"success", false, "message", "외부 DB 컬럼 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ── 유효성 헬퍼 ───────────────────────────────────────────────
|
||||
|
||||
private boolean isBlank(Map<String, Object> body, String key) {
|
||||
Object v = body.get(key);
|
||||
return v == null || v.toString().isBlank();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.LayoutService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/layouts")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class LayoutController {
|
||||
|
||||
private final LayoutService layoutService;
|
||||
|
||||
/**
|
||||
* GET /api/layouts
|
||||
* 레이아웃 목록 조회
|
||||
* @param params page, size, category, layoutType, searchTerm, includePublic
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLayouts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(layoutService.getLayouts(params)));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/layouts/counts-by-category
|
||||
* 카테고리별 레이아웃 개수 조회
|
||||
* ※ /{id} 보다 먼저 선언해야 Spring MVC 가 정확히 매핑함
|
||||
*/
|
||||
@GetMapping("/counts-by-category")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLayoutCountsByCategory(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
layoutService.getLayoutCountsByCategory(companyCode)));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/layouts/:id
|
||||
* 레이아웃 상세 조회
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLayoutById(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("id") String layoutCode) {
|
||||
Map<String, Object> layout = layoutService.getLayoutById(layoutCode, companyCode);
|
||||
if (layout == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("레이아웃을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(layout));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/layouts
|
||||
* 레이아웃 생성
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createLayout(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("layoutName") == null || body.get("layoutType") == null || body.get("category") == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("필수 필드가 누락되었습니다. (layoutName, layoutType, category)"));
|
||||
}
|
||||
if (body.get("layoutConfig") == null || body.get("zonesConfig") == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("레이아웃 설정과 존 설정은 필수입니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> created = layoutService.createLayout(body, companyCode, userId);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "레이아웃이 성공적으로 생성되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("레이아웃 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("레이아웃 생성에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/layouts/:id
|
||||
* 레이아웃 수정
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateLayout(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") String layoutCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
try {
|
||||
Map<String, Object> updated = layoutService.updateLayout(layoutCode, body, companyCode, userId);
|
||||
if (updated == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("레이아웃을 찾을 수 없거나 수정 권한이 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "레이아웃이 성공적으로 수정되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("레이아웃 수정 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("레이아웃 수정에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/layouts/:id
|
||||
* 레이아웃 삭제 (소프트)
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteLayout(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") String layoutCode) {
|
||||
|
||||
try {
|
||||
layoutService.deleteLayout(layoutCode, companyCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "레이아웃이 성공적으로 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("레이아웃 삭제 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("레이아웃 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/layouts/:id/duplicate
|
||||
* 레이아웃 복제
|
||||
*/
|
||||
@PostMapping("/{id}/duplicate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> duplicateLayout(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") String layoutCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String newName = (String) body.get("newName");
|
||||
if (newName == null || newName.isBlank()) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("새 레이아웃 이름이 필요합니다."));
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> duplicated = layoutService.duplicateLayout(
|
||||
layoutCode, newName, companyCode, userId);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(duplicated, "레이아웃이 성공적으로 복제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("레이아웃 복제 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("레이아웃 복제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MailAccountFileService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mail-account-file")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MailAccountFileController {
|
||||
private final MailAccountFileService mailAccountFileService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailAccountFileList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailAccountFileService.getMailAccountFileList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailAccountFileInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailAccountFileService.getMailAccountFileInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertMailAccountFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailAccountFileService.insertMailAccountFile(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateMailAccountFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailAccountFileService.updateMailAccountFile(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteMailAccountFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailAccountFileService.deleteMailAccountFile(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MailReceiveBasicService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mail-receive-basic")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MailReceiveBasicController {
|
||||
private final MailReceiveBasicService mailReceiveBasicService;
|
||||
|
||||
/** GET /today-count → 오늘 수신 메일 수 */
|
||||
@GetMapping("/today-count")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailReceiveBasicTodayCount(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
int count = mailReceiveBasicService.getMailReceiveBasicTodayCount(params);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("count", count);
|
||||
return ResponseEntity.ok(ApiResponse.success(data));
|
||||
}
|
||||
|
||||
/** GET /{accountId}/{seqno}/attachment/{index} → 첨부파일 다운로드 */
|
||||
@GetMapping("/{accountId}/{seqno}/attachment/{index}")
|
||||
public ResponseEntity<byte[]> downloadMailReceiveBasicAttachment(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long accountId,
|
||||
@PathVariable String seqno,
|
||||
@PathVariable int index) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("accountId", accountId);
|
||||
params.put("seqno", seqno);
|
||||
params.put("attachIndex", index);
|
||||
Map<String, Object> attachment = mailReceiveBasicService.getMailReceiveBasicAttachment(params);
|
||||
if (attachment == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
byte[] data = (byte[]) attachment.get("contentData");
|
||||
String fileName = (String) attachment.getOrDefault("fileName", "attachment");
|
||||
String contentType = (String) attachment.getOrDefault("contentType", "application/octet-stream");
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.body(data);
|
||||
}
|
||||
|
||||
/** POST /{accountId}/{seqno}/mark-read → 메일 읽음 처리 */
|
||||
@PostMapping("/{accountId}/{seqno}/mark-read")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> markMailReceiveBasicAsRead(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long accountId,
|
||||
@PathVariable String seqno) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("accountId", accountId);
|
||||
params.put("seqno", seqno);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailReceiveBasicService.markMailReceiveBasicAsRead(params)));
|
||||
}
|
||||
|
||||
/** DELETE /{accountId}/{seqno} → 메일 삭제 */
|
||||
@DeleteMapping("/{accountId}/{seqno}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteMailReceiveBasic(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long accountId,
|
||||
@PathVariable String seqno) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("accountId", accountId);
|
||||
params.put("seqno", seqno);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailReceiveBasicService.deleteMailReceiveBasic(params)));
|
||||
}
|
||||
|
||||
/** GET /{accountId}/{seqno} → 메일 상세 조회 */
|
||||
@GetMapping("/{accountId}/{seqno}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailReceiveBasicInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long accountId,
|
||||
@PathVariable String seqno) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("accountId", accountId);
|
||||
params.put("seqno", seqno);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailReceiveBasicService.getMailReceiveBasicInfo(params)));
|
||||
}
|
||||
|
||||
/** POST /{accountId}/test-imap → IMAP 연결 테스트 */
|
||||
@PostMapping("/{accountId}/test-imap")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> testMailReceiveBasicImapConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long accountId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("accountId", accountId);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailReceiveBasicService.testMailReceiveBasicImapConnection(params)));
|
||||
}
|
||||
|
||||
/** GET /{accountId} → 메일 목록 조회 */
|
||||
@GetMapping("/{accountId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailReceiveBasicList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long accountId,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("accountId", accountId);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailReceiveBasicService.getMailReceiveBasicList(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MailSendSimpleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 메일 발송 API
|
||||
* Node.js: app.use("/api/mail/send", mailSendSimpleRoutes)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/mail/send")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MailSendSimpleController {
|
||||
|
||||
private final MailSendSimpleService mailSendSimpleService;
|
||||
|
||||
/**
|
||||
* POST /api/mail/send/simple — 단건 메일 발송 (첨부파일 지원)
|
||||
* multipart/form-data: accountId, to(JSON), cc(JSON), bcc(JSON),
|
||||
* subject, templateId, customHtml, variables(JSON),
|
||||
* modifiedTemplateComponents(JSON), fileNames(JSON), attachments[]
|
||||
*/
|
||||
@PostMapping(value = "/simple",
|
||||
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> sendMail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam(required = false) String accountId,
|
||||
@RequestParam(required = false) String templateId,
|
||||
@RequestParam(required = false) String modifiedTemplateComponents,
|
||||
@RequestParam(required = false) String to,
|
||||
@RequestParam(required = false) String cc,
|
||||
@RequestParam(required = false) String bcc,
|
||||
@RequestParam(required = false) String subject,
|
||||
@RequestParam(required = false) String variables,
|
||||
@RequestParam(required = false) String customHtml,
|
||||
@RequestParam(required = false) String fileNames,
|
||||
@RequestPart(value = "attachments", required = false) List<MultipartFile> attachments) {
|
||||
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("accountId", accountId);
|
||||
params.put("templateId", templateId);
|
||||
params.put("modifiedTemplateComponents", modifiedTemplateComponents);
|
||||
params.put("to", to);
|
||||
params.put("cc", cc);
|
||||
params.put("bcc", bcc);
|
||||
params.put("subject", subject);
|
||||
params.put("variables", variables);
|
||||
params.put("customHtml", customHtml);
|
||||
params.put("fileNames", fileNames);
|
||||
params.put("attachments", attachments);
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
mailSendSimpleService.sendMail(params), "메일이 발송되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/mail/send/bulk — 대량 메일 발송
|
||||
* Body: { accountId, subject, templateId?, customHtml?,
|
||||
* recipients: [{ email, variables? }] }
|
||||
*/
|
||||
@PostMapping("/bulk")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> sendBulkMail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
body.put("companyCode", companyCode);
|
||||
Map<String, Object> result = mailSendSimpleService.sendBulkMail(body);
|
||||
int successCount = ((Number) result.getOrDefault("success", 0)).intValue();
|
||||
int total = ((Number) result.getOrDefault("total", 0)).intValue();
|
||||
return ResponseEntity.ok(ApiResponse.success(result,
|
||||
successCount + "/" + total + " 건 발송 완료"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/mail/send/test-connection — SMTP 연결 테스트
|
||||
* Body: { accountId }
|
||||
*/
|
||||
@PostMapping("/test-connection")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> testConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
mailSendSimpleService.testConnection(body)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MailSentHistoryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mail-sent-history")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MailSentHistoryController {
|
||||
private final MailSentHistoryService mailSentHistoryService;
|
||||
|
||||
// GET /statistics — /{id} 보다 먼저 정의해야 매핑 우선순위 확보
|
||||
@GetMapping("/statistics")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailSentHistoryStatistics(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailSentHistoryService.getMailSentHistoryStatistics(params)));
|
||||
}
|
||||
|
||||
// GET / — 목록 조회 (페이지네이션)
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailSentHistoryList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailSentHistoryService.getMailSentHistoryList(params)));
|
||||
}
|
||||
|
||||
// POST /draft — 임시 저장
|
||||
@PostMapping("/draft")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveMailSentHistoryDraft(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
mailSentHistoryService.saveMailSentHistoryDraft(body), "임시 저장되었습니다."));
|
||||
}
|
||||
|
||||
// PUT /draft/{id} — 임시 저장 업데이트
|
||||
@PutMapping("/draft/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateMailSentHistoryDraft(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
mailSentHistoryService.updateMailSentHistoryDraft(body), "임시 저장이 업데이트되었습니다."));
|
||||
}
|
||||
|
||||
// POST /bulk/delete — 일괄 소프트 삭제
|
||||
@PostMapping("/bulk/delete")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> bulkDeleteMailSentHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailSentHistoryService.bulkDeleteMailSentHistory(body)));
|
||||
}
|
||||
|
||||
// POST /bulk/permanent-delete — 일괄 영구 삭제
|
||||
@PostMapping("/bulk/permanent-delete")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> bulkPermanentDeleteMailSentHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailSentHistoryService.bulkPermanentDeleteMailSentHistory(body)));
|
||||
}
|
||||
|
||||
// POST /bulk/restore — 일괄 복구
|
||||
@PostMapping("/bulk/restore")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> bulkRestoreMailSentHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailSentHistoryService.bulkRestoreMailSentHistory(body)));
|
||||
}
|
||||
|
||||
// POST /{id}/restore — 메일 복구
|
||||
@PostMapping("/{id}/restore")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> restoreMailSentHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
mailSentHistoryService.restoreMailSentHistory(params), "메일이 복구되었습니다."));
|
||||
}
|
||||
|
||||
// DELETE /{id}/permanent — 영구 삭제
|
||||
@DeleteMapping("/{id}/permanent")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> permanentlyDeleteMailSentHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
mailSentHistoryService.permanentlyDeleteMailSentHistory(params), "메일이 영구 삭제되었습니다."));
|
||||
}
|
||||
|
||||
// GET /{id} — 단건 조회
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailSentHistoryInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailSentHistoryService.getMailSentHistoryInfo(params)));
|
||||
}
|
||||
|
||||
// DELETE /{id} — 소프트 삭제
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteMailSentHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
mailSentHistoryService.deleteMailSentHistory(params), "발송 이력이 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MailTemplateFileService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mail-template-file")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MailTemplateFileController {
|
||||
private final MailTemplateFileService mailTemplateFileService;
|
||||
|
||||
/** GET /list → 템플릿 목록 조회 (alias) */
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailTemplateFileListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailTemplateFileService.getMailTemplateFileList(params)));
|
||||
}
|
||||
|
||||
/** GET / → 템플릿 목록 조회 */
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailTemplateFileList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailTemplateFileService.getMailTemplateFileList(params)));
|
||||
}
|
||||
|
||||
/** GET /{id} → 템플릿 상세 조회 */
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMailTemplateFileInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailTemplateFileService.getMailTemplateFileInfo(params)));
|
||||
}
|
||||
|
||||
/** POST / → 템플릿 생성 */
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertMailTemplateFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailTemplateFileService.insertMailTemplateFile(body)));
|
||||
}
|
||||
|
||||
/** PUT /{id} → 템플릿 수정 */
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateMailTemplateFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailTemplateFileService.updateMailTemplateFile(body)));
|
||||
}
|
||||
|
||||
/** DELETE /{id} → 템플릿 삭제 */
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteMailTemplateFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(mailTemplateFileService.deleteMailTemplateFile(params)));
|
||||
}
|
||||
|
||||
/** POST /{id}/preview → 템플릿 HTML 미리보기 */
|
||||
@PostMapping("/{id}/preview")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewMailTemplateFile(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
Map<String, Object> result = mailTemplateFileService.previewMailTemplateFile(body);
|
||||
if (result.isEmpty()) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("템플릿을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
/** POST /{id}/preview-with-query → 쿼리 연동 미리보기 (미지원) */
|
||||
@PostMapping("/{id}/preview-with-query")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewMailTemplateFileWithQuery(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
return ResponseEntity.status(501).body(ApiResponse.error("SQL 쿼리 연동 기능은 현재 지원하지 않습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MapDataService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/map-data")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MapDataController {
|
||||
|
||||
private final MapDataService mapDataService;
|
||||
|
||||
/**
|
||||
* 외부 DB에서 지도 데이터 조회
|
||||
* GET /api/map-data/external/:connectionId
|
||||
* query params: tableName(필수), latColumn(필수), lngColumn(필수),
|
||||
* labelColumn, statusColumn, additionalColumns(쉼표구분), whereClause
|
||||
*/
|
||||
@GetMapping("/external/{connectionId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getExternalMapData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long connectionId,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
String tableName = (String) params.get("tableName");
|
||||
String latColumn = (String) params.get("latColumn");
|
||||
String lngColumn = (String) params.get("lngColumn");
|
||||
|
||||
if (tableName == null || tableName.isBlank()
|
||||
|| latColumn == null || latColumn.isBlank()
|
||||
|| lngColumn == null || lngColumn.isBlank()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("tableName, latColumn, lngColumn은 필수입니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> data = mapDataService.getExternalMapData(connectionId, params);
|
||||
return ResponseEntity.ok(ApiResponse.success(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 내부 DB에서 지도 데이터 조회
|
||||
* GET /api/map-data/internal
|
||||
* query params: tableName(필수), latColumn(필수), lngColumn(필수),
|
||||
* labelColumn, statusColumn, additionalColumns(쉼표구분), whereClause
|
||||
*/
|
||||
@GetMapping("/internal")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getInternalMapData(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
String tableName = (String) params.get("tableName");
|
||||
String latColumn = (String) params.get("latColumn");
|
||||
String lngColumn = (String) params.get("lngColumn");
|
||||
|
||||
if (tableName == null || tableName.isBlank()
|
||||
|| latColumn == null || latColumn.isBlank()
|
||||
|| lngColumn == null || lngColumn.isBlank()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("tableName, latColumn, lngColumn은 필수입니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> data = mapDataService.getInternalMapData(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MoldService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mold")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MoldController {
|
||||
|
||||
private final MoldService moldService;
|
||||
|
||||
// ── 금형 마스터 ───────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMoldList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.getMoldList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMoldListAlias(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.getMoldList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{moldCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMoldDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String moldCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("moldCode", moldCode);
|
||||
Map<String, Object> result = moldService.getMoldInfo(params);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("금형을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createMold(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("writer", userId);
|
||||
if (body.get("moldCode") == null || body.get("moldName") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("금형코드와 금형명은 필수입니다."));
|
||||
}
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.insertMold(body), "금형이 등록되었습니다."));
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage() != null && e.getMessage().contains("unique")) {
|
||||
return ResponseEntity.status(409).body(ApiResponse.error("이미 존재하는 금형코드입니다."));
|
||||
}
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{moldCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateMold(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String moldCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("moldCode", moldCode);
|
||||
Map<String, Object> result = moldService.updateMold(body);
|
||||
if (result == null) return ResponseEntity.status(404).body(ApiResponse.error("금형을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "금형이 수정되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{moldCode}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteMold(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String moldCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("moldCode", moldCode);
|
||||
if (!moldService.deleteMold(params)) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("금형을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "금형이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
// ── 일련번호 ──────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{moldCode}/serials")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMoldSerials(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String moldCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("moldCode", moldCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.getMoldSerialList(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/{moldCode}/serials")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createMoldSerial(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable String moldCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("moldCode", moldCode);
|
||||
body.put("writer", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.insertMoldSerial(body), "일련번호가 등록되었습니다."));
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage() != null && e.getMessage().contains("unique")) {
|
||||
return ResponseEntity.status(409).body(ApiResponse.error("이미 존재하는 일련번호입니다."));
|
||||
}
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/serials/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteMoldSerial(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
if (!moldService.deleteMoldSerial(params)) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("일련번호를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "일련번호가 삭제되었습니다."));
|
||||
}
|
||||
|
||||
@GetMapping("/{moldCode}/serial-summary")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMoldSerialSummary(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String moldCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("moldCode", moldCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.getMoldSerialSummary(params)));
|
||||
}
|
||||
|
||||
// ── 점검항목 ──────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{moldCode}/inspections")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMoldInspections(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String moldCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("moldCode", moldCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.getMoldInspectionList(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/{moldCode}/inspections")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createMoldInspection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable String moldCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("moldCode", moldCode);
|
||||
body.put("writer", userId);
|
||||
if (body.get("inspectionItem") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("점검항목명은 필수입니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.insertMoldInspection(body), "점검항목이 등록되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/inspections/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteMoldInspection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
if (!moldService.deleteMoldInspection(params)) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("점검항목을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "점검항목이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
// ── 부품 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{moldCode}/parts")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMoldParts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String moldCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("moldCode", moldCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.getMoldPartList(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/{moldCode}/parts")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createMoldPart(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable String moldCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("moldCode", moldCode);
|
||||
body.put("writer", userId);
|
||||
if (body.get("partName") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("부품명은 필수입니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(moldService.insertMoldPart(body), "부품이 등록되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/parts/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteMoldPart(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
if (!moldService.deleteMoldPart(params)) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("부품을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "부품이 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MultiConnectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/multi-connection")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MultiConnectionController {
|
||||
|
||||
private final MultiConnectionService multiConnectionService;
|
||||
|
||||
/** GET /connections/:connectionId/tables */
|
||||
@GetMapping("/connections/{connectionId}/tables")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTablesFromConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int connectionId) {
|
||||
List<Map<String, Object>> tables = multiConnectionService.getTablesFromConnection(connectionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(tables,
|
||||
"커넥션 " + connectionId + "의 테이블 목록을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /connections/:connectionId/tables/batch */
|
||||
@GetMapping("/connections/{connectionId}/tables/batch")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getBatchTablesWithColumns(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int connectionId) {
|
||||
List<Map<String, Object>> tables = multiConnectionService.getBatchTablesWithColumns(connectionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(tables,
|
||||
"커넥션 " + connectionId + "의 테이블 정보를 배치 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /connections/:connectionId/tables/:tableName/columns */
|
||||
@GetMapping("/connections/{connectionId}/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getColumnsFromConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int connectionId,
|
||||
@PathVariable String tableName) {
|
||||
if (tableName == null || tableName.isBlank()) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("테이블명이 입력되지 않았습니다."));
|
||||
}
|
||||
List<Map<String, Object>> columns = multiConnectionService.getColumnsFromConnection(connectionId, tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(columns,
|
||||
"테이블 " + tableName + "의 컬럼 정보를 조회했습니다."));
|
||||
}
|
||||
|
||||
/** POST /connections/:connectionId/query */
|
||||
@PostMapping("/connections/{connectionId}/query")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> fetchDataFromConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int connectionId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("tableName") == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("테이블명이 입력되지 않았습니다."));
|
||||
}
|
||||
List<Map<String, Object>> data = multiConnectionService.fetchDataFromConnection(connectionId, body);
|
||||
return ResponseEntity.ok(ApiResponse.success(data,
|
||||
"데이터 조회가 완료되었습니다. (" + data.size() + "건)"));
|
||||
}
|
||||
|
||||
/** POST /connections/:connectionId/insert */
|
||||
@PostMapping("/connections/{connectionId}/insert")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertDataToConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int connectionId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("tableName") == null || body.get("data") == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("테이블명과 데이터가 필요합니다."));
|
||||
}
|
||||
Map<String, Object> result = multiConnectionService.insertDataToConnection(connectionId, body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "데이터 삽입이 완료되었습니다."));
|
||||
}
|
||||
|
||||
/** PUT /connections/:connectionId/update */
|
||||
@PutMapping("/connections/{connectionId}/update")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> updateDataToConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int connectionId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("tableName") == null || body.get("data") == null || body.get("conditions") == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("테이블명, 데이터, 조건이 모두 필요합니다."));
|
||||
}
|
||||
List<Map<String, Object>> result = multiConnectionService.updateDataToConnection(connectionId, body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result,
|
||||
"데이터 업데이트가 완료되었습니다. (" + result.size() + "건)"));
|
||||
}
|
||||
|
||||
/** DELETE /connections/:connectionId/delete */
|
||||
@DeleteMapping("/connections/{connectionId}/delete")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> deleteDataFromConnection(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int connectionId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("tableName") == null || body.get("conditions") == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("테이블명과 삭제 조건이 필요합니다."));
|
||||
}
|
||||
List<Map<String, Object>> result = multiConnectionService.deleteDataFromConnection(connectionId, body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result,
|
||||
"데이터 삭제가 완료되었습니다. (" + result.size() + "건)"));
|
||||
}
|
||||
|
||||
/** POST /validate-self-operation */
|
||||
@PostMapping("/validate-self-operation")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> validateSelfOperation(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("tableName") == null || body.get("operation") == null || body.get("conditions") == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("테이블명, 작업 타입, 조건이 모두 필요합니다."));
|
||||
}
|
||||
String op = body.get("operation").toString();
|
||||
if (!op.equals("update") && !op.equals("delete")) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("작업 타입은 'update' 또는 'delete'만 허용됩니다."));
|
||||
}
|
||||
Map<String, Object> result = multiConnectionService.validateSelfOperation(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "검증이 완료되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.MultilangService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/multilang")
|
||||
@RequiredArgsConstructor
|
||||
public class MultilangController {
|
||||
|
||||
private final MultilangService multilangService;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 배치 번역 (인증 불필요 — SecurityConfig에서 permitAll)
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/batch")
|
||||
public ResponseEntity<ApiResponse<Map<String, String>>> getBatchTranslations(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestParam(required = false) String companyCode,
|
||||
@RequestParam(required = false) String menuCode,
|
||||
@RequestParam(required = false) String userLang) {
|
||||
|
||||
String finalCompanyCode = companyCode != null ? companyCode : str(body.get("companyCode"));
|
||||
String finalMenuCode = menuCode != null ? menuCode : str(body.get("menuCode"));
|
||||
String finalUserLang = userLang != null ? userLang : str(body.get("userLang"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> langKeys = (List<String>) body.get("langKeys");
|
||||
|
||||
if (langKeys == null || langKeys.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("langKeys 배열이 필요합니다."));
|
||||
}
|
||||
if (finalCompanyCode.isEmpty() || finalUserLang.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("companyCode와 userLang은 필수입니다."));
|
||||
}
|
||||
|
||||
Map<String, String> translations =
|
||||
multilangService.getBatchTranslations(finalCompanyCode, finalMenuCode, finalUserLang, langKeys);
|
||||
return ResponseEntity.ok(ApiResponse.success(translations, "다국어 텍스트 배치 조회 성공"));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 언어 관리
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/languages")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getLanguages() {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
multilangService.getLanguages(), "언어 목록 조회 성공"));
|
||||
}
|
||||
|
||||
@PostMapping("/languages")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createLanguage(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String langCode = str(body.get("langCode"));
|
||||
String langName = str(body.get("langName"));
|
||||
String langNative = str(body.get("langNative"));
|
||||
|
||||
if (langCode.isEmpty() || langName.isEmpty() || langNative.isEmpty()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("언어 코드, 언어명, 원어명은 필수입니다."));
|
||||
}
|
||||
|
||||
String userId = str(body.getOrDefault("createdBy", "system"));
|
||||
body.put("createdBy", userId);
|
||||
body.put("updatedBy", userId);
|
||||
Map<String, Object> created = multilangService.createLanguage(body);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(created, "언어가 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/languages/{langCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateLanguage(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String langCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String userId = str(body.getOrDefault("updatedBy", "system"));
|
||||
body.put("updatedBy", userId);
|
||||
Map<String, Object> updated = multilangService.updateLanguage(langCode, body);
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "언어가 성공적으로 수정되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/languages/{langCode}")
|
||||
public ResponseEntity<ApiResponse<String>> deleteLanguage(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String langCode) {
|
||||
|
||||
multilangService.deleteLanguage(langCode);
|
||||
return ResponseEntity.ok(ApiResponse.success("삭제 완료", "언어가 성공적으로 삭제되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/languages/{langCode}/toggle")
|
||||
public ResponseEntity<ApiResponse<String>> toggleLanguage(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String langCode) {
|
||||
|
||||
String result = multilangService.toggleLanguage(langCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "언어가 " + result + "되었습니다."));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 다국어 키 관리
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/keys")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getLangKeys(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
List<Map<String, Object>> keys = multilangService.getLangKeys(new HashMap<>(params));
|
||||
return ResponseEntity.ok(ApiResponse.success(keys, "다국어 키 목록 조회 성공"));
|
||||
}
|
||||
|
||||
@GetMapping("/keys/{keyId}/texts")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getLangTexts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int keyId) {
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
multilangService.getLangTexts(keyId), "다국어 텍스트 조회 성공"));
|
||||
}
|
||||
|
||||
@PostMapping("/keys")
|
||||
public ResponseEntity<ApiResponse<Integer>> createLangKey(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (str(body.get("companyCode")).isEmpty() || str(body.get("langKey")).isEmpty()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("회사 코드와 언어 키는 필수입니다."));
|
||||
}
|
||||
|
||||
String userId = str(body.getOrDefault("createdBy", "system"));
|
||||
body.put("createdBy", userId);
|
||||
body.put("updatedBy", userId);
|
||||
int keyId = multilangService.createLangKey(body);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(keyId, "다국어 키가 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/keys/{keyId}")
|
||||
public ResponseEntity<ApiResponse<String>> updateLangKey(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int keyId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String userId = str(body.getOrDefault("updatedBy", "system"));
|
||||
body.put("updatedBy", userId);
|
||||
multilangService.updateLangKey(keyId, body);
|
||||
return ResponseEntity.ok(ApiResponse.success("수정 완료", "다국어 키가 성공적으로 수정되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/keys/{keyId}")
|
||||
public ResponseEntity<ApiResponse<String>> deleteLangKey(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int keyId) {
|
||||
|
||||
multilangService.deleteLangKey(keyId);
|
||||
return ResponseEntity.ok(ApiResponse.success("삭제 완료", "다국어 키가 성공적으로 삭제되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/keys/{keyId}/toggle")
|
||||
public ResponseEntity<ApiResponse<String>> toggleLangKey(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int keyId) {
|
||||
|
||||
String result = multilangService.toggleLangKey(keyId);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "다국어 키가 " + result + "되었습니다."));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 다국어 텍스트 관리
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/keys/{keyId}/texts")
|
||||
public ResponseEntity<ApiResponse<String>> saveLangTexts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int keyId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> texts = (List<Map<String, Object>>) body.get("texts");
|
||||
if (texts == null || texts.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("텍스트 데이터는 필수입니다."));
|
||||
}
|
||||
|
||||
String userId = str(body.getOrDefault("updatedBy", "system"));
|
||||
for (Map<String, Object> t : texts) {
|
||||
if (t.get("createdBy") == null) t.put("createdBy", userId);
|
||||
if (t.get("updatedBy") == null) t.put("updatedBy", userId);
|
||||
}
|
||||
multilangService.saveLangTexts(keyId, texts);
|
||||
return ResponseEntity.ok(ApiResponse.success("저장 완료", "다국어 텍스트가 성공적으로 저장되었습니다."));
|
||||
}
|
||||
|
||||
@GetMapping("/user-text/{companyCode}/{menuCode}/{langKey}")
|
||||
public ResponseEntity<ApiResponse<String>> getUserText(
|
||||
@PathVariable String companyCode,
|
||||
@PathVariable String menuCode,
|
||||
@PathVariable String langKey,
|
||||
@RequestParam(required = false) String userLang) {
|
||||
|
||||
if (userLang == null || userLang.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("사용자 언어는 필수입니다."));
|
||||
}
|
||||
String text = multilangService.getUserText(companyCode, menuCode, langKey, userLang);
|
||||
return ResponseEntity.ok(ApiResponse.success(text, "사용자별 다국어 텍스트 조회 성공"));
|
||||
}
|
||||
|
||||
@GetMapping("/text/{companyCode}/{langKey}/{langCode}")
|
||||
public ResponseEntity<ApiResponse<String>> getLangText(
|
||||
@PathVariable String companyCode,
|
||||
@PathVariable String langKey,
|
||||
@PathVariable String langCode) {
|
||||
|
||||
String text = multilangService.getLangText(companyCode, langKey, langCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(text, "특정 키의 다국어 텍스트 조회 성공"));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 카테고리 관리
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/categories")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategories(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
multilangService.getCategories(), "카테고리 목록 조회 성공"));
|
||||
}
|
||||
|
||||
@GetMapping("/categories/{categoryId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryById(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int categoryId) {
|
||||
|
||||
Map<String, Object> category = multilangService.getCategoryById(categoryId);
|
||||
if (category == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("카테고리를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(category, "카테고리 상세 조회 성공"));
|
||||
}
|
||||
|
||||
@GetMapping("/categories/{categoryId}/path")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryPath(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int categoryId) {
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
multilangService.getCategoryPath(categoryId), "카테고리 경로 조회 성공"));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 자동 생성 및 오버라이드
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/keys/generate")
|
||||
public ResponseEntity<ApiResponse<Integer>> generateKey(
|
||||
@RequestAttribute("companyCode") String requestCompanyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String targetCompanyCode = str(body.get("companyCode"));
|
||||
if (targetCompanyCode.isEmpty() || str(body.get("categoryId")).isEmpty()
|
||||
|| str(body.get("keyMeaning")).isEmpty()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("회사 코드, 카테고리 ID, 키 의미는 필수입니다."));
|
||||
}
|
||||
if ("*".equals(targetCompanyCode) && !"*".equals(requestCompanyCode)) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("공통 키는 최고 관리자만 생성할 수 있습니다."));
|
||||
}
|
||||
if (!"*".equals(targetCompanyCode) && !"*".equals(requestCompanyCode)
|
||||
&& !targetCompanyCode.equals(requestCompanyCode)) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("다른 회사의 키를 생성할 권한이 없습니다."));
|
||||
}
|
||||
|
||||
body.put("createdBy", body.getOrDefault("createdBy", "system"));
|
||||
int keyId = multilangService.generateKey(body);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(keyId, "키가 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
@PostMapping("/keys/preview")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewKey(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object categoryIdObj = body.get("categoryId");
|
||||
String keyMeaning = str(body.get("keyMeaning"));
|
||||
String targetCompanyCode = str(body.get("companyCode"));
|
||||
|
||||
if (categoryIdObj == null || keyMeaning.isEmpty() || targetCompanyCode.isEmpty()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("카테고리 ID, 키 의미, 회사 코드는 필수입니다."));
|
||||
}
|
||||
|
||||
int categoryId = toInt(categoryIdObj);
|
||||
Map<String, Object> preview = multilangService.previewKey(categoryId, keyMeaning, targetCompanyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(preview, "키 미리보기 성공"));
|
||||
}
|
||||
|
||||
@PostMapping("/keys/override")
|
||||
public ResponseEntity<ApiResponse<Integer>> createOverrideKey(
|
||||
@RequestAttribute("companyCode") String requestCompanyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String targetCompanyCode = str(body.get("companyCode"));
|
||||
if (targetCompanyCode.isEmpty() || body.get("baseKeyId") == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("회사 코드와 원본 키 ID는 필수입니다."));
|
||||
}
|
||||
if ("*".equals(targetCompanyCode)) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("공통 키에 대한 오버라이드는 생성할 수 없습니다."));
|
||||
}
|
||||
if (!"*".equals(requestCompanyCode) && !targetCompanyCode.equals(requestCompanyCode)) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("다른 회사의 오버라이드 키를 생성할 권한이 없습니다."));
|
||||
}
|
||||
|
||||
body.put("createdBy", body.getOrDefault("createdBy", "system"));
|
||||
int keyId = multilangService.createOverrideKey(body);
|
||||
return ResponseEntity.status(201)
|
||||
.body(ApiResponse.success(keyId, "오버라이드 키가 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
@GetMapping("/keys/overrides/{companyCode}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getOverrideKeys(
|
||||
@RequestAttribute("companyCode") String requestCompanyCode,
|
||||
@PathVariable String companyCode) {
|
||||
|
||||
if (!"*".equals(requestCompanyCode) && !companyCode.equals(requestCompanyCode)) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("다른 회사의 오버라이드 키를 조회할 권한이 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
multilangService.getOverrideKeys(companyCode), "오버라이드 키 목록 조회 성공"));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 화면 라벨 다국어 자동 생성
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/screen-labels")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> generateScreenLabelKeys(
|
||||
@RequestAttribute("companyCode") String requestCompanyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object screenIdObj = body.get("screenId");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> labels = (List<Map<String, Object>>) body.get("labels");
|
||||
|
||||
if (screenIdObj == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("screenId는 필수입니다."));
|
||||
}
|
||||
if (labels == null || labels.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("labels 배열이 필요합니다."));
|
||||
}
|
||||
|
||||
// companyCode, companyName이 body에 없으면 requestCompanyCode 사용
|
||||
if (!body.containsKey("companyCode") || str(body.get("companyCode")).isEmpty()) {
|
||||
body.put("companyCode", requestCompanyCode);
|
||||
}
|
||||
if (!body.containsKey("companyName") || str(body.get("companyName")).isEmpty()) {
|
||||
body.put("companyName", requestCompanyCode);
|
||||
}
|
||||
|
||||
body.put("screenId", toInt(screenIdObj));
|
||||
List<Map<String, Object>> results = multilangService.generateScreenLabelKeys(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
results, results.size() + "개의 다국어 키가 생성되었습니다."));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Private utilities
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private String str(Object o) {
|
||||
return o == null ? "" : o.toString();
|
||||
}
|
||||
|
||||
private int toInt(Object o) {
|
||||
if (o == null) return 0;
|
||||
if (o instanceof Number) return ((Number) o).intValue();
|
||||
try { return Integer.parseInt(o.toString()); } catch (NumberFormatException e) { return 0; }
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.NodeExternalConnectionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Node 플로우 전용 외부 DB 연결 컨트롤러
|
||||
*
|
||||
* Node.js dataflow/node-external-connections.ts 포팅.
|
||||
*
|
||||
* GET /api/dataflow/node-external-connections/tested — 테스트 성공 커넥션 목록
|
||||
* GET /api/dataflow/node-external-connections/{id}/tables — 외부 DB 테이블 목록
|
||||
* GET /api/dataflow/node-external-connections/{id}/tables/{tableName}/columns — 외부 DB 컬럼 목록
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/dataflow/node-external-connections")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class NodeExternalConnectionController {
|
||||
|
||||
private final NodeExternalConnectionService service;
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /tested
|
||||
// Node.js: router.get("/tested", ...)
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/tested")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTestedConnections(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
log.info("노드 플로우용 테스트 완료된 커넥션 조회 요청 - companyCode: {}", companyCode);
|
||||
List<Map<String, Object>> valid = service.getTestedConnections(companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(valid,
|
||||
"테스트에 성공한 " + valid.size() + "개의 커넥션을 조회했습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("노드 플로우용 커넥션 조회 오류", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("서버 내부 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /{id}/tables
|
||||
// Node.js: router.get("/:id/tables", ...)
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{id}/tables")
|
||||
public ResponseEntity<?> getTables(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id) {
|
||||
try {
|
||||
log.info("외부 DB 테이블 목록 조회: connectionId={}", id);
|
||||
Map<String, Object> result = service.getTablesFromConnection(id);
|
||||
if (Boolean.TRUE.equals(result.get("success"))) {
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
return ResponseEntity.status(400).body(result);
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 테이블 목록 조회 오류: id={}", id, e);
|
||||
return ResponseEntity.status(500).body(Map.of(
|
||||
"success", false,
|
||||
"message", "서버 내부 오류가 발생했습니다.",
|
||||
"error", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /{id}/tables/{tableName}/columns
|
||||
// Node.js: router.get("/:id/tables/:tableName/columns", ...)
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{id}/tables/{tableName}/columns")
|
||||
public ResponseEntity<?> getTableColumns(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable int id,
|
||||
@PathVariable String tableName) {
|
||||
try {
|
||||
log.info("외부 DB 컬럼 목록 조회: connectionId={}, table={}", id, tableName);
|
||||
Map<String, Object> result = service.getColumnsFromConnection(id, tableName);
|
||||
if (Boolean.TRUE.equals(result.get("success"))) {
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
return ResponseEntity.status(400).body(result);
|
||||
} catch (Exception e) {
|
||||
log.error("외부 DB 컬럼 목록 조회 오류: id={}, table={}", id, tableName, e);
|
||||
return ResponseEntity.status(500).body(Map.of(
|
||||
"success", false,
|
||||
"message", "서버 내부 오류가 발생했습니다.",
|
||||
"error", e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.NodeFlowService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 노드 플로우 컨트롤러 (/api/dataflow/node-flows)
|
||||
*
|
||||
* Node.js node-flows.ts 포팅.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/dataflow/node-flows")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class NodeFlowController {
|
||||
|
||||
private final NodeFlowService service;
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 목록 조회
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** GET / */
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFlowList(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFlowList(companyCode)));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 목록 조회 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("플로우 목록 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 상세 조회
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /{flowId} */
|
||||
@GetMapping("/{flowId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getFlowById(
|
||||
@PathVariable int flowId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> flow = service.getFlowById(flowId, companyCode);
|
||||
if (flow == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("플로우를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(flow));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 상세 조회 오류: flowId={}", flowId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("플로우 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 생성
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** POST / */
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createFlow(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("userName") String userName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
body.put("userName", userName);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.createFlow(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 생성 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("플로우 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 수정
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** PUT / (flowId는 body에 포함) */
|
||||
@PutMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateFlow(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("userName") String userName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
body.put("userName", userName);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateFlow(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 수정 오류", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("플로우 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 삭제
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** DELETE /{flowId} */
|
||||
@DeleteMapping("/{flowId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteFlow(
|
||||
@PathVariable int flowId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("userName") String userName) {
|
||||
try {
|
||||
service.deleteFlow(flowId, companyCode, userId, userName);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "플로우가 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 삭제 오류: flowId={}", flowId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("플로우 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 소스 테이블 추출
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /{flowId}/source-table */
|
||||
@GetMapping("/{flowId}/source-table")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getSourceTable(
|
||||
@PathVariable int flowId) {
|
||||
try {
|
||||
Map<String, Object> result = service.getSourceTable(flowId);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("소스 테이블을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("소스 테이블 추출 오류: flowId={}", flowId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("소스 테이블 추출 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 플로우 실행
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/** POST /{flowId}/execute */
|
||||
@PostMapping("/{flowId}/execute")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeFlow(
|
||||
@PathVariable int flowId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("userName") String userName,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> contextData = body != null ? body : new java.util.LinkedHashMap<>();
|
||||
contextData.put("companyCode", companyCode);
|
||||
contextData.put("userId", userId);
|
||||
contextData.put("userName", userName);
|
||||
|
||||
Map<String, Object> result = service.executeFlow(flowId, contextData);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("플로우 실행 오류: flowId={}", flowId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("플로우 실행 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.NumberingRuleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/numbering-rule")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class NumberingRuleController {
|
||||
|
||||
private final NumberingRuleService numberingRuleService;
|
||||
|
||||
// ================================================================
|
||||
// ■ 규칙 목록 / 단건 조회
|
||||
// ================================================================
|
||||
|
||||
/** GET / → 회사별 채번 규칙 전체 목록 */
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRuleList(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
List<Map<String, Object>> list = numberingRuleService.getRuleList(companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(list, "채번 규칙 목록을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /available → 메뉴 기반 사용 가능 규칙 (menuObjid 없음) */
|
||||
@GetMapping("/available")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAvailableRulesForMenu(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
List<Map<String, Object>> list = numberingRuleService.getAvailableRulesForMenu(companyCode, null);
|
||||
return ResponseEntity.ok(ApiResponse.success(list, "사용 가능한 채번 규칙을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /available/{menuObjid} → 메뉴 기반 사용 가능 규칙 */
|
||||
@GetMapping("/available/{menuObjid}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAvailableRulesForMenuWithId(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer menuObjid) {
|
||||
List<Map<String, Object>> list = numberingRuleService.getAvailableRulesForMenu(companyCode, menuObjid);
|
||||
return ResponseEntity.ok(ApiResponse.success(list, "사용 가능한 채번 규칙을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /available-for-screen?tableName= → 화면 기반 사용 가능 규칙 */
|
||||
@GetMapping("/available-for-screen")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAvailableRulesForScreen(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam(required = false) String tableName) {
|
||||
List<Map<String, Object>> list = numberingRuleService.getAvailableRulesForScreen(companyCode, tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(list, "화면별 채번 규칙을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /by-column/{tableName}/{columnName} → 테이블+컬럼 기반 규칙 조회 */
|
||||
@GetMapping("/by-column/{tableName}/{columnName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getNumberingRuleByColumn(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName) {
|
||||
Map<String, Object> rule = numberingRuleService.getNumberingRuleByColumn(
|
||||
companyCode, tableName, columnName);
|
||||
if (rule == null) {
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "채번 규칙을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(rule, "채번 규칙을 조회했습니다."));
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// ■ 테스트 테이블 Operations
|
||||
// ================================================================
|
||||
|
||||
/** GET /test/list → 테스트용 규칙 목록 */
|
||||
@GetMapping("/test/list")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRulesFromTest(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
List<Map<String, Object>> list = numberingRuleService.getRulesFromTest(companyCode, null);
|
||||
return ResponseEntity.ok(ApiResponse.success(list, "테스트 채번 규칙 목록을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /test/list/{menuObjid} → 테스트용 규칙 목록 (메뉴 필터) */
|
||||
@GetMapping("/test/list/{menuObjid}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRulesFromTestWithMenu(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer menuObjid) {
|
||||
List<Map<String, Object>> list = numberingRuleService.getRulesFromTest(companyCode, menuObjid);
|
||||
return ResponseEntity.ok(ApiResponse.success(list, "테스트 채번 규칙 목록을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /test/by-column/{tableName}/{columnName} → 테스트 테이블+컬럼 기반 조회 */
|
||||
@GetMapping("/test/by-column/{tableName}/{columnName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTestRuleByColumn(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName) {
|
||||
Map<String, Object> rule = numberingRuleService.getNumberingRuleByColumn(
|
||||
companyCode, tableName, columnName);
|
||||
if (rule == null) {
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "채번 규칙을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(rule, "채번 규칙을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** POST /test/save → UPSERT */
|
||||
@PostMapping("/test/save")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveRuleToTest(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("ruleId") == null || body.get("ruleName") == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("ruleId와 ruleName이 필요합니다."));
|
||||
}
|
||||
Map<String, Object> result = numberingRuleService.saveRuleToTest(body, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "테스트 채번 규칙이 저장되었습니다."));
|
||||
}
|
||||
|
||||
/** DELETE /test/{ruleId} → 테스트 규칙 삭제 */
|
||||
@DeleteMapping("/test/{ruleId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteRuleFromTest(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId) {
|
||||
numberingRuleService.deleteRuleFromTest(ruleId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "테스트 채번 규칙이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
/** POST /test/{ruleId}/preview → 테스트 미리보기 */
|
||||
@PostMapping("/test/{ruleId}/preview")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewCodeFromTest(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> formData = body != null ? (Map<String, Object>) body.get("formData") : null;
|
||||
String manualInputValue = body != null ? (String) body.get("manualInputValue") : null;
|
||||
String code = numberingRuleService.previewCode(ruleId, companyCode, formData, manualInputValue);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("code", code), "미리보기 생성이 완료되었습니다."));
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// ■ 단건 CRUD
|
||||
// ================================================================
|
||||
|
||||
/** GET /{ruleId} → 단건 조회 */
|
||||
@GetMapping("/{ruleId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getRuleById(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId) {
|
||||
Map<String, Object> rule = numberingRuleService.getRuleById(ruleId, companyCode);
|
||||
if (rule == null) {
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "채번 규칙을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(rule, "채번 규칙을 조회했습니다."));
|
||||
}
|
||||
|
||||
/** POST / → 규칙 생성 */
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createRule(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("ruleId") == null || body.get("ruleName") == null || body.get("parts") == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("ruleId, ruleName, parts가 필요합니다."));
|
||||
}
|
||||
if (userId != null) body.put("userId", userId);
|
||||
Map<String, Object> result = numberingRuleService.createRule(body, companyCode);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "채번 규칙이 생성되었습니다."));
|
||||
}
|
||||
|
||||
/** PUT /{ruleId} → 규칙 수정 */
|
||||
@PutMapping("/{ruleId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateRule(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = numberingRuleService.updateRule(ruleId, body, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "채번 규칙이 수정되었습니다."));
|
||||
}
|
||||
|
||||
/** DELETE /{ruleId} → 규칙 삭제 */
|
||||
@DeleteMapping("/{ruleId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteRule(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId) {
|
||||
numberingRuleService.deleteRule(ruleId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "채번 규칙이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// ■ 코드 생성 Actions
|
||||
// ================================================================
|
||||
|
||||
/** POST /{ruleId}/preview → 미리보기 (순번 증가 없음) */
|
||||
@PostMapping("/{ruleId}/preview")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewCode(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> formData = body != null ? (Map<String, Object>) body.get("formData") : null;
|
||||
String manualInputValue = body != null ? (String) body.get("manualInputValue") : null;
|
||||
String code = numberingRuleService.previewCode(ruleId, companyCode, formData, manualInputValue);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("code", code), "미리보기 생성이 완료되었습니다."));
|
||||
}
|
||||
|
||||
/** POST /{ruleId}/allocate → 코드 할당 (순번 증가) */
|
||||
@PostMapping("/{ruleId}/allocate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> allocateCode(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> formData = body != null ? (Map<String, Object>) body.get("formData") : null;
|
||||
String userInputCode = body != null ? (String) body.get("userInputCode") : null;
|
||||
String code = numberingRuleService.allocateCode(ruleId, companyCode, formData, userInputCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("code", code), "코드 할당이 완료되었습니다."));
|
||||
}
|
||||
|
||||
/** POST /{ruleId}/generate (deprecated) → allocateCode 위임 */
|
||||
@PostMapping("/{ruleId}/generate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> generateCode(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId) {
|
||||
String code = numberingRuleService.generateCode(ruleId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("code", code), "코드 생성이 완료되었습니다."));
|
||||
}
|
||||
|
||||
/** POST /{ruleId}/reset → 순번 초기화 */
|
||||
@PostMapping("/{ruleId}/reset")
|
||||
public ResponseEntity<ApiResponse<Void>> resetSequence(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String ruleId) {
|
||||
numberingRuleService.resetSequence(ruleId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "시퀀스가 초기화되었습니다."));
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// ■ Admin
|
||||
// ================================================================
|
||||
|
||||
/** POST /copy-for-company → 회사간 규칙 복제 (SUPER_ADMIN) */
|
||||
@PostMapping("/copy-for-company")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyRulesForCompany(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String sourceCompanyCode = (String) body.get("sourceCompanyCode");
|
||||
String targetCompanyCode = (String) body.get("targetCompanyCode");
|
||||
if (sourceCompanyCode == null || targetCompanyCode == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("sourceCompanyCode와 targetCompanyCode가 필요합니다."));
|
||||
}
|
||||
Map<String, Object> result = numberingRuleService.copyRulesForCompany(
|
||||
sourceCompanyCode, targetCompanyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "채번 규칙 복제가 완료되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.erp.controller;
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.OpenApiProxyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/open-api-proxy")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class OpenApiProxyController {
|
||||
private final OpenApiProxyService openApiProxyService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getOpenApiProxyList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(openApiProxyService.getOpenApiProxyList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getOpenApiProxyInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(openApiProxyService.getOpenApiProxyInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Integer>> insertOpenApiProxy(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(openApiProxyService.insertOpenApiProxy(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Integer>> updateOpenApiProxy(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(openApiProxyService.updateOpenApiProxy(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Integer>> deleteOpenApiProxy(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(openApiProxyService.deleteOpenApiProxy(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.PackagingService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/packaging")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class PackagingController {
|
||||
|
||||
private final PackagingService packagingService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getPackagingList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(packagingService.getPackagingList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getPackagingInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(packagingService.getPackagingInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertPackaging(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(packagingService.insertPackaging(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updatePackaging(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(packagingService.updatePackaging(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deletePackaging(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(packagingService.deletePackaging(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.PopActionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/pop-action")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class PopActionController {
|
||||
|
||||
private final PopActionService popActionService;
|
||||
|
||||
/**
|
||||
* POST /api/pop-action/execute-action
|
||||
* Node.js popActionRoutes.ts POST /execute-action 대응
|
||||
*/
|
||||
@PostMapping("/execute-action")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeAction(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> result = popActionService.executeAction(body, companyCode, userId);
|
||||
String message = result.containsKey("message") ? result.get("message").toString()
|
||||
: result.get("processedCount") + "건 처리 완료";
|
||||
return ResponseEntity.ok(ApiResponse.success(result, message));
|
||||
} catch (PopActionService.PreConditionFailException e) {
|
||||
return ResponseEntity.status(409).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.erp.controller;
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.PopProductionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/pop-production")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class PopProductionController {
|
||||
private final PopProductionService popProductionService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getPopProductionList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(popProductionService.getPopProductionList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getPopProductionInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(popProductionService.getPopProductionInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertPopProduction(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(popProductionService.insertPopProduction(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updatePopProduction(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(popProductionService.updatePopProduction(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deletePopProduction(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(popProductionService.deletePopProduction(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package com.erp.controller;
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ProcessWorkStandardService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/process-work-standard")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ProcessWorkStandardController {
|
||||
private final ProcessWorkStandardService processWorkStandardService;
|
||||
|
||||
@GetMapping("/items")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getProcessWorkStandardItemList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.getProcessWorkStandardItemList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/items/{itemCode}/routings")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getProcessWorkStandardRoutingList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String itemCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("itemCode", itemCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.getProcessWorkStandardRoutingList(params)));
|
||||
}
|
||||
|
||||
@PutMapping("/versions/{versionId}/set-default")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> setProcessWorkStandardDefaultVersion(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long versionId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("versionId", versionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.setProcessWorkStandardDefaultVersion(params)));
|
||||
}
|
||||
|
||||
@PutMapping("/versions/{versionId}/unset-default")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> unsetProcessWorkStandardDefaultVersion(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long versionId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("versionId", versionId);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.unsetProcessWorkStandardDefaultVersion(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/routing-detail/{routingDetailId}/work-items")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getProcessWorkStandardWorkItemList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long routingDetailId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("routingDetailId", routingDetailId);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.getProcessWorkStandardWorkItemList(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/work-items")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertProcessWorkStandardWorkItem(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.insertProcessWorkStandardWorkItem(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/work-items/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateProcessWorkStandardWorkItem(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.updateProcessWorkStandardWorkItem(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/work-items/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteProcessWorkStandardWorkItem(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.deleteProcessWorkStandardWorkItem(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/work-items/{workItemId}/details")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getProcessWorkStandardWorkItemDetailList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long workItemId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("workItemId", workItemId);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.getProcessWorkStandardWorkItemDetailList(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/work-item-details")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertProcessWorkStandardWorkItemDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.insertProcessWorkStandardWorkItemDetail(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/work-item-details/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateProcessWorkStandardWorkItemDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.updateProcessWorkStandardWorkItemDetail(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/work-item-details/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteProcessWorkStandardWorkItemDetail(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.deleteProcessWorkStandardWorkItemDetail(params)));
|
||||
}
|
||||
|
||||
@PutMapping("/save-all")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveAllProcessWorkStandard(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.saveAllProcessWorkStandard(body)));
|
||||
}
|
||||
|
||||
@GetMapping("/registered-items/{screenCode}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getProcessWorkStandardRegisteredItemList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String screenCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("screenCode", screenCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.getProcessWorkStandardRegisteredItemList(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/registered-items")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertProcessWorkStandardRegisteredItem(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.insertProcessWorkStandardRegisteredItem(body)));
|
||||
}
|
||||
|
||||
@PostMapping("/registered-items/batch")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertProcessWorkStandardRegisteredItemBatch(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody List<Map<String, Object>> body) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("items", body);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.insertProcessWorkStandardRegisteredItemBatch(params)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/registered-items/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteProcessWorkStandardRegisteredItem(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(processWorkStandardService.deleteProcessWorkStandardRegisteredItem(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ProductionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/production")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ProductionController {
|
||||
|
||||
private final ProductionService productionService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getProductionList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(productionService.getProductionList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/plans")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getProductionPlans(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(productionService.getProductionList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getProductionInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(productionService.getProductionInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertProduction(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(productionService.insertProduction(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateProduction(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(productionService.updateProduction(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteProduction(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(productionService.deleteProduction(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ReportService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/report")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ReportController {
|
||||
|
||||
private final ReportService reportService;
|
||||
|
||||
// ── 외부 DB 연결 목록 ─────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/external-connections")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getExternalConnections(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(reportService.getExternalConnections(params)));
|
||||
}
|
||||
|
||||
// ── 템플릿 ────────────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/templates")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTemplates() {
|
||||
return ResponseEntity.ok(ApiResponse.success(reportService.getTemplates()));
|
||||
}
|
||||
|
||||
@PostMapping("/templates")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createTemplate(
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("createdBy", userId);
|
||||
Map<String, Object> result = reportService.createTemplate(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PostMapping("/templates/create-from-layout")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createTemplateFromLayout(
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("createdBy", userId);
|
||||
Map<String, Object> result = reportService.createTemplateFromLayout(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@DeleteMapping("/templates/{templateId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteTemplate(
|
||||
@PathVariable String templateId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("templateId", templateId);
|
||||
return ResponseEntity.ok(ApiResponse.success(reportService.deleteTemplate(params)));
|
||||
}
|
||||
|
||||
// ── 이미지 업로드 (stub) ──────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/upload-image")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> uploadImage() {
|
||||
return ResponseEntity.status(501).body(
|
||||
ApiResponse.error("이미지 업로드는 현재 지원되지 않습니다."));
|
||||
}
|
||||
|
||||
// ── Word 내보내기 (stub) ──────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/export-word")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> exportToWord() {
|
||||
return ResponseEntity.status(501).body(
|
||||
ApiResponse.error("Word 내보내기는 현재 지원되지 않습니다."));
|
||||
}
|
||||
|
||||
// ── 리포트 목록 ───────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getReportList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(reportService.getReportList(params)));
|
||||
}
|
||||
|
||||
// ── 리포트 생성 ───────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
if (body.get("reportNameKor") == null || body.get("reportType") == null) {
|
||||
return ResponseEntity.status(400).body(
|
||||
ApiResponse.error("리포트명과 리포트 타입은 필수입니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("createdBy", userId);
|
||||
Map<String, Object> result = reportService.createReport(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "리포트가 생성되었습니다."));
|
||||
}
|
||||
|
||||
// ── 리포트 복사 ───────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/{reportId}/copy")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String reportId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("reportId", reportId);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
Map<String, Object> result = reportService.copyReport(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("리포트를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
// ── 템플릿으로 저장 ───────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/{reportId}/save-as-template")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveAsTemplate(
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String reportId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("reportId", reportId);
|
||||
body.put("userId", userId);
|
||||
Map<String, Object> result = reportService.saveAsTemplate(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
// ── 레이아웃 조회/저장 ────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{reportId}/layout")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLayout(
|
||||
@PathVariable String reportId) {
|
||||
Map<String, Object> params = Map.of("reportId", reportId);
|
||||
Map<String, Object> result = reportService.getLayout(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("레이아웃을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PutMapping("/{reportId}/layout")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> saveLayout(
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String reportId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("reportId", reportId);
|
||||
body.put("userId", userId);
|
||||
Map<String, Object> result = reportService.saveLayout(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
// ── 쿼리 실행 ────────────────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/{reportId}/queries/{queryId}/execute")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> executeQuery(
|
||||
@PathVariable String reportId,
|
||||
@PathVariable String queryId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("reportId", reportId);
|
||||
body.put("queryId", queryId);
|
||||
Map<String, Object> result = reportService.executeQuery(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
// ── 리포트 상세 / 수정 / 삭제 ────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/{reportId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getReportInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String reportId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("reportId", reportId);
|
||||
params.put("companyCode", companyCode);
|
||||
Map<String, Object> result = reportService.getReportInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("리포트를 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
}
|
||||
|
||||
@PutMapping("/{reportId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute(value = "userId", required = false) String userId,
|
||||
@PathVariable String reportId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("reportId", reportId);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("updatedBy", userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(reportService.updateReport(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{reportId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String reportId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("reportId", reportId);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(reportService.deleteReport(params)));
|
||||
}
|
||||
|
||||
// ── 이전 /list 경로 호환 ──────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getReportListLegacy(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(reportService.getReportList(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.RiskAlertService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/risk-alert")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class RiskAlertController {
|
||||
|
||||
private final RiskAlertService riskAlertService;
|
||||
|
||||
/** GET / → 전체 알림 목록 */
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getAllAlerts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(riskAlertService.getAllAlerts(params)));
|
||||
}
|
||||
|
||||
/** POST /refresh → 알림 새로고침 */
|
||||
@PostMapping("/refresh")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> refreshAlerts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
Map<String, Object> params = body != null ? new HashMap<>(body) : new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(riskAlertService.refreshAlerts(params)));
|
||||
}
|
||||
|
||||
/** GET /weather → 기상 알림 목록 */
|
||||
@GetMapping("/weather")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getWeatherAlerts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(riskAlertService.getWeatherAlerts(params)));
|
||||
}
|
||||
|
||||
/** GET /accidents → 사고 알림 목록 */
|
||||
@GetMapping("/accidents")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAccidentAlerts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(riskAlertService.getAccidentAlerts(params)));
|
||||
}
|
||||
|
||||
/** GET /roadworks → 공사 알림 목록 */
|
||||
@GetMapping("/roadworks")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRoadworkAlerts(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(riskAlertService.getRoadworkAlerts(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.RoleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/roles")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class RoleController {
|
||||
|
||||
private final RoleService roleService;
|
||||
|
||||
// ──────────────────────────────────────────────────
|
||||
// 권한 그룹 CRUD
|
||||
// ──────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/roles
|
||||
* 권한 그룹 목록 조회 (관리자 전용)
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRoleGroups(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
// SUPER_ADMIN: 요청 파라미터의 companyCode 사용 (없으면 전체)
|
||||
// 그 외: 자신의 companyCode 강제 적용
|
||||
if (!isSuperAdmin(role)) {
|
||||
params.put("companyCode", companyCode);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(roleService.getRoleGroups(params), "권한 그룹 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/roles/{id}
|
||||
* 권한 그룹 상세 조회
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getRoleGroupById(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("objid", parseLong(id));
|
||||
|
||||
Map<String, Object> group = roleService.getRoleGroupById(params);
|
||||
if (group == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(group.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(group, "권한 그룹 상세 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/roles
|
||||
* 권한 그룹 생성
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createRoleGroup(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
String targetCompany = (String) body.get("companyCode");
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(targetCompany)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("다른 회사의 권한 그룹을 생성할 수 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("writer", userId);
|
||||
|
||||
Map<String, Object> created = roleService.createRoleGroup(params);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(created, "권한 그룹 생성 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/roles/{id}
|
||||
* 권한 그룹 수정
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateRoleGroup(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> findParams = Map.of("objid", parseLong(id));
|
||||
Map<String, Object> existing = roleService.getRoleGroupById(findParams);
|
||||
if (existing == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(existing.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("objid", parseLong(id));
|
||||
|
||||
Map<String, Object> updated = roleService.updateRoleGroup(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "권한 그룹 수정 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/roles/{id}
|
||||
* 권한 그룹 삭제
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteRoleGroup(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> findParams = Map.of("objid", parseLong(id));
|
||||
Map<String, Object> existing = roleService.getRoleGroupById(findParams);
|
||||
if (existing == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(existing.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("objid", parseLong(id));
|
||||
roleService.deleteRoleGroup(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "권한 그룹 삭제 성공"));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────
|
||||
// 멤버 관리 — /{id}/members 보다 먼저 정의된 2단계 경로
|
||||
// ──────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/roles/user/my-groups
|
||||
* 현재 로그인 사용자의 권한 그룹 조회
|
||||
*/
|
||||
@GetMapping("/user/my-groups")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMyRoleGroups(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("userId", userId);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(roleService.getUserRoleGroups(params), "사용자 권한 그룹 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/roles/menus/all
|
||||
* 전체 메뉴 목록 조회 (권한 설정용)
|
||||
*/
|
||||
@GetMapping("/menus/all")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAllMenus(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestParam(value = "companyCode", required = false) String requestedCompanyCode) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (isSuperAdmin(role)) {
|
||||
// SUPER_ADMIN: 쿼리 파라미터로 받은 companyCode 사용 (없으면 전체)
|
||||
params.put("companyCode", requestedCompanyCode);
|
||||
} else {
|
||||
params.put("companyCode", companyCode);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(roleService.getAllMenus(params), "메뉴 목록 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/roles/{id}/members
|
||||
* 권한 그룹 멤버 목록 조회
|
||||
*/
|
||||
@GetMapping("/{id}/members")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRoleMembers(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> findParams = Map.of("objid", parseLong(id));
|
||||
Map<String, Object> group = roleService.getRoleGroupById(findParams);
|
||||
if (group == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(group.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("masterObjid", parseLong(id));
|
||||
return ResponseEntity.ok(ApiResponse.success(roleService.getRoleMembers(params), "권한 그룹 멤버 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/roles/{id}/members
|
||||
* 권한 그룹 멤버 추가
|
||||
*/
|
||||
@PostMapping("/{id}/members")
|
||||
public ResponseEntity<ApiResponse<Void>> addRoleMembers(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestAttribute("userId") String currentUserId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> findParams = Map.of("objid", parseLong(id));
|
||||
Map<String, Object> group = roleService.getRoleGroupById(findParams);
|
||||
if (group == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(group.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("masterObjid", parseLong(id));
|
||||
params.put("writer", currentUserId);
|
||||
roleService.addRoleMembers(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "권한 그룹 멤버 추가 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/roles/{id}/members
|
||||
* 권한 그룹 멤버 일괄 업데이트 (diff 방식)
|
||||
*/
|
||||
@PutMapping("/{id}/members")
|
||||
public ResponseEntity<ApiResponse<Void>> updateRoleMembers(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestAttribute("userId") String currentUserId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> findParams = Map.of("objid", parseLong(id));
|
||||
Map<String, Object> group = roleService.getRoleGroupById(findParams);
|
||||
if (group == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(group.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("masterObjid", parseLong(id));
|
||||
params.put("writer", currentUserId);
|
||||
roleService.updateRoleMembers(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "권한 그룹 멤버 업데이트 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/roles/{id}/members
|
||||
* 권한 그룹 멤버 제거
|
||||
*/
|
||||
@DeleteMapping("/{id}/members")
|
||||
public ResponseEntity<ApiResponse<Void>> removeRoleMembers(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> findParams = Map.of("objid", parseLong(id));
|
||||
Map<String, Object> group = roleService.getRoleGroupById(findParams);
|
||||
if (group == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(group.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("masterObjid", parseLong(id));
|
||||
roleService.removeRoleMembers(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "권한 그룹 멤버 제거 성공"));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────
|
||||
// 메뉴 권한 관리
|
||||
// ──────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* GET /api/roles/{id}/menu-permissions
|
||||
* 메뉴 권한 목록 조회
|
||||
*/
|
||||
@GetMapping("/{id}/menu-permissions")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getMenuPermissions(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> findParams = Map.of("objid", parseLong(id));
|
||||
Map<String, Object> group = roleService.getRoleGroupById(findParams);
|
||||
if (group == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(group.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("authObjid", parseLong(id));
|
||||
return ResponseEntity.ok(ApiResponse.success(roleService.getMenuPermissions(params), "메뉴 권한 조회 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/roles/{id}/menu-permissions
|
||||
* 메뉴 권한 설정 (전체 교체)
|
||||
*/
|
||||
@PutMapping("/{id}/menu-permissions")
|
||||
public ResponseEntity<ApiResponse<Void>> setMenuPermissions(
|
||||
@PathVariable String id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role,
|
||||
@RequestAttribute("userId") String currentUserId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> findParams = Map.of("objid", parseLong(id));
|
||||
Map<String, Object> group = roleService.getRoleGroupById(findParams);
|
||||
if (group == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("권한 그룹을 찾을 수 없습니다."));
|
||||
}
|
||||
if (!isSuperAdmin(role) && !companyCode.equals(group.get("companyCode"))) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("권한이 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("authObjid", parseLong(id));
|
||||
params.put("writer", currentUserId);
|
||||
roleService.setMenuPermissions(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "메뉴 권한 설정 성공"));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/roles/user/{userId}/groups
|
||||
* 특정 사용자의 권한 그룹 조회
|
||||
*/
|
||||
@GetMapping("/user/{userId}/groups")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getUserRoleGroups(
|
||||
@PathVariable String userId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("role") String role) {
|
||||
|
||||
if (!isAdmin(role)) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error("관리자 권한이 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("userId", userId);
|
||||
params.put("companyCode", isSuperAdmin(role) ? null : companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(roleService.getUserRoleGroups(params), "사용자 권한 그룹 조회 성공"));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────
|
||||
// 내부 유틸
|
||||
// ──────────────────────────────────────────────────
|
||||
|
||||
private boolean isSuperAdmin(String role) {
|
||||
return "SUPER_ADMIN".equals(role);
|
||||
}
|
||||
|
||||
private boolean isAdmin(String role) {
|
||||
return "SUPER_ADMIN".equals(role) || "ADMIN".equals(role) || "COMPANY_ADMIN".equals(role);
|
||||
}
|
||||
|
||||
private Long parseLong(String value) {
|
||||
try {
|
||||
return Long.parseLong(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("유효하지 않은 ID입니다: " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.SalesReportService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/sales-report")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class SalesReportController {
|
||||
|
||||
private final SalesReportService salesReportService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getSalesReportList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(salesReportService.getSalesReportList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/summary")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getSalesReportSummary(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(salesReportService.getSalesReportSummary(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getSalesReportInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(salesReportService.getSalesReportInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertSalesReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(salesReportService.insertSalesReport(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateSalesReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(salesReportService.updateSalesReport(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteSalesReport(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(salesReportService.deleteSalesReport(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ScheduleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/schedule")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ScheduleController {
|
||||
private final ScheduleService scheduleService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScheduleList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(scheduleService.getScheduleList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{scheduleId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScheduleInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long scheduleId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("scheduleId", scheduleId);
|
||||
return ResponseEntity.ok(ApiResponse.success(scheduleService.getScheduleInfo(params)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 스케줄 미리보기 (DB 저장 없음)
|
||||
* POST /api/schedule/preview
|
||||
*/
|
||||
@PostMapping("/preview")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> previewSchedule(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
Map<String, Object> preview = scheduleService.previewSchedule(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(preview));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 스케줄 적용 (DB 저장)
|
||||
* POST /api/schedule/apply
|
||||
*/
|
||||
@PostMapping("/apply")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> applySchedules(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
Map<String, Object> applied = scheduleService.applySchedules(body);
|
||||
String message = applied.get("created") + "건 생성, " + applied.get("deleted") + "건 삭제, " + applied.get("updated") + "건 수정되었습니다.";
|
||||
return ResponseEntity.ok(ApiResponse.success(applied, message));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Integer>> insertSchedule(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(scheduleService.insertSchedule(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{scheduleId}")
|
||||
public ResponseEntity<ApiResponse<Integer>> updateSchedule(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long scheduleId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("scheduleId", scheduleId);
|
||||
return ResponseEntity.ok(ApiResponse.success(scheduleService.updateSchedule(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{scheduleId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteSchedule(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable Long scheduleId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
params.put("scheduleId", scheduleId);
|
||||
Map<String, Object> result = scheduleService.deleteSchedule(params);
|
||||
if (Boolean.FALSE.equals(result.get("success"))) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error((String) result.get("message")));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "스케줄이 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ScreenEmbeddingService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 화면 임베딩 및 데이터 전달 시스템 컨트롤러
|
||||
*
|
||||
* GET /api/screen-embedding - 목록 조회 (?parentScreenId)
|
||||
* GET /api/screen-embedding/{id} - 상세 조회
|
||||
* POST /api/screen-embedding - 생성
|
||||
* PUT /api/screen-embedding/{id} - 수정
|
||||
* DELETE /api/screen-embedding/{id} - 삭제
|
||||
*
|
||||
* GET /api/screen-data-transfer - 조회 (?sourceScreenId&targetScreenId)
|
||||
* POST /api/screen-data-transfer - 생성
|
||||
* PUT /api/screen-data-transfer/{id} - 수정
|
||||
* DELETE /api/screen-data-transfer/{id} - 삭제
|
||||
*
|
||||
* GET /api/screen-split-panel/{screenId} - 조회
|
||||
* POST /api/screen-split-panel - 생성
|
||||
* PUT /api/screen-split-panel/{id} - 수정
|
||||
* DELETE /api/screen-split-panel/{id} - 삭제
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ScreenEmbeddingController {
|
||||
|
||||
private final ScreenEmbeddingService service;
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Screen Embedding
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/screen-embedding")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getScreenEmbeddingList(
|
||||
@RequestParam(required = false) Long parentScreenId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
if (parentScreenId == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("부모 화면 ID가 필요합니다."));
|
||||
}
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("parentScreenId", parentScreenId);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getScreenEmbeddingList(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 임베딩 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 임베딩 목록 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/screen-embedding/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreenEmbeddingInfo(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
Map<String, Object> result = service.getScreenEmbeddingInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("화면 임베딩 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 임베딩 상세 조회 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 임베딩 상세 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/screen-embedding")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertScreenEmbedding(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
if (body.get("parentScreenId") == null || body.get("childScreenId") == null
|
||||
|| body.get("position") == null || body.get("mode") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("필수 필드가 누락되었습니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
Map<String, Object> result = service.insertScreenEmbedding(body);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(result));
|
||||
} catch (DuplicateKeyException e) {
|
||||
return ResponseEntity.status(409)
|
||||
.body(ApiResponse.error("이미 동일한 임베딩 설정이 존재합니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 임베딩 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 임베딩 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/screen-embedding/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateScreenEmbedding(
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
if (body.get("position") == null && body.get("mode") == null && body.get("config") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("수정할 내용이 없습니다."));
|
||||
}
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
Map<String, Object> result = service.updateScreenEmbedding(body);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("화면 임베딩 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 임베딩 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 임베딩 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/screen-embedding/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteScreenEmbedding(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
try {
|
||||
boolean deleted = service.deleteScreenEmbedding(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("화면 임베딩 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "화면 임베딩이 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 임베딩 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 임베딩 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Screen Data Transfer
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/screen-data-transfer")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreenDataTransferInfo(
|
||||
@RequestParam(required = false) Long sourceScreenId,
|
||||
@RequestParam(required = false) Long targetScreenId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
if (sourceScreenId == null || targetScreenId == null) {
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("소스 화면 ID와 타겟 화면 ID가 필요합니다."));
|
||||
}
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("sourceScreenId", sourceScreenId);
|
||||
params.put("targetScreenId", targetScreenId);
|
||||
params.put("companyCode", companyCode);
|
||||
Map<String, Object> result = service.getScreenDataTransferInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("데이터 전달 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 전달 설정 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 전달 설정 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/screen-data-transfer")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertScreenDataTransfer(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
if (body.get("sourceScreenId") == null || body.get("targetScreenId") == null
|
||||
|| body.get("dataReceivers") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("필수 필드가 누락되었습니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
Map<String, Object> result = service.insertScreenDataTransfer(body);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(result));
|
||||
} catch (DuplicateKeyException e) {
|
||||
return ResponseEntity.status(409)
|
||||
.body(ApiResponse.error("이미 동일한 데이터 전달 설정이 존재합니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 전달 설정 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 전달 설정 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/screen-data-transfer/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateScreenDataTransfer(
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
if (body.get("dataReceivers") == null && body.get("buttonConfig") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("수정할 내용이 없습니다."));
|
||||
}
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
Map<String, Object> result = service.updateScreenDataTransfer(body);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("데이터 전달 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 전달 설정 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 전달 설정 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/screen-data-transfer/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteScreenDataTransfer(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
try {
|
||||
boolean deleted = service.deleteScreenDataTransfer(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("데이터 전달 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "데이터 전달 설정이 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 전달 설정 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 전달 설정 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Screen Split Panel
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
@GetMapping("/screen-split-panel/{screenId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreenSplitPanelInfo(
|
||||
@PathVariable Long screenId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("screenId", screenId);
|
||||
params.put("companyCode", companyCode);
|
||||
Map<String, Object> result = service.getScreenSplitPanelInfo(params);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("분할 패널 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("분할 패널 설정 조회 실패: screenId={}", screenId, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("분할 패널 설정 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/screen-split-panel")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertScreenSplitPanel(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
if (body.get("screenId") == null || body.get("leftEmbedding") == null
|
||||
|| body.get("rightEmbedding") == null || body.get("dataTransfer") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("필수 필드가 누락되었습니다."));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
Map<String, Object> result = service.insertScreenSplitPanel(body);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("분할 패널 설정 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("분할 패널 설정 생성 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/screen-split-panel/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateScreenSplitPanel(
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
if (body.get("layoutConfig") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("수정할 내용이 없습니다."));
|
||||
}
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
Map<String, Object> result = service.updateScreenSplitPanel(body);
|
||||
if (result == null) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("분할 패널 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("분할 패널 설정 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("분할 패널 설정 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/screen-split-panel/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteScreenSplitPanel(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
try {
|
||||
boolean deleted = service.deleteScreenSplitPanel(params);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("분할 패널 설정을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "분할 패널 설정이 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("분할 패널 설정 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("분할 패널 설정 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.service.ScreenFileService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/screens")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ScreenFileController {
|
||||
|
||||
private final ScreenFileService screenFileService;
|
||||
|
||||
/**
|
||||
* GET /api/screens/{screenId}/components/files
|
||||
* 화면의 모든 컴포넌트 파일 조회 (컴포넌트별 그룹화)
|
||||
* 응답: { success, componentFiles, totalFiles, componentCount }
|
||||
*/
|
||||
@GetMapping("/{screenId}/components/files")
|
||||
public ResponseEntity<Map<String, Object>> getScreenComponentFiles(
|
||||
@PathVariable String screenId) {
|
||||
Map<String, Object> result = screenFileService.getScreenComponentFiles(screenId);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/screens/{screenId}/components/{componentId}/files
|
||||
* 특정 컴포넌트의 파일 목록 조회
|
||||
* 응답: { success, files, componentId, screenId }
|
||||
*/
|
||||
@GetMapping("/{screenId}/components/{componentId}/files")
|
||||
public ResponseEntity<Map<String, Object>> getComponentFiles(
|
||||
@PathVariable String screenId,
|
||||
@PathVariable String componentId) {
|
||||
Map<String, Object> result = screenFileService.getComponentFiles(screenId, componentId);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,733 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ScreenGroupService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/screen-groups")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ScreenGroupController {
|
||||
|
||||
private final ScreenGroupService service;
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Screen Groups — CRUD
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/screen-groups/groups */
|
||||
@GetMapping("/groups")
|
||||
public ResponseEntity<?> getScreenGroups(
|
||||
@RequestParam(required = false) String search,
|
||||
@RequestParam(required = false) String groupName,
|
||||
@RequestParam(required = false) Integer parentGroupId,
|
||||
@RequestParam(required = false, defaultValue = "1") int page,
|
||||
@RequestParam(required = false, defaultValue = "20") int size,
|
||||
@RequestParam(required = false) String filterCompanyCode,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
String effectiveCompanyCode = ("*".equals(companyCode) && filterCompanyCode != null)
|
||||
? filterCompanyCode : companyCode;
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", effectiveCompanyCode);
|
||||
params.put("page", page);
|
||||
params.put("size", size);
|
||||
if (search != null) params.put("search", search);
|
||||
if (groupName != null) params.put("groupName", groupName);
|
||||
if (parentGroupId != null) params.put("parentGroupId", parentGroupId);
|
||||
|
||||
// 페이지네이션 응답은 Node.js 동일 구조(total/page/size/totalPages) 유지
|
||||
return ResponseEntity.ok(service.getScreenGroups(params));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 그룹 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 그룹 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** GET /api/screen-groups/groups/:id */
|
||||
@GetMapping("/groups/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreenGroup(
|
||||
@PathVariable Integer id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
Map<String, Object> group = service.getScreenGroup(params);
|
||||
if (group == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("화면 그룹을 찾을 수 없습니다"));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(group));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 그룹 단건 조회 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 그룹 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/groups */
|
||||
@PostMapping("/groups")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createScreenGroup(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
Map<String, Object> created = service.createScreenGroup(body);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(created));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "화면 그룹 생성 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 그룹 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 그룹 생성 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/screen-groups/groups/:id */
|
||||
@PutMapping("/groups/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateScreenGroup(
|
||||
@PathVariable Integer id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateScreenGroup(body)));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "화면 그룹을 찾을 수 없습니다"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "화면 그룹 수정 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 그룹 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 그룹 수정 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/screen-groups/groups/:id */
|
||||
@DeleteMapping("/groups/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteScreenGroup(
|
||||
@PathVariable Integer id,
|
||||
@RequestParam(required = false, defaultValue = "false") boolean deleteNumberingRules,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
params.put("deleteNumberingRules", deleteNumberingRules);
|
||||
try {
|
||||
service.deleteScreenGroup(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "화면 그룹이 삭제되었습니다"));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "화면 그룹을 찾을 수 없습니다"));
|
||||
} catch (SecurityException e) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "권한이 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 그룹 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 그룹 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Screen Group Screens
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** POST /api/screen-groups/group-screens */
|
||||
@PostMapping("/group-screens")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> addScreenToGroup(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(service.addScreenToGroup(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "화면 그룹 연결 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 그룹 화면 추가 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 그룹 화면 추가 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/screen-groups/group-screens/:id */
|
||||
@PutMapping("/group-screens/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateScreenInGroup(
|
||||
@PathVariable Integer id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateScreenInGroup(body)));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "연결을 찾을 수 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 그룹 화면 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 그룹 화면 수정 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/screen-groups/group-screens/:id */
|
||||
@DeleteMapping("/group-screens/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> removeScreenFromGroup(
|
||||
@PathVariable Integer id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
service.removeScreenFromGroup(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "화면 그룹 연결이 해제되었습니다"));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "연결을 찾을 수 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 그룹 화면 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면 그룹 화면 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Field Joins
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/screen-groups/field-joins */
|
||||
@GetMapping("/field-joins")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getFieldJoins(
|
||||
@RequestParam(required = false) Integer groupId,
|
||||
@RequestParam(required = false) Integer screenId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
if (groupId != null) params.put("groupId", groupId);
|
||||
if (screenId != null) params.put("screenId", screenId);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getFieldJoins(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("필드 조인 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("필드 조인 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/field-joins */
|
||||
@PostMapping("/field-joins")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createFieldJoin(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(service.createFieldJoin(body)));
|
||||
} catch (Exception e) {
|
||||
log.error("필드 조인 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("필드 조인 생성 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/screen-groups/field-joins/:id */
|
||||
@PutMapping("/field-joins/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateFieldJoin(
|
||||
@PathVariable Integer id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateFieldJoin(body)));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "필드 조인을 찾을 수 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("필드 조인 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("필드 조인 수정 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/screen-groups/field-joins/:id */
|
||||
@DeleteMapping("/field-joins/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteFieldJoin(
|
||||
@PathVariable Integer id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
service.deleteFieldJoin(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "필드 조인이 삭제되었습니다"));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "필드 조인을 찾을 수 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("필드 조인 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("필드 조인 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Data Flows
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/screen-groups/data-flows */
|
||||
@GetMapping("/data-flows")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getDataFlows(
|
||||
@RequestParam(required = false) Integer groupId,
|
||||
@RequestParam(required = false) Integer screenId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
if (groupId != null) params.put("groupId", groupId);
|
||||
if (screenId != null) params.put("screenId", screenId);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getDataFlows(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 흐름 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 흐름 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/data-flows */
|
||||
@PostMapping("/data-flows")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createDataFlow(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(service.createDataFlow(body)));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 흐름 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 흐름 생성 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/screen-groups/data-flows/:id */
|
||||
@PutMapping("/data-flows/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateDataFlow(
|
||||
@PathVariable Integer id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateDataFlow(body)));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "데이터 흐름을 찾을 수 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 흐름 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 흐름 수정 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/screen-groups/data-flows/:id */
|
||||
@DeleteMapping("/data-flows/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteDataFlow(
|
||||
@PathVariable Integer id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
service.deleteDataFlow(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "데이터 흐름이 삭제되었습니다"));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "데이터 흐름을 찾을 수 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("데이터 흐름 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("데이터 흐름 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Table Relations
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/screen-groups/table-relations */
|
||||
@GetMapping("/table-relations")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableRelations(
|
||||
@RequestParam(required = false) Integer groupId,
|
||||
@RequestParam(required = false) Integer screenId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
if (groupId != null) params.put("groupId", groupId);
|
||||
if (screenId != null) params.put("screenId", screenId);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getTableRelations(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("화면-테이블 관계 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면-테이블 관계 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/table-relations */
|
||||
@PostMapping("/table-relations")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createTableRelation(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(service.createTableRelation(body)));
|
||||
} catch (Exception e) {
|
||||
log.error("화면-테이블 관계 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면-테이블 관계 생성 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/screen-groups/table-relations/:id */
|
||||
@PutMapping("/table-relations/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateTableRelation(
|
||||
@PathVariable Integer id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateTableRelation(body)));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "화면-테이블 관계를 찾을 수 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("화면-테이블 관계 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면-테이블 관계 수정 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/screen-groups/table-relations/:id */
|
||||
@DeleteMapping("/table-relations/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteTableRelation(
|
||||
@PathVariable Integer id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
service.deleteTableRelation(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "화면-테이블 관계가 삭제되었습니다"));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "화면-테이블 관계를 찾을 수 없습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("화면-테이블 관계 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("화면-테이블 관계 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Layout Summary
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/screen-groups/layout-summary/:screenId */
|
||||
@GetMapping("/layout-summary/{screenId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreenLayoutSummary(
|
||||
@PathVariable Integer screenId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("screenId", screenId);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getScreenLayoutSummary(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("레이아웃 요약 조회 실패: screenId={}", screenId, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("레이아웃 요약 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/layout-summary/batch */
|
||||
@PostMapping("/layout-summary/batch")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getMultipleScreenLayoutSummary(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> screenIds = (List<Integer>) body.get("screenIds");
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
service.getMultipleScreenLayoutSummary(screenIds)));
|
||||
} catch (Exception e) {
|
||||
log.error("다중 레이아웃 요약 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("다중 레이아웃 요약 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Sub Tables
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** POST /api/screen-groups/sub-tables/batch */
|
||||
@PostMapping("/sub-tables/batch")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreenSubTables(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> screenIds = (List<Integer>) body.get("screenIds");
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
service.getScreenSubTables(screenIds)));
|
||||
} catch (Exception e) {
|
||||
log.error("서브 테이블 배치 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("서브 테이블 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Sync
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/screen-groups/sync/status */
|
||||
@GetMapping("/sync/status")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getSyncStatus(
|
||||
@RequestParam(required = false) String filterCompanyCode,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
String effectiveCompanyCode = ("*".equals(companyCode) && filterCompanyCode != null)
|
||||
? filterCompanyCode : companyCode;
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getSyncStatus(effectiveCompanyCode)));
|
||||
} catch (Exception e) {
|
||||
log.error("동기화 상태 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("동기화 상태 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/sync/screen-to-menu */
|
||||
@PostMapping("/sync/screen-to-menu")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> syncScreenGroupsToMenu(
|
||||
@RequestBody(required = false) Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
try {
|
||||
String targetCompanyCode = companyCode;
|
||||
if (body != null && body.get("companyCode") != null) {
|
||||
targetCompanyCode = (String) body.get("companyCode");
|
||||
}
|
||||
Map<String, Object> result = service.syncScreenGroupsToMenu(targetCompanyCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("화면관리 → 메뉴 동기화 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("동기화 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/sync/menu-to-screen */
|
||||
@PostMapping("/sync/menu-to-screen")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> syncMenuToScreenGroups(
|
||||
@RequestBody(required = false) Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
try {
|
||||
String targetCompanyCode = companyCode;
|
||||
if (body != null && body.get("companyCode") != null) {
|
||||
targetCompanyCode = (String) body.get("companyCode");
|
||||
}
|
||||
Map<String, Object> result = service.syncMenuToScreenGroups(targetCompanyCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("메뉴 → 화면관리 동기화 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("동기화 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/sync/all */
|
||||
@PostMapping("/sync/all")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> syncAllCompanies(
|
||||
@RequestAttribute("userId") String userId) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.syncAllCompanies(userId)));
|
||||
} catch (Exception e) {
|
||||
log.error("전체 회사 동기화 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("전체 회사 동기화 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// POP Groups
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/screen-groups/pop/groups */
|
||||
@GetMapping("/pop/groups")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getPopScreenGroups(
|
||||
@RequestParam(required = false) String filterCompanyCode,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
String effectiveCompanyCode = ("*".equals(companyCode) && filterCompanyCode != null)
|
||||
? filterCompanyCode : companyCode;
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", effectiveCompanyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getPopScreenGroups(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("POP 화면 그룹 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("POP 화면 그룹 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/pop/groups */
|
||||
@PostMapping("/pop/groups")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createPopScreenGroup(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("userCompanyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(service.createPopScreenGroup(body)));
|
||||
} catch (SecurityException e) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "권한이 없습니다"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "POP 화면 그룹 생성 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("POP 화면 그룹 생성 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("POP 화면 그룹 생성 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/screen-groups/pop/groups/:id */
|
||||
@PutMapping("/pop/groups/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updatePopScreenGroup(
|
||||
@PathVariable Integer id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("id", id);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updatePopScreenGroup(body)));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "그룹을 찾을 수 없습니다"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "POP 화면 그룹 수정 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("POP 화면 그룹 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("POP 화면 그룹 수정 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/screen-groups/pop/groups/:id */
|
||||
@DeleteMapping("/pop/groups/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deletePopScreenGroup(
|
||||
@PathVariable Integer id,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
service.deletePopScreenGroup(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "POP 화면 그룹이 삭제되었습니다"));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "그룹을 찾을 수 없습니다"));
|
||||
} catch (SecurityException e) {
|
||||
return ResponseEntity.status(403).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "권한이 없습니다"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "POP 화면 그룹 삭제 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("POP 화면 그룹 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("POP 화면 그룹 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/screen-groups/pop/ensure-root */
|
||||
@PostMapping("/pop/ensure-root")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> ensurePopRootGroup(
|
||||
@RequestBody(required = false) Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
if (body != null) params.putAll(body);
|
||||
Map<String, Object> result = service.ensurePopRootGroup(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
log.error("POP 루트 그룹 확보 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("POP 루트 그룹 확보 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,653 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ScreenManagementService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/screen-management")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ScreenManagementController {
|
||||
|
||||
private final ScreenManagementService service;
|
||||
|
||||
// ─── 화면 목록 / 단건 ─────────────────────────────────────
|
||||
|
||||
@GetMapping("/screens")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreens(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", params.getOrDefault("companyCode", companyCode));
|
||||
// 권한 확인: 최고 관리자가 아니면 자사 companyCode만 허용
|
||||
String targetCode = (String) params.get("companyCode");
|
||||
if (!"*".equals(companyCode) && !companyCode.equals(targetCode)) {
|
||||
return ResponseEntity.status(403)
|
||||
.body(ApiResponse.error("다른 회사의 화면을 조회할 권한이 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getScreens(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/screens/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreen(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("id") Integer screenId) {
|
||||
Map<String, Object> screen = service.getScreenById(screenId);
|
||||
if (screen == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("화면을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(screen));
|
||||
}
|
||||
|
||||
@GetMapping("/screens/{id}/menu")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getScreenMenu(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("id") Integer screenId) {
|
||||
Map<String, Object> menuInfo = service.getMenuByScreen(screenId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(menuInfo));
|
||||
}
|
||||
|
||||
// ─── 화면 생성 / 수정 ──────────────────────────────────────
|
||||
|
||||
@PostMapping("/screens")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createScreen(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> screen = service.createScreen(body, companyCode, userId);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(screen, "화면이 생성되었습니다."));
|
||||
} catch (IllegalStateException e) {
|
||||
return ResponseEntity.status(409).body(ApiResponse.error("화면 코드가 이미 존재합니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 생성 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 생성에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/screens/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateScreen(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> screen = service.updateScreen(screenId, body, companyCode, userId);
|
||||
if (screen == null) return ResponseEntity.status(404).body(ApiResponse.error("화면을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(screen, "화면이 수정되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 수정 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 수정에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/screens/{id}/info")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateScreenInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> screen = service.updateScreenInfo(screenId, body, companyCode, userId);
|
||||
if (screen == null) return ResponseEntity.status(404).body(ApiResponse.error("화면을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(screen, "화면 정보가 수정되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 정보 수정 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 정보 수정에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PatchMapping("/screens/{screenId}/table-name")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateScreenTableName(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String tableName = (String) body.get("tableName");
|
||||
Map<String, Object> screen = service.updateScreenTableName(screenId, tableName, userId);
|
||||
if (screen == null) return ResponseEntity.status(404).body(ApiResponse.error("화면을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(screen));
|
||||
}
|
||||
|
||||
// ─── 의존성 / 연결 모달 ────────────────────────────────────
|
||||
|
||||
@GetMapping("/screens/{id}/dependencies")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkScreenDependencies(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("id") Integer screenId) {
|
||||
Map<String, Object> deps = service.checkScreenDependencies(screenId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(deps));
|
||||
}
|
||||
|
||||
@GetMapping("/screens/{id}/linked-modals")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> detectLinkedScreens(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable("id") Integer screenId) {
|
||||
List<Map<String, Object>> linked = service.detectLinkedScreens(screenId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(linked));
|
||||
}
|
||||
|
||||
// ─── 삭제 ──────────────────────────────────────────────────
|
||||
|
||||
@DeleteMapping("/screens/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteScreen(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") Integer screenId,
|
||||
@RequestParam(required = false) String deleteReason) {
|
||||
try {
|
||||
service.softDeleteScreen(screenId, userId, companyCode, deleteReason);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "화면이 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 삭제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/screens/bulk/delete")
|
||||
public ResponseEntity<ApiResponse<Void>> bulkDeleteScreens(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> screenIds = (List<Integer>) body.get("screenIds");
|
||||
try {
|
||||
service.bulkSoftDeleteScreens(screenIds, userId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, screenIds.size() + "개 화면이 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 일괄 삭제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 일괄 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 중복 체크 ─────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/screens/check-duplicate-name")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkDuplicateScreenName(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String screenName = (String) body.get("screenName");
|
||||
String targetCode = body.containsKey("companyCode") ? (String) body.get("companyCode") : companyCode;
|
||||
boolean isDuplicate = service.checkDuplicateScreenName(screenName, targetCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("isDuplicate", isDuplicate)));
|
||||
}
|
||||
|
||||
// ─── 복사 ──────────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/screens/{id}/copy")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyScreen(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") Integer screenId,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
try {
|
||||
String newName = body != null ? (String) body.get("newName") : null;
|
||||
Map<String, Object> screen = service.copyScreen(screenId, newName, companyCode, userId);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(screen, "화면이 복사되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 복사 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 복사에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/screens/{id}/copy-with-modals")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyScreenWithModals(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> result = service.copyScreenWithModals(screenId, body, companyCode, userId);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "화면과 모달이 복사되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 + 모달 복사 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 복사에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 휴지통 ────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/screens/trash/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getDeletedScreens(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getDeletedScreens(params)));
|
||||
}
|
||||
|
||||
@PostMapping("/screens/{id}/restore")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> restoreScreen(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable("id") Integer screenId) {
|
||||
try {
|
||||
Map<String, Object> screen = service.restoreScreen(screenId, userId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(screen, "화면이 복원되었습니다."));
|
||||
} catch (IllegalStateException e) {
|
||||
return ResponseEntity.status(409).body(ApiResponse.error("화면 코드가 이미 사용 중입니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 복원 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 복원에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/screens/{id}/permanent")
|
||||
public ResponseEntity<ApiResponse<Void>> permanentDeleteScreen(
|
||||
@PathVariable("id") Integer screenId) {
|
||||
try {
|
||||
service.permanentDeleteScreen(screenId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "화면이 영구 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 영구 삭제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 영구 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/screens/trash/bulk")
|
||||
public ResponseEntity<ApiResponse<Void>> bulkPermanentDeleteScreens(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> screenIds = (List<Integer>) body.get("screenIds");
|
||||
try {
|
||||
service.bulkPermanentDeleteScreens(screenIds);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, screenIds.size() + "개 화면이 영구 삭제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 일괄 영구 삭제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 일괄 영구 삭제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 화면 코드 생성 ────────────────────────────────────────
|
||||
|
||||
@GetMapping("/generate-screen-code/{companyCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> generateScreenCode(
|
||||
@PathVariable String companyCode) {
|
||||
try {
|
||||
String code = service.generateScreenCode(companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("screenCode", code)));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 코드 생성 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 코드 생성에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/generate-screen-codes")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> generateMultipleScreenCodes(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String companyCode = (String) body.get("companyCode");
|
||||
int count = body.get("count") != null ? Integer.parseInt(body.get("count").toString()) : 1;
|
||||
try {
|
||||
List<String> codes = service.generateMultipleScreenCodes(companyCode, count);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("screenCodes", codes)));
|
||||
} catch (Exception e) {
|
||||
log.error("화면 코드 일괄 생성 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("화면 코드 생성에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 테이블 관리 ───────────────────────────────────────────
|
||||
|
||||
@GetMapping("/tables")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTables() {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getTables()));
|
||||
}
|
||||
|
||||
@GetMapping("/tables/{tableName}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableInfo(
|
||||
@PathVariable String tableName) {
|
||||
Map<String, Object> info = service.getTableInfo(tableName);
|
||||
if (info == null) return ResponseEntity.status(404).body(ApiResponse.error("테이블을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(info));
|
||||
}
|
||||
|
||||
@GetMapping("/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableColumns(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getTableColumns(tableName, companyCode)));
|
||||
}
|
||||
|
||||
// ─── 레이아웃 V1 ───────────────────────────────────────────
|
||||
|
||||
@PostMapping("/screens/{screenId}/layout")
|
||||
public ResponseEntity<ApiResponse<Void>> saveLayout(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> components = (List<Map<String, Object>>) body.get("components");
|
||||
if (components == null) components = List.of();
|
||||
try {
|
||||
service.saveLayout(screenId, components, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "레이아웃이 저장되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("레이아웃 저장 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("레이아웃 저장에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/screens/{screenId}/layout")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getLayout(
|
||||
@PathVariable Integer screenId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getLayoutV1(screenId)));
|
||||
}
|
||||
|
||||
@GetMapping("/screens/{screenId}/layout-v1")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getLayoutV1(
|
||||
@PathVariable Integer screenId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getLayoutV1(screenId)));
|
||||
}
|
||||
|
||||
// ─── 레이아웃 V2 ───────────────────────────────────────────
|
||||
|
||||
@GetMapping("/screens/{screenId}/layout-v2")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLayoutV2(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId,
|
||||
@RequestParam(required = false) Integer layerId) {
|
||||
Map<String, Object> layout = service.getLayoutV2(screenId, companyCode, layerId);
|
||||
return ResponseEntity.ok(ApiResponse.success(layout));
|
||||
}
|
||||
|
||||
@PostMapping("/screens/{screenId}/layout-v2")
|
||||
public ResponseEntity<ApiResponse<Void>> saveLayoutV2(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
service.saveLayoutV2(screenId, body, companyCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "레이아웃 V2가 저장되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("레이아웃 V2 저장 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("레이아웃 저장에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── POP 레이아웃 ──────────────────────────────────────────
|
||||
|
||||
@GetMapping("/screens/{screenId}/layout-pop")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLayoutPop(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getLayoutPop(screenId, companyCode)));
|
||||
}
|
||||
|
||||
@PostMapping("/screens/{screenId}/layout-pop")
|
||||
public ResponseEntity<ApiResponse<Void>> saveLayoutPop(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
service.saveLayoutPop(screenId, body, companyCode, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "POP 레이아웃이 저장되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("POP 레이아웃 저장 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("POP 레이아웃 저장에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/screens/{screenId}/layout-pop")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteLayoutPop(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId) {
|
||||
service.deleteLayoutPop(screenId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "POP 레이아웃이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
@GetMapping("/pop-layout-screen-ids")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getScreenIdsWithPopLayout(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getScreenIdsWithPopLayout(companyCode)));
|
||||
}
|
||||
|
||||
// ─── 레이어 관리 ───────────────────────────────────────────
|
||||
|
||||
@GetMapping("/screens/{screenId}/layers")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getScreenLayers(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getScreenLayers(screenId, companyCode)));
|
||||
}
|
||||
|
||||
@GetMapping("/screens/{screenId}/layers/{layerId}/layout")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLayerLayout(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId,
|
||||
@PathVariable Integer layerId) {
|
||||
Map<String, Object> layout = service.getLayerLayout(screenId, layerId, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(layout));
|
||||
}
|
||||
|
||||
@DeleteMapping("/screens/{screenId}/layers/{layerId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteLayer(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId,
|
||||
@PathVariable Integer layerId) {
|
||||
boolean deleted = service.deleteLayer(screenId, layerId, companyCode);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("레이어를 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "레이어가 삭제되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/screens/{screenId}/layers/{layerId}/condition")
|
||||
public ResponseEntity<ApiResponse<Void>> updateLayerCondition(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId,
|
||||
@PathVariable Integer layerId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
service.updateLayerCondition(screenId, layerId, body, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "레이어 조건이 업데이트되었습니다."));
|
||||
}
|
||||
|
||||
// ─── Zone 관리 ─────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/screens/{screenId}/zones")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getScreenZones(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getScreenZones(screenId, companyCode)));
|
||||
}
|
||||
|
||||
@PostMapping("/screens/{screenId}/zones")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createZone(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> result = service.createZone(screenId, body, companyCode);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "Zone이 생성되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("Zone 생성 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("Zone 생성에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/zones/{zoneId}")
|
||||
public ResponseEntity<ApiResponse<Void>> updateZone(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer zoneId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
boolean updated = service.updateZone(zoneId, body, companyCode);
|
||||
if (!updated) return ResponseEntity.status(404).body(ApiResponse.error("Zone을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "Zone이 수정되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/zones/{zoneId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteZone(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer zoneId) {
|
||||
boolean deleted = service.deleteZone(zoneId, companyCode);
|
||||
if (!deleted) return ResponseEntity.status(404).body(ApiResponse.error("Zone을 찾을 수 없습니다."));
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "Zone이 삭제되었습니다."));
|
||||
}
|
||||
|
||||
@PostMapping("/screens/{screenId}/zones/{zoneId}/layers")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> addLayerToZone(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId,
|
||||
@PathVariable Integer zoneId,
|
||||
@RequestBody(required = false) Map<String, Object> body) {
|
||||
if (body == null) body = Map.of();
|
||||
try {
|
||||
Map<String, Object> result = service.addLayerToZone(screenId, zoneId, body, companyCode);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "레이어가 추가되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("레이어 추가 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("레이어 추가에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 메뉴-화면 할당 ────────────────────────────────────────
|
||||
|
||||
@PostMapping("/screens/{screenId}/assign-menu")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> assignScreenToMenu(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@PathVariable Integer screenId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> result = service.assignScreenToMenu(screenId, body, companyCode, userId);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "메뉴에 화면이 할당되었습니다."));
|
||||
} catch (IllegalStateException e) {
|
||||
return ResponseEntity.status(409).body(ApiResponse.error("이미 할당된 메뉴입니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("메뉴 할당 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("메뉴 할당에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/menus/{menuObjid}/screens")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getScreensByMenu(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer menuObjid) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getScreensByMenu(menuObjid, companyCode)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/screens/{screenId}/menus/{menuObjid}")
|
||||
public ResponseEntity<ApiResponse<Void>> unassignScreenFromMenu(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId,
|
||||
@PathVariable Integer menuObjid) {
|
||||
try {
|
||||
service.unassignScreenFromMenu(screenId, menuObjid, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "메뉴 할당이 해제되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("메뉴 할당 해제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("메뉴 할당 해제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/admin/cleanup-deleted-screen-menu-assignments")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> cleanupDeletedScreenMenuAssignments() {
|
||||
int count = service.cleanupDeletedMenuAssignments();
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("count", count), count + "개 메뉴 할당이 정리되었습니다."));
|
||||
}
|
||||
|
||||
// ─── 탭 참조 업데이트 ──────────────────────────────────────
|
||||
|
||||
@PostMapping("/screens/update-tab-references")
|
||||
public ResponseEntity<ApiResponse<Void>> updateTabScreenReferences(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
service.updateTabScreenReferences(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "탭 참조가 업데이트되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("탭 참조 업데이트 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("탭 참조 업데이트에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 복제 작업 ─────────────────────────────────────────────
|
||||
|
||||
@PostMapping("/copy-menu-assignments")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyScreenMenuAssignments(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
int count = service.copyScreenMenuAssignments(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("count", count)));
|
||||
} catch (Exception e) {
|
||||
log.error("메뉴 할당 복제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("메뉴 할당 복제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/copy-code-category")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyCodeCategoryAndCodes(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
int count = service.copyCodeCategoryAndCodes(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("count", count)));
|
||||
} catch (Exception e) {
|
||||
log.error("코드 카테고리 복제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("코드 카테고리 복제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/copy-category-mapping")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyCategoryMapping(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
int count = service.copyCategoryMapping(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("count", count)));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 매핑 복제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("카테고리 매핑 복제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/copy-table-type-columns")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyTableTypeColumns(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
int count = service.copyTableTypeColumns(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("count", count)));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블 타입 컬럼 복제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("테이블 타입 컬럼 복제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/copy-cascading-relation")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> copyCascadingRelation(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
int count = service.copyCascadingRelation(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("count", count)));
|
||||
} catch (Exception e) {
|
||||
log.error("연쇄관계 복제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("연쇄관계 복제에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── POP 화면 배포 ─────────────────────────────────────────
|
||||
|
||||
@GetMapping("/screens/{screenId}/pop-links")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> analyzePopScreenLinks(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Integer screenId) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.analyzePopScreenLinks(screenId, companyCode)));
|
||||
}
|
||||
|
||||
@PostMapping("/deploy-pop-screens")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deployPopScreens(
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
try {
|
||||
Map<String, Object> result = service.deployPopScreens(body, userId);
|
||||
return ResponseEntity.ok(ApiResponse.success(result, "POP 화면 배포가 완료되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("POP 화면 배포 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("POP 화면 배포에 실패했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ScreenStandardService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/screen-standard")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ScreenStandardController {
|
||||
|
||||
private final ScreenStandardService screenStandardService;
|
||||
|
||||
/**
|
||||
* GET /api/screen-standard/web-types
|
||||
* 웹타입 목록 조회 (active / category / search 필터)
|
||||
*/
|
||||
@GetMapping("/web-types")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getWebTypeList(
|
||||
@RequestParam Map<String, Object> params) {
|
||||
List<Map<String, Object>> data = screenStandardService.getWebTypeList(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "웹타입 목록을 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/screen-standard/web-types/categories
|
||||
* 웹타입 카테고리 목록 조회
|
||||
* NOTE: /web-types/{webType} 경로가 없으므로 순서 무관하지만 명확성을 위해 먼저 선언
|
||||
*/
|
||||
@GetMapping("/web-types/categories")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getWebTypeCategoryList() {
|
||||
List<Map<String, Object>> data = screenStandardService.getWebTypeCategoryList();
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "웹타입 카테고리 목록을 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/screen-standard/button-actions
|
||||
* 버튼 액션 목록 조회 (active / category / search 필터)
|
||||
*/
|
||||
@GetMapping("/button-actions")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getButtonActionList(
|
||||
@RequestParam Map<String, Object> params) {
|
||||
List<Map<String, Object>> data = screenStandardService.getButtonActionList(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "버튼 액션 목록을 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/screen-standard/button-actions/categories
|
||||
* 버튼 액션 카테고리 목록 조회
|
||||
*/
|
||||
@GetMapping("/button-actions/categories")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getButtonActionCategoryList() {
|
||||
List<Map<String, Object>> data = screenStandardService.getButtonActionCategoryList();
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "버튼 액션 카테고리 목록을 성공적으로 조회했습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.erp.controller;
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ShippingOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/shipping-order")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ShippingOrderController {
|
||||
private final ShippingOrderService shippingOrderService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getShippingOrderList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingOrderService.getShippingOrderList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getShippingOrderInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingOrderService.getShippingOrderInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertShippingOrder(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingOrderService.insertShippingOrder(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateShippingOrder(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingOrderService.updateShippingOrder(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteShippingOrder(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingOrderService.deleteShippingOrder(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.erp.controller;
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.ShippingPlanService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/shipping-plan")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ShippingPlanController {
|
||||
private final ShippingPlanService shippingPlanService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getShippingPlanList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingPlanService.getShippingPlanList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getShippingPlanInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingPlanService.getShippingPlanInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertShippingPlan(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingPlanService.insertShippingPlan(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateShippingPlan(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingPlanService.updateShippingPlan(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteShippingPlan(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(shippingPlanService.deleteShippingPlan(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.SystemNoticeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/system-notices")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class SystemNoticeController {
|
||||
|
||||
private final SystemNoticeService systemNoticeService;
|
||||
|
||||
/**
|
||||
* GET /api/system-notices
|
||||
* 공지사항 목록 조회
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getSystemNoticeList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
queryParams.put("companyCode", companyCode);
|
||||
List<Map<String, Object>> list = systemNoticeService.getSystemNoticeList(queryParams);
|
||||
return ResponseEntity.ok(ApiResponse.success(list));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/system-notices
|
||||
* 공지사항 등록
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertSystemNotice(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
|
||||
String title = (String) body.get("title");
|
||||
String content = (String) body.get("content");
|
||||
|
||||
if (title == null || title.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("제목을 입력해주세요."));
|
||||
}
|
||||
if (content == null || content.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("내용을 입력해주세요."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("createdBy", userId);
|
||||
|
||||
try {
|
||||
Map<String, Object> created = systemNoticeService.insertSystemNotice(params);
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(created, "공지사항이 등록되었습니다."));
|
||||
} catch (Exception e) {
|
||||
log.error("공지사항 등록 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("공지사항 등록 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/system-notices/:id
|
||||
* 공지사항 수정
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateSystemNotice(
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
String title = (String) body.get("title");
|
||||
String content = (String) body.get("content");
|
||||
|
||||
if (title == null || title.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("제목을 입력해주세요."));
|
||||
}
|
||||
if (content == null || content.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("내용을 입력해주세요."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>(body);
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
|
||||
try {
|
||||
Map<String, Object> updated = systemNoticeService.updateSystemNotice(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "공지사항이 수정되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("공지사항 수정 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("공지사항 수정 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/system-notices/:id
|
||||
* 공지사항 삭제
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteSystemNotice(
|
||||
@PathVariable Long id,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
params.put("companyCode", companyCode);
|
||||
|
||||
try {
|
||||
systemNoticeService.deleteSystemNotice(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "공지사항이 삭제되었습니다."));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("공지사항 삭제 실패: id={}", id, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("공지사항 삭제 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.TableCategoryValueService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/table-categories")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TableCategoryValueController {
|
||||
|
||||
private final TableCategoryValueService service;
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Category Columns
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/table-categories/all-columns */
|
||||
@GetMapping("/all-columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAllCategoryColumns(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getAllCategoryColumns(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("전체 카테고리 컬럼 조회 실패", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("전체 카테고리 컬럼 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** GET /api/table-categories/{tableName}/columns */
|
||||
@GetMapping("/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryColumns(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getCategoryColumns(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 컬럼 조회 실패: tableName={}", tableName, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("카테고리 컬럼 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Category Values — Read
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/table-categories/{tableName}/{columnName}/values */
|
||||
@GetMapping("/{tableName}/{columnName}/values")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryValues(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestParam(required = false) String menuObjid,
|
||||
@RequestParam(required = false, defaultValue = "false") boolean includeInactive,
|
||||
@RequestParam(required = false) String filterCompanyCode,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
// SUPER_ADMIN 이 특정 회사 기준 필터링 요청 시 해당 companyCode 사용
|
||||
String effectiveCompanyCode = ("*".equals(companyCode) && filterCompanyCode != null)
|
||||
? filterCompanyCode : companyCode;
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("columnName", columnName);
|
||||
params.put("companyCode", effectiveCompanyCode);
|
||||
params.put("includeInactive", includeInactive);
|
||||
if (menuObjid != null) params.put("menuObjid", Long.parseLong(menuObjid));
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getCategoryValues(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 조회 실패: tableName={}, columnName={}", tableName, columnName, e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("카테고리 값 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Category Values — Write
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** POST /api/table-categories/values */
|
||||
@PostMapping("/values")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> addCategoryValue(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
if (body.get("menuObjid") == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("menuObjid는 필수입니다"));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(service.addCategoryValue(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "카테고리 값 추가 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 추가 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 추가 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/table-categories/values/{valueId} */
|
||||
@PutMapping("/values/{valueId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateCategoryValue(
|
||||
@PathVariable Long valueId,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
body.put("valueId", valueId);
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.updateCategoryValue(body)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 수정 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 수정 실패: valueId={}", valueId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 수정 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/table-categories/values/{valueId} */
|
||||
@DeleteMapping("/values/{valueId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteCategoryValue(
|
||||
@PathVariable Long valueId,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("valueId", valueId);
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("userId", userId);
|
||||
try {
|
||||
service.deleteCategoryValue(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "카테고리 값이 삭제되었습니다"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
// 사용 중인 경우 400
|
||||
if (e.getMessage() != null && e.getMessage().contains("삭제할 수 없습니다")) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "카테고리 값 삭제 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 삭제 실패: valueId={}", valueId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/table-categories/values/bulk-delete */
|
||||
@PostMapping("/values/bulk-delete")
|
||||
public ResponseEntity<ApiResponse<Void>> bulkDeleteCategoryValues(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
Object rawIds = body.get("valueIds");
|
||||
if (!(rawIds instanceof List) || ((List<?>) rawIds).isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("삭제할 값 ID 목록이 필요합니다"));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
try {
|
||||
service.bulkDeleteCategoryValues(body);
|
||||
int count = ((List<?>) rawIds).size();
|
||||
return ResponseEntity.ok(
|
||||
ApiResponse.success(null, count + "개의 카테고리 값이 삭제되었습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 일괄 삭제 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 일괄 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/table-categories/values/reorder */
|
||||
@PostMapping("/values/reorder")
|
||||
public ResponseEntity<ApiResponse<Void>> reorderCategoryValues(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Object rawIds = body.get("orderedValueIds");
|
||||
if (!(rawIds instanceof List) || ((List<?>) rawIds).isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("순서 정보가 필요합니다"));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
service.reorderCategoryValues(body);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "카테고리 값 순서가 변경되었습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 값 순서 변경 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 순서 변경 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Labels by Codes
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** POST /api/table-categories/labels-by-codes */
|
||||
@PostMapping("/labels-by-codes")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getCategoryLabelsByCodes(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Object rawCodes = body.get("valueCodes");
|
||||
if (!(rawCodes instanceof List) || ((List<?>) rawCodes).isEmpty()) {
|
||||
return ResponseEntity.ok(ApiResponse.success(new java.util.LinkedHashMap<>()));
|
||||
}
|
||||
body.put("companyCode", companyCode);
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getCategoryLabelsByCodes(body)));
|
||||
} catch (Exception e) {
|
||||
log.error("카테고리 라벨 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("카테고리 라벨 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Second-Level Menus (NOTE: 리터럴 경로이므로 variable 경로보다 우선)
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/table-categories/second-level-menus */
|
||||
@GetMapping("/second-level-menus")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getSecondLevelMenus(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getSecondLevelMenus(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("2레벨 메뉴 목록 조회 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("2레벨 메뉴 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// Column Mapping
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
/** GET /api/table-categories/column-mapping/{tableName}/{menuObjid} */
|
||||
@GetMapping("/column-mapping/{tableName}/{menuObjid}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getColumnMapping(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable Long menuObjid,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("menuObjid", menuObjid);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getColumnMapping(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("컬럼 매핑 조회 실패: tableName={}, menuObjid={}", tableName, menuObjid, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("컬럼 매핑 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** GET /api/table-categories/logical-columns/{tableName}/{menuObjid} */
|
||||
@GetMapping("/logical-columns/{tableName}/{menuObjid}")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getLogicalColumns(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable Long menuObjid,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("menuObjid", menuObjid);
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getLogicalColumns(params)));
|
||||
} catch (Exception e) {
|
||||
log.error("논리적 컬럼 목록 조회 실패: tableName={}, menuObjid={}", tableName, menuObjid, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("논리적 컬럼 목록 조회 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/table-categories/column-mapping */
|
||||
@PostMapping("/column-mapping")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> createColumnMapping(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId) {
|
||||
String tableName = (String) body.get("tableName");
|
||||
String logicalColumnName = (String) body.get("logicalColumnName");
|
||||
String physicalColumnName = (String) body.get("physicalColumnName");
|
||||
Object menuObjid = body.get("menuObjid");
|
||||
|
||||
if (tableName == null || logicalColumnName == null
|
||||
|| physicalColumnName == null || menuObjid == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
"tableName, logicalColumnName, physicalColumnName, menuObjid는 필수입니다"));
|
||||
}
|
||||
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("userId", userId);
|
||||
// menuObjid를 Long으로 보장
|
||||
body.put("menuObjid", toLong(menuObjid));
|
||||
|
||||
try {
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(ApiResponse.success(service.createColumnMapping(body), "컬럼 매핑이 생성되었습니다"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "컬럼 매핑 생성 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("컬럼 매핑 생성 실패", e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("컬럼 매핑 생성 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/table-categories/column-mapping/{tableName}/{columnName}/all
|
||||
* NOTE: 3-segment 경로이므로 /{mappingId} 1-segment 경로보다 Spring이 우선 매핑.
|
||||
*/
|
||||
@DeleteMapping("/column-mapping/{tableName}/{columnName}/all")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteColumnMappingsByColumn(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("columnName", columnName);
|
||||
params.put("companyCode", companyCode);
|
||||
int deleted = service.deleteColumnMappingsByColumn(params);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("deletedCount", deleted);
|
||||
return ResponseEntity.ok(ApiResponse.success(data,
|
||||
deleted + "개의 컬럼 매핑이 삭제되었습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("테이블+컬럼 기준 매핑 삭제 실패: tableName={}, columnName={}", tableName, columnName, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("컬럼 매핑 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
/** DELETE /api/table-categories/column-mapping/{mappingId} */
|
||||
@DeleteMapping("/column-mapping/{mappingId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteColumnMapping(
|
||||
@PathVariable Long mappingId,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("mappingId", mappingId);
|
||||
params.put("companyCode", companyCode);
|
||||
try {
|
||||
service.deleteColumnMapping(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "컬럼 매핑이 삭제되었습니다"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(
|
||||
e.getMessage() != null ? e.getMessage() : "컬럼 매핑 삭제 중 오류가 발생했습니다"));
|
||||
} catch (Exception e) {
|
||||
log.error("컬럼 매핑 삭제 실패: mappingId={}", mappingId, e);
|
||||
return ResponseEntity.status(500).body(ApiResponse.error("컬럼 매핑 삭제 중 오류가 발생했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// ── private util ───────────────────────────────────────────────
|
||||
|
||||
private long toLong(Object val) {
|
||||
if (val == null) return 0L;
|
||||
if (val instanceof Number) return ((Number) val).longValue();
|
||||
try { return Long.parseLong(val.toString()); } catch (NumberFormatException e) { return 0L; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.TableHistoryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 테이블 이력 조회 컨트롤러
|
||||
* Node: tableHistoryRoutes.ts + tableHistoryController.ts
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/table-history")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TableHistoryController {
|
||||
|
||||
private final TableHistoryService tableHistoryService;
|
||||
|
||||
/**
|
||||
* GET /api/table-history/{tableName}/check
|
||||
* 이력 테이블 존재 여부 확인
|
||||
*/
|
||||
@GetMapping("/{tableName}/check")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkHistoryTableExists(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName) {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("companyCode", companyCode);
|
||||
|
||||
Map<String, Object> data = tableHistoryService.checkHistoryTableExists(params);
|
||||
String message = (String) data.remove("_message");
|
||||
return ResponseEntity.ok(ApiResponse.success(data, message));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/table-history/{tableName}/summary
|
||||
* 테이블 전체 이력 요약 (operation_type별 집계)
|
||||
*/
|
||||
@GetMapping("/{tableName}/summary")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableHistorySummary(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName) {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("companyCode", companyCode);
|
||||
|
||||
try {
|
||||
List<Map<String, Object>> data = tableHistoryService.getTableHistorySummary(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "이력 요약 조회 성공"));
|
||||
} catch (RuntimeException e) {
|
||||
if ("TABLE_NOT_FOUND".equals(e.getMessage())) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("이력 테이블이 존재하지 않습니다."));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/table-history/{tableName}/all
|
||||
* 전체 테이블 이력 조회 (레코드 ID 없이)
|
||||
*/
|
||||
@GetMapping("/{tableName}/all")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getAllTableHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
|
||||
queryParams.put("tableName", tableName);
|
||||
queryParams.put("companyCode", companyCode);
|
||||
|
||||
try {
|
||||
Map<String, Object> data = tableHistoryService.getAllTableHistory(queryParams);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "전체 테이블 이력 조회 성공"));
|
||||
} catch (RuntimeException e) {
|
||||
if ("TABLE_NOT_FOUND".equals(e.getMessage())) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("이력 테이블이 존재하지 않습니다."));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/table-history/{tableName}/{recordId}/timeline
|
||||
* 특정 레코드 변경 타임라인 조회 (동일 시간대 그룹화)
|
||||
*/
|
||||
@GetMapping("/{tableName}/{recordId}/timeline")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getRecordTimeline(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String recordId) {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("tableName", tableName);
|
||||
params.put("recordId", recordId);
|
||||
params.put("companyCode", companyCode);
|
||||
|
||||
try {
|
||||
List<Map<String, Object>> data = tableHistoryService.getRecordTimeline(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "타임라인 조회 성공"));
|
||||
} catch (RuntimeException e) {
|
||||
if ("TABLE_NOT_FOUND".equals(e.getMessage())) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("이력 테이블이 존재하지 않습니다."));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/table-history/{tableName}/{recordId}
|
||||
* 특정 레코드 변경 이력 상세 조회
|
||||
*/
|
||||
@GetMapping("/{tableName}/{recordId}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getRecordHistory(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String recordId,
|
||||
@RequestParam Map<String, Object> queryParams) {
|
||||
|
||||
queryParams.put("tableName", tableName);
|
||||
queryParams.put("recordId", recordId);
|
||||
queryParams.put("companyCode", companyCode);
|
||||
|
||||
try {
|
||||
Map<String, Object> data = tableHistoryService.getRecordHistory(queryParams);
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "이력 조회 성공"));
|
||||
} catch (RuntimeException e) {
|
||||
if ("TABLE_NOT_FOUND".equals(e.getMessage())) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error(
|
||||
"이력 테이블이 존재하지 않습니다. 테이블 타입 관리에서 이력 관리를 활성화해주세요."));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.TableManagementService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/table-management")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TableManagementController {
|
||||
|
||||
private final TableManagementService tableManagementService;
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 테이블 목록
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/tables */
|
||||
@GetMapping("/tables")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableList() {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getTableList(), "테이블 목록을 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 엔티티 관계 (literal segment이 path variable보다 우선)
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/tables/entity-relations */
|
||||
@GetMapping("/tables/entity-relations")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableEntityRelations(
|
||||
@RequestParam String leftTable,
|
||||
@RequestParam String rightTable,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getTableEntityRelations(leftTable, rightTable, companyCode)));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 컬럼 목록
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/columns */
|
||||
@GetMapping("/tables/{tableName}/columns")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getColumnList(
|
||||
@PathVariable String tableName,
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "50") int size,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getColumnList(tableName, page, size, companyCode),
|
||||
"컬럼 목록을 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 테이블 라벨
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/labels */
|
||||
@GetMapping("/tables/{tableName}/labels")
|
||||
public ResponseEntity<ApiResponse<Object>> getTableLabels(@PathVariable String tableName) {
|
||||
Map<String, Object> labels = tableManagementService.getTableLabels(tableName);
|
||||
Object data = labels != null ? labels : Map.of();
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "테이블 라벨 정보를 조회했습니다."));
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/label */
|
||||
@PutMapping("/tables/{tableName}/label")
|
||||
public ResponseEntity<ApiResponse<Void>> updateTableLabel(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String displayName = (String) body.get("displayName");
|
||||
String description = (String) body.get("description");
|
||||
if (displayName == null || displayName.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("표시명이 필요합니다."));
|
||||
}
|
||||
tableManagementService.updateTableLabel(tableName, displayName, description);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "테이블 라벨이 성공적으로 설정되었습니다."));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 컬럼 설정
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/columns/:columnName/labels */
|
||||
@GetMapping("/tables/{tableName}/columns/{columnName}/labels")
|
||||
public ResponseEntity<ApiResponse<Object>> getColumnLabels(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName) {
|
||||
Map<String, Object> labels = tableManagementService.getColumnLabels(tableName, columnName);
|
||||
Object data = labels != null ? labels : Map.of();
|
||||
return ResponseEntity.ok(ApiResponse.success(data, "컬럼 라벨 정보를 조회했습니다."));
|
||||
}
|
||||
|
||||
/** POST /api/table-management/tables/:tableName/columns/:columnName/settings */
|
||||
@PostMapping("/tables/{tableName}/columns/{columnName}/settings")
|
||||
public ResponseEntity<ApiResponse<Void>> updateColumnSettingsPost(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestBody Map<String, Object> settings,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return doUpdateColumnSettings(tableName, columnName, settings, companyCode);
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/columns/:columnName */
|
||||
@PutMapping("/tables/{tableName}/columns/{columnName}")
|
||||
public ResponseEntity<ApiResponse<Void>> updateColumnSettingsPut(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestBody Map<String, Object> settings,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return doUpdateColumnSettings(tableName, columnName, settings, companyCode);
|
||||
}
|
||||
|
||||
private ResponseEntity<ApiResponse<Void>> doUpdateColumnSettings(
|
||||
String tableName, String columnName, Map<String, Object> settings, String companyCode) {
|
||||
if (tableName == null || columnName == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("테이블명과 컬럼명이 필요합니다."));
|
||||
}
|
||||
if (settings == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("컬럼 설정 정보가 필요합니다."));
|
||||
}
|
||||
tableManagementService.updateColumnSettings(tableName, columnName, settings, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "컬럼 설정을 성공적으로 저장했습니다."));
|
||||
}
|
||||
|
||||
/** POST /api/table-management/tables/:tableName/columns/settings (batch) */
|
||||
@PostMapping("/tables/{tableName}/columns/settings")
|
||||
public ResponseEntity<ApiResponse<Void>> updateAllColumnSettingsPost(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody List<Map<String, Object>> columnSettings,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return doUpdateAllColumnSettings(tableName, columnSettings, companyCode);
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/columns/batch */
|
||||
@PutMapping("/tables/{tableName}/columns/batch")
|
||||
public ResponseEntity<ApiResponse<Void>> updateAllColumnSettingsBatch(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody List<Map<String, Object>> columnSettings,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return doUpdateAllColumnSettings(tableName, columnSettings, companyCode);
|
||||
}
|
||||
|
||||
private ResponseEntity<ApiResponse<Void>> doUpdateAllColumnSettings(
|
||||
String tableName, List<Map<String, Object>> columnSettings, String companyCode) {
|
||||
if (tableName == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("테이블명이 필요합니다."));
|
||||
}
|
||||
if (columnSettings == null || columnSettings.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("컬럼 설정 목록이 필요합니다."));
|
||||
}
|
||||
tableManagementService.updateAllColumnSettings(tableName, columnSettings, companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "모든 컬럼 설정을 성공적으로 저장했습니다."));
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/columns/:columnName/web-type */
|
||||
@PutMapping("/tables/{tableName}/columns/{columnName}/web-type")
|
||||
public ResponseEntity<ApiResponse<Void>> updateColumnWebType(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String webType = (String) body.get("webType");
|
||||
if (webType == null || webType.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("웹 타입이 필요합니다."));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> detailSettings = (Map<String, Object>) body.get("detailSettings");
|
||||
tableManagementService.updateColumnWebType(tableName, columnName, webType, detailSettings);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "컬럼 웹타입이 설정되었습니다."));
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/columns/:columnName/input-type */
|
||||
@PutMapping("/tables/{tableName}/columns/{columnName}/input-type")
|
||||
public ResponseEntity<ApiResponse<Void>> updateColumnInputType(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
String inputType = (String) body.get("inputType");
|
||||
if (tableName == null || columnName == null || inputType == null || inputType.isBlank()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("테이블명, 컬럼명, 입력 타입이 모두 필요합니다."));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> detailSettings = (Map<String, Object>) body.get("detailSettings");
|
||||
tableManagementService.updateColumnInputType(tableName, columnName, inputType, companyCode, detailSettings);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "컬럼 입력 타입이 성공적으로 설정되었습니다."));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 테이블 스키마 / 존재 여부 / 웹타입
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/schema */
|
||||
@GetMapping("/tables/{tableName}/schema")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTableSchema(
|
||||
@PathVariable String tableName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getTableSchema(tableName),
|
||||
"테이블 스키마 정보를 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/exists */
|
||||
@GetMapping("/tables/{tableName}/exists")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkTableExists(
|
||||
@PathVariable String tableName) {
|
||||
boolean exists = tableManagementService.checkTableExists(tableName);
|
||||
return ResponseEntity.ok(ApiResponse.success(Map.of("exists", exists), "테이블 존재 여부를 확인했습니다."));
|
||||
}
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/web-types */
|
||||
@GetMapping("/tables/{tableName}/web-types")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getColumnWebTypes(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getColumnInputTypes(tableName, companyCode),
|
||||
"컬럼 입력타입 정보를 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 제약조건 관리
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/constraints */
|
||||
@GetMapping("/tables/{tableName}/constraints")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableConstraints(
|
||||
@PathVariable String tableName) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getTableConstraints(tableName)));
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/primary-key */
|
||||
@PutMapping("/tables/{tableName}/primary-key")
|
||||
public ResponseEntity<ApiResponse<Void>> setTablePrimaryKey(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> columns = (List<String>) body.get("columns");
|
||||
if (tableName == null || columns == null || columns.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("테이블명과 PK 컬럼 배열이 필요합니다."));
|
||||
}
|
||||
tableManagementService.setTablePrimaryKey(tableName, columns);
|
||||
return ResponseEntity.ok(ApiResponse.success(null,
|
||||
"PK가 설정되었습니다: " + String.join(", ", columns)));
|
||||
}
|
||||
|
||||
/** POST /api/table-management/tables/:tableName/indexes */
|
||||
@PostMapping("/tables/{tableName}/indexes")
|
||||
public ResponseEntity<ApiResponse<Void>> toggleTableIndex(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String columnName = (String) body.get("columnName");
|
||||
String indexType = (String) body.get("indexType");
|
||||
String action = (String) body.get("action");
|
||||
if (tableName == null || columnName == null || indexType == null || action == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
"tableName, columnName, indexType(index|unique), action(create|drop)이 필요합니다."));
|
||||
}
|
||||
try {
|
||||
tableManagementService.toggleTableIndex(tableName, columnName, indexType, action);
|
||||
String msg = "create".equals(action)
|
||||
? "인덱스가 생성되었습니다."
|
||||
: "인덱스가 삭제되었습니다.";
|
||||
return ResponseEntity.ok(ApiResponse.success(null, msg));
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/columns/:columnName/nullable */
|
||||
@PutMapping("/tables/{tableName}/columns/{columnName}/nullable")
|
||||
public ResponseEntity<ApiResponse<Void>> toggleColumnNullable(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Object nullableObj = body.get("nullable");
|
||||
if (tableName == null || columnName == null || !(nullableObj instanceof Boolean)) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("tableName, columnName, nullable(boolean)이 필요합니다."));
|
||||
}
|
||||
boolean nullable = (Boolean) nullableObj;
|
||||
tableManagementService.toggleColumnNullable(tableName, columnName, nullable, companyCode);
|
||||
String msg = nullable ? columnName + " 컬럼의 NOT NULL 제약이 해제되었습니다."
|
||||
: columnName + " 컬럼이 NOT NULL로 설정되었습니다.";
|
||||
return ResponseEntity.ok(ApiResponse.success(null, msg));
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/columns/:columnName/unique */
|
||||
@PutMapping("/tables/{tableName}/columns/{columnName}/unique")
|
||||
public ResponseEntity<ApiResponse<Void>> toggleColumnUnique(
|
||||
@PathVariable String tableName,
|
||||
@PathVariable String columnName,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
Object uniqueObj = body.get("unique");
|
||||
if (tableName == null || columnName == null || !(uniqueObj instanceof Boolean)) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("tableName, columnName, unique(boolean)이 필요합니다."));
|
||||
}
|
||||
boolean unique = (Boolean) uniqueObj;
|
||||
tableManagementService.toggleColumnUnique(tableName, columnName, unique, companyCode);
|
||||
String msg = unique ? columnName + " 컬럼이 UNIQUE로 설정되었습니다."
|
||||
: columnName + " 컬럼의 UNIQUE 제약이 해제되었습니다.";
|
||||
return ResponseEntity.ok(ApiResponse.success(null, msg));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 데이터 CRUD
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** POST /api/table-management/tables/:tableName/data */
|
||||
@PostMapping("/tables/{tableName}/data")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableData(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> options) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getTableData(tableName, options),
|
||||
"테이블 데이터를 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/** POST /api/table-management/tables/:tableName/record (단일 레코드) */
|
||||
@PostMapping("/tables/{tableName}/record")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTableRecord(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
String filterColumn = (String) body.get("filterColumn");
|
||||
Object filterValue = body.get("filterValue");
|
||||
String displayColumn = (String) body.get("displayColumn");
|
||||
|
||||
if (filterColumn == null || filterValue == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
"tableName, filterColumn, filterValue가 필요합니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> options = new java.util.HashMap<>();
|
||||
options.put("page", 1);
|
||||
options.put("size", 1);
|
||||
options.put("search", Map.of(filterColumn, filterValue.toString()));
|
||||
|
||||
Map<String, Object> result = tableManagementService.getTableData(tableName, options);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.get("data");
|
||||
|
||||
if (data == null || data.isEmpty()) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("데이터를 찾을 수 없습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> record = data.get(0);
|
||||
Object displayValue = (displayColumn != null && !displayColumn.equals("*"))
|
||||
? record.get(displayColumn) : record;
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
Map.of("value", displayValue != null ? displayValue : "", "record", record),
|
||||
"레코드를 성공적으로 조회했습니다."));
|
||||
}
|
||||
|
||||
/** POST /api/table-management/tables/:tableName/add */
|
||||
@PostMapping("/tables/{tableName}/add")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> addTableData(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> data,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
if (data == null || data.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("추가할 데이터가 필요합니다."));
|
||||
}
|
||||
|
||||
// 멀티테넌시: company_code 자동 추가
|
||||
if (!data.containsKey("company_code") && tableManagementService.hasColumn(tableName, "company_code")) {
|
||||
data.put("company_code", companyCode);
|
||||
}
|
||||
|
||||
// 소프트 제약조건 검증
|
||||
List<String> notNullViolations = tableManagementService.validateNotNullConstraints(tableName, data, companyCode);
|
||||
if (!notNullViolations.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
"필수 항목이 비어있습니다: " + String.join(", ", notNullViolations)));
|
||||
}
|
||||
List<String> uniqueViolations = tableManagementService.validateUniqueConstraints(tableName, data, companyCode, null);
|
||||
if (!uniqueViolations.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
"중복된 값이 존재합니다: " + String.join(", ", uniqueViolations)));
|
||||
}
|
||||
|
||||
Map<String, Object> result = tableManagementService.addTableData(tableName, data);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(
|
||||
Map.of("id", result.getOrDefault("insertedId", "")),
|
||||
"테이블 데이터를 성공적으로 추가했습니다."));
|
||||
}
|
||||
|
||||
/** PUT /api/table-management/tables/:tableName/edit */
|
||||
@PutMapping("/tables/{tableName}/edit")
|
||||
public ResponseEntity<ApiResponse<Void>> editTableData(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> originalData = (Map<String, Object>) body.get("originalData");
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> updatedData = (Map<String, Object>) body.get("updatedData");
|
||||
|
||||
if (originalData == null || updatedData == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("원본 데이터와 수정할 데이터가 모두 필요합니다."));
|
||||
}
|
||||
if (updatedData.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("수정할 데이터가 없습니다."));
|
||||
}
|
||||
|
||||
// 소프트 제약조건 검증
|
||||
List<String> notNullViolations = tableManagementService.validateNotNullConstraints(tableName, updatedData, companyCode);
|
||||
if (!notNullViolations.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
"필수 항목이 비어있습니다: " + String.join(", ", notNullViolations)));
|
||||
}
|
||||
String excludeId = originalData.get("id") != null ? originalData.get("id").toString() : null;
|
||||
List<String> uniqueViolations = tableManagementService.validateUniqueConstraints(tableName, updatedData, companyCode, excludeId);
|
||||
if (!uniqueViolations.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error(
|
||||
"중복된 값이 존재합니다: " + String.join(", ", uniqueViolations)));
|
||||
}
|
||||
|
||||
tableManagementService.editTableData(tableName, originalData, updatedData);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "테이블 데이터를 성공적으로 수정했습니다."));
|
||||
}
|
||||
|
||||
/** DELETE /api/table-management/tables/:tableName/delete */
|
||||
@DeleteMapping("/tables/{tableName}/delete")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteTableData(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Object body) {
|
||||
List<Map<String, Object>> dataList;
|
||||
if (body instanceof List) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> cast = (List<Map<String, Object>>) body;
|
||||
dataList = cast;
|
||||
} else {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("삭제할 데이터가 필요합니다."));
|
||||
}
|
||||
if (dataList.isEmpty()) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("삭제할 데이터가 필요합니다."));
|
||||
}
|
||||
tableManagementService.deleteTableData(tableName, dataList);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "테이블 데이터를 성공적으로 삭제했습니다."));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 로그 관리
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** POST /api/table-management/tables/:tableName/log */
|
||||
@PostMapping("/tables/{tableName}/log")
|
||||
public ResponseEntity<ApiResponse<Void>> createLogTable(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> logColumns = (List<String>) body.get("logColumns");
|
||||
boolean isActive = Boolean.TRUE.equals(body.get("isActive"));
|
||||
tableManagementService.createLogTable(tableName, logColumns, isActive);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "로그 테이블이 생성되었습니다."));
|
||||
}
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/log/config */
|
||||
@GetMapping("/tables/{tableName}/log/config")
|
||||
public ResponseEntity<ApiResponse<Object>> getLogConfig(@PathVariable String tableName) {
|
||||
Map<String, Object> config = tableManagementService.getLogConfig(tableName);
|
||||
Object data = config != null ? config : Map.of();
|
||||
return ResponseEntity.ok(ApiResponse.success(data));
|
||||
}
|
||||
|
||||
/** GET /api/table-management/tables/:tableName/log */
|
||||
@GetMapping("/tables/{tableName}/log")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getLogData(
|
||||
@PathVariable String tableName,
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "50") int size) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getLogData(tableName, page, size)));
|
||||
}
|
||||
|
||||
/** POST /api/table-management/tables/:tableName/log/toggle */
|
||||
@PostMapping("/tables/{tableName}/log/toggle")
|
||||
public ResponseEntity<ApiResponse<Void>> toggleLogTable(
|
||||
@PathVariable String tableName,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
boolean isActive = Boolean.TRUE.equals(body.get("isActive"));
|
||||
tableManagementService.toggleLogTable(tableName, isActive);
|
||||
return ResponseEntity.ok(ApiResponse.success(null,
|
||||
isActive ? "로그가 활성화되었습니다." : "로그가 비활성화되었습니다."));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 카테고리 / 채번 컬럼
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/category-columns */
|
||||
@GetMapping("/category-columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryColumnsByCompany(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getCategoryColumnsByCompany(companyCode)));
|
||||
}
|
||||
|
||||
/** GET /api/table-management/numbering-columns */
|
||||
@GetMapping("/numbering-columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getNumberingColumnsByCompany(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getNumberingColumnsByCompany(companyCode)));
|
||||
}
|
||||
|
||||
/** GET /api/table-management/menu/:menuObjid/category-columns */
|
||||
@GetMapping("/menu/{menuObjid}/category-columns")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getCategoryColumnsByMenu(
|
||||
@PathVariable String menuObjid,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getCategoryColumnsByMenu(companyCode, menuObjid)));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 현재 테이블을 참조하는 테이블
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/columns/:tableName/referenced-by */
|
||||
@GetMapping("/columns/{tableName}/referenced-by")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getReferencedByTables(
|
||||
@PathVariable String tableName,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.getReferencedByTables(tableName, companyCode)));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// 다중 테이블 저장 / 엑셀 검증
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** POST /api/table-management/multi-table-save */
|
||||
@PostMapping("/multi-table-save")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> multiTableSave(
|
||||
@RequestBody Map<String, Object> payload,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.multiTableSave(payload, companyCode),
|
||||
"다중 테이블 저장이 완료되었습니다."));
|
||||
}
|
||||
|
||||
/** POST /api/table-management/validate-excel */
|
||||
@PostMapping("/validate-excel")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> validateExcelData(
|
||||
@RequestBody Map<String, Object> body,
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
String tableName = (String) body.get("tableName");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> rows = (List<Map<String, Object>>) body.get("rows");
|
||||
if (tableName == null || rows == null) {
|
||||
return ResponseEntity.status(400).body(ApiResponse.error("tableName과 rows가 필요합니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.validateExcelData(tableName, rows, companyCode)));
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// DB 헬스체크
|
||||
// ──────────────────────────────────────────────────────────
|
||||
|
||||
/** GET /api/table-management/health */
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> checkDatabaseConnection() {
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
tableManagementService.checkDatabaseConnection(), "데이터베이스 연결 상태를 확인했습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.TaxInvoiceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/tax-invoice")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TaxInvoiceController {
|
||||
|
||||
private final TaxInvoiceService taxInvoiceService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTaxInvoiceList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
params.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(taxInvoiceService.getTaxInvoiceList(params)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTaxInvoiceInfo(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(taxInvoiceService.getTaxInvoiceInfo(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertTaxInvoice(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(taxInvoiceService.insertTaxInvoice(body)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateTaxInvoice(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("companyCode", companyCode);
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(taxInvoiceService.updateTaxInvoice(body)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteTaxInvoice(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@PathVariable Long id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("companyCode", companyCode);
|
||||
params.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(taxInvoiceService.deleteTaxInvoice(params)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.TemplateStandardService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/template-standards")
|
||||
@RequiredArgsConstructor
|
||||
public class TemplateStandardController {
|
||||
|
||||
private final TemplateStandardService templateStandardService;
|
||||
|
||||
/**
|
||||
* GET /api/admin/template-standards
|
||||
* 템플릿 목록 조회 (페이지네이션)
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<Map<String, Object>> getTemplateStandardList(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
|
||||
params.putIfAbsent("companyCode", companyCode);
|
||||
|
||||
Map<String, Object> result = templateStandardService.getTemplateStandardList(params);
|
||||
|
||||
int total = ((Number) result.get("total")).intValue();
|
||||
int page = ((Number) result.get("page")).intValue();
|
||||
int limit = ((Number) result.get("limit")).intValue();
|
||||
|
||||
Map<String, Object> pagination = new LinkedHashMap<>();
|
||||
pagination.put("total", total);
|
||||
pagination.put("page", page);
|
||||
pagination.put("limit", limit);
|
||||
pagination.put("totalPages", (int) Math.ceil((double) total / limit));
|
||||
|
||||
Map<String, Object> response = new LinkedHashMap<>();
|
||||
response.put("success", true);
|
||||
response.put("data", result.get("templates"));
|
||||
response.put("pagination", pagination);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/template-standards/categories
|
||||
* 템플릿 카테고리 목록 조회
|
||||
*/
|
||||
@GetMapping("/categories")
|
||||
public ResponseEntity<ApiResponse<List<String>>> getTemplateStandardCategoryList(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
|
||||
List<String> categories = templateStandardService.getTemplateStandardCategoryList(companyCode);
|
||||
return ResponseEntity.ok(ApiResponse.success(categories));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/template-standards/sort-order/bulk
|
||||
* 템플릿 정렬 순서 일괄 업데이트
|
||||
*/
|
||||
@PutMapping("/sort-order/bulk")
|
||||
public ResponseEntity<ApiResponse<Void>> updateTemplateStandardSortOrder(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
Object raw = body.get("templates");
|
||||
if (!(raw instanceof List)) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("templates는 배열이어야 합니다."));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> templates = (List<Map<String, Object>>) raw;
|
||||
templateStandardService.updateTemplateStandardSortOrder(templates);
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "템플릿 정렬 순서가 성공적으로 업데이트되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/template-standards/import
|
||||
* 템플릿 가져오기 (JSON에서)
|
||||
*/
|
||||
@PostMapping("/import")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> importTemplateStandard(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("layout_config") == null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.error("유효한 템플릿 데이터가 아닙니다."));
|
||||
}
|
||||
|
||||
body.put("company_code", companyCode);
|
||||
body.put("created_by", userId);
|
||||
body.put("updated_by", userId);
|
||||
|
||||
Map<String, Object> created = templateStandardService.insertTemplateStandard(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(created, "템플릿이 성공적으로 가져왔습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/template-standards/{templateCode}
|
||||
* 템플릿 상세 조회
|
||||
*/
|
||||
@GetMapping("/{templateCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTemplateStandardInfo(
|
||||
@PathVariable String templateCode) {
|
||||
|
||||
Map<String, Object> template = templateStandardService.getTemplateStandardInfo(templateCode);
|
||||
if (template == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("템플릿을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(template));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/admin/template-standards/{templateCode}/export
|
||||
* 템플릿 내보내기 (메타데이터 제외 서브셋)
|
||||
*/
|
||||
@GetMapping("/{templateCode}/export")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> exportTemplateStandard(
|
||||
@PathVariable String templateCode) {
|
||||
|
||||
Map<String, Object> template = templateStandardService.getTemplateStandardInfo(templateCode);
|
||||
if (template == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("템플릿을 찾을 수 없습니다."));
|
||||
}
|
||||
|
||||
// DB 결과는 camelCase (map-underscore-to-camel-case: true)
|
||||
// 응답은 Node.js 호환을 위해 snake_case 키 사용
|
||||
Map<String, Object> exportData = new LinkedHashMap<>();
|
||||
exportData.put("template_code", template.get("templateCode"));
|
||||
exportData.put("template_name", template.get("templateName"));
|
||||
exportData.put("template_name_eng", template.get("templateNameEng"));
|
||||
exportData.put("description", template.get("description"));
|
||||
exportData.put("category", template.get("category"));
|
||||
exportData.put("icon_name", template.get("iconName"));
|
||||
exportData.put("default_size", template.get("defaultSize"));
|
||||
exportData.put("layout_config", template.get("layoutConfig"));
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(exportData));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/template-standards
|
||||
* 템플릿 생성
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertTemplateStandard(
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
if (body.get("template_code") == null || body.get("template_name") == null
|
||||
|| body.get("category") == null || body.get("layout_config") == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error(
|
||||
"필수 필드가 누락되었습니다. (template_code, template_name, category, layout_config)"));
|
||||
}
|
||||
|
||||
body.put("company_code", companyCode);
|
||||
body.put("created_by", userId);
|
||||
body.put("updated_by", userId);
|
||||
|
||||
Map<String, Object> created = templateStandardService.insertTemplateStandard(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(created, "템플릿이 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/template-standards/{templateCode}
|
||||
* 템플릿 수정
|
||||
*/
|
||||
@PutMapping("/{templateCode}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateTemplateStandard(
|
||||
@PathVariable String templateCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
body.put("updated_by", userId);
|
||||
Map<String, Object> updated = templateStandardService.updateTemplateStandard(templateCode, body);
|
||||
if (updated == null) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("템플릿을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(updated, "템플릿이 성공적으로 수정되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/admin/template-standards/{templateCode}
|
||||
* 템플릿 삭제
|
||||
*/
|
||||
@DeleteMapping("/{templateCode}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteTemplateStandard(
|
||||
@PathVariable String templateCode) {
|
||||
|
||||
boolean deleted = templateStandardService.deleteTemplateStandard(templateCode);
|
||||
if (!deleted) {
|
||||
return ResponseEntity.status(404).body(ApiResponse.error("템플릿을 찾을 수 없습니다."));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "템플릿이 성공적으로 삭제되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/admin/template-standards/{templateCode}/duplicate
|
||||
* 템플릿 복제
|
||||
*/
|
||||
@PostMapping("/{templateCode}/duplicate")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> duplicateTemplateStandard(
|
||||
@PathVariable String templateCode,
|
||||
@RequestAttribute("companyCode") String companyCode,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
|
||||
String newTemplateCode = (String) body.get("new_template_code");
|
||||
String newTemplateName = (String) body.get("new_template_name");
|
||||
|
||||
if (newTemplateCode == null || newTemplateName == null) {
|
||||
return ResponseEntity.badRequest().body(ApiResponse.error("필수 필드가 누락되었습니다."));
|
||||
}
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("originalCode", templateCode);
|
||||
params.put("newCode", newTemplateCode);
|
||||
params.put("newName", newTemplateName);
|
||||
params.put("company_code", companyCode);
|
||||
params.put("created_by", userId);
|
||||
|
||||
Map<String, Object> duplicated = templateStandardService.duplicateTemplateStandard(params);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(duplicated, "템플릿이 성공적으로 복제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.TestButtonDataflowService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Test Button Dataflow Controller — 추가 엔드포인트
|
||||
*
|
||||
* testButtonDataflowRoutes.ts 에서 buttonDataflowRoutes 에 없는
|
||||
* 두 가지 추가 엔드포인트만 담당한다:
|
||||
*
|
||||
* GET /api/test-button-dataflow/relationships/all — 버튼 제어용 전체 관계 목록
|
||||
* GET /api/test-button-dataflow/test-status — 테스트 모드 상태 확인
|
||||
*
|
||||
* 나머지 엔드포인트(config, diagrams, execute-*, job-status 등)는
|
||||
* ButtonDataflowController 가 동일 기본 경로에서 처리한다.
|
||||
* Spring MVC 는 @RequestMapping 이 같아도 개별 @GetMapping 경로가 다르면 정상 동작한다.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/test-button-dataflow")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TestButtonDataflowController {
|
||||
|
||||
private final TestButtonDataflowService service;
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /relationships/all
|
||||
// Node.js: router.get("/relationships/all", getAllRelationships)
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/relationships/all")
|
||||
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getAllRelationships(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
try {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getAllRelationships(companyCode)));
|
||||
} catch (Exception e) {
|
||||
log.error("전체 관계 목록 조회 오류", e);
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("전체 관계 목록 조회 중 오류가 발생했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// GET /test-status
|
||||
// Node.js: router.get("/test-status", (req, res) => res.json({...}))
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/test-status")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTestStatus(
|
||||
@RequestAttribute("companyCode") String companyCode) {
|
||||
return ResponseEntity.ok(ApiResponse.success(service.getTestStatus(companyCode)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.erp.controller;
|
||||
|
||||
import com.erp.dto.ApiResponse;
|
||||
import com.erp.service.TodoService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/todo")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TodoController {
|
||||
|
||||
private final TodoService todoService;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTodoList(
|
||||
@RequestParam Map<String, Object> params) {
|
||||
return ResponseEntity.ok(ApiResponse.success(todoService.getTodoList(params)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> insertTodo(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Map<String, Object> result = todoService.insertTodo(body);
|
||||
return ResponseEntity.status(201).body(ApiResponse.success(result, "To-Do가 생성되었습니다."));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> updateTodo(
|
||||
@PathVariable String id,
|
||||
@RequestBody Map<String, Object> body) {
|
||||
body.put("id", id);
|
||||
return ResponseEntity.ok(ApiResponse.success(todoService.updateTodo(body), "To-Do가 수정되었습니다."));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> deleteTodo(
|
||||
@PathVariable String id) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", id);
|
||||
todoService.deleteTodo(params);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "To-Do가 삭제되었습니다."));
|
||||
}
|
||||
|
||||
@PostMapping("/reorder")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> reorderTodos(
|
||||
@RequestBody Map<String, Object> body) {
|
||||
Object todoIdsObj = body.get("todoIds");
|
||||
if (!(todoIdsObj instanceof List)) {
|
||||
return ResponseEntity.status(400).body(
|
||||
ApiResponse.error("todoIds는 배열이어야 합니다."));
|
||||
}
|
||||
List<String> todoIds = new ArrayList<>();
|
||||
for (Object id : (List<?>) todoIdsObj) {
|
||||
todoIds.add(String.valueOf(id));
|
||||
}
|
||||
todoService.reorderTodos(todoIds);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "To-Do 순서가 변경되었습니다."));
|
||||
}
|
||||
|
||||
// 이전 호환
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> getTodoListLegacy(
|
||||
@RequestParam Map<String, Object> params) {
|
||||
return ResponseEntity.ok(ApiResponse.success(todoService.getTodoList(params)));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user