기관회원 건설현장 입력시 알림 내역 표기되도록 구현
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
|
|
@ -456,13 +456,6 @@
|
||||||
<version>3.12.0</version>
|
<version>3.12.0</version>
|
||||||
</dependency>
|
</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 -->
|
<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-dbcp</groupId>
|
<groupId>commons-dbcp</groupId>
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,14 @@ public interface DrillingInputMapper {
|
||||||
|
|
||||||
public int updateProjectCodeAndProjectStateCodeByCid(HashMap<String, Object> params) throws SQLException;
|
public int updateProjectCodeAndProjectStateCodeByCid(HashMap<String, Object> params) throws SQLException;
|
||||||
public int updateProjectCodeAndProjectStateCodeByProjectCode(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);
|
params.put("userId", userId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/*
|
|
||||||
List<EgovMap> sPGetTblCsiByCidParams = drillingInputMapper.sPGetTblCsiByCid( params );
|
|
||||||
|
|
||||||
if( sPGetTblCsiByCidParams.size() == 0 ) {
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
EgovMap tbl = sPGetTblCsiByCidParams.get(0);
|
|
||||||
*/
|
|
||||||
|
|
||||||
EgovMap tbl = drillingInputMapper.getItemByCid( params );
|
EgovMap tbl = drillingInputMapper.getItemByCid( params );
|
||||||
if( tbl != null ) {
|
if( tbl != null ) {
|
||||||
|
|
@ -162,6 +154,21 @@ public class DrillingInputServiceImpl implements DrillingInputService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return params;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
import geoinfo.drilling.inquiry.service.DrillingInquiryService;
|
import geoinfo.drilling.inquiry.service.DrillingInquiryService;
|
||||||
|
import geoinfo.drilling.statistics.service.DrillingStatisticsService;
|
||||||
import geoinfo.util.MyUtil;
|
import geoinfo.util.MyUtil;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
|
|
@ -32,6 +33,9 @@ public class DrillingStatisticsController {
|
||||||
@Autowired
|
@Autowired
|
||||||
DrillingInquiryService drillingInquiryService;
|
DrillingInquiryService drillingInquiryService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DrillingStatisticsService drillingStatisticsService;
|
||||||
|
|
||||||
@RequestMapping(value = "/drilling/statistics.do")
|
@RequestMapping(value = "/drilling/statistics.do")
|
||||||
public String drillingStatistics(@RequestParam HashMap<String, Object> params, ModelMap model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
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";
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import egovframework.rte.psl.dataaccess.util.EgovMap;
|
||||||
|
|
||||||
@Mapper("drillingStatisticsMapper")
|
@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 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.input.service.DrillingInputService;
|
||||||
import geoinfo.drilling.inquiry.service.DrillingInquiryMapper;
|
import geoinfo.drilling.inquiry.service.DrillingInquiryMapper;
|
||||||
import geoinfo.drilling.inquiry.service.DrillingInquiryService;
|
import geoinfo.drilling.inquiry.service.DrillingInquiryService;
|
||||||
|
import geoinfo.drilling.statistics.service.DrillingStatisticsMapper;
|
||||||
import geoinfo.drilling.statistics.service.DrillingStatisticsService;
|
import geoinfo.drilling.statistics.service.DrillingStatisticsService;
|
||||||
import geoinfo.main.login.service.LoginMapper;
|
import geoinfo.main.login.service.LoginMapper;
|
||||||
import geoinfo.main.login.service.LoginService;
|
import geoinfo.main.login.service.LoginService;
|
||||||
|
|
@ -32,12 +33,16 @@ import egovframework.rte.psl.dataaccess.util.EgovMap;
|
||||||
public class DrillingStatisticsServiceImpl implements DrillingStatisticsService {
|
public class DrillingStatisticsServiceImpl implements DrillingStatisticsService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Resource(name="drillingInquiryMapper")
|
@Resource(name="drillingInquiryMapper")
|
||||||
private DrillingInquiryMapper drillingInquiryMapper;
|
private DrillingInquiryMapper drillingInquiryMapper;
|
||||||
|
|
||||||
@Resource(name="drillingInputMapper")
|
@Resource(name="drillingInputMapper")
|
||||||
private DrillingInputMapper drillingInputMapper;
|
private DrillingInputMapper drillingInputMapper;
|
||||||
|
|
||||||
|
@Resource(name="drillingStatisticsMapper")
|
||||||
|
private DrillingStatisticsMapper drillingStatisticsMapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
DrillingInputService drillingInputService;
|
DrillingInputService drillingInputService;
|
||||||
|
|
||||||
|
|
@ -50,4 +55,45 @@ public class DrillingStatisticsServiceImpl implements DrillingStatisticsService
|
||||||
private LoginMapper loginMapper;
|
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.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
|
@ -2213,7 +2214,8 @@ public class MainController
|
||||||
|
|
||||||
response.setContentType("application/octet-stream");
|
response.setContentType("application/octet-stream");
|
||||||
response.setContentLength(fileByte.length);
|
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.setHeader("Content-Transfer-Encoding", "binary");
|
||||||
response.getOutputStream().write(fileByte);
|
response.getOutputStream().write(fileByte);
|
||||||
|
|
||||||
|
|
@ -2223,6 +2225,7 @@ public class MainController
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mv.addObject("msg", "<script>alert('파일을 다운받을 수 없습니다');</script>");
|
mv.addObject("msg", "<script>alert('파일을 다운받을 수 없습니다');</script>");
|
||||||
|
response.setContentType("text/html; charset=utf-8");
|
||||||
response.setCharacterEncoding("utf-8");
|
response.setCharacterEncoding("utf-8");
|
||||||
PrintWriter writer = response.getWriter();
|
PrintWriter writer = response.getWriter();
|
||||||
writer.println("<script type='text/javascript'>");
|
writer.println("<script type='text/javascript'>");
|
||||||
|
|
@ -2237,6 +2240,34 @@ public class MainController
|
||||||
return null;
|
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")
|
@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 {
|
public ModelAndView cmuboard_save(MultipartRequest multi, HttpServletRequest request, HttpServletResponse response, Map<String, Object> map) throws Exception {
|
||||||
|
|
|
||||||
|
|
@ -132,4 +132,26 @@
|
||||||
]]>
|
]]>
|
||||||
</update>
|
</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>
|
</mapper>
|
||||||
|
|
@ -3,4 +3,58 @@
|
||||||
|
|
||||||
<mapper namespace="geoinfo.drilling.statistics.service.DrillingStatisticsMapper">
|
<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>
|
</mapper>
|
||||||
|
|
@ -4,10 +4,7 @@
|
||||||
|
|
||||||
|
|
||||||
<%
|
<%
|
||||||
|
|
||||||
|
|
||||||
if (request.getSession().getAttribute("USERID") == null) {
|
if (request.getSession().getAttribute("USERID") == null) {
|
||||||
|
|
||||||
%>
|
%>
|
||||||
<script>alert('로그인후 이용하실 수 있습니다.');window.location.href='/index.do';</script>
|
<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 ) {
|
if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSession().getAttribute("CLS") ) == false ) {
|
||||||
|
|
||||||
%>
|
%>
|
||||||
<script>alert('발주 기관 회원만 이용가능합니다.');window.location.href='/index.do';</script>
|
<script>alert('발주 기관 회원만 이용가능합니다.');window.location.href='/index.do';</script>
|
||||||
<%
|
<%
|
||||||
|
|
@ -25,23 +20,14 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<%@ include file="/include/inc_head_2021_new.jsp" %>
|
<%@ include file="/include/inc_head_2021_new.jsp" %>
|
||||||
|
|
||||||
|
|
||||||
<!-- header start-->
|
|
||||||
<c:import url="/drilling/common/includeTopMenu.do" charEncoding="UTF-8" />
|
<c:import url="/drilling/common/includeTopMenu.do" charEncoding="UTF-8" />
|
||||||
<!-- Tailwind CSS CDN -->
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
<!-- Chart.js CDN for creating charts -->
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<!-- Google Fonts: Inter -->
|
<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">
|
||||||
<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>
|
<style>
|
||||||
@keyframes shake {
|
@keyframes shake {
|
||||||
|
|
@ -57,62 +43,48 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
90% { transform: translateX(-5px); }
|
90% { transform: translateX(-5px); }
|
||||||
100% { transform: translateX(0); }
|
100% { transform: translateX(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.shake-animation {
|
.shake-animation {
|
||||||
animation: shake 0.6s;
|
animation: shake 0.6s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The snackbar - position it at the bottom and in the middle of the screen */
|
|
||||||
#snackbar {
|
#snackbar {
|
||||||
visibility: hidden; /* Hidden by default. Visible on click */
|
visibility: hidden;
|
||||||
min-width: 250px; /* Set a default minimum width */
|
min-width: 250px;
|
||||||
margin-left: -125px; /* Divide value of min-width by 2 */
|
margin-left: -125px;
|
||||||
background-color: #000000; /* Black background color */
|
background-color: #000000;
|
||||||
color: #ff0000; /* White text color */
|
color: #ff0000;
|
||||||
text-align: center; /* Centered text */
|
text-align: center;
|
||||||
border-radius: 2px; /* Rounded borders */
|
border-radius: 2px;
|
||||||
padding: 16px; /* Padding */
|
padding: 16px;
|
||||||
position: fixed; /* Sit on top of the screen */
|
position: fixed;
|
||||||
z-index: 1; /* Add a z-index if needed */
|
z-index: 1;
|
||||||
left: 50%; /* Center the snackbar */
|
left: 50%;
|
||||||
bottom: 80px; /* 30px from the bottom */
|
bottom: 80px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Show the snackbar when clicking on a button (class added with JavaScript) */
|
|
||||||
#snackbar.show {
|
#snackbar.show {
|
||||||
visibility: visible; /* Show the snackbar */
|
visibility: visible;
|
||||||
/* Add animation: Take 0.5 seconds to fade in and out the snackbar.
|
|
||||||
However, delay the fade out process for 2.5 seconds */
|
|
||||||
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
||||||
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 {
|
@-webkit-keyframes fadein {
|
||||||
from {bottom: 0; opacity: 0;}
|
from {bottom: 0; opacity: 0;}
|
||||||
to {bottom: 80px; opacity: 1;}
|
to {bottom: 80px; opacity: 1;}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadein {
|
@keyframes fadein {
|
||||||
from {bottom: 0; opacity: 0;}
|
from {bottom: 0; opacity: 0;}
|
||||||
to {bottom: 80px; opacity: 1;}
|
to {bottom: 80px; opacity: 1;}
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes fadeout {
|
@-webkit-keyframes fadeout {
|
||||||
from {bottom: 80px; opacity: 1;}
|
from {bottom: 80px; opacity: 1;}
|
||||||
to {bottom: 0; opacity: 0;}
|
to {bottom: 0; opacity: 0;}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeout {
|
@keyframes fadeout {
|
||||||
from {bottom: 80px; opacity: 1;}
|
from {bottom: 80px; opacity: 1;}
|
||||||
to {bottom: 0; opacity: 0;}
|
to {bottom: 0; opacity: 0;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#suggestionList {
|
#suggestionList {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
width: 300px; /* 입력창 너비에 맞춰 조절 */
|
width: 300px;
|
||||||
position_: absolute;
|
position_: absolute;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
display: none;
|
display: none;
|
||||||
|
|
@ -130,25 +102,15 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
#suggestionList div .organizational-structure {
|
#suggestionList div .organizational-structure {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
#const-state-code {
|
#const-state-code {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- javascript start-->
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<!-- javascript end-->
|
|
||||||
|
|
||||||
<!-- 페이지 컨테이너 시작 -->
|
|
||||||
<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">
|
||||||
|
|
@ -158,12 +120,8 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
</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>
|
||||||
|
|
@ -171,17 +129,11 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
</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 Content -->
|
|
||||||
<main class="flex flex-col lg:flex-row gap-4">
|
<main class="flex flex-col lg:flex-row gap-4">
|
||||||
<!-- Right Sidebar -->
|
|
||||||
<aside class="w-full flex flex-col gap-4">
|
<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">
|
<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">
|
<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>
|
<h3 class="font-semibold text-gray-800 mb-2 text-4xl">건설현장 프로젝트 입력상태 별 그래프</h3>
|
||||||
<div class="w-full h-[28rem] flex justify-center items-center">
|
<div class="w-full h-[28rem] flex justify-center items-center">
|
||||||
|
|
@ -189,60 +141,38 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Notifications -->
|
|
||||||
<div class="w-full lg:w-1/2 bg-white p-4 rounded-lg shadow-md flex flex-col">
|
<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">
|
<div class="flex justify-between items-center mb-2">
|
||||||
<h3 class="font-semibold text-gray-800 text-4xl">알림 내역</h3>
|
<h3 class="font-semibold text-gray-800 text-4xl">알림 내역</h3>
|
||||||
<a href="../drilling/notice.do" class="text-3xl text-blue-600 hover:underline">모두 보기</a>
|
<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>
|
||||||
|
|
||||||
|
<%-- ▼▼▼ [수정] 기존 하드코딩된 알림 내역을 삭제하고, id를 부여합니다. ▼▼▼ --%>
|
||||||
|
<div id="notification-list" class="space-y-3 flex-grow">
|
||||||
</div>
|
</div>
|
||||||
|
<%-- ▲▲▲ [수정] 여기까지 ▲▲▲ --%>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Report Download Section -->
|
|
||||||
<div class="bg-white p-4 rounded-lg shadow-md">
|
<div class="bg-white p-4 rounded-lg shadow-md">
|
||||||
<h3 class="font-semibold text-gray-800 mb-2 text-4xl">통계 보고서 다운로드</h3>
|
<h3 class="font-semibold text-gray-800 mb-2 text-4xl">통계 보고서 다운로드</h3>
|
||||||
<p class="text-2xl text-gray-600 mb-4">발주기관 통계 기능을 보고서 형태로 다운로드 받을 수 있습니다.</p>
|
<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">
|
<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">
|
<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>
|
<h4 class="text-2xl font-medium text-center text-gray-700 mb-2">위험도 현황</h4>
|
||||||
<div class="relative h-96 w-96">
|
<div class="relative h-96 w-96">
|
||||||
<canvas id="riskChart"></canvas>
|
<canvas id="riskChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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>
|
<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">
|
<div class="relative h-96 w-full">
|
||||||
<canvas id="financialChart"></canvas>
|
<canvas id="financialChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- MODIFIED: Wrapped button in a flex container to center it and reduced its width -->
|
|
||||||
<div class="flex justify-center">
|
<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">
|
<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>
|
<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로 내보내기
|
PDF로 내보내기
|
||||||
|
|
@ -254,9 +184,9 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Chart.js initialization
|
// Chart.js initialization
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// 1. Project Status Pie Chart
|
// 1. Project Status Pie Chart
|
||||||
const ctxProjectStatus = document.getElementById('projectStatusChart').getContext('2d');
|
var ctxProjectStatus = document.getElementById('projectStatusChart').getContext('2d');
|
||||||
new Chart(ctxProjectStatus, {
|
new Chart(ctxProjectStatus, {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -264,18 +194,8 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: '프로젝트 상태',
|
label: '프로젝트 상태',
|
||||||
data: [34, 32, 18, 16],
|
data: [34, 32, 18, 16],
|
||||||
backgroundColor: [
|
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)' ],
|
||||||
'rgba(239, 68, 68, 0.8)', // Red
|
borderColor: [ 'rgba(239, 68, 68, 1)', 'rgba(245, 158, 11, 1)', 'rgba(16, 185, 129, 1)', 'rgba(59, 130, 246, 1)' ],
|
||||||
'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
|
borderWidth: 1
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
|
|
@ -283,19 +203,13 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: {
|
||||||
legend: {
|
legend: { position: 'top' },
|
||||||
position: 'top',
|
|
||||||
},
|
|
||||||
tooltip: {
|
tooltip: {
|
||||||
callbacks: {
|
callbacks: {
|
||||||
label: function(context) {
|
label: function(context) {
|
||||||
let label = context.label || '';
|
var label = context.label || '';
|
||||||
if (label) {
|
if (label) { label += ': '; }
|
||||||
label += ': ';
|
if (context.parsed !== null) { label += context.parsed + '%'; }
|
||||||
}
|
|
||||||
if (context.parsed !== null) {
|
|
||||||
label += context.parsed + '%';
|
|
||||||
}
|
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -305,42 +219,26 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Risk Status Donut Chart
|
// 2. Risk Status Donut Chart
|
||||||
const ctxRisk = document.getElementById('riskChart').getContext('2d');
|
var ctxRisk = document.getElementById('riskChart').getContext('2d');
|
||||||
new Chart(ctxRisk, {
|
new Chart(ctxRisk, {
|
||||||
type: 'doughnut',
|
type: 'doughnut',
|
||||||
data: {
|
data: {
|
||||||
labels: ['낮은 위험', '중간 위험', '높은 위험'],
|
labels: ['낮은 위험', '중간 위험', '높은 위험'],
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: [41, 22, 37],
|
data: [41, 22, 37],
|
||||||
backgroundColor: [
|
backgroundColor: [ 'rgba(34, 197, 94, 0.8)', 'rgba(245, 158, 11, 0.8)', 'rgba(239, 68, 68, 0.8)' ],
|
||||||
'rgba(34, 197, 94, 0.8)', // Green
|
borderColor: [ 'rgba(34, 197, 94, 1)', 'rgba(245, 158, 11, 1)', 'rgba(239, 68, 68, 1)' ],
|
||||||
'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
|
borderWidth: 1
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: true,
|
maintainAspectRatio: true,
|
||||||
plugins: {
|
plugins: { legend: { position: 'bottom', labels: { boxWidth: 12 } } }
|
||||||
legend: {
|
|
||||||
position: 'bottom',
|
|
||||||
labels: {
|
|
||||||
boxWidth: 12
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. Financial Status Bar Chart
|
// 3. Financial Status Bar Chart
|
||||||
const ctxFinancial = document.getElementById('financialChart').getContext('2d');
|
var ctxFinancial = document.getElementById('financialChart').getContext('2d');
|
||||||
new Chart(ctxFinancial, {
|
new Chart(ctxFinancial, {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -368,34 +266,124 @@ if (request.getSession().getAttribute("CLS") == null || "2".equals(request.getSe
|
||||||
options: {
|
options: {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
scales: {
|
scales: { y: { beginAtZero: true, ticks: { callback: function(value) { return value + '억'; } } } },
|
||||||
y: {
|
plugins: { legend: { display: false } }
|
||||||
beginAtZero: true,
|
|
||||||
ticks: {
|
|
||||||
callback: function(value) {
|
|
||||||
return value + '억';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</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>
|
||||||
|
|
||||||
|
<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" %>
|
<%@ 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() {
|
function onClickBtnViewOnMap() {
|
||||||
const projectMasterCompanyName = '${mbr.projectMasterCompanyName}';
|
const projectMasterCompanyName = '${mbr.projectMasterCompanyName}';
|
||||||
let projectCode = '${mbr.ProjectCode}';
|
let projectCode = '${mbr.ProjectCode}';
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
============================================================== -->
|
============================================================== -->
|
||||||
<!-- <link rel="stylesheet" href="/web/css/common.css"/> -->
|
<!-- <link rel="stylesheet" href="/web/css/common.css"/> -->
|
||||||
<script type="text/javaScript" src="/web/js/common.js"></script>
|
<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() {
|
xhr.onreadystatechange = function() {
|
||||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
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) {
|
} else if (xhr.readyState === 4) {
|
||||||
// 요청 실패 시 처리
|
// 요청 실패 시 처리
|
||||||
console.error('요청 실패:', xhr.status);
|
console.error('요청 실패:', xhr.status);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue