xbase patch_20230608 추가

main
이범준 1 year ago
parent f0942e2a88
commit 9e64ca6a3f

@ -0,0 +1,78 @@
<?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="cokr.xit.base.security.access.dao.ActionGroupMapper">
<resultMap id="groupRow" type="cokr.xit.base.security.access.ActionGroup">
<result property="id" column="GRP_ID"/>
<result property="name" column="GRP_NM"/>
<result property="description" column="DSCRP"/>
<result property="createdAt" column="REG_DT"/>
</resultMap>
<sql id="selectGroups"><include refid="utility.paging-prefix" />
SELECT A.*
FROM TB_ACTION_GRP A
<where>
<if test="groupIDs != null">AND GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</if>
<if test="by != null and term != null">AND ${by} LIKE CONCAT('%', #{term}, '%')</if>
</where>
<include refid="utility.paging-suffix" /></sql>
<select id="getGroupList" parameterType="map" resultType="dataobject">/* 기능그룹 목록 조회(actionGroupMapper.getGroupList) */
<include refid="selectGroups" /></select>
<select id="getGroups" parameterType="map" resultMap="groupRow">/* 기능그룹 가져오기(actionGroupMapper.getGroups) */
<include refid="selectGroups" /></select>
<insert id="insertGroup" parameterType="cokr.xit.base.security.access.ActionGroup">/* 기능그룹 등록(actionGroupMapper.insertGroup) */
INSERT INTO TB_ACTION_GRP (
GRP_ID
, GRP_NM
, DSCRP
, REG_DT
) VALUES (
#{id}
, #{name}
, #{description}
,<include refid="utility.now" />
)</insert>
<update id="updateGroup" parameterType="cokr.xit.base.security.access.ActionGroup">/* 기능그룹 수정(actionGroupMapper.updateGroup) */
UPDATE TB_ACTION_GRP SET
GRP_NM = #{name}
, DSCRP = #{description}
WHERE GRP_ID = #{id}</update>
<delete id="removeGroups" parameterType="map">/* 기능그룹 삭제(actionGroupMapper.removeGroups) */
DELETE FROM TB_ACTION_GRP
WHERE GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</delete>
<select id="getActionList" parameterType="map" resultType="dataobject">/* 그룹별 기능 가져오기(actionGroupMapper.getActionList) */
SELECT *
FROM TB_GRP_ACTION
<if test="groupIDs != null">WHERE GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</if>
ORDER BY GRP_ID, ACTION
</select>
<insert id="addActions" parameterType="map">/* 그룹별 기능 추가(actionGroupMapper.addActions) */
INSERT INTO TB_GRP_ACTION (GRP_ID, ACTION, REG_DT, RGTR)
SELECT GRP_ID, ACTION,<include refid="utility.now" />, #{currentUser.id}
FROM (<foreach collection="actions" item="action" separator="UNION">
SELECT #{groupID} GRP_ID, #{action} ACTION FROM DUAL</foreach>
) A
WHERE NOT EXISTS (
SELECT GRP_ID, ACTION
FROM TB_GRP_ACTION B
WHERE B.GRP_ID = A.GRP_ID
AND B.ACTION = A.ACTION
)</insert>
<delete id="removeActions" parameterType="map">/* 그룹별 기능 삭제(actionGroupMapper.removeActions) */
DELETE FROM TB_GRP_ACTION
<where>
<if test="groupIDs != null">AND GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</if>
<if test="actions != null">AND ACTION IN (<foreach collection="actions" item="action" separator=",">#{action}</foreach>)</if>
</where>
</delete>
</mapper>

@ -0,0 +1,141 @@
<?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="cokr.xit.base.security.access.dao.AuthorityMapper">
<resultMap id="authRow" type="cokr.xit.base.security.Authority">
<result property="type" column="AUTH_TYPE"/>
<result property="id" column="AUTH_ID"/>
<result property="name" column="AUTH_NM"/>
<result property="infoScope" column="INF_SCP"/>
<result property="userInfoScope" column="USER_INF_SCP"/>
<result property="description" column="DSCRP"/>
<result property="createdAt" column="REG_DT"/>
</resultMap>
<sql id="selectAuthorities"><include refid="utility.paging-prefix" />
SELECT * FROM (
SELECT 0 AUTH_TYPE, 'ROLE_ADMIN' AUTH_ID, '시스템 관리자' AUTH_NM, '시스템 관리자' DSCRP, 'all' INF_SCP, 'all' USER_INF_SCP,<include refid="utility.now"/>REG_DT UNION
SELECT 1 AUTH_TYPE, 'ROLE_ANONYMOUS' AUTH_ID, '익명 사용자' AUTH_NM, '모든 사용자' DSCRP, 'none' INF_SCP, 'none' USER_INF_SCP,<include refid="utility.now"/>REG_DT UNION
SELECT 1 AUTH_TYPE, 'ROLE_USER' AUTH_ID, '시스템 사용자' AUTH_NM, '로그인한 사용자' DSCRP, 'self' INF_SCP, 'self' USER_INF_SCP,<include refid="utility.now"/>REG_DT UNION
SELECT 2 AUTH_TYPE, AUTH_ID, AUTH_NM, DSCRP, INF_SCP, USER_INF_SCP, REG_DT
FROM TB_AUTHORITY
) A
<where>
<if test="authIDs != null">AND AUTH_ID IN (<foreach collection="authIDs" item="authID" separator=",">#{authID}</foreach>)</if>
<if test="by != null and term != null">AND ${by} LIKE CONCAT('%', #{term}, '%')</if>
</where>
<include refid="utility.orderBy"/>
<include refid="utility.paging-suffix" /></sql>
<select id="getAuthorityList" parameterType="map" resultType="dataobject">/* 권한 목록 조회(authorityMapper.getAuthorityList) */
<include refid="selectAuthorities" /></select>
<select id="getAuthorities" parameterType="map" resultMap="authRow">/* 권한 가져오기(authorityMapper.getAuthorities) */
<include refid="selectAuthorities" /></select>
<insert id="insertAuthority" parameterType="cokr.xit.base.security.Authority">/* 권한 등록(authorityMapper.insertAuthority) */
INSERT INTO TB_AUTHORITY (
AUTH_ID
, AUTH_NM
, DSCRP
, INF_SCP
, USER_INF_SCP
, REG_DT
) VALUES (
#{id}
, #{name}
, #{description}
, #{infoScope}
, #{userInfoScope}
,<include refid="utility.now" />
)</insert>
<update id="updateAuthority" parameterType="cokr.xit.base.security.Authority">/* 권한 수정(authorityMapper.updateAuthority) */
UPDATE TB_AUTHORITY SET
AUTH_NM = #{name}
, DSCRP = #{description}
, INF_SCP = #{infoScope}
, USER_INF_SCP = #{userInfoScope}
WHERE AUTH_ID = #{id}</update>
<delete id="removeAuthorities" parameterType="map">/* 권한 삭제(authorityMapper.removeAuthorities) */
DELETE FROM TB_AUTHORITY
WHERE AUTH_ID IN (<foreach collection="authIDs" item="authID" separator=",">#{authID}</foreach>)</delete>
<select id="getActionGroupList" parameterType="map" resultType="dataobject">/* 권한-기능그룹 가져오기(authorityMapper.getActionGroups) */
<include refid="utility.paging-prefix" />
SELECT *
FROM TB_AUTH_ACTION
<if test="authIDs != null">WHERE AUTH_ID IN (<foreach collection="authIDs" item="authID" separator=",">#{authID}</foreach>)</if>
ORDER BY AUTH_ID, GRP_ID
<include refid="utility.paging-suffix" /></select>
<insert id="addActionGroups" parameterType="map">/* 권한-기능그룹 추가(authorityMapper.addActionGroups) */
INSERT INTO TB_AUTH_ACTION (AUTH_ID, GRP_ID, REG_DT)
SELECT AUTH_ID, GRP_ID,<include refid="utility.now" />
FROM (<foreach collection="groupIDs" item="groupID" separator=" UNION">
SELECT #{authID} AUTH_ID, #{groupID} GRP_ID FROM DUAL</foreach>
) A
WHERE NOT EXISTS (
SELECT AUTH_ID, GRP_ID
FROM TB_AUTH_ACTION B
WHERE B.AUTH_ID = A.AUTH_ID
AND B.GRP_ID = A.GRP_ID
)</insert>
<delete id="removeActionGroups" parameterType="map">/* 권한-기능그룹 삭제(authorityMapper.removeActionGroups) */
DELETE FROM TB_AUTH_ACTION
<where>
<if test="authIDs != null">AND AUTH_ID IN (<foreach collection="authIDs" item="authID" separator=",">#{authID}</foreach>)</if>
<if test="groupIDs != null">AND GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</if>
</where>
</delete>
<select id="getActionList" resultType="dataobject">/* 권한-기능 가져오기(authorityMapper.getActionList) */
SELECT A.AUTH_ID
, A.GRP_ID
, C.ACTION
FROM TB_AUTH_ACTION A
, TB_ACTION_GRP B
, TB_GRP_ACTION C
WHERE A.GRP_ID = B.GRP_ID
AND B.GRP_ID = C.GRP_ID
ORDER BY A.AUTH_ID, A.GRP_ID, C.ACTION</select>
<sql id="selectAuthUser">
<include refid="utility.paging-prefix" />
SELECT *
FROM TB_AUTH_USER
<if test="authIDs != null">WHERE AUTH_ID IN (<foreach collection="authIDs" item="authID" separator=",">#{authID}</foreach>)</if>
<if test="userIDs != null">WHERE USER_ID IN (<foreach collection="userIDs" item="userID" separator=",">#{userID}</foreach>)</if>
<include refid="utility.orderBy"/>
<include refid="utility.paging-suffix" /></sql>
<select id="getUserList" parameterType="map" resultType="dataobject">/* 권한-사용자 가져오기(authorityMapper.getUserList) */
<include refid="selectAuthUser" /></select>
<select id="getUserAuths" parameterType="map" resultType="dataobject">/* 사용자-권한 가져오기(authorityMapper.getUserAuths) */
<include refid="selectAuthUser" /></select>
<insert id="addUsers" parameterType="map">/* 권한-사용자 추가(authorityMapper.addUsers) */
INSERT INTO TB_AUTH_USER (AUTH_ID, USER_ID, REG_DT)
SELECT AUTH_ID, USER_ID,<include refid="utility.now" />
FROM (<foreach collection="userIDs" item="userID" separator="UNION">
SELECT #{authID} AUTH_ID, #{userID} USER_ID FROM DUAL</foreach>
) A
WHERE NOT EXISTS (
SELECT AUTH_ID, USER_ID
FROM TB_AUTH_USER B
WHERE B.AUTH_ID = A.AUTH_ID
AND B.USER_ID = A.USER_ID
)</insert>
<delete id="removeUsers" parameterType="map">/* 권한-사용자 삭제(authorityMapper.removeUsers) */
DELETE FROM TB_AUTH_USER
<where>
<if test="authIDs != null">AND AUTH_ID IN (<foreach collection="authIDs" item="authID" separator=",">#{authID}</foreach>)</if>
<if test="userIDs != null">AND USER_ID IN (<foreach collection="userIDs" item="userID" separator=",">#{userID}</foreach>)</if>
</where>
</delete>
</mapper>

@ -0,0 +1,230 @@
<?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="cokr.xit.base.code.dao.CodeMapper">
<resultMap id="categoryRow" type="cokr.xit.base.code.CodeCategory">
<result property="id" column="CTGR_ID"/>
<result property="name" column="CTGR_NM"/>
<result property="description" column="DSCRP"/>
<result property="createdAt" column="REG_DT"/>
<result property="createdBy" column="RGTR"/>
<result property="lastModified" column="MDFCN_DT"/>
<result property="modifiedBy" column="MDFR"/>
<result property="useYN" column="USE_YN"/>
</resultMap>
<resultMap id="groupRow" type="cokr.xit.base.code.CodeGroup">
<result property="id" column="GRP_ID"/>
<result property="name" column="GRP_NM"/>
<result property="categoryID" column="CTGR_ID"/>
<result property="description" column="DSCRP"/>
<result property="createdAt" column="REG_DT"/>
<result property="createdBy" column="RGTR"/>
<result property="lastModified" column="MDFCN_DT"/>
<result property="modifiedBy" column="MDFR"/>
<result property="useYN" column="USE_YN"/>
</resultMap>
<resultMap id="codeRow" type="cokr.xit.base.code.CommonCode">
<result property="groupID" column="GRP_ID"/>
<result property="code" column="CODE"/>
<result property="value" column="CODE_VAL"/>
<result property="description" column="DSCRP"/>
<result property="etc1" column="ETC_1"/>
<result property="etc2" column="ETC_2"/>
<result property="etc3" column="ETC_3"/>
<result property="sortOrder" column="SRT_ORD"/>
<result property="createdAt" column="REG_DT"/>
<result property="createdBy" column="RGTR"/>
<result property="lastModified" column="MDFCN_DT"/>
<result property="modifiedBy" column="MDFR"/>
<result property="useYN" column="USE_YN"/>
</resultMap>
<sql id="selectCategories"><include refid="utility.paging-prefix" />
SELECT *
FROM TB_CODE_CTGR
WHERE USE_YN = 'Y'
<if test="categoryIDs != null"> AND CTGR_ID IN (<foreach collection="categoryIDs" item="categoryID" separator=",">#{categoryID}</foreach>)</if>
<include refid="utility.orderBy" />
<include refid="utility.paging-suffix" /></sql>
<select id="getCategoryList" parameterType="map" resultType="dataobject">/* 코드 카테고리 목록 조회(codeMapper.getCategoryList) */
<include refid="selectCategories" /></select>
<select id="getCategories" parameterType="map" resultMap="categoryRow">/*코드 카테고리 가져오기(codeMapper.getCategories)*/
<include refid="selectCategories" /></select>
<insert id="insertCategory" parameterType="map">/* 코드 카테고리 등록(codeMapper.insertCategory) */
INSERT INTO TB_CODE_CTGR (
CTGR_ID
, CTGR_NM
, DSCRP
, REG_DT
, RGTR
, MDFCN_DT
, MDFR
, USE_YN
) VALUES (
#{category.id}
, #{category.name}
, #{category.description}
,<include refid="utility.now" />
, #{currentUser.id}
,<include refid="utility.now" />
, #{currentUser.id}
, 'Y'
)</insert>
<update id="updateCategory" parameterType="map">/* 코드 카테고리 수정(codeMapper.updateCategory) */
UPDATE TB_CODE_CTGR SET
CTGR_NM = #{category.name}
, DSCRP = #{category.description}
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
WHERE CTGR_ID = #{category.id}</update>
<delete id="removeCategories" parameterType="map">/* 코드 카테고리 제거(codeMapper.removeCategories) */
UPDATE TB_CODE_CTGR SET
MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
, USE_YN = 'N'
<if test='categoryIDs != null'>WHERE CTGR_ID IN (<foreach collection="categoryIDs" item="categoryID" separator=",">#{categoryID}</foreach>)</if></delete>
<sql id="selectGroups"><include refid="utility.paging-prefix" />
SELECT *
FROM TB_CODE_GRP
WHERE USE_YN = 'Y'
<if test="categoryIDs != null">AND CTGR_ID IN (<foreach collection="categoryIDs" item="categoryID" separator=",">#{categoryID}</foreach>)</if>
<if test="groupIDs != null">AND GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</if>
<include refid="utility.orderBy" />
<include refid="utility.paging-suffix" /></sql>
<select id="getGroupList" parameterType="dataobject" resultType="dataobject">/* 코드그룹 목록 조회(codeMapper.getGroupList) */
<include refid="selectGroups" /></select>
<select id="getGroups" parameterType="map" resultMap="groupRow">/* 코드그룹 가져오기(codeMapper.getGroups) */
<include refid="selectGroups" /></select>
<insert id="insertGroup" parameterType="map">/* 코드그룹 등록(codeMapper.insertGroup) */
INSERT INTO TB_CODE_GRP (
GRP_ID
, GRP_NM
, CTGR_ID
, DSCRP
, REG_DT
, RGTR
, MDFCN_DT
, MDFR
, USE_YN
) VALUES (
#{group.id}
, #{group.name}
, #{group.categoryID}
, #{group.description}
,<include refid="utility.now" />
, #{currentUser.id}
,<include refid="utility.now" />
, #{currentUser.id}
, 'Y'
)</insert>
<update id="updateGroup" parameterType="map">/* 코드그룹 수정(codeMapper.updateGroup) */
UPDATE TB_CODE_GRP SET
GRP_NM = #{group.name}
, CTGR_ID = #{group.categoryID}
, DSCRP = #{group.description}
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
WHERE GRP_ID = #{group.id}</update>
<update id="removeGroups" parameterType="map">/*코드그룹 제거(codeMapper.removeGroups) */
UPDATE TB_CODE_GRP SET
USE_YN = 'N'
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
<where>
<if test="categoryIDs != null">CTGR_ID IN (<foreach collection="categoryIDs" item="categoryID" separator=",">#{categoryID}</foreach>)</if>
<if test="groupIDs != null">GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</if>
</where></update>
<sql id="selectCodes"><include refid="utility.paging-prefix" />
SELECT *
FROM TB_CMN_CODE
WHERE USE_YN = 'Y'
<if test='groupIDs != null'>AND GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</if>
<if test='codes != null'>AND CODE IN (<foreach collection="codes" item="code" separator=",">#{code}</foreach>)</if>
<include refid="utility.orderBy" />
<include refid="utility.paging-suffix" /></sql>
<select id="getCodeList" parameterType="map" resultType="dataobject">/* 그룹별 코드 가져오기(codeMapper.getCodeList) */
<include refid="selectCodes" /></select>
<select id="getCodes" parameterType="map" resultMap="codeRow">/* 코드 가져오기(codeMapper.getCodes) */
<include refid="selectCodes" /></select>
<insert id="insertCode" parameterType="map">/* 코드 등록(codeMapper.insertCode) */
INSERT INTO TB_CMN_CODE (
GRP_ID
, CODE
, CODE_VAL
, DSCRP
, ETC_1
, ETC_2
, ETC_3
, SRT_ORD
, REG_DT
, RGTR
, MDFCN_DT
, MDFR
, USE_YN
) VALUES (
#{code.groupID}
, #{code.code}
, #{code.value}
, #{code.description}
, #{code.etc1}
, #{code.etc2}
, #{code.etc3}
, #{code.sortOrder}
,<include refid="utility.now" />
, #{currentUser.id}
,<include refid="utility.now" />
, #{currentUser.id}
, 'Y'
)</insert>
<update id="updateCode" parameterType="map">/* 코드 수정(codeMapper.updateCode) */
UPDATE TB_CMN_CODE SET
CODE_VAL = #{code.value}
, DSCRP = #{code.description}
, ETC_1 = #{code.etc1}
, ETC_2 = #{code.etc2}
, ETC_3 = #{code.etc3}
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
WHERE GRP_ID = #{code.groupID}
AND CODE = #{code.code}</update>
<update id="reorderCodes" parameterType="map">/* 코드 정렬순서 변경(codeMapper.reorderCodes) */
UPDATE TB_CMN_CODE SET
SRT_ORD = CASE CODE<foreach collection="codes" item="code" index="index" separator=" ">
WHEN #{code} THEN #{index}</foreach>
ELSE SRT_ORD
END
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
WHERE GRP_ID = #{groupID}
AND CODE IN (<foreach collection="codes" item="code" separator=",">#{code}</foreach>)</update>
<update id="removeCodes" parameterType="map">/* 코드 제거(codeMapper.removeCodes) */
UPDATE TB_CMN_CODE SET
MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
, USE_YN = 'N'
<where>
<if test="groupIDs != null">AND GRP_ID IN (<foreach collection="groupIDs" item="groupID" separator=",">#{groupID}</foreach>)</if>
<if test="codes != null">AND CODE IN (<foreach collection="codes" item="code" separator=",">#{code}</foreach>) </if>
</where></update>
</mapper>

@ -0,0 +1,126 @@
<?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="cokr.xit.base.file.dao.FileMapper">
<resultMap id="fileRow" type="cokr.xit.base.file.FileInfo">
<result property="id" column="FILE_ID"/>
<result property="infoType" column="INF_TYPE"/>
<result property="infoKey" column="INF_KEY"/>
<result property="subType" column="SUB_TYPE"/>
<result property="name" column="FILE_NM"/>
<result property="path" column="FILE_PATH"/>
<result property="url" column="URL"/>
<result property="mimeType" column="MIME_TYPE"/>
<result property="size" column="FILE_SIZE"/>
<result property="downloadCount" column="DNLD_CNT"/>
<result property="sortOrder" column="SRT_ORD"/>
<result property="createdAt" column="REG_DT"/>
<result property="createdBy" column="RGTR"/>
<result property="useYN" column="USE_YN"/>
</resultMap>
<sql id="fileDirs">SELECT INF_TYPE
, CONCAT('C://workspace/xit/base/files/', DIR, DATE_FORMAT(CURRENT_DATE, '%Y/%m/%d/')) DIR
FROM (
SELECT '00' INF_TYPE, 'attachment/' DIR UNION
SELECT '01' INF_TYPE, 'document/' DIR UNION
SELECT '02' INF_TYPE, 'article/' DIR
) FILE_DIRS</sql>
<sql id="selectFiles">
<if test="fileIDs != null">
SELECT A.*, REPLACE(FILE_PATH, 'C://workspace/xit/base', '') URL
FROM TB_FILE A
WHERE FILE_ID IN (<foreach collection="fileIDs" item="fileID" separator=",">#{fileID}</foreach>)
ORDER BY FILE_ID</if>
<if test="fileIDs == null"><include refid="utility.paging-prefix" />
SELECT A.*, REPLACE(FILE_PATH, 'C://workspace/xit/base', '') URL
FROM TB_FILE A
<where>
<if test="infoType != null"> AND A.INF_TYPE = #{infoType}</if>
<if test="infoKeys != null"> AND INF_KEY IN (<foreach collection="infoKeys" item="infoKey" separator=",">#{infoKey}</foreach>)</if>
AND USE_YN = 'Y'
</where>
<include refid="utility.orderBy" />
<include refid="utility.paging-suffix" /></if></sql>
<select id="getFileList" parameterType="map" resultType="dataobject">/* 파일 목록 조회(fileMapper.getFileList) */
<include refid="selectFiles" /></select>
<select id="getFilesOf" parameterType="map" resultMap="fileRow">/* 파일 가져오기(fileMapper.getFilesOf) */
<include refid="selectFiles" /></select>
<select id="getFiles" parameterType="map" resultMap="fileRow">/* 파일 가져오기(fileMapper.getFiles) */
<include refid="selectFiles" /></select>
<insert id="insertFile" parameterType="map">/* 파일 등록(fileMapper.insertFile) */
<selectKey keyProperty="file.id,file.path" keyColumn="NEW_ID,PATH" resultType="map" order="BEFORE">
SELECT NEW_ID, CONCAT(DIR, NEW_ID, '.', #{file.extension}) PATH
FROM (
SELECT IFNULL(MAX(FILE_ID) + 1, CONCAT(THIS_DAY, '00001')) NEW_ID
FROM TB_FILE A, (<include refid="utility.selectThisDay" />) B
WHERE FILE_ID LIKE CONCAT(THIS_DAY, '%')
) T1, (
<include refid="fileDirs" />
WHERE INF_TYPE = #{file.infoType}
) T2</selectKey>
INSERT INTO TB_FILE (
FILE_ID
, INF_TYPE
, INF_KEY
, SUB_TYPE
, FILE_NM
, FILE_PATH
, MIME_TYPE
, FILE_SIZE
, DNLD_CNT
, SRT_ORD
, RGTR
, REG_DT
, USE_YN
) VALUES (
#{file.id}
, #{file.infoType}
, #{file.infoKey}
, #{file.subType}
, #{file.name}
, #{file.path}
, #{file.mimeType}
, #{file.size}
, #{file.downloadCount}
, #{file.sortOrder}
, #{currentUser.id}
,<include refid="utility.now" />
, 'Y'
)
</insert>
<update id="reorder" parameterType="map">/* 파일 순서 변경(fileMapper.reorder) */
UPDATE TB_FILE SET
SRT_ORD = CASE FILE_ID
<foreach collection="fileIDs" item="fileID" index="index" separator=" ">WHEN #{fileID} THEN #{index}
</foreach>
ELSE SRT_ORD END
WHERE FILE_ID IN (<foreach collection="fileIDs" item="fileID" separator=",">#{fileID}</foreach>)</update>
<update id="updateDownloadCount" parameterType="map">/* 다운로드 횟수 증가(fileMapper.updateDownloadCount) */
UPDATE TB_FILE SET
DNLD_CNT = DNLD_CNT + 1
WHERE USE_YN = 'Y'
AND FILE_ID IN (<foreach collection="fileIDs" item="fileID" separator=",">#{fileID}</foreach>)</update>
<update id="removeFiles" parameterType="map">/* 파일 제거(fileMapper.removeFiles) */
UPDATE TB_FILE SET
USE_YN = 'N'
WHERE USE_YN = 'Y'
<if test="fileIDs != null"> AND FILE_ID IN (<foreach collection="fileIDs" item="fileID" separator=",">#{fileID}</foreach>)</if>
<if test="infoKeys != null">
AND INF_TYPE = #{infoType}
AND INF_KEY IN (<foreach collection="infoKeys" item="infoKey" separator=",">#{infoKey}</foreach>)</if></update>
<delete id="deleteFiles" parameterType="map">/* 파일 삭제(fileMapper.deleteFiles) */
DELETE FROM TB_FILE
<if test="fileIDs != null">WHERE FILE_ID IN (<foreach collection="fileIDs" item="fileID" separator=",">#{fileID}</foreach>)</if>
</delete>
</mapper>

@ -0,0 +1,94 @@
<?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="cokr.xit.base.menu.dao.MenuMapper">
<resultMap id="menuRow" type="cokr.xit.base.menu.Menu">
<result property="id" column="MENU_NO"/>
<result property="name" column="MENU_NM"/>
<result property="programFilename" column="PGRM_FILE_NM"/>
<result property="action" column="ACTION"/>
<result property="description" column="DSCRP"/>
<result property="parentID" column="PRNT_NO"/>
<result property="imageName" column="IMG_NM"/>
<result property="imageConf" column="IMG_CNF"/>
<result property="sortOrder" column="SRT_ORD"/>
<result property="createdAt" column="REG_DT"/>
<result property="createdBy" column="RGTR"/>
</resultMap>
<sql id="selectMenus">
SELECT A.*
FROM TB_MENU A
<if test='menuID != null'>WHERE MENU_NO = #{menuID}</if>
ORDER BY PRNT_NO, SRT_ORD, MENU_NO</sql>
<select id="getMenus" parameterType="map" resultMap="menuRow">/* 메뉴 정보 조회(menuMapper.getMenus) */
<include refid="selectMenus" /></select>
<select id="getMenu" parameterType="int" resultMap="menuRow">/* 메뉴 가져오기(menuMapper.getMenu) */
<include refid="selectMenus" /></select>
<insert id="insertMenu" parameterType="map">/* 메뉴 등록(menuMapper.insertMenu) */
<selectKey order="BEFORE" resultType="map" keyColumn="NEW_NO,NEW_ORD" keyProperty="menu.id,menu.sortOrder">
SELECT NEW_NO, NEW_ORD
FROM (SELECT IFNULL(MAX(MENU_NO) + 1, 0) NEW_NO FROM TB_MENU) A,
(<include refid="newSortOrder" />) B</selectKey>
INSERT INTO TB_MENU (
MENU_NO
, MENU_NM
, PRNT_NO
, PGRM_FILE_NM
, ACTION
, DSCRP
, IMG_NM
, IMG_CNF
, SRT_ORD
, REG_DT
, RGTR
) VALUES (
#{menu.id}
, #{menu.name}
, #{menu.parentID}
, #{menu.programFilename}
, #{menu.action}
, #{menu.description}
, #{menu.imageName}
, #{menu.imageConf}
, #{menu.sortOrder}
,<include refid="utility.now" />
, #{currentUser.id}
)</insert>
<update id="updateMenu" parameterType="map">/* 메뉴 수정(menuMapper.updateMenu) */
UPDATE TB_MENU SET
MENU_NM = #{menu.name}
, PGRM_FILE_NM = #{menu.programFilename}
, ACTION = #{menu.action}
, DSCRP = #{menu.description}
, IMG_NM = #{menu.imageName}
, IMG_CNF = #{menu.imageConf}
WHERE MENU_NO = #{menu.id}</update>
<sql id="newSortOrder">SELECT IFNULL(MAX(SRT_ORD) + 1, 0) NEW_ORD FROM TB_MENU WHERE PRNT_NO = IFNULL(#{parentID}, IFNULL(#{menu.parentID}, 0))</sql>
<update id="moveMenus" parameterType="map">/* 메뉴 이동(menuMapper.moveMenus) */
UPDATE TB_MENU SET
PRNT_NO = #{parentID}
, SRT_ORD = SRT_ORD + (<include refid="newSortOrder" />)
WHERE MENU_NO IN (<foreach collection="menuIDs" item="menuID" separator=",">#{menuID}</foreach>)
</update>
<update id="reorderMenus" parameterType="map">/* 메뉴 순서 변경(menuMapper.reorderMenus) */
UPDATE TB_MENU SET
SRT_ORD = CASE MENU_NO
<foreach collection="menuIDs" item="menuID" index="index">WHEN #{menuID} THEN #{index}
</foreach>
ELSE MENU_NO END
WHERE MENU_NO IN (<foreach collection="menuIDs" item="menuID" separator=",">#{menuID}</foreach>)</update>
<delete id="removeMenus" parameterType="map">/* 메뉴 제거(menuMapper.removeMenus) */
DELETE FROM TB_MENU
WHERE MENU_NO IN (<foreach collection="menuIDs" item="menuID" separator=",">#{menuID}</foreach>)
</delete>
</mapper>

@ -0,0 +1,70 @@
<?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="cokr.xit.base.security.authentication.dao.PolicyMapper">
<resultMap id="policyRow" type="cokr.xit.base.security.authentication.AuthenticationPolicy">
<result property="userID" column="USER_ID"/>
<result property="ipAddress" column="IP_ADRS"/>
<result property="duplicateYN" column="DPLCT_YN"/>
<result property="limitYN" column="LIMIT_YN"/>
<result property="createdBy" column="RGTR"/>
<result property="createdAt" column="REG_DT"/>
<result property="modifiedBy" column="MDFR"/>
<result property="lastModified" column="MDFCN_DT"/>
</resultMap>
<select id="getPolicyList" parameterType="map" resultType="dataobject">/* 로그인 정책 목록 조회(policyMapper.getPolicyList) */
<include refid="utility.paging-prefix"/>
SELECT A.USER_ID
, USER_NM
, IP_ADRS
, DPLCT_YN
, LIMIT_YN
, MDFR
, MDFCN_DT
FROM TB_USER A LEFT OUTER JOIN TB_LOGIN_POLICY B ON A.USER_ID = B.USER_ID
<if test="term != null">WHERE A.${by} LIKE CONCAT('%', #{term}, '%')</if>
<include refid="utility.orderBy" />
<include refid="utility.paging-suffix"/></select>
<select id="getPolicies" parameterType="map" resultMap="policyRow">/* 로그인 정책 가져오기(policyMapper.getPolicies) */
SELECT *
FROM TB_LOGIN_POLICY
<if test="userIDs != null">WHERE USER_ID IN (<foreach collection="userIDs" item="userID" separator=",">#{userID}</foreach>)</if>
ORDER BY USER_ID</select>
<insert id="insertPolicy" parameterType="map">/* 로그인 정책 등록(policyMapper.insertPolicy) */
INSERT INTO TB_LOGIN_POLICY (
USER_ID
, IP_ADRS
, DPLCT_YN
, LIMIT_YN
, REG_DT
, RGTR
, MDFCN_DT
, MDFR
) VALUES (
#{policy.userID}
, #{policy.ipAddress}
, #{policy.duplicateYN}
, #{policy.limitYN}
,<include refid="utility.now" />
, #{currentUser.id}
,<include refid="utility.now" />
, #{currentUser.id}
)</insert>
<update id="updatePolicy" parameterType="map">/* 로그인 정책 수정(policyMapper.updatePolicy) */
UPDATE TB_LOGIN_POLICY SET
IP_ADRS = #{policy.ipAddress}
, DPLCT_YN = #{policy.duplicateYN}
, LIMIT_YN = #{policy.limitYN}
, MDFR = #{currentUser.id}
, MDFCN_DT =<include refid="utility.now" />
WHERE USER_ID = #{policy.userID}</update>
<delete id="removePolicy" parameterType="map">/* 로그인 정책 삭제(policyMapper.removePolicy) */
DELETE FROM TB_LOGIN_POLICY
WHERE USER_ID IN (<foreach collection="userIDs" item="userID" separator=",">#{userID}</foreach>)</delete>
</mapper>

@ -0,0 +1,135 @@
<?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="program">
<resultMap id="programRow" type="cokr.xit.base.menu.Program">
<result property="filename" column="PGRM_FILE_NM"/>
<result property="location" column="PGRM_FILE_PATH"/>
<result property="name" column="PGRM_NM"/>
<result property="description" column="DSCRP"/>
<result property="url" column="URL"/>
</resultMap>
<resultMap id="reqRow" type="cokr.xit.base.menu.ChangeRequest">
<result property="filename" column="PGRM_FILE_NM"/>
<result property="id" column="REQ_ID"/>
<result property="subject" column="SUBJECT"/>
<result property="requestorID" column="REQ_USER"/>
<result property="requestDate" column="REQ_DT"/>
<result property="requestDetail" column="REQ_CNTNT"/>
<result property="processorID" column="PRSC_USER"/>
<result property="processDate" column="PRCS_DT"/>
<result property="processDetail" column="PRCS_CNTNT"/>
<result property="status" column="PRCS_STATUS"/>
</resultMap>
<sql id="selectPrograms">
<include refid="utility.paging-prefix"/>
SELECT A.*
FROM TB_PROGRAM A
<where>
<if test="by != null and term != null">${by} LIKE CONCAT('%', #{term}, '%')</if>
<if test='filenames != null'>PGRM_FILE_NM IN (<foreach collection="filenames" item="filename" separator=",">#{filename}</foreach>)</if>
</where>
ORDER BY<if test='by != null'>${by}</if><if test='by == null'>PGRM_FILE_NM</if>
<include refid="utility.paging-suffix"/></sql>
<select id="getProgramList" parameterType="map" resultType="dataobject">/* 프로그램 목록 조회(program.getProgramList) */
<include refid="selectPrograms"/></select>
<select id="getPrograms" parameterType="map" resultMap="programRow">/* 프로그램 가져오기(program.getPrograms) */
<include refid="selectPrograms"/></select>
<insert id="insertProgram" parameterType="cokr.xit.base.menu.Program">/* 프로그램 등록(program.insertProgram) */
INSERT INTO TB_PROGRAM (
PGRM_FILE_NM
, PGRM_FILE_PATH
, PGRM_NM
, DSCRP
, URL
) VALUES (
#{filename}
, #{location}
, #{name}
, #{description}
, #{url}
)</insert>
<update id="updateProgram" parameterType="cokr.xit.base.menu.Program">/* 프로그램 수정(program.updateProgram) */
UPDATE TB_PROGRAM SET
PGRM_FILE_PATH = #{location}
, PGRM_NM = #{name}
, DSCRP = #{description}
, URL = #{url}
WHERE PGRM_FILE_NM = #{filename}</update>
<delete id="removePrograms" parameterType="map">/* 프로그램 삭제(program.removePrograms) */
DELETE FROM TB_PROGRAM
WHERE PGRM_FILE_NM IN (<foreach collection="filenames" item="filename" separator=",">#{filename}</foreach>)</delete>
<delete id="clearPrograms" parameterType="map">/* 프로그램 비우기(program.clearPrograms) */
DELETE FROM TB_PROGRAM
WHERE PGRM_FILE_NM NOT IN (SELECT PGRM_FILE_NM FROM TB_MENU)</delete>
<sql id="selectRequests">
SELECT A.*
FROM TB_PGRM_CHNG_REQ A
<where>
<if test='fromReqDate != null'>REQ_DT >= #{fromReqDate}</if>
<if test='toReqDate != null'>REQ_DT &lt;= #{toReqDate}</if>
<if test="by != null and term != null">${by} LIKE CONCAT('%', #{term}, '%')</if>
<if test='filenames != null'>PGRM_FILE_NAME IN (<foreach collection="filenames" item="filename" separator=",">#{filename}</foreach>)</if>
<if test='reqIDs != null'>REQ_ID IN (<foreach collection="reqIDs" item="reqID" separator=",">#{reqID}</foreach>)</if>
</where>
ORDER BY PGRM_FILE_NM,<if test='by != null'>${by}</if><if test='by == null'>REQ_ID DESC</if></sql>
<select id="getRequestList" parameterType="map" resultType="dataobject">/* 변경요청 목록 조회(program.getRequestList) */
<include refid="selectRequests" /></select>
<select id="getRequests" parameterType="map" resultType="dataobject">/* 프로그램별 변경요청 목록 조회(program.getRequests) */
<include refid="selectRequests" /></select>
<insert id="insertRequest" parameterType="cokr.xit.base.menu.ChangeRequest">/* 프로그램 변경요청 등록(program.insertRequest) */
INSERT INTO TB_PGRM_CHNG_REQ (
PGRM_FILE_NM
, REQ_ID
, SUBJECT
, REQ_USER
, REQ_DT
, REQ_CNTNT
, PRSC_USER
, PRCS_DT
, PRCS_CNTNT
, PRCS_STATUS
) VALUES (
#{filename}
, #{id}
, #{subject}
, #{requestorID}
, #{requestDate}
, #{requestDetail}
, #{processorID}
, #{processDate}
, #{processDetail}
, #{status}
)</insert>
<update id="updateRequest" parameterType="cokr.xit.base.menu.ChangeRequest">/* 프로그램 변경요청 수정(program.updateRequest) */
UPDATE TB_PGRM_CHNG_REQ SET
SUBJECT = #{subject}
, REQ_USER = #{requestorID}
, REQ_DT = #{requestDate}
, REQ_CNTNT = #{requestDetail}
, PRSC_USER = #{processorID}
, PRCS_DT = #{processDate}
, PRCS_CNTNT = #{processDetail}
WHERE PGRM_FILE_NM = #{filename}
AND REQ_ID = #{id}</update>
<update id="setRequestStatus" parameterType="map">/* 프로그램 변경요청 상태 변경(program.setRequestStatus) */
UPDATE TB_PGRM_CHNG_REQ SET
PRCS_STATUS = #{status}
WHERE PGRM_FILE_NM = #{filename}
AND REQ_ID = #{id}</update>
</mapper>

@ -0,0 +1,13 @@
<?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="cokr.xit.foundation.test.TestMapper">
<insert id="insert" parameterType="map">${sql}</insert>
<update id="update" parameterType="map">${sql}</update>
<delete id="delete" parameterType="map">${sql}</delete>
<update id="commit">COMMIT</update>
</mapper>

@ -0,0 +1,221 @@
<?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="cokr.xit.base.user.dao.UserMapper">
<resultMap id="userRow" type="cokr.xit.base.user.ManagedUser">
<result property="id" column="USER_ID"/>
<result property="account" column="USER_ACNT"/>
<result property="name" column="USER_NM"/>
<result property="password" column="PASSWD"/>
<result property="passwordHint" column="PASSWD_HINT"/>
<result property="passwordHintAnswer" column="PASSWD_NSR"/>
<result property="empNo" column="EMP_NO"/>
<result property="residentRegNo" column="RSDNT_NO"/>
<result property="gender" column="GENDER"/>
<result property="birthday" column="BRDT"/>
<result property="areaNo" column="AREA_NO"/>
<result property="zipCode" column="ZIP"/>
<result property="address" column="ADDR"/>
<result property="addressDetail" column="DADDR"/>
<result property="phoneNo" column="TELNO"/>
<result property="mobilePhoneNo" column="MBL_TELNO"/>
<result property="faxNo" column="FXNO"/>
<result property="emailAddress" column="EML_ADRS"/>
<result property="positionName" column="POS_NM"/>
<result property="groupID" column="GRP_ID"/>
<result property="orgID" column="ORG_ID"/>
<result property="deptCode" column="DEPT_CD"/>
<result property="institute" column="NSTT_CD"/>
<result property="certificateDn" column="CRTFC_DN"/>
<result property="locked" column="LOCK_YN"/>
<result property="lockCount" column="LOCK_CNT"/>
<result property="lockedDate" column="LOCK_DT"/>
<result property="createdAt" column="REG_DT"/>
<result property="createdBy" column="RGTR"/>
<result property="lastModified" column="MDFCN_DT"/>
<result property="modifiedBy" column="MDFR"/>
<result property="useYN" column="USE_YN"/>
<result property="status" column="STTS"/>
</resultMap>
<sql id="selectUsers"><include refid="utility.paging-prefix" />
SELECT USER_ID
, USER_ACNT
, USER_NM
, PASSWD_HINT
, PASSWD_NSR
, EMP_NO
, RSDNT_NO
, GENDER
, BRDT
, AREA_NO
, ZIP
, ADDR
, DADDR
, TELNO
, MBL_TELNO
, FXNO
, EML_ADRS
, POS_NM
, GRP_ID
, ORG_ID
, DEPT_CD
, NSTT_CD
, CRTFC_DN
, LOCK_YN
, LOCK_CNT
, LOCK_DT
, REG_DT
, STTS
FROM TB_USER
<where><if test="by != null and term != null">AND ${by} LIKE CONCAT('%', #{term}, '%')</if>
<if test="userIDs != null">USER_ID IN (<foreach collection="userIDs" item="userID" separator=",">#{userID}</foreach>)</if>
<if test="status == null and userIDs == null">AND STTS != 'D'</if>
<if test="status != null">AND STTS = #{status}</if></where>
<include refid="utility.orderBy" />
<include refid="utility.paging-suffix" /></sql>
<select id="getUserList" parameterType="map" resultType="dataobject">/* 사용자 목록 조회(userMapper.getUserList) */
<include refid="selectUsers"/></select>
<select id="getUsers" parameterType="map" resultMap="userRow">/* 사용자 가져오기(userMapper.getUsers) */
<include refid="selectUsers"/></select>
<select id="getUser" parameterType="map" resultMap="userRow">/* 사용자 계정 가져오기(userMapper.getUser) */
SELECT *
FROM TB_USER
WHERE USER_ACNT = #{account}
AND NSTT_CD = #{institute}</select>
<insert id="insertUser" parameterType="cokr.xit.base.user.ManagedUser">
<selectKey resultType="string" keyProperty="id" keyColumn="NEW_ID" order="BEFORE">SELECT LPAD(IFNULL(MAX(USER_ID) + 1, 1), 10, '0') NEW_ID FROM TB_USER</selectKey>
/* 사용자 정보 등록(userMapper.insertUser) */
INSERT INTO TB_USER (
USER_ID
, USER_ACNT
, USER_NM
, PASSWD
, PASSWD_HINT
, PASSWD_NSR
, EMP_NO
, RSDNT_NO
, GENDER
, BRDT
, AREA_NO
, ZIP
, ADDR
, DADDR
, TELNO
, MBL_TELNO
, FXNO
, EML_ADRS
, POS_NM
, GRP_ID
, ORG_ID
, NSTT_CD
, CRTFC_DN
, LOCK_YN
, LOCK_CNT
, LOCK_DT
, REG_DT
, RGTR
, MDFCN_DT
, MDFR
, USE_YN
, STTS
) VALUES (
#{id}
, #{account}
, #{name}
, #{password}
, #{passwordHint}
, #{passwordHintAnswer}
, #{empNo}
, #{residentRegNo}
, #{gender}
, #{birthday}
, #{areaNo}
, #{zipCode}
, #{address}
, #{addressDetail}
, #{phoneNo}
, #{mobilePhoneNo}
, #{faxNo}
, #{emailAddress}
, #{positionName}
, #{groupID}
, #{orgID}
, #{institute}
, #{certificateDn}
, 'N'
, 0
, NULL
,<include refid="utility.now" />
, #{createdBy}
,<include refid="utility.now" />
, #{createdBy}
, 'Y'
, #{status}
)</insert>
<update id="updateUser" parameterType="cokr.xit.base.user.ManagedUser">/* 사용자 정보 수정(userMapper.updateUser) */
UPDATE TB_USER SET
USER_NM = #{name}
, PASSWD_HINT = #{passwordHint}
, PASSWD_NSR = #{passwordHintAnswer}
, EMP_NO = #{empNo}
, RSDNT_NO = #{residentRegNo}
, GENDER = #{gender}
, BRDT = #{birthday}
, AREA_NO = #{areaNo}
, ZIP = #{zipCode}
, ADDR = #{address}
, DADDR = #{addressDetail}
, TELNO = #{phoneNo}
, MBL_TELNO = #{mobilePhoneNo}
, FXNO = #{faxNo}
, EML_ADRS = #{emailAddress}
, POS_NM = #{positionName}
, GRP_ID = #{groupID}
, ORG_ID = #{orgID}
, NSTT_CD = #{institute}
, CRTFC_DN = #{certificateDn}
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{modifiedBy}
WHERE USER_ID = #{id}</update>
<update id="changePassword" parameterType="map">/* 비밀번호 변경(userMapper.changePassword) */
UPDATE TB_USER SET
PASSWD = CASE USER_ID<foreach collection="userPasswords" item="userPassword" separator=" ">
WHEN #{userPassword.userID} THEN #{userPassword.password}</foreach>
ELSE PASSWD END
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
WHERE USER_ID IN (<foreach collection="userIDs" item="userID" separator=",">#{userID}</foreach>)
</update>
<update id="lockUsers" parameterType="map">/* 사용자 잠김 해제(userMapper.lockUsers) */
UPDATE TB_USER SET
<if test='lock == true'> LOCK_YN = 'Y'
, LOCK_CNT = LOCK_CNT + 1
, LOCK_DT =<include refid="utility.now" /></if>
<if test='lock == false'> LOCK_YN = 'N'
, LOCK_CNT = 0
, LOCK_DT = NULL</if>
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
WHERE USER_ID IN (<foreach collection="userIDs" item="userID" separator=",">#{userID}</foreach>)
</update>
<update id="setStatus" parameterType="map">/* 사용자 상태 변경(userMapper.setStatus) */
UPDATE TB_USER SET
STTS = #{status}
<if test='"D" == status'>, USE_YN = 'N'</if>
, MDFCN_DT =<include refid="utility.now" />
, MDFR = #{currentUser.id}
WHERE USER_ID IN (<foreach collection="userIDs" item="userID" separator=",">#{userID}</foreach>)
AND STTS != #{status}
</update>
</mapper>

@ -3,30 +3,26 @@
<mapper namespace="utility">
<!-- For Maria DB -->
<sql id="paging-prefix">
<if test="fetchSize != null and fetchSize &gt; 0">
<sql id="paging-prefix"><if test="fetchSize != null and fetchSize &gt; 0">
SELECT QROWS.* FROM (
SELECT ROW_NUMBER() OVER(<include refid="utility.sortBy" />) ROW_NUM
, COUNT(*) OVER() TOT_CNT, QBODY.*
FROM (</if>
</sql>
FROM (</if></sql>
<sql id="paging-suffix">
<if test="fetchSize != null and fetchSize &gt; 0"> ) QBODY
<sql id="paging-suffix"><if test="fetchSize != null and fetchSize &gt; 0"> ) QBODY
) QROWS
WHERE ROW_NUM BETWEEN ((#{pageNum} - 1) * #{fetchSize}) + 1 AND (#{pageNum} * #{fetchSize})
</if>
</sql>
WHERE ROW_NUM BETWEEN ((#{pageNum} - 1) * #{fetchSize}) + 1 AND (#{pageNum} * #{fetchSize})</if></sql>
<select id="foundRows" resultType="dataobject">/* 전체 결과수 가져오기(utility.foundRows) */
SELECT FOUND_ROWS() TOT_CNT
</select>
SELECT FOUND_ROWS() TOT_CNT</select>
<sql id="sortBy"><if test="orderBy != null and orderBy != ''">ORDER BY ${orderBy}</if></sql>
<sql id="orderBy"><if test="fetchSize == null or fetchSize &lt; 1"><include refid="utility.sortBy" /></if></sql>
<sql id="thisDay">IFNULL(#{thisDay}, TO_CHAR(CURRENT_DATE, 'YYYYMMDD'))</sql>
<sql id="now">DATE_FORMAT(CURRENT_TIMESTAMP(), '%Y%m%d%H%i%s')</sql>
<sql id="thisDay">IFNULL(#{thisDay}, DATE_FORMAT(CURRENT_DATE, '%Y%m%d'))</sql>
<sql id="selectThisDay">SELECT<include refid="utility.thisDay" />THIS_DAY</sql>

@ -0,0 +1,80 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<form id="infoPrefix-form">
<div class="row g-3">
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="id"
>아이디</label
>
<div class="col-sm-10">
<input name="id" type="text" required data-map="GRP_ID" maxlength="50" class="form-control" placeholder="prefixName 아이디" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="name"
>이름</label
>
<div class="col-sm-10">
<input name="name" type="text" required data-map="GRP_NM" maxlength="60" class="form-control" placeholder="prefixName 이름" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>설명</label
>
<div class="col-sm-10">
<input name="description" type="text" data-map="DSCRP" maxlength="200" class="form-control dob-picker" placeholder="prefixName 설명"/>
</div>
</div>
</div>
<div class="row mt-4 justify-content-end">
<div class="col-sm-12" style="text-align:right;">
<button onclick="saveinfoPrefix();" type="button" class="btn btn-primary">저장</button>
</div>
</div>
</form>
<script type="text/javascript">
var infoPrefixFields = new FormFields("#infoPrefix-form");
infoPrefixControl.groups.setInfo = obj => {
infoPrefixFields.set(obj);
let create = isEmpty(obj.data.GRP_ID);
$("input[name='id']").prop("readonly", !create);
$("#infoPrefix-form input")
.change(function() {
let input = $(this),
name = input.attr("data-map"),
val = input.val();
infoPrefixControl.groups.setValue(name, val);
})
.onEnterPress(saveinfoPrefix);
document.querySelector("input[name='" + (create ? "id" : "name") + "']").focus();
}
infoPrefixControl.groups.onModify = (changed) => {
if (["GRP_NM"].filter(e => changed.includes(e)).length < 1)
return;
renderinfoPrefixList();
infoPrefixControl.groups.dataset.setState();
}
function saveinfoPrefix() {
if (!$("#infoPrefix-form input").validInputs()) return;
dialog.alert({
content:"현재 prefixName 정보를 저장하시겠습니까?",
onOK:() => {
infoPrefixControl.groups.save(infoPrefixFields.get());
}
});
}
//# sourceURL=actionGroup-info.jsp
</script>

@ -0,0 +1,264 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<jsp:include page="/WEB-INF/jsp/include/head.jsp" />
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<jsp:include page="/WEB-INF/jsp/include/userMenus.jsp" />
<!-- Layout container -->
<!-- Layout page -->
<div class="layout-page">
<jsp:include page="/WEB-INF/jsp/include/top.jsp" />
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<%--h4 id="pageTitle" class="fw-bold py-3 mb-4">페이지 제목</h4--%>
<c:set var="prefixName" scope="request">기능 그룹</c:set>
<!-- Page Body -->
<div class="card">
<div class="card-datatable text-nowrap">
<div id="DataTables_Table_0_wrapper" class="dataTables_wrapper dt-bootstrap5 no-footer">
<div class="d-flex flex-row justify-content-evenly">
<div style="width:49%;">
<h5 class="mt-3">기능 그룹</h5>
<div class="d-flex flex-row justify-content-between p-3">
<div>
<div class="input-group" id="DataTables_Table_0_length">
<select id="by" onchange="document.getElementById('term').focus();" aria-controls="DataTables_Table_0" class="form-select">
<option value="${infoPrefix}Name">이름</option>
<option value="${infoPrefix}ID">아이디</option>
</select>
<input id="term" autofocus type="text" placeholder="조회 조건을 입력하십시오." class="form-control">
</div>
</div>
<div>
<button onclick="search${infoPrefix}s();" class="btn btn-primary">찾기</button>
<button onclick="${infoPrefix}Control.groups.newInfo();" class="btn btn-primary">+ 추가</button>
<button id="btnRemove${infoPrefix}s" onclick="remove${infoPrefix}s();" class="btn btn-primary">- 제거</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input onchange="${infoPrefix}Control.groups.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting sorting_asc" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Full name: activate to sort column descending" style="">아이디</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending" style="">이름</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="">등록일자</th>
</tr>
</thead>
<tbody id="${infoPrefix}List">
</tbody>
<template id="${infoPrefix}Row">
<tr data-key="{GRP_ID}">
<td style="text-align:center;"><input value="{GRP_ID}" onchange="${infoPrefix}Control.groups.select('{GRP_ID}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="${infoPrefix}Control.groups.setCurrent('{GRP_ID}')" ondblclick="${infoPrefix}Control.groups.getInfo({})">{GRP_ID}</td>
<td onclick="${infoPrefix}Control.groups.setCurrent('{GRP_ID}')" ondblclick="${infoPrefix}Control.groups.getInfo({})">{GRP_NM}</td>
<td onclick="${infoPrefix}Control.groups.setCurrent('{GRP_ID}')" ondblclick="${infoPrefix}Control.groups.getInfo({})">{REG_DT}</td>
</tr>
</template>
<template id="${infoPrefix}NotFound">
<tr class="odd">
<td valign="top" colspan="4" class="dataTables_empty text-center">${prefixName} 정보를 찾지 못했습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="${infoPrefix}PagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="${infoPrefix}Paging" class="pagination pagination-primary">
</ul>
</div>
</div>
<div style="width:49%;">
<h5 class="mt-3">기능 URL</h5>
<div class="d-flex flex-row justify-content-end p-3">
<div>
<button id="btnAddActions" onclick="${infoPrefix}Control.addActions();" class="btn btn-primary">+ 추가</button>
<button id="btnRemoveActions" onclick="removeActions();" class="btn btn-primary">- 제거</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input id="actionToggler" onchange="${infoPrefix}Control.actions.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending" style="">기능 URL</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="">등록일자</th>
</tr>
</thead>
<tbody id="actionList">
</tbody>
<template id="actionRow">
<tr data-key="{GRP_ID}-{ACTION}">
<td style="text-align:center;"><input value="{GRP_ID}-{ACTION}" onchange="${infoPrefix}Control.actions.select('{GRP_ID}-{ACTION}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="${infoPrefix}Control.actions.setCurrent('{GRP_ID}-{ACTION}')">{ACTION}</td>
<td onclick="${infoPrefix}Control.actions.setCurrent('{GRP_ID}-{ACTION}">{REG_DT}</td>
</tr>
</template>
<template id="actionNotFound">
<tr class="odd">
<td valign="top" colspan="3" class="dataTables_empty text-center">기능 URL 정보를 찾지 못했습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="actionPagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="actionPaging" class="pagination pagination-primary">
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ Page Body -->
<hr class="my-5" />
</div>
<!-- / Content -->
<jsp:include page="/WEB-INF/jsp/include/bottom.jsp" />
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
</div>
<!-- / Layout wrapper -->
<jsp:include page="/WEB-INF/jsp/include/tail.jsp" />
<script src="<c:url value="/resources/js/base/actionGroup.js"/>" type="text/javascript"></script>
<script >
${functions}
${userMenus}
let ${infoPrefix}Control = new ActionGroupControl();
function search${infoPrefix}s() {
${infoPrefix}Control.groups.query = {
by:$("#by").val(),
term:$("#term").val()
};
${infoPrefix}Control.groups.load(1);
}
function remove${infoPrefix}s() {
dialog.alert({
content:"선택한 ${prefixName} 정보를 제거하시겠습니까?",
onOK:() => {
${infoPrefix}Control.groups.remove();
}
});
}
function removeActions() {
dialog.alert({
content:"선택한 기능 URL을 삭제하시겠습니까?",
onOK:() => {
${infoPrefix}Control.removeActions();
}
});
}
function render${infoPrefix}List() {
let ${infoPrefix}List = ${infoPrefix}Control.groups.dataset;
let empty = ${infoPrefix}List.empty;
let trs = empty ?
[document.getElementById("${infoPrefix}NotFound").innerHTML] : <%-- from template#${infoPrefix}NotFound --%>
${infoPrefix}List.inStrings(document.getElementById("${infoPrefix}Row").innerHTML); <%-- from template#${infoPrefix}Row --%>
$("#${infoPrefix}List").html(trs.join());
$("th input[type='checkbox']").prop("checked", false);
}
${infoPrefix}Control.onGroupListChange = obj => {
render${infoPrefix}List();
$("#${infoPrefix}Paging").setPaging({
list:${infoPrefix}Control.groups.dataset,
prefix:${infoPrefix}Control.groups.prefix,
start:obj.${infoPrefix}Start,
totalSize:obj.${infoPrefix}Total,
fetchSize:obj.${infoPrefix}Fetch,
func:"${infoPrefix}Control.groups.load({index})"
});
};
${infoPrefix}Control.onCurrentGroupChange = item => {
$("#btnAddActions").prop("disabled", !item);
if (!item) return;
let key = item.data.GRP_ID;
$("#${infoPrefix}List").setCurrentRow(key);
};
${infoPrefix}Control.onGroupSelect = selected => {
let ${infoPrefix}List = ${infoPrefix}Control.groups.dataset;
let keys = selected.map(e => ${infoPrefix}List.getKey(e));
$("#${infoPrefix}List input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
$("#btnRemove${infoPrefix}s").prop("disabled", keys.length < 1);
};
${infoPrefix}Control.onActionListChange = obj => {
let ${infoPrefix}List = ${infoPrefix}Control.actions.dataset;
let empty = ${infoPrefix}List.empty;
let trs = empty ?
[document.getElementById("actionNotFound").innerHTML] : <%-- from template#${infoPrefix}NotFound --%>
${infoPrefix}List.inStrings(document.getElementById("actionRow").innerHTML); <%-- from template#${infoPrefix}Row --%>
$("#actionList").html(trs.join());
$("#actionToggler").prop("checked", false);
$("#actionPaging").setPaging({
list:${infoPrefix}Control.actions.dataset,
prefix:${infoPrefix}Control.actions.prefix,
start:obj.actionStart,
totalSize:obj.actionTotal,
fetchSize:obj.actionFetch,
func:"${infoPrefix}Control.actions.load({index})"
});
};
${infoPrefix}Control.onCurrentActionChange = item => {
if (!item) return;
let data = item.data;
let key = data.GRP_ID + "-" + data.ACTION;
$("#actionList").setCurrentRow(key);
};
${infoPrefix}Control.onActionSelect = selected => {
let ${infoPrefix}List = ${infoPrefix}Control.actions.dataset;
let keys = selected.map(e => ${infoPrefix}List.getKey(e));
$("#actionList input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
$("#btnRemoveActions").prop("disabled", keys.length < 1);
};
$("#term").onEnterPress(search${infoPrefix}s);
$(function(){
${onload}
${infoPrefix}Control.groups.setData({
${infoPrefix}List:${groupList},
${infoPrefix}Start:${groupStart},
${infoPrefix}Fetch:${groupFetch},
${infoPrefix}Total:${groupTotal}
});
});
</script>
</body>
</html>

@ -0,0 +1,121 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<c:set var="prefixName" scope="request">기능 그룹</c:set>
<!-- Page Body -->
<div class="card">
<div class="card-datatable text-nowrap">
<div id="DataTables_Table_0_wrapper" class="dataTables_wrapper dt-bootstrap5 no-footer">
<div class="d-flex flex-row justify-content-between p-3">
<div>
<div class="input-group" id="DataTables_Table_0_length">
<select id="_groupBy" onchange="document.getElementById('_groupTerm').focus();" aria-controls="DataTables_Table_0" class="form-select">
<option value="${infoPrefix}Name">이름</option>
<option value="${infoPrefix}ID">아이디</option>
</select>
<input id="_groupTerm" autofocus type="text" placeholder="조회 조건을 입력하십시오." class="form-control">
</div>
</div>
<div>
<button onclick="search${infoPrefix}s();" class="btn btn-primary">찾기</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input onchange="${infoPrefix}Control.groups.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting sorting_asc" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Full name: activate to sort column descending" style="">아이디</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending" style="">이름</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="">등록일자</th>
</tr>
</thead>
<tbody id="${infoPrefix}List">
</tbody>
<template id="${infoPrefix}Row">
<tr data-key="{GRP_ID}">
<td style="text-align:center;"><input value="{GRP_ID}" onchange="${infoPrefix}Control.groups.select('{GRP_ID}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="${infoPrefix}Control.groups.setCurrent('{GRP_ID}')" ondblclick="${infoPrefix}Control.groups.getInfo({})">{GRP_ID}</td>
<td onclick="${infoPrefix}Control.groups.setCurrent('{GRP_ID}')" ondblclick="${infoPrefix}Control.groups.getInfo({})">{GRP_NM}</td>
<td onclick="${infoPrefix}Control.groups.setCurrent('{GRP_ID}')" ondblclick="${infoPrefix}Control.groups.getInfo({})">{REG_DT}</td>
</tr>
</template>
<template id="${infoPrefix}NotFound">
<tr class="odd">
<td valign="top" colspan="4" class="dataTables_empty text-center">${prefixName} 정보를 찾지 못했습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="${infoPrefix}PagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="${infoPrefix}Paging" class="pagination pagination-primary">
</ul>
</div>
</div>
</div>
</div>
<!--/ Page Body -->
<script >
var ${infoPrefix}Control = new ActionGroupControl(false);
function getSelectedActionGroup() {
let selected = ${infoPrefix}Control.groups.dataset.getKeys("selected");
if (selected.length < 1)
return dialog.alert("기능그룹을 선택하십시오.");
else
return selected;
}
function search${infoPrefix}s() {
${infoPrefix}Control.groups.query = {
by:$("#_groupBy").val(),
term:$("#_groupTerm").val()
};
${infoPrefix}Control.groups.load(1);
}
${infoPrefix}Control.onGroupListChange = obj => {
let ${infoPrefix}List = ${infoPrefix}Control.groups.dataset;
let empty = ${infoPrefix}List.empty;
let trs = empty ?
[document.getElementById("${infoPrefix}NotFound").innerHTML] : <%-- from template#${infoPrefix}NotFound --%>
${infoPrefix}List.inStrings(document.getElementById("${infoPrefix}Row").innerHTML); <%-- from template#${infoPrefix}Row --%>
$("#${infoPrefix}List").html(trs.join());
$("th input[type='checkbox']").prop("checked", false);
$("#${infoPrefix}Paging").setPaging({
list:${infoPrefix}Control.groups.dataset,
prefix:${infoPrefix}Control.groups.prefix,
start:obj.${infoPrefix}Start,
totalSize:obj.${infoPrefix}Total,
fetchSize:obj.${infoPrefix}Fetch,
func:"${infoPrefix}Control.groups.load({index})"
});
};
${infoPrefix}Control.onCurrentGroupChange = item => {
if (!item) return;
let key = item.data.GRP_ID;
$("#${infoPrefix}List").setCurrentRow(key);
};
${infoPrefix}Control.onGroupSelect = selected => {
let ${infoPrefix}List = ${infoPrefix}Control.groups.dataset;
let keys = selected.map(e => ${infoPrefix}List.getKey(e));
$("#${infoPrefix}List input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
};
$("#_groupTerm").onEnterPress(search${infoPrefix}s);
$(function(){
${onload}
${infoPrefix}Control.groups.setData({
${infoPrefix}List:${groupList},
${infoPrefix}Start:${groupStart},
${infoPrefix}Fetch:${groupFetch},
${infoPrefix}Total:${groupTotal}
});
});
</script>

@ -0,0 +1,91 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<div class="d-flex flex-row justify-content-end p-3">
<div>
<button id="btnAddActions" onclick="${infoPrefix}Control.addActions();" class="btn btn-primary">+ 추가</button>
<button id="btnRemoveActions" onclick="removeActions();" class="btn btn-primary">- 제거</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input id="actionToggler" onchange="${infoPrefix}Control.actions.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending" style="">기능 그룹</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="">등록일자</th>
</tr>
</thead>
<tbody id="actionList">
</tbody>
<template id="actionRow">
<tr data-key="{AUTH_ID}-{GRP_ID}">
<td style="text-align:center;"><input value="{AUTH_ID}-{GRP_ID}" onchange="${infoPrefix}Control.actions.select('{AUTH_ID}-{GRP_ID}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="${infoPrefix}Control.actions.setCurrent('{AUTH_ID}-{GRP_ID}')">{GRP_ID}</td>
<td onclick="${infoPrefix}Control.actions.setCurrent('{AUTH_ID}-{GRP_ID}">{REG_DT}</td>
</tr>
</template>
<template id="actionNotFound">
<tr class="odd">
<td valign="top" colspan="3" class="dataTables_empty text-center">기능 그룹 정보를 찾지 못했습니다.</td>
</tr>
</template>
<template id="adminActions">
<tr class="odd">
<td valign="top" colspan="3" class="dataTables_empty text-center">{authority}는 모든 기능을 사용할 수 있습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="actionPagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="actionPaging" class="pagination pagination-primary">
</ul>
</div>
<c:set var="actionGroupFunc" scope="request">function removeActions() {
dialog.alert({
content:"선택한 기능그룹을 삭제하시겠습니까?",
onOK:() => {
${infoPrefix}Control.removeActions();
}
});
}
${infoPrefix}Control.onActionListChange = obj => {
let authority = ${infoPrefix}Control.authorities.getCurrent();
authority = authority ? authority.AUTH_NM : "";
let ${infoPrefix}List = ${infoPrefix}Control.actions.dataset;
let empty = ${infoPrefix}List.empty;
let trs =
${infoPrefix}Control.authorities.isAdmin() ? [document.getElementById("adminActions").innerHTML.replace(/{authority}/, authority)] :
empty ?
[document.getElementById("actionNotFound").innerHTML] : <%-- from template#${infoPrefix}NotFound --%>
${infoPrefix}List.inStrings(document.getElementById("actionRow").innerHTML); <%-- from template#${infoPrefix}Row --%>
$("#actionList").html(trs.join());
$("#actionToggler").prop("checked", false);
$("#actionPaging").setPaging({
list:${infoPrefix}Control.actions.dataset,
prefix:${infoPrefix}Control.actions.prefix,
start:obj.actionStart,
totalSize:obj.actionTotal,
fetchSize:obj.actionFetch,
func:"${infoPrefix}Control.actions.load({index})"
});
};
${infoPrefix}Control.onCurrentActionChange = item => {
if (!item) return;
let data = item.data;
let key = data.AUTH_ID + "-" + data.GRP_ID;
$("#actionList").setCurrentRow(key);
};
${infoPrefix}Control.onActionSelect = selected => {
let ${infoPrefix}List = ${infoPrefix}Control.actions.dataset;
let keys = selected.map(e => ${infoPrefix}List.getKey(e));
$("#actionList input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
$("#btnRemoveActions").prop("disabled", keys.length < 1);
};</c:set>

@ -0,0 +1,82 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<form id="infoPrefix-form">
<div class="row g-3">
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="id"
>아이디</label
>
<div class="col-sm-10">
<input name="id" type="text" required data-map="AUTH_ID" maxlength="50" class="form-control" placeholder="prefixName 아이디" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="name"
>이름</label
>
<div class="col-sm-10">
<input name="name" type="text" required data-map="AUTH_NM" maxlength="60" class="form-control" placeholder="prefixName 이름" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>설명</label
>
<div class="col-sm-10">
<input name="description" type="text" data-map="DSCRP" maxlength="200" class="form-control dob-picker" placeholder="prefixName 설명"/>
</div>
</div>
</div>
<div class="row mt-4 justify-content-end">
<div class="col-sm-12" style="text-align:right;">
<button id="btnSaveAuth" onclick="saveinfoPrefix();" type="button" class="btn btn-primary">저장</button>
</div>
</div>
</form>
<script type="text/javascript">
var infoPrefixFields = new FormFields("#infoPrefix-form");
infoPrefixControl.authorities.setInfo = obj => {
infoPrefixFields.set(obj);
let info = obj.data;
let create = isEmpty(info.AUTH_ID);
$("input[name='id']").prop("readonly", !create);
$("#infoPrefix-form input")
.change(function() {
let input = $(this),
name = input.attr("data-map"),
val = input.val();
infoPrefixControl.authorities.setValue(name, val);
})
.onEnterPress(saveinfoPrefix);
$("input[name='" + (create ? "id" : "name") + "']").focus();
$("#btnSaveAuth").prop("disabled", infoPrefixControl.authorities.isBuiltIn(info));
}
infoPrefixControl.authorities.onModify = (changed) => {
if (["AUTH_NM"].filter(e => changed.includes(e)).length < 1)
return;
renderinfoPrefixList();
infoPrefixControl.authorities.dataset.setState();
}
function saveinfoPrefix() {
if (!$("#infoPrefix-form input").validInputs()) return;
dialog.alert({
content:"현재 prefixName 정보를 저장하시겠습니까?",
onOK:() => {
infoPrefixControl.authorities.save(infoPrefixFields.get());
}
});
}
//# sourceURL=actionGroup-info.jsp
</script>

@ -0,0 +1,207 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<jsp:include page="/WEB-INF/jsp/include/head.jsp" />
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<jsp:include page="/WEB-INF/jsp/include/userMenus.jsp" />
<!-- Layout container -->
<!-- Layout page -->
<div class="layout-page">
<jsp:include page="/WEB-INF/jsp/include/top.jsp" />
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<%--h4 id="pageTitle" class="fw-bold py-3 mb-4">페이지 제목</h4--%>
<c:set var="prefixName" scope="request">권한</c:set>
<!-- Page Body -->
<div class="card">
<div class="card-datatable text-nowrap">
<div id="DataTables_Table_0_wrapper" class="dataTables_wrapper dt-bootstrap5 no-footer">
<div class="d-flex flex-row justify-content-evenly">
<div style="width:49%;">
<h5 class="mt-3">권한</h5>
<div class="d-flex flex-row justify-content-between p-3">
<div>
<div class="input-group" id="DataTables_Table_0_length">
<select id="by" onchange="document.getElementById('term').focus();" aria-controls="DataTables_Table_0" class="form-select">
<option value="authName">이름</option>
<option value="authID">아이디</option>
</select>
<input id="term" autofocus type="text" placeholder="조회 조건을 입력하십시오." class="form-control">
</div>
</div>
<div>
<button onclick="search${infoPrefix}s();" class="btn btn-primary">찾기</button>
<button onclick="${infoPrefix}Control.authorities.newInfo();" class="btn btn-primary">+ 추가</button>
<button id="btnRemove${infoPrefix}s" onclick="remove${infoPrefix}s();" class="btn btn-primary">- 제거</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input onchange="${infoPrefix}Control.authorities.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting sorting_asc" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Full name: activate to sort column descending" style="">아이디</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending" style="">이름</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="">등록일자</th>
</tr>
</thead>
<tbody id="${infoPrefix}List">
</tbody>
<template id="${infoPrefix}Row">
<tr data-key="{AUTH_ID}">
<td style="text-align:center;"><input value="{AUTH_ID}" onchange="${infoPrefix}Control.authorities.select('{AUTH_ID}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="${infoPrefix}Control.authorities.setCurrent('{AUTH_ID}')" ondblclick="${infoPrefix}Control.authorities.getInfo({})">{AUTH_ID}</td>
<td onclick="${infoPrefix}Control.authorities.setCurrent('{AUTH_ID}')" ondblclick="${infoPrefix}Control.authorities.getInfo({})">{AUTH_NM}</td>
<td onclick="${infoPrefix}Control.authorities.setCurrent('{AUTH_ID}')" ondblclick="${infoPrefix}Control.authorities.getInfo({})">{REG_DT}</td>
</tr>
</template>
<template id="${infoPrefix}NotFound">
<tr class="odd">
<td valign="top" colspan="4" class="dataTables_empty text-center">${prefixName} 정보를 찾지 못했습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="${infoPrefix}PagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="${infoPrefix}Paging" class="pagination pagination-primary">
</ul>
</div>
</div>
<div style="width:49%; padding-top:.25em;">
<div class="nav-align-top">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<button type="button" onClick="${infoPrefix}Control.getLinkedList('users');" class="nav-link active" role="tab" data-bs-toggle="tab" data-bs-target="#navs-top-users" aria-controls="navs-top-users" aria-selected="true">사용자</button>
</li>
<li class="nav-item">
<button type="button" onClick="${infoPrefix}Control.getLinkedList('actions');" class="nav-link" role="tab" data-bs-toggle="tab" data-bs-target="#navs-top-actions" aria-controls="navs-top-actions" aria-selected="false">기능그룹</button>
</li>
</ul>
<div class="tab-content" style="padding:.6em 0;">
<div class="tab-pane fade show active" id="navs-top-users" role="tabpanel">
<jsp:include page="user-list.jsp" />
</div>
<div class="tab-pane fade" id="navs-top-actions" role="tabpanel">
<jsp:include page="actionGroup-list.jsp" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ Page Body -->
<hr class="my-5" />
</div>
<!-- / Content -->
<jsp:include page="/WEB-INF/jsp/include/bottom.jsp" />
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
</div>
<!-- / Layout wrapper -->
<jsp:include page="/WEB-INF/jsp/include/tail.jsp" />
<script src="<c:url value="/resources/js/base/user.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/actionGroup.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/authority.js?${ver}"/>"></script>
<script >
${functions}
${userMenus}
let ${infoPrefix}Control = new AuthorityControl();
function search${infoPrefix}s() {
${infoPrefix}Control.authorities.query = {
by:$("#by").val(),
term:$("#term").val()
};
${infoPrefix}Control.authorities.load(1);
}
function remove${infoPrefix}s() {
dialog.alert({
content:"선택한 ${prefixName} 정보를 제거하시겠습니까?",
onOK:() => {
${infoPrefix}Control.removeAuthorities();
}
});
}
function render${infoPrefix}List() {
let ${infoPrefix}List = ${infoPrefix}Control.authorities.dataset;
let empty = ${infoPrefix}List.empty;
let trs = empty ?
[document.getElementById("${infoPrefix}NotFound").innerHTML] : <%-- from template#${infoPrefix}NotFound --%>
${infoPrefix}List.inStrings(document.getElementById("${infoPrefix}Row").innerHTML); <%-- from template#${infoPrefix}Row --%>
$("#${infoPrefix}List").html(trs.join());
$("th input[type='checkbox']").prop("checked", false);
}
${infoPrefix}Control.onAuthorityListChange = obj => {
render${infoPrefix}List();
$("#${infoPrefix}Paging").setPaging({
list:${infoPrefix}Control.authorities.dataset,
prefix:${infoPrefix}Control.authorities.prefix,
start:obj.${infoPrefix}Start,
totalSize:obj.${infoPrefix}Total,
fetchSize:obj.${infoPrefix}Fetch,
func:"${infoPrefix}Control.authorities.load({index})"
});
};
${infoPrefix}Control.onCurrentAuthorityChange = item => {
$("#btnAddActions").prop("disabled", !item || ${infoPrefix}Control.authorities.isAdmin(item.data));
$("#btnAddUsers").prop("disabled", !item || ${infoPrefix}Control.authorities.isImplicit(item.data));
if (!item) return;
let key = item.data.AUTH_ID;
$("#${infoPrefix}List").setCurrentRow(key);
};
${infoPrefix}Control.onAuthoritySelect = selected => {
let ${infoPrefix}List = ${infoPrefix}Control.authorities.dataset;
let keys = selected.map(e => ${infoPrefix}List.getKey(e));
$("#${infoPrefix}List input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
let builtIn = selected.filter(info => ${infoPrefix}Control.authorities.isBuiltIn(info)).length > 0;
$("#btnRemove${infoPrefix}s").prop("disabled", keys.length < 1 || builtIn);
};
${userFunc}
${actionGroupFunc}
$("#term").onEnterPress(search${infoPrefix}s);
$(function(){
${onload}
${infoPrefix}Control.authorities.setData({
${infoPrefix}List:${authorityList},
${infoPrefix}Start:${authorityStart},
${infoPrefix}Fetch:${authorityFetch},
${infoPrefix}Total:${authorityTotal}
});
});
</script>
</body>
</html>

@ -0,0 +1,91 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<div class="d-flex flex-row justify-content-end p-3">
<div>
<button id="btnAddUsers" onclick="${infoPrefix}Control.addUsers();" class="btn btn-primary">+ 추가</button>
<button id="btnRemoveUsers" onclick="removeUsers();" class="btn btn-primary">- 제거</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input id="userToggler" onchange="${infoPrefix}Control.users.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending" style="">사용자</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="">등록일자</th>
</tr>
</thead>
<tbody id="userList">
</tbody>
<template id="userRow">
<tr data-key="{AUTH_ID}-{USER_ID}">
<td style="text-align:center;"><input value="{AUTH_ID}-{USER_ID}" onchange="${infoPrefix}Control.users.select('{AUTH_ID}-{USER_ID}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="${infoPrefix}Control.users.setCurrent('{AUTH_ID}-{USER_ID}')">{USER_ID}</td>
<td onclick="${infoPrefix}Control.users.setCurrent('{AUTH_ID}-{USER_ID}">{REG_DT}</td>
</tr>
</template>
<template id="userNotFound">
<tr class="odd">
<td valign="top" colspan="3" class="dataTables_empty text-center">사용자 정보를 찾지 못했습니다.</td>
</tr>
</template>
<template id="implicitActions">
<tr class="odd">
<td valign="top" colspan="3" class="dataTables_empty text-center">{authority}는 사용자를 지정하지 않습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="userPagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="userPaging" class="pagination pagination-primary">
</ul>
</div>
<c:set var="userFunc" scope="request">
function removeUsers() {
dialog.alert({
content:"선택한 사용자를 삭제하시겠습니까?",
onOK:() => {
${infoPrefix}Control.removeUsers();
}
});
}
${infoPrefix}Control.onUserListChange = obj => {
let authority = ${infoPrefix}Control.authorities.getCurrent();
authority = authority ? authority.AUTH_NM : "";
let ${infoPrefix}List = ${infoPrefix}Control.users.dataset;
let empty = ${infoPrefix}List.empty;
let trs =
${infoPrefix}Control.authorities.isImplicit() ? [document.getElementById("implicitActions").innerHTML.replace(/{authority}/, authority)] :
empty ? [document.getElementById("userNotFound").innerHTML] : <%-- from template#${infoPrefix}NotFound --%>
${infoPrefix}List.inStrings(document.getElementById("userRow").innerHTML); <%-- from template#${infoPrefix}Row --%>
$("#userList").html(trs.join());
$("#userToggler").prop("checked", false);
$("#userPaging").setPaging({
list:${infoPrefix}Control.users.dataset,
prefix:${infoPrefix}Control.users.prefix,
start:obj.userStart,
totalSize:obj.userTotal,
fetchSize:obj.userFetch,
func:"${infoPrefix}Control.users.load({index})"
});
};
${infoPrefix}Control.onCurrentUserChange = item => {
if (!item) return;
let data = item.data;
let key = data.AUTH_ID + "-" + data.USER_ID;
$("#userList").setCurrentRow(key);
};
${infoPrefix}Control.onUserSelect = selected => {
let ${infoPrefix}List = ${infoPrefix}Control.users.dataset;
let keys = selected.map(e => ${infoPrefix}List.getKey(e));
$("#userList input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
$("#btnRemoveUsers").prop("disabled", keys.length < 1);
};</c:set>

@ -0,0 +1,142 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<form id="code-form">
<div class="row g-3">
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="code"
>코드</label
>
<div class="col-sm-10">
<input name="code" type="text" required data-map="CODE" maxlength="15" class="form-control" placeholder="코드" />
<input name="groupID" type="hidden" data-map="GRP_ID" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="value"
>코드값</label
>
<div class="col-sm-10">
<input name="value" type="text" required data-map="CODE_VAL" maxlength="60" class="form-control" placeholder="코드값" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>설명</label
>
<div class="col-sm-10">
<input name="description" type="text" data-map="DSCRP" maxlength="200" class="form-control" placeholder="코드 설명"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="etc1"
>기타값 1</label
>
<div class="col-sm-10">
<input name="etc1" type="text" data-map="ETC1" maxlength="200" class="form-control" placeholder="기타값 1"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="etc2"
>기타값2</label
>
<div class="col-sm-10">
<input name="etc2" type="text" data-map="ETC2" maxlength="200" class="form-control" placeholder="기타값 2"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="etc3"
>기타값3</label
>
<div class="col-sm-10">
<input name="etc3" type="text" data-map="ET3" maxlength="200" class="form-control" placeholder="기타값 3"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="createdBy"
>등록자</label
>
<div class="col-sm-10">
<input type="text" data-map="RGTR" readonly class="form-control" placeholder="등록자"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>등록일자</label
>
<div class="col-sm-10">
<input type="text" data-map="REG_DT" readonly class="form-control" placeholder="등록일자"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>사용여부</label
>
<div class="col-sm-10" style="padding:.5em .7em;">
<span id="codeInUse"></span>
</div>
</div>
</div>
<div class="row mt-4 justify-content-end">
<div class="col-sm-12" style="text-align:right;">
<button onclick="saveCode();" type="button" class="btn btn-primary">저장</button>
</div>
</div>
</form>
<script type="text/javascript">
var codeFields = new FormFields("#code-form");
codeControl.codes.setInfo = obj => {
let info = obj.data;
codeFields.set(obj);
let create = isEmpty(info.CODE);
$("input[name='code']").prop("readonly", !create);
$("#code-form input")
.change(function() {
let input = $(this),
name = input.attr("data-map"),
val = input.val();
codeControl.codes.setValue(name, val);
})
.onEnterPress(saveCode);
$("#codeInUse").html("Y" == info.USE_YN ? "사용 중" : "사용하지 않음");
document.querySelector("input[name='" + (create ? "code" : "value") + "']").focus();
}
codeControl.codes.onModify = (changed) => {
if (["CODE", "CODE_VAL"].filter(e => changed.includes(e)).length < 1)
return;
renderCodeList();
codeControl.codes.dataset.setState();
}
function saveCode() {
if (!$("#code-form input").validInputs()) return;
dialog.alert({
content:"현재 코드 정보를 저장하시겠습니까?",
onOK:() => {
codeControl.codes.save(codeFields.get());
}
});
}
//# sourceURL=code-info.jsp
</script>

@ -0,0 +1,269 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<jsp:include page="/WEB-INF/jsp/include/head.jsp" />
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<jsp:include page="/WEB-INF/jsp/include/userMenus.jsp" />
<!-- Layout container -->
<!-- Layout page -->
<div class="layout-page">
<jsp:include page="/WEB-INF/jsp/include/top.jsp" />
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<%--h4 id="pageTitle" class="fw-bold py-3 mb-4">페이지 제목</h4--%>
<c:set var="prefixName" scope="request">코드 그룹</c:set>
<!-- Page Body -->
<div class="card">
<div class="card-datatable text-nowrap">
<div id="DataTables_Table_0_wrapper" class="dataTables_wrapper dt-bootstrap5 no-footer">
<div class="d-flex flex-row justify-content-evenly">
<div style="width:49%;">
<h5 class="mt-3">${prefixName}</h5>
<div class="d-flex flex-row justify-content-between p-3">
<%--div>
<div class="input-group" id="DataTables_Table_0_length">
<select id="by" onchange="document.getElementById('term').focus();" aria-controls="DataTables_Table_0" class="form-select">
<option value="groupName">이름</option>
<option value="groupID">아이디</option>
</select>
<input id="term" autofocus type="text" placeholder="조회 조건을 입력하십시오." class="form-control">
</div>
</div--%>
<div>
<%--button onclick="searchGroups();" class="btn btn-primary">찾기</button--%>
<button onclick="codeControl.groups.newInfo();" class="btn btn-primary">+ 추가</button>
<button id="btnRemoveGroups" onclick="removeGroups();" class="btn btn-primary">- 제거</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input onchange="codeControl.groups.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting sorting_asc" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Full name: activate to sort column descending">아이디</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending">이름</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending">등록일자</th>
</tr>
</thead>
<tbody id="groupList">
</tbody>
<template id="groupRow">
<tr data-key="{GRP_ID}">
<td style="text-align:center;"><input value="{GRP_ID}" onchange="codeControl.groups.select('{GRP_ID}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="codeControl.groups.setCurrent('{GRP_ID}')" ondblclick="codeControl.groups.getInfo({})">{GRP_ID}</td>
<td onclick="codeControl.groups.setCurrent('{GRP_ID}')" ondblclick="codeControl.groups.getInfo({})">{GRP_NM}</td>
<td onclick="codeControl.groups.setCurrent('{GRP_ID}')" ondblclick="codeControl.groups.getInfo({})">{REG_DT}</td>
</tr>
</template>
<template id="groupNotFound">
<tr class="odd">
<td valign="top" colspan="4" class="dataTables_empty text-center">${prefixName} 정보를 찾지 못했습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="groupPagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="groupPaging" class="pagination pagination-primary">
</ul>
</div>
</div>
<div style="width:49%;">
<h5 class="mt-3">공통 코드</h5>
<div class="d-flex flex-row justify-content-end p-3">
<div>
<button id="btnAddCode" onclick="codeControl.newCode();" class="btn btn-primary">+ 추가</button>
<button id="btnRemoveCodes" onclick="removeCodes();" class="btn btn-primary">- 제거</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input id="codeToggler" onchange="codeControl.codes.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending">코드</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending">코드값</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending">등록일자</th>
</tr>
</thead>
<tbody id="codeList">
</tbody>
<template id="codeRow">
<tr data-key="{CODE}">
<td style="text-align:center;"><input value="{CODE}" onchange="codeControl.codes.select('{CODE}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="codeControl.codes.setCurrent('{CODE}')" ondblclick="codeControl.codes.getInfo({})">{CODE}</td>
<td onclick="codeControl.codes.setCurrent('{CODE}')" ondblclick="codeControl.codes.getInfo({})">{CODE_VAL}</td>
<td onclick="codeControl.codes.setCurrent('{CODE}')" ondblclick="codeControl.codes.getInfo({})">{REG_DT}</td>
</tr>
</template>
<template id="codeNotFound">
<tr class="odd">
<td valign="top" colspan="4" class="dataTables_empty text-center">코드 정보를 찾지 못했습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="codePagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="codePaging" class="pagination pagination-primary">
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!--/ Page Body -->
<hr class="my-5" />
</div>
<!-- / Content -->
<jsp:include page="/WEB-INF/jsp/include/bottom.jsp" />
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
</div>
<!-- / Layout wrapper -->
<jsp:include page="/WEB-INF/jsp/include/tail.jsp" />
<script src="<c:url value="/resources/js/base/code.js"/>?${ver}"></script>
<script >
${functions}
${userMenus}
let codeControl = new CodeControl();
function searchGroups() {
codeControl.groups.query = {
by:$("#by").val(),
term:$("#term").val()
};
codeControl.groups.load(1);
}
function removeGroups() {
dialog.alert({
content:"선택한 ${prefixName} 정보를 제거하시겠습니까?",
onOK:() => {
codeControl.groups.remove();
}
});
}
function removeCodes() {
dialog.alert({
content:"선택한 코드를 삭제하시겠습니까?",
onOK:() => {
codeControl.removeCodes();
}
});
}
function renderGroupList() {
let groupList = codeControl.groups.dataset;
let empty = groupList.empty;
let trs = empty ?
[document.getElementById("groupNotFound").innerHTML] : <%-- from template#groupNotFound --%>
groupList.inStrings(document.getElementById("groupRow").innerHTML); <%-- from template#groupRow --%>
$("#groupList").html(trs.join());
$("th input[type='checkbox']").prop("checked", false);
}
codeControl.onGroupListChange = obj => {
renderGroupList();
$("#groupPaging").setPaging({
list:codeControl.groups.dataset,
prefix:codeControl.groups.prefix,
start:obj.groupStart,
totalSize:obj.groupTotal,
fetchSize:obj.groupFetch,
func:"codeControl.groups.load({index})"
});
};
codeControl.onCurrentGroupChange = item => {
$("#btnAddCode").prop("disabled", !item);
if (!item) return;
let key = item.data.GRP_ID;
$("#groupList").setCurrentRow(key);
};
codeControl.onGroupSelect = selected => {
let groupList = codeControl.groups.dataset;
let keys = selected.map(e => groupList.getKey(e));
$("#groupList input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
$("#btnRemoveGroups").prop("disabled", keys.length < 1);
};
function renderCodeList() {
let codeList = codeControl.codes.dataset;
let empty = codeList.empty;
let trs = empty ?
[document.getElementById("codeNotFound").innerHTML] : <%-- from template#groupNotFound --%>
codeList.inStrings(document.getElementById("codeRow").innerHTML); <%-- from template#groupRow --%>
$("#codeList").html(trs.join());
$("#codeToggler").prop("checked", false);
}
codeControl.onCodeListChange = obj => {
renderCodeList();
$("#codePaging").setPaging({
list:codeControl.codes.dataset,
prefix:codeControl.codes.prefix,
start:obj.codeStart,
totalSize:obj.codeTotal,
fetchSize:obj.codeFetch,
func:"codeControl.codes.load({index})"
});
};
codeControl.onCurrentCodeChange = item => {
if (!item) return;
let data = item.data;
let key = data.CODE;
$("#codeList").setCurrentRow(key);
};
codeControl.onCodeSelect = selected => {
let codeList = codeControl.codes.dataset;
let keys = selected.map(e => codeList.getKey(e));
$("#codeList input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
$("#btnRemoveCodes").prop("disabled", selected.length < 1);
};
$("#term").onEnterPress(searchGroups);
$(function(){
${onload}
codeControl.groups.setData({
groupList:${groupList},
groupStart:${groupStart},
groupFetch:${groupFetch},
groupTotal:${groupTotal}
});
});
</script>
</body>
</html>

@ -0,0 +1,112 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<form id="group-form">
<div class="row g-3">
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="id"
>아이디</label
>
<div class="col-sm-10">
<input name="id" type="text" required data-map="GRP_ID" maxlength="50" class="form-control" placeholder="그룹 아이디" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="name"
>이름</label
>
<div class="col-sm-10">
<input name="name" type="text" required data-map="GRP_NM" maxlength="60" class="form-control" placeholder="그룹 이름" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>설명</label
>
<div class="col-sm-10">
<input name="description" type="text" data-map="DSCRP" maxlength="200" class="form-control" placeholder="그룹 설명"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="createdBy"
>등록자</label
>
<div class="col-sm-10">
<input type="text" data-map="RGTR" readonly class="form-control" placeholder="등록자"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>등록일자</label
>
<div class="col-sm-10">
<input type="text" data-map="REG_DT" readonly class="form-control" placeholder="등록일자"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>사용여부</label
>
<div class="col-sm-10" style="padding:.5em .7em;">
<span id="groupInUse"></span>
</div>
</div>
</div>
<div class="row mt-4 justify-content-end">
<div class="col-sm-12" style="text-align:right;">
<button onclick="saveGroup();" type="button" class="btn btn-primary">저장</button>
</div>
</div>
</form>
<script type="text/javascript">
var groupFields = new FormFields("#group-form");
codeControl.groups.setInfo = obj => {
let info = obj.data;
groupFields.set(obj);
let create = isEmpty(info.GRP_ID);
$("input[name='id']").prop("readonly", !create);
$("#group-form input")
.change(function() {
let input = $(this),
name = input.attr("data-map"),
val = input.val();
codeControl.groups.setValue(name, val);
})
.onEnterPress(saveGroup);
$("#groupInUse").html(create ? "" : info.USE_YN == "Y" ? "사용 중" : "사용하지 않음");
document.querySelector("input[name='" + (create ? "id" : "name") + "']").focus();
}
codeControl.groups.onModify = (changed) => {
if (["GRP_NM"].filter(e => changed.includes(e)).length < 1)
return;
renderGroupList();
codeControl.groups.dataset.setState();
}
function saveGroup() {
if (!$("#group-form input").validInputs()) return;
dialog.alert({
content:"현재 그룹 정보를 저장하시겠습니까?",
onOK:() => {
codeControl.groups.save(groupFields.get());
}
});
}
//# sourceURL=group-info.jsp
</script>

@ -0,0 +1,108 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<form id="menu-form">
<div class="row g-3">
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="id"
>아이디</label
>
<div class="col-sm-10">
<input name="id" type="text" readonly maxlength="50" class="form-control" placeholder="저장하시면 시스템이 부여합니다." />
<input name="parentID" type="hidden" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="name"
>이름</label
>
<div class="col-sm-10">
<input name="name" type="text" required maxlength="60" class="form-control" placeholder="메뉴 이름" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="action"
>URL</label
>
<div class="col-sm-10 input-group" style="width:83.3%;">
<span id="btnSelectURL" onClick="setURL();" class="input-group-text"><i class="bx bx-search"></i></span>
<input name="action" type="text" maxlength="60" class="form-control" placeholder="URL" />
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="description"
>설명</label
>
<div class="col-sm-10">
<input name="description" type="text" maxlength="200" class="form-control" placeholder="메뉴 설명"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="imageName"
>이미지 이름</label
>
<div class="col-sm-10">
<input name="imageName" type="text" maxlength="200" class="form-control" placeholder="이미지 이름"/>
</div>
</div>
</div>
<div class="col-md-12">
<div class="row">
<label class="col-sm-2 col-form-label text-sm-end" for="imageConf"
>이미지 설정</label
>
<div class="col-sm-10">
<input name="imageConf" type="text" maxlength="200" class="form-control" placeholder="이미지 설정"/>
</div>
</div>
</div>
<div class="row mt-4 justify-content-end">
<div class="col-sm-12" style="text-align:right;">
<button id="btnSaveAuth" onclick="saveMenu();" type="button" class="btn btn-primary">저장</button>
</div>
</div>
</form>
<c:set var="menuFunc" scope="request">
var menuFields = new FormFields("#menu-form");
menuControl.setInfo = obj => {
menuFields.set(obj);
$("input[name='name']").focus();
}
menuControl.onModify = (changed) => {
if (["name", "url"].filter(e => changed.includes(e)).length < 1)
return;
}
async function setURL() {
let url = await selectURL(false);
$("input[name='action']").val(url).change();
}
function saveMenu() {
if (!$("#menu-form input").validInputs()) return;
dialog.alert({
content:"현재 메뉴 정보를 저장하시겠습니까?",
onOK:() => menuControl.save(menuFields.get())
});
}
$("#menu-form input")
.change(function() {
let input = $(this),
name = input.attr("name"),
val = input.val();
menuControl.setValue(name, val);
})
.onEnterPress(() => saveMenu());
</c:set>

@ -0,0 +1,178 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<jsp:include page="/WEB-INF/jsp/include/head.jsp" />
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/libs/jstree/jstree.css"/>" /--%>
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<jsp:include page="/WEB-INF/jsp/include/userMenus.jsp" />
<!-- Layout container -->
<!-- Layout page -->
<div class="layout-page">
<jsp:include page="/WEB-INF/jsp/include/top.jsp" />
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<%--h4 id="pageTitle" class="fw-bold py-3 mb-4">페이지 제목</h4--%>
<c:set var="prefixName" scope="request">메뉴</c:set>
<!-- Page Body -->
<div class="card">
<div class="card-datatable text-nowrap">
<div id="DataTables_Table_0_wrapper" class="dataTables_wrapper dt-bootstrap5 no-footer">
<div class="d-flex flex-row justify-content-evenly">
<div style="width:49%;">
<h5 class="mt-3">레이아웃</h5>
<div id="menu-tree" class="main-left d-flex flex-column flex-grow-1">
<div class="d-flex justify-content-between" style="padding-top:.5em; padding-bottom:.5em; border-top:1px solid #dfdfdf; border-bottom:1px solid #dfdfdf;">
<span>
<button id="menuToggler" onclick="toggleMenus();" class="btn btn-primary"></button>
</span>
</div>
<div id="menuTree" style="padding-top:1em; min-height:26em; overflow:auto;">
</div>
</div>
</div>
<div style="width:49%;">
<h5 class="mt-3">등록 정보</h5>
<div class="d-flex flex-row justify-content-end p-3">
<div>
<button id="btnRemoveMenus" onclick="removeMenus();" class="btn btn-primary">- 제거</button>
</div>
</div>
<jsp:include page="menu-info.jsp" />
</div>
</div>
</div>
</div>
</div>
<!--/ Page Body -->
<hr class="my-5" />
</div>
<!-- / Content -->
<jsp:include page="/WEB-INF/jsp/include/bottom.jsp" />
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
</div>
<!-- / Layout wrapper -->
<jsp:include page="/WEB-INF/jsp/include/tail.jsp" />
<script src="<c:url value="/resources/3rd-party/sneat/libs/jstree/jstree.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/jstree/jstree-support.js"/>"></script>
<script src="<c:url value="/resources/js/base/menu.js"/>?${ver}"></script>
<script >
${functions}
${userMenus}
var menuBranches = treeSupport({
selector:"#menuTree",
trace:wctx.trace,
plugins: ["checkbox", "contextmenu", "dnd"] ,
core:{check_callback:true,
multiple:false
},
checkbox:{
whole_node:false,
tie_selection:false
},
contextmenu:{items:{
newMenu:{label:"메뉴 추가", action:function(obj){
var current = menuControl.getCurrent(),
parentID = current.parentID;
menuControl.newInfo({parentID:parentID});
$("input[name='parentID']").val(parentID);
}},
newChildMenu:{label:"하위메뉴 추가", action:function(obj){
var current = menuControl.getCurrent(),
parentID = current.id;
menuControl.newInfo({parentID:parentID});
$("input[name='parentID']").val(parentID);
log("current", menuControl.getCurrent());
}},
}},
onNodeSelect:function(obj) {
var key = obj[0];
menuControl.setCurrent(key);
},
onNodeMove:function(obj) {
var parentID = obj.parent,
menuID = obj.node.id;
if (parentID == "#")
parentID = null;
menuControl.move(parentID, menuID);
},
onNodeReorder:function(obj) {
var parentID = obj.parent,
menuID = obj.node.id,
menuIDs = menuBranches.getChildIDs(parentID);
menuControl.reorder(menuIDs);
},
onNodeCheck:function(obj) {
var checked = obj.checked,
menuID = obj.node.id;
menuControl.select(menuID, checked);
}
});
function toggleMenus() {
$("#menuToggler").text(menuBranches.toggleFolding() == "collapsed" ? "+ 펼치기" : "- 닫기");
}
let menuControl = new MenuControl();
menuControl.onDatasetChange = obj => {
menuBranches.setData(treeHtml(menuControl.menus, {
id:function(e){return e.id;},
text:function(e){
return e.name == e.url ? e.name : e.name + (e.url ? " (" + e.url + ")" : "");
}
}));
$("#btnSelectURL").prop("disabled", menuControl.dataset.empty);
}
menuControl.onCurrentChange = item => {
menuControl.setInfo(item.data);
menuBranches.selectNode(item.data.id);
}
menuControl.onSelectionChange = selected => {
$("#btnRemoveMenus").prop("disabled", selected.length < 1);
}
menuControl.onMenusChanged = () => loadUserMenus();
${menuFunc}
async function loadUserMenus() {
let userMenus = await menuControl.getUserMenus();
setUserMenus(userMenus);
}
function removeMenus() {
dialog.alert({
content:"선택한 메뉴 정보를 삭제하시겠습니까?",
onOK:() => menuControl.remove()
});
}
$(function(){
${onload}
$("#menuToggler").text(menuBranches._folding == "collapsed" ? "+ 펼치기" : "- 닫기");
menuControl.setData(${menus});
menuBranches.open();
});
</script>
</body>
</html>

@ -0,0 +1,122 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<c:set var="prefixName" scope="request">사용자</c:set>
<!-- Page Body -->
<div class="card">
<div class="card-datatable text-nowrap">
<div id="DataTables_Table_0_wrapper" class="dataTables_wrapper dt-bootstrap5 no-footer">
<div class="d-flex flex-row justify-content-between p-3">
<div>
<div class="input-group" id="DataTables_Table_0_length">
<select id="_userBy" onchange="document.getElementById('_userTerm').focus();" aria-controls="DataTables_Table_0" class="form-select">
<option value="${infoPrefix}Name">이름</option>
<option value="${infoPrefix}ID">아이디</option>
</select>
<input id="_userTerm" autofocus type="text" placeholder="조회 조건을 입력하십시오." class="form-control">
</div>
</div>
<div>
<button onclick="search${infoPrefix}s();" class="btn btn-primary">찾기</button>
</div>
</div>
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="text-align:center;"><input onchange="${infoPrefix}Control.dataset.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting sorting_asc" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Full name: activate to sort column descending" style="">아이디</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending" style="">이름</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="">등록일자</th>
</tr>
</thead>
<tbody id="_${infoPrefix}List">
</tbody>
<template id="_${infoPrefix}Row">
<tr data-key="{USER_ID}">
<td style="text-align:center;"><input value="{USER_ID}" onchange="${infoPrefix}Control.dataset.select('{USER_ID}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="${infoPrefix}Control.setCurrent('{USER_ID}')" ondblclick="${infoPrefix}Control.getInfo({})">{USER_ID}</td>
<td onclick="${infoPrefix}Control.setCurrent('{USER_ID}')" ondblclick="${infoPrefix}Control.getInfo({})">{USER_NM}</td>
<td onclick="${infoPrefix}Control.setCurrent('{USER_ID}')" ondblclick="${infoPrefix}Control.getInfo({})">{REG_DT}</td>
</tr>
</template>
<template id="_${infoPrefix}NotFound">
<tr class="odd">
<td valign="top" colspan="4" class="dataTables_empty text-center">${prefixName} 정보를 찾지 못했습니다.</td>
</tr>
</template>
</table>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="_${infoPrefix}PagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="_${infoPrefix}Paging" class="pagination pagination-primary">
</ul>
</div>
</div>
</div>
</div>
<!--/ Page Body -->
<script >
var ${infoPrefix}Control = new UserControl();
function getSelectedUser() {
let selected = ${infoPrefix}Control.dataset.getKeys("selected");
if (selected.length < 1)
return dialog.alert("사용자를 선택하십시오.");
else
return selected;
}
function search${infoPrefix}s() {
${infoPrefix}Control.query = {
by:$("#_userBy").val(),
term:$("#_userTerm").val()
};
${infoPrefix}Control.load(1);
}
${infoPrefix}Control.onDatasetChange = obj => {
let ${infoPrefix}List = ${infoPrefix}Control.dataset;
let empty = ${infoPrefix}List.empty;
let trs = empty ?
[document.getElementById("_${infoPrefix}NotFound").innerHTML] : <%-- from template#${infoPrefix}NotFound --%>
${infoPrefix}List.inStrings(document.getElementById("_${infoPrefix}Row").innerHTML); <%-- from template#${infoPrefix}Row --%>
$("#_${infoPrefix}List").html(trs.join());
$("th input[type='checkbox']").prop("checked", false);
$("#_${infoPrefix}Paging").setPaging({
list:${infoPrefix}Control.dataset,
prefix:${infoPrefix}Control.prefix,
start:obj.${infoPrefix}Start,
totalSize:obj.${infoPrefix}Total,
fetchSize:obj.${infoPrefix}Fetch,
func:"${infoPrefix}Control.load({index})"
});
};
${infoPrefix}Control.onCurrentChange = item => {
if (!item) return;
let key = item.data.USER_ID;
$("#_${infoPrefix}List").setCurrentRow(key);
};
${infoPrefix}Control.onSelectionChange = selected => {
let ${infoPrefix}List = ${infoPrefix}Control.dataset;
let keys = selected.map(e => ${infoPrefix}List.getKey(e));
$("#_${infoPrefix}List input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
};
$("#_userTerm").onEnterPress(search${infoPrefix}s);
$(function(){
${onload}
${infoPrefix}Control.setData({
${infoPrefix}List:${userList},
${infoPrefix}Start:${userStart},
${infoPrefix}Fetch:${userFetch},
${infoPrefix}Total:${userTotal}
});
});
//# sourceURL=select-user.jsp
</script>

@ -0,0 +1,200 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<form id="infoPrefix-form">
<div class="row g-3">
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="account"
>계정</label
>
<div class="col-sm-9">
<input name="id" type="hidden" data-map="USER_ID" />
<input name="institute" type="hidden" data-map="NSTT_CD" />
<input name="account" type="text" required data-map="USER_ACNT" class="form-control" placeholder="prefixName 계정" />
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="name"
>이름</label
>
<div class="col-sm-9">
<input name="name" type="text" required data-map="USER_NM" class="form-control" placeholder="prefixName 이름" />
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="password"
>비밀번호</label
>
<div class="col-sm-9">
<input name="password" type="password" required class="form-control" placeholder="비밀번호" />
</div>
</div>
</div>
<div class="col-md-6 hidden">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="confirmPassword"
>비밀번호 확인</label
>
<div class="col-sm-9">
<input name="confirmPassword" type="password" required class="form-control" placeholder="비밀번호 확인" />
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="birthday"
>생년월일</label
>
<div class="col-sm-9">
<input name="birthday" type="text" data-map="BRDT" class="form-control dob-picker" placeholder="YYYY-MM-DD"/>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="gender"
>성별</label
>
<div class="col-sm-9">
<div class="form-check form-check-inline mt-3">
<input name="gender" value="M" type="radio" data-map="GENDER" class="form-check-input"/>
<label class="form-check-label" for="male">남자</label>
</div>
<div class="form-check form-check-inline">
<input name="gender" value="F" type="radio" data-map="GENDER" class="form-check-input"/>
<label class="form-check-label" for="female">여자</label>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="emailAddress"
>이메일 주소</label
>
<div class="col-sm-9">
<input name="emailAddress" type="email" required data-map="EML_ADRS" class="form-control" placeholder="이메일 주소" />
</div>
</div>
</div>
<div class="col-md-6 select2-primary">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="mobilePhoneNo"
>전화번호(무선)</label
>
<div class="col-sm-9">
<input name="mobilePhoneNo" type="text" data-map="MBL_TELNO" class="form-control phone-mask" placeholder="010-0000-0000" />
</div>
</div>
</div>
<div class="col-md-6 select2-primary">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="phoneNo"
>전화번호(유선)</label
>
<div class="col-sm-9">
<input name="phoneNo" type="text" data-map="TELNO" class="form-control phone-mask" placeholder="000-0000-0000" />
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="faxNo">팩스</label>
<div class="col-sm-9">
<input name="faxNo" type="text" data-map="FXNO" class="form-control phone-mask" placeholder="000-0000-0000"/>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for=positionName>직위</label>
<div class="col-sm-9">
<input name="positionName" type="text" data-map="POS_NM" class="form-control" placeholder="직위"/>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<label class="col-sm-3 col-form-label text-sm-end" for="status">상태</label>
<div class="col-sm-9">
<input name="status" type="text" data-map="STTS" class="form-control" placeholder="상태"/>
</div>
</div>
</div>
</div>
<div class="row mt-4 justify-content-end">
<div class="col-md-6">
<div class="row justify-content-end">
<div class="col-sm-3">
<button onclick="saveinfoPrefix();" type="button" class="btn btn-primary">저장</button>
</div>
</div>
</div>
</div>
</form>
<script type="text/javascript">
var infoPrefixFields = new FormFields("#infoPrefix-form");
infoPrefixControl.setInfo = obj => {
infoPrefixFields.set(obj);
let create = isEmpty(obj.data.USER_ACNT);
$("input[name='account']").prop("readonly", !create);
$("input[type='password']").each(function(){
let password = $(this).prop("required", create);
let div = password.parent().parent().parent();
if (create) {
$("input[name='institute']").val("default");
div.show();
} else
div.hide();
});
$("#infoPrefix-form input")
.change(function() {
let input = $(this),
name = input.attr("data-map"),
val = input.val();
infoPrefixControl.setValue(name, val);
})
.onEnterPress(saveinfoPrefix);
document.querySelector("input[name='" + (create ? "account" : "name") + "']").focus();
}
infoPrefixControl.onModify = (changed) => {
if (["USER_NM", "EML_ADRS", "MBL_TELNO"].filter(e => changed.includes(e)).length < 1)
return;
renderinfoPrefixList();
infoPrefixControl.dataset.setState();
}
function saveinfoPrefix() {
if (!$("#infoPrefix-form input").validInputs()) return;
let match = Array.from(document.querySelectorAll("input[type='password']"))
.map(input => input.value)
.reduce((total, current) => total == current);
if (!match) {
dialog.alert({
content:"비밀번호와 비밀번호 확인이 다릅니다.",
onClose:function(){
document.querySelector("input[name='confirmPassword']").focus();
}
});
return;
}
dialog.alert({
content:"현재 prefixName 정보를 저장하시겠습니까?",
onOK:() => {
infoPrefixControl.save(infoPrefixFields.get());
}
});
}
//# sourceURL=user-info.jsp
</script>

@ -0,0 +1,179 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<jsp:include page="/WEB-INF/jsp/include/head.jsp" />
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<jsp:include page="/WEB-INF/jsp/include/userMenus.jsp" />
<!-- Layout container -->
<!-- Layout page -->
<div class="layout-page">
<jsp:include page="/WEB-INF/jsp/include/top.jsp" />
<!-- Content wrapper -->
<div class="content-wrapper">
<!-- Content -->
<div class="container-xxl flex-grow-1 container-p-y">
<%--h4 id="pageTitle" class="fw-bold py-3 mb-4">페이지 제목</h4--%>
<c:set var="prefixName" scope="request">사용자</c:set>
<!-- Page Body -->
<div class="card">
<div class="card-datatable text-nowrap">
<div id="DataTables_Table_0_wrapper" class="dataTables_wrapper dt-bootstrap5 no-footer">
<div class="d-flex flex-row justify-content-between p-3">
<div>
<div class="input-group" id="DataTables_Table_0_length">
<select id="by" onchange="document.getElementById('term').focus();" aria-controls="DataTables_Table_0" class="form-select">
<option value="${infoPrefix}Name">이름</option>
<option value="${infoPrefix}Account">계정</option>
</select>
<input id="term" autofocus type="text" placeholder="조회 조건을 입력하십시오." class="form-control">
</div>
</div>
<div>
<button onclick="search${infoPrefix}s();" class="btn btn-primary">찾기</button>
<button onclick="${infoPrefix}Control.newInfo();" class="btn btn-primary">+ 추가</button>
<button id="btnRemove${infoPrefix}s" onclick="remove${infoPrefix}s();" class="btn btn-primary">- 제거</button>
</div>
</div>
<div class="table-responsive">
<table class="datatables-ajax table table-bordered dataTable no-footer" id="DataTables_Table_0" aria-describedby="DataTables_Table_0_info">
<thead>
<tr><th tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" style="width: 158.828px; text-align:center;"><input onchange="${infoPrefix}Control.select(this.checked);" type="checkbox" class="form-check-input"></th>
<th class="sorting sorting_asc" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Full name: activate to sort column descending" style="width: 223.719px;">계정</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Email: activate to sort column ascending" style="width: 146.156px;">이름</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Position: activate to sort column ascending" style="width: 195.688px;">이메일</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Office: activate to sort column ascending" style="width: 160.141px;">전화번호(무선)</th>
<th class="sorting" tabindex="0" aria-controls="DataTables_Table_0" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="width: 230.469px;">등록일자</th>
</tr>
</thead>
<tbody id="${infoPrefix}List">
</tbody>
<template id="${infoPrefix}Row">
<tr data-key="{USER_ID}">
<td style="text-align:center;"><input value="{USER_ID}" onchange="${infoPrefix}Control.select('{USER_ID}', this.checked);" type="checkbox" class="form-check-input"></td>
<td onclick="${infoPrefix}Control.setCurrent('{USER_ID}')" ondblclick="${infoPrefix}Control.getInfo({})">{USER_ACNT}</td>
<td onclick="${infoPrefix}Control.setCurrent('{USER_ID}')" ondblclick="${infoPrefix}Control.getInfo({})">{USER_NM}</td>
<td onclick="${infoPrefix}Control.setCurrent('{USER_ID}')" ondblclick="${infoPrefix}Control.getInfo({})">{EML_ADRS}</td>
<td onclick="${infoPrefix}Control.setCurrent('{USER_ID}')" ondblclick="${infoPrefix}Control.getInfo({})">{MBL_TELNO}</td>
<td onclick="${infoPrefix}Control.setCurrent('{USER_ID}')" ondblclick="${infoPrefix}Control.getInfo({})">{REG_DT}</td>
</tr>
</template>
<template id="${infoPrefix}NotFound">
<tr class="odd">
<td valign="top" colspan="6" class="dataTables_empty text-center">${prefixName} 정보를 찾지 못했습니다.</td>
</tr>
</template>
</table>
</div>
<div class="d-flex flex-row p-3 justify-content-between">
<label id="${infoPrefix}PagingInfo" class="dataTables_info" role="status" aria-live="polite"></label>
<ul id="${infoPrefix}Paging" class="pagination pagination-primary">
</ul>
</div>
</div>
</div>
</div>
<!--/ Page Body -->
<hr class="my-5" />
</div>
<!-- / Content -->
<jsp:include page="/WEB-INF/jsp/include/bottom.jsp" />
<div class="content-backdrop fade"></div>
</div>
<!-- Content wrapper -->
</div>
<!-- / Layout page -->
</div>
</div>
<!-- / Layout wrapper -->
<jsp:include page="/WEB-INF/jsp/include/tail.jsp" />
<script src="<c:url value="/resources/js/base/user.js?${ver}"/>"></script>
<script >
${functions}
${userMenus}
let ${infoPrefix}Control = new UserControl();
function search${infoPrefix}s() {
${infoPrefix}Control.query = {
by:$("#by").val(),
term:$("#term").val()
};
${infoPrefix}Control.load(1);
}
function remove${infoPrefix}s() {
dialog.alert({
content:"선택한 ${prefixName} 정보를 제거하시겠습니까?",
onOK:() => {
${infoPrefix}Control.remove();
}
});
}
function render${infoPrefix}List() {
let ${infoPrefix}List = ${infoPrefix}Control.dataset;
let empty = ${infoPrefix}List.empty;
let trs = empty ?
[document.getElementById("${infoPrefix}NotFound").innerHTML] : <%-- from template#${infoPrefix}NotFound --%>
${infoPrefix}List.inStrings(document.getElementById("${infoPrefix}Row").innerHTML); <%-- from template#${infoPrefix}Row --%>
$("#${infoPrefix}List").html(trs.join());
$("th input[type='checkbox']").prop("checked", false);
}
${infoPrefix}Control.onDatasetChange = obj => {
render${infoPrefix}List();
$("#${infoPrefix}Paging").setPaging({
list:${infoPrefix}Control.dataset,
prefix:${infoPrefix}Control.prefix,
start:obj.${infoPrefix}Start,
totalSize:obj.${infoPrefix}Total,
fetchSize:obj.${infoPrefix}Fetch,
func:"${infoPrefix}Control.load({index})"
});
};
${infoPrefix}Control.onCurrentChange = item => {
if (!item) return;
let key = item.data.USER_ID;
$("#${infoPrefix}List").setCurrentRow(key);
};
${infoPrefix}Control.onSelectionChange = selected => {
let ${infoPrefix}List = ${infoPrefix}Control.dataset;
let keys = selected.map(e => ${infoPrefix}List.getKey(e));
$("#${infoPrefix}List input[type='checkbox']").each(function() {
let checkbox = $(this);
checkbox.prop("checked", keys.includes(checkbox.val()));
});
$("#btnRemove${infoPrefix}s").prop("disabled", keys.length < 1);
};
$("#term").onEnterPress(search${infoPrefix}s);
$(function(){
${onload}
${infoPrefix}Control.setData({
${infoPrefix}List:${userList},
${infoPrefix}Start:${userStart},
${infoPrefix}Fetch:${userFetch},
${infoPrefix}Total:${userTotal}
});
});
</script>
</body>
</html>

@ -0,0 +1,80 @@
<%@ page language="java" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<%@ page import="java.util.HashMap, javax.servlet.http.HttpServletRequest, cokr.xit.foundation.data.Convert" %>
<%! private static final HashMap<String, String> titles = new HashMap<>();
static {
titles.put("404", "Page Not Found");
titles.put("sessionExpired", "Session Expired");
titles.put("invalidSession", "Invalid Session");
titles.put("accessDenied", "Access Denied");
titles.put("500", "Server Error");
}
private static void setTitle(HttpServletRequest hreq) {
String status = Convert.toString(hreq.getAttribute("status"));
if (status == "")
status = "500";
String title = titles.get(status);
if (title == null)
title = titles.get("500");
hreq.setAttribute("title", title);
}
%>
<% setTitle(request); %>
<c:if test="${json}"><%
response.setContentType("application/json; charset=UTF-8");
%>{
"path": "${path}",
"failed": true,
"status": "${status}",
"title": "${title}",
"message": "${message}",
"description": "${description}",
"stacktrace": "${stacktrace}"
}</c:if>
<c:if test="${!json}"><%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<jsp:include page="/WEB-INF/jsp/include/head.jsp" />
<style>
.misc-wrapper {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: calc(100vh - (1.625rem * 2));
text-align: center;
}
</style>
<body>
<!-- Content -->
<!-- Error -->
<div class="container-xxl container-p-y">
<div class="misc-wrapper">
<h2 class="mb-2 mx-2">${title} :(</h2>
<p class="mb-4 mx-2">죄송합니다. 😖</p>
<p class="mb-4 mx-2">${message}</p>
<a onclick="wctx.home();" class="btn btn-primary" href="javascript:void(0);">처음으로 돌아가기</a>
<a onclick="history.back();" class="btn btn-primary mt-2" href="javascript:void(0);" autofocus>이전으로 돌아가기</a>
<div class="mt-3">
<img
src="<c:url value="/resources/img/illustrations/page-misc-error-light.png"/>"
alt="page-misc-error-light"
width="500"
class="img-fluid"
data-app-dark-img="illustrations/page-misc-error-dark.png"
data-app-light-img="illustrations/page-misc-error-light.png"
/>
</div>
</div>
</div>
<!-- /Error -->
<!-- / Content -->
<jsp:include page="/WEB-INF/jsp/include/tail.jsp" />
<script>
${functions}
</script>
</body>
</html></c:if>

@ -0,0 +1,34 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<!-- Footer -->
<footer class="content-footer footer bg-footer-theme">
<div class="container-xxl d-flex flex-wrap justify-content-between py-2 flex-md-row flex-column">
<div class="mb-2 mb-md-0">
©
<script>
document.write(new Date().getFullYear());
</script>
, made with XIT Base by
<a href="http://xit.co.kr" target="_blank" class="footer-link fw-bolder">(주)엑스아이티</a>
</div>
<%--div>
<a href="https://themeselection.com/license/" class="footer-link me-4" target="_blank">License</a>
<a href="https://themeselection.com/" target="_blank" class="footer-link me-4">More Themes</a>
<a
href="https://demos.themeselection.com/sneat-bootstrap-html-admin-template/documentation/"
target="_blank"
class="footer-link me-4"
>Documentation</a
>
<a
href="https://themeselection.com/support/"
target="_blank"
class="footer-link d-none d-sm-inline-block"
>Support</a
>
</div--%>
</div>
</footer>
<!-- / Footer -->

@ -0,0 +1,41 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<!DOCTYPE html>
<html
lang="kr"
class="light-style layout-navbar-fixed layout-menu-fixed "
dir="ltr"
data-theme="theme-default"
data-assets-path="<c:url value="/resources/"/>"
data-template="vertical-menu-template-starter">
<head>
<meta charset="utf-8" />
<title>XIT Base Example</title>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="<c:url value="/resources/image/favicon.ico"/>" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet">
<!-- Icons. Uncomment required icon fonts -->
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/fonts/boxicons.css"/>" />
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/fonts/fontawesome.css"/>" />
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/fonts/flag-icons.css"/>" />
<!-- Core CSS -->
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/css/rtl/core.css"/>" class="template-customizer-core-css" />
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/css/rtl/theme-default.css"/>" class="template-customizer-theme-css" />
<%--link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/css/demo.css" /--%>
<!-- Vendors CSS -->
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/libs/perfect-scrollbar/perfect-scrollbar.css"/>" />
<%--link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/libs/typeahead-js/typeahead.css"/>" />
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/libs/datatables-bs5/datatables.bootstrap5.css"/>" />
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/libs/datatables-responsive-bs5/responsive.bootstrap5.css"/>" />
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/libs/flatpickr/flatpickr.css"/>" /--%>
<link rel="stylesheet" href="<c:url value="/resources/css/styles.css"/>" />
</head>

@ -1,11 +1,4 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%--@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"--%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%--@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"--%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%--@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" --%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"
%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"
%><%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"
%><%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

@ -0,0 +1,72 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<div class="spinner-border spinner-border-lg text-primary wait" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<!-- Helpers -->
<script src="<c:url value="/resources/3rd-party/sneat/js/helpers.js"/>"></script>
<!--! Template customizer & Theme config files MUST be included after core stylesheets and helpers.js in the <head> section -->
<!--? Template customizer: To hide customizer set displayCustomizer value false in config.js. -->
<script src="<c:url value="/resources/3rd-party/sneat/js/template-customizer.js"/>"></script>
<%--? Config: Mandatory theme config file contain global vars & default theme options, Set your preferred theme option in this file. -->
<script src="../../assets/js/config.js"></script--%>
<!-- Core JS -->
<!-- build:js assets/vendor/js/core.js -->
<script src="<c:url value="/resources/3rd-party/sneat/libs/jquery/jquery.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/jquery-ui/1.13.2/jquery-ui.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/sneat/libs/popper/popper.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/sneat/js/bootstrap.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/sneat/libs/perfect-scrollbar/perfect-scrollbar.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/sneat/libs/hammer/hammer.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/sneat/libs/i18n/i18n.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/sneat/js/menu.js"/>"></script>
<script src="<c:url value="/resources/js/base/base.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/dataset.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/menu-support.js?${ver}"/>"></script>
<!-- endbuild -->
<c:set var="functions" scope="request">
wctx.path = "${pageContext.request.contextPath}";
wctx.version = "${ver}";
wctx.trace = ${!production};
wctx.csrf = {
header:"${_csrf.headerName}",
token:"${_csrf.token}"
};
dialog.title = "XIT Base";
<c:if test="${currentUser.authenticated}">
function logout() {
dialog.alert({
content:"로그아웃 하시겠습니까?",
onOK:function(){
var form = $("<form action=\"<c:url value='/logout.do'/>\", method=\"POST\">");
$("<input name=\"${_csrf.parameterName}\" value=\"${_csrf.token}\" type=\"hidden\">").appendTo(form);
form.appendTo("body").submit();
}
});
}</c:if>
<c:if test="${currentUser.hasAuthorities('ROLE_ADMIN')}">
async function selectURL(multiple) {
return new Promise(function(resolve, reject) {
ajax.get({
url:wctx.url("/urls.do"),
data:{multiple:multiple},
success: resp => {
dialog.open({
title:"URL 선택",
content:resp,
getData:() => getSelectedURL(),
onOK:selected => {
resolve(selected);
}
});
}
});
});
}
</c:if>
${functions}</c:set>

@ -0,0 +1,484 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
</-- Navbar -->
<nav
class="layout-navbar container-xxl navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"
id="layout-navbar"
>
<div class="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
<a class="nav-item nav-link px-0 me-xl-4" href="javascript:void(0)">
<i class="bx bx-menu bx-sm"></i>
</a>
</div>
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
<!-- Search -->
<div class="navbar-nav align-items-center">
<div class="nav-item navbar-search-wrapper mb-0">
<a class="nav-item nav-link search-toggler px-0" href="javascript:void(0);">
<span id="pageTitle" class="fw-bold" style="font-size:x-large;"></span>
</a>
</div>
</div>
<!-- /Search -->
<ul class="navbar-nav flex-row align-items-center ms-auto">
<%-- Language -->
<li class="nav-item dropdown-language dropdown me-2 me-xl-0">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown">
<i class="fi fi-us fis rounded-circle fs-3 me-1"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="javascript:void(0);" data-language="en">
<i class="fi fi-us fis rounded-circle fs-4 me-1"></i>
<span class="align-middle">English</span>
</a>
</li>
<li>
<a class="dropdown-item" href="javascript:void(0);" data-language="fr">
<i class="fi fi-fr fis rounded-circle fs-4 me-1"></i>
<span class="align-middle">France</span>
</a>
</li>
<li>
<a class="dropdown-item" href="javascript:void(0);" data-language="de">
<i class="fi fi-de fis rounded-circle fs-4 me-1"></i>
<span class="align-middle">German</span>
</a>
</li>
<li>
<a class="dropdown-item" href="javascript:void(0);" data-language="pt">
<i class="fi fi-pt fis rounded-circle fs-4 me-1"></i>
<span class="align-middle">Portuguese</span>
</a>
</li>
</ul>
</li>
<!--/ Language --%>
<!-- Style Switcher -->
<li class="nav-item me-2 me-xl-0">
<a class="nav-link style-switcher-toggle hide-arrow" href="javascript:void(0);">
<i class="bx bx-sm"></i>
</a>
</li>
<!--/ Style Switcher -->
<%-- Quick links -->
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="bx bx-grid-alt bx-sm"></i>
</a>
<div class="dropdown-menu dropdown-menu-end py-0">
<div class="dropdown-menu-header border-bottom">
<div class="dropdown-header d-flex align-items-center py-3">
<h5 class="text-body mb-0 me-auto">Shortcuts</h5>
<a
href="javascript:void(0)"
class="dropdown-shortcuts-add text-body"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Add shortcuts"
><i class="bx bx-sm bx-plus-circle"></i
></a>
</div>
</div>
<div class="dropdown-shortcuts-list scrollable-container">
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon bg-label-secondary rounded-circle mb-2">
<i class="bx bx-calendar fs-4"></i>
</span>
<a href="app-calendar.html" class="stretched-link">Calendar</a>
<small class="text-muted mb-0">Appointments</small>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon bg-label-secondary rounded-circle mb-2">
<i class="bx bx-food-menu fs-4"></i>
</span>
<a href="app-invoice-list.html" class="stretched-link">Invoice App</a>
<small class="text-muted mb-0">Manage Accounts</small>
</div>
</div>
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon bg-label-secondary rounded-circle mb-2">
<i class="bx bx-user fs-4"></i>
</span>
<a href="app-user-list.html" class="stretched-link">User App</a>
<small class="text-muted mb-0">Manage Users</small>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon bg-label-secondary rounded-circle mb-2">
<i class="bx bx-check-shield fs-4"></i>
</span>
<a href="app-access-roles.html" class="stretched-link">Role Management</a>
<small class="text-muted mb-0">Permission</small>
</div>
</div>
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon bg-label-secondary rounded-circle mb-2">
<i class="bx bx-pie-chart-alt-2 fs-4"></i>
</span>
<a href="index.html" class="stretched-link">Dashboard</a>
<small class="text-muted mb-0">User Profile</small>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon bg-label-secondary rounded-circle mb-2">
<i class="bx bx-cog fs-4"></i>
</span>
<a href="pages-account-settings-account.html" class="stretched-link">Setting</a>
<small class="text-muted mb-0">Account Settings</small>
</div>
</div>
<div class="row row-bordered overflow-visible g-0">
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon bg-label-secondary rounded-circle mb-2">
<i class="bx bx-help-circle fs-4"></i>
</span>
<a href="pages-help-center-landing.html" class="stretched-link">Help Center</a>
<small class="text-muted mb-0">FAQs & Articles</small>
</div>
<div class="dropdown-shortcuts-item col">
<span class="dropdown-shortcuts-icon bg-label-secondary rounded-circle mb-2">
<i class="bx bx-window-open fs-4"></i>
</span>
<a href="modal-examples.html" class="stretched-link">Modals</a>
<small class="text-muted mb-0">Useful Popups</small>
</div>
</div>
</div>
</div>
</li>
<!-- Quick links --%>
<%-- Notification -->
<li class="nav-item dropdown-notifications navbar-dropdown dropdown me-3 me-xl-1">
<a
class="nav-link dropdown-toggle hide-arrow"
href="javascript:void(0);"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<i class="bx bx-bell bx-sm"></i>
<span class="badge bg-danger rounded-pill badge-notifications">5</span>
</a>
<ul class="dropdown-menu dropdown-menu-end py-0">
<li class="dropdown-menu-header border-bottom">
<div class="dropdown-header d-flex align-items-center py-3">
<h5 class="text-body mb-0 me-auto">Notification</h5>
<a
href="javascript:void(0)"
class="dropdown-notifications-all text-body"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Mark all as read"
><i class="bx fs-4 bx-envelope-open"></i
></a>
</div>
</li>
<li class="dropdown-notifications-list scrollable-container">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-action dropdown-notifications-item">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="<c:url value="/resources/img/avatars/1.png"/>" alt class="w-px-40 h-auto rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Congratulation Lettie 🎉</h6>
<p class="mb-0">Won the monthly best seller gold badge</p>
<small class="text-muted">1h ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<span class="avatar-initial rounded-circle bg-label-danger">CF</span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Charles Franklin</h6>
<p class="mb-0">Accepted your connection</p>
<small class="text-muted">12hr ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="<c:url value="/resources/img/avatars/2.png"/>" alt class="w-px-40 h-auto rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">New Message ✉️</h6>
<p class="mb-0">You have new message from Natalie</p>
<small class="text-muted">1h ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<span class="avatar-initial rounded-circle bg-label-success"
><i class="bx bx-cart"></i
></span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Whoo! You have new order 🛒</h6>
<p class="mb-0">ACME Inc. made new order $1,154</p>
<small class="text-muted">1 day ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="<c:url value="/resources/img/avatars/9.png"/>" alt class="w-px-40 h-auto rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Application has been approved 🚀</h6>
<p class="mb-0">Your ABC project application has been approved.</p>
<small class="text-muted">2 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<span class="avatar-initial rounded-circle bg-label-success"
><i class="bx bx-pie-chart-alt"></i
></span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Monthly report is generated</h6>
<p class="mb-0">July monthly financial report is generated</p>
<small class="text-muted">3 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="<c:url value="/resources/img/avatars/5.png"/>" alt class="w-px-40 h-auto rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">Send connection request</h6>
<p class="mb-0">Peter sent you connection request</p>
<small class="text-muted">4 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<img src="<c:url value="/resources/img/avatars/6.png"/>" alt class="w-px-40 h-auto rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">New message from Jane</h6>
<p class="mb-0">Your have new message from Jane</p>
<small class="text-muted">5 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
<li class="list-group-item list-group-item-action dropdown-notifications-item marked-as-read">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar">
<span class="avatar-initial rounded-circle bg-label-warning"
><i class="bx bx-error"></i
></span>
</div>
</div>
<div class="flex-grow-1">
<h6 class="mb-1">CPU is running high</h6>
<p class="mb-0">CPU Utilization Percent is currently at 88.63%,</p>
<small class="text-muted">5 days ago</small>
</div>
<div class="flex-shrink-0 dropdown-notifications-actions">
<a href="javascript:void(0)" class="dropdown-notifications-read"
><span class="badge badge-dot"></span
></a>
<a href="javascript:void(0)" class="dropdown-notifications-archive"
><span class="bx bx-x"></span
></a>
</div>
</div>
</li>
</ul>
</li>
<li class="dropdown-menu-footer border-top">
<a href="javascript:void(0);" class="dropdown-item d-flex justify-content-center p-3">
View all notifications
</a>
</li>
</ul>
</li>
<!--/ Notification --%>
<!-- User -->
<li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown">
<div class="avatar avatar-online">
<img src="<c:url value="/resources/img/avatars/1.png"/>" alt class="w-px-40 h-auto rounded-circle" />
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="pages-account-settings-account.html">
<div class="d-flex">
<div class="flex-shrink-0 me-3">
<div class="avatar avatar-online">
<img src="<c:url value="/resources/img/avatars/1.png"/>" alt class="w-px-40 h-auto rounded-circle" />
</div>
</div>
<div class="flex-grow-1">
<span class="fw-semibold d-block">${currentUser.name}</span>
<small class="text-muted">${currentUser.account}</small>
</div>
</div>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="pages-profile-user.html">
<i class="bx bx-user me-2"></i>
<span class="align-middle">프로필</span>
</a>
</li>
<li>
<a class="dropdown-item" href="pages-account-settings-account.html">
<i class="bx bx-cog me-2"></i>
<span class="align-middle">설정</span>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li>
<a class="dropdown-item" href="pages-help-center-landing.html">
<i class="bx bx-support me-2"></i>
<span class="align-middle">Help</span>
</a>
</li>
<li>
<div class="dropdown-divider"></div>
</li>
<li onclick="logout();">
<a class="dropdown-item">
<i class="bx bx-power-off me-2"></i>
<span class="align-middle">로그아웃</span>
</a>
</li>
</ul>
</li>
<!--/ User -->
</ul>
</div>
<%-- Search Small Screens -->
<div class="navbar-search-wrapper search-input-wrapper d-none">
<input
type="text"
class="form-control search-input container-xxl border-0"
placeholder="Search..."
aria-label="Search..."
/>
<i class="bx bx-x bx-sm search-toggler cursor-pointer"></i>
</div --%>
</nav>
<!-- / Navbar -->
<c:set var="functions" scope="request">${functions}
function setPageTitle(pageTitle) {
$("#pageTitle").html(pageTitle);
}</c:set>

@ -0,0 +1,96 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<!-- Menu -->
<aside id="layout-menu" class="layout-menu menu-vertical menu bg-menu-theme">
<div class="app-brand demo">
<a href="javascript:wctx.home();" class="app-brand-link">
<span class="app-brand-logo demo">
<svg
width="25"
viewBox="0 0 25 42"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<path
d="M13.7918663,0.358365126 L3.39788168,7.44174259 C0.566865006,9.69408886 -0.379795268,12.4788597 0.557900856,15.7960551 C0.68998853,16.2305145 1.09562888,17.7872135 3.12357076,19.2293357 C3.8146334,19.7207684 5.32369333,20.3834223 7.65075054,21.2172976 L7.59773219,21.2525164 L2.63468769,24.5493413 C0.445452254,26.3002124 0.0884951797,28.5083815 1.56381646,31.1738486 C2.83770406,32.8170431 5.20850219,33.2640127 7.09180128,32.5391577 C8.347334,32.0559211 11.4559176,30.0011079 16.4175519,26.3747182 C18.0338572,24.4997857 18.6973423,22.4544883 18.4080071,20.2388261 C17.963753,17.5346866 16.1776345,15.5799961 13.0496516,14.3747546 L10.9194936,13.4715819 L18.6192054,7.984237 L13.7918663,0.358365126 Z"
id="path-1"
></path>
<path
d="M5.47320593,6.00457225 C4.05321814,8.216144 4.36334763,10.0722806 6.40359441,11.5729822 C8.61520715,12.571656 10.0999176,13.2171421 10.8577257,13.5094407 L15.5088241,14.433041 L18.6192054,7.984237 C15.5364148,3.11535317 13.9273018,0.573395879 13.7918663,0.358365126 C13.5790555,0.511491653 10.8061687,2.3935607 5.47320593,6.00457225 Z"
id="path-3"
></path>
<path
d="M7.50063644,21.2294429 L12.3234468,23.3159332 C14.1688022,24.7579751 14.397098,26.4880487 13.008334,28.506154 C11.6195701,30.5242593 10.3099883,31.790241 9.07958868,32.3040991 C5.78142938,33.4346997 4.13234973,34 4.13234973,34 C4.13234973,34 2.75489982,33.0538207 2.37032616e-14,31.1614621 C-0.55822714,27.8186216 -0.55822714,26.0572515 -4.05231404e-15,25.8773518 C0.83734071,25.6075023 2.77988457,22.8248993 3.3049379,22.52991 C3.65497346,22.3332504 5.05353963,21.8997614 7.50063644,21.2294429 Z"
id="path-4"
></path>
<path
d="M20.6,7.13333333 L25.6,13.8 C26.2627417,14.6836556 26.0836556,15.9372583 25.2,16.6 C24.8538077,16.8596443 24.4327404,17 24,17 L14,17 C12.8954305,17 12,16.1045695 12,15 C12,14.5672596 12.1403557,14.1461923 12.4,13.8 L17.4,7.13333333 C18.0627417,6.24967773 19.3163444,6.07059163 20.2,6.73333333 C20.3516113,6.84704183 20.4862915,6.981722 20.6,7.13333333 Z"
id="path-5"
></path>
</defs>
<g id="g-app-brand" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Brand-Logo" transform="translate(-27.000000, -15.000000)">
<g id="Icon" transform="translate(27.000000, 15.000000)">
<g id="Mask" transform="translate(0.000000, 8.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use fill="#696cff" xlink:href="#path-1"></use>
<g id="Path-3" mask="url(#mask-2)">
<use fill="#696cff" xlink:href="#path-3"></use>
<use fill-opacity="0.2" fill="#FFFFFF" xlink:href="#path-3"></use>
</g>
<g id="Path-4" mask="url(#mask-2)">
<use fill="#696cff" xlink:href="#path-4"></use>
<use fill-opacity="0.2" fill="#FFFFFF" xlink:href="#path-4"></use>
</g>
</g>
<g
id="Triangle"
transform="translate(19.000000, 11.000000) rotate(-300.000000) translate(-19.000000, -11.000000) "
>
<use fill="#696cff" xlink:href="#path-5"></use>
<use fill-opacity="0.2" fill="#FFFFFF" xlink:href="#path-5"></use>
</g>
</g>
</g>
</g>
</svg>
</span>
<span class="app-brand-text demo menu-text fw-bolder ms-2">XIT Base</span>
</a>
<a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large ms-auto">
<i class="bx bx-chevron-left bx-sm align-middle"></i>
</a>
</div>
<div class="menu-inner-shadow"></div>
<ul id="menus" class="menu-inner py-1">
</ul>
</aside>
<!-- / Menu -->
<c:set var="userMenus" scope="request">let userMenus = ${userMenus};
<%--if (menus.length < 1)
menus = [
{"id":0, "name": "사용자", "url":"/user/main.do", "parentID":null, "description":"사용자 관리", "imagePath":null, "displayWindow":"_self"},
{"id":1, "name": "권한", "url":null, "parentID":null, "description":"권한 관리", "imagePath":null, "displayWindow":"_self",
"children":[
{"id":2, "name": "권한 설정", "url":"/authority/list.do", "parentID":1, "description":"권한 관리", "imagePath":null, "displayWindow":"_self"},
{"id":3, "name": "액션 설정", "url":"/authority/action/list.do", "parentID":1, "description":"액션 관리", "imagePath":null, "displayWindow":"_self"},
]
},
{"id":4, "name": "메뉴", "url":"/menu/list.do", "parentID":null, "description":"메뉴 관리", "imagePath":null, "displayWindow":"_self"}
];--%>
function setUserMenus(menus) {
let menuSupport = new MenuSupport("#layout-menu").setMenuInfo(menus).setActive(wctx.current());
let currentMenu = menuSupport.getMenu(wctx.current());
if (currentMenu)
setPageTitle(currentMenu.name);
}
setUserMenus(userMenus);
</c:set>

@ -0,0 +1,30 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<jsp:include page="/WEB-INF/jsp/include/head.jsp" />
<body>
<!-- Layout wrapper -->
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<jsp:include page="/WEB-INF/jsp/include/userMenus.jsp" />
<!-- Layout container -->
<div class="layout-page">
<jsp:include page="/WEB-INF/jsp/include/top.jsp" />
</div>
<!-- / Layout page -->
</div>
</div>
<!-- / Layout wrapper -->
<jsp:include page="/WEB-INF/jsp/include/tail.jsp" />
<script >
${functions}
${userMenus}
$(function(){
${onload}
});
</script>
</body>
</html>

@ -0,0 +1,157 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<jsp:include page="/WEB-INF/jsp/include/head.jsp" />
<body>
<!-- Content -->
<div class="authentication-wrapper authentication-cover">
<div class="authentication-inner row m-0">
<!-- /Left Text -->
<div class="d-none d-lg-flex col-lg-7 col-xl-8 align-items-center p-5">
<div class="w-100 d-flex justify-content-center">
<img
src="<c:url value="/resources/img/illustrations/boy-with-rocket-light.png"/>"
class="img-fluid"
alt="Login image"
width="700"
data-app-dark-img="illustrations/boy-with-rocket-dark.png"
data-app-light-img="illustrations/boy-with-rocket-light.png"
/>
</div>
</div>
<!-- /Left Text -->
<!-- Login -->
<div class="d-flex col-12 col-lg-5 col-xl-4 align-items-center authentication-bg p-sm-5 p-4" style="background-color:white;">
<div class="w-px-400 mx-auto">
<!-- Logo -->
<div class="app-brand mb-5">
<a href="index.html" class="app-brand-link gap-2">
<span class="app-brand-logo demo">
<svg
width="25"
viewBox="0 0 25 42"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<path
d="M13.7918663,0.358365126 L3.39788168,7.44174259 C0.566865006,9.69408886 -0.379795268,12.4788597 0.557900856,15.7960551 C0.68998853,16.2305145 1.09562888,17.7872135 3.12357076,19.2293357 C3.8146334,19.7207684 5.32369333,20.3834223 7.65075054,21.2172976 L7.59773219,21.2525164 L2.63468769,24.5493413 C0.445452254,26.3002124 0.0884951797,28.5083815 1.56381646,31.1738486 C2.83770406,32.8170431 5.20850219,33.2640127 7.09180128,32.5391577 C8.347334,32.0559211 11.4559176,30.0011079 16.4175519,26.3747182 C18.0338572,24.4997857 18.6973423,22.4544883 18.4080071,20.2388261 C17.963753,17.5346866 16.1776345,15.5799961 13.0496516,14.3747546 L10.9194936,13.4715819 L18.6192054,7.984237 L13.7918663,0.358365126 Z"
id="path-1"
></path>
<path
d="M5.47320593,6.00457225 C4.05321814,8.216144 4.36334763,10.0722806 6.40359441,11.5729822 C8.61520715,12.571656 10.0999176,13.2171421 10.8577257,13.5094407 L15.5088241,14.433041 L18.6192054,7.984237 C15.5364148,3.11535317 13.9273018,0.573395879 13.7918663,0.358365126 C13.5790555,0.511491653 10.8061687,2.3935607 5.47320593,6.00457225 Z"
id="path-3"
></path>
<path
d="M7.50063644,21.2294429 L12.3234468,23.3159332 C14.1688022,24.7579751 14.397098,26.4880487 13.008334,28.506154 C11.6195701,30.5242593 10.3099883,31.790241 9.07958868,32.3040991 C5.78142938,33.4346997 4.13234973,34 4.13234973,34 C4.13234973,34 2.75489982,33.0538207 2.37032616e-14,31.1614621 C-0.55822714,27.8186216 -0.55822714,26.0572515 -4.05231404e-15,25.8773518 C0.83734071,25.6075023 2.77988457,22.8248993 3.3049379,22.52991 C3.65497346,22.3332504 5.05353963,21.8997614 7.50063644,21.2294429 Z"
id="path-4"
></path>
<path
d="M20.6,7.13333333 L25.6,13.8 C26.2627417,14.6836556 26.0836556,15.9372583 25.2,16.6 C24.8538077,16.8596443 24.4327404,17 24,17 L14,17 C12.8954305,17 12,16.1045695 12,15 C12,14.5672596 12.1403557,14.1461923 12.4,13.8 L17.4,7.13333333 C18.0627417,6.24967773 19.3163444,6.07059163 20.2,6.73333333 C20.3516113,6.84704183 20.4862915,6.981722 20.6,7.13333333 Z"
id="path-5"
></path>
</defs>
<g id="g-app-brand" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Brand-Logo" transform="translate(-27.000000, -15.000000)">
<g id="Icon" transform="translate(27.000000, 15.000000)">
<g id="Mask" transform="translate(0.000000, 8.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use fill="#696cff" xlink:href="#path-1"></use>
<g id="Path-3" mask="url(#mask-2)">
<use fill="#696cff" xlink:href="#path-3"></use>
<use fill-opacity="0.2" fill="#FFFFFF" xlink:href="#path-3"></use>
</g>
<g id="Path-4" mask="url(#mask-2)">
<use fill="#696cff" xlink:href="#path-4"></use>
<use fill-opacity="0.2" fill="#FFFFFF" xlink:href="#path-4"></use>
</g>
</g>
<g
id="Triangle"
transform="translate(19.000000, 11.000000) rotate(-300.000000) translate(-19.000000, -11.000000) "
>
<use fill="#696cff" xlink:href="#path-5"></use>
<use fill-opacity="0.2" fill="#FFFFFF" xlink:href="#path-5"></use>
</g>
</g>
</g>
</g>
</svg>
</span>
<span class="app-brand-text demo text-body fw-bolder">XIT Base Example</span>
</a>
</div>
<!-- /Logo -->
<h4 class="mb-2">반갑습니다, XIT Base입니다. 👋</h4>
<p class="mb-4">이 사이트는 XIT Base로 만든 예제 사이트 입니다.</p>
<div id="formAuthentication" class="mb-3">
<div class="mb-3">
<label for="userId" class="form-label">아이디</label>
<input id="userId" type="text" required class="form-control" placeholder="아이디를 입력하십시오." autofocus />
</div>
<div class="mb-3 form-password-toggle">
<div class="d-flex justify-content-between">
<label class="form-label" for="password">비밀번호</label>
<a href="auth-forgot-password-cover.html">
<small>비밀번호 찾기</small>
</a>
</div>
<div class="input-group input-group-merge">
<input id="password" type="password" required class="form-control" placeholder="비밀번호를 입력하십시오." aria-describedby="password" />
<span class="input-group-text cursor-pointer"><i class="bx bx-hide"></i></span>
</div>
</div>
<button class="btn btn-primary d-grid w-100" onclick="login();">로그인</button>
</div>
</div>
</div>
<!-- /Login -->
</div>
</div>
<!-- / Content -->
<jsp:include page="/WEB-INF/jsp/include/tail.jsp" />
<!-- Main JS -->
<script>
${functions}
function login() {
if (!$("#formAuthentication input").validInputs()) return;
var params = {
account:$("#userId").val(),
password:$("#password").val(),
institute:"default"
};
json.post({
url:wctx.url("/login.do"),
data:params,
success:function(resp) {
if (resp.authenticated) {
if (resp.message)
dialog.alert(resp.message);
wctx.home();
} else {
dialog.alert({
content:resp.reason,
onClose:() => $("#userId").focus()
});
}
}
});
}
$(function(){
$("#formAuthentication input").onEnterPress(login);
});
</script>
</body>
</html>

@ -0,0 +1,56 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@ include file="/WEB-INF/jsp/include/taglib.jsp"%>
<link rel="stylesheet" href="<c:url value="/resources/3rd-party/sneat/libs/jstree/jstree.css"/>" /--%>
<div id="_url-tree" class="main-left d-flex flex-column flex-grow-1">
<div class="d-flex justify-content-between" style="padding-top:.5em; padding-bottom:.5em; border-top:1px solid #dfdfdf; border-bottom:1px solid #dfdfdf;">
<span>
<button id="_urlToggler" onclick="_toggleURLs();" class="btn btn-primary"></button>
</span>
</div>
<div id="_urlTree" style="padding-top:1em; height:37em; overflow:auto;">
</div>
</div>
<script src="<c:url value="/resources/3rd-party/sneat/libs/jstree/jstree.js"/>"></script>
<script src="<c:url value="/resources/3rd-party/jstree/jstree-support.js"/>"></script>
<script type="text/javascript">
var _multiple = ${multiple},
_urlSupport = treeSupport({
selector:"#_urlTree",
trace:wctx.trace,
plugins: _multiple ? ["checkbox"] : [],
core:{check_callback:true,
multiple:_multiple
// themes:{name:"proton"}
},
checkbox:{
whole_node:false,
tie_selection:false
}
});
function getSelectedURL() {
var selected = _multiple ? _urlSupport.checkedNodes() : _urlSupport.selectedNodes();
if (selected.length < 1)
return dialog.alert("URL을 선택하십시오.");
if (_multiple)
return selected;
else
return selected[0];
}
function _toggleURLs() {
$("#_urlToggler").text(_urlSupport.toggleFolding() == "collapsed" ? "+ 펼치기" : "- 닫기");
}
var urls = ${urls};
_urlSupport.setData(treeHtml(urls, {
id:function(e){return e.url;},
text:function(e){
return e.name == e.url ? e.name : e.name + " (" + e.url + ")";
}
}));
$("#_urlToggler").text(_urlSupport._folding == "collapsed" ? "+ 펼치기" : "- 닫기");
</script>

@ -42,12 +42,6 @@
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<context-param>
<param-name>spring.liveBeansView.mbeanDomain</param-name>
<param-value>local</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring/context-*.xml</param-value>
@ -69,8 +63,6 @@
<servlet-name>action</servlet-name>
<url-pattern>/</url-pattern>
<url-pattern>*.do</url-pattern>
<!-- FIMS 추가 -->
<url-pattern>*.ajax</url-pattern>
</servlet-mapping>
<servlet-mapping>

@ -0,0 +1,114 @@
class ActionGroupControl {
constructor(linked) {
this.linked = false !== linked;
this.groups = new DatasetControl({
prefix:"group",
prefixName:"기능그룹",
keymapper:info => info.GRP_ID,
dataGetter:obj => obj.groupList,
formats: {
REG_DT:datetimeFormat
},
urls:{
load:wctx.url("/actionGroup/list.do"),
getInfo:wctx.url("/actionGroup/info.do"),
create:wctx.url("/actionGroup/create.do"),
update:wctx.url("/actionGroup/update.do"),
remove:wctx.url("/actionGroup/remove.do")
}
});
this.actions = new DatasetControl({
prefix:"action",
prefixName:"기능",
keymapper:info => info.GRP_ID + "-" + info.ACTION,
dataGetter:obj => obj.actionList,
formats: {
REG_DT:datetimeFormat
},
urls:{
load:wctx.url("/actionGroup/action/list.do")
}
});
this.actions.urls.load = wctx.url("/actionGroup/action/list.do")
this.groups.onDatasetChange = obj => this.onGroupListChange(obj);
this.groups.onCurrentChange = item => {
this.onCurrentGroupChange(item);
if (!this.linked) return;
let row = item ? item.data : null;
if (row) {
this.actions.query.groupIDs = row.GRP_ID;
this.actions.load();
} else
this.actions.dataset.clear();
};
this.groups.onSelectionChange = selected => this.onGroupSelect(selected);
this.actions.onDatasetChange = obj => this.onActionListChange(obj);
this.actions.onCurrentChange = item => this.onCurrentActionChange(item);
this.actions.onSelectionChange = selected => this.onActionSelect(selected);
}
onGroupListChange(obj) {}
onCurrentGroupChange(item) {}
onGroupSelect(selected) {}
async selectActionGroup() {
return new Promise((resolve, reject) => {
ajax.get({
url:wctx.url("/actionGroup/select.do"),
data:{multiple:true},
success:resp => {
dialog.open({
title:"기능그룹 선택",
content:resp,
getData:() => {return getSelectedActionGroup();},
onOK:(selected) => resolve(selected)
});
}
});
});
}
onActionListChange(obj) {}
onCurrentActionChange(item) {}
onActionSelect(selected) {}
async addActions() {
let actions = await selectURL(true);
actions = actions.filter(a => "/" == a || a.endsWith(".do"));
let groupID = this.groups.dataset.getCurrent().GRP_ID;
json.post({
url:wctx.url("/actionGroup/action/add.do"),
data:{
groupID:groupID,
actions:actions.join(",")
},
success:resp => {
this.actions._load();
}
});
}
removeActions() {
let selected = this.actions.dataset.getDataset("selected").map(info => info.ACTION);
let groupID = this.groups.dataset.getCurrent().GRP_ID;
json.post({
url:wctx.url("/actionGroup/action/remove.do"),
data:{
groupID:groupID,
actions:selected.join(",")
},
success:resp => {
if (resp.saved)
this.actions._load();
}
});
}
}

@ -0,0 +1,188 @@
class AuthorityControl {
constructor() {
this.authorities = new DatasetControl({
prefix:"authority",
prefixName:"권한",
keymapper:info => info.AUTH_ID,
dataGetter:obj => obj.authorityList,
formats: {
REG_DT:datetimeFormat
}
});
this.authorities.isBuiltIn = (info) => {
let current = info || this.authorities.getCurrent();
return current && current.AUTH_TYPE < 2;
};
this.authorities.isImplicit = (info) => {
let current = info || this.authorities.getCurrent();
return current && current.AUTH_TYPE === 1;
};
this.authorities.isAdmin = (info) => {
let current = info || this.authorities.getCurrent();
return current && current.AUTH_TYPE === 0;
};
this.users = new DatasetControl({
prefix:"user",
prefixName:"사용자",
keymapper:info => info.AUTH_ID + "-" + info.USER_ID,
dataGetter:obj => obj.userList,
formats: {
REG_DT:datetimeFormat
},
urls:{
load:wctx.url("/authority/user/list.do")
}
});
this.actions = new DatasetControl({
prefix:"action",
prefixName:"기능 그룹",
keymapper:info => info.AUTH_ID + "-" + info.GRP_ID,
dataGetter:obj => obj.actionList,
formats: {
REG_DT:datetimeFormat
},
urls:{
load:wctx.url("/authority/action/list.do")
}
});
this.linkedList = "users";
this.authorities.onDatasetChange = obj => this.onAuthorityListChange(obj);
this.authorities.onCurrentChange = item => {
this.onCurrentAuthorityChange(item);
let info = item ? item.data : null;
this.getLinkedList(this.linkedList, info);
};
this.authorities.onSelectionChange = selected => this.onAuthoritySelect(selected);
this.users.onDatasetChange = obj => this.onUserListChange(obj);
this.users.onCurrentChange = item => this.onCurrentUserChange(item);
this.users.onSelectionChange = selected => this.onUserSelect(selected);
this.actions.onDatasetChange = obj => this.onActionListChange(obj);
this.actions.onCurrentChange = item => this.onCurrentActionChange(item);
this.actions.onSelectionChange = selected => this.onActionSelect(selected);
}
getLinkedList(linked, info) {
if (!info)
info = this.authorities.getCurrent();
switch (this.linkedList = linked) {
case "users":
if (info && !this.authorities.isImplicit(info)) {
if (this.users.query.authIDs == info.AUTH_ID) return;
this.users.query.authIDs = info.AUTH_ID;
this.users.load();
} else {
this.users.query.authIDs = info.AUTH_ID;
this.users.dataset.clear();
}
break;
case "actions":
if (info && !this.authorities.isAdmin(info)) {
if (this.actions.query.authIDs == info.AUTH_ID) return;
this.actions.query.authIDs = info.AUTH_ID;
this.actions.load();
} else {
this.actions.query.authIDs = info.AUTH_ID;
this.actions.dataset.clear();
}
break;
default: break;
}
}
onAuthorityListChange(obj) {}
onCurrentAuthorityChange(item) {}
onAuthoritySelect(selected) {}
removeAuthorities() {
let authIDs = this.authorities.dataset.getKeys("selected");
this.authorities.remove({authIDs:authIDs.join(",")});
}
onUserListChange(obj) {}
onCurrentUserChange(item) {}
onUserSelect(selected) {}
onActionListChange(obj) {}
onCurrentActionChange(item) {}
onActionSelect(selected) {}
async addUsers() {
let userIDs = await new UserControl().selectUser(true);
let authID = this.authorities.dataset.getCurrent().AUTH_ID;
json.post({
url:wctx.url("/authority/user/add.do"),
data:{
authID:authID,
userIDs:userIDs.join(",")
},
success:resp => {
if (resp.saved)
this.users._load();
}
});
}
removeUsers() {
let selected = this.users.dataset.getDataset("selected").map(info => info.USER_ID);
let authID = this.authorities.dataset.getCurrent().AUTH_ID;
json.post({
url:wctx.url("/authority/user/remove.do"),
data:{
authID:authID,
userIDs:selected.join(",")
},
success:resp => {
if (resp.saved)
this.users._load();
}
});
}
async addActions() {
let actions = await new ActionGroupControl(false).selectActionGroup(true);
let authID = this.authorities.dataset.getCurrent().AUTH_ID;
json.post({
url:wctx.url("/authority/action/add.do"),
data:{
authID:authID,
groupIDs:actions.join(",")
},
success:resp => {
if (resp.saved)
this.actions._load();
}
});
}
removeActions() {
let selected = this.actions.dataset.getDataset("selected").map(info => info.GRP_ID);
let authID = this.authorities.dataset.getCurrent().AUTH_ID;
json.post({
url:wctx.url("/authority/action/remove.do"),
data:{
authID:authID,
groupIDs:selected.join(",")
},
success:resp => {
if (resp.saved)
this.actions._load();
}
});
}
}

@ -226,8 +226,8 @@ var ajax = {
return success(resp);
dialog.alert({
content:resp.message,
onClose:"sessionExpired" == resp.status ? wctx.home : undefined
title:resp.title,
content:resp.message
});
debug("stacktrace", stacktrace);
@ -684,7 +684,7 @@ class FormFields {
if (value && value == input.value)
input.checked = true;
} else {
input.value = value;
input.value = value || "";
}
});
}

@ -0,0 +1,63 @@
class CodeControl {
constructor() {
this.groups = new DatasetControl({
prefix:"group",
prefixName:"코드그룹",
keymapper:info => info.GRP_ID,
dataGetter:obj => obj.groupList,
formats: {
REG_DT:datetimeFormat
},
urls:{
load:wctx.url("/code/group/list.do"),
getInfo:wctx.url("/code/group/info.do"),
create:wctx.url("/code/group/create.do"),
update:wctx.url("/code/group/update.do"),
remove:wctx.url("/code/group/remove.do")
}
});
this.codes = new DatasetControl({
prefix:"code",
prefixName:"코드",
keymapper:info => info.CODE,
dataGetter:obj => obj.codeList,
formats: {
REG_DT:datetimeFormat
}
});
this.groups.onDatasetChange = obj => this.onGroupListChange(obj);
this.groups.onCurrentChange = item => {
this.onCurrentGroupChange(item);
let info = item ? item.data : null;
if (info) {
this.codes.query.groupIDs = info.GRP_ID;
this.codes.load();
} else
this.codes.dataset.clear();
};
this.groups.onSelectionChange = selected => this.onGroupSelect(selected);
this.codes.onDatasetChange = obj => this.onCodeListChange(obj);
this.codes.onCurrentChange = item => this.onCurrentCodeChange(item);
this.codes.onSelectionChange = selected => this.onCodeSelect(selected);
}
onGroupListChange(obj) {}
onCurrentGroupChange(item) {}
onGroupSelect(selected) {}
newCode() {
this.codes.newInfo({GRP_ID:this.groups.getCurrent().GRP_ID})
}
onCodeListChange(obj) {}
onCurrentCodeChange(item) {}
onCodeSelect(selected) {}
}

@ -39,9 +39,10 @@ const dateFormat = {
* @returns {string} formatted value
*/
format(value) {
let date = value instanceof Date ? value : "number" == typeof(value) ? new Date(value) : null;
if (!date) return "";
if (isEmpty(value)) return "";
let _format = v => {
let date = "number" == typeof v ? new Date(v) : v;
let year = date.getFullYear(),
month = date.getMonth() + 1,
day = date.getDate();
@ -50,6 +51,14 @@ const dateFormat = {
if (day < 10)
day = "0" + day;
return year + "-" + month + "-" + day;
};
switch (value instanceof Date ? "date" : typeof value) {
case "number":
case "date": return _format(value);
case "string": return value.substr(0, 4) + "-" + value.substr(4, 2) + "-" + value.substr(6, 2);
default: return "";
}
}
};
@ -60,8 +69,17 @@ const datetimeFormat = {
* @returns {string} formatted value
*/
format(value) {
let date = value instanceof Date ? value : "number" == typeof(value) ? new Date(value) : null;
return dateFormat.format(date) + " " + date.toLocaleTimeString();
let _format = v => {
let date = "number" == typeof v ? new Date(v) : v;
return date.toLocaleTimeString();
};
switch (value instanceof Date ? "date" : typeof value) {
case "number":
case "date": return dateFormat.format(value) + " " + _format(value);
case "string": return dateFormat.format(value) + " " + value.substr(8, 2) + ":" + value.substr(10, 2) + ":" + value.substr(12)
default: return "";
}
}
};
@ -1248,7 +1266,7 @@ class DatasetControl {
let item = this.getCurrent("item"),
create = "added" == item.state;
json.post({
ajax.post({
url:!create ? this.urls.update : this.urls.create,
data:info,
success:resp => this.onSave(resp)
@ -1272,7 +1290,7 @@ class DatasetControl {
params[this.prefixed("IDs")] = selected.join(",");
}
json.post({
ajax.post({
url:this.urls.remove,
data:params,
success:resp => this.onRemove(selected, resp)

@ -0,0 +1,174 @@
/** .
*/
class MenuSupport {
/** MenuSupport .
* @param selector {string} 메뉴를 담을 컨테이너에 대한 css selector
*/
constructor(selector) {
this._container = document.querySelector(this._selector = selector);
this._horizontal = this._container && this._container.classList.contains('menu-horizontal');
this._orientation = this._horizontal ? "horizontal" : "vertical";
this._template = this._orientation + "-menu-template";
this._menuItem = '<li data-key="{menuID}" class="menu-item"><a href="{url}" class="menu-link{toggle}"><i class="menu-icon tf-icons bx bx-layout"></i><div data-i18n="{menuName}">{menuName}</div></a>{menuSub}</li>';
this._menuSub = '<ul class="menu-sub">{children}</ul>';
this._menus = [];
}
/** .
* @param menus {array} 메뉴 정보 배열<br />
* 메뉴 정보의 레이아웃은 다음과 같다.<br />
* {"id":메뉴 아이디, "name":"메뉴 이름", "url":"실행 url", "parentID":"상위 메뉴 아이디", "description":"메뉴 설명", "imagePath":"이미지 경로", "displayWindow":"표시 창", "children":[하위 메뉴 배열]}
* @returns MenuSupport
*/
setMenuInfo(menus) {
let setParent = menu => {
let children = menu.children || [];
if (children.length < 1) return;
children.forEach(child => {
child.parent = menu;
setParent(child);
});
};
menus.forEach(menu => setParent(menu));
this._menus = menus;
let menuItemTag = menu => {
let tag = this._menuItem
.replace(/{menuID}/gi, menu.id)
.replace(/{menuName}/gi, menu.name)
.replace(/{url}/gi, !menu.url ? "javascript:void(0);" : wctx.url(menu.url));
let parent = menu.children && menu.children.length > 0;
tag = tag.replace(/{toggle}/gi, !parent ? "" : " menu-toggle");
if (!parent)
return tag.replace(/{menuSub}/gi, "");
let children = menu.children.map(child => menuItemTag(child)).join("\n\t")
return tag.replace(/{menuSub}/gi, this._menuSub.replace(/{children}/gi, children));
}
let tags = (menus || []).map(menu => menuItemTag(menu));
document.querySelector("#menus").innerHTML = tags.join("");
return this._init();
}
_init() {
document.querySelectorAll(this._selector).forEach(element => {
let menu = new Menu(element, {
orientation: this._orientation,
closeChildren: this._horizontal,
showDropdownOnHover: localStorage.getItem('templateCustomizer-' + this._template + '--ShowDropdownOnHover')
? localStorage.getItem('templateCustomizer-' + this._template + '--ShowDropdownOnHover') === 'true'
: window.templateCustomizer !== undefined
? window.templateCustomizer.settings.defaultShowDropdownOnHover
: true
});
window.Helpers.scrollToActive(false); //animate = false
window.Helpers.mainMenu = menu;
});
//Sets toggler
document.querySelectorAll('.layout-menu-toggle').forEach(item => {
item.addEventListener('click', event => {
event.preventDefault();
window.Helpers.toggleCollapsed();
if (config.enableMenuLocalStorage && !window.Helpers.isSmallScreen()) {
try {
localStorage.setItem(
'templateCustomizer-' + this._template + '--LayoutCollapsed',
String(window.Helpers.isCollapsed())
);
} catch (e) {}
}
});
});
// Display menu toggle (layout-menu-toggle) on hover with delay
let delay = (elem, callback) => {
let timeout = null;
elem.onmouseenter = () => {
// Set timeout to be a timer which will invoke callback after 300ms (not for small screen)
timeout = !Helpers.isSmallScreen() ? setTimeout(callback, 300) : setTimeout(callback, 0);
};
elem.onmouseleave = () => {
// Clear any timers set to timeout
document.querySelector('.layout-menu-toggle').classList.remove('d-block');
clearTimeout(timeout);
};
};
if (this._container) {
delay(this._container, () => {
// not for small screen
if (!Helpers.isSmallScreen()) {
document.querySelector('.layout-menu-toggle').classList.add('d-block');
}
});
}
return this;
}
/** url .
* @param url {string} 메뉴 url
* @returns MenuSupport
*/
setActive(url) {
document
.querySelectorAll(this._selector + " li")
.forEach(li => li.classList.remove("active", "open"));
let a = document.querySelector(this._selector + ' a[href=\"' + wctx.url(url) + '\"]');
if (!a) return this;
let activate = (e, open) => {
let p = e.parentNode;
let tag = (p != this._container ? p : null) ? p.tagName : "";
if (!tag) return;
if ("li" == tag.toLowerCase()) {
p.classList.add("active");
if (open)
p.classList.add("open");
}
activate(p, true);
};
activate(a);
return this;
}
/** url .
* @param url {string} 메뉴 url
* @returns 지정하는 url의 메뉴 정보
*/
getMenu(url) {
let find = menus => {
for (let i = 0; i < menus.length; ++i) {
let menu = menus[i];
if (url == menu.url)
return menu;
let found = find(menu.children || []);
if (found)
return found;
}
return null;
};
return find(this._menus);
}
breadcrumb(url, separator = " / ") {
let menu = this.getMenu(url);
if (!menu)
return "";
let getName = menu => {
let name = menu.name;
let parent = !menu.parent ? "" : getName(menu.parent);
return parent ? parent + separator + name : name;
}
return getName(menu);
}
}

@ -0,0 +1,77 @@
class MenuControl extends DatasetControl {
constructor() {
super({
keymapper: info => info ? info.id : "",
prefix:"menu",
prefixName:"메뉴"
});
this.urls.load = this.url("/tree.do");
delete this.urls.getInfo;
this.menus = [];
}
setData(obj) {
let list = [];
let asList = array => {
if (!array || array.length < 1) return;
for (var i = 0; i < array.length; ++i) {
let menu = array[i];
list.push(menu);
asList(menu.children);
}
};
asList(this.menus = Array.isArray(obj) ? obj : obj.menus);
super.setData(list);
}
move(parentID, menuID) {
json.post({
url:wctx.url("/menu/move.do"),
data:{
parentID:parentID,
menuIDs:menuID
},
success:resp => {
this._load();
this.onMenusChanged();
}
});
}
reorder(menuIDs) {
json.post({
url:wctx.url("/menu/reorder.do"),
data:{
menuIDs:Array.isArray(menuIDs) ? menuIDs.join(",") : menuIDs
},
success:resp => {
this._load();
this.onMenusChanged();
}
});
}
onSave(resp) {
super.onSave(resp);
this.onMenusChanged();
}
onRemove(selected, resp) {
super.onRemove(selected, resp);
this.onMenusChanged();
}
onMenusChanged() {}
async getUserMenus() {
return new Promise((resolve, reject) => {
json.get({
url:this.url("/userMenus.do"),
data:{},
success:resp => resolve(resp.userMenus)
});
});
}
}

@ -0,0 +1,31 @@
class UserControl extends DatasetControl {
constructor(conf) {
super(conf || {
prefix:"user",
prefixName:"사용자",
infoSize:"xl",
keymapper:info => info ? info.USER_ID : "",
dataGetter:obj => obj.userList,
formats: {
REG_DT:datetimeFormat
}
});
}
async selectUser(multiple) {
return new Promise((resolve, reject) => {
ajax.get({
url:this.url("/select.do"),
data:{multiple:multiple},
success:resp => {
dialog.open({
title:"사용자 선택",
content:resp,
getData:() => {return getSelectedUser();},
onOK:(selected) => resolve(selected)
});
}
});
});
}
}
Loading…
Cancel
Save