Merge pull request 'jh/jh' (#13) from jh/jh into dev

Reviewed-on: http://211.119.124.110:3000/cjm/clean-parking/pulls/13
pull/14/head
cjm 4 weeks ago
commit 0dfb93ce8f

@ -0,0 +1,197 @@
package go.kr.project.biz.minwon.dayanswer.controller;
import egovframework.constant.TilesConstants;
import egovframework.util.ApiResponseUtil;
import go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto;
import go.kr.project.biz.minwon.dayanswer.service.DayAnswerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
//import net.sf.jsqlparser.Model;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@Slf4j
@RequiredArgsConstructor
public class DayAnswerController {
private final DayAnswerService dayAnswerService;
@GetMapping("/minwon/dayanswer/dayanswer.do")
@Operation(summary = "일별답변결과", description = "일별답변결과 페이지를 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공")
})
public String dayanswerPageReturn() {
return "biz/minwon/dayanswer/dayanswer" + TilesConstants.BASE;
}
@PostMapping("/minwon/dayanswer/dayanswer-select.ajax")
public ResponseEntity<?> list(@ModelAttribute DayAnswerDto.Request.Search dto) {
dto.setTotalCount(0);
dto.setPagingYn("Y");
List<DayAnswerDto.Response.cpMain> result;
result = dayAnswerService.selectAllDayAnswer(dto);
return ApiResponseUtil.successWithGrid(result, dto);
}
@GetMapping("/minwon/dayanswer/dayanswertotalPop.do")
public String dayanswertotalPopup(@RequestParam("asMmcode") String asMmcode,
Model model) {
DayAnswerDto.Response.cpMain data =
dayAnswerService.selectOneByasMmcode(asMmcode);
model.addAttribute("data", data);
return "biz/minwon/dayanswer/dayanswertotal";
}
@PostMapping("/minwon/dayanswer/insert.ajax")
@ResponseBody
public ResponseEntity<?> insertDayAnswer(@RequestBody DayAnswerDto.Request.Insert dto) {
try {
String newCode = "41" + System.currentTimeMillis();
dto.setAsMmcode(newCode);
log.info("등록 요청: {}", dto);
dayAnswerService.insertDayAnswer(dto);
return ResponseEntity.ok(
Collections.singletonMap("result", "success")
);
} catch (Exception e) {
log.error("자료 등록 중 오류", e);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Collections.singletonMap("result", "fail"));
}
}
@GetMapping("/minwon/dayanswer/dayanswerregister.do")
public String dayanswerRegisterPageReturn() {
return "biz/minwon/dayanswer/dayanswerregister" + TilesConstants.BASE;
}
@PostMapping("/minwon/dayanswer/update.ajax")
@ResponseBody
public Map<String, Object> updateDayAnswer(@RequestBody DayAnswerDto.Request.Update dto) {
System.out.println(" UPDATE 요청 도착: " + dto.getAsMmcode() + ", 내용=" + dto.getAsText());
Map<String, Object> result = new HashMap<>();
try {
dayAnswerService.updateDayAnswer(dto);
result.put("status", "success");
} catch (Exception e) {
e.printStackTrace();
result.put("status", "error");
result.put("message", e.getMessage());
}
return result;
}
@GetMapping("/minwon/dayanswer/dayanswer-excel.do")
public void downloadExcel(
@ModelAttribute DayAnswerDto.Request.Search dto,
HttpServletResponse response
) throws Exception {
// 검색 조건을 이용해 전체 리스트 조회
List<DayAnswerDto.Response.cpMain> list = dayAnswerService.selectAllDayAnswer(dto);
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet("일별답변결과");
int rowNo = 0;
Row header = sheet.createRow(rowNo++);
header.createCell(0).setCellValue("메인코드");
header.createCell(1).setCellValue("시군구코드");
header.createCell(2).setCellValue("구분");
header.createCell(3).setCellValue("접수일자");
header.createCell(4).setCellValue("접수번호");
header.createCell(5).setCellValue("처리자");
header.createCell(6).setCellValue("전화번호");
header.createCell(7).setCellValue("휴대폰");
header.createCell(8).setCellValue("이메일");
header.createCell(9).setCellValue("처리상태");
header.createCell(10).setCellValue("답변내용");
for (DayAnswerDto.Response.cpMain rowData : list) {
Row row = sheet.createRow(rowNo++);
row.createCell(0).setCellValue(nvl(rowData.getAsMmcode()));
row.createCell(1).setCellValue(nvl(rowData.getAsSggcode()));
row.createCell(2).setCellValue(nvl(rowData.getAsIngb()));
row.createCell(3).setCellValue(nvl(rowData.getAsJsdate()));
row.createCell(4).setCellValue(nvl(rowData.getAsJsno()));
row.createCell(5).setCellValue(nvl(rowData.getAsUser()));
row.createCell(6).setCellValue(nvl(rowData.getAsTel()));
row.createCell(7).setCellValue(nvl(rowData.getAsCell()));
row.createCell(8).setCellValue(nvl(rowData.getAsEmail()));
row.createCell(9).setCellValue(nvl(rowData.getAsState()));
row.createCell(10).setCellValue(nvl(rowData.getAsText()));
}
for (int i = 0; i <= 10; i++) {
sheet.autoSizeColumn(i);
}
String fileName = URLEncoder.encode("일별답변결과.xlsx", StandardCharsets.UTF_8.name())
.replaceAll("\\+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
wb.write(response.getOutputStream());
wb.close();
}
private String nvl(String s) {
return s == null ? "" : s;
}
@GetMapping("/minwon/dayanswer/history.ajax")
@ResponseBody
public List<DayAnswerDto.Response.History> getHistory(
@RequestParam("asMmcode") String asMmcode) {
System.out.println(" [getHistory] 호출됨 - asMmcode = " + asMmcode);
List<DayAnswerDto.Response.History> list = dayAnswerService.selectHistoryasMmcode(asMmcode);
System.out.println(" 결과건수 = " + (list != null ? list.size() : 0));
return list;
}
}

@ -0,0 +1,22 @@
package go.kr.project.biz.minwon.dayanswer.mapper;
import go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DayAnswerMapper {
List<DayAnswerDto.Response.cpMain> selectAllDayAnswer(DayAnswerDto.Request.Search Dto);
DayAnswerDto.Response.cpMain selectOneByasMmcode(String asMmcode);
void insertDayAnswer(DayAnswerDto.Request.Insert dto);
void updateDayAnswer(DayAnswerDto.Request.Update dto);
List<DayAnswerDto.Response.History> selectHistoryasMmcode(String asMmcode);
int insertAnswerHistory(DayAnswerDto.Request.Update dto);
}

@ -0,0 +1,84 @@
package go.kr.project.biz.minwon.dayanswer.model;
import go.kr.project.system.common.model.PagingVO;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
public class DayAnswerDto {
public static class Request {
@Getter
@Setter
public static class Search extends PagingVO {
private String searchCondition;
private String searchKeyword;
private String searchStartDt;
private String searchEndDt;
private String worker;
}
@Data
public static class Update {
private String asMmcode;
private String asText;
}
@Data
public static class Insert {
private String asMmcode;
private String asSggcode;
private String asIngb;
private String asJsdate;
private String asJsno;
private String asUser;
private String asTel;
private String asCell;
private String asEmail;
private String asText;
}
}
public static class Response {
@Getter
@Setter
public static class cpMain {
private String asMmcode;
private String asSggcode;
private String asIngb;
private String asJsdate;
private String asJsno;
private String asJsnoM;
private String asBbsNo;
private String asLimitDt;
private String asUser;
private String asTel;
private String asCell;
private String asEmail;
private String asState;
private String asPostCd;
private String asPostDt;
private String asStateDt;
private String asText;
private String asReuser;
private String asInline;
private String asSysGubunC;
private String asPetiAncCodeV;
private String asPetiNoC;
}
@Data
public static class History {
private String asMmcode;
private String asText;
private String asUser;
private String asState;
private String updateDt;
}
}
}

@ -0,0 +1,4 @@
package go.kr.project.biz.minwon.dayanswer.repository;
public class DayAnswerQueryDslRepository {
}

@ -0,0 +1,22 @@
package go.kr.project.biz.minwon.dayanswer.service;
import go.kr.project.biz.minwon.dayanswer.mapper.DayAnswerMapper;
import go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
public interface DayAnswerService {
List<DayAnswerDto.Response.cpMain> selectAllDayAnswer(DayAnswerDto.Request.Search Dto);
DayAnswerDto.Response.cpMain selectOneByasMmcode(String asMmcode);
void insertDayAnswer(DayAnswerDto.Request.Insert dto);
List<DayAnswerDto.Response.History> selectHistoryasMmcode(String asMmcode);
void updateDayAnswer(DayAnswerDto.Request.Update dto);
}

@ -0,0 +1,51 @@
package go.kr.project.biz.minwon.dayanswer.service.impl;
import go.kr.project.biz.minwon.dayanswer.mapper.DayAnswerMapper;
import go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto;
import go.kr.project.biz.minwon.dayanswer.service.DayAnswerService;
import lombok.RequiredArgsConstructor;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@RequiredArgsConstructor
public class DayAnswerServiceImpl extends EgovAbstractServiceImpl implements DayAnswerService {
private final DayAnswerMapper dayAnswerMapper;
@Override
public List<DayAnswerDto.Response.cpMain> selectAllDayAnswer(DayAnswerDto.Request.Search dto) {
List<DayAnswerDto.Response.cpMain> result = dayAnswerMapper.selectAllDayAnswer(dto);
return result;
}
@Override
public DayAnswerDto.Response.cpMain selectOneByasMmcode (String asMmcode){
return dayAnswerMapper.selectOneByasMmcode(asMmcode);
}
@Override
public void insertDayAnswer(DayAnswerDto.Request.Insert dto) {
dayAnswerMapper.insertDayAnswer(dto);
}
@Override
public List<DayAnswerDto.Response.History> selectHistoryasMmcode(String asMmcode) {
return dayAnswerMapper.selectHistoryasMmcode(asMmcode);
}
@Override
@Transactional
public void updateDayAnswer(DayAnswerDto.Request.Update dto) {
dayAnswerMapper.updateDayAnswer(dto);
dayAnswerMapper.insertAnswerHistory(dto);
}
}

@ -90,4 +90,4 @@
ANSWER_ID = #{answerId}
</select>
</mapper>
</mapper>

@ -0,0 +1,113 @@
<?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.minwon.dayanswer.mapper.DayAnswerMapper">
<!--
매퍼인터페이스의 매소드명과 id가 일치해야 한다.
parameterType은 가져올 파라미터,
resultType은 쿼리 결과를 반납하는 객체를 넣어준다.
아래 보면 이너클래스는 $형태로 들어간다.
-->
<select id="selectAllDayAnswer"
parameterType="go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto$Request$Search"
resultType="go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto$Response$cpMain">
select *
from cp_answer
<!-- left outer join cp_answer CA on(cm.mm_code = ca.as_mmcode)-->
<where>
<if test="searchStartDt != null and searchStartDt != ''">
AND as_jsdate &gt;= REPLACE(#{searchStartDt}, '-', '')
</if>
<if test="searchEndDt != null and searchEndDt != ''">
AND as_jsdate &lt;= REPLACE(#{searchEndDt}, '-', '')
</if>
<choose>
<!-- 접수번호 -->
<when test="searchCondition == 'title' and searchKeyword != null and searchKeyword != ''">
AND as_Jsno LIKE CONCAT('%', #{searchKeyword}, '%')
</when>
<!-- 처리자명 -->
<when test="searchCondition == 'contents' and searchKeyword != null and searchKeyword != ''">
AND as_User LIKE CONCAT('%', #{searchKeyword}, '%')
</when>
<!-- 전화번호: 컬럼/입력 하이픈 제거 후 비교 -->
<when test="searchCondition == 'writer' and searchKeyword != null and searchKeyword != ''">
AND REPLACE(as_Tel, '-', '') LIKE CONCAT('%', REPLACE(#{searchKeyword}, '-', ''), '%')
</when>
<!-- 검색구분 비어 있고 키워드만 있는 경우 -->
<otherwise>
<if test="searchKeyword != null and searchKeyword != ''">
AND (
as_jsno LIKE CONCAT('%', #{searchKeyword}, '%')
OR as_user LIKE CONCAT('%', #{searchKeyword}, '%')
OR as_tel LIKE CONCAT('%', #{searchKeyword}, '%')
)
</if>
</otherwise>
</choose>
</where>
</select>
<select id="selectOneByasMmcode" parameterType="string" resultType="go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto$Response$cpMain">
select
AS_MMCODE asMmcode,
AS_SGGCODE asSggcode,
AS_INGB asIngb,
AS_JSDATE asJsdate,
AS_JSNO asJsno,
AS_BBS_NO asBbsNo,
AS_LIMIT_DT asLimitDt,
AS_USER asUser,
AS_TEL asTel,
AS_CELL asCell,
AS_EMAIL asEmail,
AS_TEXT asText
from cp_answer
<!-- left outer join cp_answer CA on(cm.mm_code = ca.as_mmcode) -->
WHERE AS_MMCODE = #{asMmcode}
</select>
<update id="updateDayAnswer"
parameterType="go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto$Request$Update">
UPDATE cp_answer
SET AS_TEXT = #{asText},
AS_STATE_DT = DATE_FORMAT(NOW(), '%Y%m%d%H%i%s')
WHERE AS_MMCODE = #{asMmcode}
</update>
<insert id="insertAnswerHistory"
parameterType="go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto$Request$Update">
INSERT INTO CP_ANSWER_HISTORY (
AS_MMCODE, AS_TEXT, UPDATE_DT
) VALUES (
#{asMmcode}, #{asText}, NOW()
)
</insert>
<insert id="insertDayAnswer"
parameterType="go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto$Request$Insert">
INSERT INTO cp_answer (
AS_MMCODE, AS_SGGCODE, AS_INGB, AS_JSDATE,
AS_JSNO, AS_USER, AS_TEL, AS_CELL, AS_EMAIL, AS_TEXT, AS_STATE
) VALUES (
#{asMmcode}, #{asSggcode}, #{asIngb}, #{asJsdate},
#{asJsno}, #{asUser}, #{asTel}, #{asCell}, #{asEmail}, #{asText}, '1'
)
</insert>
<select id="selectHistoryasMmcode"
parameterType="string"
resultType="go.kr.project.biz.minwon.dayanswer.model.DayAnswerDto$Response$History">
SELECT
AS_MMCODE asMmcode,
AS_TEXT asText,
AS_USER asUser,
AS_STATE asState,
DATE_FORMAT(UPDATE_DT, '%Y-%m-%d %H:%i:%s') as updateDt
FROM cp_answer_history
WHERE AS_MMCODE = #{asMmcode}
ORDER BY UPDATE_DT DESC
</select>
</mapper>

@ -0,0 +1,488 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- Main body -->
<div class="main_body">
<section id="section8" class="main_bars">
<div class="bgs-main">
<section id="section5">
<div class="sub_title"></div>
<button type="button" onclick="location.href='<c:url value='/template/noticeSample/register.do'/>'" class="newbtn bg1">등록</button>
</section>
</div>
</section>
<input type="text" id="bbs_no">
<div class="contants_body">
<div class="gs_b_top">
<ul class="lef">
<li class="th">검색구분</li>
<li>
<select id="searchCondition" name="searchCondition" class="input">
<option value="">검색구분</option>
<option value="title" <c:if test="${paramVO.searchCondition eq 'title'}">selected</c:if>>접수번호</option>
<option value="contents" <c:if test="${paramVO.searchCondition eq 'contents'}">selected</c:if>>처리자명</option>
<option value="writer" <c:if test="${paramVO.searchCondition eq 'writer'}">selected</c:if>>전화번호</option>
</select>
</li>
<li class="th">검색어</li>
<li><input type="text" id="searchKeyword" name="searchKeyword" class="input" value="${param.searchKeyword}"/></li>
<li class="th">접수일자 지정</li>
<li>
<input type="text" id="searchStartDt" name="searchStartDt" class="input calender datepicker" value="${param.searchStartDt}" /> ~
<input type="text" id="searchEndDt" name="searchEndDt" class="input calender datepicker" value="${param.searchEndDt}" />
</li>
<li>
<button type="button" id="search_btn" class="newbtnss bg1">검색</button>
<button type="button" id="btnAdd" class="newbtnss bg1">자료등록</button>
<button type="button" id="btnExcel" class="newbtnss bg1">엑셀다운로드</button>
</li>
</ul>
<ul class="rig2">
<li>
<select id="perPageSelect" class="input">
<option value="10" <c:if test="${param.perPage eq '10'}">selected</c:if>>페이지당 10</option>
<option value="20" <c:if test="${param.perPage eq '20'}">selected</c:if>>페이지당 20</option>
<option value="30" <c:if test="${param.perPage eq '30'}">selected</c:if>>페이지당 30</option>
</select>
<span class="page_number"><span id="currentPage"></span><span class="bar">/</span><sapn id="totalPages"></sapn> Pages</span>
</li>
</ul>
</div>
<div class="gs_booking">
<div class="row">
<div class="col-sm-12">
<div class="box_column">
<div class="containers">
<div id="grid"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /Main body -->
<script type="text/javascript">
/**
* 게시판 목록 관리 모듈
* 게시판 목록을 조회하고 관리하는 기능을 제공합니다.
*/
(function(window, $) {
'use strict';
var SEARCH_COND = {};
// 검색정보 셋팅
var setSearchCond = function() {
var searchCondition = $.trim(nvl($("#searchCondition").val(), ""));
var searchKeyword = $.trim(nvl($("#searchKeyword").val(), ""));
var searchUseYn = $.trim(nvl($("#searchUseYn").val(), ""));
var searchStartDt = $.trim(nvl($("#searchStartDt").val(), ""));
var searchEndDt = $.trim(nvl($("#searchEndDt").val(), ""));
SEARCH_COND.searchCondition = searchCondition;
SEARCH_COND.searchKeyword = searchKeyword;
SEARCH_COND.searchUseYn = searchUseYn;
SEARCH_COND.searchStartDt = searchStartDt;
SEARCH_COND.searchEndDt = searchEndDt;
};
/**
* 게시판 목록 관리 네임스페이스
*/
var NoticeList = {
/**
* 그리드 관련 객체
*/
grid: {
/**
* 그리드 인스턴스
*/
instance: null,
/**
* 그리드 설정 초기화
* @returns {Object} 그리드 설정 객체
*/
initConfig: function() {
// 데이터 소스 설정
var dataSource = this.createDataSource();
// 현재 선택된 perPage 값 가져오기
var perPage = parseInt($('#perPageSelect').val() || 10, 10);
// 그리드 설정 객체 생성
var gridConfig = new XitTuiGridConfig();
// 기본 설정
gridConfig.setOptDataSource(dataSource); // 데이터소스 연결
gridConfig.setOptGridId('grid'); // 그리드를 출력할 Element ID
gridConfig.setOptGridHeight(390); // 그리드 높이(단위: px)
gridConfig.setOptRowHeight(30); // 그리드 행 높이(단위: px)
gridConfig.setOptRowHeaderType('checkbox'); // 행 첫번째 셀 타입(rowNum: 순번, checkbox: 체크박스, '': 출력 안함)
// 페이징 옵션 설정
gridConfig.setOptPageOptions({
useClient: false, // 클라이언트 페이징 여부(false: 서버 페이징)
perPage: perPage // 페이지당 표시 건수
});
gridConfig.setOptUseClientSort(false); // 서버사이드 정렬 false
// 컬럼 정보 설정
gridConfig.setOptColumns([
{
header: 'asMmcode',
name: 'asMmcode',
width: 50,
align: 'center'
},
{
header: 'asSggcode',
name: 'asSggcode',
width: 70,
align: 'center'
},
{
header: 'asIngb',
name: 'asIngb',
width: 100,
align: 'center'
},
{
header: 'asJsdate',
name: 'asJsdate',
width: 100,
align: 'center'
},
{
header: 'asJsno',
name: 'asJsno',
width: 150,
align: 'center'
},
{
header: 'asJsnoM',
name: 'asJsnoM',
width: 70,
align: 'center'
},
{
header: 'asBbsNo',
name: 'asBbsNo',
width: 70,
align: 'center'
},
{
header: 'asLimitDt',
name: 'asLimitDt',
width: 150,
align: 'center'
},
{
header: 'asUser',
name: 'asUser',
width: 150,
align: 'center'
},
{
header: 'asTel',
name: 'asTel',
width: 50,
align: 'center'
},
{
header: 'asCell',
name: 'asCell',
width: 250,
align: 'center'
},
{
header: 'asEmail',
name: 'asEmail',
width: 150,
align: 'center'
},
{
header: 'asState',
name: 'asState',
width: 150,
align: 'center'
},
{
header: 'asPostCd',
name: 'asPostCd',
width: 150,
align: 'center'
},
{
header: 'asPostDt',
name: 'asPostDt',
width: 150,
align: 'center'
},
{
header: 'asStateDt',
name: 'asStateDt',
width: 150,
align: 'center'
},
{
header: 'asText',
name: 'asText',
width: 150,
align: 'center'
},
{
header: 'asReuser',
name: 'asReuser',
width: 150,
align: 'center'
},
{
header: 'asInline',
name: 'asInline',
width: 150,
align: 'center'
},
{
header: 'asSysGubunC',
name: 'asSysGubunC',
width: 150,
align: 'center'
},
{
header: 'asPetiAncCodeV',
name: 'asPetiAncCodeV',
width: 150,
align: 'center'
},
{
header: 'asPetiNoC',
name: 'asPetiNoC',
width: 150,
align: 'center'
}
]);
return gridConfig;
},
/**
* 데이터 소스 생성
* @returns {Object} 데이터 소스 객체
*/
createDataSource: function() {
return {
api: {
readData: {
url: '<c:url value="/minwon/dayanswer/dayanswer-select.ajax"/>',
method: 'POST',
contentType: 'application/x-www-form-urlencoded',
processData: true
}
},
initialRequest: false,
serializer: function (params) {
setSearchCond();
SEARCH_COND.perPage = params.perPage;
SEARCH_COND.page = params.page;
return $.param(SEARCH_COND);
}
};
},
/**
* 그리드 인스턴스 생성
*/
create: function() {
var gridConfig = this.initConfig();
var Grid = tui.Grid;
this.instance = gridConfig.instance(Grid);
// 그리드 테마 설정
Grid.applyTheme('striped');
// 그리드 이벤트 설정
this.gridBindEvents();
},
/**
* 그리드 이벤트 바인딩
*/
gridBindEvents: function() {
var self = this;
// 요청 성공 시 총 건수 표시
this.instance.on('successResponse', function(ev) {
var responseObj = JSON.parse(ev.xhr.response);
//$('.totCnt').text(responseObj.data.pagination.totalCount);
$("#currentPage").text(responseObj.data.pagination.page);
$("#totalPages").text(responseObj.data.pagination.totalPages);
});
this.instance.on('dblclick', function (ev) {
if (ev.rowKey === undefined) {
return;
}
var rowData = self.instance.getRow(ev.rowKey);
if (!rowData) {
return;
}
var asMmcode = rowData.asMmcode;
console.log("더블클릭 asMmcode =", asMmcode);
if (!asMmcode) {
alert("선택한 행에 asMmcode 값이 없습니다.");
return;
}
var popUrl = '<c:url value="/minwon/dayanswer/dayanswertotalPop.do"/>'
+ '?asMmcode=' + encodeURIComponent(asMmcode);
console.log("팝업 URL =", popUrl);
var popTitle = "상세정보";
var popOption = "width=1100,height=700,resizable=yes,scrollbars=yes,location=no,top=100,left=100";
window.open(popUrl, popTitle, popOption);
});
$('#btnAdd').on('click', function() {
const popUrl = '${pageContext.request.contextPath}/minwon/dayanswer/dayanswerregister.do';
const popTitle = '자료 등록';
const popOption = 'width=700,height=600,resizable=yes,scrollbars=yes';
window.open(popUrl, popTitle, popOption);
});
}
},
/**
* 이벤트 핸들러 설정
*/
eventBindEvents: function(e) {
var self = this;
$('#btnExcel').on('click', function() {
// 지금 화면의 검색조건 그대로 가져오기
const params = $.param({
searchCondition: $('#searchCondition').val(),
searchKeyword: $('#searchKeyword').val(),
searchStartDt: $('#searchStartDt').val(),
searchEndDt: $('#searchEndDt').val()
});
const url = '${pageContext.request.contextPath}/minwon/dayanswer/dayanswer-excel.do?' + params;
console.log("엑셀 다운로드 URL:", url);
window.location.href = url;
});
// 검색 버튼 클릭 이벤트
$('#search_btn').on('click', function() {
SEARCH_COND = {};
// 등록일 from~to 유효성 검사
var startDate = $("#searchStartDt").val().trim();
var endDate = $("#searchEndDt").val().trim();
// 시작일과 종료일 중 하나만 입력된 경우 체크
if ((startDate && !endDate) || (!startDate && endDate)) {
alert("등록일 검색 시 시작일과 종료일을 모두 입력해주세요.");
return;
}
// 시작일과 종료일이 모두 입력된 경우 유효성 검사
if (startDate && endDate) {
if (!isDate(startDate) || !isDate(endDate)) {
alert("유효한 날짜 형식이 아닙니다. (YYYY-MM-DD)");
return;
}
// 시작일이 종료일보다 늦은 경우 체크
var startDateObj = new Date(startDate);
var endDateObj = new Date(endDate);
if (startDateObj > endDateObj) {
alert("시작일은 종료일보다 이후일 수 없습니다.");
return;
}
}
// 페이지를 1로 리셋
$("#page").val(1);
// 그리드 데이터 리로드
self.grid.instance.readData(1);
});
// 검색어 입력 필드에서 엔터키 이벤트 처리
$('#searchKeyword').on('keypress', function(e) {
if (e.which === 13) { // 엔터키 코드는 13
e.preventDefault(); // 기본 이벤트 방지
$('#search_btn').trigger('click'); // 검색 버튼 클릭 이벤트 트리거
}
});
// perPage 변경 이벤트 추가
$('#perPageSelect').on('change', function() {
var perPage = parseInt($(this).val(), 10);
// Grid의 perPage 설정 변경 및 데이터 리로드
self.grid.instance.setPerPage(perPage);
});
},
/**
* 모듈 초기화
*/
init: function() {
// 그리드 생성
this.grid.create();
// 이벤트 핸들러 설정
this.eventBindEvents();
this.grid.instance.readData(${param.page eq null or param.page eq 0 ? 1 : param.page});
}
};
// 페이지 로드 시 초기화
$(function() {
NoticeList.init();
// $.ajax({
// url: "http://localhost:8080/postman/test",
// type: 'POST',
// contentType: 'application/json',
// data: JSON.stringify({
// aaa: "111",
// bbb: "222",
// ccc: "333"
// }), // 비어 있어도 {}
// success: function(response) {
// console.log(response);
// $("#bbs_no").val(response.asBbsNo);
// console.log($("#bbs_no").val());
//
//
// },
// error: function(xhr, status, error) {
// // 에러 처리는 xit-common.js의 ajaxError에서 처리됨
// }
// });
});
// 전역 네임스페이스에 모듈 노출
window.NoticeList = NoticeList;
})(window, jQuery);
</script>

@ -0,0 +1,138 @@
<%--
Created by IntelliJ IDEA.
User: moong
Date: 2025-11-06
Time: 오후 1:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>자료 등록</title>
<style>
body {
font-family: 'Noto Sans KR', sans-serif;
background: #f9fafc;
margin: 0;
padding: 20px;
}
.form-container {
background: white;
border-radius: 10px;
padding: 25px;
max-width: 600px;
margin: auto;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.form-item { margin-bottom: 12px; }
.form-item label { display: block; font-weight: bold; margin-bottom: 4px; color: #004b87; }
.form-item input, .form-item textarea {
width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 5px;
}
.submit-btn {
width: 100%;
background-color: #004b87;
color: white;
border: none;
padding: 12px;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
}
.submit-btn:hover { background-color: #0063b1; }
</style>
</head>
<body>
<div class="form-container">
<h2>자료 등록</h2>
<form id="registerForm">
<!-- asMmcode 자동 생성 -->
<input type="hidden" id="asMmcode" name="asMmcode"/>
<div class="form-item">
<label>SGG 코드</label>
<input type="text" id="asSggcode" name="asSggcode" required>
</div>
<div class="form-item">
<label>접수구분</label>
<input type="text" id="asIngb" name="asIngb">
</div>
<div class="form-item">
<label>접수일자</label>
<input type="text" id="asJsdate" name="asJsdate" placeholder="YYYYMMDD" required>
</div>
<div class="form-item">
<label>접수번호</label>
<input type="text" id="asJsno" name="asJsno">
</div>
<div class="form-item">
<label>담당자명</label>
<input type="text" id="asUser" name="asUser">
</div>
<div class="form-item">
<label>전화번호</label>
<input type="text" id="asTel" name="asTel">
</div>
<div class="form-item">
<label>휴대폰</label>
<input type="text" id="asCell" name="asCell">
</div>
<div class="form-item">
<label>이메일</label>
<input type="email" id="asEmail" name="asEmail">
</div>
<div class="form-item">
<label>답변내용</label>
<textarea id="asText" name="asText" rows="5"></textarea>
</div>
<button type="button" class="submit-btn" id="btnSave">등록</button>
</form>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
// 등록 버튼 클릭
$('#btnSave').on('click', function() {
var formData = {
asSggcode: $('#asSggcode').val(),
asIngb: $('#asIngb').val(),
asJsdate: $('#asJsdate').val(),
asJsno: $('#asJsno').val(),
asUser: $('#asUser').val(),
asTel: $('#asTel').val(),
asCell: $('#asCell').val(),
asEmail: $('#asEmail').val(),
asText: $('#asText').val()
};
$.ajax({
url: '/minwon/dayanswer/insert.ajax',
type: 'POST',
contentType: 'application/json; charset=UTF-8',
data: JSON.stringify(formData),
success: function (res) {
alert('등록이 완료되었습니다.');
window.close();
if (opener && opener.NoticeList && opener.NoticeList.grid) {
opener.NoticeList.grid.instance.readData(1);
} else if (opener) {
opener.location.reload();
}
},
error: function (xhr, status, error) {
console.log('등록 실패 응답:', xhr.responseText);
alert('등록 실패, 다시 시도해주세요.');
}
});
});
</script>
</body>
</html>

@ -0,0 +1,288 @@
<%--
Created by IntelliJ IDEA.
User: moong
Date: 2025-11-05
Time: 오후 1:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>상세정보</title>
<style>
/* 🌤 전체 배경 - 부드러운 연하늘색 */
body {
margin: 0;
min-height: 100vh;
background: linear-gradient(180deg, #e8f4fc, #d8f2ff);
font-family: 'Noto Sans KR', sans-serif;
color: #333;
}
/* 가운데 흰 카드 */
.main_body {
background: #ffffff;
border-radius: 10px;
padding: 20px 25px;
width: 85%;
max-width: 1100px;
margin: 30px auto;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
}
/* 왼쪽 상단 제목 */
.page-title {
display: inline-block;
background-color: #bde3ff;
color: #004b87;
font-weight: 700;
font-size: 22px;
padding: 8px 16px;
border-radius: 6px;
margin: 5px 0 20px 5px;
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
}
/* 상세 정보 카드 영역 */
.info-section {
margin: 10px auto;
padding: 15px 20px;
background: #ffffff;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
max-width: 900px;
}
.info-title {
text-align: left;
color: #004b87;
font-size: 18px;
font-weight: 700;
margin-bottom: 12px;
}
/* 2열 × 6행 (12개) */
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px 20px;
}
.info-item {
background: #f8fbff;
border: 1px solid #cde5f9;
border-radius: 6px;
padding: 8px 10px;
}
.info-label {
font-weight: 600;
color: #004b87;
font-size: 13px;
margin-bottom: 4px;
}
.info-value {
font-size: 14px;
color: #333;
word-break: break-all;
}
</style>
</head>
<body>
<div class="main_body">
<div class="info-section">
<h2 class="info-title">상세 정보</h2>
<div class="info-grid">
<div class="info-item">
<div class="info-label">asMmcode</div>
<div class="info-value">${data.asMmcode}</div>
<input type="hidden" id="asMmcode" value="${data.asMmcode}">
</div>
<div class="info-item">
<div class="info-label">asSggcode</div>
<div class="info-value">${data.asSggcode}</div>
</div>
<div class="info-item">
<div class="info-label">asIngb</div>
<div class="info-value">${data.asIngb}</div>
</div>
<div class="info-item">
<div class="info-label">asJsdate</div>
<div class="info-value">${data.asJsdate}</div>
</div>
<div class="info-item">
<div class="info-label">asJsno</div>
<div class="info-value">${data.asJsno}</div>
</div>
<div class="info-item">
<div class="info-label">asBbsNo</div>
<div class="info-value">${data.asBbsNo}</div>
</div>
<div class="info-item">
<div class="info-label">asLimitDt</div>
<div class="info-value">${data.asLimitDt}</div>
</div>
<div class="info-item">
<div class="info-label">asUser</div>
<div class="info-value">${data.asUser}</div>
</div>
<div class="info-item">
<div class="info-label">asTel</div>
<div class="info-value">${data.asTel}</div>
</div>
<div class="info-item">
<div class="info-label">asCell</div>
<div class="info-value">${data.asCell}</div>
</div>
<div class="info-item">
<div class="info-label">asEmail</div>
<div class="info-value">${data.asEmail}</div>
</div>
<div class="info-item">
<div class="info-label">asText</div>
<div class="info-value">${data.asText}</div>
</div>
<div class="info-item">
<div class="info-label">답변내용</div>
<div class="info-value">
<textarea id="asText" readonly style="width:100%;height:100px;">${data.asText}</textarea>
</div>
</div>
</div>
<div style="text-align:right; margin-top:20px;">
<button id="btnEdit" class="btn">답변수정</button>
<button id="btnSave" class="btn" style="display:none;">저장</button>
<button id="btnCancel" class="btn" style="display:none;">취소</button>
</div>
</div>
</div>
<div style="text-align:right; margin-bottom:10px;">
<button type="button" id="btnHistory"
style="background:#007BFF; color:#fff; border:none; padding:8px 14px; border-radius:5px;">
답변이력보기
</button>
</div>
<div id="historyModal"
style="display:none; position:fixed; top:0; left:0; width:100%; height:100%;
background:rgba(0,0,0,0.4); z-index:9999;">
<div style="background:#fff; width:80%; max-width:800px; margin:80px auto; padding:20px;
border-radius:10px; box-shadow:0 4px 15px rgba(0,0,0,0.3);">
<h3 style="margin-bottom:15px; color:#004b87;"> 답변 이력</h3>
<table style="width:100%; border-collapse:collapse; text-align:center;">
<thead>
<tr style="background:#e8f4fc; color:#004b87;">
<th style="padding:8px; border:1px solid #ccc;">날짜</th>
<th style="padding:8px; border:1px solid #ccc;">작성자</th>
<th style="padding:8px; border:1px solid #ccc;">상태</th>
<th style="padding:8px; border:1px solid #ccc;">내용</th>
</tr>
</thead>
<tbody id="historyTableBody"></tbody>
</table>
<div style="text-align:right; margin-top:15px;">
<button onclick="$('#historyModal').hide()"
style="background:#999; color:white; border:none; padding:6px 12px; border-radius:4px;">
닫기
</button>
</div>
</div>
</div>
</div>
</body>
</html>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
$(function(){
$('#btnEdit').on('click', function(){
$('#asText').prop('readonly', false).focus();
$('#btnEdit').hide();
$('#btnSave, #btnCancel').show();
});
$('#btnCancel').on('click', function(){
$('#asText').prop('readonly', true);
$('#btnEdit').show();
$('#btnSave, #btnCancel').hide();
});
$('#btnSave').on('click', function(){
const asMmcode = $('#asMmcode').val();
const asText = $('#asText').val().trim();
if (!asMmcode) {
alert("asMmcode 값이 없습니다. 수정할 수 없습니다.");
return;
}
if(!asText){
alert("답변 내용을 입력하세요.");
return;
}
$.ajax({
url: '${pageContext.request.contextPath}/minwon/dayanswer/update.ajax',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ asMmcode: asMmcode, asText: asText }),
success: function(res){
alert('수정이 완료되었습니다.');
opener.location.reload();
window.close();
},
error: function(xhr, status, error){
alert('수정 실패: ' + error);
}
});
});
});
$('#btnHistory').on('click', function() {
const asMmcode = '${data.asMmcode}'; // 상세화면에 바인딩된 코드
if (!asMmcode) {
alert('asMmcode 값이 없습니다.');
return;
}
$.ajax({
url: '<c:url value="/minwon/dayanswer/history.ajax"/>',
type: 'GET',
data: { asMmcode: asMmcode }, // → 컨트롤러에서 @RequestParam("asMmcode") 로 받음
success: function(list) {
const tbody = $('#historyTableBody').empty();
if (!list || list.length === 0) {
tbody.append('<tr><td colspan="4">이력 데이터가 없습니다.</td></tr>');
$('#historyModal').show();
return;
}
list.forEach(function(item) {
tbody.append(
'<tr>'
+ '<td style="padding:6px; border:1px solid #ccc;">' + (item.updateDt || '') + '</td>'
+ '<td style="padding:6px; border:1px solid #ccc;">' + (item.asUser || '-') + '</td>'
+ '<td style="padding:6px; border:1px solid #ccc;">' + (item.asState || '-') + '</td>'
+ '<td style="padding:6px; border:1px solid #ccc;">' + (item.asText || '-') + '</td>'
+ '</tr>'
);
});
$('#historyModal').show();
},
error: function(xhr, status, error) {
console.log('history.ajax 에러', status, error);
alert('답변조회 실패');
}
});
});
</script>
Loading…
Cancel
Save