feat: 건설현장 통계에 기관별 등록 건수 추가
parent
225a32decf
commit
eaab9989f3
|
|
@ -1,6 +1,7 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/main/java/geoinfo/admins/chLog/DownloadAppController.java=UTF-8
|
||||
encoding//src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-project-statistics-index.jsp=UTF-8
|
||||
encoding//src/main/webapp/body/map/web3d/web3d.jsp=UTF-8
|
||||
encoding//src/main/webapp/popups/pop_201705_01.jsp=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ if /i "!workspace_path:~1,2!" == "\:" (
|
|||
rem # 최종 target_prefix를 설정합니다.
|
||||
set "target_prefix=!workspace_path!\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\geoinfo_admin\"
|
||||
|
||||
explorer "!target_prefix!"
|
||||
#explorer "!target_prefix!"
|
||||
|
||||
echo target_prefix: "!target_prefix!"
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ if "!line:~-4!" == ".xml" (
|
|||
set "target_file=%target_prefix%!relative_path!"
|
||||
)
|
||||
|
||||
rem --- [수정된 부분] 파일 복사 실행 및 결과 출력 ---
|
||||
rem --- 파일 복사 실행 및 결과 출력 ---
|
||||
if defined source_file (
|
||||
if exist "!source_file!" (
|
||||
echo [COPY]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
#게시판 - 자료실에 파일 업로드 안 되는 문제 수정 건
|
||||
src\main\webapp\WEB-INF\views\admins\constructionProjectManagement\construction-project-statistics-index.jsp
|
||||
src\main\resources\geoinfo\sqlmap\mappers\admins\user\DrillingInquiryMapper.xml
|
||||
src\main\resources\geoinfo\sqlmap\mappers\admins\constructionProjectManagement\ConstructionProjectManagementMapper.xml
|
||||
|
|
@ -6,6 +6,7 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
|
@ -25,6 +26,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||
|
||||
import egovframework.rte.psl.dataaccess.util.EgovMap;
|
||||
import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
|
||||
import geoinfo.admins.constructionProjectManagement.service.ConstructionProjectManagementService;
|
||||
import geoinfo.admins.user.service.DrillingInquiryService;
|
||||
import geoinfo.admins.user.service.GeneralUserMngService;
|
||||
import geoinfo.admins.user.service.HomeTrainingService;
|
||||
|
|
@ -32,8 +34,6 @@ import geoinfo.comm.util.strUtil;
|
|||
import geoinfo.session.UserInfo;
|
||||
import geoinfo.util.MyUtil;
|
||||
|
||||
|
||||
|
||||
@Controller
|
||||
public class ConstructionProjectManagementController {
|
||||
@Resource(name = "generalUserMngService")
|
||||
|
|
@ -43,11 +43,16 @@ public class ConstructionProjectManagementController {
|
|||
private HomeTrainingService homeTrainingService;
|
||||
|
||||
|
||||
@Resource(name = "drillingInquiryService")
|
||||
private DrillingInquiryService drillingInquiryService;
|
||||
// [변경] 새로 만든 서비스 주입
|
||||
@Resource(name = "constructionProjectManagementService")
|
||||
private ConstructionProjectManagementService constructionProjectManagementService;
|
||||
|
||||
// [추가] 기존 검색/조회 기능을 위해 필요 (변수 선언 추가)
|
||||
@Resource(name = "drillingInquiryService")
|
||||
private DrillingInquiryService drillingInquiryService;
|
||||
|
||||
/**
|
||||
* 집합교육 화면
|
||||
* 건설현장 통계 화면
|
||||
* @param params
|
||||
* @param model
|
||||
* @param response
|
||||
|
|
@ -66,6 +71,41 @@ public class ConstructionProjectManagementController {
|
|||
return "admins/constructionProjectManagement/construction-project-statistics-index";
|
||||
}
|
||||
|
||||
/**
|
||||
* 건설현장 통계 데이터 조회 (AJAX)
|
||||
*/
|
||||
@RequestMapping(value = "admins/constructionProjectManagement/selectStatistics.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public JSONObject selectStatistics(HttpServletRequest request, @RequestBody String strJSON, HttpServletResponse response) {
|
||||
JSONObject jsonResponse = new JSONObject();
|
||||
|
||||
try {
|
||||
// 1. 파라미터 파싱
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
JSONObject jsonObject = (JSONObject) jsonParser.parse(strJSON);
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
|
||||
if (jsonObject != null) {
|
||||
for(Object key : jsonObject.keySet()){
|
||||
params.put((String)key, jsonObject.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 서비스 호출 (새로 만든 서비스 사용)
|
||||
Map<String, Object> stats = constructionProjectManagementService.selectConstructionProjectStatistics(params);
|
||||
|
||||
jsonResponse.put("result", "true");
|
||||
jsonResponse.put("data", stats);
|
||||
|
||||
} catch (Exception e) {
|
||||
jsonResponse.put("result", "false");
|
||||
jsonResponse.put("message", e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return jsonResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 집합교육 추가
|
||||
* @param request
|
||||
|
|
@ -612,42 +652,6 @@ public class ConstructionProjectManagementController {
|
|||
return "admins/constructionProjectManagement/construction-user-detail";
|
||||
}
|
||||
|
||||
// 발주기관 프로젝트목록 가져오기
|
||||
// @ResponseBody
|
||||
// @RequestMapping(value = "/drilling-project-list", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
|
||||
// public String getDrillingProjectList(HttpServletRequest request, HttpServletResponse response, @RequestParam HashMap<String,Object> params) throws Exception {
|
||||
// if (!UserInfo.isValidSession(request, response, "admin")) {
|
||||
// return "";
|
||||
// }
|
||||
// JSONObject jsonObject = new JSONObject();
|
||||
// strUtil sUtil = new strUtil();
|
||||
//
|
||||
// String projectName = sUtil.checkNull((String)params.get("projectName"));
|
||||
//
|
||||
// JSONArray jsonListObject = new JSONArray();
|
||||
//
|
||||
//// if( projectName == ""){
|
||||
//// jsonObject.put("resultMessage", "OK");
|
||||
//// jsonObject.put("resultCode", 200);
|
||||
//// jsonObject.put("result", new JSONObject().put("list", jsonListObject));
|
||||
//// } else {
|
||||
// JSONObject result = new JSONObject();
|
||||
// result.put("list", drillingInquiryService.drillingInquiryAutocompleteList(request, params));
|
||||
//
|
||||
// jsonObject.put("resultMessage", "OK");
|
||||
// jsonObject.put("resultCode", 200);
|
||||
// jsonObject.put("result", result);
|
||||
//// }
|
||||
//
|
||||
// response.setContentType("application/json; charset=UTF-8"); // 응답 헤더 설정
|
||||
// response.setCharacterEncoding("UTF-8"); // 응답 데이터 인코딩 설정 (중요)
|
||||
//
|
||||
// try (OutputStream os = response.getOutputStream()) { // OutputStream 사용
|
||||
// os.write(jsonObject.toString().getBytes("UTF-8")); // UTF-8 인코딩하여 출력
|
||||
// }
|
||||
//
|
||||
// return null; // @ResponseBody이므로 반환 값은 필요 없습니다.
|
||||
// }
|
||||
@RequestMapping(value = "/drilling/inquiry/list.do", method = RequestMethod.GET, produces = { "application/json; charset=utf-8" })
|
||||
@ResponseBody
|
||||
public ResponseEntity<JSONObject> drillingInquiryList (
|
||||
|
|
@ -771,4 +775,4 @@ public class ConstructionProjectManagementController {
|
|||
return "admins/constructionProjectManagement/construction-user-login-history";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package geoinfo.admins.constructionProjectManagement.service;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import egovframework.rte.psl.dataaccess.mapper.Mapper;
|
||||
import egovframework.rte.psl.dataaccess.util.EgovMap;
|
||||
|
||||
@Mapper("constructionProjectManagementMapper")
|
||||
public interface ConstructionProjectManagementMapper {
|
||||
|
||||
/**
|
||||
* 전체 건설현장 등록 건수 조회
|
||||
*/
|
||||
public Long selectTotalCount(HashMap<String, Object> params) throws SQLException;
|
||||
|
||||
/**
|
||||
* 지역별 통계 조회
|
||||
*/
|
||||
public List<EgovMap> selectRegionCount(HashMap<String, Object> params) throws SQLException;
|
||||
|
||||
/**
|
||||
* 단계별 통계 조회
|
||||
*/
|
||||
public List<EgovMap> selectStageCount(HashMap<String, Object> params) throws SQLException;
|
||||
|
||||
/**
|
||||
* 최근 입력된 건설현장 목록 조회 (상위 N개)
|
||||
*/
|
||||
public List<EgovMap> selectRecentProjects(HashMap<String, Object> params) throws SQLException;
|
||||
|
||||
/**
|
||||
* 통계 대상 기관명 목록 조회
|
||||
*/
|
||||
public List<String> selectStatTargetCompanies() throws SQLException;
|
||||
|
||||
/**
|
||||
* 기관명을 이용해 지역코드(GL, GM, GS) 구하기 (Stored Procedure 호출)
|
||||
*/
|
||||
public void spGetMasterCompanyDistrict(HashMap<String, Object> params) throws SQLException;
|
||||
|
||||
/**
|
||||
* 지역코드로 건설현장 수 구하기
|
||||
*/
|
||||
public int selectSiteCountByDistrictCodes(HashMap<String, Object> params) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package geoinfo.admins.constructionProjectManagement.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ConstructionProjectManagementService {
|
||||
|
||||
/**
|
||||
* 건설현장 통계 대시보드 데이터 조회
|
||||
* @param params 검색 조건
|
||||
* @return 통계 결과 Map (totalCount, regionList, stageList, recentList 등)
|
||||
* @throws Exception
|
||||
*/
|
||||
public Map<String, Object> selectConstructionProjectStatistics(HashMap<String, Object> params) throws Exception;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
package geoinfo.admins.constructionProjectManagement.service.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import egovframework.rte.psl.dataaccess.util.EgovMap;
|
||||
import geoinfo.admins.constructionProjectManagement.service.ConstructionProjectManagementMapper;
|
||||
import geoinfo.admins.constructionProjectManagement.service.ConstructionProjectManagementService;
|
||||
import geoinfo.admins.user.service.DrillingInputService;
|
||||
import geoinfo.util.MyUtil;
|
||||
|
||||
@Service("constructionProjectManagementService")
|
||||
public class ConstructionProjectManagementServiceImpl implements ConstructionProjectManagementService {
|
||||
|
||||
@Resource(name = "constructionProjectManagementMapper")
|
||||
private ConstructionProjectManagementMapper constructionProjectManagementMapper;
|
||||
|
||||
@Autowired
|
||||
private DrillingInputService drillingInputService;
|
||||
|
||||
/**
|
||||
* 건설현장 통계 대시보드 데이터 조회
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> selectConstructionProjectStatistics(HashMap<String, Object> params) throws Exception {
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
|
||||
// 1. 사용자 권한 및 조직 코드 설정 (기존 로직)
|
||||
String userId = MyUtil.getStringFromObject(params.get("userId"));
|
||||
if (userId != null && !userId.isEmpty()) {
|
||||
HashMap<String, Object> orgCodes = drillingInputService.getOrganizationUserGlGmGsGfCodes(userId);
|
||||
if (orgCodes != null) {
|
||||
params.put("masterCompanyOCode", orgCodes.get("v_gl"));
|
||||
params.put("masterCompanyTwCode", orgCodes.get("v_gm"));
|
||||
params.put("masterCompanyThCode", orgCodes.get("v_gs"));
|
||||
params.put("masterCompanyName", orgCodes.get("v_gf"));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// 2. 전체 등록 수 조회
|
||||
Long totalCount = constructionProjectManagementMapper.selectTotalCount(params);
|
||||
resultMap.put("totalCount", totalCount);
|
||||
|
||||
// =================================================================
|
||||
// [기관별 통계 로직] v_gl='01' 필터링 및 코드순 정렬
|
||||
// =================================================================
|
||||
List<Map<String, Object>> institutionStats = new ArrayList<>();
|
||||
|
||||
// A. 통계 대상 기관명 목록 조회
|
||||
List<String> companyList = constructionProjectManagementMapper.selectStatTargetCompanies();
|
||||
|
||||
// 부산 지역(v_gl='01') 합계용 변수
|
||||
int busanTotalCount = 0;
|
||||
|
||||
if (companyList != null) {
|
||||
for (String companyName : companyList) {
|
||||
if (companyName == null || companyName.trim().isEmpty()) continue;
|
||||
|
||||
// B. SP 호출하여 지역코드(GL, GM, GS) 획득
|
||||
HashMap<String, Object> spParams = new HashMap<>();
|
||||
spParams.put("projectMasterCompanyName", companyName);
|
||||
|
||||
// SP 실행 (OUT 변수는 spParams에 담김: v_gl, v_gm, v_gs)
|
||||
constructionProjectManagementMapper.spGetMasterCompanyDistrict(spParams);
|
||||
|
||||
String v_gl = (String) spParams.get("v_gl");
|
||||
String v_gm = (String) spParams.get("v_gm");
|
||||
String v_gs = (String) spParams.get("v_gs");
|
||||
|
||||
// [필터링 조건] v_gl이 '01'인 경우에만 처리
|
||||
if ("01".equals(v_gl)) {
|
||||
|
||||
// C. 해당 지역코드로 건설현장 수 카운트
|
||||
HashMap<String, Object> countParams = new HashMap<>();
|
||||
countParams.put("v_gl", v_gl);
|
||||
countParams.put("v_gm", v_gm);
|
||||
countParams.put("v_gs", v_gs);
|
||||
|
||||
int siteCount = constructionProjectManagementMapper.selectSiteCountByDistrictCodes(countParams);
|
||||
|
||||
// 그래프용 데이터 저장 (기관명, 건수, 정렬용 코드들)
|
||||
Map<String, Object> stat = new HashMap<>();
|
||||
stat.put("name", companyName);
|
||||
stat.put("count", siteCount);
|
||||
stat.put("gl", v_gl);
|
||||
stat.put("gm", v_gm);
|
||||
stat.put("gs", v_gs);
|
||||
|
||||
institutionStats.add(stat);
|
||||
|
||||
// 부산 지역 합계 누적
|
||||
busanTotalCount += siteCount;
|
||||
}
|
||||
}
|
||||
|
||||
// [정렬] GL_CODE ASC, GM_CODE ASC, GS_CODE ASC 순서로 정렬
|
||||
Collections.sort(institutionStats, new Comparator<Map<String, Object>>() {
|
||||
@Override
|
||||
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
|
||||
String gl1 = (String) o1.get("gl");
|
||||
String gl2 = (String) o2.get("gl");
|
||||
int result = compareString(gl1, gl2);
|
||||
if (result != 0) return result;
|
||||
|
||||
String gm1 = (String) o1.get("gm");
|
||||
String gm2 = (String) o2.get("gm");
|
||||
result = compareString(gm1, gm2);
|
||||
if (result != 0) return result;
|
||||
|
||||
String gs1 = (String) o1.get("gs");
|
||||
String gs2 = (String) o2.get("gs");
|
||||
return compareString(gs1, gs2);
|
||||
}
|
||||
|
||||
// null-safe string comparison
|
||||
private int compareString(String s1, String s2) {
|
||||
if (s1 == null) s1 = "";
|
||||
if (s2 == null) s2 = "";
|
||||
return s1.compareTo(s2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 결과 맵에 저장 (정렬된 리스트)
|
||||
resultMap.put("institutionStats", institutionStats);
|
||||
resultMap.put("busanCount", busanTotalCount);
|
||||
|
||||
|
||||
// 3. 지역별 통계 조회
|
||||
List<EgovMap> regionList = constructionProjectManagementMapper.selectRegionCount(params);
|
||||
resultMap.put("regionList", regionList);
|
||||
|
||||
// 4. 단계별 통계 조회
|
||||
List<EgovMap> stageList = constructionProjectManagementMapper.selectStageCount(params);
|
||||
Map<String, Integer> stageCounts = new HashMap<>();
|
||||
|
||||
// 초기화
|
||||
stageCounts.put("feasibility", 0);
|
||||
stageCounts.put("basicDesign", 0);
|
||||
stageCounts.put("detailDesign", 0);
|
||||
stageCounts.put("construction", 0);
|
||||
stageCounts.put("completion", 0);
|
||||
stageCounts.put("maintenance", 0);
|
||||
|
||||
for (EgovMap map : stageList) {
|
||||
String stateCode = String.valueOf(map.get("constStateCode"));
|
||||
Integer cnt = Integer.parseInt(String.valueOf(map.get("cnt")));
|
||||
|
||||
if ("1".equals(stateCode)) stageCounts.put("feasibility", cnt);
|
||||
else if ("2".equals(stateCode)) stageCounts.put("basicDesign", cnt);
|
||||
else if ("3".equals(stateCode)) stageCounts.put("detailDesign", cnt);
|
||||
else if ("4".equals(stateCode)) stageCounts.put("construction", cnt);
|
||||
else if ("5".equals(stateCode)) stageCounts.put("completion", cnt);
|
||||
else if ("6".equals(stateCode)) stageCounts.put("maintenance", cnt);
|
||||
}
|
||||
resultMap.put("stageCounts", stageCounts);
|
||||
|
||||
// 5. 최근 입력된 건설현장
|
||||
params.put("firstIndex", 0);
|
||||
params.put("recordCountPerPage", 5);
|
||||
|
||||
List<EgovMap> recentList = constructionProjectManagementMapper.selectRecentProjects(params);
|
||||
resultMap.put("recentList", recentList);
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
throw new Exception("통계 데이터 조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<!-- namespace 확인: Java Interface 경로와 일치 -->
|
||||
<mapper namespace="geoinfo.admins.constructionProjectManagement.service.ConstructionProjectManagementMapper">
|
||||
|
||||
<!-- [공통] 검색 조건 Fragment (기존 유지) -->
|
||||
<sql id="searchConditions">
|
||||
<if test="constName != null and constName != ''">
|
||||
AND A.CONST_NAME LIKE '%' || #{constName} || '%'
|
||||
</if>
|
||||
<if test="masterCompanyName != null and masterCompanyName != ''">
|
||||
AND A.MASTER_COMPANY_NAME LIKE '%' || #{masterCompanyName} || '%'
|
||||
</if>
|
||||
<if test="masterCompanyAdmin != null and masterCompanyAdmin != ''">
|
||||
AND A.MASTER_COMPANY_ADMIN LIKE '%' || #{masterCompanyAdmin} || '%'
|
||||
</if>
|
||||
<if test="masterCompanyTel != null and masterCompanyTel != ''">
|
||||
AND A.MASTER_COMPANY_TEL LIKE '%' || #{masterCompanyTel} || '%'
|
||||
</if>
|
||||
<if test="constTag != null and constTag != ''">
|
||||
AND A.CONST_TAG = #{constTag}
|
||||
</if>
|
||||
<if test="masterCompanyOCode != null and masterCompanyOCode != ''">
|
||||
AND A.MASTER_COMPANY_O_CODE = #{masterCompanyOCode}
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<!-- 1. 전체 등록 수 조회 (기존 유지) -->
|
||||
<select id="selectTotalCount" parameterType="hashmap" resultType="long">
|
||||
SELECT COUNT(*)
|
||||
FROM TEMP_CONSTRUCT_SITE_INFO A
|
||||
WHERE 1=1
|
||||
<include refid="searchConditions" />
|
||||
</select>
|
||||
|
||||
<!-- 2. 지역별 통계 조회 (기존 유지) -->
|
||||
<select id="selectRegionCount" parameterType="hashmap" resultType="egovMap">
|
||||
SELECT
|
||||
SUBSTR(B.PROJECT_START_SPOT, 1, 2) AS REGION_NAME,
|
||||
COUNT(*) AS CNT
|
||||
FROM TEMP_CONSTRUCT_SITE_INFO A
|
||||
LEFT JOIN TBL_PROJECT_INFO B ON A.PROJECT_CODE = B.PROJECT_CODE
|
||||
WHERE 1=1
|
||||
AND B.PROJECT_START_SPOT IS NOT NULL
|
||||
<include refid="searchConditions" />
|
||||
GROUP BY SUBSTR(B.PROJECT_START_SPOT, 1, 2)
|
||||
</select>
|
||||
|
||||
<!-- 3. 단계별 통계 조회 (기존 유지) -->
|
||||
<select id="selectStageCount" parameterType="hashmap" resultType="egovMap">
|
||||
SELECT
|
||||
CONST_STATE_CODE AS "constStateCode",
|
||||
COUNT(*) AS "cnt"
|
||||
FROM TEMP_CONSTRUCT_SITE_INFO A
|
||||
WHERE 1=1
|
||||
<include refid="searchConditions" />
|
||||
GROUP BY CONST_STATE_CODE
|
||||
</select>
|
||||
|
||||
<!-- 4. 최근 입력된 건설현장 목록 조회 (기존 유지) -->
|
||||
<select id="selectRecentProjects" parameterType="hashmap" resultType="egovMap">
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT ROWNUM RN, TB.*
|
||||
FROM (
|
||||
SELECT
|
||||
A.CID,
|
||||
A.CONST_NAME,
|
||||
B.PROJECT_START_SPOT,
|
||||
A.CONST_STATE_CODE,
|
||||
A.CONST_COMPANY_CODE,
|
||||
A.PROJECT_STATE_CODE,
|
||||
A.CRT_DT,
|
||||
A.MOD_DT
|
||||
FROM TEMP_CONSTRUCT_SITE_INFO A
|
||||
LEFT JOIN TBL_PROJECT_INFO B ON A.PROJECT_CODE = B.PROJECT_CODE
|
||||
WHERE 1=1
|
||||
<include refid="searchConditions" />
|
||||
ORDER BY A.CRT_DT DESC
|
||||
) TB
|
||||
)
|
||||
WHERE RN BETWEEN #{firstIndex} + 1 AND #{firstIndex} + #{recordCountPerPage}
|
||||
</select>
|
||||
|
||||
<!-- 5. [수정] 통계 대상 기관명 목록 조회 (사용자 요청 쿼리 적용) -->
|
||||
<select id="selectStatTargetCompanies" resultType="string">
|
||||
SELECT tmc.COM_NAME
|
||||
FROM (
|
||||
SELECT
|
||||
wmi.*,
|
||||
ROW_NUMBER() OVER (PARTITION BY wmi.PROJECT_MASTER_COMPANY_CODE ORDER BY wmi.DATETIME DESC) as rn
|
||||
FROM
|
||||
web_member_in wmi
|
||||
WHERE
|
||||
wmi.cls = 2
|
||||
) wmi
|
||||
LEFT JOIN TBL_MASTER_COMPANY tmc ON
|
||||
TRIM(wmi.PROJECT_MASTER_COMPANY_CODE) = tmc.COM_CODE
|
||||
WHERE rn = 1
|
||||
AND tmc.COM_NAME IS NOT NULL
|
||||
</select>
|
||||
|
||||
<!-- 6. 기관명을 이용해 지역코드 구하기 (SP 호출) -->
|
||||
<select id="spGetMasterCompanyDistrict" statementType="CALLABLE" parameterType="hashmap">
|
||||
{ call SP_GET_MASTER_COMPANY_DISTRICT (
|
||||
#{projectMasterCompanyName, mode=IN, jdbcType=VARCHAR},
|
||||
#{v_gl, mode=OUT, jdbcType=VARCHAR},
|
||||
#{v_gm, mode=OUT, jdbcType=VARCHAR},
|
||||
#{v_gs, mode=OUT, jdbcType=VARCHAR},
|
||||
#{v_gf, mode=OUT, jdbcType=VARCHAR}
|
||||
)}
|
||||
</select>
|
||||
|
||||
<!-- 7. [수정] 지역코드로 건설현장 수 구하기 (사용자 요청 매핑 적용) -->
|
||||
<select id="selectSiteCountByDistrictCodes" parameterType="hashmap" resultType="int">
|
||||
SELECT COUNT(*)
|
||||
FROM TEMP_CONSTRUCT_SITE_INFO
|
||||
WHERE MASTER_COMPANY_O_CODE = #{v_gl}
|
||||
AND MASTER_COMPANY_TW_CODE = #{v_gm}
|
||||
AND MASTER_COMPANY_TH_CODE = #{v_gs}
|
||||
<!-- 유효한 현장만 카운트할 경우 아래 주석 해제 -->
|
||||
<!-- AND CONST_TAG = 'Y' -->
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -3,175 +3,261 @@
|
|||
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
|
||||
<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<!-- Chart.js 라이브러리 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" HREF="${pageContext.request.contextPath}/css/admins/style.css" type="text/css">
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||
<!-- <script src="${pageContext.request.contextPath}/js/admins/chart.js"></script> -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
var context = "${pageContext.request.contextPath}";
|
||||
var myChartInstance = null; // 단계별 차트 인스턴스
|
||||
var instChartInstance = null; // 기관별 차트 인스턴스 (신규)
|
||||
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||
<script src="${pageContext.request.contextPath}/js/admins/common.js"></script>
|
||||
<link rel="stylesheet" HREF="${pageContext.request.contextPath}/css/admins/style.css" type="text/css">
|
||||
// [1] 문서 로드 완료 시 초기 실행
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// 초기 로딩 시 검색 조건 없이 전체 통계 조회
|
||||
moveConstructionUserDetail();
|
||||
});
|
||||
|
||||
<script>
|
||||
var context = "${pageContext.request.contextPath}";
|
||||
// [2] 통계 조회 함수 (Vanilla JS)
|
||||
function moveConstructionUserDetail() {
|
||||
// 기본 검색 조건 (필요시 변경 가능)
|
||||
var params = {
|
||||
constTag: "Y"
|
||||
};
|
||||
|
||||
let xhr;
|
||||
if(window.XMLHttpRequest) {
|
||||
xhr = new XMLHttpRequest();
|
||||
} else {
|
||||
// IE5, IE6 일때
|
||||
xhr = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
// AJAX 요청 (XMLHttpRequest 사용)
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", context + "/admins/constructionProjectManagement/selectStatistics.do", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
|
||||
const ctx = document.getElementById('myChart');
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4) { // 요청 완료
|
||||
if (xhr.status === 200) { // 성공
|
||||
try {
|
||||
var res = JSON.parse(xhr.responseText);
|
||||
if(res.result == "true" || res.result == true) {
|
||||
renderStatistics(res.data);
|
||||
} else {
|
||||
alert("통계 데이터를 불러오는 중 오류가 발생했습니다: " + (res.message || ""));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("JSON 파싱 오류:", e);
|
||||
}
|
||||
} else {
|
||||
console.error("AJAX Error:", xhr.statusText);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send(JSON.stringify(params));
|
||||
}
|
||||
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
|
||||
datasets: [{
|
||||
label: '# of Votes',
|
||||
data: [12, 19, 3, 5, 2, 3],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
// [3] 화면 갱신 함수
|
||||
function renderStatistics(data) {
|
||||
// (1) 전체 등록 수
|
||||
var totalCountElem = document.getElementById("total-count");
|
||||
if(totalCountElem) totalCountElem.textContent = (data.totalCount || 0) + " 건";
|
||||
|
||||
<body>
|
||||
<h1>건설현장 통계</h1>
|
||||
<div class="home-trainning">
|
||||
// (2) 지역별 통계
|
||||
var busanElem = document.getElementById("busan-count");
|
||||
var daeguElem = document.getElementById("daegu-count");
|
||||
var sejongElem = document.getElementById("sejong-count");
|
||||
|
||||
if(busanElem) busanElem.textContent = "0 건";
|
||||
if(daeguElem) daeguElem.textContent = "0 건";
|
||||
if(sejongElem) sejongElem.textContent = "0 건";
|
||||
|
||||
// 서버에서 계산된 부산 카운트가 있으면 우선 적용
|
||||
if(data.busanCount !== undefined && busanElem) {
|
||||
busanElem.textContent = data.busanCount + " 건";
|
||||
}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row content">
|
||||
<div class="col-sm-12">
|
||||
<h4>검색</h4>
|
||||
<div class="well">
|
||||
<div class="container mt-5">
|
||||
<form class="form-inline">
|
||||
<div class="form-group mb-2 mr-2">
|
||||
<label for="project-name" class="mr-2">프로젝트명:</label>
|
||||
<input type="text" class="form-control" id="project-name" placeholder="프로젝트명 입력">
|
||||
</div>
|
||||
<div class="form-group mb-2 mr-2">
|
||||
<label for="client-name" class="mr-2">발주기관 명:</label>
|
||||
<input type="text" class="form-control" id="client-name" placeholder="발주기관 명 입력">
|
||||
</div>
|
||||
<div class="form-group mb-2 mr-2 w-50">
|
||||
<label for="manager-name" class="mr-2">담당자:</label>
|
||||
<input type="text" class="form-control" id="manager-name" placeholder="담당자 이름 입력">
|
||||
</div>
|
||||
<div class="form-group mb-2 mr-2">
|
||||
<label for="contact-number" class="mr-2">연락처:</label>
|
||||
<input type="text" class="form-control" id="contact-number" placeholder="연락처 입력">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="text-right mt-3">
|
||||
<button type="submit" class="btn btn-primary mb-2">검색</button>
|
||||
</div>
|
||||
</div>
|
||||
// 기존 리스트 기반 지역 카운트 (필요 시 사용)
|
||||
if(data.regionList) {
|
||||
data.regionList.forEach(function(item) {
|
||||
var region = item.regionName || item.REGION_NAME || "";
|
||||
var count = item.cnt || item.CNT || 0;
|
||||
|
||||
// 부산은 위에서 처리했으므로 제외하거나 중복 처리 가능
|
||||
if(region.indexOf("대구") >= 0 && daeguElem) daeguElem.textContent = count + " 건";
|
||||
else if(region.indexOf("세종") >= 0 && sejongElem) sejongElem.textContent = count + " 건";
|
||||
});
|
||||
}
|
||||
|
||||
<h4>건설현장 등록 건수</h4>
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="well">
|
||||
<h4>전체 등록 수</h4>
|
||||
<p>12 건</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="well">
|
||||
<h4>부산광역시</h4>
|
||||
<p>12 건</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="well">
|
||||
<h4>대구광역시</h4>
|
||||
<p>0 건</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="well">
|
||||
<h4>세종특별자치시</h4>
|
||||
<p>0 건</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
// (3) 최근 입력된 건설현장
|
||||
var recentArea = document.getElementById("recent-project-area");
|
||||
var recentHtml = '<p class="fw-bold" style="font-size: 18px; color:#c87202;">최근 입력된 건설현장</p>';
|
||||
|
||||
if(data.recentList && data.recentList.length > 0) {
|
||||
data.recentList.forEach(function(project) {
|
||||
var name = project.constName || project.CONST_NAME || "";
|
||||
var spot = project.projectStartSpot || project.PROJECT_START_SPOT || "";
|
||||
var spotShort = spot.split(" ")[0];
|
||||
recentHtml += '<p>' + name + ' - ' + spotShort + '</p>';
|
||||
});
|
||||
} else {
|
||||
recentHtml += '<p>최근 등록된 데이터가 없습니다.</p>';
|
||||
}
|
||||
recentHtml += '<div class="d-flex justify-content-between align-items-center">' +
|
||||
'<div class="btn-group"><button type="button" class="btn btn-sm btn-outline-secondary">+ 더 보기</button></div></div>';
|
||||
if(recentArea) recentArea.innerHTML = recentHtml;
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<div class="well">
|
||||
<p class="fw-bold" style="font-size: 18px; color:#c87202;">최근 입력된 건설현장</p>
|
||||
<p>부산 북항 재개발 사업 - 부산광역시</p>
|
||||
<p>가덕도 신공항 건설공사 - 부산광역시</p>
|
||||
<p>부산 에코델타시티 조성사업 - 부산광역시</p>
|
||||
<p>동해남부선 복선전철화 사업 - 부산광역시</p>
|
||||
<p>부산 도시철도 1호선 연장 공사 - 부산광역시</p>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary">+ 더 보기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="well">
|
||||
<p class="fw-bold" style="font-size: 18px; color:#c87202;">단계별 건수</p>
|
||||
<p><b>타당성조사 및 계획검토:</b> 12건</p>
|
||||
<p><b>기본설계:</b> 0건</p>
|
||||
<p><b>실시설계:</b> 0건</p>
|
||||
<p><b>시공중:</b> 0건</p>
|
||||
<p><b>준공:</b> 0건</p>
|
||||
<p><b>유지보수:</b> 0건</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="well">
|
||||
<p class="fw-bold" style="font-size: 18px; color:#c87202;">프로젝트 연결률</p>
|
||||
<p><b>부산광역시:</b> 8.33%</p>
|
||||
<p><b>대전광역시:</b> 0%</p>
|
||||
<p><b>세종특별자치시:</b> 0%</p>
|
||||
<p><b>서울특별시:</b> 0%</p>
|
||||
<p><b>대구광역시:</b> 0%</p>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary">+ 더 보기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<div class="well">
|
||||
<p>Text</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="well">
|
||||
<p>Text</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</
|
||||
div>
|
||||
</div>
|
||||
// (4) 단계별 건수 차트
|
||||
updateStageChart(data.stageCounts || {});
|
||||
|
||||
// (5) [신규] 기관별 등록 건수 차트 업데이트
|
||||
updateInstitutionChart(data.institutionStats || []);
|
||||
}
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
// 단계별 차트 그리기
|
||||
function updateStageChart(stageCounts) {
|
||||
var chartData = [
|
||||
stageCounts.feasibility || 0,
|
||||
stageCounts.basicDesign || 0,
|
||||
stageCounts.detailDesign || 0,
|
||||
stageCounts.construction || 0,
|
||||
stageCounts.completion || 0,
|
||||
stageCounts.maintenance || 0
|
||||
];
|
||||
|
||||
var stageFeasElem = document.getElementById("stage-feasibility");
|
||||
if(stageFeasElem) stageFeasElem.textContent = (stageCounts.feasibility || 0) + "건";
|
||||
|
||||
var ctx = document.getElementById('myChart');
|
||||
if(!ctx) return;
|
||||
|
||||
if (myChartInstance) myChartInstance.destroy();
|
||||
|
||||
myChartInstance = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['타당성조사', '기본설계', '실시설계', '시공중', '준공', '유지보수'],
|
||||
datasets: [{
|
||||
label: '건설현장 단계별 건수',
|
||||
data: chartData,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: { scales: { y: { beginAtZero: true } } }
|
||||
});
|
||||
}
|
||||
|
||||
// [신규] 기관별 차트 그리기 함수
|
||||
function updateInstitutionChart(instStats) {
|
||||
var ctx = document.getElementById('institutionChart');
|
||||
if(!ctx) return;
|
||||
|
||||
if (instChartInstance) instChartInstance.destroy();
|
||||
|
||||
var labels = [];
|
||||
var data = [];
|
||||
|
||||
// 데이터 분리 및 라벨 보정
|
||||
instStats.forEach(function(stat) {
|
||||
var name = stat.name;
|
||||
|
||||
// [라벨 보정] '울산광역시' -> '한국도로공사'
|
||||
if (name === '울산광역시') {
|
||||
name = '한국도로공사';
|
||||
}
|
||||
|
||||
labels.push(name);
|
||||
data.push(stat.count);
|
||||
});
|
||||
|
||||
instChartInstance = new Chart(ctx, {
|
||||
type: 'bar', // 막대 그래프
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: '등록 건수',
|
||||
data: data,
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.5)', // 색상 설정
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: { stepSize: 1 } // 정수 단위 표시
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: { display: false }, // 범례 숨김 (단일 데이터셋이므로)
|
||||
title: {
|
||||
display: true,
|
||||
text: '기관별 건설현장 등록 현황',
|
||||
font: { size: 16 }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>건설현장 통계</h1>
|
||||
<div class="home-trainning">
|
||||
<div class="container-fluid">
|
||||
<div class="row content">
|
||||
<div class="col-sm-12">
|
||||
|
||||
<!-- [신규] 기관별 통계 그래프 영역 추가 (하단 전체 너비) -->
|
||||
<div class="row" style="margin-top: 30px;">
|
||||
<div class="col-sm-12">
|
||||
<div class="well" style="background-color: #fff;">
|
||||
<p class="fw-bold" style="font-size: 18px; color:#c87202; margin-bottom: 15px;">기관별 등록 건수</p>
|
||||
<div style="height: 400px;"> <!-- 높이 지정 -->
|
||||
<canvas id="institutionChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- 최근 입력된 건설현장 -->
|
||||
<div class="col-sm-4">
|
||||
<div class="well" id="recent-project-area">
|
||||
<p class="fw-bold" style="font-size: 18px; color:#c87202;">최근 입력된 건설현장</p>
|
||||
<p>로딩 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 단계별 건수 텍스트 -->
|
||||
<div class="col-sm-4">
|
||||
<div class="well">
|
||||
<p class="fw-bold" style="font-size: 18px; color:#c87202;">단계별 건수</p>
|
||||
<p><b>타당성조사 및 계획검토:</b> <span id="stage-feasibility">0건</span></p>
|
||||
<p><b>기본설계:</b> 0건</p>
|
||||
<p><b>실시설계:</b> 0건</p>
|
||||
<p><b>시공중:</b> 0건</p>
|
||||
<p><b>준공:</b> 0건</p>
|
||||
<p><b>유지보수:</b> 0건</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 단계별 건수 그래프 -->
|
||||
<div class="col-sm-4">
|
||||
<div class="well">
|
||||
<canvas id="myChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue