Merge branch 'refs/heads/dev' into xithoon

pull/24/head
xhoon 4 weeks ago
commit 3758117293

@ -62,4 +62,26 @@ public class TotalInfoController {
}
@PostMapping("/total/info/{mmCode}/info/edit.ajax")
public ResponseEntity<?> updateTotalInfo(@PathVariable String mmCode, @RequestBody TotalInfoDto.Request.Edit totalInfoDto) {
try {
totalInfoService.updateTotalInfo(mmCode, totalInfoDto);
return ApiResponseUtil.success("수정되었습니다.");
} catch (Exception e) {
return ApiResponseUtil.error("게시물 수정에 실패했습니다.");
}
}
@PostMapping("/total/info/{mmCode}/{state}/state.ajax")
public ResponseEntity<?> updateMinwonState(@PathVariable String mmCode, @PathVariable String state) {
totalInfoService.updateState(mmCode, state);
return ApiResponseUtil.success("수정되었습니다.");
}
}

@ -0,0 +1,17 @@
package go.kr.project.biz.totalInfo.mapper;
import go.kr.project.biz.totalInfo.model.TotalInfoDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface TotalInfoMapper {
void updateCpMain(@Param("mmCode") String mmCode, TotalInfoDto.Request.Edit totalInfoDto);
void updateCpAnswer(@Param("mmCode") String mmCode, TotalInfoDto.Request.Edit totalInfoDto);
int updateState(@Param("mmCode") String mmCode, @Param("state") String state);
int insertCpOwner(TotalInfoDto.Request.Edit totalInfoDto);
}

@ -20,6 +20,25 @@ public class TotalInfoDto {
}
@Getter
@Setter
public static class Edit {
//메인
private String mmCode;
private String mmSgtel;
private String mmSgpos;
private String mmLawgb;
private String mmKeum1;
//답변
private String asState;
}
}

@ -27,7 +27,7 @@ public class TotalInfoQueryDslRepository {
public TotalInfoDto.Response.TotalInfoResult findTotalInfo(String mmCode) {
String jobGroup = "";
String jobGroup = "1";
//해당 QueryDsl문법이 어렵다면, sql문을 ChatGpt에 붙여넣고 QueryDsl로 바꿔달라고 하면 바꿔준다.
//읽어보고 맞다면 붙여넣으면 된다.

@ -1,9 +1,13 @@
package go.kr.project.biz.totalInfo.service;
import go.kr.project.biz.totalInfo.model.TotalInfoDto;
import org.apache.ibatis.annotations.Param;
public interface TotalInfoService {
TotalInfoDto.Response.TotalInfoResult findTotalInfo(String mmCode);
void updateTotalInfo(String mmCode, TotalInfoDto.Request.Edit totalInfoDto) throws Exception;
void updateState(String mmCode, String state);
}

@ -1,11 +1,13 @@
package go.kr.project.biz.totalInfo.service.impl;
import go.kr.project.biz.totalInfo.mapper.TotalInfoMapper;
import go.kr.project.biz.totalInfo.model.TotalInfoDto;
import go.kr.project.biz.totalInfo.repository.TotalInfoQueryDslRepository;
import go.kr.project.biz.totalInfo.service.TotalInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
@ -13,10 +15,41 @@ import org.springframework.stereotype.Service;
public class TotalInfoServiceImpl implements TotalInfoService {
private final TotalInfoQueryDslRepository totalInfoQueryDslRepository;
private final TotalInfoMapper totalInfoMapper;
@Override
public TotalInfoDto.Response.TotalInfoResult findTotalInfo(String mmCode) {
return totalInfoQueryDslRepository.findTotalInfo(mmCode);
}
@Override
public void updateTotalInfo(String mmCode, TotalInfoDto.Request.Edit totalInfoDto) throws Exception{
log.info("updateTotalInfo");
totalInfoMapper.updateCpMain(mmCode, totalInfoDto);
totalInfoMapper.updateCpAnswer(mmCode, totalInfoDto);
}
@Override
public void updateState(String mmCode, String state) {
switch(state) {
case "aaa" :
break;
case "bbb" :
break;
case "ccc" :
break;
}
totalInfoMapper.updateState(mmCode, state);
}
}

@ -41,7 +41,7 @@ public class ImageModifySampleController {
})
@GetMapping("/imageModify.do")
public String imageModify(NoticeSampleVO paramVO, Model model) {
return "template/imageModifySample/imageModify" + TilesConstants.BASE;
return "template/imageModifySample/imageModify_tui" + TilesConstants.BASE;
}
}

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="go.kr.project.biz.totalInfo.mapper.TotalInfoMapper">
<update id="updateCpMain"
parameterType="go.kr.project.biz.totalInfo.model.TotalInfoDto$Request$Edit">
UPDATE cp_main
SET
MM_LAWGB = ${mmLawgb}
MM_SGTEL = ${mmSgtel},
MM_SGPOS = ${mmSgpos},
MM_KEUM1 = ${mmKeum1}
WHERE
MM_CODE = #{mmCode}
</update>
<update id="updateCpAnswer"
parameterType="go.kr.project.biz.totalInfo.model.TotalInfoDto$Request$Edit">
UPDATE cp_answer
SET
AS_STATE = ${asState}
WHERE
MM_CODE = #{mmCode}
</update>
<update id="updateState">
UPDATE cp_main
SET
MM_STATE = ${state}
WHERE
MM_CODE = #{mmCode}
</update>
<insert id="insertCpOwner"
parameterType="go.kr.project.biz.totalInfo.model.TotalInfoDto$Request$Edit">
insert into cp_owner
(
OM_CODE,
OM_SGGCODE,
OM_NAME,
OM_NO1,
OM_JNO,
OM_NOGB,
OM_JUSO,
OM_BUNJI,
OM_ZIP,
OM_DORO_CODE,
OM_BLD_POSITION,
OM_BLD_NO1,
OM_BLD_NO2,
OM_BLD_ADMNO,
OM_INGB,
OM_INDT,
OM_BDCODE
) VALUES (
#{mmCode},
#{omSggcode},
#{omName},
#{omNo1},
#{omJno},
#{omNogb},
#{omJuso},
#{omBunji},
#{omZip},
#{omDoroCode},
#{omBldPosition},
#{omBldNo1},
#{omBldNo2},
#{omBldAdmno},
#{omIngb},
#{omIndt},
#{omBdcode}
)
</insert>
</mapper>

@ -77,6 +77,7 @@
*/
(function(window, $) {
'use strict';
let TOTAL_INFO_POPUP = null;
var SEARCH_COND = {};
@ -295,17 +296,33 @@
// 행 더블클릭 이벤트 - 게시물 상세 페이지로 이동
this.instance.on('dblclick', (ev) => {
var popUrl = '${pageContext.request.contextPath}/total/info.do';
var popTitle = "";
var popTitle = "totalInfoPopup";
var popOption = "width=1400px, height=900px, resizable=yes, scrollbars=yes, location=no, top=100px, left=100px";
// 1) localStorage에 저장
let cursor = this.instance.getValue(ev.rowKey, 'mmCode');
let mmCodes = this.instance.getData().map(row => row.mmCode);
const state = { cursor, mmCodes, savedAt: Date.now() };
localStorage.setItem('TOTAL_INFO_STATE', JSON.stringify(state));
// 2) 팝업이 없거나 닫혀 있으면 새로 열기
if (!TOTAL_INFO_POPUP || TOTAL_INFO_POPUP.closed) {
TOTAL_INFO_POPUP = window.open(popUrl, popTitle, popOption);
} else {
// 이미 떠 있으면 새로 안 만들고, 그 창에 포커스만 줌
TOTAL_INFO_POPUP.focus();
TOTAL_INFO_POPUP.TOTAL_INFO_POPUP_API.search();
// 필요하면 URL도 다시 세팅해서 강제 새로고침
// totalInfoPopup.location.href = popUrl;
}
// 팝업 띄우기
let cursor = this.instance.getValue(ev.rowKey, 'mmCode'); // 선택한 mmCode
let mmCodes = this.instance.getData().map(row => row.mmCode); // 리스트업 된 자료 mmCode 리스트
const $openPop = window.open(popUrl, popTitle, popOption);
$($openPop).prop('cursor', cursor);
$($openPop).prop('mmCodes', mmCodes);
// const $openPop = window.open(popUrl, popTitle, popOption);
// $($openPop).prop('cursor', cursor);
// $($openPop).prop('mmCodes', mmCodes);
});

@ -0,0 +1,187 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- TOAST UI 이미지 에디터 CSS -->
<link rel="stylesheet" href="<c:url value='/plugins/tui-color-picker/tui-color-picker.min.css' />" />
<link rel="stylesheet" href="<c:url value='/plugins/tui-image-editor/tui-image-editor.css' />" />
<!-- 라이브러리 순서대로 로드 -->
<script src="<c:url value='/plugins/fabric.js/fabric.min.js' />"></script>
<script src="<c:url value='/plugins/tui-color-picker/tui-color-picker.min.js' />"></script>
<script src="<c:url value='/plugins/tui-image-editor/tui-image-editor.min.js' />"></script>
<link rel="stylesheet" href="<c:url value='/xit/xit-imageModify.css' />" />
<div id="photoDialog" style="display:none;">
<section id="section8" class="main_bars">
<div class="bgs-main">
<section id="section5">
<div class="sub_title">이미지 편집 (TOAST UI)</div>
</section>
</div>
</section>
<div class="contants_body">
<div class="gs_booking">
<div class="row">
<div class="col-sm-12">
<div class="box_column">
<!-- 이미지 에디터 컨테이너 -->
<div class="tui-image-editor-warapper" style="width: 100%; height: 700px;">
<div id="tui-image-editor"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<%-- <!-- 🔹 보기 모드 -->--%>
<%-- <div id="photoViewMode">--%>
<%-- <img id="photoDialogImg"--%>
<%-- src=""--%>
<%-- alt="사진 보기"--%>
<%-- style="max-width:100%; height:auto; display:block; margin:0 auto;">--%>
<%-- <div style="text-align:right; margin-top:8px;">--%>
<%-- <button type="button" id="btnPhotoEdit" class="btn btn-light">사진 편집</button>--%>
<%-- <button type="button" id="btnPhotoClose" class="btn btn-light">닫기</button>--%>
<%-- </div>--%>
<%-- </div>--%>
<%-- <!-- 🔹 편집 모드 -->--%>
<%-- <div id="photoEditMode" style="display:none;">--%>
<%-- <div class="edit-canvas-wrap">--%>
<%-- <!-- 나중에 cropperjs 붙일 이미지 or canvas -->--%>
<%-- <img id="photoEditImg"--%>
<%-- src=""--%>
<%-- alt="편집 대상"--%>
<%-- style="max-width:100%; height:auto; display:block; margin:0 auto;">--%>
<%-- </div>--%>
<%-- <div class="edit-toolbar" style="text-align:right; margin-top:8px;">--%>
<%-- <!-- 여기부터는 예시 버튼들. 나중에 기능 붙이면 됨 -->--%>
<%-- <button type="button" id="btnEditRotate" class="btn btn-light">회전</button>--%>
<%-- <button type="button" id="btnEditApply" class="btn btn-light">적용</button>--%>
<%-- <button type="button" id="btnEditCancel" class="btn btn-light">취소</button>--%>
<%-- </div>--%>
<%-- </div>--%>
</div>
<script type="text/javascript">
let photoDialogFn = {
photoMode: "view", // "view" | "edit"
setPhotoMode: (mode) => {
photoDialogFn.photoMode = mode;
if (mode === "view") {
$("#photoViewMode").show();
$("#photoEditMode").hide();
} else if (mode === "edit") {
$("#photoViewMode").hide();
$("#photoEditMode").show();
}
},
init: () => {
// ...
},
btnSet: (infoState) => {
// ...
},
eventListener: () => {
/** 🔹 썸네일 더블클릭 → 보기 모드로 다이얼로그 오픈 */
$("#photoThumbs").on("dblclick", "img", function () {
const src = $(this).attr("src");
// 보기/편집 둘 다 같은 src를 기본으로 사용
$("#photoDialogImg").attr("src", src);
$("#photoEditImg").attr("src", src);
photoDialogFn.setPhotoMode("view");
$("#photoDialog").dialog("open");
});
/** 🔹 보기 모드에서 "사진 편집" 버튼 */
$("#btnPhotoEdit").on("click", () => {
photoDialogFn.setPhotoMode("edit");
// 여기서 cropperjs 또는 편집 초기화 로직 들어가면 됨
// ex)
// const image = document.getElementById("photoEditImg");
// if (!fnBiz._cropper) {
// fnBiz._cropper = new Cropper(image, {...});
// }
});
/** 🔹 보기 모드에서 "닫기" 버튼 */
$("#btnPhotoClose").on("click", () => {
$("#photoDialog").dialog("close");
});
/** 🔹 편집 모드 "취소" → 다시 보기 모드로 */
$("#btnEditCancel").on("click", () => {
// 편집 취소 시, 보기 모드로 되돌리기
photoDialogFn.setPhotoMode("view");
// 필요하면 cropper 리셋/삭제
// if (fnBiz._cropper) {
// fnBiz._cropper.destroy();
// fnBiz._cropper = null;
// }
});
/** 🔹 편집 모드 "적용" */
$("#btnEditApply").on("click", () => {
// 여기서 편집 적용 → 서버 저장 or preview 반영 등
// 예: cropper.getCroppedCanvas().toDataURL() 등
// 일단은 그냥 보기 모드로만 전환
photoDialogFn.setPhotoMode("view");
});
/** 🔹 편집 모드 "회전" (예시) */
$("#btnEditRotate").on("click", () => {
// 나중에 cropper 붙이면:
// if (photoDialogFn._cropper) {
// photoDialogFn._cropper.rotate(90);
// }
});
}
};
$(function () {
$("#photoDialog").dialog({
autoOpen: false,
modal: true,
resizable: true,
// width: "auto",
width: 1000,
maxHeight: 800,
show: { effect: "slide", direction: "right", duration: 200 },
hide: { effect: "slide", direction: "right", duration: 200 },
title: "사진 보기",
open: function () {
// 다이얼로그 내용 스크롤 맨 위로
const $content = $(this); // .ui-dialog-content
$content.scrollTop(0);
$(this).dialog("widget").focus();
// 혹시 부모 컨테이너에 스크롤이 잡히는 경우까지 대비
const $wrapper = $content.closest(".ui-dialog");
$wrapper.scrollTop(0);
$(this).dialog("widget").focus();
}
});
})
</script>

@ -35,14 +35,17 @@
<input type="hidden" id="mmCodes" />
<%-- 부모창에서 받아오는 리스크 커서 --%>
<input type="hidden" id="cursor" />
<%-- 개별총정보 상태값 --%>
<input type="hidden" id="infoState" value="init" />
<div class="page-indicator"><span id="pageNow">2</span> of <span id="pageTotal">4</span></div>
<div class="page-indicator">
<span id="cursorCnt">0</span>of <span id="total">0</span></div>
<div class="nav-group">
<button type="button" class="nav-btn" data-act="first" id="first">◀◀</button>
<button type="button" class="nav-btn" data-act="prev">◀</button>
<button type="button" class="nav-btn" data-act="next">▶</button>
<button type="button" class="nav-btn" data-act="last">▶▶</button>
<button type="button" class="nav-btn" name="navigate" data-act="first" id="first">◀◀</button>
<button type="button" class="nav-btn" name="navigate" data-act="prev">◀</button>
<button type="button" class="nav-btn" name="navigate" data-act="next">▶</button>
<button type="button" class="nav-btn" name="navigate" data-act="last">▶▶</button>
</div>
</div>
@ -55,71 +58,83 @@
<div class="form-grid">
<div class="lbl">등록구분</div>
<div class="fld">
<input type="text" id="" value="" readonly>
<input type="text" data-field="mmLawgb" id="mmLawgb" value="" readonly>
</div>
<div class="lbl">자료출처</div>
<div class="fld">
<input type="text" id="" value="" readonly>
<input type="text" data-field="" id="" value="" readonly>
</div>
<div class="lbl">위반일시</div>
<div class="fld">
<input type="text" id="mmDate" value="" readonly>
<input type="text" name="cpMain" data-field="mmDate" id="mmDate" value="" readonly>
</div>
<div class="lbl">위반명</div>
<div class="fld">
<input type="text" id="" value="" readonly>
<input type="text" data-field="" id="" value="" readonly>
</div>
<div class="lbl">신고자</div>
<div class="fld">
<input type="text" id="mmSgnm" value="" readonly>
<input type="text" name="cpMain" data-field="mmSgnm" id="mmSgnm" value="" readonly>
</div>
<div class="lbl">연락처</div>
<div class="fld">
<input type="text" id="" value="" readonly>
<input type="text" name="cpAnswer" data-field="asCell" id="asCell" value="" readonly>
</div>
<div class="lbl">담당자</div>
<div class="fld"><input type="text" id="mmSgtel" value="" readonly></div>
<div class="fld">
<input type="text" name="cpMain" data-field="mmSgtel" id="mmSgtel" value="" readonly>
</div>
<div class="lbl">공개여부</div>
<div class="fld">
<input type="text" id="" value="" readonly>
<input type="text" data-field="" id="" value="" readonly>
</div>
<div class="lbl">신고내용</div>
<div class="fld block">
<textarea id="mmSgcont" value="" readonly></textarea>
<textarea name="cpMain" data-field="mmSgcont" id="mmSgcont" value="" readonly></textarea>
</div>
<div class="lbl">위반장소</div>
<div class="fld"><input type="text" id="" value="" readonly></div>
<div class="fld"><input type="text" data-field="" id="" value="" readonly></div>
<div class="lbl">접수번호</div>
<div class="fld"><input type="text" id="" value="" readonly></div>
<div class="fld"><input type="text" name="cpAnswer" data-field="asJsno" id="asJsno" value="" readonly></div>
<div class="lbl">접수일자</div>
<div class="fld"><input type="text" id="" value="" readonly></div>
<div class="fld"><input type="text" name="cpAnswer" data-field="asJsdate" id="asJsdate" value="" readonly></div>
<div class="lbl">목록번호</div>
<div class="fld"><input type="text" id="" value="" readonly></div>
<div class="fld"><input type="text" name="cpAnswer" data-field="asBbsNo" id="asBbsNo" value="" readonly></div>
<div class="lbl">법정동</div>
<div class="fld"><input type="text" id="" value="" readonly></div>
<div class="fld"><input type="text" data-field="" id="" value="" readonly></div>
<div></div><div></div>
<div class="lbl">사진등록금액</div>
<div class="fld"><input type="text" id="mmKeum1" value="" readonly></div>
<div class="fld">
<input type="text" name="cpMain" data-field="mmKeum1" id="mmKeum1" value="" readonly>
</div>
<div class="lbl">부과금액</div>
<div class="fld"><input type="text" id="" value="" readonly></div>
<div class="fld">
<input type="text" name="cpMain" data-field="mmKeum2" id="mmKeum2" value="" readonly>
</div>
<div class="lbl">감액금액</div>
<div class="fld"><input type="text" id="" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" id="" value="" readonly>
</div>
<div class="lbl">총수납액</div>
<div class="fld"><input type="text" id="" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" id="" value="" readonly>
</div>
<div class="lbl">잔액</div>
<div class="fld"><input class="hl" type="text" value="" readonly></div>
<div class="fld">
<input class="hl" data-field="" type="text" value="" readonly>
</div>
<div class="lbl">특기사항</div>
<div class="fld">
<button type="button" class="btn btn-light" id="btnSpecial">특기사항 보기</button>
@ -128,17 +143,27 @@
<div class="block bar"></div>
<div class="lbl">처리상태일시</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" name="cpAnswer" data-field="asStateDt" id="asStateDt" value="" readonly>
</div>
<div class="lbl">처리상태</div>
<div class="fld"><input class="hl" type="text" value="" readonly></div>
<div class="fld">
<input type="text" class="hl" name="cpAnswer" data-field="asState" id="asState" value="" readonly>
</div>
<div class="lbl">차량명</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">차량색상</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">연료구분</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div></div><div></div>
<div class="block bar"></div>
@ -146,25 +171,41 @@
<div class="section-title block">소유주 정보</div>
<div class="lbl">소유주</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">등록구분</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">주민번호</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">우편번호</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">주소</div>
<div class="fld block"><input type="text" value="" readonly></div>
<div class="fld block">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">번지</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">차대번호</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div class="lbl">도로코드</div>
<div class="fld"><input type="text" value="" readonly></div>
<div class="fld">
<input type="text" data-field="" value="" readonly>
</div>
<div></div><div></div>
</div>
</div>
@ -184,6 +225,19 @@
<img id="photoPreview" src="${pageContext.request.contextPath}/static/img/sample-1.jpg" alt="미리보기">
</div>
</div>
<div id="btn-area">
<button type="button" class="btn btn-light" id="infoEdit" hidden>수정</button>
<button type="button" class="btn btn-light" id="infoSave" hidden>저장</button>
<button type="button" class="btn btn-light" id="infoReadReturn" hidden>되돌리기</button>
<button type="button" class="btn btn-light" id="infoDel" hidden>삭제</button>
<button type="button" class="btn btn-light" id="delay" hidden>보류</button>
<button type="button" class="btn btn-light" id="destructionDocReReg" hidden>서손자료 재등록</button>
<button type="button" class="btn btn-light" id="buillPrint" hidden>고지서 출력</button>
<button type="button" class="btn btn-light" name="changeSt" id="non-target" value="81" hidden>미부과</button>
<button type="button" class="btn btn-light" id="stateChange" hidden>처리상태 변경</button>
</div>
</div>
<div class="statusbar">
@ -196,6 +250,10 @@
</div>
</div>
<div id="photoEditSection" style="display:none;">
<jsp:include page="/WEB-INF/views/biz/totalInfo/totalInfo_photo_dialog.jsp" />
</div>
<div id="tabs-b">
의견진술
@ -215,45 +273,43 @@
<%--<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>--%>
<%--<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>--%>
<script type="text/javascript">
const fnBiz = {
init: () => {
// fnBiz.search();
},
// 조회결과 바인딩 샘플
// const { cursor, mmCodes } = JSON.parse(localStorage.getItem("TOTAL_INFO_STATE"));
//해당 객체는 팝업으로 인한 브라우저 전역선언이다.
//일반적으로 함수를 선언할땐 그냥 fnBiz로 선언하면 된다.
//window 전역을 그냥 복사하면 덮어씌워져서 난리남.
//sample.jsp 형태로 하면됨
window.TOTAL_INFO_POPUP_API = {
search: () => {
console.log("search!!!!")
console.log("Total Info Search!!!!")
const { cursor, mmCodes } = JSON.parse(localStorage.getItem("TOTAL_INFO_STATE"));
let mmCode = $("#cursor").val();
console.log('mmcode check', mmCode)
$.ajax({
// PathVariable 형태로 url를 동적으로 쓰는방식이다.
// 해당 방식 이외에 그냥 쿼리스트링으로 넘기는 방법도 있다.
url: "/total/info/" + mmCode + "/info.ajax",
url: "/total/info/" + cursor + "/info.ajax",
type: "GET",
dataType: 'json',
success: function(response) {
// 리스폰스로 받아온 결과를 태그에 바인딩 해준다.
// 태그 id = 유니크 / 태그 name = 중복가능
// 묶음단위 혹은 동일한 값을 넣어야할때 name을 쓰고 보통은 id를 통해 바인딩 한다.
// 정확한 개념은 바인딩보다는 태그 value를 갈아끼는 것이다.
// 25.11.03 샘플로 작성한거라 main테이블 정보만 가져와서 뿌려주고 있다.
// f12 개발자 모드 > 콘솔창을 보면 아래 넘어오는 데이트를 볼수 있다.
console.log(response.data)
// .val 은 제이쿼리 함수로 테그의 value를 세팅하는 함수이다.
// 기본적으로 제이쿼리를 쓸텐데 아래 링크를 참조한다.
// https://xianeml.tistory.com/70
$("#mmLawgb").val(response.data.cpMain.mmLawgb);
$("#mmKeum1").val(response.data.cpMain.mmKeum1);
$("#mmKeum2").val(response.data.cpMain.mmKeum2);
$("#mmSgcont").val(response.data.cpMain.mmSgcont);
$("#mmSgnm").val(response.data.cpMain.mmSgnm);
$("#mmSgtel").val(response.data.cpMain.mmSgtel);
$("#mmDate").val(response.data.cpMain.mmDate);
$("#asBbsNo").val(response.data.cpAnswer.asBbsNo);
$("#asState").val(response.data.cpAnswer.asState);
$("#asStateDt").val(response.data.cpAnswer.asStateDt);
$("#asCell").val(response.data.cpAnswer.asCell);
$("#asJsno").val(response.data.cpAnswer.asJsno);
$("#asJsdate").val(response.data.cpAnswer.asJsdate);
$("#mmCode").text(response.data.cpMain.mmCode.substring(5).replace(/^(\d{4})(.*)$/, '$1-$2'))
@ -275,40 +331,193 @@
;
thumbContainer.append(img);
});
//네비게이터 커서 카운트
$("#cursorCnt").text(mmCodes.indexOf(cursor) + 1);
$("#total").text(mmCodes.length);
// total info 초기상태
$("#infoState").val("init").trigger("change");
},
error: function(xhr, status, error) {
$("#result").text("조회 실패");
}
});
}
},
}
let fnBiz = {
init: () => {
// fnBiz.search();
},
infoSave: () => {
const { cursor, mmCodes } = JSON.parse(localStorage.getItem("TOTAL_INFO_STATE"));
const payload = fnBiz.collectByDataField();
console.log("data-field payload:", payload);
$.ajax({
url: "/total/info/" + cursor + "/info/edit.ajax",
type: "POST",
data: JSON.stringify(payload),
contentType: "application/json",
success: function(response) {
alert("수정완료.")
},
error: function(xhr, status, error) {
$("#result").text("수정 실패");
}
});
},
changeState: (e) => {
let state = e.target.value;
const { cursor, mmCodes } = JSON.parse(localStorage.getItem("TOTAL_INFO_STATE"));
$.ajax({
url: `/total/info/\${cursor}/\${state}/state.ajax`,
type: "POST",
contentType: "application/json",
success: function(response) {
alert("완료.")
},
error: function(xhr, status, error) {
$("#result").text("수정 실패");
}
});
},
btnSet: (infoState) => {
switch (infoState) {
case "init":
$("#btn-area > button").prop("hidden", true);
$("#infoEdit").prop("hidden", false);
$("#infoDel").prop("hidden", false);
$("#delay").prop("hidden", false);
$("#buillPrint").prop("hidden", false);
$("#stateChange").prop("hidden", false);
$("#non-target").prop("hidden", false);
break;
case "edit":
$("#btn-area > button").prop("hidden", true);
$("#infoSave").prop("hidden", false);
$("#infoReadReturn").prop("hidden", false);
break;
}
switch ($("#asState")) {
case "":
$("#destructionDocReReg").prop("hidden", false);
}
},
collectByDataField: () => {
const payload = {};
$("[data-field]").each(function () {
const key = $(this).data("field");
const val = $(this).val();
payload[key] = val;
});
return payload;
},
eventListener: () => {
/** 네비게이션 */
$("button[name=navigate]").on("click", (e) => {
let flag = $(e.currentTarget).data("act");
let {cursor, mmCodes} = JSON.parse(localStorage.getItem("TOTAL_INFO_STATE"));
if (!cursor || !mmCodes) return;
const idx = mmCodes.indexOf(cursor);
let nextCursor = cursor;
switch (flag) {
case "first":
nextCursor = mmCodes[0];
break;
case "prev":
nextCursor = mmCodes[Math.max(0, idx - 1)];
break;
case "next":
nextCursor = mmCodes[Math.min(mmCodes.length - 1, idx + 1)];
break;
case "last":
nextCursor = mmCodes[mmCodes.length - 1];
break;
}
// 스토리지 업데이트
localStorage.setItem("TOTAL_INFO_STATE", JSON.stringify({ cursor: nextCursor, mmCodes: mmCodes }))
//커서로 조회
TOTAL_INFO_POPUP_API.search();
});
/** 개별총정보 상태변경 트리거 */
$("#infoState").on("change", () => {
fnBiz.btnSet($("#infoState").val());
})
/** 개별총정보 수정모드 진입*/
$("#infoEdit").on("click", () => {
$("input").prop("readonly", false);
$("#infoState").val("edit").trigger("change");
})
/** 개별총정보 읽기모드 진입 */
$("#infoReadReturn").on("click", () => {
$("input").prop("readonly", true);
TOTAL_INFO_POPUP_API.search();
$("#infoState").val("init").trigger("change");
})
/** 정보수정 */
$("#infoSave").on("click", () => {
fnBiz.infoSave();
$("input").prop("readonly", true);
TOTAL_INFO_POPUP_API.search();
})
/** 상태값 변경 */
$("button[name='changeSt']").on("click", (e) => {
let flag = e.target.value;
fnBiz.changeState(e, flag);
})
/** 사진 더블클릭 → 원본 다이얼로그 */
$("#photoThumbs").on("dblclick", "img", function () {
const src = $(this).attr("src"); // 썸네일 경로
$("#photoDialogImg").attr("src", src); // 같은 경로를 원본으로 사용 (원본/썸네일 분리돼 있으면 여기서 가공)
$("#photoDialog").dialog("open");
});
}
}
$(function () {
console.log("init")
$("#tabs").tabs();
//mmcode 리스트 가져오기
$("#cursor").val(window.cursor);
$("#mmCodes").val(window.mmCodes);
console.log($('#mmCodes').val());
// mmCodes 값이 세팅되면 search() 호출
const checkMmCode = setInterval(() => {
const cursor = $("#mmCodes").val();
const mmCodes = $("#mmCodes").val();
if (cursor && mmCodes) {
clearInterval(checkMmCode);
fnBiz.search(); // 값이 들어온 시점에 호출
}
}, 100);
TOTAL_INFO_POPUP_API.search();
fnBiz.eventListener();
});

@ -0,0 +1,16 @@
<%--
Created by IntelliJ IDEA.
User: kurt
Date: 2025. 11. 14.
Time: 오후 4:11
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
</body>
</html>

@ -139,7 +139,7 @@ var imageEditor = new tui.ImageEditor('#tui-image-editor', {
theme: {
// 테마 설정
},
menu: ['crop', 'flip', 'rotate', 'draw', 'shape', 'icon', 'text', 'mask', 'filter'],
menu: ['crop', 'flip', 'rotate', 'draw', 'shape', 'icon', 'text', 'mask', 'filter', 'mosaic'],
initMenu: 'filter',
uiSize: {
width: '100%',

Loading…
Cancel
Save