결재 건수 및 결재 상세 화면 아마란스 연동
This commit is contained in:
247
WebContent/WEB-INF/view/approval/amaranthApprovalDetail.jsp
Normal file
247
WebContent/WEB-INF/view/approval/amaranthApprovalDetail.jsp
Normal file
@@ -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" %>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title><%=Constants.SYSTEM_NAME%> - 결재 문서 상세</title>
|
||||
<style>
|
||||
/* 상세 팝업 전용 스타일 */
|
||||
.doc-detail-wrap {
|
||||
padding: 10px;
|
||||
}
|
||||
.doc-info-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.doc-info-table td {
|
||||
padding: 5px 8px;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 12px;
|
||||
}
|
||||
.doc-info-table td.label {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.doc-contents-wrap {
|
||||
border: 1px solid #ccc;
|
||||
margin-top: 5px;
|
||||
background: #fff;
|
||||
}
|
||||
.doc-contents-wrap iframe {
|
||||
width: 100%;
|
||||
min-height: 500px;
|
||||
border: none;
|
||||
}
|
||||
.file-list-wrap {
|
||||
margin-top: 8px;
|
||||
padding: 5px 8px;
|
||||
border: 1px solid #ccc;
|
||||
background: #fafafa;
|
||||
}
|
||||
.file-list-wrap .file-title {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.file-list-wrap .file-item {
|
||||
font-size: 11px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
.loading-msg {
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
.error-msg {
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
font-size: 14px;
|
||||
color: #e74c3c;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
$(document).ready(function(){
|
||||
fn_loadDetail();
|
||||
});
|
||||
|
||||
$('#btn_close').click(function(){
|
||||
self.close();
|
||||
});
|
||||
});
|
||||
|
||||
// 결재 문서 상세 조회
|
||||
function fn_loadDetail(){
|
||||
var docId = fnc_getUrlParam("docId");
|
||||
var deptSeq = fnc_getUrlParam("deptSeq");
|
||||
|
||||
if(!docId){
|
||||
$("#detailContent").html('<div class="error-msg">문서 ID가 없습니다.</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "/approval/getAmaranthApprovalDocDetail.do",
|
||||
type: "POST",
|
||||
data: {
|
||||
"docId": docId,
|
||||
"deptSeq": deptSeq || ""
|
||||
},
|
||||
dataType: "json",
|
||||
beforeSend: function(){
|
||||
$("#detailContent").html('<div class="loading-msg">문서 정보를 조회중입니다...</div>');
|
||||
},
|
||||
success: function(data){
|
||||
if(data.resultCode == 0 && data.resultData && data.resultData.result){
|
||||
fn_renderDetail(data.resultData.result);
|
||||
} else {
|
||||
var msg = data.resultMsg || "문서 조회에 실패했습니다.";
|
||||
$("#detailContent").html('<div class="error-msg">' + msg + '</div>');
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error){
|
||||
console.error("상세 조회 오류:", error);
|
||||
$("#detailContent").html('<div class="error-msg">문서 조회 중 오류가 발생했습니다.</div>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 상세 정보 렌더링
|
||||
function fn_renderDetail(result){
|
||||
var html = '<div class="doc-detail-wrap">';
|
||||
|
||||
// 문서 기본 정보 테이블
|
||||
html += '<table class="doc-info-table">';
|
||||
html += '<tr>';
|
||||
html += '<td class="label">문서번호</td><td>' + (result.docId || '') + '</td>';
|
||||
html += '<td class="label">양식명</td><td>' + (result.formName || '') + '</td>';
|
||||
html += '</tr>';
|
||||
html += '<tr>';
|
||||
html += '<td class="label">제목</td><td colspan="3">' + (result.docTitle || '') + '</td>';
|
||||
html += '</tr>';
|
||||
html += '<tr>';
|
||||
html += '<td class="label">기안부서</td><td>' + (result.deptName || '') + '</td>';
|
||||
html += '<td class="label">기안자</td><td>' + (result.empName || '') + '</td>';
|
||||
html += '</tr>';
|
||||
html += '<tr>';
|
||||
html += '<td class="label">직급</td><td>' + (result.positionName || '') + '</td>';
|
||||
html += '<td class="label">직책</td><td>' + (result.dutyName || '') + '</td>';
|
||||
html += '</tr>';
|
||||
html += '<tr>';
|
||||
html += '<td class="label">기안일</td><td>' + fn_formatDate(result.repDt) + '</td>';
|
||||
html += '<td class="label">상태</td><td>' + (result.docStsName || '') + '</td>';
|
||||
html += '</tr>';
|
||||
html += '<tr>';
|
||||
html += '<td class="label">최종결재자</td><td>' + (result.lineName || '') + '</td>';
|
||||
html += '<td class="label">첨부파일</td><td>' + (result.attachCnt || '0') + '건</td>';
|
||||
html += '</tr>';
|
||||
html += '</table>';
|
||||
|
||||
// 첨부파일 목록
|
||||
if(result.fileList && result.fileList.length > 0){
|
||||
html += '<div class="file-list-wrap">';
|
||||
html += '<div class="file-title">첨부파일 (' + result.fileList.length + '건)</div>';
|
||||
for(var i = 0; i < result.fileList.length; i++){
|
||||
var file = result.fileList[i];
|
||||
var fileName = (file.originalFileName || '파일') + '.' + (file.fileExtsn || '');
|
||||
var fileSize = fn_formatFileSize(file.fileSize);
|
||||
html += '<div class="file-item">📎 ' + fileName + ' (' + fileSize + ')</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
// 문서 내용 (HTML)
|
||||
if(result.contents){
|
||||
html += '<div class="doc-contents-wrap">';
|
||||
html += '<iframe id="docContentsFrame" sandbox="allow-same-origin"></iframe>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
$("#detailContent").html(html);
|
||||
|
||||
// iframe에 문서 HTML 삽입
|
||||
if(result.contents){
|
||||
setTimeout(function(){
|
||||
var iframe = document.getElementById("docContentsFrame");
|
||||
if(iframe){
|
||||
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
iframeDoc.open();
|
||||
iframeDoc.write(result.contents);
|
||||
iframeDoc.close();
|
||||
|
||||
// iframe 높이 자동 조절
|
||||
setTimeout(function(){
|
||||
try {
|
||||
var bodyHeight = iframeDoc.body.scrollHeight;
|
||||
if(bodyHeight > 0){
|
||||
iframe.style.height = Math.min(bodyHeight + 30, 800) + "px";
|
||||
}
|
||||
} catch(e){}
|
||||
}, 500);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
// 날짜 포맷팅 (YYYYMMDDHHMISS → YYYY-MM-DD HH:MI)
|
||||
function fn_formatDate(dt){
|
||||
if(!dt || dt.length < 8) return dt || '';
|
||||
var formatted = dt.substring(0, 4) + '-' + dt.substring(4, 6) + '-' + dt.substring(6, 8);
|
||||
if(dt.length >= 12){
|
||||
formatted += ' ' + dt.substring(8, 10) + ':' + dt.substring(10, 12);
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
// 파일 크기 포맷팅
|
||||
function fn_formatFileSize(size){
|
||||
if(!size) return '0 B';
|
||||
var s = parseInt(size);
|
||||
if(s < 1024) return s + ' B';
|
||||
if(s < 1024 * 1024) return (s / 1024).toFixed(1) + ' KB';
|
||||
return (s / (1024 * 1024)).toFixed(1) + ' MB';
|
||||
}
|
||||
|
||||
// URL 파라미터 가져오기
|
||||
function fnc_getUrlParam(name){
|
||||
var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href);
|
||||
if(results == null) return '';
|
||||
return decodeURIComponent(results[1]) || '';
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="backcolor_light_blue">
|
||||
<form name="form1" action="" method="post">
|
||||
<section>
|
||||
<div class="plm_menu_name">
|
||||
<h2>
|
||||
<span>결재 문서 상세</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div id="businessPopupFormWrap">
|
||||
<div id="detailContent">
|
||||
<div class="loading-msg">문서 정보를 조회중입니다...</div>
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<div class="plm_btn_wrap_center">
|
||||
<br>
|
||||
<input type="button" value="닫기" id="btn_close" class="plm_btns">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,58 +8,159 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title><%=Constants.SYSTEM_NAME%></title>
|
||||
|
||||
<!-- //JSTL 변수선언 -->
|
||||
<%-- [주석 처리] 기존 JSTL 페이징 변수 - Amaranth API AJAX 방식으로 변경
|
||||
<c:set var="totalCount" value="${empty TOTAL_COUNT?0:TOTAL_COUNT}" />
|
||||
<c:set var="maxPage" value="${empty MAX_PAGE_SIZE?1:MAX_PAGE_SIZE}" />
|
||||
<c:set var="nPage" value="${empty param.page?1:param.page}" />
|
||||
<c:set var="pageIndex" value="${(nPage-1)/10}" />
|
||||
<c:set var="nextPage" value="${empty NEXT_PAGE?1:NEXT_PAGE}" />
|
||||
<c:set var="prevPage" value="${empty PREV_PAGE?1:PREV_PAGE}" />
|
||||
--%>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 현재 페이지 및 페이징 상태
|
||||
var currentPage = 1;
|
||||
var maxPage = 1;
|
||||
var totalCount = 0;
|
||||
|
||||
$(function(){
|
||||
$(document).ready(function(){
|
||||
fnc_datepick();
|
||||
// 페이지 로드 시 Amaranth API로 결재 목록 조회
|
||||
fn_loadApprovalList(1);
|
||||
});
|
||||
|
||||
$(".searchInput").keyup(function(e){
|
||||
var keyCode = e.keyCode;
|
||||
if(keyCode == 13){
|
||||
fn_search();
|
||||
if(e.keyCode == 13){
|
||||
fn_searchAmaranth();
|
||||
}
|
||||
});
|
||||
|
||||
$("#btnSearch").click(function(){
|
||||
fn_search();
|
||||
fn_searchAmaranth();
|
||||
});
|
||||
|
||||
$(".btnApprovalDetail").click(function(){
|
||||
var approvalObjId = $(this).attr("data-APPROVAL_OBJID");
|
||||
var routeObjId = $(this).attr("data-ROUTE_OBJID");
|
||||
//Swal.fire("approvalObjId : "+approvalObjId+", routeObjId : "+routeObjId);
|
||||
var params = "?approvalObjId="+approvalObjId;
|
||||
params += "&routeObjId="+routeObjId;
|
||||
//Swal.fire("params : "+params);
|
||||
window.open("/approval/approvalDetail.do"+params,"approvalDetailPopup","width=650 height=620 menubar=no status=no");
|
||||
});
|
||||
|
||||
//결재 유형에 따른 대상구분명을 가져와 보여준다.
|
||||
$("X.targetTypeA").each( function() {
|
||||
var code = $(this).text();
|
||||
var codeName = fnc_getApprovalTargetName(code);
|
||||
$(this).text(codeName);
|
||||
} );
|
||||
});
|
||||
|
||||
// Amaranth API 결재 문서 목록 조회
|
||||
function fn_loadApprovalList(page){
|
||||
currentPage = page;
|
||||
|
||||
var keyWord = $("#search_approvalTitle").val() || "";
|
||||
var fromDt = $("#search_fromDate").val() || "";
|
||||
var toDt = $("#search_toDate").val() || "";
|
||||
|
||||
$.ajax({
|
||||
url: "/approval/getAmaranthApprovalDocList.do",
|
||||
type: "POST",
|
||||
data: {
|
||||
"page": page,
|
||||
"search_approvalTitle": keyWord,
|
||||
"search_fromDate": fromDt,
|
||||
"search_toDate": toDt
|
||||
},
|
||||
dataType: "json",
|
||||
beforeSend: function(){
|
||||
$("#approvalListBody").html('<tr style="text-align:center;"><td colspan="7">조회중...</td></tr>');
|
||||
},
|
||||
success: function(data){
|
||||
totalCount = data.totalCount || 0;
|
||||
maxPage = data.maxPage || 1;
|
||||
var list = data.list || [];
|
||||
|
||||
fn_renderList(list);
|
||||
fn_renderPaging(currentPage, maxPage, totalCount);
|
||||
},
|
||||
error: function(xhr, status, error){
|
||||
console.error("결재 목록 조회 오류:", error);
|
||||
$("#approvalListBody").html('<tr style="text-align:center;"><td colspan="7">조회 중 오류가 발생했습니다.</td></tr>');
|
||||
fn_renderPaging(1, 1, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 검색
|
||||
function fn_searchAmaranth(){
|
||||
fn_loadApprovalList(1);
|
||||
}
|
||||
|
||||
// 테이블 목록 렌더링
|
||||
function fn_renderList(list){
|
||||
var html = "";
|
||||
|
||||
if(list.length == 0){
|
||||
html = '<tr style="text-align:center;"><td colspan="7">조회된 정보가 없습니다.</td></tr>';
|
||||
} else {
|
||||
for(var i = 0; i < list.length; i++){
|
||||
var item = list[i];
|
||||
html += '<tr style="text-align:center;">';
|
||||
html += '<td>' + (item.RNUM || '') + '</td>';
|
||||
html += '<td><a href="javascript:fn_openApprovalDetail(\'' + (item.DOC_ID || '') + '\',\'' + (item.DEPT_SEQ || '') + '\');" style="color:#0066cc;text-decoration:underline;">' + (item.DOC_ID || '') + '</a></td>';
|
||||
html += '<td>' + (item.FORM_NAME || '') + '</td>';
|
||||
html += '<td class="align_l4"><a href="javascript:fn_openApprovalDetail(\'' + (item.DOC_ID || '') + '\',\'' + (item.DEPT_SEQ || '') + '\');">' + (item.DOC_TITLE || '') + '</a></td>';
|
||||
html += '<td>' + (item.REP_DT || '') + '</td>';
|
||||
html += '<td>' + (item.DEPT_NAME || '') + ' ' + (item.EMP_NAME || '') + '</td>';
|
||||
html += '<td>' + (item.DOC_STS_NAME || '') + '</td>';
|
||||
html += '</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
$("#approvalListBody").html(html);
|
||||
}
|
||||
|
||||
// Amaranth 결재 문서 상세 팝업 열기
|
||||
function fn_openApprovalDetail(docId, deptSeq){
|
||||
if(!docId) return;
|
||||
var params = "?docId=" + docId + "&deptSeq=" + (deptSeq || "");
|
||||
window.open("/approval/amaranthApprovalDetail.do" + params, "amaranthApprovalDetail", "width=1000,height=800,menubar=no,status=no,scrollbars=yes,resizable=yes");
|
||||
}
|
||||
|
||||
// 페이징 렌더링
|
||||
function fn_renderPaging(nPage, maxPage, totalCount){
|
||||
var html = "";
|
||||
|
||||
if(totalCount > 0){
|
||||
html += '<table><tr>';
|
||||
|
||||
// prev
|
||||
if(nPage > 1){
|
||||
html += '<td><a href="javascript:fn_loadApprovalList(' + (nPage - 1) + ');">prev</a></td>';
|
||||
} else {
|
||||
html += '<td class="no_more_page">prev</td>';
|
||||
}
|
||||
|
||||
// 페이지 번호
|
||||
var startPage = nPage > 5 ? nPage - 5 : 1;
|
||||
var endPage = nPage > 5 ? nPage + 4 : 10;
|
||||
if(endPage > maxPage) endPage = maxPage;
|
||||
|
||||
for(var i = startPage; i <= endPage; i++){
|
||||
if(i == nPage){
|
||||
html += '<td><a href="#" class="now_page">' + i + '</a></td>';
|
||||
} else {
|
||||
html += '<td><a href="javascript:fn_loadApprovalList(' + i + ');">' + i + '</a></td>';
|
||||
}
|
||||
}
|
||||
|
||||
// next
|
||||
if(nPage < maxPage){
|
||||
html += '<td><a href="javascript:fn_loadApprovalList(' + (nPage + 1) + ');">next</a></td>';
|
||||
} else {
|
||||
html += '<td class="no_more_page">next</td>';
|
||||
}
|
||||
|
||||
html += '</tr></table>';
|
||||
html += '<p id="adminPageCount">총 ' + totalCount + '건</p>';
|
||||
}
|
||||
|
||||
$("#pagingArea").html(html);
|
||||
}
|
||||
|
||||
<%-- [주석 처리] 기존 form submit 방식 검색 - AJAX 방식으로 변경
|
||||
function fn_search(){
|
||||
document.form1.action = "/approval/approvalList.do";
|
||||
document.form1.submit();
|
||||
}
|
||||
|
||||
function openApprovalPop(){
|
||||
window.open("/approval/approvalDetail.do","specDataPopUp","width=650 height=730 menubar=no status=no");
|
||||
}
|
||||
|
||||
--%>
|
||||
</script>
|
||||
|
||||
</head>
|
||||
@@ -83,33 +184,17 @@ function openApprovalPop(){
|
||||
<table>
|
||||
<tr>
|
||||
<td class="">
|
||||
<label for="" class="">제목</label>
|
||||
<label for="" class="">검색어</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="search_approvalTitle" id="search_approvalTitle" class="searchInput" value="${param.search_approvalTitle}" style="width:250px;"/>
|
||||
<input type="text" name="search_approvalTitle" id="search_approvalTitle" class="searchInput" value="" style="width:250px;" placeholder="제목/내용/작성자"/>
|
||||
</td>
|
||||
<td class="">
|
||||
<label for="" class="">상신일</label>
|
||||
<label for="" class="">기안일</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="search_fromDate" id="search_fromDate" value="${param.search_fromDate}" class="input_date_solo searchInput"> ~ <input type="text" name="search_toDate" id="search_toDate" value="${param.search_toDate}" class="input_date_solo searchInput">
|
||||
<input type="text" name="search_fromDate" id="search_fromDate" value="" class="input_date_solo searchInput"> ~ <input type="text" name="search_toDate" id="search_toDate" value="" class="input_date_solo searchInput">
|
||||
</td>
|
||||
<td class="">
|
||||
<label for="" class="">상신자</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="search_writerUserName" id="search_writerUserName" value="${param.search_writerUserName}" class="searchInput">
|
||||
</td>
|
||||
<%-- <td class="">
|
||||
<label for="" class="">상태</label>
|
||||
</td>
|
||||
<td>
|
||||
<select name="search_approvalStatus" id="search_approvalStatus">
|
||||
<option value="">전체</option>
|
||||
<option value="inProcess" ${param.search_approvalStatus eq 'inProcess'?'selected':''}>결재중</option>
|
||||
<option value="complete" ${param.search_approvalStatus eq 'complete'?'selected':''}>결재완료</option>
|
||||
</select>
|
||||
</td> --%>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -119,20 +204,20 @@ function openApprovalPop(){
|
||||
<colgroup>
|
||||
<col width="5%">
|
||||
<col width="10%">
|
||||
<col width="10%">
|
||||
<col width="12%">
|
||||
<col width="*">
|
||||
<col width="10%">
|
||||
<col width="20%">
|
||||
<col width="10%">
|
||||
<col width="15%">
|
||||
<col width="8%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="plm_thead">
|
||||
<td>No</td>
|
||||
<td>결재번호</td>
|
||||
<td>대상구분</td>
|
||||
<td>문서번호</td>
|
||||
<td>양식명</td>
|
||||
<td>제목</td>
|
||||
<td>상신일</td>
|
||||
<td>상신자</td>
|
||||
<td>기안일</td>
|
||||
<td>기안자</td>
|
||||
<td>상태</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -142,101 +227,23 @@ function openApprovalPop(){
|
||||
<colgroup>
|
||||
<col width="5%">
|
||||
<col width="10%">
|
||||
<col width="10%">
|
||||
<col width="12%">
|
||||
<col width="*">
|
||||
<col width="10%">
|
||||
<col width="20%">
|
||||
<col width="10%">
|
||||
<col width="15%">
|
||||
<col width="8%">
|
||||
</colgroup>
|
||||
<c:choose>
|
||||
<c:when test="${!empty LIST}">
|
||||
<c:forEach var="item" items="${LIST}" varStatus="status">
|
||||
<tr style="text-align:center;">
|
||||
<td>${item.RNUM}</td>
|
||||
<td>${item.ROUTE_NO}</td>
|
||||
<td class="targetType">${item.TARGET_NAME}</td>
|
||||
<td class="align_l4"><a href="#" class="btnApprovalDetail" data-APPROVAL_OBJID="${item.APPROVAL_OBJID}" data-ROUTE_OBJID="${item.ROUTE_OBJID}">${item.APPROVAL_TITLE}</a></td>
|
||||
<td>${item.ROUTE_REGDATE}</td>
|
||||
<td>${item.WRITER_DEPT_NAME} ${item.WRITER_USER_NAME}</td>
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${item.STATUS eq 'inProcess'}">
|
||||
결재중
|
||||
</c:when>
|
||||
<c:when test="${item.STATUS eq 'reject'}">
|
||||
반려
|
||||
</c:when>
|
||||
<c:when test="${item.STATUS eq 'complete'}">
|
||||
결재완료
|
||||
</c:when>
|
||||
<c:when test="${item.STATUS eq 'cancel'}">
|
||||
결재취소
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
${item.STATUS}
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<tr style="text-align:center;">
|
||||
<td colspan="7">조회된 정보가 없습니다.</td>
|
||||
</tr>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<tbody id="approvalListBody">
|
||||
<tr style="text-align:center;">
|
||||
<td colspan="7">조회중...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pdm_page">
|
||||
|
||||
<%--
|
||||
nPage ${nPage}
|
||||
prevPage ${prevPage}
|
||||
maxPage ${maxPage}
|
||||
nextPage ${nextPage}
|
||||
totalCount ${totalCount}
|
||||
--%>
|
||||
|
||||
<input type="hidden" name="page" id="page" value="${nPage}">
|
||||
<c:if test="${!empty LIST}">
|
||||
<div class="page_pro">
|
||||
<table>
|
||||
<tr>
|
||||
<c:choose>
|
||||
<c:when test="${nPage > 1}">
|
||||
<td><a href="javascript:fnc_goPrev('${prevPage}');">prev</a></td>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<td class="no_more_page">prev</td>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<c:forEach var="v" begin="${nPage>5?nPage-5:1}" end="${nPage>5?nPage+4:10}" step="1" varStatus="status">
|
||||
<c:if test="${status.index -1 < maxPage}">
|
||||
<c:choose>
|
||||
<c:when test="${status.index eq nPage}">
|
||||
<td><a href="#" class="now_page">${nPage}</a></td>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<td><a href="javascript:fnc_goPage('${status.index}');">${status.index}</a></td>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:if>
|
||||
</c:forEach>
|
||||
<c:choose>
|
||||
<c:when test="${nPage < maxPage}">
|
||||
<td><a href="javascript:fnc_goNext('${nextPage}');">next</a></td>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<td class="no_more_page">next</td>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</tr>
|
||||
</table>
|
||||
<p id="adminPageCount">총 ${totalCount}건</p>
|
||||
<div class="page_pro" id="pagingArea">
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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(){
|
||||
|
||||
<!-- 우측 버튼 영역 -->
|
||||
<td style="text-align: right; padding-right: 10px;">
|
||||
<span id="blink" style="padding: 3px 6px; border-radius:3px; font-size:10px; background-color:#ff6b35; color:#fff; cursor:pointer; margin-right: 5px;" class="btnApprovalList blink_none">
|
||||
결재 <label class="notice_no">0</label>건</span>
|
||||
<!-- <span id="blink" style="padding: 3px 6px; border-radius:3px; font-size:10px; background-color:#ff6b35; color:#fff; cursor:pointer; margin-right: 5px;" class="btnApprovalList blink_none">
|
||||
결재 <label class="notice_no">0</label>건</span> -->
|
||||
|
||||
<a href="#" onclick="javascript:fn_openBoardList('qna');" style="color:#fff;background-color:#676868; border-radius:2px; padding:2px 4px; text-decoration: none; display: inline-block; font-size:9px; margin-right: 5px;">Q&A</a>
|
||||
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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<String, Object> 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<String, Object> 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<String, Object> paramMap)throws Exception{
|
||||
String jsonResult = approvalService.getAmaranthApprovalDocDetail(request, paramMap);
|
||||
request.setAttribute("RESULT", jsonResult);
|
||||
return "/ajax/ajaxResult";
|
||||
}
|
||||
|
||||
/**
|
||||
* 결재 상신 Form
|
||||
* @param request
|
||||
|
||||
@@ -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<String, Object> 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<String, Object> 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<HashMap<String, Object>> list = (ArrayList<HashMap<String, Object>>) resultMap.get("LIST");
|
||||
if(list != null){
|
||||
for(int i = 0; i < list.size(); i++){
|
||||
if(i > 0) json.append(",");
|
||||
HashMap<String, Object> 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<String, Object> getAmaranthApprovalDocList(HttpServletRequest request, Map paramMap){
|
||||
Map<String, Object> resultMap = new HashMap();
|
||||
ArrayList<HashMap<String, Object>> 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<HashMap<String, Object>> parseApprovalDocList(String jsonResponse){
|
||||
ArrayList<HashMap<String, Object>> 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<String, Object> 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<String, Object> parseDocObject(String objStr){
|
||||
HashMap<String, Object> 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<HashMap<String,Object>> resultList = new ArrayList();
|
||||
SqlSession sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
|
||||
Reference in New Issue
Block a user