Browse Source

Merge branch 'develop' into eskim

eskim 5 years ago
parent
commit
dc3fa08cf1

+ 92 - 0
style24.admin/src/main/java/com/style24/admin/biz/dao/TsaNoticeDao.java

@@ -0,0 +1,92 @@
+package com.style24.admin.biz.dao;
+
+import java.util.Collection;
+
+import com.style24.core.support.annotation.ShopDs;
+import com.style24.persistence.domain.Notice;
+
+/**
+ * 공지사항 Dao
+ * 
+ * @author gagamel
+ * @since 2020. 10. 30
+ */
+@ShopDs
+public interface TsaNoticeDao {
+
+	/**
+	 * 공지사항 목록
+	 * @param notice - 공지사항 정보
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	Collection<Notice> getNoticeList(Notice notice);
+
+	/**
+	 * 공지사항 수신자 목록
+	 * @param noticeSq - 공지사항일련번호
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	Collection<Notice> getNoticeReceiverList(Integer noticeSq);
+
+	/**
+	 * 공지사항 파일 목록
+	 * @param noticeSq - 공지사항일련번호
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	Collection<Notice> getNoticeFileList(Integer noticeSq);
+
+	/**
+	 * 공지사항 저장
+	 * @param notice - 공지사항 정보
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	void createNotice(Notice notice);
+
+	/**
+	 * 공지사항 수정
+	 * @param notice - 공지사항 정보
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	void updateNotice(Notice notice);
+
+	/**
+	 * 공지사항 파일 저장
+	 * @param notice - 공지사항 정보
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	void createNoitceFlie(Notice notice);
+
+	/**
+	 * 공지사항 파일 삭제
+	 * @param notice - 공지사항 정보
+	 * @author jaewonHo
+	 * @since 2020. 01. 15
+	 */
+	void deleteNoticeFile(Notice notice);
+
+	/**
+	 * 공지사항 수신자 삭제
+	 * @param notice - 공지사항 정보
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	void deleteNoticeReceiver(Notice notice);
+
+	/**
+	 * 공지사항 수신자 저장
+	 * @param notice - 공지사항 정보
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	void createNoticeReceiver(Notice notice);
+
+}

+ 127 - 0
style24.admin/src/main/java/com/style24/admin/biz/service/TsaNoticeService.java

@@ -0,0 +1,127 @@
+package com.style24.admin.biz.service;
+
+import java.util.Collection;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.style24.admin.biz.dao.TsaNoticeDao;
+import com.style24.admin.support.security.session.TsaSession;
+import com.style24.persistence.domain.Notice;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 공지사항 Service
+ *
+ * @author gagamel
+ * @since 2020. 10. 30
+ */
+@Service
+@Slf4j
+public class TsaNoticeService {
+
+	@Autowired
+	private TsaNoticeDao noticeDao;
+
+	/**
+	 * 공지사항 목록
+	 * @param notice - 공지사항 정보
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	public Collection<Notice> getNoticeList(Notice notice) {
+		return noticeDao.getNoticeList(notice);
+	}
+
+	/**
+	 * 공지사항 수신자 목록
+	 * @param noticeSq - 공지사항일련번호
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	public Collection<Notice> getNoticeReceiverList(Integer noticeSq) {
+		return noticeDao.getNoticeReceiverList(noticeSq);
+	}
+
+	/**
+	 * 공지사항 파일 목록
+	 * @param noticeSq - 공지사항일련번호
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	public Collection<Notice> getNoticeFileList(Integer noticeSq) {
+		return noticeDao.getNoticeFileList(noticeSq);
+	}
+
+	/**
+	 * 공지사항 저장
+	 * @param notice - 공지사항 정보
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	@Transactional("shopTxnManager")
+	public void saveNotice(Notice notice) {
+		notice.setRegNo(TsaSession.getInfo().getUserNo());
+		notice.setUpdNo(TsaSession.getInfo().getUserNo());
+
+		// 신규 일때
+		if (notice.getNoticeSq() == null) {
+			// 공지사항 저장
+			noticeDao.createNotice(notice);
+
+			// 등록된 사용자번호 값 가져오기
+			Integer noticeSq = notice.getNoticeSq();
+			log.info("noticeSq: {}", noticeSq);
+			notice.setNoticeSq(noticeSq);
+		} else {
+			// 공지사항 수정
+			noticeDao.updateNotice(notice);
+		}
+
+		// 수신자 저장
+		if (!StringUtils.isAllBlank(notice.getReceiverIds())) {
+			noticeDao.deleteNoticeReceiver(notice);
+
+//			for (int i = 0; i < notice.getReceiverIds().length; i++) {
+			for (String receiverId : notice.getReceiverIds()) {
+				if (StringUtils.isNotBlank(receiverId)) {
+					notice.setReceiverId(receiverId);
+					log.info("noticeReceiver: {}", notice);
+					noticeDao.createNoticeReceiver(notice);
+				}
+			}
+		}
+
+		// 파일이 존재할때
+		if (!StringUtils.isAllBlank(notice.getSysFileNms())) {
+			noticeDao.deleteNoticeFile(notice);
+
+			for (int i = 0; i < notice.getFileCnt(); i++) {
+				notice.setOrgFileNm(notice.getOrgFileNms()[i]);
+				notice.setSysFileNm(notice.getSysFileNms()[i]);
+				log.info("noticeFile: {}", notice);
+				noticeDao.createNoitceFlie(notice);
+			}
+		}
+	}
+
+	/**
+	 * 공지사항 첨부파일 삭제
+	 * @param notice - 공지사항 정보
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	@Transactional("shopTxnManager")
+	public void deleteNoticeFile(Notice notice) {
+		noticeDao.deleteNoticeFile(notice);
+	}
+
+}

+ 0 - 3
style24.admin/src/main/java/com/style24/admin/biz/service/TsaSystemService.java

@@ -54,9 +54,6 @@ public class TsaSystemService {
 	 */
 	@Transactional("shopTxnManager")
 	public void deleteUserList(Collection<User> userList) {
-		if (userList == null || userList.isEmpty())
-			throw new IllegalStateException(message.getMessage("FAIL_1001"));
-
 		for (User user : userList) {
 			user.setUpdNo(TsaSession.getInfo().getUserNo());
 			systemDao.deleteUser(user);

+ 155 - 0
style24.admin/src/main/java/com/style24/admin/biz/web/TsaBoardController.java

@@ -0,0 +1,155 @@
+package com.style24.admin.biz.web;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.style24.admin.biz.service.TsaNoticeService;
+import com.style24.admin.biz.service.TsaRendererService;
+import com.style24.admin.support.controller.TsaBaseController;
+import com.style24.admin.support.env.TsaConstants;
+import com.style24.core.support.message.TscMessageByLocale;
+import com.style24.persistence.domain.Notice;
+
+import lombok.extern.slf4j.Slf4j;
+
+import com.gagaframework.web.rest.server.GagaResponse;
+import com.gagaframework.web.util.GagaFileUtil;
+
+/**
+ * 게시판 Controller
+ *
+ * @author gagamel
+ * @since 2020. 10. 30
+ */
+@Controller
+@RequestMapping("/board")
+@Slf4j
+public class TsaBoardController extends TsaBaseController {
+
+	@Autowired
+	private TscMessageByLocale message;
+
+	@Autowired
+	private TsaNoticeService noticeService;
+
+	@Autowired
+	private TsaRendererService rendererService;
+
+	@Value("${upload.default.target.path}")
+	private String uploadTargetPath;
+
+	/**
+	 * 공지사항 화면
+	 * @param noticeType - 공지유형(10:사이트공지, 20:내부공지)
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	@GetMapping("/notice/form/{noticeType}")
+	public ModelAndView noticeForm(@PathVariable String noticeType) {
+		ModelAndView mav = new ModelAndView();
+
+		// 공지유형
+		mav.addObject("noticeType", noticeType);
+
+		// 수신자 목록
+		// 공지유형이 "10:사이트공지"일 때는 사이트 목록
+		// 공지유형이 "20:내부공지"일 때는 공지수신자-조직 목록
+		if (noticeType.equals(TsaConstants.NoticeType.SITE.value())) {
+			mav.addObject("noticeReceiverList", rendererService.getAvailCommonCodeList("G000"));
+		} else if (noticeType.equals(TsaConstants.NoticeType.INNER.value())) {
+			mav.addObject("noticeReceiverList", rendererService.getAvailCommonCodeList("G048"));
+		}
+
+		mav.setViewName("board/NoticeForm");
+
+		return mav;
+	}
+
+	/**
+	 * 사이트 공지 목록
+	 * @param notice - 공지사항 정보
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	@PostMapping("/notice/list")
+	@ResponseBody
+	public Collection<Notice> getNoticeList(@RequestBody Notice notice) {
+		return noticeService.getNoticeList(notice);
+	}
+
+	/**
+	 * 공지사항 수신자 목록
+	 * @param noticeSq - 공지사항일련번호
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	@GetMapping("/notice/receiver/list/{noticeSq}")
+	@ResponseBody
+	public Collection<Notice> getNoticeReceiverList(@PathVariable Integer noticeSq) {
+		return noticeService.getNoticeReceiverList(noticeSq);
+	}
+
+	/**
+	 * 공지사항 파일목록 조회
+	 * @param noticeSq - 공지사항일련번호
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	@GetMapping("/notice/file/list/{noticeSq}")
+	@ResponseBody
+	public Collection<Notice> getNoticeFileList(@PathVariable Integer noticeSq) {
+		return noticeService.getNoticeFileList(noticeSq);
+	}
+
+	/**
+	 * 공지사항 저장
+	 * @param notice - 공지사항 정보
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	@PostMapping("/notice/save")
+	@ResponseBody
+	public GagaResponse saveNotice(@RequestBody Notice notice) {
+		noticeService.saveNotice(notice);
+		return super.ok(message.getMessage("SUCC_0001"));
+	}
+
+	/**
+	 * 첨부파일 삭제
+	 * @param notice - 공지사항 정보
+	 * @return
+	 * @throws IOException
+	 * @author gagamel
+	 * @since 2020. 3. 24
+	 */
+	@PostMapping("/notice/file/delete")
+	@ResponseBody
+	public GagaResponse deleteNoticeFile(@RequestBody Notice notice) throws IOException {
+		// 파일 삭제
+		String fileName = GagaFileUtil.getConcatenationPath(uploadTargetPath, "board", notice.getSysFileNm());
+
+		GagaFileUtil.deleteFile(fileName);
+
+		// 삭제된 파일 DB 처리
+		noticeService.deleteNoticeFile(notice);
+
+		return super.ok(message.getMessage("SUCC_0003"));
+	}
+
+}

+ 1 - 1
style24.admin/src/main/java/com/style24/admin/biz/web/TsaBusinessController.java

@@ -30,7 +30,7 @@ import com.gagaframework.web.rest.server.GagaResponse;
 /**
  * 영업관리 Controller
  *
- * @author jaewonHo
+ * @author gagamel
  * @since 2020. 10. 14
  */
 @Controller

+ 21 - 2
style24.admin/src/main/java/com/style24/admin/biz/web/TsaSystemController.java

@@ -123,7 +123,11 @@ public class TsaSystemController extends TsaBaseController {
 	@PostMapping("/user/list/delete")
 	@ResponseBody
 	public GagaResponse deleteUserList(@RequestBody Collection<User> userList) {
+		if (userList == null || userList.isEmpty())
+			throw new IllegalStateException(message.getMessage("FAIL_1001"));
+
 		systemService.deleteUserList(userList);
+
 		return super.ok(message.getMessage("SUCC_0003"));
 	}
 
@@ -208,10 +212,10 @@ public class TsaSystemController extends TsaBaseController {
 	 */
 	@PostMapping("/user/password/change")
 	@ResponseBody
-	public GagaResponse sendUserTemporaryPassword(@RequestBody User user) {
+	public GagaResponse changePassword(@RequestBody User user) {
 		user.setPasswd(passwordEncoder.encode(user.getPasswd()));
 		user.setUpdNo(TsaSession.getInfo().getUserNo());
-		log.debug("user: {}", user);
+		log.info("user: {}", user);
 
 		// 어드민사용자 비밀번호 수정
 		systemService.updateUserPassword(user);
@@ -252,6 +256,21 @@ public class TsaSystemController extends TsaBaseController {
 		return super.ok(message.getMessage("SUCC_0001"));
 	}
 
+	/**
+	 * 비밀번호 변경 팝업
+	 * @return
+	 * @author gagamel
+	 * @since 2020. 10. 30
+	 */
+	@GetMapping("/password/change/form")
+	public ModelAndView passwordChangeForm() {
+		ModelAndView mav = new ModelAndView();
+
+		mav.setViewName("system/PasswordChangeForm");
+
+		return mav;
+	}
+
 	/**
 	 * 메뉴관리 화면
 	 * @return

+ 16 - 0
style24.admin/src/main/java/com/style24/admin/support/env/TsaConstants.java

@@ -13,4 +13,20 @@ public class TsaConstants {
 
 	public static final String EXCEL_FOOTER_TITLE = "Copyright(c) 2020 STYLE24, All rights reserved.";
 
+	// 공지유형
+	public enum NoticeType {
+		SITE("G047_10"),
+		INNER("G047_20");
+
+		private String value;
+
+		private NoticeType(String value) {
+			this.value = value;
+		}
+
+		public String value() {
+			return value;
+		}
+	}
+
 }

+ 47 - 0
style24.admin/src/main/java/com/style24/persistence/domain/Notice.java

@@ -0,0 +1,47 @@
+package com.style24.persistence.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.style24.persistence.TscBaseDomain;
+
+import lombok.Data;
+
+/**
+ * 공지사항 Domain
+ * 
+ * @author gagamel
+ * @since 2020. 10. 30
+ */
+@SuppressWarnings("serial")
+@Data
+public class Notice extends TscBaseDomain {
+
+	private Integer noticeSq;		// 공지사항일련번호
+	private String noticeType;		// 공지사항유형
+	private String urgentYn;		// 긴급여부
+	private String noticeTitle;		// 공지사항제목
+	private String noticeContent;	// 공지사항내용
+	private int fileCnt;			// 파일건수
+	private String noticeStdt;		// 공지시작일시
+	private String noticeEddt;		// 공지종료일시
+	private int readCnt;			// 조회수
+	private String useYn;			// 사용여부
+
+	// 검색용
+	private String startDt;			// 시작일자
+	private String endDt;			// 종료일자
+	private String receiverId;		// 수신자ID
+
+	// 공지사항 수신자
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private String[] receiverIds;
+
+	// 공지사항 첨부파일
+	private Integer seq;
+	private String orgFileNm;
+	private String sysFileNm;
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private String[] orgFileNms;
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private String[] sysFileNms;
+
+}

+ 175 - 0
style24.admin/src/main/java/com/style24/persistence/mybatis/shop/TsaNotice.xml

@@ -0,0 +1,175 @@
+<?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="com.style24.admin.biz.dao.TsaNoticeDao">
+
+	<!-- 공지사항 목록 -->
+	<select id="getNoticeList" parameterType="Notice" resultType="Notice">
+		/* TsaNotice.getNoticeList */
+		SELECT A.NOTICE_SQ                                         /*공지번호*/
+		     , A.NOTICE_TYPE                                       /*공지유형*/
+		     , A.URGENT_YN                                         /*긴급여부*/
+		     , A.NOTICE_TITLE                                      /*공지제목*/
+		     , A.NOTICE_CONTENT                                    /*공지내용*/
+		     , IFNULL((SELECT COUNT(*)
+		               FROM   TB_NOTICE_FILE
+		               WHERE  NOTICE_SQ = A.NOTICE_SQ
+		              ),0)                          AS FILE_CNT    /*파일건수*/
+		     , DATE_FORMAT(A.NOTICE_STDT,'%Y%m%d')  AS NOTICE_STDT /*공지시작일자*/
+		     , DATE_FORMAT(A.NOTICE_EDDT,'%Y%m%d')  AS NOTICE_EDDT /*공지종료일자*/
+		     , A.USE_YN                                            /*사용여부*/
+		     , A.READ_CNT                                          /*조회수*/
+		     , FN_GET_USER_NM(A.REG_NO)             AS REG_NM      /*등록자*/
+		     , DATE_FORMAT(A.REG_DT,'%Y%m%d%H%i%S') AS REG_DT      /*등록일시*/
+		     , FN_GET_USER_NM(A.UPD_NO)             AS UPD_NM      /*수정자*/
+		     , DATE_FORMAT(A.UPD_DT,'%Y%m%d%H%i%S') AS UPD_DT      /*수정일시*/
+		FROM   TB_NOTICE A
+		WHERE  A.NOTICE_TYPE = #{noticeType}
+		<if test="startDt != null and startDt !=''">
+		AND    A.REG_DT <![CDATA[>=]]> STR_TO_DATE(#{startDt},'%Y-%m-%d')
+		</if>
+		<if test="startDt != null and startDt !='' and endDt != null and endDt != ''">
+		AND    A.REG_DT <![CDATA[<]]> DATE_ADD(STR_TO_DATE(#{endDt},'%Y-%m-%d'),INTERVAL 1 DAY)
+		</if>
+		<if test='useYn != null and useYn !=""'>
+		AND    A.USE_YN = #{useYn}
+		</if>
+		<if test="noticeTitle != null and noticeTitle !=''">
+		AND    LOWER(A.NOTICE_TITLE) LIKE CONCAT('%',LOWER(#{noticeTitle}),'%')
+		</if>
+		<if test='receiverId != null and receiverId !=""'>
+		AND    A.NOTICE_SQ IN (SELECT NOTICE_SQ
+		                       FROM   TB_NOTICE_RECEIVER
+		                       WHERE  RECEIVER_ID = #{receiverId}
+		                      )
+		</if>
+		ORDER  BY A.URGENT_YN DESC, A.NOTICE_SQ DESC
+	</select>
+
+	<!-- 공지사항 수신자 목록 -->
+	<select id="getNoticeReceiverList" parameterType="Integer" resultType="Notice">
+		/* TsaNotice.getNoticeReceiverList */
+		SELECT RECEIVER_ID
+		FROM   TB_NOTICE_RECEIVER
+		WHERE  NOTICE_SQ = #{noticeSq}
+	</select>
+
+	<!-- 공지사항 파일 목록 -->
+	<select id="getNoticeFileList" parameterType="Integer" resultType="Notice">
+		/* TsaNotice.getNoticeFileList */
+		SELECT NOTICE_SQ
+		     , SEQ
+		     , ORG_FILE_NM
+		     , SYS_FILE_NM
+		FROM   TB_NOTICE_FILE
+		WHERE  NOTICE_SQ = #{noticeSq}
+	</select>
+
+	<!-- 공지사항 저장 -->
+	<insert id="createNotice" parameterType="Notice" keyProperty="noticeSq">
+		/* TsaNotice.createNotice */
+		INSERT INTO TB_NOTICE (
+		       NOTICE_SQ
+		     , NOTICE_TYPE
+		     , NOTICE_TITLE
+		     , NOTICE_STDT
+		     , NOTICE_EDDT
+		     , NOTICE_CONTENT
+		     , URGENT_YN
+		     , USE_YN
+		     , READ_CNT
+		     , REG_NO
+		     , REG_DT
+		     , UPD_NO
+		     , UPD_DT
+		)
+		VALUES (
+		       NULL
+		     , #{noticeType}
+		     , #{noticeTitle}
+		     , STR_TO_DATE(#{noticeStdt},'%Y-%m-%d')
+		     , STR_TO_DATE(#{noticeEddt},'%Y-%m-%d')
+		     , #{noticeContent}
+		     , IFNULL(#{urgentYn},'N')
+		     , #{useYn}
+		     , IFNULL(#{readCnt},0)
+		     , #{regNo}
+		     , NOW()
+		     , #{updNo}
+		     , NOW()
+		)
+	</insert>
+
+	<!-- 공지사항 수정 -->
+	<update id="updateNotice" parameterType="Notice">
+		/* TsaNotice.updateNotice */
+		UPDATE TB_NOTICE
+		SET    NOTICE_TITLE = #{noticeTitle}
+		     , NOTICE_CONTENT = #{noticeContent}
+		     , NOTICE_STDT = STR_TO_DATE(#{noticeStdt},'%Y-%m-%d')
+		     , NOTICE_EDDT = STR_TO_DATE(#{noticeEddt},'%Y-%m-%d')
+		     , URGENT_YN = IFNULL(#{urgentYn},'N')
+		     , USE_YN = #{useYn}
+		     , UPD_NO = #{updNo}
+		     , UPD_DT = NOW()
+		WHERE  NOTICE_SQ = #{noticeSq}
+	</update>
+
+	<!-- 공지사항 수신자 삭제 -->
+	<delete id="deleteNoticeReceiver" parameterType="Notice">
+		/* TsaNotice.deleteNoticeReceiver */
+		DELETE FROM TB_NOTICE_RECEIVER
+		WHERE  NOTICE_SQ = #{noticeSq}
+	</delete>
+
+	<!--공지사항 수신자 등록 -->
+	<insert id="createNoticeReceiver" parameterType="Notice">
+		/* TsaNotice.createNoticeReceiver */
+		INSERT INTO TB_NOTICE_RECEIVER (
+		       NOTICE_SQ
+		     , RECEIVER_ID
+		     , REG_NO
+		     , REG_DT
+		)
+		VALUES (
+		       #{noticeSq}
+		     , #{receiverId}
+		     , #{regNo}
+		     , NOW()
+		)
+	</insert>
+
+	<!-- 공지사항 파일 삭제 -->
+	<delete id="deleteNoticeFile" parameterType="Notice">
+		/* TsaNotice.deleteNoticeFile */
+		DELETE FROM TB_NOTICE_FILE
+		WHERE  NOTICE_SQ = #{noticeSq}
+		<if test="seq != null and seq !=''">
+		AND    SEQ = #{seq}
+		</if>
+	</delete>
+
+	<!-- 공지사항 파일 저장 -->
+	<insert id="createNoitceFlie" parameterType="Notice">
+		/* TsaNotice.createNoitceFlie */
+		INSERT INTO TB_NOTICE_FILE (
+		       NOTICE_SQ
+		     , SEQ
+		     , ORG_FILE_NM
+		     , SYS_FILE_NM
+		     , REG_NO
+		     , REG_DT
+		)
+		VALUES (
+		       #{noticeSq}
+		     , IFNULL((SELECT MAX(SEQ)
+		               FROM   TB_NOTICE_FILE
+		               WHERE  NOTICE_SQ = #{noticeSq}
+		              ),0) + 1
+		     , #{orgFileNm}
+		     , #{sysFileNm}
+		     , #{regNo}
+		     , NOW()
+		)
+	</insert>
+
+</mapper>

+ 523 - 0
style24.admin/src/main/webapp/WEB-INF/views/board/NoticeForm.html

@@ -0,0 +1,523 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : NoticeForm.html
+ * @desc    : 공지사항관리 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2020 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2020.10.30   gagamel     최초 작성
+ *******************************************************************************
+ -->
+	<div id="main">
+		<!-- 메인타이틀 영역 -->
+		<div class="main-title">
+		</div>
+		<!-- //메인타이틀 영역 -->
+		
+		<!-- 메뉴 설명 -->
+		<div class="infoBox menu-desc">
+		</div>
+		<!-- //메뉴 설명 -->
+		
+		<!-- 검색조건 영역 -->
+		<div class="panelStyle">
+			<form id="searchForm" name="searchForm" action="#" th:action="@{'/board/notice/list'}" onsubmit="$('#btnSearch').trigger('click'); return false;">
+				<input type="hidden" name="noticeType" th:value="${noticeType}"/> <!-- 공지유형(10:사이트공지, 20:내부공지) -->
+				
+				<table class="frmStyle" aria-describedby="검색조건">
+					<colgroup>
+						<col width="10%"/>
+						<col width="23%"/>
+						<col width="10%"/>
+						<col width="23%"/>
+						<col width="10%"/>
+						<col width="24%"/>
+					</colgroup>
+					<tr>
+						<th>등록기간</th>
+						<td colspan="5" id="noticeTerms">
+						</td>
+					</tr>
+					<tr>
+						<th th:text="${noticeType == 'G047_10' ? '사이트' : '부서'}">수신자</th>
+						<td>
+							<select name="receiverId">
+								<option value="">[전체]</option>
+								<option th:if="${noticeReceiverList}" th:each="oneData, status : ${noticeReceiverList}" th:value="${oneData.cd}" th:text="${'[' + oneData.cd + '] ' + oneData.cdNm}"></option>
+							</select>
+						</td>
+						<th>공지제목</th>
+						<td>
+							<input name="noteicTitle" type="text" maxlength="200"/>
+						</td>
+						<th>사용여부</th>
+						<td>
+							<select name="useYn">
+								<option value="">[전체]</option>
+								<option value="Y">[Y] Yes</option>
+								<option value="N">[N] No</option>
+							</select>
+						</td>
+					</tr>
+				</table>
+				
+				<ul class="panelBar">
+					<li class="center">
+						<button type="button" class="btn btn-base btn-lg" id="btnSearch">조회</button>
+						<button type="button" class="btn btn-gray btn-lg" onclick="$('#searchForm')[0].reset();">초기화</button>
+					</li>
+				</ul>
+			</form>
+		</div>
+		<!-- 검색조건 영역 -->
+
+		<!-- 리스트 영역 -->
+		<div class="panelStyle">
+			<div id="gridList" style="width: 100%; height: 470px" class="ag-theme-balham"></div>
+		</div>
+		<!-- //리스트 영역 -->
+		
+		<!-- 등록/수정 -->
+		<div class="panelStyle">
+			<form id="detailForm" name="detailForm" action="#" th:action="@{'/board/notice/save'}">
+				<input type="hidden" name="noticeType" th:value="${noticeType}"/> <!-- 공지유형(10:사이트공지, 20:내부공지) -->
+				<input type="hidden" name="noticeStdt"/> <!-- 공지시작일자 -->
+				<input type="hidden" name="noticeEddt"/> <!-- 공지종료일자 -->
+				
+				<table class="frmStyle" aria-describedby="등록/수정 폼">
+					<colgroup>
+						<col style="width:10%;"/>
+						<col style="width:15%;"/>
+						<col style="width:10%;"/>
+						<col style="width:15%;"/>
+						<col style="width:10%;"/>
+						<col style="width:15%;"/>
+						<col style="width:10%;"/>
+						<col style="width:15%;"/>
+					</colgroup>
+					<tr>
+						<th>공지번호</th>
+						<td>
+							<input type="text" class="w100" name="noticeSq" placeholder="자동부여" readonly="readonly"/>
+						</td>
+						<th>긴급공지여부</th>
+						<td>
+							<label class="rdoBtn"><input type="radio" name="urgentYn" value="N" checked="checked">일반</label>
+							<label class="rdoBtn"><input type="radio" name="urgentYn" value="Y">긴급</label>
+						</td>
+						<th>사용여부</th>
+						<td>
+							<input type="hidden" name="useYn"/>
+							<label class="chkBox"><input type="checkbox" name="chkUseYn" checked="checked" value="Y"/>사용</label>
+						</td>
+					</tr>
+					<tr id="trNew">
+						<th>공지기간<i class="required" title="필수"></i></th>
+						<td colspan="5">
+							<input type="text" class="schDate w100" name="noticeStdt1" maxlength="10" th:value="${#calendars.format(#calendars.createNow(), 'yyyy-MM-dd')}"/>
+							~
+							<input type="text" class="schDate w100" name="noticeEddt1" maxlength="10" th:value="${#calendars.format(#calendars.createNow(), 'yyyy-MM-dd')}"/>
+						</td>
+					</tr>
+					<tr id="trDetail" style="display: none;">
+						<th>공지기간<i class="required" title="필수"></i></th>
+						<td>
+							<input type="text" class="schDate w100" name="noticeStdt2" maxlength="10"/>
+							~
+							<input type="text" class="schDate w100" name="noticeEddt2" maxlength="10"/>
+						</td>
+						<th>조회수</th>
+						<td>
+							<input type="text" class="w100 aR" name="readCnt" readonly="readonly"/>
+						</td>
+						<th>등록자/등록일</th>
+						<td>
+							<input type="text" class="w100" name="regNm" readonly="readonly"/>
+							/
+							<input type="text" class="w100" name="regDt" th:value="${#calendars.format(#calendars.createNow(), 'yyyy-MM-dd')}" readonly="readonly"/>
+						</td>
+					</tr>
+					<tr>
+						<th><span th:text="${noticeType == 'G047_10' ? '사이트' : '부서'}">수신자</span><i class="required" title="필수"></i></th>
+						<td colspan="5">
+							<label class="chkBox" th:if="${noticeReceiverList}" th:each="oneData, status : ${noticeReceiverList}">
+								<input type="checkbox" name="receiverIds" th:value="${oneData.cd}" th:text="${oneData.cdNm}"/>
+							</label>
+						</td>
+					</tr>
+					<tr>
+						<th>제목<i class="required" title="필수"></i></th>
+						<td colspan="5">
+							<input type="text" name="noticeTitle" required="required" data-valid-name="제목"/>
+						</td>
+					</tr>
+					<tr>
+						<th>공지내용<i class="required" title="필수"></i></th>
+						<td colspan="5">
+							<textarea class="textareaR4" name="noticeContent" id="noticeContent"></textarea>
+						</td>
+					</tr>
+					<tr>
+						<th>파일첨부</th>
+						<td colspan="5">
+							<div id="registeredFile"></div>
+							<div style="display: block">
+								<select name="fileCnt" id="fileCnt">
+									<th:block th:each="num: ${#numbers.sequence(1,10)}">
+										<option th:value="${num}" th:text="${num}"></option>
+									</th:block>
+								</select>* 파일 개수 선택(10개까지 가능)
+							</div>
+							<th:block th:each="num: ${#numbers.sequence(1,10)}">
+								<div>
+									<div class="uFile w500">
+										<input type="file" th:id="${'file' + num}" th:name="${'file' + num}" class="uFileInput w500"/>
+										<label th:for="${'file' + num}" class="uFileLabel">파일선택</label>
+										<input type="hidden" name="orgFileNms" th:id="${'orgFileNm' + num}"/>
+										<input type="hidden" name="sysFileNms" th:id="${'sysFileNm' + num}"/>
+									</div>
+									<br/>
+								</div>
+							</th:block>
+						</td>
+					</tr>
+				</table>
+			</form>
+			
+			<!-- 버튼 배치 영역 -->
+			<ul class="panelBar">
+				<li class="right">
+					<button type="button" class="btn btn-info btn-lg" id="btnNew">신규</button>
+					<button type="button" class="btn btn-success btn-lg" id="btnSave">저장</button>
+				</li>
+			</ul>
+			<!-- //버튼 배치 영역 -->
+		</div>
+		<!-- 등록/수정 -->
+	</div>
+
+<script type="text/javascript" src="/ux/plugins/summernote/summernote.js?v=2020103001"></script>
+<script type="text/javascript" src="/ux/plugins/gaga/gaga.summernote.js?v=2020103001"></script>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	// 공지사항유형(10:사이트공지, 20:내부공지)
+	let noticeType = [[${noticeType}]];
+
+	let columnDefs = [
+		{headerName: "공지번호", field: "noticeSq", width: 90, cellClass: 'text-center'},
+		{
+			headerName: "긴급공지", field: "urgentYn", width:90, cellClass: 'text-center',
+			cellRenderer: function(params) { return params.value == 'Y' ? '긴급' : '일반'; }
+		},
+// 		{headerName: "사이트", field: "siteNm", width: 200, cellClass: 'text-center'},
+		{
+			headerName: "공지제목", field: "noticeTitle", width: 500,
+			cellRenderer: function(params) { return '<a href="javascript:void(0);">' + params.value + '</a>'; }
+		},
+		{
+			headerName: "파일", field: "fileCnt", width: 50, cellClass: 'text-center',
+			cellRenderer: function(params) { return params.value > 0 ? '<i class="fa fa-folder fa-lg"></i>' : ''; }
+		},
+		{headerName: "공지내용", field: "noticeContent", width: 500, hide: true },
+		{
+			headerName: "공지시작일", field: "noticeStdt", width:120, cellClass: 'text-center',
+			cellRenderer: function(params) { return gagaAgGrid.toDateFormat(params.value); }
+		},
+		{
+			headerName: "공지종료일", field: "noticeEddt", width:120, cellClass: 'text-center',
+			cellRenderer: function(params) { return gagaAgGrid.toDateFormat(params.value); }
+		},
+		{headerName: "조회수", field: "readCnt", width:90, cellClass: 'text-center'},
+		{headerName: "사용여부", field: "useYn", width:90, cellClass: 'text-center'},
+		{headerName: "등록자", field: "regNm", width:90, cellClass: 'text-center'},
+		{
+			headerName: "등록일자", field: "regDt", width:120, cellClass: 'text-center',
+			cellRenderer: function(params) { return gagaAgGrid.toDateFormat(params.value); }
+		}
+	];
+
+	let gridOptions = gagaAgGrid.getGridOptions(columnDefs);
+
+	// Cell click
+	gridOptions.onCellClicked = function(event) {
+		if (event.colDef.field != 'noticeTitle')
+			return;
+		
+		$('#trNew').hide();
+		$('#trDetail').show();
+
+		$('#detailForm input[name=noticeSq]').val(event.data.noticeSq);
+		$('#detailForm input[name=noticeType]').val(event.data.noticeType);
+
+		if (event.data.urgentYn == 'Y') {
+			$('#detailForm input:radio[name=urgentYn]').eq(1).trigger('click');
+		} else {
+			$('#detailForm input:radio[name=urgentYn]').eq(0).trigger('click');
+		}
+
+		if (event.data.useYn == 'Y') {
+			$('#detailForm input:checkbox[name=chkUseYn]').prop('checked', true);
+		} else {
+			$('#detailForm input:checkbox[name=chkUseYn]').prop('checked', false);
+		}
+		
+		$('#detailForm input[name=noticeStdt2]').val(event.data.noticeStdt.toDate("YYYYMMDD").format("YYYY-MM-DD"));
+		$('#detailForm input[name=noticeEddt2]').val(event.data.noticeEddt.toDate("YYYYMMDD").format("YYYY-MM-DD"));
+		$('#detailForm input[name=readCnt]').val(event.data.readCnt);
+		$('#detailForm input[name=regNm]').val(event.data.regNm);
+		$('#detailForm input[name=regDt]').val(event.data.regDt.toDate("YYYYMMDD").format("YYYY-MM-DD"));
+		$('#detailForm input[name=noticeTitle]').val(event.data.noticeTitle);
+
+		// 공지내용. Summernote에 값 세팅
+		gagaSn.setContents('#noticeContent', event.data.noticeContent);
+
+		// 수신자 목록
+		fnGetNoticeReceiverList(event.data.noticeSq);
+
+		// 파일 목록
+		fnGetNoticeFileList(event.data.noticeSq);
+	}
+
+	// 검색
+	$('#btnSearch').on('click', function() {
+		gagaAgGrid.fetch($('#searchForm').prop('action'), gridOptions, '#searchForm');
+	});
+	
+	// 수신자 목록 조회
+	var fnGetNoticeReceiverList = function(noticeSq) {
+		let actionUrl = '/board/notice/receiver/list/' + noticeSq;
+		if (noticeType == 'G047_20') {
+			actionUrl = '/renderer/avail/commonCode/list/G048'; // 부서
+		}
+		
+		$.getJSON(actionUrl
+			, function(result) {
+				// 수신자 체크박스 체크 제거
+				$('#detailForm input:checkbox[name=receiverIds]').prop('checked', false);
+	
+				// 체크박스 개수
+				var chkboxCnt = $('#detailForm input:checkbox[name=receiverIds]').length;
+	
+				// 데이터 개수
+				var dataCnt = result.length;
+	
+				if (dataCnt > 0) {
+					for (var i = 0; i < chkboxCnt; i++) {
+						for (var j = 0; j < dataCnt; j++){
+							var data = result[j].receiverId;
+							if ($('#detailForm input:checkbox[name=receiverIds]').eq(i).val() == data) {
+								$('#detailForm input:checkbox[name=receiverIds]').eq(i).prop('checked', true);
+							}
+						}
+					}
+				}
+			});
+	}
+	
+	// 파일 조회
+	var fnGetNoticeFileList = function(noticeSq) {
+		$.getJSON('/board/notice/file/list/' + noticeSq
+			, function(result) {
+				if (result.length == 0) {
+					$('#registeredFile').html('');
+				} else {
+					$.each(result, function(idx, item) {
+						var tag = '';
+						tag += '<span class="memAdd">';
+						tag += '	<a id="dnFile' + (idx + 1) + '" href="#" onclick="fnDownloadFile(' + (idx + 1) + ', \'' + item.sysFileNm + '\');">' + item.orgFileNm + '</a>\n';
+						tag += '	<button type="button" onclick="fnDeleteFile(this, ' + item.noticeSq + ', ' + item.seq + ', \'' + item.sysFileNm + '\');">삭제</button>\n';
+						tag += '</span>';
+						$('#registeredFile').prepend(tag);
+					});
+				}
+			});
+	}
+	
+	// 파일다운로드
+	var fnDownloadFile = function(idx, fileNm) {
+		$('#dnFile' + idx).attr({
+			href : _uploadDefaultUrl + '/board/' + fileNm,
+			target: '_blank'
+		}).get(0).click();
+	}
+	
+	// 첨부파일 삭제
+	var fnDeleteFile = function(obj, noticeSq, seq, sysFileNm) {
+		mcxDialog.confirm('정말 삭제하시겠습니까?', {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				var params = new Object();
+				params.noticeSq = noticeSq;
+				params.seq = seq;
+				params.sysFileNm = sysFileNm;
+
+				var jsonData = JSON.stringify(params);
+				gagajf.ajaxJsonSubmit('/board/notice/file/delete', jsonData, function() {
+					$(obj).parent().remove();
+				});
+			}
+		});
+	}
+
+	// 첨부파일 개수 선택시
+	$("#fileCnt").on("change", function() {
+		for (var i = 1; i <= 10; i++) {
+			$('#file' + i).parent().parent().show();
+		}
+
+		var fileCnt = $(this).val();
+		for (var i = 10; i > fileCnt; i--) {
+			$('#file' + i).parent().parent().hide();
+		}
+	});
+
+	// 파일첨부 선택 시
+	$('#file1').on('change', function() { fnChooseFile(this, 1); });
+	$('#file2').on('change', function() { fnChooseFile(this, 2); });
+	$('#file3').on('change', function() { fnChooseFile(this, 3); });
+	$('#file4').on('change', function() { fnChooseFile(this, 4); });
+	$('#file5').on('change', function() { fnChooseFile(this, 5); });
+	$('#file6').on('change', function() { fnChooseFile(this, 6); });
+	$('#file7').on('change', function() { fnChooseFile(this, 7); });
+	$('#file8').on('change', function() { fnChooseFile(this, 8); });
+	$('#file9').on('change', function() { fnChooseFile(this, 9); });
+	$('#file10').on('change', function() { fnChooseFile(this, 10); });
+
+	var fnChooseFile = function(obj, fileNo) {
+		// multiple 속성이 있으면 files에는 다수의 객체가 할당됨
+		var file = obj.files[0];
+
+		// 파일 업로드
+		gagajf.ajaxFileUpload('/common/file/upload?subDir=/board'
+				, file
+				, function(result) {
+					// 업로드한 파일명 설정
+					$('#orgFileNm' + fileNo).val(result.oldFileName);
+					$('#sysFileNm' + fileNo).val(result.newFileName);
+				}
+		);
+	}
+	
+	// 신규 버튼 클릭
+	$("#btnNew").on("click", function(){
+		$('#detailForm')[0].reset();
+
+		$('#trNew').show();
+		$('#trDetail').hide();
+
+		$('#detailForm input[name=noticeSq]').val('');
+		$('#detailForm input[name=noticeStdt]').val(_today);
+		$('#detailForm input[name=noticeEddt]').val(_today);
+	});
+	
+	// 저장
+	$("#btnSave").on("click", function() {
+		// 날짜 체크
+		if (gagajf.isNull($('#detailForm input[name=noticeSq]').val())) {
+			if (gagajf.isNull($('#detailForm input[name=noticeStdt1]').val())) {
+				mcxDialog.alertC('공지시작일자를 입력해 주세요.', {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						$('#detailForm input[name=noticeStdt1]').focus();
+					}
+				});
+				return;
+			}
+
+			if (gagajf.isNull($('#detailForm input[name=noticeEddt1]').val())) {
+				mcxDialog.alertC('공지종료일자를 입력해 주세요.', {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						$('#detailForm input[name=noticeEddt1]').focus();
+					}
+				});
+				return;
+			}
+
+			$('#detailForm input[name=noticeStdt]').val($('#detailForm input[name=noticeStdt1]').val());
+			$('#detailForm input[name=noticeEddt]').val($('#detailForm input[name=noticeEddt1]').val());
+		} else {
+			if (gagajf.isNull($('#detailForm input[name=noticeStdt2]').val())) {
+				mcxDialog.alertC('공지시작일자를 입력해 주세요.', {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						$('#detailForm input[name=noticeStdt2]').focus();
+					}
+				});
+				return;
+			}
+
+			if (gagajf.isNull($('#detailForm input[name=noticeEddt2]').val())) {
+				mcxDialog.alertC('공지종료일자를 입력해 주세요.', {
+					sureBtnText: "확인",
+					sureBtnClick: function() {
+						$('#detailForm input[name=noticeEddt2]').focus();
+					}
+				});
+				return;
+			}
+
+			$('#detailForm input[name=noticeStdt]').val($('#detailForm input[name=noticeStdt2]').val());
+			$('#detailForm input[name=noticeEddt]').val($('#detailForm input[name=noticeEddt2]').val());
+		}
+
+		var stDate = $('#detailForm input[name=noticeStdt]').val().toDate('YYYY-MM-DD');
+		var edDate = $('#detailForm input[name=noticeEddt]').val().toDate('YYYY-MM-DD');
+
+		if (stDate > edDate) {
+			mcxDialog.alert("공지기간 종료일자는 시작일자 보다 클 수 없습니다.");
+			return;
+		}
+
+		// 수신자 선택
+		if ($('#detailForm input:checkbox[name=receiverIds]').is(":checked") != true) {
+			if (noticeType == 'G047_10') { // 사이트공지
+				mcxDialog.alert("사이트를 선택해 주세요.");
+				return;
+			} else if (noticeType == 'G047_20') { // 내부공지
+				mcxDialog.alert("부서를 선택해 주세요.");
+				return;
+			}
+		}
+
+		// validation
+		if (!gagajf.validation('#detailForm'))
+			return false;
+
+		$('#detailForm input[name=useYn]').val($('#detailForm input:checkbox[name=chkUseYn]').is(":checked") ? 'Y' : 'N');
+
+		mcxDialog.confirm('저장하시겠습니까?', {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				var jsonData = JSON.stringify($('#detailForm').serializeObject());
+				gagajf.ajaxJsonSubmit($('#detailForm').prop('action'), jsonData, function() {
+					$('#btnSearch').trigger('click');
+				});
+			}
+		});
+	});
+	
+	$(document).ready(function() {
+		cfnCreateCalendar('#noticeTerms', 'startDt', 'endDt');
+		
+		// Create a agGrid
+		gagaAgGrid.createGrid('gridList', gridOptions);
+		
+		// Create a summernote
+		let snOptions = gagaSn.getToolbarOptions('media');
+		gagaSn.createSummernote(snOptions, '#noticeContent');
+		
+		$("#fileCnt").trigger('change');
+	});
+/*]]>*/
+</script>
+
+</html>

+ 6 - 1
style24.admin/src/main/webapp/WEB-INF/views/common/fragments/gnb.html

@@ -43,7 +43,7 @@
 			<i class="dot">&bull;</i>
 			<a th:text="${sessionInfo.roleNm}">Director</a>
 			<i class="dot">&bull;</i>
-			<a th:onclick="|cfnPasswordChange();|">비밀번호 변경</a>
+			<a href="#" th:onclick="|fnOpenPasswordChangePopup();|">비밀번호 변경</a>
 			<i class="dot">&bull;</i>
 			<a href="#" th:href="@{/logout}">Log out</a>
 		</div>
@@ -82,6 +82,11 @@
 		cfnDrawLnbMenu($(a).data('menuId'));
 	});
 	
+	// 비밀번호 변경 팝업
+	var fnOpenPasswordChangePopup = function() {
+		cfnOpenModalPopup('/system/password/change/form', 'popupPasswordChange');
+	}
+	
 	$(document.body).ready(function() {
 		// 로그인메뉴목록 설정
 		cfnSetLoginMenuList([[${loginMenuList}]]);

+ 2 - 4
style24.admin/src/main/webapp/WEB-INF/views/envset/ClauseDetailForm.html

@@ -158,7 +158,7 @@
 </div>
 
 <script type="text/javascript" src="/ux/plugins/summernote/summernote.js?v=2020102902"></script>
-<script type="text/javascript" src="/ux/plugins/gaga/gaga.summernote.js?v=2020102904"></script>
+<script type="text/javascript" src="/ux/plugins/gaga/gaga.summernote.js?v=20201030"></script>
 <script th:inline="javascript">
 /*<![CDATA[*/
 	// 저장
@@ -181,11 +181,9 @@
 		});
 	});
 	
-	// Get a summernote options
-	let snOptions = gagaSn.getToolbarOptions();
-	
 	$(document).ready(function() {
 		// Create a summernote
+		let snOptions = gagaSn.getToolbarOptions();
 		gagaSn.createSummernote(snOptions, '#clauseContent');
 	});
 /*]]>*/

+ 41 - 29
style24.admin/src/main/webapp/WEB-INF/views/system/PopupPasswordChangeForm.html → style24.admin/src/main/webapp/WEB-INF/views/system/PasswordChangeForm.html

@@ -3,44 +3,51 @@
 	xmlns:th="http://www.thymeleaf.org">
 <!--
  *******************************************************************************
- * @source  : PopupPasswordChangeForm.html
- * @desc    : 비밀번호 변경 팝업
+ * @source  : PasswordChangeForm.html
+ * @desc    : 비밀번호 변경 팝업 Page
  *============================================================================
- * SISUN
- * Copyright(C) 2019 TSIT, All rights reserved.
+ * STYLE24
+ * Copyright(C) 2020 TSIT, All rights reserved.
  *============================================================================
  * VER  DATE         AUTHOR      DESCRIPTION
  * ===  ===========  ==========  =============================================
- * 1.0  2020.01.16   rladbwnd5   최초 작성
+ * 1.0  2020.10.30   gagamel     최초 작성
  *******************************************************************************
  -->
-	<ul class="popup modal" data-width="500" >
-		<li class="mdPopTitle">
+<div class="modalPopup" data-width="500" id="popupPasswordChange">
+	<div class="panelStyle">
+		<!-- TITLE -->
+		<div class="panelTitle">
 			<strong>비밀번호 변경</strong>
-			<button type="button" class="close" onclick="uifnPopupClose('popupPassword')"><i class="fa fa-times"></i></button>
-		</li>
-		<li class="mdPopContent">
+			<button type="button" class="close" onclick="uifnPopupClose('popupPasswordChange');"><em class="fa fa-times"></em></button>
+		</div>
+		<!-- //TITLE -->
+		
+		<!-- CONTENT -->
+		<div class="panelContent">
 			<form name="popupPasswordForm" id="popupPasswordForm" action="#" th:action="@{'/system/user/password/change'}" th:method="post">
-				<input type="hidden" name="userId" th:value="${userId}"/>
-				<table class="frmStyle" aria-describedby="수정">
+				<input type="hidden" name="userNo" th:value="${sessionInfo.userNo}"/>
+				
+				<table class="frmStyle" aria-describedby="변경폼">
 					<colgroup>
 						<col style="width:10%;"/>
+						<col/>
 					</colgroup>
 					<tbody>
 						<tr>
-							<th class="dashR">관리자ID<i class="star" aria-hidden="true"></i></th>
-							<td class="dashR" th:text="${userId}">
+							<th>사용자ID<em class="required" title="필수"></em></th>
+							<td th:text="${sessionInfo.userId}">
 							</td>
 						</tr>
 						<tr>
-							<th class="dashR">비밀번호<i class="star" aria-hidden="true"></i></th>
-							<td class="dashR">
+							<th>비밀번호<em class="required" title="필수"></em></th>
+							<td>
 								<input type="password" class="w300" name="passwd" data-valid-type="password" required="required" data-valid-name="비밀번호"/>
 							</td>
 						</tr>
 						<tr>
-							<th class="dashR">비밀번호 확인<i class="star" aria-hidden="true"></i></th>
-							<td class="dashR">
+							<th>비밀번호 확인<em class="required" title="필수"></em></th>
+							<td>
 								<input type="password" class="w300" name="passwdConfirm" data-valid-type="password" required="required" data-valid-name="비밀번호 확인"/>
 							</td>
 						</tr>
@@ -49,18 +56,23 @@
 				<p class="dot cBlue">대문자, 소문자, 특수문자, 숫자로 구성해야 합니다.</p>
 				<p class="dot cBlue">이 중 3개 이상은 8 ~ 20자, 2개 이상은 10 ~ 20자로 설정해야 합니다.</p>
 			</form>
-		</li>
-		<li class="boxContentBtnB">
-			<button type="button" class="btn btn-success btn-lg " id="btnPasswordChange">저장</button>
-		</li>
-	</ul>
+		</div>
+		<!-- //CONTENT -->
+		
+		<!-- 버튼 배치 영역 -->
+		<ul class="panelBar">
+			<li class="right">
+				<button type="button" class="btn btn-info btn-lg" id="btnPasswordChange">저장</button>
+			</li>
+		</ul>
+		<!-- //버튼 배치 영역 -->
+	</div>
+</div>
 
 <script th:inline="javascript">
 /*<![CDATA[*/
 	$('#btnPasswordChange').on('click', function() {
-		var formId = '#popupPasswordForm';
-		
-		if (!gagajf.validation(formId))
+		if (!gagajf.validation('#popupPasswordForm'))
 			return false;
 		
 		var pwd = $('#popupPasswordForm input[name="passwd"]').val();
@@ -71,12 +83,12 @@
 			return;
 		}
 		
-		mcxDialog.confirm("비밀번호를 변경 하시겠습니까?", {
+		mcxDialog.confirm("비밀번호를 변경하시겠습니까?", {
 			cancelBtnText: "취소",
 			sureBtnText: "확인",
 			sureBtnClick: function() {
-				gagajf.ajaxFormSubmit($(formId).prop('action'), formId, function() {
-					uifnPopupClose('popupPassword');
+				gagajf.ajaxFormSubmit($('#popupPasswordForm').prop('action'), '#popupPasswordForm', function() {
+					uifnPopupClose('popupPasswordChange');
 				});
 			}
 		});

+ 0 - 16
style24.admin/src/main/webapp/ux/js/admin.popup.js

@@ -268,22 +268,6 @@ var cfnOpenReviewDetailPopup = function(reviewSq) {
 
 }
 
-/**
- * @type   : function
- * @access : public
- * @desc   : 비밀번호 변경 팝업
- * <pre>
- *     cfnPasswordChange();
- * </pre>
- * @param  : actionUrl - 로딩 URL
- * @since  : 2020/01/16
- * @author : rladbwnd5
- */
-var cfnPasswordChange = function() {
-	var actionUrl = "/system/popup/password/change/form";
-	cfnOpenModalPopup(actionUrl,'popupPassword');
-}
-
 /**
  * @type   : function
  * @access : public

+ 1 - 1
style24.admin/src/main/webapp/ux/plugins/gaga/gaga.summernote.js

@@ -81,7 +81,7 @@ var gagaSn = {
 			lang : 'ko-KR', //기본 언어 인코딩
 			fontNames: ['Malgun Gothic', 'HY견고딕', 'Helvetica', 'Verdana', 'Arial', 'Arial Black'], //폰트 스타일
 			fontNamesIgnoreCheck: ['Malgun Gothic'], //기본폰트 스타일
-			focus: true, //로드시 에디터창에 포커싱
+			focus: false, //로드시 에디터창에 포커싱
 			fontSizes: ['8','9','10','11','12','13','14','15','16','17','18','19','20','24','30','36'],
 			toolbar: toolbarOptions,
 			callbacks: {

+ 8 - 6
style24.admin/src/main/webapp/ux/plugins/summernote/summernote.js

@@ -10238,9 +10238,8 @@ external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summe
 
 
 
-/* 이모티콘/이모지 : Emoji js ===================================================================================================*/
+/* 이모티콘 : Emoji js ===================================================================================================*/
 
-/*
 (function (factory) {
     if (typeof define === 'function' && define.amd) {
         define(['jquery'], factory);
@@ -10387,14 +10386,14 @@ external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summe
         }
     });
 }));
-*/
+/* //이모티콘 ============================================================================================*/
 
 
 
 
 
 /* 프린트 : Print js ===================================================================================================*/
-/*
+
 (function (factory) {
     // global define
     if (typeof define === 'function' && define.amd) {
@@ -10432,7 +10431,7 @@ external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summe
 
         //@param {Object} context - context object has status of editor.
         'print': function (context) {
-            var self = this;E
+            var self = this;
 
             // ui has renders to build ui elements.
             //  - you can create a button with `ui.button`
@@ -10508,4 +10507,7 @@ external_root_jQuery_commonjs2_jquery_commonjs_jquery_amd_jquery_default.a.summe
         }
     });
 }));
-//프린트 ===================================================================================================*/
+
+/* //프린트 ===================================================================================================*/
+
+