thkim 2026-02-09 18:30:50 +09:00
commit 09f09766a2
7 changed files with 214 additions and 37 deletions

View File

@ -387,26 +387,31 @@ public class DrillingInquiryController {
idx++; idx++;
// sb.append(row.get("cid")).append(","); // sb.append(row.get("cid")).append(",");
sb.append(s(row.get("constName"))).append(","); sb.append(csv(row.get("constName"))).append(",");
sb.append(s(row.get("projectStateCodeName"))).append(","); sb.append(csv(row.get("projectStateCodeName"))).append(",");
// 사업기간 constStartDate ~ constEndDate // 사업기간 constStartDate ~ constEndDate
sb.append(s(row.get("constStartDate"))).append(" ~ ").append(s(row.get("constEndDate"))).append(","); sb.append(csv(row.get("constStartDate"))).append(" ~ ").append(csv(row.get("constEndDate"))).append(",");
sb.append(s(row.get("constStateCodeName"))).append(","); sb.append(csv(row.get("constStateCodeName"))).append(",");
sb.append(s(row.get("masterCompanyDept"))).append(","); sb.append(csv(row.get("masterCompanyDept"))).append(",");
sb.append(s(row.get("masterCompanyAdmin"))).append(","); sb.append(csv(row.get("masterCompanyAdmin"))).append(",");
sb.append(s(row.get("masterCompanyTel"))).append(","); sb.append(csv(row.get("masterCompanyTel"))).append(",");
sb.append(s(row.get("constCompanyDept"))).append(","); sb.append(csv(row.get("coinstCompanyDept"))).append(",");
sb.append(s(row.get("constCompanyAdmin"))).append(","); sb.append(csv(row.get("constCompanyAdmin"))).append(",");
sb.append(s(row.get("constCompanyTel"))).append("\n"); sb.append(csv(row.get("constCompanyTel"))).append("\n");
} }
byte[] csvBytes = sb.toString().getBytes("UTF-8"); byte[] csvBytes = sb.toString().getBytes("UTF-8");
byte[] bom = new byte[] {(byte)0xEF, (byte)0xBB, (byte)0xBF}; byte[] bom = new byte[] {(byte)0xEF, (byte)0xBB, (byte)0xBF};
// ---------- ★ 한글 파일명 브라우저별 처리 ---------- // ---------- ★ 한글 파일명 브라우저별 처리 ----------
String filename = "건설현장조회.csv"; String excelFileNm = "건설현장조회";
if (params.get("excelFileNm") != null && !"".equals(params.get("excelFileNm"))) {
excelFileNm = (String) params.get("excelFileNm");
}
String filename = excelFileNm+".csv";
String userAgent = request.getHeader("User-Agent"); String userAgent = request.getHeader("User-Agent");
String encodedFilename; String encodedFilename;
@ -434,4 +439,26 @@ public class DrillingInquiryController {
private String s(Object o) { private String s(Object o) {
return o == null ? "" : o.toString(); return o == null ? "" : o.toString();
} }
private String csv(Object o) {
if (o == null) return "";
String value = o.toString();
boolean needQuote =
value.contains(",") ||
value.contains("\"") ||
value.contains("\n") ||
value.contains("\r");
if (value.contains("\"")) {
value = value.replace("\"", "\"\"");
}
if (needQuote) {
value = "\"" + value + "\"";
}
return value;
}
} }

View File

@ -35,16 +35,26 @@
ST.MODIFY_ITEM, ST.MODIFY_ITEM,
tcsi.CID, tcsi.CID,
tcsi.CRT_USERID, tcsi.CRT_USERID,
tcsi.CONST_USERID tcsi.CONST_USERID,
tgld.GL_DISTRICT,
tgmd.GM_DISTRICT,
tgsd.GS_DISTRICT,
COALESCE(tgsd.GS_DISTRICT, tgmd.GM_DISTRICT, tgld.GL_DISTRICT) AS last_district -- 우선순위: GS -> GM -> GL 순으로 NULL이 아닌 값을 선택
FROM TEMP_PROJECT_INFO A FROM TEMP_PROJECT_INFO A
LEFT JOIN (SELECT * LEFT JOIN (SELECT *
FROM (SELECT L.* FROM (SELECT L.*
,ROW_NUMBER() OVER (PARTITION BY PROJECT_CODE ORDER BY REG_DATE DESC) AS RN ,ROW_NUMBER() OVER (PARTITION BY PROJECT_CODE ORDER BY REG_DATE DESC) AS RN
FROM TEMP_SMS_LOG L) FROM TEMP_SMS_LOG L)
WHERE RN = 1) B ON A.PROJECT_CODE = B.PROJECT_CODE WHERE RN = 1) B ON A.PROJECT_CODE = B.PROJECT_CODE
LEFT JOIN TEMP_MANAGE_STATE ST ON ST.PROJECT_CODE = A.PROJECT_CODE LEFT JOIN TEMP_MANAGE_STATE ST ON ST.PROJECT_CODE = A.PROJECT_CODE
AND ST.STATE = '5' AND ST.STATE = '5'
LEFT JOIN TEMP_CONSTRUCT_SITE_INFO tcsi ON tcsi.PROJECT_CODE = A.PROJECT_CODE LEFT JOIN TEMP_CONSTRUCT_SITE_INFO tcsi ON tcsi.PROJECT_CODE = A.PROJECT_CODE
LEFT JOIN TBL_GL_DISTRICT tgld ON tcsi.MASTER_COMPANY_O_CODE = tgld.GL_CODE
LEFT JOIN TBL_GM_DISTRICT tgmd ON tcsi.MASTER_COMPANY_O_CODE = tgmd.GL_CODE
AND tcsi.MASTER_COMPANY_TW_CODE = tgmd.GM_CODE
LEFT JOIN TBL_GS_DISTRICT tgsd ON tcsi.MASTER_COMPANY_O_CODE = tgsd.GL_CODE
AND tcsi.MASTER_COMPANY_TW_CODE = tgsd.GM_CODE
AND tcsi.MASTER_COMPANY_TH_CODE = tgsd.GS_CODE
WHERE WHERE
NVL(A.USE_YN,' ') <> 'N' AND A.USERID = #{userId} NVL(A.USE_YN,' ') <> 'N' AND A.USERID = #{userId}
]]> ]]>

View File

@ -441,6 +441,7 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
params.append("constCompanyAdmin", trim($('#company-admin').val())); params.append("constCompanyAdmin", trim($('#company-admin').val()));
params.append("constCompanyTel", trim($('#company-tel').val())); params.append("constCompanyTel", trim($('#company-tel').val()));
params.append("excelDownload", "Y"); params.append("excelDownload", "Y");
params.append("excelFileNm", "건설현장 조회");
// 페이지 정보 // 페이지 정보
const pagingEle = document.getElementById('paging'); const pagingEle = document.getElementById('paging');

View File

@ -239,6 +239,35 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
}); });
/**
* 발주기관 목록화면 tr 드래그 시 상세화면 이동 방지처리
* 드래그 이벤트와 클릭이벤트를 구분하여 감지한다.
*/
function clickExcelListDown() {
const params = new URLSearchParams();
params.append("constTag", trim($('#const-tag').val()));
params.append("constName", trim($('#const-name').val()));
params.append("constStartDate", trim($('#const-start-date').val()));
params.append("constEndDate", trim($('#const-end-date').val()));
params.append("constStateCode", trim($('#const-state-code').val()));
params.append("projectStateCode", 6);
params.append("constCompanyName", trim($('#company-dept').val()));
params.append("constCompanyAdmin", trim($('#company-admin').val()));
params.append("constCompanyTel", trim($('#company-tel').val()));
params.append("excelDownload", "Y");
params.append("excelFileNm", "관리 시추정보 현황");
// 페이지 정보
const pagingEle = document.getElementById('paging');
params.append("nPage", pagingEle.getAttribute("data-npage"));
params.append("nCount", pagingEle.getAttribute("data-ncount"));
// AJAX가 아닌 직접 다운로드 요청
window.location.href = "/drilling/inquiry/csvDownload.do?" + params.toString();
$('#excelDownload').val("");
}
/** /**
* 발주기관 목록화면 tr 드래그 시 상세화면 이동 방지처리 * 발주기관 목록화면 tr 드래그 시 상세화면 이동 방지처리
* 드래그 이벤트와 클릭이벤트를 구분하여 감지한다. * 드래그 이벤트와 클릭이벤트를 구분하여 감지한다.
@ -287,6 +316,7 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
<div class="page-top-search"> <div class="page-top-search">
<form class="form-inline"> <form class="form-inline">
<label class="input-label-display">검색</label> <label class="input-label-display">검색</label>
<input type="hidden" id="excelDownload" name="excelDownload" value="" >
<input type="hidden" id="const-tag" name="const-tag" value="P" > <input type="hidden" id="const-tag" name="const-tag" value="P" >
<input type="search" id="const-name" name="const-name" class="input" placeholder="프로젝트명" title="" value=""> <input type="search" id="const-name" name="const-name" class="input" placeholder="프로젝트명" title="" value="">
<input type="date" id="const-start-date" name="const-start-date" > <input type="date" id="const-start-date" name="const-start-date" >
@ -306,7 +336,13 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
</button> </button>
</form> </form>
</div> </div>
<div class="table-info-group">Total: <span id="count">-</span>건</div> <div class="table-info-group display-flex" style="justify-content: space-between;">
<div>
<button class="btn-green btn-list-excel-download" type="button" id="excel-download-btn" onclick="javascript:clickExcelListDown();">CSV 다운로드</button>
</div>
<div>Total: <span id="count">-</span>건</div>
</div>
<!-- <div class="table-info-group">Total: <span id="count">-</span>건</div> -->
<div class="table-wrap"> <div class="table-wrap">
<table> <table>
<colgroup> <colgroup>

View File

@ -251,6 +251,35 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
}); });
/**
* 발주기관 목록화면 tr 드래그 시 상세화면 이동 방지처리
* 드래그 이벤트와 클릭이벤트를 구분하여 감지한다.
*/
function clickExcelListDown() {
const params = new URLSearchParams();
params.append("constTag", trim($('#const-tag').val()));
params.append("constName", trim($('#const-name').val()));
params.append("constStartDate", trim($('#const-start-date').val()));
params.append("constEndDate", trim($('#const-end-date').val()));
params.append("constStateCode", trim($('#const-state-code').val()));
params.append("projectStateCode", trim($('#project-state-code').val()));
params.append("constCompanyName", trim($('#company-dept').val()));
params.append("constCompanyAdmin", trim($('#company-admin').val()));
params.append("constCompanyTel", trim($('#company-tel').val()));
params.append("excelDownload", "Y");
params.append("excelFileNm", "시추정보 관리");
// 페이지 정보
const pagingEle = document.getElementById('paging');
params.append("nPage", pagingEle.getAttribute("data-npage"));
params.append("nCount", pagingEle.getAttribute("data-ncount"));
// AJAX가 아닌 직접 다운로드 요청
window.location.href = "/drilling/inquiry/csvDownload.do?" + params.toString();
$('#excelDownload').val("");
}
/** /**
* 발주기관 목록화면 tr 드래그 시 상세화면 이동 방지처리 * 발주기관 목록화면 tr 드래그 시 상세화면 이동 방지처리
* 드래그 이벤트와 클릭이벤트를 구분하여 감지한다. * 드래그 이벤트와 클릭이벤트를 구분하여 감지한다.
@ -299,6 +328,7 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
<div class="page-top-search"> <div class="page-top-search">
<form class="form-inline"> <form class="form-inline">
<label class="input-label-display">검색</label> <label class="input-label-display">검색</label>
<input type="hidden" id="excelDownload" name="excelDownload" value="" >
<input type="hidden" id="const-tag" name="const-tag" value="P" > <input type="hidden" id="const-tag" name="const-tag" value="P" >
<input type="search" id="const-name" name="const-name" class="input" placeholder="프로젝트명" title="" value=""> <input type="search" id="const-name" name="const-name" class="input" placeholder="프로젝트명" title="" value="">
<input type="date" id="const-start-date" name="const-start-date" > <input type="date" id="const-start-date" name="const-start-date" >
@ -338,7 +368,13 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
</button> </button>
</form> </form>
</div> </div>
<div class="table-info-group">Total: <span id="count">-</span>건</div> <div class="table-info-group display-flex" style="justify-content: space-between;">
<div>
<button class="btn-green btn-list-excel-download" type="button" id="excel-download-btn" onclick="javascript:clickExcelListDown();">CSV 다운로드</button>
</div>
<div>Total: <span id="count">-</span>건</div>
</div>
<!-- <div class="table-info-group">Total: <span id="count">-</span>건</div> -->
<div class="table-wrap"> <div class="table-wrap">
<table> <table>
<colgroup> <colgroup>

View File

@ -112,6 +112,7 @@ function getStatusInfo(statusCode) {
/** /**
* API 호출 결과를 받아 화면에 이력 목록을 표시하는 콜백 함수 * API 호출 결과를 받아 화면에 이력 목록을 표시하는 콜백 함수
*/ */
var historyData;
function displayHistoryList(response) { function displayHistoryList(response) {
// ▼▼▼ [수정] 대상 ID를 'notification-list-full'로 변경 // ▼▼▼ [수정] 대상 ID를 'notification-list-full'로 변경
var notificationList = document.getElementById('notification-list-full'); var notificationList = document.getElementById('notification-list-full');
@ -120,7 +121,7 @@ function displayHistoryList(response) {
if (response && response.resultCode === 200 && response.datas) { if (response && response.resultCode === 200 && response.datas) {
var datas = response.datas; var datas = response.datas;
var contentHtml = ''; var contentHtml = '';
historyData = response.datas; // 전역 변수에 셋팅(엑셀다운로드시 필요)
for (var i = 0; i < datas.length; i++) { for (var i = 0; i < datas.length; i++) {
var item = datas[i]; var item = datas[i];
@ -169,10 +170,74 @@ function displayHistoryList(response) {
console.error("Error fetching history list:", response.resultMessage); console.error("Error fetching history list:", response.resultMessage);
} }
} }
/**
* 알림내역 CSV 다운로드
*/
function clickExcelListDown() {
console.log(historyData);
if (!historyData || historyData.length === 0) {
alert("다운로드할 데이터가 없습니다.");
return;
}
const headers = [
"프로젝트명",
"이전상태",
"변경상태",
"변경일시"
];
const STATE_MAP = {
"0": "미입력",
"1": "입력 중",
"2": "검수 준비 대기중",
"3": "검수중",
"4": "수정 요청",
"6": "검수 완료",
"6": "등록 완료"
};
const rows = historyData.map(function (item) {
return [
item.constName,
STATE_MAP[item.preProjectStateCode] || item.preProjectStateCode,
STATE_MAP[item.projectStateCode] || item.projectStateCode,
item.modDt
];
});
let csvContent = "";
csvContent += headers.join(",") + "\n";
rows.forEach(function (row) {
csvContent += row
.map(function (value) {
return '"' + String(value).replace(/"/g, '""') + '"';
})
.join(",") + "\n";
});
const blob = new Blob(
["\uFEFF" + csvContent],
{ type: "text/csv;charset=utf-8;" }
);
const link = document.createElement("a");
const url = URL.createObjectURL(blob);
link.href = url;
link.download = "상태변경이력.csv";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
</script> </script>
<section class="drilling-page-container"> <section class="drilling-page-container">
<div class="page-content-wrapper drilling inquiry"> <div class="page-content-wrapper drilling inquiry">
<div class="page-sidebar-wrapper"> <div class="page-sidebar-wrapper">
<div class="page-sidebar"> <div class="page-sidebar">
<div class="treeview-project-name"> <div class="treeview-project-name">
<p class="project-title">알림</p> <p class="project-title">알림</p>
@ -181,31 +246,32 @@ function displayHistoryList(response) {
</div> </div>
</div> </div>
</div> </div>
<div class="page-content"> <div class="page-content">
<div class="page-content-inner"> <div class="page-content-inner">
<div class="category-wrapper"> <div class="category-wrapper">
<ul class="page-category"> <ul class="page-category">
<li class="category-item"></li> <li class="category-item"></li>
<li class="category-item">알림 내역</li> <li class="category-item">알림 내역</li>
</ul> </ul>
<a href="#" class="btn btn-help">도움말</a> <a href="#" class="btn btn-help">도움말</a>
</div> </div>
<h1 class="page-title-1depth">알림 내역</h1> <h1 class="page-title-1depth">알림 내역</h1>
<div class="content-wrapper"> <div class="content-wrapper">
<main class="w-full"> <main class="w-full">
<div class="bg-white p-6 rounded-lg shadow-md"> <div class="bg-white p-6 rounded-lg shadow-md">
<div class="border-b pb-4 mb-4"> <div class="border-b pb-4 mb-4 display-flex" style="justify-content: space-between;">
<h3 class="font-semibold text-gray-800 text-4xl">건설현장 프로젝트 상태 변경 이력</h3> <h3 class="font-semibold text-gray-800 text-4xl">건설현장 프로젝트 상태 변경 이력</h3>
</div> <button class="btn-green btn-list-excel-download marB0 marR0" type="button" id="excel-download-btn" onclick="javascript:clickExcelListDown();">CSV 다운로드</button>
<div id="notification-list-full" class="space-y-6"> </div>
<div class="p-4 text-center text-gray-500">알림 목록을 불러오는 중입니다...</div> <div id="notification-list-full" class="space-y-6">
</div> <div class="p-4 text-center text-gray-500">알림 목록을 불러오는 중입니다...</div>
</div> </div>
</main> </div>
</main>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<div id="calenderDiv" class="trViewOff" style="position:absolute;"></div> <div id="calenderDiv" class="trViewOff" style="position:absolute;"></div>

View File

@ -166,6 +166,7 @@ function kendoGrid() {
dataSource : gridData, dataSource : gridData,
columns: [ columns: [
{ field: "rowNumber", width: 50, title: "순번", template: "<span class='row-number'></span>" }, { field: "rowNumber", width: 50, title: "순번", template: "<span class='row-number'></span>" },
{field: "reqCompany", width: 180, title: "배정 발주기관", template: function (data) { return data.lastDistrict || data.gsDistrict || data.gmDistrict || data.glDistrict || ""; }, attributes: { style: "text-align: left" }},
{ {
field: "projectName", field: "projectName",
title: "프로젝트명", title: "프로젝트명",