fix(itms): 고객 수정요청 40건 처리 — 로그인 잠금·서비스데스크 권한/검증·용어 통일·브랜딩 관리(F12) (SR_20260708)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
itms-merge-dev 2026-07-19 17:10:04 +09:00
parent feffb37021
commit 53b8f42c76
84 changed files with 3270 additions and 2232 deletions

3
.gitignore vendored
View File

@ -36,3 +36,6 @@ Thumbs.db
# 설치 패키지 빌드 산출물(make_package.sh 로 재생성)
/dist/
# MCP 설정(API 키 포함 — 커밋 금지)
.mcp.json

View File

@ -81,6 +81,24 @@ public class MainController
@Value("${custom.front_host_info}")
private String strFrontHostInfo;
// 2026.07.19 SR#1 : 시스템 관리자(KIC 담당자) 성명/호칭 동적 셋팅 (미설정 "시스템 관리자")
@Value("${custom.adminName:}")
private String strAdminName;
@Value("${custom.adminTitle:}")
private String strAdminTitle;
private String getAdminDisplay()
{
String strName = (strAdminName == null) ? "" : strAdminName.trim();
String strTitle = (strAdminTitle == null) ? "" : strAdminTitle.trim();
if(strName.equals(""))
{
return "시스템 관리자";
}
return "시스템 관리자(" + strName + (strTitle.equals("") ? "" : " " + strTitle) + ")";
}
/**
* Header Page를 조회한다.
* @param menuManageVO MenuManageVO
@ -275,6 +293,14 @@ public class MainController
return ResultData.ok(resBody);
}
// 2026.07.19 SR#1 : 계정이 잠겨 있는 경우 비밀번호 초기화 차단 + 잠금 안내 (관리자가 잠금 해제 초기화 가능)
else if(CommonUtil.nvl(userInfoMap.get("lockAt")).equals("Y"))
{
resBody.put("resultCd" , -7 );
resBody.put("resultMsg", "로그인 시도 횟수 초과로 계정이 잠겼습니다. " + getAdminDisplay() + "에게 문의 바랍니다." );
return ResultData.ok(resBody);
}
String strResetPassword = CommonUtil.getRandomChar(10);

View File

@ -283,12 +283,34 @@ public class SvcDeskController
LinkedHashMap<String, Object> resBody = new LinkedHashMap<String, Object>();
LinkedHashMap<String, Object> incidentVoMap = (LinkedHashMap<String, Object>)requestMap.get("incidentVo" ); // 인스던트 기본정보
LinkedHashMap<String, Object> incidentVoMap = (LinkedHashMap<String, Object>)requestMap.get("incidentVo" ); // 서비스 기본정보
LinkedHashMap<String, Object> reqApprovalMap = (LinkedHashMap<String, Object>)requestMap.get("reqApprovalMap" ); // 승인요청 정보
List<LinkedHashMap<String, Object>> approvalsList = (List<LinkedHashMap<String, Object>>)requestMap.get("approvalsList"); // 인스던트 결재정보
List<LinkedHashMap<String, Object>> fileList = (List<LinkedHashMap<String, Object>>)requestMap.get("fileList" ); // 인스던트 첨부파일
List<LinkedHashMap<String, Object>> approvalsList = (List<LinkedHashMap<String, Object>>)requestMap.get("approvalsList"); // 서비스 결재정보
List<LinkedHashMap<String, Object>> fileList = (List<LinkedHashMap<String, Object>>)requestMap.get("fileList" ); // 서비스 첨부파일
// 서비스 인스던트 등록
// 2026.07.19 SR#12 : 입력값 길이 예외처리 (초과 명확한 안내 + 등록 차단)
String strTitle = CommonUtil.nvl(incidentVoMap.get("vcIncidentTitle"));
String strBody = CommonUtil.nvl(incidentVoMap.get("txIncidentBody"));
if(strTitle.length() > 200)
{
resBody.put("resultCd" , "-2" );
resBody.put("resultMsg" , "제목은 200자 이내로 입력해 주세요. (현재 " + strTitle.length() + "자)" );
return ResultData.ok(resBody);
}
if(strBody.length() > 60000)
{
resBody.put("resultCd" , "-2" );
resBody.put("resultMsg" , "본문 내용이 너무 깁니다. 60,000자 이내로 입력해 주세요." );
return ResultData.ok(resBody);
}
// 2026.07.19 SR#9-2,9-3 : 접수자/접수일시는 서버 권한값으로 강제 (일반 사용자의 임의 조작 차단)
TokenInfo tokenInfoReg = CommonUtil.getAccessTokenInfo(request);
incidentVoMap.put("inRegUser" , tokenInfoReg.getUniqId()); // 접수자 ID = 로그인 사용자
incidentVoMap.put("vcRegUser" , tokenInfoReg.getUserName()); // 접수자 = 로그인 사용자
incidentVoMap.put("dtReceiptDatetime", CommonUtil.getKST("yyyy-MM-dd HH:mm")); // 접수일시 = 서버 현재시각
// 서비스 등록
LinkedHashMap<String, Object> returnMap = svcDeskService.addIncident(incidentVoMap, approvalsList, fileList, reqApprovalMap);
int iSucc = (int)returnMap.get("iSucc");

View File

@ -78,6 +78,13 @@ public class SvcDeskReqController
log.info("tokenInfo [{}]", tokenInfo.toString() );
log.info("tokenInfo [{}]", tokenInfo.getAuthorities() );
// 2026.07.19 SR#16 : 일반 사용자(비관리자) 본인이 신청한 건만 조회 (서버측 권한 제어)
String strRoleReq = CommonUtil.nvl(tokenInfo.getAuthorities());
if(strRoleReq.indexOf("ROLE_ADMIN") < 0)
{
requestMap.put("reqUserFilter", tokenInfo.getUniqId());
}
// 서비스데스크 조회
List<LinkedHashMap<String, Object>> resultList = svcDeskReqService.searchReqIncident(requestMap);
@ -202,10 +209,26 @@ public class SvcDeskReqController
LinkedHashMap<String, Object> resBody = new LinkedHashMap<String, Object>();
LinkedHashMap<String, Object> incidentReqVoMap = (LinkedHashMap<String, Object>)requestMap.get("incidentReqVo" ); // 인스던트 기본정보
List<LinkedHashMap<String, Object>> fileList = (List<LinkedHashMap<String, Object>>)requestMap.get("fileList" ); // 인스던트 첨부파일
LinkedHashMap<String, Object> incidentReqVoMap = (LinkedHashMap<String, Object>)requestMap.get("incidentReqVo" ); // 서비스 기본정보
List<LinkedHashMap<String, Object>> fileList = (List<LinkedHashMap<String, Object>>)requestMap.get("fileList" ); // 서비스 첨부파일
// 서비스 인스던트 신청 등록
// 2026.07.19 SR#12 : 입력값 길이 예외처리 (초과 명확한 안내 + 등록 차단)
String strReqTitle = CommonUtil.nvl(incidentReqVoMap.get("vcIncidentTitle"));
String strReqBody = CommonUtil.nvl(incidentReqVoMap.get("txIncidentBody"));
if(strReqTitle.length() > 200)
{
resBody.put("resultCd" , "-2" );
resBody.put("resultMsg" , "제목은 200자 이내로 입력해 주세요. (현재 " + strReqTitle.length() + "자)" );
return ResultData.ok(resBody);
}
if(strReqBody.length() > 60000)
{
resBody.put("resultCd" , "-2" );
resBody.put("resultMsg" , "본문 내용이 너무 깁니다. 60,000자 이내로 입력해 주세요." );
return ResultData.ok(resBody);
}
// 서비스 신청 등록
LinkedHashMap<String, Object> returnMap = svcDeskReqService.addReqIncident(incidentReqVoMap, fileList);
int iSucc = (int)returnMap.get("iSucc");

View File

@ -373,6 +373,15 @@ public class UserManageController
// 사용자 기본정보 추출
LinkedHashMap<String, Object> userInfoMap = userManageService.selectUser(requestMap);
// 2026.07.19 SR#1 : 계정이 잠겨 있는 경우 비밀번호 초기화 차단 (잠금 해제 초기화 가능)
if(CommonUtil.nvl(userInfoMap.get("lockAt")).equals("Y"))
{
resBody.put("resultCd" , "-2" );
resBody.put("resultMsg", "계정이 잠겨 있습니다. [로그인인증제한해제]로 잠금을 먼저 해제한 후 비밀번호를 초기화하세요." );
return ResultData.ok(resBody);
}
if(CommonUtil.nvl(userInfoMap.get("emailAdres")).equals(""))
{
resBody.put("resultCd" , "-1" );

View File

@ -35,6 +35,8 @@
, IFNULL(b.USER_NM, a.PSTGR_NM) AS frstRegisterNm
, DATE_FORMAT(a.FRST_REG_DTM, '%Y-%m-%d') AS frstRegisterPnttm
, a.INQ_CNT AS inqireCo
, ( SELECT COUNT(1) FROM TB_CMNT_INFO cc
WHERE cc.NTT_ID = a.NTT_ID AND cc.USE_AT = 'Y' ) AS cmntCnt <!-- 2026.07.19 기능개선10/F10 : 댓글 수량 -->
, a.PARNTSCTT_NO AS parnts
, a.CMNT_AT AS replyAt
, a.CMNT_LCTN AS replyLc

View File

@ -46,9 +46,12 @@
</sql>
<sql id="searchFilter">
<if test="incidentReqNum != null and incidentReqNum != ''"> AND A.VC_REQ_INCIDENT_NUM = #{incidentReqNum} </if>
<!-- 2026.07.19 SR#14 : 신청번호 부분검색(와일드카드) 지원 + 바인딩(#{}) 적용 -->
<if test="incidentReqNum != null and incidentReqNum != ''"> AND A.VC_REQ_INCIDENT_NUM LIKE CONCAT('%', #{incidentReqNum}, '%') </if>
<if test="reqUser != null and reqUser != ''"> AND A.VC_REQ_USER LIKE "%${reqUser}%" </if>
<if test="incidentTitle != null and incidentTitle != ''"> AND A.VC_INCIDENT_TITLE LIKE "%${incidentTitle}%" </if>
<!-- 2026.07.19 SR#16 : 일반 사용자는 본인 신청 건만 조회 (컨트롤러가 비관리자에 한해 reqUserFilter 주입) -->
<if test="reqUserFilter != null and reqUserFilter != ''"> AND A.IN_REQ_USER = #{reqUserFilter} </if>
</sql>
<select id="searchReqIncident" parameterType="java.util.HashMap" resultMap="reqIncident">

View File

@ -0,0 +1,86 @@
# ITMS 고객(KIC) 수정요청 백로그 — 2026-07-08 접수 / 2026-07-19 처리
> 근거: `docs/ITSM 고객 수정 요청 체크리스트_20260708.xlsx`(체크리스트 25건 + 이미지) · `docs/ITSM 기능개선 및 장애처리_V1.1_20260707.pptx`(기능개선 11 + 장애처리 4) · 소유자 추가지시 F12(브랜딩)
> 대상: URP ITMS 모노레포(`workspace/itms`) — auth / api / front / common
> 판정 구분: **즉시구현**(코드로 바로 처리) · **설계필요**(신규기능·상태전이 등 설계 선행) · **검토제안**(정책 판단 필요, 안전기본으로 처리) · **DB의존**(런타임 DB/스토어드프로시저/템플릿 데이터 필요)
---
## A. 체크리스트 25건 (xlsx)
| # | 구분 | 요약 | 대상 모듈·파일 | 난이도 | 판정 | 상태 |
|---|------|------|----------------|--------|------|------|
| 1 | 로그인 | 잠긴 계정 비밀번호 초기화 차단 + 메일 미발송 결함 | api `baseapi/main/MainController`·`itmsapi/sys/UserManageController` / front `PopPasswordReset.jsp` | 중 | 즉시구현 | 완료 |
| 2 | 로그인 | 잠금 메시지 문구 교체(시스템관리자 성명·호칭 동적) | front `basefront/MainController` + `custom.adminName/adminTitle` | 하 | 즉시구현 | 완료 |
| 3 | 로그인 | 아이디/패스워드 오입력 메시지(잠금과 구분) | front `basefront/MainController` | 하 | 즉시구현 | 완료 |
| 4 | 사용자관리 | 사용자 조회 시 원소속 부서로 표기 | api `UserSearchMapper.xml`(`TB_TASK_USER_INFO.ORG_ID`) | 중 | DB의존 | 보류 |
| 5 | 서비스데스크 | SR 프로세스 명확화(결재라인 처리자 포함·반려 이전단계 복귀·단계별 메일 7종) | api `SvcDeskService`·`SvcDeskMapper.xml`(스토어드프로시저)·`CmmUseController` 메일 / DB 템플릿 `SM_003` | 상 | 설계필요·DB의존 | 부분 |
| 6 | 서비스양식 | 빈양식 외 양식 작성(장애/이슈보고), SR기본요청양식, 서버점검양식 문구/행높이 | api 서비스양식 DB(`CM_SERVICE` 템플릿) | 중 | DB의존 | 보류 |
| 7 | 이슈보고 | "등록" 버튼 → "임시저장" | front `Report*Insert.jsp`·`Report*CopyInsert.jsp` | 하 | 즉시구현 | 완료 |
| 8 | 이슈보고 | 중복 "새로만들기" 버튼 제거 | front `ReportIssueDetail.jsp` | 하 | 즉시구현 | 완료 |
| 9 | 서비스데스크 | 조치예정자 사용자 직접선택 차단(신청) + 접수자/접수일시 서버제어(접수) | front `SvcDeskReqInsert.jsp` / api `SvcDeskController.addIncident` | 중 | 즉시구현 | 완료(완료요청일시 유지) |
| 10 | 서비스데스크 | 등록/승인요청 vs 등록 버튼 구분("등록"→"임시저장") | front `SvcDeskInsert.jsp`·`SvcDeskCopyInsert.jsp` | 하 | 즉시구현 | 완료 |
| 11 | 서비스데스크 | 텍스트 줄바꿈이 밀리는 현상 | front CSS(해당 화면 재현 필요) | 중 | 검토제안 | 보류(재현필요) |
| 12 | 서비스데스크 | 입력값 길이 예외처리 + "장애페이지 후 등록되는 이중 결함" | api `SvcDeskController`·`SvcDeskReqController` / front `SvcDeskController`·JSP | 중 | 즉시구현 | 완료 |
| 13 | 서비스데스크 | 에디터 높이 무한 증가 → 최대높이/스크롤 | front `tinymce_uritms_setting.js` | 하 | 즉시구현 | 완료 |
| 14 | 서비스데스크 | 신청번호 부분검색(와일드카드) | api `SvcDeskReqMapper.xml` | 하 | 즉시구현 | 완료 |
| 15 | 서비스데스크 | 결재 단계별 알림 발송 여부 점검 | api `CmmUseController`/`HtmlEmailUtil` + batch 발송 · SMTP | 중 | DB의존·설계 | 부분(SR5와 통합) |
| 16 | 서비스데스크 | 일반 사용자는 본인 신청건만 조회 | api `SvcDeskReqController`·`SvcDeskReqMapper.xml` | 중 | 즉시구현 | 완료 |
| 17 | 서비스데스크 | 접수번호 노출 필요성 검토 | front 신청 목록/상세 JSP | 하 | 검토제안 | 검토(유지 권고) |
| 18 | 서비스데스크 | 서비스데스크 메뉴 등록 버튼 일반 사용자 비노출 | 메뉴 권한(DB) / front `SvcDeskList.jsp` | 중 | 검토제안 | 검토(메뉴권한 권고) |
| 19 | 공통 | 오타 "없무권한" → "업무권한" | front `error/errorNoAuth.jsp` | 하 | 즉시구현 | 완료 |
| 20 | 공통 | "인스턴트"(인스던트/인시던트) → "서비스" 용어 통일 | front 전 화면(48파일 172건) | 중 | 즉시구현 | 완료 |
| 21 | 업무게시판 | 메인 카드 vs 메뉴 진입 화면 상이 | front `taskPortlet2.jsp`(고정 bbsId) vs 메뉴(DB) | 중 | 검토제안·DB의존 | 검토(정렬 권고) |
| 22 | 시스템관리 | 자동로그인 시 시스템관리 메뉴 필요성 | 메뉴/권한(DB) | 하 | 검토제안 | 검토(비노출 권고) |
| 23 | 메인페이지 | 메인 필요성 + FOOTER 레이아웃 | front `IncFooter.jsp` | 하 | 검토제안 | 부분(오타수정·유지 권고) |
| 24 | 메인페이지 | 통합검색 결과 권한 필터 | api `/api/v1/search` 매퍼(권한 컨텍스트) | 상 | 설계필요 | 부분(권고) |
| 25 | 메인페이지 | 보고서 현황 카드 텍스트 잘림 | front `MyReportsPortlet.jsp`/CSS | 하 | 검토제안 | 부분(권고) |
### SR#5 세부 분해 (SR 관리 업무 프로세스 명확화)
프로세스: **등록 → 접수 → 처리 → PM확인 → KIC담당자 최종확인**, 반려 시 이전 단계 복귀.
| 하위 | 내용 | 판정 | 상태 |
|------|------|------|------|
| 5-a | 접수 시 결재라인에 **처리자(조치예정자)** 포함(현재 미포함 → 승인 후에도 처리 가능) | 설계필요 (결재 시맨틱 변경) | 보류(설계) |
| 5-b | 반려 시 이전 단계 복귀(PM반려→처리, KIC반려→PM확인) | DB의존 (`PROC_REJECT` 등 스토어드프로시저가 저장소 밖) | 보류(DB) |
| 5-c1 | 등록 메일: 발신 등록자 / 수신 PM / 제목 `[ITSM] SR(제목) 등록` | DB의존 (템플릿 `SM_003`) + 라우팅 | 부분 |
| 5-c2 | 접수 메일: 발신 접수자(PM) / 수신 처리자 / `처리 요청` | DB의존·라우팅(`getIncidentMailReciever` type=1/3) | 부분 |
| 5-c3 | 처리 메일: 발신 처리자 / 수신 PM / `처리 완료` | DB의존 (type=6) | 부분 |
| 5-c4 | PM확인 메일: 발신 PM / 수신 KIC담당자 / `종결 요청` | DB의존 (type=4) | 부분 |
| 5-c5 | KIC종결 메일: 발신 KIC / 수신 요청자 / `종결 알림` | DB의존 | 부분 |
| 5-c6 | PM반려 메일: 발신 PM / 수신 처리자 / `반려` | DB의존 (type=5) | 부분 |
| 5-c7 | KIC반려 메일: 발신 KIC / 수신 PM / `반려` | DB의존 | 부분 |
> **구현 메모(5):** 메일 발송 인프라는 `HtmlEmailUtil.SendAlarmInsert`가 알림큐 테이블에 적재하고 **batch 모듈**(`MailKaTalkSend*Job`)이 실제 SMTP 발송한다. 코드상 수신자 라우팅(type 1~7)은 존재하나, 각 단계 제목/본문은 DB 공통코드 템플릿 `SM_003`에 있어 **문구 확정은 DB 데이터 변경**이 필요하다. 상태전이(반려 시 복귀)는 `PROC_APPROVAL/PROC_REJECT/PROC_REQ_APPROVAL` **스토어드프로시저**에 있고 저장소에 정의가 없어 **DB에서 수정**해야 한다. 처리자 결재라인 포함(5-a)은 접수측 `approvalsList`에 조치예정자를 추가하는 설계 변경으로, 승인 시맨틱에 영향이 커 별도 승인 후 진행 권고. 코드로 처리한 것: 등록 커밋 이후 메일 발송 실패가 사용자 오류화면으로 노출되던 문제(→ SR#12 try/catch).
---
## B. 기능개선 11 + 장애처리 4 (pptx) + F12(브랜딩)
| # | 구분 | 요약 | 대상 | 판정 | 상태 | 중복매핑 |
|---|------|------|------|------|------|----------|
| F01 | 기능개선 | 보고서 양식명 전체(요약) 표시 | front `ReportList.jsp` (+select 네이티브 truncation 잔존) | 검토제안 | 부분 | |
| F02 | 기능개선 | 다수 문서 선택 후 프린트·승인(관리자·kic_it) | front `ReportCheckList.jsp` 신규 체크박스+배치호출 | 설계필요 | 보류 | |
| F03 | 기능개선 | 서비스신청 시 서비스 항목 선택 제거→SR기본요청양식 고정 | front `SvcDeskReqInsert.jsp` | 즉시구현 | 완료 | SR#6 연관 |
| F04 | 기능개선 | 권한그룹관리 가입상태 표시 + 삭제상태면 등록여부 자동 N | api `AuthorGroupMapper.xml` union에 가입상태 컬럼 추가 | 설계필요·DB검증 | 보류 | |
| F05 | 기능개선 | 업무사용자관리 그룹아이디 기본값 KIC | front `UserSelectUpdt.jsp` | 즉시구현 | 완료 | |
| F06 | 기능개선 | 게시판 제목 클릭 진입 | front `ReportCheckList.jsp`(제목 링크) | 즉시구현 | 완료 | |
| F07 | 기능개선 | 사용자관리 메뉴명 통일 + 불필요 기능 제거 | DB `TB_MENU_INFO` 메뉴명 | DB의존 | 보류 | |
| F08 | 기능개선 | 권한명별 포틀릿(엔지니어·빈권한은 자산현황·보고서 처리현황 비노출) | api 포틀릿 신규 role 차원 | 설계필요 | 보류 | |
| F09 | 기능개선 | 관리자 게시물·댓글 삭제 권한 | front `NoticeInqire.jsp` + `BBSAdminManageController` | 즉시구현 | 완료 | |
| F10 | 기능개선 | 게시판 목록 조회수·댓글수 표기 | api `BBSAdminManageMapper.xml` + front `NoticeList.jsp` | 즉시구현 | 완료 | |
| F11 | 기능개선 | 그룹웨어 자동 로그인 JWT(Token) 방식 | 그룹웨어→ITMS SSO(기존 `ssoDirectlogin.do` 계약 확장) | 설계필요 | 부분(파라미터 보류) | SR#22 연관 |
| F12 | 브랜딩(소유자지시) | 로고·파비콘 업로드/교체 관리(KIC) | front `BrandingController`·`brandingManage.jsp`·`SecurityConfig`·레이아웃/헤더/로그인 JSP | 중 | 즉시구현 | 완료 |
| D01 | 장애처리 | 게시판 뒤로가기 '양식 다시 제출' 오류 | front `NoticeList/NoticeInqire`(POST→GET/PRG) | 설계필요 | 보류(권고) | |
| D02 | 장애처리 | 조회조건 유지(목록 복귀 시 검색조건 초기화) | front `ReportCheckUpdate/CopyInsert.jsp` 반환경로 | 검토제안 | 부분(권고) | |
| D03 | 장애처리 | 비밀번호 오류 vs 5회 잠금 구분 + 사번형 ID(2220105) 초기화 결함 | front `basefront/MainController` + api 초기화 흐름 | 즉시구현 | 완료 | **SR#1~3 통합** |
| D04 | 장애처리 | 검색 후 페이지네이션 시 검색조건 소실 | front `AuthorGroupManage.jsp`(pagination jsFunction) | 즉시구현 | 완료 | |
> **F11(JWT SSO) 메모:** 그룹웨어 측 발급 JWT 계약(키/클레임/발급경로)이 미확보 상태. ITMS측 수용 훅은 기존 `/main/ssoDirectlogin.do`(SecurityConfig permitAll)가 존재하므로 이를 JWT 수용 엔드포인트로 확장하는 설계로 정리하고, **연동 파라미터(서명키·iss·클레임 매핑)는 보류**로 기록한다. 실구현은 그룹웨어 계약 확보 후.
---
## 요약
- 즉시구현/완료: SR 1·2·3·7·8·9·10·12·13·14·16·19·20 + F03·F05·F06·F09·F10·F12 + D03·D04 (+ F01 부분)
- 설계필요·DB의존·검토(부분/보류): SR 4·5·6·11·15·17·18·21·22·23·24·25 + F02·F04·F07·F08·F11 + D01·D02

416
docs/SR_CHANGES_20260719.md Normal file
View File

@ -0,0 +1,416 @@
# ITMS SR 소스 변경 상세 (변경 전 → 변경 후) — 2026-07-19
> 리뷰·감사 추적용. 자격증명·AES 암호문·프로파일 yml·키파일은 변경 대상 아님(미기재). 빌드: `:api:compileJava :front:compileJava` BUILD SUCCESSFUL.
---
## SR#1 잠긴 계정 비밀번호 초기화 차단 + 메일 미발송 결함
### `api/src/main/java/com/urpsys/itmsapi/sys/controller/UserManageController.java` (관리자 초기화)
변경 전:
```java
LinkedHashMap<String, Object> userInfoMap = userManageService.selectUser(requestMap);
if(CommonUtil.nvl(userInfoMap.get("emailAdres")).equals(""))
{
resBody.put("resultCd" , "-1" );
resBody.put("resultMsg", "E-mail 이 존재하지 않습니다." );
return ResultData.ok(resBody);
}
```
변경 후:
```java
LinkedHashMap<String, Object> userInfoMap = userManageService.selectUser(requestMap);
// SR#1 : 계정이 잠겨 있으면 초기화 차단 (잠금 해제 후 가능)
if(CommonUtil.nvl(userInfoMap.get("lockAt")).equals("Y"))
{
resBody.put("resultCd" , "-2" );
resBody.put("resultMsg", "계정이 잠겨 있습니다. [로그인인증제한해제]로 잠금을 먼저 해제한 후 비밀번호를 초기화하세요." );
return ResultData.ok(resBody);
}
if(CommonUtil.nvl(userInfoMap.get("emailAdres")).equals(""))
{ ... 동일 ... }
```
### `api/src/main/java/com/urpsys/baseapi/main/controller/MainController.java` (로그인화면 초기화)
변경 전:
```java
else if(!CommonUtil.nvl(userInfoMap.get("emailAdres")).equals(requestMap.get("userEmail")))
{
resBody.put("resultCd" , -6 );
resBody.put("resultMsg", "사용자정보가 일치하지 않습니다." );
return ResultData.ok(resBody);
}
String strResetPassword = CommonUtil.getRandomChar(10);
```
변경 후:
```java
else if(!CommonUtil.nvl(userInfoMap.get("emailAdres")).equals(requestMap.get("userEmail")))
{ ... 동일 ... }
// SR#1 : 계정 잠금 시 초기화 차단 + 안내
else if(CommonUtil.nvl(userInfoMap.get("lockAt")).equals("Y"))
{
resBody.put("resultCd" , -7 );
resBody.put("resultMsg", "로그인 시도 횟수 초과로 계정이 잠겼습니다. " + getAdminDisplay() + "에게 문의 바랍니다." );
return ResultData.ok(resBody);
}
String strResetPassword = CommonUtil.getRandomChar(10);
```
### `front/.../webapp/WEB-INF/jsp/main/PopPasswordReset.jsp` (서버 안내 메시지 노출)
변경 전:
```javascript
else
{
alert("비밀번호 초기화에 실패하였습니다. \n사용자정보을 확인해주시길 바랍니다.");
}
```
변경 후:
```javascript
else
{
if(data.resultMsg != null && data.resultMsg != "") { alert(data.resultMsg); }
else { alert("비밀번호 초기화에 실패하였습니다. \n사용자정보을 확인해주시길 바랍니다."); }
}
```
---
## SR#2, SR#3, D03 로그인 메시지(잠금/오입력 구분 + 관리자 성명 동적)
### `front/src/main/java/com/urpsys/basefront/controller/MainController.java`
변경 전:
```java
if(srError[0].equals("-1")) { strErrorMsg = "고객님의 아이디는 5회 로그인 오류로 인해 잠금처리 되었습니다. 시스템 관리자에게 연락해 주세요."; }
else if(srError[0].equals("-2")) { strErrorMsg = "아이디 혹은 비밀번호을 확인해주세요. 5회 로그인 오류인경우 아이디가 잠금처리가 됩니다."; }
else if(srError[0].equals("-3")) { strErrorMsg = "아이디 혹은 비밀번호을 확인해주세요. 5회 로그인 오류인경우 아이디가 잠금처리가 됩니다."; }
```
변경 후:
```java
if(srError[0].equals("-1")) { strErrorMsg = "로그인 시도 횟수 초과로 계정이 잠겼습니다. " + getAdminDisplay() + "에게 문의 바랍니다."; }
else if(srError[0].equals("-2")) { strErrorMsg = "아이디 또는 패스워드가 잘못 되었습니다. 아이디와 패스워드를 정확히 입력해 주세요."; }
else if(srError[0].equals("-3")) { strErrorMsg = "아이디 또는 패스워드가 잘못 되었습니다. 아이디와 패스워드를 정확히 입력해 주세요."; }
```
추가(동적 관리자 표기 — 프로파일 yml `custom.adminName`/`custom.adminTitle` 미설정 시 "시스템 관리자"):
```java
@Value("${custom.adminName:}") private String strAdminName;
@Value("${custom.adminTitle:}") private String strAdminTitle;
private String getAdminDisplay() {
String n = (strAdminName==null)?"":strAdminName.trim();
String t = (strAdminTitle==null)?"":strAdminTitle.trim();
if(n.equals("")) return "시스템 관리자";
return "시스템 관리자(" + n + (t.equals("")?"":" "+t) + ")";
}
```
(api `baseapi/main/MainController`에도 동일 `getAdminDisplay()`/`@Value` 추가 — SR#1 잠금 메시지용)
---
## SR#7, SR#10 "등록" 버튼 → "임시저장"
### `front/.../jsp/itms/srm/{SvcDeskInsert,SvcDeskCopyInsert,ReportCheckInsert,ReportCheckCopyInsert,ReportIssueInsert,ReportIssueCopyInsert,ReportErrorInsert,ReportErrorCopyInsert,ReportOtherInsert,ReportOtherCopyInsert}.jsp` (10파일)
변경 전(각 파일 등록/승인요청 옆의 단독 등록 버튼):
```jsp
<button type="button" class="btn-etc" title="<spring:message code="button.create" />" onclick="fncXxxInsert(); return false;">
<spring:message code="button.create" />
</button>
```
변경 후:
```jsp
<button type="button" class="btn-etc" title="임시저장" onclick="fncXxxInsert(); return false;">
임시저장
</button>
```
(`등록/승인요청` 버튼은 그대로 유지. 단독 신청 버튼만 있는 `SvcDeskReqInsert.jsp`는 제외.)
---
## SR#8 중복 "새로만들기" 제거
### `front/.../jsp/itms/srm/ReportIssueDetail.jsp`
변경 전(승인요청 블록 + 수정/삭제 블록에 각각 새로만들기 → 2개 표출):
```jsp
<c:if test="${(privType eq 'mine' && report.inReportStatus ne 3) || privType eq 'super'}">
<!-- 새로만들기 기능 추가 -->
<button type="button" class="btn-etc" title="새로만들기" onclick="fncReportIssueCopyInsert(); return false;">새로만들기</button>
<button type="button" class="btn-etc" title="수정" onclick="fncReportIssueUpdate(); return false;">
```
변경 후(수정/삭제 블록의 중복 새로만들기 제거):
```jsp
<c:if test="${(privType eq 'mine' && report.inReportStatus ne 3) || privType eq 'super'}">
<!-- SR#8 중복 '새로만들기' 제거 (상단 승인요청 블록의 새로만들기로 일원화) -->
<button type="button" class="btn-etc" title="수정" onclick="fncReportIssueUpdate(); return false;">
```
---
## SR#9 조치예정자 직접선택 차단(신청) + 접수자/접수일시 서버제어(접수)
### `front/.../jsp/itms/srm/SvcDeskReqInsert.jsp` (조치예정자 돋보기 제거)
변경 전:
```jsp
<input type="text" name="vcChargeUser" id="vcChargeUser" style="width: 90%;" readonly value=""/>
<a href="<c:url value='/cmm/selectUserListPopup.do' />" ... onclick="fn_User_Search('조치예정', 'inChargeUser', '', 'vcChargeUser', '', '');return false;">
<img src="...btn_search.gif" alt="조치예정자 검색" title="조치예정자 검색"></a>
<input type="hidden" name="inChargeUser" id="inChargeUser" value="" >
```
변경 후:
```jsp
<!-- SR#9-1 : 서비스 선택에 따라 자동배정, 돋보기 제거 -->
<input type="text" name="vcChargeUser" id="vcChargeUser" style="width: 60%;" readonly value=""/>
<span style="color:#888;">(자동배정)</span>
<input type="hidden" name="inChargeUser" id="inChargeUser" value="" >
```
### `api/.../itmsapi/srm/controller/SvcDeskController.java` (접수자/접수일시 서버 강제)
변경 전: (클라이언트가 보낸 incidentVo 값을 그대로 서비스로 전달)
```java
LinkedHashMap<String, Object> returnMap = svcDeskService.addIncident(incidentVoMap, approvalsList, fileList, reqApprovalMap);
```
변경 후:
```java
// SR#9-2,9-3 : 접수자/접수일시 서버 권한값 강제
TokenInfo tokenInfoReg = CommonUtil.getAccessTokenInfo(request);
incidentVoMap.put("inRegUser" , tokenInfoReg.getUniqId());
incidentVoMap.put("vcRegUser" , tokenInfoReg.getUserName());
incidentVoMap.put("dtReceiptDatetime", CommonUtil.getKST("yyyy-MM-dd HH:mm"));
LinkedHashMap<String, Object> returnMap = svcDeskService.addIncident(incidentVoMap, approvalsList, fileList, reqApprovalMap);
```
(완료요청일시는 사용자 입력 성격상 유지)
---
## SR#12 입력값 길이 검증 + 이중 결함(장애페이지 후 등록) 차단
### `api/.../itmsapi/srm/controller/SvcDeskController.java``SvcDeskReqController.java` (등록 전 길이검증)
변경 전: 검증 없이 바로 등록 호출.
변경 후(양 컨트롤러 공통):
```java
String strTitle = CommonUtil.nvl(incidentVoMap.get("vcIncidentTitle"));
String strBody = CommonUtil.nvl(incidentVoMap.get("txIncidentBody"));
if(strTitle.length() > 200) { resBody.put("resultCd","-2"); resBody.put("resultMsg","제목은 200자 이내로 입력해 주세요. (현재 "+strTitle.length()+"자)"); return ResultData.ok(resBody); }
if(strBody.length() > 60000){ resBody.put("resultCd","-2"); resBody.put("resultMsg","본문 내용이 너무 깁니다. 60,000자 이내로 입력해 주세요."); return ResultData.ok(resBody); }
```
### `front/.../itmsfront/srm/controller/SvcDeskController.java` (커밋 후 메일 예외 격리)
변경 전:
```java
if(returnMap.get("resultCd").equals("0")) { commonService.sendIncidentMail(1, (int)returnMap.get("inIncidentSeq")); }
if(strReqApprovalYn.equals("Y") && returnMap.get("resultCd").equals("0")) { commonService.sendIncidentMail(3, (int)returnMap.get("inIncidentSeq")); }
```
변경 후:
```java
try {
if(returnMap.get("resultCd").equals("0")) { commonService.sendIncidentMail(1, (int)returnMap.get("inIncidentSeq")); }
if(strReqApprovalYn.equals("Y") && returnMap.get("resultCd").equals("0")) { commonService.sendIncidentMail(3, (int)returnMap.get("inIncidentSeq")); }
} catch(Exception mailEx) {
log.error("서비스 등록 후 메일발송 실패(등록은 정상): {}", mailEx.getMessage()); // 등록 결과에 영향 없음
}
```
### `front/.../jsp/itms/srm/{SvcDeskInsert,SvcDeskReqInsert}.jsp` (검증 메시지 노출 + maxlength)
변경 전:
```javascript
success: function(data) { alert("등록 완료 되었습니다."); fncSvcDeskList(); }
```
변경 후:
```javascript
success: function(data) {
if(data.resultCd != "0") { alert(data.resultMsg); return; } // SR#12 검증 실패 안내
alert("등록 완료 되었습니다."); fncSvcDeskList();
}
```
그리고 제목 input에 `maxlength="200"` 추가.
---
## SR#13 에디터 높이 무한 증가 → 최대높이
### `front/src/main/resources/static/js/tinymce_uritms_setting.js` (drawEditorWrite/drawEditorRead 2곳)
변경 전:
```javascript
height: 300,
min_height: 300, // 최소 높이
toolbar_mode: 'floating',
```
변경 후:
```javascript
height: 300,
min_height: 300, // 최소 높이
max_height: 600, // SR#13 최대 높이 제한(초과 시 내부 스크롤)
toolbar_mode: 'floating',
```
---
## SR#14 신청번호 부분검색 + SR#16 본인 신청건만 조회
### `api/.../mapper/.../itms/srm/SvcDeskReqMapper.xml`
변경 전:
```xml
<sql id="searchFilter">
<if test="incidentReqNum != null and incidentReqNum != ''"> AND A.VC_REQ_INCIDENT_NUM = #{incidentReqNum} </if>
...
</sql>
```
변경 후:
```xml
<sql id="searchFilter">
<!-- SR#14 부분검색 + 바인딩 -->
<if test="incidentReqNum != null and incidentReqNum != ''"> AND A.VC_REQ_INCIDENT_NUM LIKE CONCAT('%', #{incidentReqNum}, '%') </if>
...
<!-- SR#16 일반 사용자 본인 신청건만 -->
<if test="reqUserFilter != null and reqUserFilter != ''"> AND A.IN_REQ_USER = #{reqUserFilter} </if>
</sql>
```
### `api/.../itmsapi/srm/controller/SvcDeskReqController.java` (비관리자 필터 주입)
변경 후 추가:
```java
String strRoleReq = CommonUtil.nvl(tokenInfo.getAuthorities());
if(strRoleReq.indexOf("ROLE_ADMIN") < 0) { requestMap.put("reqUserFilter", tokenInfo.getUniqId()); }
```
---
## SR#19 오타 "없무권한" → "업무권한"
### `front/.../jsp/itms/error/errorNoAuth.jsp`
변경 전: `시스템 관리자에게 없무권한 부여후 사용하시길 바랍니다.`
변경 후: `시스템 관리자에게 업무권한 부여후 사용하시길 바랍니다.`
---
## SR#20 "인스턴트"(인스던트/인시던트) → "서비스"
front 모듈 전체 스윕 — JSP/JS/Java/XML 48파일 172건. 예:
- 변경 전: `<title> 인스던트 신청 </title>` / `confirm("인스던트 신청 처리를 하시겠습니까?")` / `<th> 인스던트 접수번호 </th>`
- 변경 후: `<title> 서비스 신청 </title>` / `confirm("서비스 신청 처리를 하시겠습니까?")` / `<th> 서비스 접수번호 </th>`
(명령: `sed 's/인스던트/서비스/g'`, `sed 's/인시던트/서비스/g'` — "인스턴스"(instance)는 미변경)
---
## SR#23 FOOTER 저작권 오타
### `front/.../jsp/main/inc/IncFooter.jsp`
변경 전: `COPYRIGHT © 20242 URP. All Right Reserved`
변경 후: `COPYRIGHT © 2024 URP. All Right Reserved`
---
## F01 보고서 양식명 전체 표시(툴팁)
### `front/.../jsp/itms/rem/ReportList.jsp`
변경 전: `<td><a href="javascript:fncSelectReport('${report.inReportForm}')" style="text-align: center;" >${report.vcFormName}</a></td>`
변경 후: `<td title="${report.vcFormName}"><a href="javascript:fncSelectReport('${report.inReportForm}')" title="${report.vcFormName}">${report.vcFormName}</a></td>`
---
## F03 서비스신청 서비스 항목 고정(SR기본요청양식)
### `front/.../jsp/itms/srm/SvcDeskReqInsert.jsp`
변경 후 추가(select 아래):
```javascript
$(function(){
var $s = $('#inServiceCode');
$s.find('option').each(function(){ if($.trim($(this).text())=='SR기본요청양식'){ $s.val($(this).val()); return false; } });
$s.css({'pointer-events':'none','background-color':'#f2f2f2'}).attr('tabindex','-1'); // 값은 제출, 변경 불가
});
```
---
## F05 그룹아이디 기본값 KIC
### `front/.../jsp/itms/sys/UserSelectUpdt.jsp`
변경 후 추가(select 아래):
```javascript
$(function(){
var $g = $('#groupId');
if($g.length>0 && ($g.val()==null || $g.val()=='')) {
$g.find('option').each(function(){ if($.trim($(this).text())=='KIC'){ $g.val($(this).val()); return false; } });
}
});
```
---
## F06 게시판 제목 클릭 진입
### `front/.../jsp/itms/srm/ReportCheckList.jsp`
변경 전(제목 = 일반 텍스트):
```jsp
<td title="${reportList.vcReportTitle}">
<c:choose><c:when test="${fn:length(reportList.vcReportTitle) > 25}">...</c:when><c:otherwise>...</c:otherwise></c:choose>
</td>
```
변경 후(제목 = 링크):
```jsp
<td title="${reportList.vcReportTitle}">
<a href="javascript:fncSelectReportCheck('${reportList.inReportSeq}')">
<c:choose>...</c:choose>
</a>
</td>
```
---
## F09 관리자 게시물/댓글 삭제 권한
### `front/.../itmsfront/bbs/controller/BBSAdminManageController.java`
변경 후 추가: `model.addAttribute("sessionAdminYn", (role.indexOf("ROLE_ADMIN")>-1)?"Y":"N");`
### `front/.../jsp/itms/bbs/admin/NoticeInqire.jsp`
변경 후: 작성자 삭제 블록 뒤에 관리자 전용 삭제 버튼 추가
```jsp
<c:if test="${result.frstRegisterId != sessionUniqId && sessionAdminYn == 'Y'}">
<button ... onclick="fn_egov_delete_notice(); return false;">삭제</button>
</c:if>
```
댓글 삭제 조건 변경 전: `<c:if test="${listCn.deleteYn eq 'Y' }">` → 변경 후: `<c:if test="${listCn.deleteYn eq 'Y' || sessionAdminYn == 'Y' }">`
---
## F10 게시판 조회수/댓글수 표기
### `api/.../mapper/.../itms/bbs/BBSAdminManageMapper.xml`
변경 후 추가(select 컬럼):
```xml
, ( SELECT COUNT(1) FROM TB_CMNT_INFO cc WHERE cc.NTT_ID = a.NTT_ID AND cc.USE_AT = 'Y' ) AS cmntCnt
```
### `front/.../jsp/itms/bbs/admin/NoticeList.jsp`
헤더에 `<th scope="col">댓글수</th>`, 본문에 `<td><c:out value="${result.cmntCnt}" /></td>` 추가(빈목록 colspan 7/5/4 → 8/6/5).
---
## F12 로고/파비콘 브랜딩 관리(KIC)
### 신규 `front/.../basefront/controller/BrandingController.java`
- `GET /branding/logo`·`/branding/favicon` : 업로드본 우선, 없으면 번들 KIC 기본자산(webapp `/branding/default/*`) 폴백. 캐시무효화 헤더.
- `GET /branding/brandingManageView.do` : 관리자 화면(비관리자 → 메인 리다이렉트).
- `POST /branding/upload.do` : 관리자 검증 + 확장자 화이트리스트(logo: svg/png/jpg/gif, favicon: ico/png/svg/jpg/gif) + 2MB 제한 + 저장파일명 서버고정(`kind.ext`, 사용자 파일명 미사용→경로조작 차단) + canonical 경로 재확인.
### `front/.../basefront/config/SecurityConfig.java`
변경 후 추가: `.antMatchers("/branding/logo", "/branding/favicon").permitAll()` (로그인 전 표출).
### 참조 변경(정적 로고/파비콘 → 동적 엔드포인트)
- `front/.../jsp/main/LoginUsr.jsp`·`LoginUsr_kic.jsp` : `${ctx}/images/main/logo.png``${ctx}/branding/logo`
- `front/.../jsp/tilesLayout/{uritms-base-main1,uritms-base-main2,uritms-base-popup1,uritms-popup1}.jsp` : `<link rel="shortcut icon" href="data:image/x-icon;,">``href="${pageContext.request.contextPath}/branding/favicon"`
- `front/.../jsp/main/inc/IncHeader.jsp` : `<h1 class="logo">``background-image:url('<c:url value="/branding/logo"/>')` 인라인 지정
### 신규 자산·화면
- `front/src/main/webapp/branding/default/logo.svg`·`favicon.jpg` (KIC 공식 자산 번들)
- `front/.../jsp/branding/brandingManage.jsp` (업로드/미리보기 화면)
---
## D04 검색 후 페이지네이션 검색조건 소실
### `front/.../jsp/itms/sys/AuthorGroupManage.jsp`
변경 전: `<ui:pagination paginationInfo="${paginationInfo}" type="image" jsFunction="fn_egov_select_linkPage"/>` (해당 함수 미정의 → 검색조건 유실)
변경 후: `<ui:pagination paginationInfo="${paginationInfo}" type="image" jsFunction="linkPage"/>` (listForm 재제출 → searchCondition/searchKeyword 유지)

View File

@ -170,7 +170,7 @@ public class CommonService
}
/**
* 인스던트 액션별 메일처리
* 서비스 액션별 메일처리
* @author urp 인프라본부 나혁제
* 작성일 : 2025.03.20
*/

View File

@ -70,6 +70,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
.antMatchers("/main/noAuth*.do" ).permitAll()
.antMatchers("/validator*" ).permitAll()
.antMatchers("/main/ssoDirectlogin.do" ).permitAll() // 2026.04.02 나혁제 SSO 로그인처리
.antMatchers("/branding/logo", "/branding/favicon").permitAll() // 2026.07.19 F12 브랜딩 로고/파비콘 공개 서빙 (로그인 페이지 표출용)
// .antMatchers("//validator*" ).permitAll()
// .antMatchers("/main/searchIdFind.do" ).permitAll()

View File

@ -0,0 +1,227 @@
package com.urpsys.basefront.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.urpsys.basefront.domain.TokenInfo;
import lombok.extern.slf4j.Slf4j;
/**
* @Class Name : BrandingController.java
* @Description : 2026.07.19 기능개선12/F12 로고/파비콘 교체 관리(KIC 브랜딩)
*
* - 공개 서빙 : GET /branding/logo, GET /branding/favicon (로그인 페이지·헤더·favicon 참조)
* - 관리자 화면 : GET /branding/brandingManageView.do (업로드/미리보기)
* - 업로드 처리 : POST /branding/upload.do (관리자만, 확장자 화이트리스트·크기제한·경로조작 차단)
*
* DB 의존 없음. 업로드본은 파일시스템(custom.brandingDir, 미설정 java.io.tmpdir/itms-branding) 저장하며
* 재기동 없이 즉시 반영된다. 업로드본이 없으면 webapp 번들 KIC 기본자산(/branding/default/*)으로 폴백한다.
*
* @author URP 인프라본부
* @since 2026.07.19
*/
@Slf4j
@Controller
public class BrandingController
{
// 허용 확장자(화이트리스트) 사용자 입력 파일명은 절대 저장경로에 사용하지 않음(경로조작 차단)
private static final List<String> ALLOW_LOGO = Arrays.asList("svg", "png", "jpg", "jpeg", "gif");
private static final List<String> ALLOW_FAVICON = Arrays.asList("ico", "png", "svg", "jpg", "jpeg", "gif");
private static final long MAX_SIZE = 2L * 1024 * 1024; // 2MB
@Value("${custom.brandingDir:}")
private String strBrandingDir;
/** 업로드 저장 디렉터리(미설정 시 임시디렉터리 하위 고정 폴더) */
private File getBrandingDir()
{
String dir = (strBrandingDir == null) ? "" : strBrandingDir.trim();
if(dir.equals(""))
{
dir = System.getProperty("java.io.tmpdir") + File.separator + "itms-branding";
}
File f = new File(dir);
if(!f.exists()) f.mkdirs();
return f;
}
private String contentType(String ext)
{
switch(ext)
{
case "svg" : return "image/svg+xml";
case "png" : return "image/png";
case "jpg" :
case "jpeg": return "image/jpeg";
case "ico" : return "image/x-icon";
case "gif" : return "image/gif";
default : return "application/octet-stream";
}
}
/** 업로드된 오버라이드 파일(kind.ext) 탐색 — 없으면 null */
private File findOverride(String kind, List<String> allow)
{
File dir = getBrandingDir();
for(String ext : allow)
{
File f = new File(dir, kind + "." + ext);
if(f.exists() && f.isFile()) return f;
}
return null;
}
/** 확장자 추출(소문자) */
private String extOf(String name)
{
if(name == null) return "";
int p = name.lastIndexOf('.');
return (p < 0) ? "" : name.substring(p + 1).toLowerCase();
}
/** 공통 서빙 로직 : 오버라이드 → 없으면 번들 기본자산 */
private void serve(String kind, List<String> allow, String defaultResource, String defaultExt
, HttpServletRequest request, HttpServletResponse response) throws IOException
{
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
File override = findOverride(kind, allow);
if(override != null)
{
response.setContentType(contentType(extOf(override.getName())));
try(InputStream in = new FileInputStream(override); OutputStream out = response.getOutputStream())
{
copy(in, out);
}
return;
}
// 번들 KIC 기본자산 폴백 (webapp /branding/default/*)
response.setContentType(contentType(defaultExt));
try(InputStream in = request.getServletContext().getResourceAsStream(defaultResource);
OutputStream out = response.getOutputStream())
{
if(in != null) copy(in, out);
}
}
private void copy(InputStream in, OutputStream out) throws IOException
{
byte[] buf = new byte[8192];
int n;
while((n = in.read(buf)) != -1) out.write(buf, 0, n);
out.flush();
}
// ---------------------------------------------------------------------
// 공개 서빙 엔드포인트 (SecurityConfig permitAll)
// ---------------------------------------------------------------------
@RequestMapping(value = "/branding/logo")
public void logo(HttpServletRequest request, HttpServletResponse response) throws IOException
{
serve("logo", ALLOW_LOGO, "/branding/default/logo.svg", "svg", request, response);
}
@RequestMapping(value = "/branding/favicon")
public void favicon(HttpServletRequest request, HttpServletResponse response) throws IOException
{
serve("favicon", ALLOW_FAVICON, "/branding/default/favicon.jpg", "jpg", request, response);
}
// ---------------------------------------------------------------------
// 관리자 화면 + 업로드 (인증 필요, 관리자 권한 검증)
// ---------------------------------------------------------------------
private boolean isAdmin(HttpServletRequest request)
{
HttpSession session = request.getSession(false);
if(session == null) return false;
Object obj = session.getAttribute("tokenInfo");
if(!(obj instanceof TokenInfo)) return false;
String auth = ((TokenInfo)obj).getAuthorities();
return (auth != null && auth.indexOf("ROLE_ADMIN") > -1);
}
@RequestMapping(value = "/branding/brandingManageView.do")
public ModelAndView brandingManageView(HttpServletRequest request)
{
ModelAndView mav = new ModelAndView();
if(!isAdmin(request))
{
mav.setViewName("redirect:/main/mainPage.do");
return mav;
}
mav.addObject("hasLogo" , findOverride("logo" , ALLOW_LOGO) != null);
mav.addObject("hasFavicon", findOverride("favicon", ALLOW_FAVICON) != null);
mav.setViewName("uritms-tiles1/branding/brandingManage");
return mav;
}
@ResponseBody
@RequestMapping(value = "/branding/upload.do")
public String upload(@RequestParam("kind") String kind
, @RequestParam("file") MultipartFile file
, HttpServletRequest request) throws IOException
{
if(!isAdmin(request))
{
return "{\"resultCd\":\"-9\",\"resultMsg\":\"관리자만 변경할 수 있습니다.\"}";
}
if(!("logo".equals(kind) || "favicon".equals(kind)))
{
return "{\"resultCd\":\"-1\",\"resultMsg\":\"잘못된 요청입니다.\"}";
}
if(file == null || file.isEmpty())
{
return "{\"resultCd\":\"-2\",\"resultMsg\":\"파일을 선택해 주세요.\"}";
}
if(file.getSize() > MAX_SIZE)
{
return "{\"resultCd\":\"-3\",\"resultMsg\":\"파일 크기는 2MB 이하만 허용됩니다.\"}";
}
List<String> allow = "logo".equals(kind) ? ALLOW_LOGO : ALLOW_FAVICON;
String ext = extOf(file.getOriginalFilename());
if(!allow.contains(ext))
{
return "{\"resultCd\":\"-4\",\"resultMsg\":\"허용되지 않는 형식입니다. (허용: " + allow + ")\"}";
}
// 저장 파일명은 서버가 고정 생성(kind.ext) 사용자 파일명 미사용 경로조작 원천 차단
File dir = getBrandingDir();
// 기존 동종 오버라이드 정리(확장자 변경 대비)
File old = findOverride(kind, allow);
if(old != null) old.delete();
File target = new File(dir, kind + "." + ext);
// canonical 경로가 지정 디렉터리 하위인지 재확인(방어적)
if(!target.getCanonicalPath().startsWith(dir.getCanonicalPath()))
{
return "{\"resultCd\":\"-5\",\"resultMsg\":\"잘못된 경로입니다.\"}";
}
Files.copy(file.getInputStream(), target.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
log.info("F12 브랜딩 업로드 완료: kind={}, ext={}, path={}", kind, ext, target.getAbsolutePath());
return "{\"resultCd\":\"0\",\"resultMsg\":\"정상적으로 변경되었습니다.\"}";
}
}

View File

@ -108,6 +108,28 @@ public class MainController
@Value("${custom.urlAuthCheck}")
private String strUrlAuthCheck; // 2026.03.12 나혁제 url 보안체크 여부
// 2026.07.19 SR#1~3 시스템 관리자(KIC 담당자) 성명/호칭 동적 셋팅 (프로파일 yml custom.adminName/custom.adminTitle 설정, 미설정 "시스템 관리자")
@Value("${custom.adminName:}")
private String strAdminName; // 시스템 관리자 성명 (: 홍길동)
@Value("${custom.adminTitle:}")
private String strAdminTitle; // 시스템 관리자 호칭 (: 과장)
/**
* 시스템 관리자 표기 문자열 생성 (SR#1~3)
* 성명 미설정: "시스템 관리자" / 성명 설정: "시스템 관리자(홍길동 과장)"
*/
private String getAdminDisplay()
{
String strName = (strAdminName == null) ? "" : strAdminName.trim();
String strTitle = (strAdminTitle == null) ? "" : strAdminTitle.trim();
if(strName.equals(""))
{
return "시스템 관리자";
}
return "시스템 관리자(" + strName + (strTitle.equals("") ? "" : " " + strTitle) + ")";
}
@RequestMapping(value={ "/", "/main/actionMain.do"})
public String actionMain(HttpServletRequest request
, HttpServletResponse response
@ -149,15 +171,18 @@ public class MainController
// 에러메세지 생성
if(srError[0].equals("-1"))
{
strErrorMsg = "고객님의 아이디는 5회 로그인 오류로 인해 잠금처리 되었습니다. 시스템 관리자에게 연락해 주세요.";
// SR#1,2 / 장애처리03 : 계정 잠금 안내 (시스템 관리자 성명·호칭 동적)
strErrorMsg = "로그인 시도 횟수 초과로 계정이 잠겼습니다. " + getAdminDisplay() + "에게 문의 바랍니다.";
}
else if(srError[0].equals("-2"))
{
strErrorMsg = "아이디 혹은 비밀번호을 확인해주세요. 5회 로그인 오류인경우 아이디가 잠금처리가 됩니다.";
// SR#3 / 장애처리03 : 아이디 또는 패스워드 오입력 (잠금과 구분)
strErrorMsg = "아이디 또는 패스워드가 잘못 되었습니다. 아이디와 패스워드를 정확히 입력해 주세요.";
}
else if(srError[0].equals("-3"))
{
strErrorMsg = "아이디 혹은 비밀번호을 확인해주세요. 5회 로그인 오류인경우 아이디가 잠금처리가 됩니다.";
// SR#3 / 장애처리03 : 아이디 또는 패스워드 오입력 (잠금과 구분)
strErrorMsg = "아이디 또는 패스워드가 잘못 되었습니다. 아이디와 패스워드를 정확히 입력해 주세요.";
}
else if(srError[0].equals("-4"))
{

View File

@ -88,7 +88,7 @@ public class ArticleCommentController
String strMoveUrl = "";
// 인스던트 상세화면을 이동
// 서비스 상세화면을 이동
if(comment.getBbsId().equals("INCIDENT"))
{
strMoveUrl = "redirect:/srm/getIncidentBySeq.do?inIncidentSeq="+comment.getNttId();
@ -131,7 +131,7 @@ public class ArticleCommentController
String strMoveUrl = "";
// 인스던트 상세화면을 이동
// 서비스 상세화면을 이동
if(comment.getBbsId().equals("INCIDENT"))
{
strMoveUrl = "redirect:/srm/getIncidentBySeq.do?inIncidentSeq="+comment.getNttId();

View File

@ -469,6 +469,9 @@ public class BBSAdminManageController
model.addAttribute("result" , returnMap.get("resultMap"));
model.addAttribute("resultCnList" , returnMap.get("resultCnList")); // 2025.04.01 나혁제 댓글정보 추가
model.addAttribute("sessionUniqId", memberVo.getTokenInfo().getUniqId());
// 2026.07.19 기능개선09/F09 : 관리자 게시물/댓글 삭제 권한 플래그
String strBbsRole = memberVo.getTokenInfo().getAuthorities();
model.addAttribute("sessionAdminYn", (strBbsRole != null && strBbsRole.indexOf("ROLE_ADMIN") > -1) ? "Y" : "N");
//----------------------------
// template 처리 (기본 BBS template 지정 포함)

View File

@ -189,7 +189,7 @@ public class ReportCheckController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strReportBody = (String)resultReportCheck.get("txReportBody");
String strReportBodyDec = CommonUtil.base64decode(strReportBody);
@ -257,7 +257,7 @@ public class ReportCheckController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strReportBody = (String)resultReportCheck.get("txReportBody");
String strReportBodyDec = CommonUtil.base64decode(strReportBody);
@ -307,16 +307,16 @@ public class ReportCheckController
List<Map<String, Object>> resultService = (List<Map<String, Object>>)returnMap.get("resultService");
List<Map<String, Object>> resultForm = (List<Map<String, Object>>)returnMap.get("resultForm");
Map<String, Object> resultTaskMap = (Map<String, Object>)returnMap.get("resultTask");
Map<String, Object> resultIncident = (Map<String, Object>)returnMap.get("resultIncident"); // 인스던트 정보 확인
Map<String, Object> resultIncident = (Map<String, Object>)returnMap.get("resultIncident"); // 서비스 정보 확인
Map<String, Object> resultAsset = (Map<String, Object>)returnMap.get("resultAsset"); // 2025.08.20 나혁제 자산정보추가
model.addAttribute("resultService" , resultService ); // 서비스 정보
model.addAttribute("resultTaskMap" , resultTaskMap ); // 작업정보
model.addAttribute("resultIncident" , resultIncident ); // 인스던트 정보
model.addAttribute("resultIncident" , resultIncident ); // 서비스 정보
model.addAttribute("resultForm" , resultForm ); // 보고서 양식 정보
model.addAttribute("resultAsset" , resultAsset ); // 보고서 양식 정보
// 인스던트 정보가 없는경우 0 으로 세팅
// 서비스 정보가 없는경우 0 으로 세팅
if(resultIncident.get("inIncidentSeq") == null)
{
model.addAttribute("inIncidentSeq", 0 );

View File

@ -180,7 +180,7 @@ public class ReportErrorController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strReportBody = (String)resultReportError.get("txReportBody");
String strReportBodyDec = CommonUtil.base64decode(strReportBody);
@ -247,7 +247,7 @@ public class ReportErrorController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strReportBody = (String)resultReportError.get("txReportBody");
String strReportBodyDec = CommonUtil.base64decode(strReportBody);
@ -294,14 +294,14 @@ public class ReportErrorController
List<Map<String, Object>> resultService = (List<Map<String, Object>>)returnMap.get("resultService");
List<Map<String, Object>> resultForm = (List<Map<String, Object>>)returnMap.get("resultForm");
Map<String, Object> resultTaskMap = (Map<String, Object>)returnMap.get("resultTask");
Map<String, Object> resultIncident = (Map<String, Object>)returnMap.get("resultIncident"); // 인스던트 정보 확인
Map<String, Object> resultIncident = (Map<String, Object>)returnMap.get("resultIncident"); // 서비스 정보 확인
model.addAttribute("resultService" , resultService ); // 서비스 정보
model.addAttribute("resultTaskMap" , resultTaskMap ); // 작업정보
model.addAttribute("resultIncident" , resultIncident ); // 인스던트 정보
model.addAttribute("resultIncident" , resultIncident ); // 서비스 정보
model.addAttribute("resultForm" , resultForm ); // 보고서 양식 정보
// 인스던트 정보가 없는경우 0 으로 세팅
// 서비스 정보가 없는경우 0 으로 세팅
if(resultIncident.get("inIncidentSeq") == null)
{
model.addAttribute("inIncidentSeq", 0 );

View File

@ -180,7 +180,7 @@ public class ReportIssueController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strReportBody = (String)resultReportIssue.get("txReportBody");
String strReportBodyDec = CommonUtil.base64decode(strReportBody);
@ -247,7 +247,7 @@ public class ReportIssueController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strReportBody = (String)resultReportIssue.get("txReportBody");
String strReportBodyDec = CommonUtil.base64decode(strReportBody);
@ -295,14 +295,14 @@ public class ReportIssueController
List<Map<String, Object>> resultService = (List<Map<String, Object>>)returnMap.get("resultService");
List<Map<String, Object>> resultForm = (List<Map<String, Object>>)returnMap.get("resultForm");
Map<String, Object> resultTaskMap = (Map<String, Object>)returnMap.get("resultTask");
Map<String, Object> resultIncident = (Map<String, Object>)returnMap.get("resultIncident"); // 인스던트 정보 확인
Map<String, Object> resultIncident = (Map<String, Object>)returnMap.get("resultIncident"); // 서비스 정보 확인
model.addAttribute("resultService" , resultService ); // 서비스 정보
model.addAttribute("resultTaskMap" , resultTaskMap ); // 작업정보
model.addAttribute("resultIncident" , resultIncident ); // 인스던트 정보
model.addAttribute("resultIncident" , resultIncident ); // 서비스 정보
model.addAttribute("resultForm" , resultForm ); // 보고서 양식 정보
// 인스던트 정보가 없는경우 0 으로 세팅
// 서비스 정보가 없는경우 0 으로 세팅
if(resultIncident.get("inIncidentSeq") == null)
{
model.addAttribute("inIncidentSeq", 0 );

View File

@ -181,7 +181,7 @@ public class ReportOtherController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strReportBody = (String)resultReportOther.get("txReportBody");
String strReportBodyDec = CommonUtil.base64decode(strReportBody);
@ -247,7 +247,7 @@ public class ReportOtherController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strReportBody = (String)resultReportOther.get("txReportBody");
String strReportBodyDec = CommonUtil.base64decode(strReportBody);
@ -298,14 +298,14 @@ public class ReportOtherController
List<Map<String, Object>> resultService = (List<Map<String, Object>>)returnMap.get("resultService");
List<Map<String, Object>> resultForm = (List<Map<String, Object>>)returnMap.get("resultForm");
Map<String, Object> resultTaskMap = (Map<String, Object>)returnMap.get("resultTask");
Map<String, Object> resultIncident = (Map<String, Object>)returnMap.get("resultIncident"); // 인스던트 정보 확인
Map<String, Object> resultIncident = (Map<String, Object>)returnMap.get("resultIncident"); // 서비스 정보 확인
model.addAttribute("resultService" , resultService ); // 서비스 정보
model.addAttribute("resultTaskMap" , resultTaskMap ); // 작업정보
model.addAttribute("resultIncident" , resultIncident ); // 인스던트 정보
model.addAttribute("resultIncident" , resultIncident ); // 서비스 정보
model.addAttribute("resultForm" , resultForm ); // 보고서 양식 정보
// 인스던트 정보가 없는경우 0 으로 세팅
// 서비스 정보가 없는경우 0 으로 세팅
if(resultIncident.get("inIncidentSeq") == null)
{
model.addAttribute("inIncidentSeq", 0 );

View File

@ -77,7 +77,7 @@ public class SvcDeskController
CommonService commonService;
/**
* 서비스 데스크 인스던트 목록을 조회한다.
* 서비스 데스크 서비스 목록을 조회한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.08
*/
@ -138,7 +138,7 @@ public class SvcDeskController
}
/**
* 서비스 데스크 인스던트 상세조회 화면으로 이동한다.
* 서비스 데스크 서비스 상세조회 화면으로 이동한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.13
*/
@ -187,7 +187,7 @@ public class SvcDeskController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strIncidentBody = (String)resultIncident.get("txIncidentBody");
String strIncidentBodyDec = CommonUtil.base64decode(strIncidentBody);
@ -215,7 +215,7 @@ public class SvcDeskController
}
/**
* 서비스 데스크 인스던트 인쇄 화면 오픈
* 서비스 데스크 서비스 인쇄 화면 오픈
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.15
*/
@ -261,7 +261,7 @@ public class SvcDeskController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strIncidentBody = (String)resultIncident.get("txIncidentBody");
String strIncidentBodyDec = CommonUtil.base64decode(strIncidentBody);
@ -286,7 +286,7 @@ public class SvcDeskController
/**
* 서비스 데스크 인스던트 등록 화면으로 이동한다.
* 서비스 데스크 서비스 등록 화면으로 이동한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.13
*/
@ -338,7 +338,7 @@ public class SvcDeskController
// 서비스코드
String strInServiceCode = CommonUtil.nvl(resultReqIncident.get("inServiceCode"));
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strIncidentBody = (String)resultReqIncident.get("txIncidentBody");
String strIncidentBodyDec = CommonUtil.base64decode(strIncidentBody);
@ -382,7 +382,7 @@ public class SvcDeskController
}
/**
* 서비스 데스크 인스던트 수정 화면으로 이동한다.
* 서비스 데스크 서비스 수정 화면으로 이동한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.13
*/
@ -433,7 +433,7 @@ public class SvcDeskController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strIncidentBody = (String)resultIncident.get("txIncidentBody");
String strIncidentBodyDec = CommonUtil.base64decode(strIncidentBody);
@ -473,7 +473,7 @@ public class SvcDeskController
}
/**
* 서비스 데스크 인스던트 새로만들기 화면으로 이동한다.
* 서비스 데스크 서비스 새로만들기 화면으로 이동한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2026.01.21
*/
@ -522,7 +522,7 @@ public class SvcDeskController
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strIncidentBody = (String)resultIncident.get("txIncidentBody");
String strIncidentBodyDec = CommonUtil.base64decode(strIncidentBody);
@ -586,7 +586,7 @@ public class SvcDeskController
/**
* 서비스데스크 인스던트 등록 처리를 한다.
* 서비스데스크 서비스 등록 처리를 한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.13
*/
@ -701,6 +701,10 @@ public class SvcDeskController
String strReqApprovalYn = CommonUtil.getData(request, "reqApprovalYn");
// 2026.07.19 SR#12 : 등록(커밋) 이후의 메일발송 실패가 사용자에게 오류페이지로 노출되어
// 'DB에는 등록됐는데 에러화면' 이중 결함을 유발하던 문제 try/catch로 격리
try
{
// 접수처리 메일처리
if(returnMap.get("resultCd").equals("0"))
{
@ -712,6 +716,12 @@ public class SvcDeskController
{
commonService.sendIncidentMail(3, (int)returnMap.get("inIncidentSeq"));
}
}
catch(Exception mailEx)
{
// 메일 발송 실패는 등록 결과에 영향을 주지 않음 (등록은 이미 정상 처리됨)
log.error("서비스 등록 후 메일발송 실패(등록은 정상): {}", mailEx.getMessage());
}
log.info("<<<<<<<<<<<<<<< /srm/addIncident.do >>>>>>>>>>>>>>>");
@ -719,7 +729,7 @@ public class SvcDeskController
}
/**
* 서비스데스크 인스던트 수정 처리를 한다.
* 서비스데스크 서비스 수정 처리를 한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.14
*/
@ -878,7 +888,7 @@ public class SvcDeskController
}
/**
* 서비스데스크 인스던트 삭제 처리를 한다.
* 서비스데스크 서비스 삭제 처리를 한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.24
*/
@ -915,7 +925,7 @@ public class SvcDeskController
}
/**
* 서비스데스크 인스던트 승인요청 처리를 한다.
* 서비스데스크 서비스 승인요청 처리를 한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.24
*/
@ -978,7 +988,7 @@ public class SvcDeskController
/**
* 서비스데스크 인스던트 처리완료 처리를 한다.
* 서비스데스크 서비스 처리완료 처리를 한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.15
*/
@ -1041,7 +1051,7 @@ public class SvcDeskController
}
/**
* 인스던트 승인 처리를 한다.
* 서비스 승인 처리를 한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.24
*/
@ -1103,7 +1113,7 @@ public class SvcDeskController
}
/**
* 인스던트 반려 처리를 한다.
* 서비스 반려 처리를 한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.02.24
*/

View File

@ -77,7 +77,7 @@ public class SvcDeskReqController
CommonService commonService;
/**
* 서비스 데스크 인스던트 신청 목록을 조회한다.
* 서비스 데스크 서비스 신청 목록을 조회한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.12.15
*/
@ -128,7 +128,7 @@ public class SvcDeskReqController
}
/**
* 서비스 데스크 인스던트 신청 상세조회 화면으로 이동한다.
* 서비스 데스크 서비스 신청 상세조회 화면으로 이동한다.
* @author URP 인프라본부 나혁제
* 작성일 : 2025.12.16
*/
@ -165,7 +165,7 @@ public class SvcDeskReqController
log.info("strCompletedYn [{}]", strCompletedYn );
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strIncidentBody = (String)resultReqIncident.get("txIncidentBody");
String strIncidentBodyDec = CommonUtil.base64decode(strIncidentBody);
@ -220,7 +220,7 @@ public class SvcDeskReqController
/**
* 서비스 데스크 인스던트 신청 등록 화면으로 이동한다.
* 서비스 데스크 서비스 신청 등록 화면으로 이동한다.
* @author URP 인프라본부 나혁제
* 작성일 : 2025.12.15
*/
@ -270,7 +270,7 @@ public class SvcDeskReqController
}
/**
* 서비스 데스크 인스던트 신청 수정 화면으로 이동한다.
* 서비스 데스크 서비스 신청 수정 화면으로 이동한다.
* @author URP 인프라본부 나혁제
* 작성일 : 2025.12.16
*/
@ -300,7 +300,7 @@ public class SvcDeskReqController
Map<String, Object> resultReqIncident = (Map<String, Object>)returnMap.get("resultReqIncident");
// RestApi Call End ---------------------------------
// 인스던트 본문 복호화처리
// 서비스 본문 복호화처리
String strIncidentBody = (String)resultReqIncident.get("txIncidentBody");
String strIncidentBodyDec = CommonUtil.base64decode(strIncidentBody);
@ -342,7 +342,7 @@ public class SvcDeskReqController
/**
* 서비스데스크 인스던트 신청 등록 처리를 한다.
* 서비스데스크 서비스 신청 등록 처리를 한다.
* @author URP 인프라본부 나혁제
* 작성일 : 2025.12.15
*/
@ -421,7 +421,7 @@ public class SvcDeskReqController
}
/**
* 서비스데스크 인스던트 신청 수정 처리를 한다.
* 서비스데스크 서비스 신청 수정 처리를 한다.
* @author URP 인프라본부 나혁제
* 작성일 : 2025.12.17
*/
@ -516,7 +516,7 @@ public class SvcDeskReqController
}
/**
* 서비스데스크 인스던트 신청정보 삭제 처리를 한다.
* 서비스데스크 서비스 신청정보 삭제 처리를 한다.
* @author urp 인프라본부 나혁제
* 작성일 : 2025.12.18
*/
@ -553,7 +553,7 @@ public class SvcDeskReqController
}
/**
* 인스던트 신청정보 반려 처리를 한다.
* 서비스 신청정보 반려 처리를 한다.
* @author URP 인프라본부 나혁제
* 작성일 : 2025.12.18
*/

View File

@ -1,7 +1,7 @@
package com.urpsys.itmsfront.srm.domain;
/**
* 서비스데스크 인스던트 신청 처리 model 클래스를 정의한다.
* 서비스데스크 서비스 신청 처리 model 클래스를 정의한다.
* @author urp 인프라본부 나혁제
* @since 2025.12.15
* @version 1.0

View File

@ -1,7 +1,7 @@
package com.urpsys.itmsfront.srm.domain;
/**
* 서비스데스크 인스던트 처리 model 클래스를 정의한다.
* 서비스데스크 서비스 처리 model 클래스를 정의한다.
* @author urp 인프라본부 나혁제
* @since 2025.02.13
* @version 1.0

View File

@ -29,6 +29,7 @@ function drawEditorWrite(strBody, content)
selector: strSelector,
height: 300,
min_height: 300, // 최소 높이
max_height: 600, // 2026.07.19 SR#13 최대 높이 제한 (초과 시 에디터 내부 스크롤)
toolbar_mode: 'floating',
//image upload
image_title: true,
@ -134,6 +135,7 @@ function drawEditorRead(strBody, content)
selector: strSelector,
height: 300,
min_height: 300, // 최소 높이
max_height: 600, // 2026.07.19 SR#13 최대 높이 제한 (초과 시 에디터 내부 스크롤)
toolbar_mode: 'floating',
// readonly: 1,
menubar: false,

View File

@ -55,7 +55,7 @@
</field>
</form>
<!-- 서비스데스크 인스던트 처리 -->
<!-- 서비스데스크 서비스 처리 -->
<form name="svcDeskManage">
<field property="XXXXXXX" depends="">
</field>
@ -70,7 +70,7 @@
</field>
</form>
<!-- 서비스데스크 인스던트 처리 -->
<!-- 서비스데스크 서비스 처리 -->
<form name="svcDeskReqManage">
<field property="XXXXXXX" depends="">
</field>

View File

@ -0,0 +1,115 @@
<!DOCTYPE html>
<%--
* @Class Name : brandingManage.jsp
* @Description : 2026.07.19 기능개선12/F12 — 로고/파비콘 교체 관리(KIC 브랜딩)
* @author URP 인프라본부
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<title> 로고/파비콘 관리 </title>
<script type="text/javaScript" language="javascript">
function fncUpload(kind)
{
var inputId = (kind == 'logo') ? 'logoFile' : 'faviconFile';
var f = document.getElementById(inputId);
if(!f || f.files.length == 0)
{
alert("파일을 선택해 주세요.");
return;
}
var formData = new FormData();
formData.append("kind", kind);
formData.append("file", f.files[0]);
$.ajax({
url: '<c:url value="/branding/upload.do"/>'
, type: 'post'
, data: formData
, processData: false
, contentType: false
, cache: false
, dataType: 'json'
, success: function(data)
{
alert(data.resultMsg);
if(data.resultCd == "0")
{
// 재기동 없이 즉시 반영 — 캐시 무력화 위해 타임스탬프 부여
var ts = new Date().getTime();
if(kind == 'logo') $('#previewLogo').attr('src', '<c:url value="/branding/logo"/>?t=' + ts);
if(kind == 'favicon') $('#previewFavicon').attr('src', '<c:url value="/branding/favicon"/>?t=' + ts);
}
}
, error: function(e)
{
alert("업로드 중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(e));
}
});
}
</script>
<div class="body_wrap">
<!-- main title -->
<div class="main_titWrap">
<h3>로고 / 파비콘 관리</h3>
<div class="location">
<div class="location-cont">
<div>
<ul class="route_navi">
<li><a href="#" title="홈"><span class="home">홈</span></a></li>
<li><a href="#" title="시스템관리">시스템관리</a></li>
<li>로고/파비콘 관리</li>
</ul>
</div>
</div>
</div>
</div>
<!--//main title -->
<div class="bbs_view">
<table class="tbl_form">
<caption>로고/파비콘 관리</caption>
<colgroup>
<col style="width: 15%;">
<col style="width: 35%">
<col style="width: 20%">
<col style="width: 30%;">
</colgroup>
<tbody>
<tr>
<th> 로고 </th>
<td>
<img id="previewLogo" src="<c:url value='/branding/logo'/>" alt="로고 미리보기" style="max-height:40px; background:#fff; padding:4px; border:1px solid #eee;">
</td>
<th> 로고 파일 </th>
<td>
<input type="file" id="logoFile" accept=".svg,.png,.jpg,.jpeg,.gif">
<button type="button" class="btn-etc" onclick="fncUpload('logo'); return false;">변경</button>
<div style="color:#888; font-size:12px;">허용: svg/png/jpg/gif, 2MB 이하</div>
</td>
</tr>
<tr>
<th> 파비콘 </th>
<td>
<img id="previewFavicon" src="<c:url value='/branding/favicon'/>" alt="파비콘 미리보기" style="max-height:32px; background:#fff; padding:4px; border:1px solid #eee;">
</td>
<th> 파비콘 파일 </th>
<td>
<input type="file" id="faviconFile" accept=".ico,.png,.svg,.jpg,.jpeg,.gif">
<button type="button" class="btn-etc" onclick="fncUpload('favicon'); return false;">변경</button>
<div style="color:#888; font-size:12px;">허용: ico/png/svg/jpg/gif, 2MB 이하</div>
</td>
</tr>
</tbody>
</table>
<p style="color:#888; margin-top:10px;">※ 변경 시 재기동 없이 즉시 반영됩니다. 업로드본이 없으면 KIC 기본 로고/파비콘이 표시됩니다.</p>
</div>
</div>

View File

@ -327,6 +327,12 @@
<spring:message code="button.delete" />
</button>
</c:if>
<%-- 2026.07.19 기능개선09/F09 : 관리자는 타인 게시물도 삭제 가능 --%>
<c:if test="${result.frstRegisterId != sessionUniqId && sessionAdminYn == 'Y'}">
<button type="button" class="btn-etc" onclick="fn_egov_delete_notice(); return false;" title="<spring:message code="button.delete" />">
<spring:message code="button.delete" />
</button>
</c:if>
<%-- 2025.04.01 나혁제 댓글형태 변경
<c:if test="${result.replyPosblAt == 'Y'}">
@ -390,7 +396,8 @@
<strong style='font-weight: bold; margin-right: 20px;'> ${listCn.wrterNm} </strong>
<span> ${listCn.frstRegisterPnttm} </span>
<div align='right' style='display: inline-table; float: right;'>
<c:if test="${listCn.deleteYn eq 'Y' }">
<%-- 2026.07.19 기능개선09/F09 : 작성자 또는 관리자면 댓글 삭제 가능 --%>
<c:if test="${listCn.deleteYn eq 'Y' || sessionAdminYn == 'Y' }">
<a href="javascript:fn_egov_deleteCommentList('${listCn.commentNo}', '${result.bbsId}', '${result.nttId}')" >
<spring:message code="button.delete" />
</a>

View File

@ -213,6 +213,7 @@
</c:if>
<th scope="col">작성일</th>
<th scope="col">조회수</th>
<th scope="col">댓글수</th><!-- 2026.07.19 기능개선10/F10 : 댓글수 표기 -->
</tr>
</thead>
@ -221,17 +222,17 @@
<tr>
<c:choose>
<c:when test="${brdMstrVO.bbsAttrbCode == 'BBSA01'}">
<td colspan="7"><spring:message code="common.nodata.msg" /></td>
<td colspan="8"><spring:message code="common.nodata.msg" /></td>
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${anonymous == 'true'}">
<td colspan="4"><spring:message code="common.nodata.msg" /></td>
<td colspan="5"><spring:message code="common.nodata.msg" /></td>
</c:when>
<c:otherwise>
<td colspan="5"><spring:message code="common.nodata.msg" /></td>
<td colspan="6"><spring:message code="common.nodata.msg" /></td>
</c:otherwise>
</c:choose>
</c:otherwise>
@ -284,6 +285,7 @@
<td><c:out value="${result.frstRegisterPnttm}" /></td>
<td><c:out value="${result.inqireCo}" /></td>
<td><c:out value="${result.cmntCnt}" /></td><!-- 2026.07.19 기능개선10/F10 : 댓글수 -->
</tr>
</c:forEach>
</tbody>

View File

@ -54,7 +54,7 @@
해당 사용자는 현재 업무에 대해 처리권한이 없습니다.
<span class="error_message">
서비스 이용에 불편을 드려 죄송합니다.<br>
시스템 관리자에게 무권한 부여후 사용하시길 바랍니다.
시스템 관리자에게 무권한 부여후 사용하시길 바랍니다.
</span>
</h4>
</li>

View File

@ -52,7 +52,7 @@
$(location).attr("href", "/srm/getReportWithBodyIssue.do?inReportSeq="+strId+strMenu);
}
}
// 인스던트
// 서비스
else if(strInType == '2')
{
strMenu = "&baseMenuNo=3000000&leftMenuNo=3010000";

View File

@ -161,7 +161,7 @@
<c:out value="${(searchVO.pageIndex-1) * searchVO.pageSize + status.count}"/>
</td>
<td><c:out value="${report.inTaskNm}"/></td>
<td><a href="javascript:fncSelectReport('${report.inReportForm}')" style="text-align: center;" >${report.vcFormName}</a></td>
<td><a href="javascript:fncSelectReport('${report.inReportForm}')" title="${report.vcFormName}">${report.vcFormName}</a></td>
<td><c:out value="${report.vcTaskUser}"/></td>
<td><c:out value="${report.inSortSn}"/></td>
<td><c:out value="${report.vcFormDesc}"/></td>

View File

@ -68,7 +68,7 @@
{
var strMenu = "";
// 인스던트
// 서비스
if(strGb=="1")
{
strMenu = "&baseMenuNo=3000000&leftMenuNo=3010000";
@ -154,7 +154,7 @@
<!-- 카테고리 : 키워드 검색 건수 -->
<div class="search-tit">
<c:if test="${strGb == '1'}"><strong>인스던트</strong></c:if>
<c:if test="${strGb == '1'}"><strong>서비스</strong></c:if>
<c:if test="${strGb == '2'}"><strong>보고서</strong></c:if>
<c:if test="${strGb == '2'}"><strong>게시판</strong></c:if>

View File

@ -66,7 +66,7 @@
}
//----------------------------------------
// 인스던트 상세조회 화면 이동
// 서비스 상세조회 화면 이동
// ----------------------------------------
function DataDetailIncidentSearch(strId)
{
@ -159,7 +159,7 @@
<div class="search-list-box">
<!-- 카테고리 : 키워드 검색 건수 -->
<div class="search-tit">
<strong>인스던트</strong>
<strong>서비스</strong>
<span>'<span class="keyword">${searchVO.searchKeyword}</span>'&nbsp;관련 정보 총<span class="keyword_num">${iIncidentCnt}</span>건</span>
</div>
<!--//카테고리 : 키워드 검색 건수 -->

View File

@ -700,7 +700,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td> </td>
<th> 작업분류 </th>
<td>
@ -923,8 +923,8 @@
<button type="button" class="btn-etc" onclick="fncReportCheckInsertApp(); return false;" title="등록/승인요청" >
등록/승인요청
</button>
<button type="button" class="btn-etc" onclick="fncReportCheckInsert(); return false;" title="<spring:message code="button.create" />">
<spring:message code="button.create" />
<button type="button" class="btn-etc" onclick="fncReportCheckInsert(); return false;" title="임시저장">
임시저장
</button>
</div>
<!-- // 오른쪽영역-->

View File

@ -503,7 +503,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>
${incidentId}
</td>

View File

@ -811,7 +811,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>${resultIncident.vcIncidentNum} </td>
<th> 작업분류 </th>
<td>
@ -992,8 +992,8 @@
<button type="button" class="btn-etc" onclick="fncReportCheckInsertApp(); return false;" title="등록/승인요청" >
등록/승인요청
</button>
<button type="button" class="btn-etc" onclick="fncReportCheckInsert(); return false;" title="<spring:message code="button.create" />">
<spring:message code="button.create" />
<button type="button" class="btn-etc" onclick="fncReportCheckInsert(); return false;" title="임시저장">
임시저장
</button>
</div>
<!-- // 오른쪽영역-->

View File

@ -164,7 +164,7 @@
<input class="s_input" id="reportId" name="reportId" type="text" size="35" maxlength="155" style="width: 155px;"
value='<c:out value="${searchVO.reportId}"/>' title="<spring:message code="title.search" /> <spring:message code="input.input" />" >
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<label>인스던트 접수번호:</label>
<label>서비스 접수번호:</label>
<input class="s_input" id="incidentNum" name="incidentNum" type="text" size="35" maxlength="155" style="width: 155px;"
value='<c:out value="${searchVO.incidentNum}"/>' title="<spring:message code="title.search" /> <spring:message code="input.input" />" >
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -226,7 +226,7 @@
<thead>
<tr>
<th>문서번호</th>
<th>인스던트 접수번호</th>
<th>서비스 접수번호</th>
<th>서비스</th>
<th>승인상태</th>
<th>제목</th>
@ -250,7 +250,9 @@
<td><c:out value="${reportList.vcReportStatus}"/></td>
<!-- 2025.11.17 나혁제 제목이 35자 이상인경우 -->
<!-- 2026.07.19 기능개선06/F06 : 제목 클릭으로도 상세 진입 가능 -->
<td title="${reportList.vcReportTitle}">
<a href="javascript:fncSelectReportCheck('${reportList.inReportSeq}')">
<c:choose>
<c:when test="${fn:length(reportList.vcReportTitle) > 25}">
<c:out value="${fn:substring(reportList.vcReportTitle,0,25)}"/>...
@ -259,6 +261,7 @@
<c:out value="${reportList.vcReportTitle}"/>
</c:otherwise>
</c:choose>
</a>
</td>
<%-- 2026.03.11 나혁제 작성자 부분 그룹 추가 --%>
<td>

View File

@ -184,7 +184,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>
${incidentId}
</td>

View File

@ -800,7 +800,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>${incidentId}</td>
<th> 작업분류 </th>
<td>

View File

@ -701,7 +701,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td> </td>
<th> 작업분류 </th>
<td>
@ -926,8 +926,8 @@
<button type="button" class="btn-etc" onclick="fncReportErrorInsertApp(); return false;" title="등록/승인요청" >
등록/승인요청
</button>
<button type="button" class="btn-etc" onclick="fncReportErrorInsert(); return false;" title="<spring:message code="button.create" />">
<spring:message code="button.create" />
<button type="button" class="btn-etc" onclick="fncReportErrorInsert(); return false;" title="임시저장">
임시저장
</button>
</div>
<!-- // 오른쪽영역-->

View File

@ -480,7 +480,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>
${incidentId}
</td>

View File

@ -808,7 +808,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>${resultIncident.vcIncidentNum} </td>
<th> 작업분류 </th>
<td>
@ -992,8 +992,8 @@
<button type="button" class="btn-etc" onclick="fncReportErrorInsertApp(); return false;" title="등록/승인요청" >
등록/승인요청
</button>
<button type="button" class="btn-etc" onclick="fncReportErrorInsert(); return false;" title="<spring:message code="button.create" />">
<spring:message code="button.create" />
<button type="button" class="btn-etc" onclick="fncReportErrorInsert(); return false;" title="임시저장">
임시저장
</button>
</div>
</div>

View File

@ -164,7 +164,7 @@
<input class="s_input" id="reportId" name="reportId" type="text" size="35" maxlength="155" style="width: 155px;"
value='<c:out value="${searchVO.reportId}"/>' title="<spring:message code="title.search" /> <spring:message code="input.input" />" >
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<label>인스던트 접수번호:</label>
<label>서비스 접수번호:</label>
<input class="s_input" id="incidentNum" name="incidentNum" type="text" size="35" maxlength="155" style="width: 155px;"
value='<c:out value="${searchVO.incidentNum}"/>' title="<spring:message code="title.search" /> <spring:message code="input.input" />" >
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -226,7 +226,7 @@
<thead>
<tr>
<th>문서번호</th>
<th>인스던트 접수번호</th>
<th>서비스 접수번호</th>
<th>서비스</th>
<th>승인상태</th>
<th>제목</th>

View File

@ -160,7 +160,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>
${incidentId}
</td>

View File

@ -795,7 +795,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>${incidentId}</td>
<th> 작업분류 </th>
<td>

View File

@ -701,7 +701,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td> </td>
<th> 작업분류 </th>
<td>
@ -921,8 +921,8 @@
<button type="button" class="btn-etc" onclick="fncReportIssueInsertApp(); return false;" title="등록/승인요청" >
등록/승인요청
</button>
<button type="button" class="btn-etc" onclick="fncReportIssueInsert(); return false;" title="<spring:message code="button.create" />">
<spring:message code="button.create" />
<button type="button" class="btn-etc" onclick="fncReportIssueInsert(); return false;" title="임시저장">
임시저장
</button>
</div>
<!-- // 오른쪽영역-->

View File

@ -498,7 +498,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>
${incidentId}
</td>
@ -677,10 +677,7 @@
</c:if>
<c:if test="${(privType eq 'mine' && report.inReportStatus ne 3) || privType eq 'super'}">
<!-- 2026.01.22 나혁제 새로만들기 기능 추가 -->
<button type="button" class="btn-etc" title="새로만들기" onclick="fncReportIssueCopyInsert(); return false;">
새로만들기
</button>
<!-- 2026.07.19 SR#8 중복 '새로만들기' 버튼 제거 (상단 승인요청 블록의 새로만들기로 일원화) -->
<button type="button" class="btn-etc" title="수정" onclick="fncReportIssueUpdate(); return false;">
수정
</button>

View File

@ -810,7 +810,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>${resultIncident.vcIncidentNum} </td>
<th> 작업분류 </th>
<td>
@ -989,8 +989,8 @@
<button type="button" class="btn-etc" onclick="fncReportIssueInsertApp(); return false;" title="등록/승인요청" >
등록/승인요청
</button>
<button type="button" class="btn-etc" onclick="fncReportIssueInsert(); return false;" title="<spring:message code="button.create" />">
<spring:message code="button.create" />
<button type="button" class="btn-etc" onclick="fncReportIssueInsert(); return false;" title="임시저장">
임시저장
</button>
</div>
</div>

View File

@ -164,7 +164,7 @@
<input class="s_input" id="reportId" name="reportId" type="text" size="35" maxlength="155" style="width: 155px;"
value='<c:out value="${searchVO.reportId}"/>' title="<spring:message code="title.search" /> <spring:message code="input.input" />" >
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<label>인스던트 접수번호:</label>
<label>서비스 접수번호:</label>
<input class="s_input" id="incidentNum" name="incidentNum" type="text" size="35" maxlength="155" style="width: 155px;"
value='<c:out value="${searchVO.incidentNum}"/>' title="<spring:message code="title.search" /> <spring:message code="input.input" />" >
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -226,7 +226,7 @@
<thead>
<tr>
<th>문서번호</th>
<th>인스던트 접수번호</th>
<th>서비스 접수번호</th>
<th>서비스</th>
<th>승인상태</th>
<th>제목</th>

View File

@ -160,7 +160,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>
${incidentId}
</td>

View File

@ -792,7 +792,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>${incidentId}</td>
<th> 작업분류 </th>
<td>

View File

@ -700,7 +700,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td> </td>
<th> 작업분류 </th>
<td>
@ -923,8 +923,8 @@
<button type="button" class="btn-etc" onclick="fncReportOtherInsertApp(); return false;" title="등록/승인요청" >
등록/승인요청
</button>
<button type="button" class="btn-etc" onclick="fncReportOtherInsert(); return false;" title="<spring:message code="button.create" />">
<spring:message code="button.create" />
<button type="button" class="btn-etc" onclick="fncReportOtherInsert(); return false;" title="임시저장">
임시저장
</button>
</div>
<!-- // 오른쪽영역-->

View File

@ -519,7 +519,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>
${incidentId}
</td>

View File

@ -828,7 +828,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>${resultIncident.vcIncidentNum} </td>
<th> 작업분류 </th>
<td>
@ -1006,8 +1006,8 @@
<button type="button" class="btn-etc" onclick="fncReportOtherInsertApp(); return false;" title="등록/승인요청" >
등록/승인요청
</button>
<button type="button" class="btn-etc" onclick="fncReportOtherInsert(); return false;" title="<spring:message code="button.create" />">
<spring:message code="button.create" />
<button type="button" class="btn-etc" onclick="fncReportOtherInsert(); return false;" title="임시저장">
임시저장
</button>
</div>
</div>

View File

@ -168,7 +168,7 @@
<input class="s_input" id="reportId" name="reportId" type="text" size="35" maxlength="155" style="width: 155px;"
value='<c:out value="${searchVO.reportId}"/>' title="<spring:message code="title.search" /> <spring:message code="input.input" />" >
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<label>인스던트 접수번호:</label>
<label>서비스 접수번호:</label>
<input class="s_input" id="incidentNum" name="incidentNum" type="text" size="35" maxlength="155" style="width: 155px;"
value='<c:out value="${searchVO.incidentNum}"/>' title="<spring:message code="title.search" /> <spring:message code="input.input" />" >
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -230,7 +230,7 @@
<thead>
<tr>
<th>문서번호</th>
<th>인스던트 접수번호</th>
<th>서비스 접수번호</th>
<th>서비스</th>
<th>승인상태</th>
<th>제목</th>

View File

@ -184,7 +184,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>
${incidentId}
</td>

View File

@ -802,7 +802,7 @@
</td>
</tr>
<tr>
<th> 인스던트 접수번호 </th>
<th> 서비스 접수번호 </th>
<td>${incidentId}</td>
<th> 작업분류 </th>
<td>

View File

@ -30,7 +30,7 @@
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<title> 인스던트 수정 </title>
<title> 서비스 수정 </title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
@ -228,7 +228,7 @@
// ----------------------------------------
function fncSvcDeskIncidentInsert()
{
var bYes = confirm("인스던트 접수 처리를 하시겠습니까?");
var bYes = confirm("서비스 접수 처리를 하시겠습니까?");
if(bYes==false) return;
var form = document.svcDeskManage;
@ -264,7 +264,7 @@
// ----------------------------------------
function fncSvcDeskIncidentInsertReqApp()
{
var bYes = confirm("인스던트 등록/승인요청 처리를 하시겠습니까?");
var bYes = confirm("서비스 등록/승인요청 처리를 하시겠습니까?");
if(bYes==false) return;
var form = document.svcDeskManage;
@ -298,7 +298,7 @@
//----------------------------------------
// 인스던트 변경/승인처리 처리(최종 저장 처리 )
// 서비스 변경/승인처리 처리(최종 저장 처리 )
// ----------------------------------------
function fncAppLast(strMsg)
{
@ -429,7 +429,7 @@
// ----------------------------------------
var proc =
{
// 인스던트 접수
// 서비스 접수
fn_incident_save : function ()
{
var form = $('#svcDeskManage')[0];
@ -452,7 +452,7 @@
},
error: function(errorThrown)
{
alert("인스던트 접수 등록중 오류가 발생하였습니다. \n 시스템관리자에게 문의해 주시기 바랍니다.");
alert("서비스 접수 등록중 오류가 발생하였습니다. \n 시스템관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
@ -527,7 +527,7 @@
<ul class="route_navi">
<li><a href="#" title="홈"><span class="home">홈</span></a></li>
<li><a href="#" title="SR관리">SR관리</a></li>
<li>인스던트 수정</li>
<li>서비스 수정</li>
</ul>
</div>
</div>
@ -723,8 +723,8 @@
<button type="button" class="btn-etc" title="등록/승인요청" onclick="fncSvcDeskIncidentInsertReqApp(); return false;">
등록/승인요청
</button>
<button type="button" class="btn-etc" title="<spring:message code="button.create" />" onclick="fncSvcDeskIncidentInsert(); return false;">
<spring:message code="button.create" />
<button type="button" class="btn-etc" title="임시저장" onclick="fncSvcDeskIncidentInsert(); return false;">
임시저장
</button>
</div>
</div>

View File

@ -30,7 +30,7 @@
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<title> 인스던트 상세조회 </title>
<title> 서비스 상세조회 </title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
@ -89,27 +89,27 @@
}
//----------------------------------------
// 인스던트 수정 화면 이동처리
// 서비스 수정 화면 이동처리
// ----------------------------------------
function fncSvcDeskIncidentUpdate()
{
if($('#inIncidentStatus').val()=='1')
{
if(confirm("인시던트가 승인 진행중입니다.\n수정하면 모든 승인 정보는 초기화 됩니다.\n수정하시겠습니까?") == false) return;
if(confirm("서비스가 승인 진행중입니다.\n수정하면 모든 승인 정보는 초기화 됩니다.\n수정하시겠습니까?") == false) return;
}
else if($('#inIncidentStatus').val() == '2')
{
// 2025.11.18 나혁제 반려된 자료 수정불가
// if(confirm("반려된 인시던트입니다.\n수정하면 모든 승인 정보는 초기화 됩니다.\n수정하시겠습니까?") == false) return;
alert("반려된 인시던트입니다.\n 재작성하시길 바랍니다.");
// if(confirm("반려된 서비스입니다.\n수정하면 모든 승인 정보는 초기화 됩니다.\n수정하시겠습니까?") == false) return;
alert("반려된 서비스입니다.\n 재작성하시길 바랍니다.");
return;
}
else if($('#inIncidentStatus').val() == '3')
{
// 2025.11.18 나혁제 반려된 자료 수정불가
// if(confirm("승인완료된 인시던트입니다.\n수정하면 모든 승인 정보는 초기화 됩니다.\n수정하시겠습니까?") == false) return;
alert("승인완료된 인시던트입니다.\n 재작성하시길 바랍니다.");
// if(confirm("승인완료된 서비스입니다.\n수정하면 모든 승인 정보는 초기화 됩니다.\n수정하시겠습니까?") == false) return;
alert("승인완료된 서비스입니다.\n 재작성하시길 바랍니다.");
return;
}
@ -130,13 +130,13 @@
//----------------------------------------
// 2025.01.21 나혁제 새로만들 기능확장
// 인스던트 새로만들기 화면 이동처리
// 서비스 새로만들기 화면 이동처리
// ----------------------------------------
function fncSvcDeskIncidentCopyInsert()
{
if($('#inIncidentStatus').val() != '2' && $('#inIncidentStatus').val() != '3' )
{
alert("[승인완료/반려]된 인시던트에서만 새로만들기가 가능합니다.");
alert("[승인완료/반려]된 서비스에서만 새로만들기가 가능합니다.");
return;
}
@ -148,18 +148,18 @@
//----------------------------------------
// 인스던트 삭제 처리
// 서비스 삭제 처리
// ----------------------------------------
function fncSvcDeskIncidentDelete()
{
// 2025.11.18 나혁제 [승인완료/반려] 삭제 불가
if($('#inIncidentStatus').val() == '2' || $('#inIncidentStatus').val() == '3' )
{
alert("[승인완료/반려] 상태의 인시던트는 삭제가 불가합니다.");
alert("[승인완료/반려] 상태의 서비스는 삭제가 불가합니다.");
return;
}
var bYes = confirm("인스던트 삭제 처리를 하시겠습니까?");
var bYes = confirm("서비스 삭제 처리를 하시겠습니까?");
if(bYes==false) return;
proc.fn_IncidentDelete_save();
@ -171,7 +171,7 @@
// ----------------------------------------
function fncSvcDeskIncidentCompleted()
{
var bYes = confirm("인스던트 처리완료 처리를 하시겠습니까?");
var bYes = confirm("서비스 처리완료 처리를 하시겠습니까?");
if(bYes==false) return;
// 처리완료 메세지 팝업 open
@ -195,7 +195,7 @@
// ----------------------------------------
function fncSvcDeskIncidentReqApp()
{
var bYes = confirm("인스던트 승인요청 처리를 하시겠습니까?");
var bYes = confirm("서비스 승인요청 처리를 하시겠습니까?");
if(bYes==false) return;
// 승인요청 메세지 팝업 open
@ -203,7 +203,7 @@
}
//----------------------------------------
// 인스던트 승인요청 처리(최종 저장 처리 )
// 서비스 승인요청 처리(최종 저장 처리 )
// ----------------------------------------
function fncAppLast(strMsg)
{
@ -218,7 +218,7 @@
// ----------------------------------------
function fncSvcDeskIncidentAppRej()
{
var bYes = confirm("인스던트 승인/반려 처리를 하시겠습니까?");
var bYes = confirm("서비스 승인/반려 처리를 하시겠습니까?");
if(bYes==false) return;
// 승인&반려 메세지 팝업 open
@ -226,7 +226,7 @@
}
//----------------------------------------
// 인스던트 변경/승인 처리(최종 저장 처리 )
// 서비스 변경/승인 처리(최종 저장 처리 )
// ----------------------------------------
// 2025.11.17 나혁제 strStsfdgCd 만족도 추가
function fncAppRejLast(strGubun , strMsg, strStsfdgCd)
@ -374,7 +374,7 @@
}
//----------------------------------------
// 인스던트 댓글 등록
// 서비스 댓글 등록
// ----------------------------------------
function fn_egov_insert_commentList(bbsId, nttId)
{
@ -396,7 +396,7 @@
}
//----------------------------------------
// 인스던트 댓글 삭제
// 서비스 댓글 삭제
// ----------------------------------------
function fn_egov_deleteCommentList(commentNo, bbsId, nttId)
{
@ -416,7 +416,7 @@
// 서블릿 통신
var proc =
{
// 인스던트 처리완료
// 서비스 처리완료
fn_completedIncident_save : function ()
{
var form = $('#svcDeskManage')[0];
@ -438,13 +438,13 @@
},
error: function(errorThrown)
{
alert("인스던트 처리완료중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
alert("서비스 처리완료중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
}
,
// 인스던트 승인요청
// 서비스 승인요청
fn_IncidentReqApp_save : function ()
{
var form = $('#svcDeskManage')[0];
@ -466,13 +466,13 @@
},
error: function(errorThrown)
{
alert("인스던트 승인요청중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
alert("서비스 승인요청중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
}
,
// 인스던트 삭제
// 서비스 삭제
fn_IncidentDelete_save : function ()
{
var form = $('#svcDeskManage')[0];
@ -489,18 +489,18 @@
, cache:false
, success: function(data)
{
alert("인스던트 삭제 되었습니다.");
alert("서비스 삭제 되었습니다.");
fncSvcDeskList();
},
error: function(errorThrown)
{
alert("인스던트 삭제중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
alert("서비스 삭제중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
}
,
// 인스던트 승인
// 서비스 승인
fn_Incident_Approval : function ()
{
var form = $('#svcDeskManage')[0];
@ -517,18 +517,18 @@
, cache:false
, success: function(data)
{
alert("인스던트 승인 되었습니다.");
alert("서비스 승인 되었습니다.");
fncSvcDeskList();
},
error: function(errorThrown)
{
alert("인스던트 승인중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
alert("서비스 승인중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
}
,
// 인스던트 반려
// 서비스 반려
fn_Incident_Reject : function ()
{
var form = $('#svcDeskManage')[0];
@ -545,12 +545,12 @@
, cache:false
, success: function(data)
{
alert("인스던트 반려 되었습니다.");
alert("서비스 반려 되었습니다.");
fncSvcDeskList();
},
error: function(errorThrown)
{
alert("인스던트 반려중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
alert("서비스 반려중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
@ -639,7 +639,7 @@
<!-- main title -->
<div class="main_titWrap">
<h3>인스던트 상세조회</h3>
<h3>서비스 상세조회</h3>
<!-- location :s -->
<div class="location">
@ -648,7 +648,7 @@
<ul class="route_navi">
<li><a href="#" title="홈"><span class="home">홈</span></a></li>
<li><a href="#" title="SR관리">SR관리</a></li>
<li>인스던트 상세조회</li>
<li>서비스 상세조회</li>
</ul>
</div>
</div>

View File

@ -30,7 +30,7 @@
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<title> 인스던트 등록 </title>
<title> 서비스 등록 </title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
@ -251,7 +251,7 @@ ${uploadMax }
// ----------------------------------------
function fncSvcDeskIncidentInsert()
{
var bYes = confirm("인스던트 접수 처리를 하시겠습니까?");
var bYes = confirm("서비스 접수 처리를 하시겠습니까?");
if(bYes==false) return;
var form = document.svcDeskManage;
@ -287,7 +287,7 @@ ${uploadMax }
// ----------------------------------------
function fncSvcDeskIncidentInsertReqApp()
{
var bYes = confirm("인스던트 등록/승인요청 처리를 하시겠습니까?");
var bYes = confirm("서비스 등록/승인요청 처리를 하시겠습니까?");
if(bYes==false) return;
var form = document.svcDeskManage;
@ -320,7 +320,7 @@ ${uploadMax }
}
//----------------------------------------
// 인스던트 변경/승인처리 처리(최종 저장 처리 )
// 서비스 변경/승인처리 처리(최종 저장 처리 )
// ----------------------------------------
function fncAppLast(strMsg)
{
@ -451,7 +451,7 @@ ${uploadMax }
// ----------------------------------------
var proc =
{
// 인스던트 접수
// 서비스 접수
fn_incident_save : function ()
{
var form = $('#svcDeskManage')[0];
@ -468,13 +468,19 @@ ${uploadMax }
, cache:false
, success: function(data)
{
// 2026.07.19 SR#12 : 서버 검증 실패(길이초과 등) 시 안내 메시지 노출 후 등록 중단
if(data.resultCd != "0")
{
alert(data.resultMsg);
return;
}
alert("등록 완료 되었습니다.");
fncSvcDeskList();
},
error: function(errorThrown)
{
alert("인스던트 접수 등록중 오류가 발생하였습니다. \n 시스템관리자에게 문의해 주시기 바랍니다.");
alert("서비스 접수 등록중 오류가 발생하였습니다. \n 시스템관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
@ -616,7 +622,7 @@ ${uploadMax }
<ul class="route_navi">
<li><a href="#" title="홈"><span class="home">홈</span></a></li>
<li><a href="#" title="SR관리">SR관리</a></li>
<li>인스던트 접수</li>
<li>서비스 접수</li>
</ul>
</div>
</div>
@ -631,7 +637,7 @@ ${uploadMax }
<!-- 등록폼 -->
<table class="tbl_form" summary="<spring:message code="common.summary.list" arguments="등록" />">
<caption>인스던트 등록</caption>
<caption>서비스 등록</caption>
<colgroup>
<col style="width: 10%;">
<col style="width: 30%">
@ -687,7 +693,7 @@ ${uploadMax }
<tr>
<th> 제목 </th>
<td colspan=3>
<input type="text" name="vcIncidentTitle" id="vcIncidentTitle" value="" style="width:90%;"/>
<input type="text" name="vcIncidentTitle" id="vcIncidentTitle" value="" style="width:90%;" maxlength="200"/><!-- 2026.07.19 SR#12 제목 길이 제한 -->
</td>
<th> 조치자 </th>
<td>
@ -808,8 +814,8 @@ ${uploadMax }
<button type="button" class="btn-etc" title="등록/승인요청" onclick="fncSvcDeskIncidentInsertReqApp(); return false;">
등록/승인요청
</button>
<button type="button" class="btn-etc" title="<spring:message code="button.create" />" onclick="fncSvcDeskIncidentInsert(); return false;">
<spring:message code="button.create" />
<button type="button" class="btn-etc" title="임시저장" onclick="fncSvcDeskIncidentInsert(); return false;">
임시저장
</button>
</div>
</div>

View File

@ -233,7 +233,7 @@
<!-- 목록영역 -->
<table class="table" summary="<spring:message code="common.summary.list" arguments="자산관리" />">
<caption> 서비스데스크 인스던트 관리 <spring:message code="title.list" /></caption>
<caption> 서비스데스크 서비스 관리 <spring:message code="title.list" /></caption>
<colgroup>
<col style="width: 15%;">
<col style="width: 10%;">

View File

@ -30,7 +30,7 @@
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<title> 인스던트 신청 </title>
<title> 서비스 신청 </title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
@ -86,7 +86,7 @@
}
//----------------------------------------
// 인스던트 신청 수정 화면 이동처리
// 서비스 신청 수정 화면 이동처리
// ----------------------------------------
function fncSvcDeskReqIncidentUpdate()
{
@ -97,18 +97,18 @@
}
//----------------------------------------
// 인스던트 삭제 처리
// 서비스 삭제 처리
// ----------------------------------------
function fncSvcDeskReqIncidentDelete()
{
// 2025.11.18 나혁제 [승인완료/반려] 삭제 불가
if($('#inReqStatus').val() != '-1' )
{
alert("신청상태 이외의 인시던트 신청정보는 삭제가 불가합니다.");
alert("신청상태 이외의 서비스 신청정보는 삭제가 불가합니다.");
return;
}
var bYes = confirm("인스던트 신청정보 삭제 처리를 하시겠습니까?");
var bYes = confirm("서비스 신청정보 삭제 처리를 하시겠습니까?");
if(bYes==false) return;
proc.fn_ReqIncidentDelete_save();
@ -119,7 +119,7 @@
// ----------------------------------------
function fncSvcDeskReqIncidentRptRej()
{
var bYes = confirm("인스던트 접수/반려 처리를 하시겠습니까?");
var bYes = confirm("서비스 접수/반려 처리를 하시겠습니까?");
if(bYes==false) return;
// 승인&반려 메세지 팝업 open
@ -127,7 +127,7 @@
}
//----------------------------------------
// 인스던트 접수/반려 처리(최종 저장 처리 )
// 서비스 접수/반려 처리(최종 저장 처리 )
// ----------------------------------------
function fncRptRejLast(strGubun , strMsg)
{
@ -136,7 +136,7 @@
// 접수처리
if(strGubun=='0')
{
// 인스던트 접수 화면으로 이동처리
// 서비스 접수 화면으로 이동처리
var varFrom = document.getElementById("svcDeskReqManage");
varFrom.action = "<c:url value='/srm/insertViewIncident.do'/>";
varFrom.submit();
@ -192,7 +192,7 @@
// ----------------------------------------
var proc =
{
// 인스던트 삭제
// 서비스 삭제
fn_ReqIncidentDelete_save : function ()
{
var form = $('#svcDeskReqManage')[0];
@ -209,17 +209,17 @@
, cache:false
, success: function(data)
{
alert("인스던트 신청정보 삭제 되었습니다.");
alert("서비스 신청정보 삭제 되었습니다.");
fncSvcDeskReqList();
},
error: function(errorThrown)
{
alert("인스던트 신청정보 삭제처리중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
alert("서비스 신청정보 삭제처리중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
}
// 인스던트 신청정보 반려
// 서비스 신청정보 반려
, fn_Incident_Req_Reject : function ()
{
var form = $('#svcDeskReqManage')[0];
@ -236,12 +236,12 @@
, cache:false
, success: function(data)
{
alert("인스던트 신청정보 반려 되었습니다.");
alert("서비스 신청정보 반려 되었습니다.");
fncSvcDeskReqList();
},
error: function(errorThrown)
{
alert("인스던트 신청정보 반려중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
alert("서비스 신청정보 반려중 오류가 발생하였습니다. \n 시스템 관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
@ -272,7 +272,7 @@
<ul class="route_navi">
<li><a href="#" title="홈"><span class="home">홈</span></a></li>
<li><a href="#" title="SR관리">SR관리</a></li>
<li>인스던트 신청 상세조회</li>
<li>서비스 신청 상세조회</li>
</ul>
</div>
</div>
@ -287,7 +287,7 @@
<!-- 등록폼 -->
<table class="tbl_form" summary="<spring:message code="common.summary.list" arguments="등록" />">
<caption>인스던트 등록</caption>
<caption>서비스 등록</caption>
<colgroup>
<col style="width: 10%;">
<col style="width: 30%">
@ -337,7 +337,7 @@
<div class="bbs_view">
<!-- 등록폼 -->
<table class="tbl_form" summary="<spring:message code="common.summary.list" arguments="등록" />">
<caption>인스던트 등록</caption>
<caption>서비스 등록</caption>
<colgroup>
<col style="width: 10%;">
<col style="width: 14%">

View File

@ -30,7 +30,7 @@
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<title> 인스던트 신청 </title>
<title> 서비스 신청 </title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
@ -148,7 +148,7 @@
// ----------------------------------------
function fncSvcDeskReqIncidentInsert()
{
var bYes = confirm("인스던트 신청 처리를 하시겠습니까?");
var bYes = confirm("서비스 신청 처리를 하시겠습니까?");
if(bYes==false) return;
var form = document.svcDeskReqManage;
@ -233,7 +233,7 @@
// ----------------------------------------
var proc =
{
// 인스던트 신청 등록
// 서비스 신청 등록
fn_req_incident_save : function ()
{
var form = $('#svcDeskReqManage')[0];
@ -250,13 +250,19 @@
, cache:false
, success: function(data)
{
// 2026.07.19 SR#12 : 서버 검증 실패(길이초과 등) 시 안내 후 신청 중단
if(data.resultCd != "0")
{
alert(data.resultMsg);
return;
}
alert("신청 완료 되었습니다.");
fncSvcDeskReqList();
},
error: function(errorThrown)
{
alert("인스던트 신청 등록중 오류가 발생하였습니다. \n 시스템관리자에게 문의해 주시기 바랍니다.");
alert("서비스 신청 등록중 오류가 발생하였습니다. \n 시스템관리자에게 문의해 주시기 바랍니다.");
console.log(JSON.stringify(errorThrown));
}
});
@ -323,7 +329,7 @@
<ul class="route_navi">
<li><a href="#" title="홈"><span class="home">홈</span></a></li>
<li><a href="#" title="SR관리">SR관리</a></li>
<li>인스던트 신청</li>
<li>서비스 신청</li>
</ul>
</div>
</div>
@ -338,7 +344,7 @@
<!-- 등록폼 -->
<table class="tbl_form" summary="<spring:message code="common.summary.list" arguments="등록" />">
<caption>인스던트 등록</caption>
<caption>서비스 등록</caption>
<colgroup>
<col style="width: 10%;">
<col style="width: 30%">
@ -371,19 +377,28 @@
<tr>
<th> 서비스 </th>
<td>
<!-- 2026.07.19 기능개선03/F03 : 서비스신청 시 서비스 항목은 'SR기본요청양식'으로 고정(사용자 선택 불가) -->
<select name="inServiceCode" id="inServiceCode" onchange="selInServiceCode()" style="width: 80%;" >
<c:forEach items="${serviceList}" var="result" varStatus="status">
<option value="${result.value}" > ${result.label} </option><!-- 분류코드명 -->
</c:forEach>
</select>
<script type="text/javascript">
// F03 : 'SR기본요청양식' 옵션을 기본 선택하고 변경 불가 처리(값은 정상 제출)
$(function(){
var $s = $('#inServiceCode');
$s.find('option').each(function(){
if($.trim($(this).text()) == 'SR기본요청양식'){ $s.val($(this).val()); return false; }
});
$s.css({'pointer-events':'none','background-color':'#f2f2f2'}).attr('tabindex','-1');
});
</script>
</td>
<th> 조치예정자 </th>
<td>
<input type="text" name="vcChargeUser" id="vcChargeUser" style="width: 90%;" readonly value=""/>
<a href="<c:url value='/cmm/selectUserListPopup.do' />" target="_blank" title="새 창으로 이동" onclick="fn_User_Search('조치예정', 'inChargeUser', '', 'vcChargeUser', '', '');return false;">
<img src="<c:url value='/egov/images/egovframework/com/cmm/btn/btn_search.gif' />" alt="조치예정자 검색" title="조치예정자 검색">
</a>
<!-- 2026.07.19 SR#9-1 : 신청 시 조치예정자는 서비스 선택에 따라 자동배정, 사용자 직접 선택(돋보기) 제거 -->
<input type="text" name="vcChargeUser" id="vcChargeUser" style="width: 60%;" readonly value=""/>
<span style="color:#888;">(자동배정)</span>
<input type="hidden" name="inChargeUser" id="inChargeUser" value="" >
@ -397,7 +412,7 @@
<tr>
<th> 제목 </th>
<td colspan=2>
<input type="text" name="vcIncidentTitle" id="vcIncidentTitle" value="" style="width:90%;"/>
<input type="text" name="vcIncidentTitle" id="vcIncidentTitle" value="" style="width:90%;" maxlength="200"/><!-- 2026.07.19 SR#12 제목 길이 제한 -->
</td>
<th><spring:message code="cop.atchFile" /></th>

View File

@ -135,7 +135,7 @@
<!-- 목록영역 -->
<table class="table" summary="<spring:message code="common.summary.list" arguments="자산관리" />">
<caption> 서비스데스크 인스던트 관리 <spring:message code="title.list" /></caption>
<caption> 서비스데스크 서비스 관리 <spring:message code="title.list" /></caption>
<colgroup>
<col style="width: 16%;">
<col style="width: 16%;">

View File

@ -30,7 +30,7 @@
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<title> 인스던트 신청 수정 </title>
<title> 서비스 신청 수정 </title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
@ -144,11 +144,11 @@
}
//----------------------------------------
// 인스던트 변경처리
// 서비스 변경처리
// ----------------------------------------
function fncSvcDeskReqIncidentUpdate()
{
var bYes = confirm("인스던트 신청 변경 처리를 하시겠습니까?");
var bYes = confirm("서비스 신청 변경 처리를 하시겠습니까?");
if(bYes==false) return;
var form = document.svcDeskReqManage;
@ -267,7 +267,7 @@
},
error: function(errorThrown)
{
alert("인스던트 신청 정보 수정 처리중 오류가 발생 하였습니다. \n 시스템 관리자에게 연락바랍니다.");
alert("서비스 신청 정보 수정 처리중 오류가 발생 하였습니다. \n 시스템 관리자에게 연락바랍니다.");
console.log(JSON.stringify(errorThrown));
}
@ -335,7 +335,7 @@
<ul class="route_navi">
<li><a href="#" title="홈"><span class="home">홈</span></a></li>
<li><a href="#" title="SR관리">SR관리</a></li>
<li>인스던트 신청</li>
<li>서비스 신청</li>
</ul>
</div>
</div>
@ -350,7 +350,7 @@
<!-- 등록폼 -->
<table class="tbl_form" summary="<spring:message code="common.summary.list" arguments="등록" />">
<caption>인스던트 등록</caption>
<caption>서비스 등록</caption>
<colgroup>
<col style="width: 10%;">
<col style="width: 30%">

View File

@ -30,7 +30,7 @@
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<title> 인스던트 수정 </title>
<title> 서비스 수정 </title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
@ -224,11 +224,11 @@
}
//----------------------------------------
// 인스던트 변경처리
// 서비스 변경처리
// ----------------------------------------
function fncSvcDeskIncidentUpdate()
{
var bYes = confirm("인스던트 변경 처리를 하시겠습니까?");
var bYes = confirm("서비스 변경 처리를 하시겠습니까?");
if(bYes==false) return;
var form = document.svcDeskManage;
@ -260,11 +260,11 @@
}
//----------------------------------------
// 인스던트 변경/승인처리 처리
// 서비스 변경/승인처리 처리
// ----------------------------------------
function fncSvcDeskIncidentUpdateApp()
{
var bYes = confirm("인스던트 변경/승인요청 처리를 하시겠습니까?");
var bYes = confirm("서비스 변경/승인요청 처리를 하시겠습니까?");
if(bYes==false) return;
var form = document.svcDeskManage;
@ -332,7 +332,7 @@
}
//----------------------------------------
// 인스던트 변경/승인처리 처리(최종 저장 처리 )
// 서비스 변경/승인처리 처리(최종 저장 처리 )
// ----------------------------------------
function fncAppLast(strMsg)
{
@ -496,7 +496,7 @@
},
error: function(errorThrown)
{
alert("인스던트 정보 수정 처리중 오류가 발생 하였습니다. \n 시스템 관리자에게 연락바랍니다.");
alert("서비스 정보 수정 처리중 오류가 발생 하였습니다. \n 시스템 관리자에게 연락바랍니다.");
console.log(JSON.stringify(errorThrown));
}
@ -627,7 +627,7 @@
<!-- main title -->
<div class="main_titWrap">
<h3>인스던트 수정</h3>
<h3>서비스 수정</h3>
<!-- location :s -->
<div class="location">
@ -636,7 +636,7 @@
<ul class="route_navi">
<li><a href="#" title="홈"><span class="home">홈</span></a></li>
<li><a href="#" title="SR관리">SR관리</a></li>
<li>인스던트 수정</li>
<li>서비스 수정</li>
</ul>
</div>
</div>

View File

@ -372,7 +372,8 @@
<c:if test="${!empty authorGroupVO.pageIndex }">
<!-- paging navigation -->
<div class="pagination">
<ul><ui:pagination paginationInfo="${paginationInfo}" type="image" jsFunction="fn_egov_select_linkPage"/></ul>
<%-- 2026.07.19 장애처리04/D04 : 페이지 이동 시 검색조건 유지 (미정의 fn_egov_select_linkPage → listForm 재제출 linkPage 로 교정) --%>
<ul><ui:pagination paginationInfo="${paginationInfo}" type="image" jsFunction="linkPage"/></ul>
</div>
</c:if>

View File

@ -433,6 +433,17 @@
<form:options items="${groupId_result}" itemValue="code" itemLabel="codeNm"/>
</form:select>
<div><form:errors path="groupId" cssClass="error"/></div>
<script type="text/javascript">
// 2026.07.19 기능개선05/F05 : 그룹아이디 미선택 시 기본값 'KIC' 자동 선택
$(function(){
var $g = $('#groupId');
if($g.length > 0 && ($g.val() == null || $g.val() == '')){
$g.find('option').each(function(){
if($.trim($(this).text()) == 'KIC'){ $g.val($(this).val()); return false; }
});
}
});
</script>
</td>
</tr>

View File

@ -273,7 +273,7 @@
<!-- login :s -->
<div class="logback">
<h1><img src="${ctx}/images/main/logo.png" alt="uWorks Portal logo"></h1>
<h1><img src="${ctx}/branding/logo" alt="uWorks Portal logo"></h1>
<h3>urITSM 에 오신것을 환영합니다.</h3>
<!-- login_box :s -->
<div class="login_box">

View File

@ -319,7 +319,7 @@
<!-- Right: 로그인 박스 -->
<div class="login-right">
<h1><img src="${ctx}/images/main/logo.png" alt="uWorks Portal logo"></h1>
<h1><img src="${ctx}/branding/logo" alt="uWorks Portal logo"></h1>
</br>
<h3>urITSM 에 오신것을 환영합니다.</h3>
@ -361,12 +361,12 @@
<%--
<!-- login :s -->
<div class="login-left"" >
<img src="${ctx}/images/main/logo.png" alt="uWorks Portal logo" style="width:400px;">
<img src="${ctx}/branding/logo" alt="uWorks Portal logo" style="width:400px;">
</div>
<!-- login :s -->
<div class="login-container" style="width:40%;text-align:center;padding-left: 5px;align-self: center;">
<h1><img src="${ctx}/images/main/logo.png" alt="uWorks Portal logo"></h1>
<h1><img src="${ctx}/branding/logo" alt="uWorks Portal logo"></h1>
<h3>urITSM 에 오신것을 환영합니다.</h3>
<!-- login_box :s -->
<div class="login_box">

View File

@ -74,7 +74,7 @@
// 서블릿 통신
var proc =
{
// 인스던트 처리완료
// 서비스 처리완료
fn_id_find : function ()
{
var form = $('#PopIdFind')[0];

View File

@ -102,9 +102,17 @@
fncClose();
}
else
{
// 2026.07.19 SR#1 : 서버 안내 메시지(계정 잠금 등) 우선 노출
if(data.resultMsg != null && data.resultMsg != "")
{
alert(data.resultMsg);
}
else
{
alert("비밀번호 초기화에 실패하였습니다. \n사용자정보을 확인해주시길 바랍니다.");
}
}
// alert(JSON.stringify(data));
// $('#userId').val(data.userId);
},

View File

@ -19,7 +19,7 @@
<div class="box">
<p class="fLogo"><img src="<c:url value='/'/>images/main/footer_logo.png" alt="urAIRPA 시스템 logo"></p>
<address>서울시 강서구 양천로 570(등촌동 NH서울타워 5층), (주)유알피</address>
<p class="copy">COPYRIGHT © 20242 URP. All Right Reserved</p>
<p class="copy">COPYRIGHT © 2024 URP. All Right Reserved</p><!-- 2026.07.19 SR#23 오타(20242) 수정 -->
<%-- 2025.06.11 나혁제 불필요한 부분
<ul class="menu">
<li><a href="#" title="Privacy policy">Privacy policy</a></li>

View File

@ -99,7 +99,8 @@
<div class="header-top">
<div class="header-inner">
<a href="<c:url value='/'/>main/mainPage.do"><h1 class="logo" title="uWorks Portal">uWorks Portal</h1></a>
<%-- 2026.07.19 기능개선12/F12 : 상단 헤더 로고를 브랜딩 엔드포인트(KIC 기본/업로드본)로 참조 --%>
<a href="<c:url value='/'/>main/mainPage.do"><h1 class="logo" title="uWorks Portal" style="background-image:url('<c:url value="/branding/logo"/>'); background-size:contain; background-repeat:no-repeat; background-position:left center; text-indent:-9999px; overflow:hidden;">uWorks Portal</h1></a>
<%
TokenInfo tokenInfo = (TokenInfo)session.getAttribute("tokenInfo");

View File

@ -33,7 +33,7 @@
<meta name="description" content="urITSM 에 오신것을 환영합니다.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="shortcut icon" href="${pageContext.request.contextPath}/branding/favicon" type="image/x-icon"><!-- F12 KIC 파비콘 -->
<link rel="stylesheet" href="${ctx}/js/js-calendar/calendar-jquery-ui.css">
<script type="text/javascript" src="${ctx}/ js/jquery-2.2.4.min.js"></script>

View File

@ -37,7 +37,7 @@
<meta name="keywords" content="urITSM">
<meta name="description" content="urITSM 에 오신것을 환영합니다.">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="shortcut icon" href="${pageContext.request.contextPath}/branding/favicon" type="image/x-icon"><!-- F12 KIC 파비콘 -->
<link rel="stylesheet" href="${ctx}/js/js-calendar/calendar-jquery-ui.css">
<script type="text/javascript" src="${ctx}/js/jquery-2.2.4.min.js"></script>

View File

@ -30,7 +30,7 @@
<meta name="keywords" content="urITSM">
<meta name="description" content="urITSM 에 오신것을 환영합니다.">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="shortcut icon" href="${pageContext.request.contextPath}/branding/favicon" type="image/x-icon"><!-- F12 KIC 파비콘 -->
<link rel="stylesheet" type="text/css" href="${ctx}/css/import.css">
<script type="text/javascript" src="${ctx}/js/jquery-2.2.4.min.js"></script>

View File

@ -29,7 +29,7 @@
<meta name="keywords" content="urITSM">
<meta name="description" content="urITSM 에 오신것을 환영합니다.">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="shortcut icon" href="${pageContext.request.contextPath}/branding/favicon" type="image/x-icon"><!-- F12 KIC 파비콘 -->
<link rel="stylesheet" type="text/css" href="${ctx}/css/import.css">
<script type="text/javascript" src="${ctx}/js/jquery-2.2.4.min.js"></script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,14 @@
<svg width="250" height="35" viewBox="0 0 250 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M119.793 26.5656V7.20582H123.696V13.2493H127.571V15.6822H123.696V26.5656H119.793ZM114.735 12.4581C115.416 12.9864 115.948 13.6462 116.333 14.4348C116.716 15.2312 116.91 16.0765 116.91 16.9837C116.91 18.6279 116.326 20.0376 115.145 21.2051C113.978 22.3751 112.558 22.9602 110.896 22.9602C109.233 22.9602 107.862 22.3777 106.664 21.2051C105.473 20.035 104.876 18.6279 104.876 16.9837C104.876 16.0765 105.078 15.2286 105.483 14.4348C105.886 13.6488 106.424 12.9864 107.084 12.4581H104.012V10.0536H108.943V6.92233H112.848V10.0536H117.776V12.4581H114.74H114.735ZM109.274 14.373C108.8 15.0997 108.558 15.9708 108.558 16.9837C108.558 17.9965 108.8 18.8702 109.274 19.6072C109.751 20.3469 110.296 20.7129 110.896 20.7129C111.495 20.7129 112.053 20.3469 112.522 19.6072C112.994 18.8676 113.226 17.9939 113.226 16.9837C113.226 15.9734 112.994 15.0997 112.522 14.373C112.05 13.6462 111.512 13.2802 110.896 13.2802C110.279 13.2802 109.751 13.6462 109.274 14.373ZM112.265 30.9932H124.53V33.4029H111.051C110.281 33.4029 109.641 33.1452 109.129 32.6401C108.616 32.1324 108.359 31.4365 108.359 30.55V24.9188H112.265V30.9907V30.9932Z" fill="white"/>
<path d="M131.619 7.38364H148.231V13.1385C148.231 13.8575 148.145 14.6358 147.963 15.4812C147.78 16.3265 147.55 16.9373 147.275 17.3161H151.018V19.7232H141.86V23.9318H148.17V33.421H144.297V26.3311H131.556V23.9318H137.957V19.7232H128.996V17.3161H143.877C144.073 16.7698 144.193 16.1383 144.246 15.4193C144.3 14.7054 144.323 13.9761 144.323 13.2364V9.78558H131.619V7.38364Z" fill="white"/>
<path d="M159.62 14.7492V17.0893H172.644V19.4938H158.403C157.585 19.4938 156.943 19.231 156.448 18.7026C155.959 18.1769 155.711 17.4914 155.711 16.646V7.53827H172.387V9.94021H159.62V12.3782H172.293V14.7492H159.62ZM174.985 21.9628V24.3673H165.924V33.4467H162.019V24.3673H152.958V21.9628H174.985Z" fill="white"/>
<path d="M193.768 7.22901H197.607V13.7776L201.516 13.7467V16.1822H197.607V33.4261H193.768V7.22901Z" fill="white"/>
<path d="M224.654 20.9113H202.632V18.5068H209.676V12.7493H213.579V18.5068H224.654V20.9113ZM205.258 7.43261H221.906V12.6849C221.906 13.4658 221.799 14.2853 221.584 15.1358C221.373 15.9914 221.128 16.5765 220.853 16.8935H217.488C217.702 16.3445 217.844 15.7157 217.903 15.0121C217.967 14.306 218.003 13.5715 218.003 12.8138V9.87062H205.261V7.43261H205.258ZM218.255 24.1817C219.512 25.3569 220.147 26.7821 220.147 28.4676C220.147 30.1531 219.512 31.5551 218.255 32.7251C216.996 33.8952 215.479 34.4802 213.707 34.4802C211.935 34.4802 210.398 33.8952 209.143 32.7251C207.897 31.5551 207.277 30.1325 207.277 28.4676C207.277 26.8027 207.897 25.3569 209.143 24.1817C210.398 23.0143 211.912 22.4241 213.707 22.4241C215.502 22.4241 216.996 23.0143 218.255 24.1817ZM211.915 25.9394C211.428 26.679 211.178 27.5218 211.178 28.4676C211.178 29.4134 211.428 30.2201 211.915 30.9391C212.407 31.653 213.006 32.0112 213.709 32.0112C214.413 32.0112 215.004 31.653 215.491 30.9391C215.971 30.2201 216.208 29.4005 216.208 28.4676C216.208 27.5347 215.971 26.679 215.491 25.9394C215.004 25.2023 214.413 24.8312 213.709 24.8312C213.006 24.8312 212.409 25.2023 211.915 25.9394Z" fill="white"/>
<path d="M187.018 10.5046V13.0509C187.018 15.5404 187.614 17.6769 188.84 19.4423C189.827 20.8546 191.657 22.1535 193.034 22.6019L191.114 24.4369C190.171 24.1663 188.789 23.3442 187.79 22.504C186.635 21.5298 185.455 20.4757 185.047 19.2799C184.642 20.4757 183.459 21.5298 182.306 22.504C181.304 23.3467 179.925 24.1663 178.979 24.4369L177.057 22.6019C178.439 22.1509 180.264 20.8546 181.253 19.4423C182.48 17.6769 183.079 15.5404 183.079 13.0509V10.5046H178.533V8.08206H191.494V10.5046H187.015" fill="white"/>
<path d="M246.094 13.4916H250V15.8987H246.094V33.4261H242.219V7.22901H246.094V13.4916Z" fill="white"/>
<path d="M235.083 7.79599V13.0509C235.083 15.5404 235.68 17.6769 236.904 19.4423C237.89 20.8546 239.723 22.1535 241.1 22.6019L239.178 24.4369C238.237 24.1663 236.853 23.3442 235.851 22.504C234.696 21.5298 233.521 20.4757 233.11 19.2799C232.702 20.4757 231.525 21.5298 230.37 22.504C229.373 23.3467 227.986 24.1663 227.045 24.4369L225.123 22.6019C226.5 22.1509 228.333 20.8546 229.317 19.4423C230.543 17.6769 231.142 15.5404 231.142 13.0509V7.79599H235.081H235.083Z" fill="white"/>
<path d="M72.1269 21.5504V26.8955C72.1269 28.666 70.6814 30.1015 68.8917 30.1015C67.1021 30.1015 65.6566 28.666 65.6566 26.8955V7.24705C65.6566 5.47394 67.1021 4.04103 68.8917 4.04103C70.6814 4.04103 72.1269 5.47394 72.1269 7.24705V12.5329H81.3863V11.9736C81.3863 6.63368 81.7355 0 68.8943 0C56.053 0 56.4023 6.63368 56.4023 11.9736V22.169C56.4023 27.5089 56.0505 34.1426 68.8943 34.1426C81.7381 34.1426 81.3863 27.5089 81.3863 22.169V21.5504H72.1269Z" fill="white"/>
<path d="M9.25426 0.682953H0V33.4055H9.25426V0.682953Z" fill="white"/>
<path d="M31.541 33.4029L19.4034 17.012L28.9151 0.682953H19.0872L12.3543 12.5664C11.1485 14.7157 10.0522 17.3677 12.1376 20.4551L20.9304 33.4055H31.5384L31.541 33.4029Z" fill="white"/>
<path d="M46.8578 0.78862H37.6035V33.5112H46.8578V0.78862Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB