diff --git a/WebContent/WEB-INF/view/approval/amaranthApprovalDetail.jsp b/WebContent/WEB-INF/view/approval/amaranthApprovalDetail.jsp
new file mode 100644
index 0000000..b90705e
--- /dev/null
+++ b/WebContent/WEB-INF/view/approval/amaranthApprovalDetail.jsp
@@ -0,0 +1,247 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<%@ page import="com.pms.common.utils.*"%>
+<%@ page import="java.util.*" %>
+<%@include file= "/init.jsp" %>
+
+
+
+
+<%=Constants.SYSTEM_NAME%> - 결재 문서 상세
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WebContent/WEB-INF/view/approval/approvalList.jsp b/WebContent/WEB-INF/view/approval/approvalList.jsp
index 71cb689..be4d6c3 100644
--- a/WebContent/WEB-INF/view/approval/approvalList.jsp
+++ b/WebContent/WEB-INF/view/approval/approvalList.jsp
@@ -8,58 +8,159 @@
<%=Constants.SYSTEM_NAME%>
-
+<%-- [주석 처리] 기존 JSTL 페이징 변수 - Amaranth API AJAX 방식으로 변경
+--%>
@@ -83,33 +184,17 @@ function openApprovalPop(){
@@ -119,20 +204,20 @@ function openApprovalPop(){
-
+
-
-
+
+
No
- 결재번호
- 대상구분
+ 문서번호
+ 양식명
제목
- 상신일
- 상신자
+ 기안일
+ 기안자
상태
@@ -142,101 +227,23 @@ function openApprovalPop(){
-
+
-
-
+
+
-
-
-
-
- ${item.RNUM}
- ${item.ROUTE_NO}
- ${item.TARGET_NAME}
- ${item.APPROVAL_TITLE}
- ${item.ROUTE_REGDATE}
- ${item.WRITER_DEPT_NAME} ${item.WRITER_USER_NAME}
-
-
-
- 결재중
-
-
- 반려
-
-
- 결재완료
-
-
- 결재취소
-
-
- ${item.STATUS}
-
-
-
-
-
-
-
-
- 조회된 정보가 없습니다.
-
-
-
+
+
+ 조회중...
+
+
-
- <%--
- nPage ${nPage}
- prevPage ${prevPage}
- maxPage ${maxPage}
- nextPage ${nextPage}
- totalCount ${totalCount}
- --%>
-
-
-
-
diff --git a/WebContent/WEB-INF/view/main/header.jsp b/WebContent/WEB-INF/view/main/header.jsp
index 207889d..e448d21 100644
--- a/WebContent/WEB-INF/view/main/header.jsp
+++ b/WebContent/WEB-INF/view/main/header.jsp
@@ -142,9 +142,9 @@ $(function(){
fn_goMyTaskMyApproval();
});
- //결재건수 세팅
- fn_setApprovalCnt();
- setInterval(fn_setApprovalCnt, 60000); //refresh
+ //결재건수 세팅 (주석 해제 시 Amaranth10 결재 건수 조회 활성화)
+ //fn_setApprovalCnt();
+ //setInterval(fn_setApprovalCnt, 60000); //refresh
//setTimeout(() => fn_setApprovalCnt(), 10000);
$(".blink_none").children("span").children("img").attr({src:"/images/bell.png"});
@@ -411,8 +411,8 @@ function fn_setApprovalCnt(){
-
- 결재 0 건
+
Q&A
diff --git a/src/com/pms/api/AmaranthApprovalApiClient.java b/src/com/pms/api/AmaranthApprovalApiClient.java
index f1d4097..9cc4338 100644
--- a/src/com/pms/api/AmaranthApprovalApiClient.java
+++ b/src/com/pms/api/AmaranthApprovalApiClient.java
@@ -403,6 +403,285 @@ public class AmaranthApprovalApiClient {
}
}
+ /**
+ * 결재 문서 목록 조회 - 서버 인증 방식
+ * @param baseUrl API 서버의 기본 URL
+ * @param empSeq 사원 시퀀스
+ * @param compSeq 회사 시퀀스
+ * @param menuId 결재함 메뉴 ID (미결: 1001000 등)
+ * @param fromDt 조회 시작일 (YYYY-MM-DD)
+ * @param toDt 조회 종료일 (YYYY-MM-DD)
+ * @param keyWord 검색어
+ * @param page 페이지 번호
+ * @param pageSize 페이지 사이즈
+ * @return API 응답 결과 (JSON 문자열)
+ */
+ public String getApprovalDocList(String baseUrl, String empSeq, String compSeq,
+ String menuId, String fromDt, String toDt, String keyWord,
+ String page, String pageSize) throws Exception {
+
+ System.setProperty("https.protocols", "TLSv1.2");
+
+ TrustManager[] trustAllCerts = new TrustManager[] {
+ new X509TrustManager() {
+ public X509Certificate[] getAcceptedIssuers() { return null; }
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {}
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
+ }
+ };
+
+ SSLContext sc = SSLContext.getInstance("TLS");
+ sc.init(null, trustAllCerts, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
+ public boolean verify(String hostname, javax.net.ssl.SSLSession session) { return true; }
+ });
+
+ String urlPath = "/apiproxy/api99u02A02";
+ String cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
+ String fullUrl = cleanBaseUrl + urlPath;
+
+ URL url = new URL(fullUrl);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setConnectTimeout(30000);
+ connection.setReadTimeout(30000);
+ connection.setInstanceFollowRedirects(false);
+
+ try {
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setRequestProperty("callerName", CALLER_NAME);
+ connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN);
+
+ String transactionId = generateTransactionId();
+ connection.setRequestProperty("transaction-id", transactionId);
+
+ String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+ connection.setRequestProperty("timestamp", timestamp);
+
+ connection.setRequestProperty("groupSeq", GROUP_SEQ);
+
+ String wehagoSign = generateWehagoSign(ACCESS_TOKEN, transactionId, timestamp, urlPath, HASH_KEY);
+ connection.setRequestProperty("wehago-sign", wehagoSign);
+
+ // 요청 본문 작성
+ StringBuilder body = new StringBuilder();
+ body.append("{");
+ body.append("\"header\":{");
+ body.append("\"empSeq\":\"").append(escapeJson(empSeq)).append("\",");
+ body.append("\"groupSeq\":\"").append(escapeJson(GROUP_SEQ)).append("\"");
+ body.append("},");
+ body.append("\"body\":{");
+ body.append("\"menuId\":\"").append(escapeJson(menuId)).append("\",");
+ if (fromDt != null && !fromDt.isEmpty()) {
+ body.append("\"fromDt\":\"").append(escapeJson(fromDt)).append("\",");
+ }
+ if (toDt != null && !toDt.isEmpty()) {
+ body.append("\"toDt\":\"").append(escapeJson(toDt)).append("\",");
+ }
+ body.append("\"pageSize\":\"").append(escapeJson(pageSize != null ? pageSize : "30")).append("\",");
+ body.append("\"keyWord\":\"").append(escapeJson(keyWord != null ? keyWord : "")).append("\",");
+ body.append("\"page\":\"").append(escapeJson(page != null ? page : "1")).append("\",");
+ body.append("\"sort\":\"10\",");
+ body.append("\"langCode\":\"kr\",");
+ body.append("\"searchKind\":\"1\",");
+ body.append("\"companyInfo\":{");
+ body.append("\"compSeq\":\"").append(escapeJson(compSeq)).append("\"");
+ body.append("}");
+ body.append("}");
+ body.append("}");
+
+ String requestBody = body.toString();
+
+ System.out.println("=== Amaranth 결재 문서 목록 조회 ===");
+ System.out.println("URL: " + fullUrl);
+ System.out.println("Request Body: " + requestBody);
+
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+
+ OutputStreamWriter writer = new OutputStreamWriter(
+ connection.getOutputStream(), StandardCharsets.UTF_8);
+ writer.write(requestBody);
+ writer.flush();
+ writer.close();
+
+ int responseCode = connection.getResponseCode();
+
+ BufferedReader reader = null;
+ StringBuilder response = new StringBuilder();
+
+ try {
+ if (responseCode >= 200 && responseCode < 300) {
+ reader = new BufferedReader(new InputStreamReader(
+ connection.getInputStream(), StandardCharsets.UTF_8));
+ } else {
+ java.io.InputStream errorStream = connection.getErrorStream();
+ if (errorStream != null) {
+ reader = new BufferedReader(new InputStreamReader(
+ errorStream, StandardCharsets.UTF_8));
+ } else {
+ throw new Exception("결재 문서 목록 조회 실패: HTTP " + responseCode);
+ }
+ }
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ response.append(line);
+ }
+ } finally {
+ if (reader != null) reader.close();
+ }
+
+ System.out.println("Response Code: " + responseCode);
+
+ if (responseCode >= 200 && responseCode < 300) {
+ return response.toString();
+ } else {
+ throw new Exception("결재 문서 목록 조회 실패: HTTP " + responseCode + " - " + response.toString());
+ }
+
+ } finally {
+ connection.disconnect();
+ }
+ }
+
+ /**
+ * 결재 문서 상세 조회 - 서버 인증 방식
+ * @param baseUrl API 서버 기본 URL
+ * @param empSeq 사원 시퀀스
+ * @param compSeq 회사 시퀀스
+ * @param deptSeq 부서 시퀀스
+ * @param docId 문서 ID
+ * @return API 응답 결과 (JSON 문자열)
+ */
+ public String getApprovalDocDetail(String baseUrl, String empSeq, String compSeq,
+ String deptSeq, String docId) throws Exception {
+
+ System.setProperty("https.protocols", "TLSv1.2");
+
+ TrustManager[] trustAllCerts = new TrustManager[] {
+ new X509TrustManager() {
+ public X509Certificate[] getAcceptedIssuers() { return null; }
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {}
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
+ }
+ };
+
+ SSLContext sc = SSLContext.getInstance("TLS");
+ sc.init(null, trustAllCerts, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
+ public boolean verify(String hostname, javax.net.ssl.SSLSession session) { return true; }
+ });
+
+ String urlPath = "/apiproxy/api99u02A04";
+ String cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
+ String fullUrl = cleanBaseUrl + urlPath;
+
+ URL url = new URL(fullUrl);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setConnectTimeout(30000);
+ connection.setReadTimeout(30000);
+ connection.setInstanceFollowRedirects(false);
+
+ try {
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setRequestProperty("callerName", CALLER_NAME);
+ connection.setRequestProperty("Authorization", "Bearer " + ACCESS_TOKEN);
+
+ String transactionId = generateTransactionId();
+ connection.setRequestProperty("transaction-id", transactionId);
+
+ String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+ connection.setRequestProperty("timestamp", timestamp);
+
+ connection.setRequestProperty("groupSeq", GROUP_SEQ);
+
+ String wehagoSign = generateWehagoSign(ACCESS_TOKEN, transactionId, timestamp, urlPath, HASH_KEY);
+ connection.setRequestProperty("wehago-sign", wehagoSign);
+
+ // 요청 본문 작성
+ StringBuilder body = new StringBuilder();
+ body.append("{");
+ body.append("\"header\":{");
+ body.append("\"pId\":\"\",");
+ body.append("\"tId\":\"\",");
+ body.append("\"groupSeq\":\"").append(escapeJson(GROUP_SEQ)).append("\",");
+ body.append("\"empSeq\":\"").append(escapeJson(empSeq)).append("\"");
+ body.append("},");
+ body.append("\"body\":{");
+ body.append("\"migYn\":\"0\",");
+ body.append("\"langCode\":\"kr\",");
+ body.append("\"spMigYn\":\"0\",");
+ body.append("\"docId\":\"").append(escapeJson(docId)).append("\",");
+ body.append("\"spDocId\":\"\",");
+ body.append("\"companyInfo\":{");
+ body.append("\"compSeq\":\"").append(escapeJson(compSeq)).append("\",");
+ body.append("\"deptSeq\":\"").append(escapeJson(deptSeq)).append("\"");
+ body.append("}");
+ body.append("}");
+ body.append("}");
+
+ String requestBody = body.toString();
+
+ System.out.println("=== Amaranth 결재 문서 상세 조회 ===");
+ System.out.println("URL: " + fullUrl);
+ System.out.println("docId: " + docId);
+ System.out.println("Request Body: " + requestBody);
+
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+
+ OutputStreamWriter writer = new OutputStreamWriter(
+ connection.getOutputStream(), StandardCharsets.UTF_8);
+ writer.write(requestBody);
+ writer.flush();
+ writer.close();
+
+ int responseCode = connection.getResponseCode();
+
+ BufferedReader reader = null;
+ StringBuilder response = new StringBuilder();
+
+ try {
+ if (responseCode >= 200 && responseCode < 300) {
+ reader = new BufferedReader(new InputStreamReader(
+ connection.getInputStream(), StandardCharsets.UTF_8));
+ } else {
+ java.io.InputStream errorStream = connection.getErrorStream();
+ if (errorStream != null) {
+ reader = new BufferedReader(new InputStreamReader(
+ errorStream, StandardCharsets.UTF_8));
+ } else {
+ throw new Exception("결재 문서 상세 조회 실패: HTTP " + responseCode);
+ }
+ }
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ response.append(line);
+ }
+ } finally {
+ if (reader != null) reader.close();
+ }
+
+ System.out.println("Response Code: " + responseCode);
+
+ if (responseCode >= 200 && responseCode < 300) {
+ return response.toString();
+ } else {
+ throw new Exception("결재 문서 상세 조회 실패: HTTP " + responseCode + " - " + response.toString());
+ }
+
+ } finally {
+ connection.disconnect();
+ }
+ }
+
/**
* loginId 암호화 (AES128 CBC PKCS5Padding)
*/
diff --git a/src/com/pms/controller/ApprovalController.java b/src/com/pms/controller/ApprovalController.java
index a6fe717..3a4170c 100644
--- a/src/com/pms/controller/ApprovalController.java
+++ b/src/com/pms/controller/ApprovalController.java
@@ -47,6 +47,45 @@ public class ApprovalController {
return "/approval/approvalList";
}
+ /**
+ * Amaranth10 전자결재 문서 목록 조회 (AJAX 전용)
+ * approvalList.jsp에서만 사용하는 전용 엔드포인트
+ * @param request
+ * @param paramMap
+ * @return JSON 결과
+ */
+ @RequestMapping("/approval/getAmaranthApprovalDocList.do")
+ public String getAmaranthApprovalDocList(HttpServletRequest request, @RequestParam Map paramMap)throws Exception{
+ String jsonResult = approvalService.getAmaranthApprovalDocListJson(request, paramMap);
+ request.setAttribute("RESULT", jsonResult);
+ return "/ajax/ajaxResult";
+ }
+
+ /**
+ * Amaranth10 결재 문서 상세 팝업 페이지
+ * approvalList.jsp에서 문서번호 클릭 시 호출
+ * @param request
+ * @param paramMap docId, deptSeq 필수
+ * @return 상세 팝업 JSP
+ */
+ @RequestMapping("/approval/amaranthApprovalDetail.do")
+ public String amaranthApprovalDetail(HttpServletRequest request, @RequestParam Map paramMap)throws Exception{
+ return "/approval/amaranthApprovalDetail";
+ }
+
+ /**
+ * Amaranth10 결재 문서 상세 데이터 조회 (AJAX 전용)
+ * @param request
+ * @param paramMap docId, deptSeq 필수
+ * @return JSON 결과
+ */
+ @RequestMapping("/approval/getAmaranthApprovalDocDetail.do")
+ public String getAmaranthApprovalDocDetail(HttpServletRequest request, @RequestParam Map paramMap)throws Exception{
+ String jsonResult = approvalService.getAmaranthApprovalDocDetail(request, paramMap);
+ request.setAttribute("RESULT", jsonResult);
+ return "/ajax/ajaxResult";
+ }
+
/**
* 결재 상신 Form
* @param request
diff --git a/src/com/pms/service/ApprovalService.java b/src/com/pms/service/ApprovalService.java
index 0ebf9dc..9295d23 100644
--- a/src/com/pms/service/ApprovalService.java
+++ b/src/com/pms/service/ApprovalService.java
@@ -1228,6 +1228,406 @@ public class ApprovalService {
return count;
}
+ /**
+ * Amaranth10 전자결재 문서 목록 조회 - JSON 문자열 반환 (AJAX 전용)
+ * approvalList.jsp 전용 엔드포인트에서 호출
+ * @param request HttpServletRequest
+ * @param paramMap 검색 파라미터
+ * @return JSON 문자열
+ */
+ public String getAmaranthApprovalDocListJson(HttpServletRequest request, Map paramMap){
+ Map resultMap = getAmaranthApprovalDocList(request, paramMap);
+ return buildApprovalDocListJson(resultMap);
+ }
+
+ /**
+ * Amaranth10 결재 문서 상세 조회
+ * @param request HttpServletRequest
+ * @param paramMap docId, deptSeq 필수
+ * @return API 응답 JSON 원본 (contents HTML 포함)
+ */
+ public String getAmaranthApprovalDocDetail(HttpServletRequest request, Map paramMap){
+ try {
+ // 세션에서 사원 정보 가져오기
+ HttpSession session = request.getSession();
+ PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
+ String empSeq = CommonUtils.checkNull(person.getEmpseq());
+ String compSeq = "1000";
+
+ String docId = CommonUtils.checkNull(paramMap.get("docId"));
+ String deptSeq = CommonUtils.checkNull(paramMap.get("deptSeq"));
+
+ System.out.println("=== Amaranth 결재 문서 상세 조회 ===");
+ System.out.println("empSeq: " + empSeq + ", docId: " + docId + ", deptSeq: " + deptSeq);
+
+ if(empSeq == null || empSeq.isEmpty()){
+ System.err.println("empSeq가 비어있습니다.");
+ return "{\"resultCode\":-1,\"resultMsg\":\"empSeq가 비어있습니다.\"}";
+ }
+ if(docId == null || docId.isEmpty()){
+ System.err.println("docId가 비어있습니다.");
+ return "{\"resultCode\":-1,\"resultMsg\":\"docId가 비어있습니다.\"}";
+ }
+
+ // API 호출
+ com.pms.api.AmaranthApprovalApiClient apiClient = new com.pms.api.AmaranthApprovalApiClient();
+ String baseUrl = "https://erp.rps-korea.com";
+
+ String apiResponse = apiClient.getApprovalDocDetail(baseUrl, empSeq, compSeq, deptSeq, docId);
+
+ System.out.println("상세 조회 API 응답 길이: " + (apiResponse != null ? apiResponse.length() : 0) + " bytes");
+
+ return apiResponse;
+
+ } catch(Exception e){
+ System.err.println("Amaranth 결재 문서 상세 조회 오류: " + e.getMessage());
+ e.printStackTrace();
+ return "{\"resultCode\":-1,\"resultMsg\":\"" + escapeJsonValue(e.getMessage()) + "\"}";
+ }
+ }
+
+ /**
+ * 결재 문서 목록 결과를 JSON 문자열로 변환
+ */
+ private String buildApprovalDocListJson(Map resultMap){
+ StringBuilder json = new StringBuilder();
+ json.append("{");
+
+ // 페이징 정보
+ json.append("\"totalCount\":").append(resultMap.get("TOTAL_COUNT")).append(",");
+ json.append("\"maxPage\":").append(resultMap.get("MAX_PAGE_SIZE")).append(",");
+ json.append("\"nextPage\":").append(resultMap.get("NEXT_PAGE")).append(",");
+ json.append("\"prevPage\":").append(resultMap.get("PREV_PAGE")).append(",");
+
+ // 문서 리스트
+ json.append("\"list\":[");
+ ArrayList> list = (ArrayList>) resultMap.get("LIST");
+ if(list != null){
+ for(int i = 0; i < list.size(); i++){
+ if(i > 0) json.append(",");
+ HashMap doc = list.get(i);
+ json.append("{");
+ json.append("\"RNUM\":\"").append(escapeJsonValue(String.valueOf(doc.get("RNUM")))).append("\",");
+ json.append("\"DOC_ID\":\"").append(escapeJsonValue(String.valueOf(doc.get("DOC_ID")))).append("\",");
+ json.append("\"DOC_TITLE\":\"").append(escapeJsonValue(String.valueOf(doc.get("DOC_TITLE")))).append("\",");
+ json.append("\"FORM_NAME\":\"").append(escapeJsonValue(String.valueOf(doc.get("FORM_NAME")))).append("\",");
+ json.append("\"EMP_NAME\":\"").append(escapeJsonValue(String.valueOf(doc.get("EMP_NAME")))).append("\",");
+ json.append("\"DEPT_NAME\":\"").append(escapeJsonValue(String.valueOf(doc.get("DEPT_NAME")))).append("\",");
+ json.append("\"DOC_STS_NAME\":\"").append(escapeJsonValue(String.valueOf(doc.get("DOC_STS_NAME")))).append("\",");
+ json.append("\"REP_DT\":\"").append(escapeJsonValue(String.valueOf(doc.get("REP_DT")))).append("\",");
+ json.append("\"DOC_STS\":\"").append(escapeJsonValue(String.valueOf(doc.get("DOC_STS")))).append("\",");
+ json.append("\"DEPT_SEQ\":\"").append(escapeJsonValue(String.valueOf(doc.get("DEPT_SEQ")))).append("\"");
+ json.append("}");
+ }
+ }
+ json.append("]");
+ json.append("}");
+
+ return json.toString();
+ }
+
+ /**
+ * JSON 값 이스케이프 (서비스 내부용)
+ */
+ private String escapeJsonValue(String value){
+ if(value == null || "null".equals(value)) return "";
+ return value.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
+ }
+
+ /**
+ * Amaranth10 전자결재 문서 목록 조회 (서버 인증 방식)
+ * @param request HttpServletRequest
+ * @param paramMap 검색 파라미터 (search_approvalTitle, search_fromDate, search_toDate, page 등)
+ * @return 결재 문서 목록 및 페이징 정보
+ */
+ public Map getAmaranthApprovalDocList(HttpServletRequest request, Map paramMap){
+ Map resultMap = new HashMap();
+ ArrayList> resultList = new ArrayList();
+
+ try{
+ // 세션에서 사원 정보 가져오기
+ HttpSession session = request.getSession();
+ PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN);
+ String empSeq = CommonUtils.checkNull(person.getEmpseq());
+ String compSeq = "1000"; // 회사 시퀀스
+
+ System.out.println("=== Amaranth 결재 문서 목록 조회 ===");
+ System.out.println("empSeq: " + empSeq);
+
+ if(empSeq == null || empSeq.isEmpty()){
+ System.err.println("empSeq가 비어있습니다. LoginId 업데이트 배치를 먼저 실행하세요.");
+ resultMap.put("LIST", resultList);
+ resultMap.put("TOTAL_COUNT", 0);
+ return resultMap;
+ }
+
+ // 검색 조건 매핑
+ String keyWord = CommonUtils.checkNull(paramMap.get("search_approvalTitle"));
+ String fromDt = CommonUtils.checkNull(paramMap.get("search_fromDate"));
+ String toDt = CommonUtils.checkNull(paramMap.get("search_toDate"));
+ String page = CommonUtils.checkNull(paramMap.get("page"), "1");
+ String pageSize = "20";
+
+ // menuId: 기안함(1000400) - 결재 전체 목록 조회용
+ String menuId = CommonUtils.checkNull(paramMap.get("menuId"), "1000400");
+
+ // API 호출
+ com.pms.api.AmaranthApprovalApiClient apiClient = new com.pms.api.AmaranthApprovalApiClient();
+ String baseUrl = "https://erp.rps-korea.com";
+
+ String apiResponse = apiClient.getApprovalDocList(
+ baseUrl, empSeq, compSeq, menuId, fromDt, toDt, keyWord, page, pageSize);
+
+ System.out.println("API 응답 길이: " + (apiResponse != null ? apiResponse.length() : 0) + " bytes");
+
+ // JSON 파싱
+ resultList = parseApprovalDocList(apiResponse);
+ int totalCnt = extractTotalCnt(apiResponse);
+
+ // 번호 매기기 (RNUM)
+ int startNum = (Integer.parseInt(page) - 1) * Integer.parseInt(pageSize);
+ for(int i = 0; i < resultList.size(); i++){
+ resultList.get(i).put("RNUM", String.valueOf(startNum + i + 1));
+ }
+
+ // 페이징 정보 설정
+ int currentPage = Integer.parseInt(page);
+ int pageSizeInt = Integer.parseInt(pageSize);
+ int maxPage = (int) Math.ceil((double) totalCnt / pageSizeInt);
+ if(maxPage < 1) maxPage = 1;
+
+ resultMap.put("LIST", resultList);
+ resultMap.put("TOTAL_COUNT", totalCnt);
+ resultMap.put("MAX_PAGE_SIZE", maxPage);
+ resultMap.put("NEXT_PAGE", Math.min(currentPage + 1, maxPage));
+ resultMap.put("PREV_PAGE", Math.max(currentPage - 1, 1));
+
+ System.out.println("결재 문서 수: " + resultList.size() + ", 전체: " + totalCnt);
+
+ }catch(Exception e){
+ System.err.println("Amaranth 결재 문서 목록 조회 오류: " + e.getMessage());
+ e.printStackTrace();
+ resultMap.put("LIST", resultList);
+ resultMap.put("TOTAL_COUNT", 0);
+ resultMap.put("MAX_PAGE_SIZE", 1);
+ resultMap.put("NEXT_PAGE", 1);
+ resultMap.put("PREV_PAGE", 1);
+ }
+
+ return resultMap;
+ }
+
+ /**
+ * API 응답에서 eaDocList 배열 파싱
+ * 응답 구조: {"resultData":{"eaDocList":[{...},{...}],"totalCnt":94}}
+ */
+ private ArrayList> parseApprovalDocList(String jsonResponse){
+ ArrayList> list = new ArrayList();
+
+ try {
+ // eaDocList 배열 찾기
+ int eaDocListIndex = jsonResponse.indexOf("\"eaDocList\"");
+ if(eaDocListIndex == -1){
+ System.err.println("eaDocList를 찾을 수 없습니다.");
+ return list;
+ }
+
+ // eaDocList 다음의 [ 찾기
+ int arrayStart = jsonResponse.indexOf("[", eaDocListIndex);
+ if(arrayStart == -1){
+ System.err.println("eaDocList 배열 시작을 찾을 수 없습니다.");
+ return list;
+ }
+
+ // 대응하는 ] 찾기
+ int bracketCount = 0;
+ int arrayEnd = -1;
+ for(int i = arrayStart; i < jsonResponse.length(); i++){
+ char c = jsonResponse.charAt(i);
+ if(c == '[') bracketCount++;
+ else if(c == ']') bracketCount--;
+
+ if(bracketCount == 0){
+ arrayEnd = i;
+ break;
+ }
+ }
+
+ if(arrayEnd == -1){
+ System.err.println("eaDocList 배열 끝을 찾을 수 없습니다.");
+ return list;
+ }
+
+ String arrayStr = jsonResponse.substring(arrayStart + 1, arrayEnd);
+
+ // 각 문서 객체 파싱
+ int searchFrom = 0;
+ while(searchFrom < arrayStr.length()){
+ int objStart = arrayStr.indexOf("{", searchFrom);
+ if(objStart == -1) break;
+
+ // 중첩 { } 처리
+ int braceCount = 0;
+ int objEnd = -1;
+ for(int i = objStart; i < arrayStr.length(); i++){
+ char c = arrayStr.charAt(i);
+ if(c == '{') braceCount++;
+ else if(c == '}') braceCount--;
+
+ if(braceCount == 0){
+ objEnd = i;
+ break;
+ }
+ }
+
+ if(objEnd == -1) break;
+
+ String objStr = arrayStr.substring(objStart, objEnd + 1);
+ HashMap doc = parseDocObject(objStr);
+ if(!doc.isEmpty()){
+ list.add(doc);
+ }
+
+ searchFrom = objEnd + 1;
+ }
+
+ System.out.println("파싱된 문서 수: " + list.size());
+
+ } catch (Exception e) {
+ System.err.println("eaDocList 파싱 오류: " + e.getMessage());
+ e.printStackTrace();
+ }
+
+ return list;
+ }
+
+ /**
+ * 개별 문서 JSON 객체 파싱
+ */
+ private HashMap parseDocObject(String objStr){
+ HashMap doc = new HashMap();
+
+ try {
+ doc.put("DOC_ID", extractJsonStringValue(objStr, "docId"));
+ doc.put("DOC_TITLE", extractJsonStringValue(objStr, "docTitle"));
+ doc.put("FORM_NAME", extractJsonStringValue(objStr, "formName"));
+ doc.put("EMP_NAME", extractJsonStringValue(objStr, "empName"));
+ doc.put("DEPT_NAME", extractJsonStringValue(objStr, "deptName"));
+ doc.put("DOC_STS", extractJsonStringValue(objStr, "docSts"));
+ doc.put("DOC_STS_NAME", extractJsonStringValue(objStr, "docStsName"));
+ doc.put("POSITION_NAME", extractJsonStringValue(objStr, "positionName"));
+ doc.put("DUTY_NAME", extractJsonStringValue(objStr, "dutyName"));
+ doc.put("LINE_NAME", extractJsonStringValue(objStr, "lineName"));
+ doc.put("ATTACH_CNT", extractJsonStringValue(objStr, "attachCnt"));
+ doc.put("COMMENT_CNT", extractJsonStringValue(objStr, "commentCnt"));
+ doc.put("EMERGENCY_FLAG", extractJsonStringValue(objStr, "emergencyFlag"));
+ doc.put("DELAY_FLAG", extractJsonStringValue(objStr, "delayFlag"));
+ doc.put("READ_YN", extractJsonStringValue(objStr, "readYN"));
+ doc.put("APP_YN", extractJsonStringValue(objStr, "appYN"));
+ doc.put("COMP_SEQ", extractJsonStringValue(objStr, "compSeq"));
+ doc.put("EMP_SEQ", extractJsonStringValue(objStr, "empSeq"));
+ doc.put("DEPT_SEQ", extractJsonStringValue(objStr, "deptSeq"));
+
+ // 상신일(repDt) 포맷팅: YYYYMMDDHHMISS → YYYY-MM-DD
+ String repDt = extractJsonStringValue(objStr, "repDt");
+ if(repDt != null && repDt.length() >= 8){
+ doc.put("REP_DT", repDt.substring(0, 4) + "-" + repDt.substring(4, 6) + "-" + repDt.substring(6, 8));
+ } else {
+ doc.put("REP_DT", repDt);
+ }
+
+ // 생성일(createdDt) 포맷팅
+ String createdDt = extractJsonStringValue(objStr, "createdDt");
+ if(createdDt != null && createdDt.length() >= 8){
+ doc.put("CREATED_DT", createdDt.substring(0, 4) + "-" + createdDt.substring(4, 6) + "-" + createdDt.substring(6, 8));
+ } else {
+ doc.put("CREATED_DT", createdDt);
+ }
+
+ } catch (Exception e) {
+ System.err.println("문서 객체 파싱 오류: " + e.getMessage());
+ }
+
+ return doc;
+ }
+
+ /**
+ * JSON 문자열에서 특정 키의 문자열 값 추출
+ */
+ private String extractJsonStringValue(String json, String key){
+ String searchKey = "\"" + key + "\"";
+ int keyIndex = json.indexOf(searchKey);
+ if(keyIndex == -1) return "";
+
+ int colonIndex = json.indexOf(":", keyIndex + searchKey.length());
+ if(colonIndex == -1) return "";
+
+ // 콜론 뒤의 공백 건너뛰기
+ int valueStart = colonIndex + 1;
+ while(valueStart < json.length() && json.charAt(valueStart) == ' '){
+ valueStart++;
+ }
+
+ if(valueStart >= json.length()) return "";
+
+ // null 값 체크
+ if(json.substring(valueStart).startsWith("null")){
+ return "";
+ }
+
+ // 숫자 값 체크 (따옴표 없는 경우)
+ char firstChar = json.charAt(valueStart);
+ if(firstChar != '"'){
+ // 숫자나 boolean 값
+ int valueEnd = valueStart;
+ while(valueEnd < json.length()){
+ char c = json.charAt(valueEnd);
+ if(c == ',' || c == '}' || c == ']') break;
+ valueEnd++;
+ }
+ return json.substring(valueStart, valueEnd).trim();
+ }
+
+ // 문자열 값 (따옴표 있는 경우)
+ int quoteStart = valueStart; // 이미 '"' 위치
+ int quoteEnd = json.indexOf("\"", quoteStart + 1);
+ if(quoteEnd == -1) return "";
+
+ return json.substring(quoteStart + 1, quoteEnd);
+ }
+
+ /**
+ * API 응답에서 totalCnt 추출
+ */
+ private int extractTotalCnt(String jsonResponse){
+ try {
+ String searchKey = "\"totalCnt\"";
+ int keyIndex = jsonResponse.indexOf(searchKey);
+ if(keyIndex == -1) return 0;
+
+ int colonIndex = jsonResponse.indexOf(":", keyIndex + searchKey.length());
+ if(colonIndex == -1) return 0;
+
+ int valueStart = colonIndex + 1;
+ while(valueStart < jsonResponse.length() && jsonResponse.charAt(valueStart) == ' '){
+ valueStart++;
+ }
+
+ int valueEnd = valueStart;
+ while(valueEnd < jsonResponse.length()){
+ char c = jsonResponse.charAt(valueEnd);
+ if(c == ',' || c == '}' || c == ']') break;
+ valueEnd++;
+ }
+
+ String cntStr = jsonResponse.substring(valueStart, valueEnd).trim();
+ return Integer.parseInt(cntStr);
+ } catch (Exception e) {
+ System.err.println("totalCnt 추출 오류: " + e.getMessage());
+ return 0;
+ }
+ }
+
public ArrayList getApprovalLine(HttpServletRequest request, Map paramMap){
ArrayList> resultList = new ArrayList();
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession();