기관회원 건설현장 입력시 알림 내역 표기되도록 구현
parent
396073a070
commit
3eff840e71
|
|
@ -0,0 +1 @@
|
|||
- to "C:\Users\dbnt\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\geoinfo_eGov_work\WEB-INF\views\drilling\statistics\drilling_statistics.jsp"
|
||||
7
pom.xml
7
pom.xml
|
|
@ -455,13 +455,6 @@
|
|||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8 -->
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
<version>23.2.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,14 @@ public interface DrillingInputMapper {
|
|||
|
||||
public int updateProjectCodeAndProjectStateCodeByCid(HashMap<String, Object> params) throws SQLException;
|
||||
public int updateProjectCodeAndProjectStateCodeByProjectCode(HashMap<String, Object> params) throws SQLException;
|
||||
|
||||
/**
|
||||
* 건설현장 정보 상태 변경 이력을 등록합니다.
|
||||
* @param params
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
public int insertConstructSiteHist(HashMap<String, Object> params) throws SQLException;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -137,14 +137,6 @@ public class DrillingInputServiceImpl implements DrillingInputService {
|
|||
params.put("userId", userId);
|
||||
|
||||
try {
|
||||
/*
|
||||
List<EgovMap> sPGetTblCsiByCidParams = drillingInputMapper.sPGetTblCsiByCid( params );
|
||||
|
||||
if( sPGetTblCsiByCidParams.size() == 0 ) {
|
||||
return params;
|
||||
}
|
||||
EgovMap tbl = sPGetTblCsiByCidParams.get(0);
|
||||
*/
|
||||
|
||||
EgovMap tbl = drillingInputMapper.getItemByCid( params );
|
||||
if( tbl != null ) {
|
||||
|
|
@ -161,7 +153,22 @@ public class DrillingInputServiceImpl implements DrillingInputService {
|
|||
throw new Exception( "해당 프로젝트는 이미 다른 프로젝트와 연결되어 있습니다." );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (nResult > 0) { // 업데이트가 성공했을 경우에만 이력 기록
|
||||
HashMap<String, Object> histParams = new HashMap<String, Object>();
|
||||
|
||||
// 이전 상태값 (EgovMap은 보통 camelCase로 키를 반환합니다)
|
||||
Object preStateCode = tbl.get("projectStateCode");
|
||||
|
||||
histParams.put("CID", params.get("CID"));
|
||||
histParams.put("PROJECT_CODE", params.get("PROJECT_CODE"));
|
||||
histParams.put("PRE_PROJECT_STATE_CODE", preStateCode != null ? preStateCode.toString() : null); // 이전 상태
|
||||
histParams.put("PROJECT_STATE_CODE", params.get("PROJECT_STATE_CODE")); // 현재 변경된 상태
|
||||
histParams.put("MOD_REASON", "지반정보 등록 프로젝트 연결"); // 변경 사유 (필요에 따라 파라미터로 받아서 설정 가능)
|
||||
histParams.put("userId", userId);
|
||||
|
||||
drillingInputMapper.insertConstructSiteHist(histParams);
|
||||
}
|
||||
}
|
||||
return params;
|
||||
} catch (SQLException e) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import geoinfo.drilling.inquiry.service.DrillingInquiryService;
|
||||
import geoinfo.drilling.statistics.service.DrillingStatisticsService;
|
||||
import geoinfo.util.MyUtil;
|
||||
|
||||
@Controller
|
||||
|
|
@ -31,6 +32,9 @@ public class DrillingStatisticsController {
|
|||
|
||||
@Autowired
|
||||
DrillingInquiryService drillingInquiryService;
|
||||
|
||||
@Autowired
|
||||
DrillingStatisticsService drillingStatisticsService;
|
||||
|
||||
@RequestMapping(value = "/drilling/statistics.do")
|
||||
public String drillingStatistics(@RequestParam HashMap<String, Object> params, ModelMap model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
|
|
@ -50,4 +54,37 @@ public class DrillingStatisticsController {
|
|||
|
||||
return "/drilling/statistics/drilling_notice";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/drilling/statistics/hist-list.do", method = RequestMethod.GET, produces = { "application/json; charset=utf-8" })
|
||||
@ResponseBody
|
||||
public ResponseEntity<JSONObject> drillingStatisticsHistList (
|
||||
HttpServletRequest request,
|
||||
@RequestParam HashMap<String, Object> params,
|
||||
HttpServletResponse response
|
||||
) {
|
||||
JSONObject jSONOResponse = null;
|
||||
try {
|
||||
jSONOResponse = drillingStatisticsService.getConstructSiteHistList(request, params);
|
||||
jSONOResponse.put("resultCode", 200);
|
||||
jSONOResponse.put("resultMessage", "OK");
|
||||
|
||||
} catch (Exception e) {
|
||||
jSONOResponse = new JSONObject();
|
||||
jSONOResponse.put("resultCode", -1);
|
||||
jSONOResponse.put("resultMessage", e.getMessage());
|
||||
LOGGER.error("drillingStatisticsHistList Error: ", e);
|
||||
}
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setHeader("Content-Type", "application/json; charset=utf-8");
|
||||
|
||||
try {
|
||||
response.getWriter().print(jSONOResponse);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Response Write Error: ", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ import egovframework.rte.psl.dataaccess.mapper.Mapper;
|
|||
import egovframework.rte.psl.dataaccess.util.EgovMap;
|
||||
|
||||
@Mapper("drillingStatisticsMapper")
|
||||
public interface DrillingStatisticsMapper {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public interface DrillingStatisticsMapper {
|
||||
public List<EgovMap> selectConstructSiteHistList(HashMap<String, Object> params) throws SQLException;
|
||||
public Long selectConstructSiteHistListCnt(HashMap<String, Object> params) throws SQLException;
|
||||
}
|
||||
|
|
@ -12,5 +12,5 @@ import egovframework.rte.psl.dataaccess.util.EgovMap;
|
|||
|
||||
|
||||
public interface DrillingStatisticsService {
|
||||
|
||||
public JSONObject getConstructSiteHistList(HttpServletRequest request, HashMap<String, Object> params) throws Exception;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import geoinfo.drilling.input.service.DrillingInputMapper;
|
|||
import geoinfo.drilling.input.service.DrillingInputService;
|
||||
import geoinfo.drilling.inquiry.service.DrillingInquiryMapper;
|
||||
import geoinfo.drilling.inquiry.service.DrillingInquiryService;
|
||||
import geoinfo.drilling.statistics.service.DrillingStatisticsMapper;
|
||||
import geoinfo.drilling.statistics.service.DrillingStatisticsService;
|
||||
import geoinfo.main.login.service.LoginMapper;
|
||||
import geoinfo.main.login.service.LoginService;
|
||||
|
|
@ -32,12 +33,16 @@ import egovframework.rte.psl.dataaccess.util.EgovMap;
|
|||
public class DrillingStatisticsServiceImpl implements DrillingStatisticsService {
|
||||
|
||||
|
||||
|
||||
@Resource(name="drillingInquiryMapper")
|
||||
private DrillingInquiryMapper drillingInquiryMapper;
|
||||
|
||||
@Resource(name="drillingInputMapper")
|
||||
private DrillingInputMapper drillingInputMapper;
|
||||
|
||||
@Resource(name="drillingStatisticsMapper")
|
||||
private DrillingStatisticsMapper drillingStatisticsMapper;
|
||||
|
||||
@Autowired
|
||||
DrillingInputService drillingInputService;
|
||||
|
||||
|
|
@ -50,4 +55,45 @@ public class DrillingStatisticsServiceImpl implements DrillingStatisticsService
|
|||
private LoginMapper loginMapper;
|
||||
|
||||
|
||||
@Override
|
||||
public JSONObject getConstructSiteHistList(HttpServletRequest request, HashMap<String, Object> params)
|
||||
throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
JSONObject jsonResponse = new JSONObject();
|
||||
String userId = MyUtil.getStringFromObject(request.getSession().getAttribute("USERID"));
|
||||
|
||||
if (userId == null) {
|
||||
throw new Exception("로그인이 필요한 서비스입니다.");
|
||||
}
|
||||
|
||||
// 1. 현재 로그인한 사용자의 지역(영역) 코드 조회
|
||||
HashMap<String, Object> userAreaCodes = drillingInputService.getOrganizationUserGlGmGsGfCodes(userId);
|
||||
|
||||
params.put("masterCompanyOCode", MyUtil.getStringFromObject(userAreaCodes.get("v_gl")));
|
||||
params.put("masterCompanyTwCode", MyUtil.getStringFromObject(userAreaCodes.get("v_gm")));
|
||||
params.put("masterCompanyThCode", MyUtil.getStringFromObject(userAreaCodes.get("v_gs")));
|
||||
|
||||
// 2. 페이징 처리를 위한 파라미터 설정
|
||||
int page = params.get("page") == null ? 1 : Integer.parseInt(params.get("page").toString());
|
||||
int rows = params.get("rows") == null ? 10 : Integer.parseInt(params.get("rows").toString());
|
||||
params.put("firstIndex", (page - 1) * rows + 1);
|
||||
params.put("lastIndex", page * rows);
|
||||
|
||||
try {
|
||||
// 3. 총 카운트 및 목록 조회
|
||||
Long count = drillingStatisticsMapper.selectConstructSiteHistListCnt(params);
|
||||
List<EgovMap> datas = drillingStatisticsMapper.selectConstructSiteHistList(params);
|
||||
|
||||
jsonResponse.put("count", count);
|
||||
jsonResponse.put("datas", datas);
|
||||
|
||||
return jsonResponse;
|
||||
|
||||
} catch (SQLException e) {
|
||||
System.out.println("Error at getConstructSiteHistList: " + e.getMessage());
|
||||
throw new Exception("이력 조회 중 오류가 발생하였습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLEncoder;
|
||||
|
|
@ -2213,7 +2214,8 @@ public class MainController
|
|||
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setContentLength(fileByte.length);
|
||||
response.setHeader("Content-Disposition", "attachment; fileName=\"" + URLEncoder.encode(filenameDn, "utf-8") + "\";");
|
||||
String headerFilename = getContentDispositionHeader( request, filenameDn);
|
||||
response.setHeader("Content-Disposition", headerFilename);
|
||||
response.setHeader("Content-Transfer-Encoding", "binary");
|
||||
response.getOutputStream().write(fileByte);
|
||||
|
||||
|
|
@ -2223,6 +2225,7 @@ public class MainController
|
|||
else
|
||||
{
|
||||
mv.addObject("msg", "<script>alert('파일을 다운받을 수 없습니다');</script>");
|
||||
response.setContentType("text/html; charset=utf-8");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.println("<script type='text/javascript'>");
|
||||
|
|
@ -2237,6 +2240,34 @@ public class MainController
|
|||
return null;
|
||||
}
|
||||
|
||||
private String getContentDispositionHeader (HttpServletRequest request, String filenameDn) throws UnsupportedEncodingException {
|
||||
// User-Agent를 통해 브라우저 정보 획득
|
||||
String userAgent = request.getHeader("User-Agent");
|
||||
|
||||
// Content-Disposition 헤더에 사용할 파일명 변수
|
||||
String headerFilename = "";
|
||||
|
||||
// IE 계열 브라우저 체크 (MSIE 또는 Trident 포함)
|
||||
if (userAgent.contains("MSIE") || userAgent.contains("Trident") || userAgent.contains("Edge")) {
|
||||
// IE, Edge 등: UTF-8로 인코딩 후, ISO-8859-1로 변환 (역호환성을 위함)
|
||||
// URLEncoder.encode 결과는 공백이 '+'로 바뀌므로, 이를 '%20'으로 치환
|
||||
headerFilename = "attachment; filename=\"" +
|
||||
new String(URLEncoder.encode(filenameDn, "UTF-8").replaceAll("\\+", " ").getBytes("UTF-8"), "ISO-8859-1") +
|
||||
"\"";
|
||||
|
||||
// **또는 더 간단한 방법 (많이 사용됨):**
|
||||
// headerFilename = "attachment; filename=\"" + URLEncoder.encode(filenameDn, "UTF-8").replaceAll("\\+", "%20") + "\"";
|
||||
|
||||
} else {
|
||||
// Chrome, Firefox 등: UTF-8 인코딩 (URL 인코딩 결과를 그대로 사용)
|
||||
headerFilename = "attachment; filename=\"" + URLEncoder.encode(filenameDn, "UTF-8").replaceAll("\\+", "%20") + "\"";
|
||||
// RFC 5987 표준을 따르는 인코딩 방식 (권장):
|
||||
// headerFilename = "attachment; filename*=UTF-8''" + URLEncoder.encode(filenameDn, "UTF-8").replaceAll("\\+", "%20");
|
||||
}
|
||||
|
||||
return headerFilename;
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/upload-file-and-up-load-su.do")
|
||||
public ModelAndView cmuboard_save(MultipartRequest multi, HttpServletRequest request, HttpServletResponse response, Map<String, Object> map) throws Exception {
|
||||
|
|
|
|||
|
|
@ -132,4 +132,26 @@
|
|||
]]>
|
||||
</update>
|
||||
|
||||
<insert id="insertConstructSiteHist" parameterType="map">
|
||||
INSERT INTO TEMP_CONSTRUCT_SITE_HIST (
|
||||
HIST_ID,
|
||||
CID,
|
||||
PROJECT_CODE,
|
||||
PRE_PROJECT_STATE_CODE,
|
||||
PROJECT_STATE_CODE,
|
||||
MOD_REASON,
|
||||
MOD_USERID,
|
||||
MOD_DT
|
||||
) VALUES (
|
||||
CONSTRUCT_SITE_HIST_SEQ.NEXTVAL,
|
||||
#{CID},
|
||||
#{PROJECT_CODE},
|
||||
#{PRE_PROJECT_STATE_CODE},
|
||||
#{PROJECT_STATE_CODE},
|
||||
#{MOD_REASON},
|
||||
#{userId},
|
||||
SYSTIMESTAMP
|
||||
)
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -2,5 +2,59 @@
|
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="geoinfo.drilling.statistics.service.DrillingStatisticsMapper">
|
||||
|
||||
<select id="selectConstructSiteHistList" parameterType="map" resultType="egovMap">
|
||||
SELECT
|
||||
*
|
||||
FROM (
|
||||
SELECT
|
||||
ROW_NUMBER() OVER(ORDER BY h.MOD_DT DESC) AS RNUM,
|
||||
h.HIST_ID,
|
||||
h.CID,
|
||||
csi.CONST_NAME,
|
||||
h.PROJECT_CODE,
|
||||
h.PRE_PROJECT_STATE_CODE,
|
||||
h.PROJECT_STATE_CODE,
|
||||
h.MOD_REASON,
|
||||
h.MOD_USERID,
|
||||
TO_CHAR(h.MOD_DT, 'YYYY-MM-DD HH24:MI:SS') AS MOD_DT
|
||||
FROM
|
||||
TEMP_CONSTRUCT_SITE_HIST h
|
||||
JOIN
|
||||
TEMP_CONSTRUCT_SITE_INFO csi ON h.CID = csi.CID
|
||||
WHERE
|
||||
1=1
|
||||
<if test="masterCompanyOCode != null and masterCompanyOCode != ''">
|
||||
AND csi.MASTER_COMPANY_O_CODE = #{masterCompanyOCode}
|
||||
</if>
|
||||
<if test="masterCompanyTwCode != null and masterCompanyTwCode != ''">
|
||||
AND csi.MASTER_COMPANY_TW_CODE = #{masterCompanyTwCode}
|
||||
</if>
|
||||
<if test="masterCompanyThCode != null and masterCompanyThCode != ''">
|
||||
AND csi.MASTER_COMPANY_TH_CODE = #{masterCompanyThCode}
|
||||
</if>
|
||||
)
|
||||
WHERE RNUM BETWEEN #{firstIndex} AND #{lastIndex}
|
||||
</select>
|
||||
|
||||
<select id="selectConstructSiteHistListCnt" parameterType="map" resultType="long">
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM
|
||||
TEMP_CONSTRUCT_SITE_HIST h
|
||||
JOIN
|
||||
TEMP_CONSTRUCT_SITE_INFO csi ON h.CID = csi.CID
|
||||
WHERE
|
||||
1=1
|
||||
<if test="masterCompanyOCode != null and masterCompanyOCode != ''">
|
||||
AND csi.MASTER_COMPANY_O_CODE = #{masterCompanyOCode}
|
||||
</if>
|
||||
<if test="masterCompanyTwCode != null and masterCompanyTwCode != ''">
|
||||
AND csi.MASTER_COMPANY_TW_CODE = #{masterCompanyTwCode}
|
||||
</if>
|
||||
<if test="masterCompanyThCode != null and masterCompanyThCode != ''">
|
||||
AND csi.MASTER_COMPANY_TH_CODE = #{masterCompanyThCode}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -4,10 +4,7 @@
|
|||
|
||||
|
||||
<%
|
||||
|
||||
|
||||
if (request.getSession().getAttribute("USERID") == null) {
|
||||
|
||||
%>
|
||||
<script>alert('로그인후 이용하실 수 있습니다.');window.location.href='/index.do';</script>
|
||||
<%
|
||||
|
|
@ -15,9 +12,7 @@ if (request.getSession().getAttribute("USERID") == null) {
|
|||
}
|
||||
%>
|
||||
<%
|
||||
|
||||
if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSession().getAttribute("CLS") ) == false ) {
|
||||
|
||||
%>
|
||||
<script>alert('발주 기관 회원만 이용가능합니다.');window.location.href='/index.do';</script>
|
||||
<%
|
||||
|
|
@ -25,24 +20,15 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
|||
}
|
||||
%>
|
||||
|
||||
|
||||
|
||||
<%@ include file="/include/inc_head_2021_new.jsp" %>
|
||||
|
||||
|
||||
<!-- header start-->
|
||||
<c:import url="/drilling/common/includeTopMenu.do" charEncoding="UTF-8" />
|
||||
<!-- Tailwind CSS CDN -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<!-- Chart.js CDN for creating charts -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<!-- Google Fonts: Inter -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+KR:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+KR:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- header end-->
|
||||
|
||||
<style>
|
||||
@keyframes shake {
|
||||
0% { transform: translateX(0); }
|
||||
|
|
@ -57,98 +43,74 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
|||
90% { transform: translateX(-5px); }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
.shake-animation {
|
||||
animation: shake 0.6s;
|
||||
}
|
||||
|
||||
/* The snackbar - position it at the bottom and in the middle of the screen */
|
||||
#snackbar {
|
||||
visibility: hidden; /* Hidden by default. Visible on click */
|
||||
min-width: 250px; /* Set a default minimum width */
|
||||
margin-left: -125px; /* Divide value of min-width by 2 */
|
||||
background-color: #000000; /* Black background color */
|
||||
color: #ff0000; /* White text color */
|
||||
text-align: center; /* Centered text */
|
||||
border-radius: 2px; /* Rounded borders */
|
||||
padding: 16px; /* Padding */
|
||||
position: fixed; /* Sit on top of the screen */
|
||||
z-index: 1; /* Add a z-index if needed */
|
||||
left: 50%; /* Center the snackbar */
|
||||
bottom: 80px; /* 30px from the bottom */
|
||||
visibility: hidden;
|
||||
min-width: 250px;
|
||||
margin-left: -125px;
|
||||
background-color: #000000;
|
||||
color: #ff0000;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
padding: 16px;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
left: 50%;
|
||||
bottom: 80px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Show the snackbar when clicking on a button (class added with JavaScript) */
|
||||
#snackbar.show {
|
||||
visibility: visible; /* Show the snackbar */
|
||||
/* Add animation: Take 0.5 seconds to fade in and out the snackbar.
|
||||
However, delay the fade out process for 2.5 seconds */
|
||||
visibility: visible;
|
||||
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
||||
animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
||||
}
|
||||
|
||||
/* Animations to fade the snackbar in and out */
|
||||
@-webkit-keyframes fadein {
|
||||
from {bottom: 0; opacity: 0;}
|
||||
to {bottom: 80px; opacity: 1;}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from {bottom: 0; opacity: 0;}
|
||||
to {bottom: 80px; opacity: 1;}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeout {
|
||||
from {bottom: 80px; opacity: 1;}
|
||||
to {bottom: 0; opacity: 0;}
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
from {bottom: 80px; opacity: 1;}
|
||||
to {bottom: 0; opacity: 0;}
|
||||
}
|
||||
|
||||
|
||||
#suggestionList {
|
||||
border: 1px solid #ccc;
|
||||
width: 300px; /* 입력창 너비에 맞춰 조절 */
|
||||
position_: absolute;
|
||||
background-color: white;
|
||||
display: none;
|
||||
left: 91px;
|
||||
top: 54px;
|
||||
z-index: 3;
|
||||
}
|
||||
#suggestionList div {
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#suggestionList div:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
#suggestionList div .organizational-structure {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#const-state-code {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
|
||||
#suggestionList {
|
||||
border: 1px solid #ccc;
|
||||
width: 300px;
|
||||
position_: absolute;
|
||||
background-color: white;
|
||||
display: none;
|
||||
left: 91px;
|
||||
top: 54px;
|
||||
z-index: 3;
|
||||
}
|
||||
#suggestionList div {
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#suggestionList div:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
#suggestionList div .organizational-structure {
|
||||
color: red;
|
||||
}
|
||||
#const-state-code {
|
||||
width: 160px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- javascript start-->
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
</script>
|
||||
<!-- javascript end-->
|
||||
|
||||
<!-- 페이지 컨테이너 시작 -->
|
||||
<section class="drilling-page-container">
|
||||
<div class="page-content-wrapper drilling inquiry">
|
||||
<!-- 서브메뉴 시작 -->
|
||||
<div class="page-sidebar-wrapper">
|
||||
<div class="page-sidebar">
|
||||
<div class="treeview-project-name">
|
||||
|
|
@ -158,12 +120,8 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 서브메뉴 끝 -->
|
||||
|
||||
<!-- 콘텐츠 시작 -->
|
||||
<div class="page-content">
|
||||
<div class="page-content-inner">
|
||||
<!-- 카테고리 시작 -->
|
||||
<div class="category-wrapper">
|
||||
<ul class="page-category">
|
||||
<li class="category-item"></li>
|
||||
|
|
@ -171,231 +129,261 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
|||
</ul>
|
||||
<a href="#" class="btn btn-help">도움말</a>
|
||||
</div>
|
||||
<!-- 카테고리 끝 -->
|
||||
<h1 class="page-title-1depth">통계</h1>
|
||||
<!-- 내용 시작 -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Main Content -->
|
||||
<main class="flex flex-col lg:flex-row gap-4">
|
||||
<!-- Right Sidebar -->
|
||||
<aside class="w-full flex flex-col gap-4">
|
||||
<!-- Wrapper div for side-by-side layout on large screens -->
|
||||
<div class="flex flex-col lg:flex-row gap-4">
|
||||
<!-- Project Status Chart -->
|
||||
<div class="w-full lg:w-1/2 bg-white p-4 rounded-lg shadow-md">
|
||||
<h3 class="font-semibold text-gray-800 mb-2 text-4xl">건설현장 프로젝트 입력상태 별 그래프</h3>
|
||||
<div class="w-full h-[28rem] flex justify-center items-center">
|
||||
<canvas id="projectStatusChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<main class="flex flex-col lg:flex-row gap-4">
|
||||
<aside class="w-full flex flex-col gap-4">
|
||||
<div class="flex flex-col lg:flex-row gap-4">
|
||||
<div class="w-full lg:w-1/2 bg-white p-4 rounded-lg shadow-md">
|
||||
<h3 class="font-semibold text-gray-800 mb-2 text-4xl">건설현장 프로젝트 입력상태 별 그래프</h3>
|
||||
<div class="w-full h-[28rem] flex justify-center items-center">
|
||||
<canvas id="projectStatusChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notifications -->
|
||||
<div class="w-full lg:w-1/2 bg-white p-4 rounded-lg shadow-md flex flex-col">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="font-semibold text-gray-800 text-4xl">알림 내역</h3>
|
||||
<a href="../drilling/notice.do" class="text-3xl text-blue-600 hover:underline">모두 보기</a>
|
||||
</div>
|
||||
<div class="space-y-3 flex-grow">
|
||||
<div class="flex items-start p-2 bg-blue-50 rounded-lg">
|
||||
<div class="bg-blue-500 text-white rounded-full h-8 w-8 flex-shrink-0 flex items-center justify-center mr-3">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-3xl font-medium text-gray-800">수정 요청</p>
|
||||
<p class="text-2xl text-gray-600">'제3연륙교 건설 공사' 프로젝트의 시추정보 수정이 필요합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start p-2 rounded-lg">
|
||||
<div class="bg-green-500 text-white rounded-full h-8 w-8 flex-shrink-0 flex items-center justify-center mr-3">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-3xl font-medium text-gray-800">검수 완료</p>
|
||||
<p class="text-2xl text-gray-600">'충북선 달천 충주간' 프로젝트가 검수 완료되었습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full lg:w-1/2 bg-white p-4 rounded-lg shadow-md flex flex-col">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h3 class="font-semibold text-gray-800 text-4xl">알림 내역</h3>
|
||||
<a href="/drilling/notice.do" class="text-3xl text-blue-600 hover:underline">모두 보기</a>
|
||||
</div>
|
||||
|
||||
<%-- ▼▼▼ [수정] 기존 하드코딩된 알림 내역을 삭제하고, id를 부여합니다. ▼▼▼ --%>
|
||||
<div id="notification-list" class="space-y-3 flex-grow">
|
||||
</div>
|
||||
<%-- ▲▲▲ [수정] 여기까지 ▲▲▲ --%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Report Download Section -->
|
||||
<div class="bg-white p-4 rounded-lg shadow-md">
|
||||
<h3 class="font-semibold text-gray-800 mb-2 text-4xl">통계 보고서 다운로드</h3>
|
||||
<p class="text-2xl text-gray-600 mb-4">발주기관 통계 기능을 보고서 형태로 다운로드 받을 수 있습니다.</p>
|
||||
<!-- MODIFIED: Changed grid to 3 columns to allow for different chart widths -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
||||
<!-- MODIFIED: Set column span to 1 -->
|
||||
<div class="md:col-span-1 flex flex-col items-center">
|
||||
<h4 class="text-2xl font-medium text-center text-gray-700 mb-2">위험도 현황</h4>
|
||||
<div class="relative h-96 w-96">
|
||||
<canvas id="riskChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MODIFIED: Set column span to 2 to make it twice as wide -->
|
||||
<div class="md:col-span-2 flex flex-col items-center">
|
||||
<h4 class="text-2xl font-medium text-center text-gray-700 mb-2">프로젝트 재정 현황</h4>
|
||||
<!-- MODIFIED: Changed width to w-full to fill the new column span -->
|
||||
<div class="relative h-96 w-full">
|
||||
<canvas id="financialChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MODIFIED: Wrapped button in a flex container to center it and reduced its width -->
|
||||
<div class="flex justify-center">
|
||||
<!-- MODIFIED: Reduced width from md:w-1/4 to md:w-[15%] (40% reduction) -->
|
||||
<button class="w-full md:w-[15%] bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-lg flex items-center justify-center transition duration-300 text-3xl">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
|
||||
PDF로 내보내기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</main>
|
||||
<div class="bg-white p-4 rounded-lg shadow-md">
|
||||
<h3 class="font-semibold text-gray-800 mb-2 text-4xl">통계 보고서 다운로드</h3>
|
||||
<p class="text-2xl text-gray-600 mb-4">발주기관 통계 기능을 보고서 형태로 다운로드 받을 수 있습니다.</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
||||
<div class="md:col-span-1 flex flex-col items-center">
|
||||
<h4 class="text-2xl font-medium text-center text-gray-700 mb-2">위험도 현황</h4>
|
||||
<div class="relative h-96 w-96">
|
||||
<canvas id="riskChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:col-span-2 flex flex-col items-center">
|
||||
<h4 class="text-2xl font-medium text-center text-gray-700 mb-2">프로젝트 재정 현황</h4>
|
||||
<div class="relative h-96 w-full">
|
||||
<canvas id="financialChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<button class="w-full md:w-[15%] bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-lg flex items-center justify-center transition duration-300 text-3xl">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
|
||||
PDF로 내보내기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// Chart.js initialization
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// 1. Project Status Pie Chart
|
||||
const ctxProjectStatus = document.getElementById('projectStatusChart').getContext('2d');
|
||||
new Chart(ctxProjectStatus, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: ['등록완료', '미입력', '검수중', '수정요청'],
|
||||
datasets: [{
|
||||
label: '프로젝트 상태',
|
||||
data: [34, 32, 18, 16],
|
||||
backgroundColor: [
|
||||
'rgba(239, 68, 68, 0.8)', // Red
|
||||
'rgba(245, 158, 11, 0.8)', // Amber
|
||||
'rgba(16, 185, 129, 0.8)', // Emerald
|
||||
'rgba(59, 130, 246, 0.8)' // Blue
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(239, 68, 68, 1)',
|
||||
'rgba(245, 158, 11, 1)',
|
||||
'rgba(16, 185, 129, 1)',
|
||||
'rgba(59, 130, 246, 1)'
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top',
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
let label = context.label || '';
|
||||
if (label) {
|
||||
label += ': ';
|
||||
<script>
|
||||
// Chart.js initialization
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 1. Project Status Pie Chart
|
||||
var ctxProjectStatus = document.getElementById('projectStatusChart').getContext('2d');
|
||||
new Chart(ctxProjectStatus, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: ['등록완료', '미입력', '검수중', '수정요청'],
|
||||
datasets: [{
|
||||
label: '프로젝트 상태',
|
||||
data: [34, 32, 18, 16],
|
||||
backgroundColor: [ 'rgba(239, 68, 68, 0.8)', 'rgba(245, 158, 11, 0.8)', 'rgba(16, 185, 129, 0.8)', 'rgba(59, 130, 246, 0.8)' ],
|
||||
borderColor: [ 'rgba(239, 68, 68, 1)', 'rgba(245, 158, 11, 1)', 'rgba(16, 185, 129, 1)', 'rgba(59, 130, 246, 1)' ],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: { position: 'top' },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
var label = context.label || '';
|
||||
if (label) { label += ': '; }
|
||||
if (context.parsed !== null) { label += context.parsed + '%'; }
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context.parsed !== null) {
|
||||
label += context.parsed + '%';
|
||||
}
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 2. Risk Status Donut Chart
|
||||
const ctxRisk = document.getElementById('riskChart').getContext('2d');
|
||||
new Chart(ctxRisk, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['낮은 위험', '중간 위험', '높은 위험'],
|
||||
datasets: [{
|
||||
data: [41, 22, 37],
|
||||
backgroundColor: [
|
||||
'rgba(34, 197, 94, 0.8)', // Green
|
||||
'rgba(245, 158, 11, 0.8)', // Amber
|
||||
'rgba(239, 68, 68, 0.8)' // Red
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(34, 197, 94, 1)',
|
||||
'rgba(245, 158, 11, 1)',
|
||||
'rgba(239, 68, 68, 1)'
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
boxWidth: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Financial Status Bar Chart
|
||||
const ctxFinancial = document.getElementById('financialChart').getContext('2d');
|
||||
new Chart(ctxFinancial, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['프로젝트 A', '프로젝트 B', '프로젝트 C', '프로젝트 D'],
|
||||
datasets: [{
|
||||
label: '예산',
|
||||
data: [65, 59, 80, 81],
|
||||
backgroundColor: 'rgba(59, 130, 246, 0.7)',
|
||||
borderColor: 'rgba(59, 130, 246, 1)',
|
||||
borderWidth: 1
|
||||
}, {
|
||||
label: '실제 비용',
|
||||
data: [45, 49, 60, 70],
|
||||
backgroundColor: 'rgba(239, 68, 68, 0.7)',
|
||||
borderColor: 'rgba(239, 68, 68, 1)',
|
||||
borderWidth: 1
|
||||
},{
|
||||
label: '예상 비용',
|
||||
data: [75, 69, 90, 91],
|
||||
backgroundColor: 'rgba(16, 185, 129, 0.7)',
|
||||
borderColor: 'rgba(16, 185, 129, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return value + '억';
|
||||
// 2. Risk Status Donut Chart
|
||||
var ctxRisk = document.getElementById('riskChart').getContext('2d');
|
||||
new Chart(ctxRisk, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['낮은 위험', '중간 위험', '높은 위험'],
|
||||
datasets: [{
|
||||
data: [41, 22, 37],
|
||||
backgroundColor: [ 'rgba(34, 197, 94, 0.8)', 'rgba(245, 158, 11, 0.8)', 'rgba(239, 68, 68, 0.8)' ],
|
||||
borderColor: [ 'rgba(34, 197, 94, 1)', 'rgba(245, 158, 11, 1)', 'rgba(239, 68, 68, 1)' ],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: { legend: { position: 'bottom', labels: { boxWidth: 12 } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
});
|
||||
// 3. Financial Status Bar Chart
|
||||
var ctxFinancial = document.getElementById('financialChart').getContext('2d');
|
||||
new Chart(ctxFinancial, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['프로젝트 A', '프로젝트 B', '프로젝트 C', '프로젝트 D'],
|
||||
datasets: [{
|
||||
label: '예산',
|
||||
data: [65, 59, 80, 81],
|
||||
backgroundColor: 'rgba(59, 130, 246, 0.7)',
|
||||
borderColor: 'rgba(59, 130, 246, 1)',
|
||||
borderWidth: 1
|
||||
}, {
|
||||
label: '실제 비용',
|
||||
data: [45, 49, 60, 70],
|
||||
backgroundColor: 'rgba(239, 68, 68, 0.7)',
|
||||
borderColor: 'rgba(239, 68, 68, 1)',
|
||||
borderWidth: 1
|
||||
},{
|
||||
label: '예상 비용',
|
||||
data: [75, 69, 90, 91],
|
||||
backgroundColor: 'rgba(16, 185, 129, 0.7)',
|
||||
borderColor: 'rgba(16, 185, 129, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: { y: { beginAtZero: true, ticks: { callback: function(value) { return value + '억'; } } } },
|
||||
plugins: { legend: { display: false } }
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 내용 끝 -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- 콘텐츠 끝 -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- 페이지 컨테이너 끝 -->
|
||||
|
||||
<div id="calenderDiv" class="trViewOff" style="position:absolute;"></div>
|
||||
|
||||
<%@ include file="/include/inc_footer_2021_new.jsp" %>
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 페이지 로드 시 이력 목록을 불러옵니다.
|
||||
loadHistoryList();
|
||||
});
|
||||
|
||||
/**
|
||||
* 서버에 건설현장 이력 목록을 요청하는 함수
|
||||
*/
|
||||
function loadHistoryList() {
|
||||
// 알림 내역은 최신 3개만 가져오도록 설정
|
||||
var url = '/drilling/statistics/hist-list.do?page=1&rows=3';
|
||||
requesetGet(url, displayHistoryList, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 상태 코드에 따라 아이콘과 색상, 텍스트를 반환하는 함수
|
||||
*/
|
||||
function getStatusInfo(statusCode) {
|
||||
var status = {
|
||||
name: '알 수 없음',
|
||||
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>',
|
||||
bgColor: 'bg-gray-500',
|
||||
textColor: 'text-gray-600'
|
||||
};
|
||||
|
||||
switch (String(statusCode)) {
|
||||
case '0':
|
||||
status.name = '미입력';
|
||||
break;
|
||||
case '1':
|
||||
status.name = '입력 중';
|
||||
status.icon = '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.5L14.732 3.732z"></path></svg>';
|
||||
status.bgColor = 'bg-blue-500';
|
||||
status.textColor = 'text-blue-600';
|
||||
break;
|
||||
case '2':
|
||||
case '3':
|
||||
status.name = '검수중';
|
||||
status.icon = '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16l4-4m0 0l4-4m-4 4v6m0-6H8a2 2 0 00-2 2v6a2 2 0 002 2h8a2 2 0 002-2v-6a2 2 0 00-2-2h-2"></path></svg>';
|
||||
status.bgColor = 'bg-yellow-500';
|
||||
status.textColor = 'text-yellow-600';
|
||||
break;
|
||||
case '5':
|
||||
status.name = '수정 요청';
|
||||
status.icon = '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>';
|
||||
status.bgColor = 'bg-red-500';
|
||||
status.textColor = 'text-red-600';
|
||||
break;
|
||||
case '6':
|
||||
status.name = '등록 완료';
|
||||
status.icon = '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>';
|
||||
status.bgColor = 'bg-green-500';
|
||||
status.textColor = 'text-green-600';
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* API 호출 결과를 받아 화면에 이력 목록을 표시하는 콜백 함수
|
||||
*/
|
||||
function displayHistoryList(response) {
|
||||
var notificationList = document.getElementById('notification-list');
|
||||
notificationList.innerHTML = ''; // 기존 목록 초기화
|
||||
|
||||
if (response && response.resultCode === 200 && response.datas) {
|
||||
var datas = response.datas;
|
||||
var contentHtml = '';
|
||||
|
||||
for (var i = 0; i < datas.length; i++) {
|
||||
var item = datas[i];
|
||||
|
||||
var preStateInfo = getStatusInfo(item.preProjectStateCode);
|
||||
var currentStateInfo = getStatusInfo(item.projectStateCode);
|
||||
|
||||
var dateParts = item.modDt ? item.modDt.split(' ') : ['', ''];
|
||||
var ymd = dateParts[0];
|
||||
var hms = dateParts[1];
|
||||
|
||||
contentHtml +=
|
||||
'<div class="flex items-start p-2 bg-gray-50 rounded-lg">' +
|
||||
'<div class="' + currentStateInfo.bgColor + ' text-white rounded-full h-8 w-8 flex-shrink-0 flex items-center justify-center mr-3">' +
|
||||
currentStateInfo.icon +
|
||||
'</div>' +
|
||||
'<div>' +
|
||||
'<p class="text-3xl font-medium text-gray-800">\'' + item.constName + '\'</p>' +
|
||||
'<p class="text-2xl text-gray-600">' +
|
||||
'상태가 <span class="font-semibold ' + preStateInfo.textColor + '">' + preStateInfo.name + '</span>에서 ' +
|
||||
'<span class="font-semibold ' + currentStateInfo.textColor + '">' + currentStateInfo.name + '</span>으로 변경되었습니다.' +
|
||||
'</p>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
if (datas.length === 0) {
|
||||
contentHtml = '<div class="p-4 text-center text-gray-500">최근 알림 내역이 없습니다.</div>';
|
||||
}
|
||||
|
||||
notificationList.innerHTML = contentHtml;
|
||||
} else {
|
||||
notificationList.innerHTML = '<div class="p-4 text-center text-gray-500">알림 목록을 불러오는 데 실패했습니다.</div>';
|
||||
console.error("Error fetching history list:", response.resultMessage);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<%@ include file="/include/inc_footer_2021_new.jsp" %>
|
||||
|
|
@ -1,11 +1,3 @@
|
|||
let xhr;
|
||||
if(window.XMLHttpRequest) {
|
||||
xhr = new XMLHttpRequest();
|
||||
} else {
|
||||
// IE5, IE6 일때
|
||||
xhr = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
|
||||
function onClickBtnViewOnMap() {
|
||||
const projectMasterCompanyName = '${mbr.projectMasterCompanyName}';
|
||||
let projectCode = '${mbr.ProjectCode}';
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
============================================================== -->
|
||||
<!-- <link rel="stylesheet" href="/web/css/common.css"/> -->
|
||||
<script type="text/javaScript" src="/web/js/common.js"></script>
|
||||
<script language=JavaScript src="${pageContext.request.contextPath}/js/common/myXhr.js"></script>
|
||||
|
||||
<!-- ==============================================================
|
||||
공통 커스텀
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ function requesetGet(URL, callback, callbackParamAsJson) {
|
|||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
const obj = JSON.parse(xhr.responseText);
|
||||
var obj = JSON.parse(xhr.responseText);
|
||||
if (typeof callback === 'function') {
|
||||
callback(obj, callbackParamAsJson);
|
||||
}
|
||||
} else if (xhr.readyState === 4) {
|
||||
// 요청 실패 시 처리
|
||||
console.error('요청 실패:', xhr.status);
|
||||
|
|
|
|||
Loading…
Reference in New Issue