Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a884e53e3 | |||
| 7de00ecad2 |
Vendored
-189
@@ -1,189 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent none
|
|
||||||
|
|
||||||
options {
|
|
||||||
timestamps()
|
|
||||||
disableConcurrentBuilds()
|
|
||||||
skipDefaultCheckout() // stage별 agent의 자동 SCM checkout 방지 (Deploy 노드는 git 접근 불필요, unstash로만 WAR 수신)
|
|
||||||
buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '20'))
|
|
||||||
}
|
|
||||||
|
|
||||||
environment {
|
|
||||||
GIT_SSH_COMMAND = 'ssh -o StrictHostKeyChecking=accept-new'
|
|
||||||
WEBHOOK_URL = 'http://172.30.1.50:18000/api/hooks/01ba51b01d3c4c98ae8f3183a23a84ed713197857d024b5da4f303458195eb32'
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('Build (djb-vm)') {
|
|
||||||
agent { label 'djb-vm' }
|
|
||||||
environment {
|
|
||||||
JAVA_HOME = '/apps/opts/jdk8'
|
|
||||||
GRADLE_HOME = '/apps/opts/gradle-8.7'
|
|
||||||
GRADLE_USER_HOME = '/apps/opts/gradle-home'
|
|
||||||
NODE_HOME = '/apps/opts/node-v24'
|
|
||||||
PATH = "/apps/opts/jdk8/bin:/apps/opts/gradle-8.7/bin:/apps/opts/node-v24/bin:/apps/opts/bin:${env.PATH}"
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps { checkout scm }
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Checkout dependencies') {
|
|
||||||
steps {
|
|
||||||
sh '''
|
|
||||||
set -eu
|
|
||||||
cd "$WORKSPACE/.."
|
|
||||||
|
|
||||||
mkdir -p eapim-online
|
|
||||||
|
|
||||||
for REPO in elink-online-core elink-online-core-jpa elink-online-transformer elink-online-common elink-online-emsclient; do
|
|
||||||
TARGET="eapim-online/$REPO"
|
|
||||||
if [ ! -d "$TARGET/.git" ]; then
|
|
||||||
rm -rf "$TARGET"
|
|
||||||
git clone --depth=1 --branch master \
|
|
||||||
"ssh://git@172.30.1.50:2222/djb-eapim/$REPO.git" \
|
|
||||||
"$TARGET"
|
|
||||||
else
|
|
||||||
git -C "$TARGET" fetch --depth=1 origin master
|
|
||||||
git -C "$TARGET" reset --hard origin/master
|
|
||||||
git -C "$TARGET" clean -fdx
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
for REPO in elink-portal-common eapim-admin-djb; do
|
|
||||||
if [ ! -d "$REPO/.git" ]; then
|
|
||||||
rm -rf "$REPO"
|
|
||||||
git clone --depth=1 --branch master \
|
|
||||||
"ssh://git@172.30.1.50:2222/djb-eapim/$REPO.git" \
|
|
||||||
"$REPO"
|
|
||||||
else
|
|
||||||
git -C "$REPO" fetch --depth=1 origin master
|
|
||||||
git -C "$REPO" reset --hard origin/master
|
|
||||||
git -C "$REPO" clean -fdx
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Verify toolchain') {
|
|
||||||
steps {
|
|
||||||
sh '''
|
|
||||||
set -eu
|
|
||||||
java -version
|
|
||||||
gradle --version
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Build WAR') {
|
|
||||||
steps { sh 'gradle clean build -x test --no-daemon -Pprofile=weblogic' }
|
|
||||||
post {
|
|
||||||
success {
|
|
||||||
sh '''
|
|
||||||
set -eu
|
|
||||||
cd build/libs
|
|
||||||
sha256sum eapim-admin.war > eapim-admin.war.sha256
|
|
||||||
'''
|
|
||||||
archiveArtifacts artifacts: 'build/libs/eapim-admin.war,build/libs/eapim-admin.war.sha256', fingerprint: true
|
|
||||||
stash name: 'war', includes: 'build/libs/eapim-admin.war'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SBOM(CycloneDX) -> xlsx. 산출물 eapim-admin-sbom.xlsx 를 아티팩트로 보관.
|
|
||||||
// 실패해도 배포는 진행하도록 UNSTABLE 로만 표시한다.
|
|
||||||
stage('SBOM') {
|
|
||||||
steps {
|
|
||||||
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
|
|
||||||
sh 'gradle sbomXlsx --no-daemon -Pprofile=weblogic'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
archiveArtifacts allowEmptyArchive: true, artifacts: 'build/reports/sbom/*.xlsx', fingerprint: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Deploy (weblogic)') {
|
|
||||||
agent { label 'weblogic' }
|
|
||||||
environment {
|
|
||||||
JENKINS_NODE_COOKIE = 'dontKillMe' // background weblogic를 빌드 종료 시 죽이지 않게
|
|
||||||
WL_HOME = '/app/eapim/adminportal'
|
|
||||||
WL_DEPLOY_DIR = '/app/eapim/adminportal'
|
|
||||||
WL_WAR_NAME = 'eapim-admin.war'
|
|
||||||
WL_HTTP_PORT = '39120'
|
|
||||||
WL_NOHUP = '/logs/weblogic/domains/eapimDomain/nohup.emsSvr11.out'
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Stop WebLogic') {
|
|
||||||
steps {
|
|
||||||
sh '"$WL_HOME/stopEms11.sh"' // 동기: 완전 종료까지 블록, 미기동 시에도 안전
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Deploy WAR') {
|
|
||||||
steps {
|
|
||||||
unstash 'war'
|
|
||||||
sh '''
|
|
||||||
set -eu
|
|
||||||
cp build/libs/eapim-admin.war "$WL_DEPLOY_DIR/$WL_WAR_NAME"
|
|
||||||
ls -la "$WL_DEPLOY_DIR"
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Start WebLogic and readiness') {
|
|
||||||
steps {
|
|
||||||
sh '''
|
|
||||||
set -eu
|
|
||||||
"$WL_HOME/startEms11.sh" # nohup & 로 백그라운드 기동, 즉시 리턴
|
|
||||||
|
|
||||||
DEADLINE=$(($(date +%s) + 300))
|
|
||||||
STATUS=000
|
|
||||||
while [ "$(date +%s)" -lt "$DEADLINE" ]; do
|
|
||||||
STATUS=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 \
|
|
||||||
"http://localhost:$WL_HTTP_PORT/monitoring/loginForm.do" 2>/dev/null || echo "000")
|
|
||||||
case "$STATUS" in
|
|
||||||
200|302|401) echo "Readiness OK (/monitoring/loginForm.do HTTP $STATUS)"; break ;;
|
|
||||||
esac
|
|
||||||
sleep 3
|
|
||||||
done
|
|
||||||
|
|
||||||
case "$STATUS" in
|
|
||||||
200|302|401) ;;
|
|
||||||
*)
|
|
||||||
echo "Readiness failed within 300s, last HTTP=$STATUS"
|
|
||||||
[ -f "$WL_NOHUP" ] && tail -120 "$WL_NOHUP"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
post {
|
|
||||||
success {
|
|
||||||
node('weblogic') {
|
|
||||||
sh '''
|
|
||||||
set +e
|
|
||||||
payload=$(printf '{"text":"[%s #%s](%s) SUCCESS"}' "$JOB_NAME" "$BUILD_NUMBER" "$BUILD_URL")
|
|
||||||
curl -sS --fail --max-time 5 -H 'Content-Type: application/json' -X POST --data "$payload" "$WEBHOOK_URL" >/dev/null || echo "Webhook failed"
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
failure {
|
|
||||||
node('weblogic') {
|
|
||||||
sh '''
|
|
||||||
set +e
|
|
||||||
payload=$(printf '{"text":"[%s #%s](%s) FAILURE"}' "$JOB_NAME" "$BUILD_NUMBER" "$BUILD_URL")
|
|
||||||
curl -sS --fail --max-time 5 -H 'Content-Type: application/json' -X POST --data "$payload" "$WEBHOOK_URL" >/dev/null || echo "Webhook failed"
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,9 +12,6 @@ PortalTermsManController_약관관리_APIGW_INSERT,UPDATE,DELETE
|
|||||||
ProdClientManController_운영Client (키정보)관리_APIGW_INSERT,UPDATE,DELETE
|
ProdClientManController_운영Client (키정보)관리_APIGW_INSERT,UPDATE,DELETE
|
||||||
ApiSpecController_API스펙관리_APIGW_INSERT,DELETE
|
ApiSpecController_API스펙관리_APIGW_INSERT,DELETE
|
||||||
MessageTemplateManController_메세지템플릿관리_APIGW_INSERT,UPDATE,DELETE
|
MessageTemplateManController_메세지템플릿관리_APIGW_INSERT,UPDATE,DELETE
|
||||||
PortalPartnershipManController_피드백/개선요청관리_APIGW_UNMASK,DELETE
|
PortalPartnershipManController_사업제휴신청관리_APIGW_UNMASK
|
||||||
PortalPropertyController_포탈 프로퍼티 관리_APIGW_UPDATE
|
PortalPropertyController_포탈 프로퍼티 관리_APIGW_UPDATE
|
||||||
PortalUserTermsManController_약관동의 이력_APIGW_UNMASK
|
PortalUserTermsManController_약관동의 이력_APIGW_UNMASK
|
||||||
MessageRequestManController_메세지발송내역_APIGW_UPDATE_STATUS
|
|
||||||
PortalInquiryManController_Q&A문의관리_APIGW_VISIBILITY
|
|
||||||
PortalMenuManController_포탈메뉴관리_APIGW_INSERT,UPDATE,DELETE,TRANSACTION_PLACEMENT,INITIALIZE,TRANSACTION_RELOAD
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
targetNamespace="http://xmlns.oracle.com/weblogic/weblogic-web-app"
|
||||||
|
xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
|
||||||
|
<xs:element name="weblogic-web-app">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="context-root" type="xs:string" minOccurs="0"/>
|
||||||
|
<xs:element name="session-descriptor" minOccurs="0">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="timeout-secs" type="xs:integer" minOccurs="0"/>
|
||||||
|
<xs:element name="persistent-store-type" type="xs:string" minOccurs="0"/>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="container-descriptor" minOccurs="0">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="prefer-application-packages" minOccurs="0">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="package-name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="prefer-application-resources" minOccurs="0">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="resource-name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
</xs:schema>
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app">
|
<weblogic-web-app
|
||||||
|
xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app weblogic-web-app.xsd">
|
||||||
|
|
||||||
<context-root>monitoring</context-root>
|
<context-root>monitoring</context-root>
|
||||||
<session-descriptor>
|
<session-descriptor>
|
||||||
<timeout-secs>1800</timeout-secs>
|
<timeout-secs>1800</timeout-secs>
|
||||||
<cookie-name>JSESSIONID_EMS</cookie-name>
|
|
||||||
<persistent-store-type>replicated_if_clustered</persistent-store-type>
|
<persistent-store-type>replicated_if_clustered</persistent-store-type>
|
||||||
</session-descriptor>
|
</session-descriptor>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@charset "utf-8";
|
@charset "utf-8";
|
||||||
|
|
||||||
.gnb .depth1 > li:hover > a{color:#008cc5;} /* theme */
|
.gnb .depth1 > li:hover > a{color:#008cc5;} /* theme */
|
||||||
.gnb .sitemap-link:hover{color:#008cc5;} /* theme */
|
|
||||||
.gnb .depth1 > li > .red_box{background:#008cc5;}/* theme */
|
.gnb .depth1 > li > .red_box{background:#008cc5;}/* theme */
|
||||||
.gnb .depth2 > li > a:hover{color:#008cc5;}/* theme */
|
.gnb .depth2 > li > a:hover{color:#008cc5;}/* theme */
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@charset "utf-8";
|
@charset "utf-8";
|
||||||
|
|
||||||
.gnb .depth1 > li:hover > a{color:#16a085;} /* theme */
|
.gnb .depth1 > li:hover > a{color:#16a085;} /* theme */
|
||||||
.gnb .sitemap-link:hover{color:#16a085;} /* theme */
|
|
||||||
.gnb .depth1 > li > .red_box{background:#16a085;}/* theme */
|
.gnb .depth1 > li > .red_box{background:#16a085;}/* theme */
|
||||||
.gnb .depth2 > li > a:hover{color:#16a085;}/* theme */
|
.gnb .depth2 > li > a:hover{color:#16a085;}/* theme */
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@charset "utf-8";
|
@charset "utf-8";
|
||||||
|
|
||||||
.gnb .depth1 > li:hover > a{color:#e74c3c;} /* theme */
|
.gnb .depth1 > li:hover > a{color:#e74c3c;} /* theme */
|
||||||
.gnb .sitemap-link:hover{color:#e74c3c;} /* theme */
|
|
||||||
.gnb .depth1 > li > .red_box{background:#e74c3c;}/* theme */
|
.gnb .depth1 > li > .red_box{background:#e74c3c;}/* theme */
|
||||||
.gnb .depth2 > li > a:hover{color:#e74c3c;}/* theme */
|
.gnb .depth2 > li > a:hover{color:#e74c3c;}/* theme */
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@charset "utf-8";
|
@charset "utf-8";
|
||||||
|
|
||||||
.gnb .depth1 > li:hover > a{color:#ff80c0;} /* theme */
|
.gnb .depth1 > li:hover > a{color:#ff80c0;} /* theme */
|
||||||
.gnb .sitemap-link:hover{color:#ff80c0;} /* theme */
|
|
||||||
.gnb .depth1 > li > .red_box{background:#ff80c0;}/* theme */
|
.gnb .depth1 > li > .red_box{background:#ff80c0;}/* theme */
|
||||||
.gnb .depth2 > li > a:hover{color:#ff80c0;}/* theme */
|
.gnb .depth2 > li > a:hover{color:#ff80c0;}/* theme */
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@charset "utf-8";
|
@charset "utf-8";
|
||||||
|
|
||||||
.gnb .depth1 > li:hover > a{color:#be8200;} /* theme */
|
.gnb .depth1 > li:hover > a{color:#be8200;} /* theme */
|
||||||
.gnb .sitemap-link:hover{color:#be8200;} /* theme */
|
|
||||||
.gnb .depth1 > li > .red_box{background:#be8200;}/* theme */
|
.gnb .depth1 > li > .red_box{background:#be8200;}/* theme */
|
||||||
.gnb .depth2 > li > a:hover{color:#be8200;}/* theme */
|
.gnb .depth2 > li > a:hover{color:#be8200;}/* theme */
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ header.sub{position:relative; padding-top:80px;}
|
|||||||
100% { color:rgba(255,96,78,0); }
|
100% { color:rgba(255,96,78,0); }
|
||||||
} */
|
} */
|
||||||
|
|
||||||
.gnb_bg{position:absolute; top:80px; left:0; display:none; width:100%; height:282px; box-sizing:border-box; background:white; box-shadow: 0px 5px 5px 0px rgba(0,0,0,0.2);}
|
.gnb_bg{position:absolute; top:80px; left:0; display:none; width:100%; height:382px; box-sizing:border-box; background:white; box-shadow: 0px 5px 5px 0px rgba(0,0,0,0.2);}
|
||||||
.gnb{position:absolute; top:0px; left:180px; display:inline-block; height:80px; overflow-y:hidden;}
|
.gnb{position:absolute; top:0px; left:230px; display:inline-block; height:80px; overflow-y:hidden;}
|
||||||
.gnb:hover{height:auto; overflow-y:visible;}
|
.gnb:hover{height:auto; overflow-y:visible;}
|
||||||
.gnb:hover + .gnb_bg{display:block;}
|
.gnb:hover + .gnb_bg{display:block;}
|
||||||
.gnb h1{float:left; display:block; width:auto; height:100%; line-height:80px;}
|
.gnb h1{float:left; display:block; width:auto; height:100%; line-height:80px;}
|
||||||
@@ -71,15 +71,15 @@ header.sub{position:relative; padding-top:80px;}
|
|||||||
|
|
||||||
.gnb .depth1 > li{position:relative;}
|
.gnb .depth1 > li{position:relative;}
|
||||||
.gnb .depth1 > li > a{position:relative; display:block; box-sizing:border-box; color:#000; font-size:14px; width:160px; height:80px; text-align:center; line-height:80px; letter-spacing:-0.5px; opacity:0.7; transition:all 0.3s;}
|
.gnb .depth1 > li > a{position:relative; display:block; box-sizing:border-box; color:#000; font-size:14px; width:160px; height:80px; text-align:center; line-height:80px; letter-spacing:-0.5px; opacity:0.7; transition:all 0.3s;}
|
||||||
.gnb .depth1 > li > a:after{content:''; position:absolute; top:34px; right:0; display:inline-block; width:1px; height:13px; }
|
.gnb .depth1 > li > a:after{content:''; position:absolute; top:34px; right:0; display:inline-block; width:1px; height:13px; background:#ddd;}
|
||||||
.gnb .depth1 > li:first-child > a:before{content:''; position:absolute; top:34px; left:0; display:inline-block; width:1px; height:13px; }
|
.gnb .depth1 > li:first-child > a:before{content:''; position:absolute; top:34px; left:0; display:inline-block; width:1px; height:13px; background:#ddd;}
|
||||||
/*
|
/*
|
||||||
.gnb .depth1 > li:hover .red_box{transform:scaleX(1);}
|
.gnb .depth1 > li:hover .red_box{transform:scaleX(1);}
|
||||||
.gnb .depth1 > li:hover > a{opacity:1;}
|
.gnb .depth1 > li:hover > a{opacity:1;}
|
||||||
.gnb .depth1 > li > .red_box{display:block; position:absolute; width:100%; height:2px; top:78px; box-sizing:border-box; background:#ed1c24; transform-origin:center center; transform:scaleX(0); transition:all 0.3s;}
|
.gnb .depth1 > li > .red_box{display:block; position:absolute; width:100%; height:2px; top:78px; box-sizing:border-box; background:#ed1c24; transform-origin:center center; transform:scaleX(0); transition:all 0.3s;}
|
||||||
*/
|
*/
|
||||||
.gnb .depth2{position:absolute; left:0; top:80px; width:160px; height:280px; box-sizing:border-box; padding:20px 0; border-right:1px solid #eee; text-align:center; z-index:9;}
|
.gnb .depth2{position:absolute; left:0; top:80px; width:160px; height:410px; box-sizing:border-box; padding:20px 0; border-right:1px solid #eee; text-align:center; z-index:9;}
|
||||||
.gnb .depth1 > li:first-child .depth2{border-left:1px solid #eee;}
|
.gnb .depth2.first{border-left:1px solid #eee;}
|
||||||
.gnb .depth2 > li > a{display:block; color:#000; font-size:13px; line-height:30px;}
|
.gnb .depth2 > li > a{display:block; color:#000; font-size:13px; line-height:30px;}
|
||||||
.gnb .depth2 > li > a:hover{color:#ff0000;}
|
.gnb .depth2 > li > a:hover{color:#ff0000;}
|
||||||
|
|
||||||
@@ -94,9 +94,9 @@ header.sub{position:relative; padding-top:80px;}
|
|||||||
.left_box .depth3 > li:hover > a, .left_box .depth3 > li.on > a{color:#ed1c24;}
|
.left_box .depth3 > li:hover > a, .left_box .depth3 > li.on > a{color:#ed1c24;}
|
||||||
|
|
||||||
.content_top{position:fixed; top:0; left:0; padding:0 30px; width:100%; height:50px; line-height:50px; background:#eee; border-top:1px solid #ddd; border-left:1px solid #ddd; z-index:100;}
|
.content_top{position:fixed; top:0; left:0; padding:0 30px; width:100%; height:50px; line-height:50px; background:#eee; border-top:1px solid #ddd; border-left:1px solid #ddd; z-index:100;}
|
||||||
.content_top .path{margin:0; padding:0;}
|
.content_top .path{}
|
||||||
.content_top .path > li{display:inline-block; margin:0; padding:0;}
|
.content_top .path > li{display:inline-block;}
|
||||||
.content_top .path > li a{display:block; height:50px; line-height:50px; padding-left:10px; font-size:12px; color:#999; text-decoration:none;}
|
.content_top .path > li a{display:block; height:50px; line-height:50px; padding-left:10px; font-size:12px; color:#999;}
|
||||||
.content_top .path > li a:hover{color:#666;}
|
.content_top .path > li a:hover{color:#666;}
|
||||||
.content_top .path > li a:before{content:'>'; margin-right:10px;}
|
.content_top .path > li a:before{content:'>'; margin-right:10px;}
|
||||||
.content_top .path > li:first-child a:before{content:'';}
|
.content_top .path > li:first-child a:before{content:'';}
|
||||||
|
|||||||
@@ -1,170 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
|
|
||||||
<%@ page import="java.lang.reflect.Method" %>
|
|
||||||
<%@ page import="org.apache.commons.lang3.StringUtils" %>
|
|
||||||
<%@ page import="com.eactive.eai.rms.common.login.SessionManager" %>
|
|
||||||
<%!
|
|
||||||
// 최소 HTML 이스케이프 (진단 페이지 XSS 방지)
|
|
||||||
private String esc(String s) {
|
|
||||||
if (s == null) return "";
|
|
||||||
StringBuilder b = new StringBuilder(s.length() + 16);
|
|
||||||
for (int i = 0; i < s.length(); i++) {
|
|
||||||
char c = s.charAt(i);
|
|
||||||
switch (c) {
|
|
||||||
case '&': b.append("&"); break;
|
|
||||||
case '<': b.append("<"); break;
|
|
||||||
case '>': b.append(">"); break;
|
|
||||||
case '"': b.append("""); break;
|
|
||||||
case '\'': b.append("'"); break;
|
|
||||||
default: b.append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b.toString();
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
<%
|
|
||||||
// 로그인 사용자만 접근 — real 모드에서 운영 키 암복호화 오라클이 되지 않도록 보호
|
|
||||||
if (StringUtils.isBlank(SessionManager.getUserId(request))
|
|
||||||
&& StringUtils.isBlank(SessionManager.getRoleIdString(request))) {
|
|
||||||
response.sendRedirect(request.getContextPath() + "/loginForm.do");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
request.setCharacterEncoding("utf-8");
|
|
||||||
|
|
||||||
String op = request.getParameter("op");
|
|
||||||
String input = request.getParameter("input");
|
|
||||||
boolean run = request.getParameter("run") != null;
|
|
||||||
if (op == null) op = "encrypt";
|
|
||||||
if (input == null) input = "";
|
|
||||||
|
|
||||||
String mode = "UNKNOWN";
|
|
||||||
String revision = "-";
|
|
||||||
String returnCode = "-";
|
|
||||||
String result = "";
|
|
||||||
String error = "";
|
|
||||||
boolean loaded = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class<?> cls = Class.forName("com.eactive.ext.djb.DamoManager");
|
|
||||||
Object damo = cls.getMethod("getInstance").invoke(null);
|
|
||||||
loaded = true;
|
|
||||||
|
|
||||||
boolean bypass = (Boolean) cls.getMethod("isBypassMode").invoke(damo);
|
|
||||||
boolean fake = (Boolean) cls.getMethod("isFakeMode").invoke(damo);
|
|
||||||
mode = bypass ? "BYPASS" : (fake ? "FAKE" : "REAL");
|
|
||||||
revision = String.valueOf(cls.getMethod("getRevision").invoke(damo));
|
|
||||||
returnCode = String.valueOf(cls.getMethod("getReturnCode").invoke(damo));
|
|
||||||
|
|
||||||
if (run) {
|
|
||||||
if ("encrypt".equals(op)) {
|
|
||||||
result = (String) cls.getMethod("encrypt", String.class).invoke(damo, input);
|
|
||||||
} else if ("decrypt".equals(op)) {
|
|
||||||
result = (String) cls.getMethod("decrypt", String.class).invoke(damo, input);
|
|
||||||
} else if ("sha256".equals(op)) {
|
|
||||||
int t = cls.getField("SHA256").getInt(null);
|
|
||||||
result = (String) cls.getMethod("hash", int.class, String.class).invoke(damo, t, input);
|
|
||||||
} else if ("sha512".equals(op)) {
|
|
||||||
int t = cls.getField("SHA512").getInt(null);
|
|
||||||
result = (String) cls.getMethod("hash", int.class, String.class).invoke(damo, t, input);
|
|
||||||
} else {
|
|
||||||
error = "알 수 없는 op: " + op;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
error = "com.eactive.ext.djb.DamoManager 클래스를 찾을 수 없습니다. "
|
|
||||||
+ "damo-manager.jar 를 WAS lib (운영) 또는 WEB-INF/lib 에 배포하세요.";
|
|
||||||
} catch (Throwable t) {
|
|
||||||
// require-real fail-fast(ExceptionInInitializerError) 또는 초기화 실패(NoClassDefFoundError) 포함
|
|
||||||
Throwable c = (t.getCause() != null) ? t.getCause() : t;
|
|
||||||
error = c.toString();
|
|
||||||
if (c instanceof NoClassDefFoundError
|
|
||||||
|| error.contains("require-real")
|
|
||||||
|| error.contains("Could not initialize")) {
|
|
||||||
error += " (※ -Ddamo-manager.require-real=true 인데 scpdb 가 없어 기동에 실패했을 수 있습니다. "
|
|
||||||
+ "scpdb 를 갖추거나 옵션을 내리세요.)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String badgeColor = "REAL".equals(mode) ? "#1a7f37"
|
|
||||||
: "BYPASS".equals(mode) ? "#9a3412"
|
|
||||||
: "FAKE".equals(mode) ? "#9a6700" : "#6e7781";
|
|
||||||
%>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
||||||
<title>DamoManager 테스트</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: -apple-system, "Malgun Gothic", sans-serif; margin: 24px; color: #24292f; }
|
|
||||||
h1 { font-size: 20px; margin: 0 0 4px; }
|
|
||||||
.sub { color: #6e7781; font-size: 13px; margin-bottom: 16px; }
|
|
||||||
.badge { display:inline-block; color:#fff; padding:2px 10px; border-radius:12px; font-size:12px; font-weight:600; background:<%= badgeColor %>; }
|
|
||||||
.meta { font-size:12px; color:#57606a; margin-left:8px; }
|
|
||||||
.card { border:1px solid #d0d7de; border-radius:8px; padding:16px; max-width:760px; }
|
|
||||||
label { display:block; font-size:13px; font-weight:600; margin:12px 0 4px; }
|
|
||||||
textarea, select { width:100%; box-sizing:border-box; font-size:14px; padding:8px; border:1px solid #d0d7de; border-radius:6px; font-family:ui-monospace, Menlo, monospace; }
|
|
||||||
textarea { height:90px; resize:vertical; }
|
|
||||||
.row { display:flex; gap:12px; }
|
|
||||||
.row > div { flex:1; }
|
|
||||||
button { margin-top:14px; background:#1f6feb; color:#fff; border:0; border-radius:6px; padding:9px 18px; font-size:14px; font-weight:600; cursor:pointer; }
|
|
||||||
.result { margin-top:16px; }
|
|
||||||
.out { background:#f6f8fa; border:1px solid #d0d7de; border-radius:6px; padding:12px; white-space:pre-wrap; word-break:break-all; font-family:ui-monospace, Menlo, monospace; font-size:13px; min-height:20px; }
|
|
||||||
.err { color:#cf222e; background:#fff5f5; border-color:#ffc1c1; }
|
|
||||||
.hint { font-size:12px; color:#6e7781; margin-top:18px; line-height:1.6; }
|
|
||||||
code { background:#eff1f3; padding:1px 5px; border-radius:4px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>DamoManager 테스트</h1>
|
|
||||||
<div class="sub">웹에서 encrypt / decrypt / hash 동작을 즉시 확인 (eapim-admin)</div>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<div>
|
|
||||||
<% if (loaded) { %>
|
|
||||||
<span class="badge"><%= mode %> MODE</span>
|
|
||||||
<span class="meta">revision=<%= esc(revision) %> · returnCode=<%= esc(returnCode) %></span>
|
|
||||||
<% } else { %>
|
|
||||||
<span class="badge" style="background:#cf222e;">NOT LOADED</span>
|
|
||||||
<span class="meta">damo-manager.jar 미배포</span>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form method="post" action="<%= request.getContextPath() %>/damo.jsp">
|
|
||||||
<div class="row">
|
|
||||||
<div>
|
|
||||||
<label for="op">동작</label>
|
|
||||||
<select id="op" name="op">
|
|
||||||
<option value="encrypt" <%= "encrypt".equals(op) ? "selected" : "" %>>encrypt (암호화)</option>
|
|
||||||
<option value="decrypt" <%= "decrypt".equals(op) ? "selected" : "" %>>decrypt (복호화)</option>
|
|
||||||
<option value="sha256" <%= "sha256".equals(op) ? "selected" : "" %>>hash SHA-256</option>
|
|
||||||
<option value="sha512" <%= "sha512".equals(op) ? "selected" : "" %>>hash SHA-512</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label for="input">입력</label>
|
|
||||||
<textarea id="input" name="input" placeholder="암호화/복호화/해시할 문자열"><%= esc(input) %></textarea>
|
|
||||||
|
|
||||||
<input type="hidden" name="run" value="1">
|
|
||||||
<button type="submit">실행</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<% if (run || error.length() > 0) { %>
|
|
||||||
<div class="result">
|
|
||||||
<label>결과<% if (run && error.length() == 0) { %> <span class="meta">(<%= esc(op) %>)</span><% } %></label>
|
|
||||||
<div class="out <%= error.length() > 0 ? "err" : "" %>"><%= error.length() > 0 ? esc(error) : esc(result) %></div>
|
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<div class="hint">
|
|
||||||
모드 의미 — <b>BYPASS</b>: 무변환 원문 통과(<b>기본값</b>, 옵션 없음) · <b>FAKE</b>: Base64/JRE 해시(<code>-Ddamo-manager.enabled=true</code>, scpdb 없음) · <b>REAL</b>: penta scpdb 실 암복호화(<code>enabled=true</code> + scpdb).<br>
|
|
||||||
BYPASS 모드에서는 encrypt/decrypt/hash 모두 입력을 그대로 반환합니다.<br>
|
|
||||||
운영은 <code>-Ddamo-manager.require-real=true</code> 로 real 강제(아니면 기동 실패). CLI 로도 동일 확인: <code>java -jar damo-manager.jar enc <text></code>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8"%>
|
<%@ page language="java" contentType="text/html; charset=utf-8"%>
|
||||||
<%@page import="org.apache.commons.lang3.StringUtils"%>
|
<%@page import="org.apache.commons.lang3.StringUtils"%>
|
||||||
<%@page import="com.eactive.eai.rms.common.login.SessionManager"%>
|
<%@page import="com.eactive.eai.rms.common.login.SessionManager"%>
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,334 +0,0 @@
|
|||||||
/**
|
|
||||||
* Editor Content Styles (editor-content.css)
|
|
||||||
*
|
|
||||||
* Summernote 에디터로 작성된 HTML 콘텐츠의 공통 스타일
|
|
||||||
* 관리자포탈/개발자포탈 양쪽에서 동일하게 사용
|
|
||||||
*
|
|
||||||
* 사용법:
|
|
||||||
* - 관리자포탈: Summernote .note-editable에 .editor-content 클래스 추가
|
|
||||||
* - 개발자포탈: 콘텐츠 wrapper에 .editor-content 클래스 추가
|
|
||||||
*
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date 2025-12-30
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
CSS Reset + 기본 설정
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content {
|
|
||||||
all: revert;
|
|
||||||
font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
||||||
font-size: 16px !important;
|
|
||||||
font-weight: 400 !important;
|
|
||||||
line-height: 1.8 !important;
|
|
||||||
color: #1A1A2E !important;
|
|
||||||
word-wrap: break-word;
|
|
||||||
text-align: left !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
헤딩 (Headings)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content h1 {
|
|
||||||
font-size: 20px !important;
|
|
||||||
font-weight: 700 !important;
|
|
||||||
margin: 32px 0 16px !important;
|
|
||||||
line-height: 1.4 !important;
|
|
||||||
color: #1A1A2E !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content h1:first-child {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content h2 {
|
|
||||||
font-size: 18px !important;
|
|
||||||
font-weight: 700 !important;
|
|
||||||
margin: 24px 0 8px !important;
|
|
||||||
line-height: 1.4 !important;
|
|
||||||
color: #1A1A2E !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content h3 {
|
|
||||||
font-size: 16px !important;
|
|
||||||
font-weight: 600 !important;
|
|
||||||
margin: 16px 0 8px !important;
|
|
||||||
line-height: 1.4 !important;
|
|
||||||
color: #1A1A2E !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content h4,
|
|
||||||
.editor-content h5,
|
|
||||||
.editor-content h6 {
|
|
||||||
font-size: 16px !important;
|
|
||||||
font-weight: 600 !important;
|
|
||||||
margin: 16px 0 8px !important;
|
|
||||||
line-height: 1.4 !important;
|
|
||||||
color: #1A1A2E !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
단락 (Paragraphs)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content p {
|
|
||||||
margin-bottom: 16px !important;
|
|
||||||
line-height: 1.8 !important;
|
|
||||||
font-size: 16px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content p:last-child {
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
리스트 (Lists) - 글로벌 reset 대응
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content ul {
|
|
||||||
list-style-type: disc !important;
|
|
||||||
padding-left: 32px !important;
|
|
||||||
margin: 16px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content ol {
|
|
||||||
list-style-type: decimal !important;
|
|
||||||
padding-left: 32px !important;
|
|
||||||
margin: 16px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content li {
|
|
||||||
margin-bottom: 8px !important;
|
|
||||||
line-height: 1.8 !important;
|
|
||||||
font-size: 16px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content li:last-child {
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 중첩 리스트 */
|
|
||||||
.editor-content ul ul {
|
|
||||||
list-style-type: circle !important;
|
|
||||||
margin: 8px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content ul ul ul {
|
|
||||||
list-style-type: square !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content ol ol {
|
|
||||||
list-style-type: lower-alpha !important;
|
|
||||||
margin: 8px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content ol ol ol {
|
|
||||||
list-style-type: lower-roman !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
테이블 (Tables)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content table {
|
|
||||||
width: 100% !important;
|
|
||||||
border-collapse: collapse !important;
|
|
||||||
margin: 24px 0 !important;
|
|
||||||
border: 1px solid #E2E8F0 !important;
|
|
||||||
border-radius: 8px !important;
|
|
||||||
overflow: hidden !important;
|
|
||||||
font-size: 14px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content th,
|
|
||||||
.editor-content td {
|
|
||||||
border: 1px solid #E2E8F0 !important;
|
|
||||||
padding: 8px 16px !important;
|
|
||||||
text-align: left !important;
|
|
||||||
vertical-align: top !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content th {
|
|
||||||
background: #EFF6FF !important;
|
|
||||||
font-weight: 600 !important;
|
|
||||||
color: #1A1A2E !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content tr:hover {
|
|
||||||
background: #F8FAFC !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
링크 (Links)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content a {
|
|
||||||
color: #0049b4 !important;
|
|
||||||
text-decoration: underline !important;
|
|
||||||
transition: color 0.3s ease !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content a:hover {
|
|
||||||
color: #003080 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
인용문 (Blockquote)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content blockquote {
|
|
||||||
border-left: 4px solid #0049b4 !important;
|
|
||||||
padding: 16px 24px !important;
|
|
||||||
margin: 24px 0 !important;
|
|
||||||
background: #F8FAFC !important;
|
|
||||||
font-style: italic !important;
|
|
||||||
color: #64748B !important;
|
|
||||||
border-radius: 0 8px 8px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content blockquote p {
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
이미지 (Images)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content img {
|
|
||||||
max-width: 100% !important;
|
|
||||||
height: auto !important;
|
|
||||||
border-radius: 8px !important;
|
|
||||||
margin: 16px 0 !important;
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
코드 (Code)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content code {
|
|
||||||
background: #F8FAFC !important;
|
|
||||||
padding: 2px 6px !important;
|
|
||||||
border-radius: 4px !important;
|
|
||||||
font-family: 'Fira Code', 'Courier New', monospace !important;
|
|
||||||
font-size: 0.9em !important;
|
|
||||||
color: #0049b4 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content pre {
|
|
||||||
background: #F8FAFC !important;
|
|
||||||
border: 1px solid #E2E8F0 !important;
|
|
||||||
border-radius: 8px !important;
|
|
||||||
padding: 16px !important;
|
|
||||||
overflow-x: auto !important;
|
|
||||||
margin: 16px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content pre code {
|
|
||||||
background: transparent !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
color: #1A1A2E !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
구분선 (Horizontal Rule)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content hr {
|
|
||||||
border: none !important;
|
|
||||||
border-top: 1px solid #E2E8F0 !important;
|
|
||||||
margin: 32px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
텍스트 강조 (Text Emphasis)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.editor-content strong,
|
|
||||||
.editor-content b {
|
|
||||||
font-weight: 700 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content em,
|
|
||||||
.editor-content i {
|
|
||||||
font-style: italic !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content u {
|
|
||||||
text-decoration: underline !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content s,
|
|
||||||
.editor-content strike,
|
|
||||||
.editor-content del {
|
|
||||||
text-decoration: line-through !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content mark {
|
|
||||||
background-color: #FEF3C7 !important;
|
|
||||||
padding: 0 2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content sub {
|
|
||||||
vertical-align: sub !important;
|
|
||||||
font-size: 0.8em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content sup {
|
|
||||||
vertical-align: super !important;
|
|
||||||
font-size: 0.8em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
반응형 (Responsive)
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.editor-content {
|
|
||||||
font-size: 14px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content h1 {
|
|
||||||
font-size: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content h2 {
|
|
||||||
font-size: 16px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content h3,
|
|
||||||
.editor-content h4,
|
|
||||||
.editor-content h5,
|
|
||||||
.editor-content h6 {
|
|
||||||
font-size: 14px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content p,
|
|
||||||
.editor-content li {
|
|
||||||
font-size: 14px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content table {
|
|
||||||
font-size: 12px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content th,
|
|
||||||
.editor-content td {
|
|
||||||
padding: 4px 8px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content ul,
|
|
||||||
.editor-content ol {
|
|
||||||
padding-left: 24px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content blockquote {
|
|
||||||
padding: 8px 16px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-content pre {
|
|
||||||
padding: 8px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
// OpenAPI 에디터 초기 상태 골격(빈 껍데기).
|
|
||||||
// - specToData() 가 deepClone 하여 서버 spec 값으로 덮어쓰는 구조 기준값.
|
|
||||||
// - 실제 데모/샘플 값은 두지 않는다(팝업은 항상 서버 spec 로드 후 렌더).
|
|
||||||
// - docOptions 만 기능 기본값으로 유지(문서 미리보기 옵션).
|
|
||||||
// locked:true = 게이트웨이 자동 주입(회색+자물쇠) / locked:false = 사용자 편집.
|
|
||||||
|
|
||||||
window.SAMPLE_DATA = (function () {
|
|
||||||
function f() { return { value: '', locked: false }; }
|
|
||||||
return {
|
|
||||||
info: {
|
|
||||||
title: f(),
|
|
||||||
version: f(),
|
|
||||||
summary: f(),
|
|
||||||
description: f(),
|
|
||||||
termsOfService: f(),
|
|
||||||
contact: { name: f(), email: f(), url: f() },
|
|
||||||
license: { name: f(), url: f() }
|
|
||||||
},
|
|
||||||
|
|
||||||
tags: [],
|
|
||||||
|
|
||||||
externalDocs: { description: f(), url: f() },
|
|
||||||
|
|
||||||
servers: [],
|
|
||||||
|
|
||||||
serverVariables: [],
|
|
||||||
|
|
||||||
operation: {
|
|
||||||
method: f(),
|
|
||||||
path: f(),
|
|
||||||
operationId: f(),
|
|
||||||
summary: f(),
|
|
||||||
description: f(),
|
|
||||||
tags: { value: [], locked: false },
|
|
||||||
deprecated: { value: false, locked: false }
|
|
||||||
},
|
|
||||||
|
|
||||||
// 파라미터 (Path/Query/Header/Cookie)
|
|
||||||
parameters: [],
|
|
||||||
|
|
||||||
// Request Body 스키마
|
|
||||||
requestBody: {
|
|
||||||
mediaType: 'application/json',
|
|
||||||
required: { value: false, locked: false },
|
|
||||||
schema: []
|
|
||||||
},
|
|
||||||
|
|
||||||
// 응답 스키마 (상태코드 별)
|
|
||||||
responses: {
|
|
||||||
'200': { description: f(), schema: [] }
|
|
||||||
},
|
|
||||||
|
|
||||||
// 보안 스킴
|
|
||||||
securitySchemes: [],
|
|
||||||
globalSecurity: [],
|
|
||||||
|
|
||||||
// 예제
|
|
||||||
examples: {
|
|
||||||
request: {},
|
|
||||||
response: {}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 문서 옵션
|
|
||||||
docOptions: {
|
|
||||||
theme: 'light',
|
|
||||||
lang: 'ko',
|
|
||||||
includeExamples: true,
|
|
||||||
tryItOut: true,
|
|
||||||
defaultExpandDepth: -1,
|
|
||||||
layout: 'BaseLayout',
|
|
||||||
tagFilter: [],
|
|
||||||
sideToc: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
/* DJB OpenAPI Editor POC — Tailwind 보강 커스텀 */
|
|
||||||
|
|
||||||
html, body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Apple SD Gothic Neo",
|
|
||||||
"Malgun Gothic", "Noto Sans KR", system-ui, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === 잠금 행/카드 좌측 띠 === */
|
|
||||||
.locked-row td:first-child {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.locked-row td:first-child::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 6px;
|
|
||||||
bottom: 6px;
|
|
||||||
width: 3px;
|
|
||||||
background: #cbd5e1;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
.locked-card {
|
|
||||||
position: relative;
|
|
||||||
background: linear-gradient(to right, #f8fafc 0%, #ffffff 4px) #ffffff;
|
|
||||||
}
|
|
||||||
.locked-card::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: 0; top: 8px; bottom: 8px;
|
|
||||||
width: 3px;
|
|
||||||
background: #cbd5e1;
|
|
||||||
border-radius: 0 2px 2px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === 스키마 테이블 — 가독성 보조 === */
|
|
||||||
.schema-table th { white-space: nowrap; }
|
|
||||||
.schema-table tbody tr:hover { background: #fafbfc; }
|
|
||||||
.schema-table input,
|
|
||||||
.schema-table select {
|
|
||||||
font-size: 12.5px;
|
|
||||||
}
|
|
||||||
.schema-table input[type="text"] {
|
|
||||||
padding-top: 4px;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === 스텝퍼 항목 hover === */
|
|
||||||
.step-item:hover { background: #f8fafc; }
|
|
||||||
|
|
||||||
/* === 미리보기 패널: Swagger UI 크기 미세조정 === */
|
|
||||||
#preview-swagger .swagger-ui {
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
#preview-swagger .swagger-ui .info { margin: 18px 0; }
|
|
||||||
#preview-swagger .swagger-ui .info .title { font-size: 22px; }
|
|
||||||
#preview-swagger .swagger-ui .scheme-container { padding: 12px 0; box-shadow: none; }
|
|
||||||
#preview-swagger .swagger-ui .opblock { margin: 0 0 12px 0; }
|
|
||||||
|
|
||||||
/* === 다크 테마 (POC 시뮬레이션 — Swagger 자체 다크는 미지원이라 컨테이너만) === */
|
|
||||||
body.theme-dark #preview-swagger { background: #1e293b; }
|
|
||||||
|
|
||||||
/* === 토스트 애니메이션 === */
|
|
||||||
#toast { transition: opacity 0.2s; }
|
|
||||||
|
|
||||||
/* === Monaco 컨테이너가 hidden 일 때 layout 깨짐 방지 === */
|
|
||||||
#preview-monaco {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Stepper 6단 grid 셀 좌우 라인 (마지막 셀 제외) === */
|
|
||||||
#stepper li {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#stepper li:not(:last-child)::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: -8px;
|
|
||||||
width: 16px;
|
|
||||||
height: 1px;
|
|
||||||
background: #e2e8f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === 보안 스킴 카드 — 잠금 표시 === */
|
|
||||||
.locked-card {
|
|
||||||
background: #fafbfc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === 칩(태그) 미세 조정 === */
|
|
||||||
.tag-chip { transition: background 0.15s; }
|
|
||||||
|
|
||||||
/* === Export menu fade === */
|
|
||||||
#export-menu { animation: fadeIn 0.12s ease-out; }
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from { opacity: 0; transform: translateY(-4px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === 1600px 기준 폼 패널 내부 가로 여유 확보 === */
|
|
||||||
#form-content { max-width: 100%; }
|
|
||||||
|
|
||||||
/* === readonly input 위에서 텍스트 커서 안 보이게 === */
|
|
||||||
input[readonly] { user-select: text; }
|
|
||||||
@@ -184,9 +184,8 @@ function getEndTime(){
|
|||||||
</td>
|
</td>
|
||||||
<th style="width:180px;"><%= localeMessage.getString("auditLogMan.remoteAddress") %></th>
|
<th style="width:180px;"><%= localeMessage.getString("auditLogMan.remoteAddress") %></th>
|
||||||
<td><input type="text" name="searchRemoteAddress" value="${param.searchRemoteAddress}" style="width:100%"></td>
|
<td><input type="text" name="searchRemoteAddress" value="${param.searchRemoteAddress}" style="width:100%"></td>
|
||||||
<th style="width:180px;"><%= localeMessage.getString("auditLogMan.parameters") %></th>
|
<th style="width:180px;"></th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchParameters" value="${param.searchParameters}" style="width:100%">
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -54,18 +54,10 @@ function detail(key){
|
|||||||
$('#systemCode').val(data.systemCode);
|
$('#systemCode').val(data.systemCode);
|
||||||
$('#logTypeText').val(data.logTypeText);
|
$('#logTypeText').val(data.logTypeText);
|
||||||
$('#remoteAddress').val(data.remoteAddress);
|
$('#remoteAddress').val(data.remoteAddress);
|
||||||
|
$('#logMsg').val(data.message);
|
||||||
$('#logSubMsg').val(data.command);
|
$('#logSubMsg').val(data.command);
|
||||||
$('#parameters').val(data.parameters);
|
$('#parameters').val(data.parameters);
|
||||||
|
|
||||||
// 사유(message)는 값이 있을 때만 노출
|
|
||||||
if (data.message) {
|
|
||||||
$('#logMsg').val(data.message);
|
|
||||||
$('#messageRow').show();
|
|
||||||
} else {
|
|
||||||
$('#logMsg').val('');
|
|
||||||
$('#messageRow').hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
},
|
||||||
error:function(e){
|
error:function(e){
|
||||||
alert(e.responseText);
|
alert(e.responseText);
|
||||||
@@ -129,9 +121,6 @@ $(document).ready(function() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th><%= localeMessage.getString("auditLogMan.command") %></th><td><input type="text" id="logSubMsg" name="logSubMsg" readonly="readonly"/></td>
|
<th><%= localeMessage.getString("auditLogMan.command") %></th><td><input type="text" id="logSubMsg" name="logSubMsg" readonly="readonly"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="messageRow" style="display:none;">
|
|
||||||
<th><%= localeMessage.getString("auditLogMan.message") %></th><td><textarea id="logMsg" name="logMsg" style="width:100%;height:80px" readonly="readonly"></textarea></td>
|
|
||||||
</tr>
|
|
||||||
<tr height="100px">
|
<tr height="100px">
|
||||||
<th><%= localeMessage.getString("auditLogMan.parameters") %></th><td><textarea id="parameters" name="parameters" style="width:100%;height:200px" readonly="readonly"></textarea></td>
|
<th><%= localeMessage.getString("auditLogMan.parameters") %></th><td><textarea id="parameters" name="parameters" style="width:100%;height:200px" readonly="readonly"></textarea></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8"%>
|
|
||||||
<%@ page import="java.util.List"%>
|
|
||||||
<%@ page import="com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode"%>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
|
||||||
<%!
|
|
||||||
private void printNodeLabel(javax.servlet.jsp.JspWriter out, SitemapNode node) throws java.io.IOException {
|
|
||||||
String url = node.getMenuUrl();
|
|
||||||
boolean hasLink = url != null && !url.trim().isEmpty() && !"NAN".equalsIgnoreCase(url.trim());
|
|
||||||
if (hasLink) {
|
|
||||||
out.print("<a href=\"javascript:void(0);\" class=\"sitemap-name\" onclick=\"goPage('"
|
|
||||||
+ escapeJs(url) + "','" + escapeJs(node.getMenuId()) + "');return false;\">"
|
|
||||||
+ escapeHtml(node.getMenuName()) + "</a>");
|
|
||||||
} else {
|
|
||||||
out.print("<span class=\"sitemap-name\">" + escapeHtml(node.getMenuName()) + "</span>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printSitemapNode(javax.servlet.jsp.JspWriter out, SitemapNode node) throws java.io.IOException {
|
|
||||||
out.print("<li>");
|
|
||||||
printNodeLabel(out, node);
|
|
||||||
|
|
||||||
List<SitemapNode> children = node.getChildren();
|
|
||||||
if (children != null && !children.isEmpty()) {
|
|
||||||
out.print("<ul>");
|
|
||||||
for (SitemapNode child : children) {
|
|
||||||
printSitemapNode(out, child);
|
|
||||||
}
|
|
||||||
out.print("</ul>");
|
|
||||||
}
|
|
||||||
out.print("</li>");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String escapeHtml(String value) {
|
|
||||||
if (value == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return value.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String escapeJs(String value) {
|
|
||||||
if (value == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return value.replace("\\", "\\\\").replace("'", "\\'");
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
|
|
||||||
List<SitemapNode> sitemapTree = (List<SitemapNode>) request.getAttribute("sitemapTree");
|
|
||||||
%>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
|
||||||
<style>
|
|
||||||
.sitemap-columns { display: flex; flex-wrap: wrap; gap: 40px; }
|
|
||||||
.sitemap-column { min-width: 180px; }
|
|
||||||
.sitemap-category { font-size: 1.1em; font-weight: bold; padding-bottom: 6px; margin-bottom: 8px; border-bottom: 2px solid #ccc; }
|
|
||||||
.sitemap-tree, .sitemap-tree ul { list-style-type: disc; margin: 0; padding-left: 18px; }
|
|
||||||
.sitemap-tree { padding-left: 0; list-style-type: none; }
|
|
||||||
.sitemap-tree li { line-height: 1.8; }
|
|
||||||
a.sitemap-name { text-decoration: none; cursor: pointer; }
|
|
||||||
a.sitemap-name:hover { text-decoration: underline; }
|
|
||||||
</style>
|
|
||||||
<script language="javascript">
|
|
||||||
function goPage(url, menuId) {
|
|
||||||
var serviceType = sessionStorage["serviceType"];
|
|
||||||
|
|
||||||
var pageUrl = url;
|
|
||||||
pageUrl += (pageUrl.indexOf("?") > -1 ? "&" : "?") + "menuId=" + menuId;
|
|
||||||
pageUrl += "&serviceType=" + serviceType;
|
|
||||||
|
|
||||||
parent.leftFrame.location.href = '<c:url value="/leftMenu.do"/>?menuId=' + menuId + '&serviceType=' + serviceType;
|
|
||||||
location.href = pageUrl;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="right_box">
|
|
||||||
<div class="content_top">
|
|
||||||
<ul class="path">
|
|
||||||
<li><a href="#">${rmsMenuPath}</a></li>
|
|
||||||
</ul>
|
|
||||||
</div><!-- end content_top -->
|
|
||||||
<div class="content_middle">
|
|
||||||
<!-- <div class="title">사이트맵</div> -->
|
|
||||||
<div class="sitemap-columns">
|
|
||||||
<%
|
|
||||||
for (SitemapNode category : sitemapTree) {
|
|
||||||
%>
|
|
||||||
<div class="sitemap-column">
|
|
||||||
<div class="sitemap-category">
|
|
||||||
<%
|
|
||||||
printNodeLabel(out, category);
|
|
||||||
%>
|
|
||||||
</div>
|
|
||||||
<ul class="sitemap-tree">
|
|
||||||
<%
|
|
||||||
List<SitemapNode> children = category.getChildren();
|
|
||||||
if (children != null) {
|
|
||||||
for (SitemapNode child : children) {
|
|
||||||
printSitemapNode(out, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
</div>
|
|
||||||
</div><!-- end content_middle -->
|
|
||||||
</div><!-- end right_box -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -18,17 +18,7 @@
|
|||||||
<script language="javascript" >
|
<script language="javascript" >
|
||||||
var url = '<c:url value="/common/acl/user/userMan.json" />';
|
var url = '<c:url value="/common/acl/user/userMan.json" />';
|
||||||
var url_view = '<c:url value="/common/acl/user/userMan.view" />';
|
var url_view = '<c:url value="/common/acl/user/userMan.view" />';
|
||||||
|
$(document).ready(function() {
|
||||||
function userStatusFormat (cellvalue){
|
|
||||||
if ( cellvalue == '1' ){
|
|
||||||
return '<%= localeMessage.getString("code.normal") %>';
|
|
||||||
}else if ( cellvalue == '2' ) {
|
|
||||||
return '<span style="color:red"><%= localeMessage.getString("code.lock") %></span>';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
var gridPostData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
var gridPostData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
||||||
$('#grid').jqGrid({
|
$('#grid').jqGrid({
|
||||||
datatype:"json",
|
datatype:"json",
|
||||||
@@ -38,20 +28,16 @@ $(document).ready(function() {
|
|||||||
colNames:['<%= localeMessage.getString("login.userId") %>',
|
colNames:['<%= localeMessage.getString("login.userId") %>',
|
||||||
'<%= localeMessage.getString("user.name") %>',
|
'<%= localeMessage.getString("user.name") %>',
|
||||||
'<%= localeMessage.getString("user.roleName") %>',
|
'<%= localeMessage.getString("user.roleName") %>',
|
||||||
'<%= localeMessage.getString("user.status") %>',
|
|
||||||
'<%= localeMessage.getString("user.createOn") %>',
|
'<%= localeMessage.getString("user.createOn") %>',
|
||||||
'<%= localeMessage.getString("user.lastLoginYms") %>',
|
|
||||||
'<%= localeMessage.getString("user.depart") %>',
|
'<%= localeMessage.getString("user.depart") %>',
|
||||||
'<%= localeMessage.getString("user.teamName") %>',
|
'<%= localeMessage.getString("user.teamName") %>',
|
||||||
'<%= localeMessage.getString("user.position") %>'
|
'<%= localeMessage.getString("user.position") %>'
|
||||||
],
|
],
|
||||||
colModel:[
|
colModel:[
|
||||||
{ name : 'USERID' , align:'center', width: 100, sortable:false },
|
{ name : 'USERID' , align:'center' ,sortable:false },
|
||||||
{ name : 'USERNAME' , align:'center', width: 100 },
|
{ name : 'USERNAME' , align:'center' },
|
||||||
{ name : 'ROLEIDNFINAME' , align:'center', width: 300 },
|
{ name : 'ROLEIDNFINAME' , align:'center' },
|
||||||
{ name : 'STATUS' , align:'center', width: 80, formatter: userStatusFormat },
|
{ name : 'LASTAMNDYMS' , align:'center', formatter: timeStampFormat },
|
||||||
{ name : 'REGDYMS' , align:'center', width: 120, formatter: timeStampFormat },
|
|
||||||
{ name : 'LASTLOGINYMS' , align:'center', width: 120, formatter: timeStampFormat },
|
|
||||||
{ name : 'DVSNNAME' , align:'center', hidden: true },
|
{ name : 'DVSNNAME' , align:'center', hidden: true },
|
||||||
{ name : 'TEAMNAME' , align:'center', hidden: true },
|
{ name : 'TEAMNAME' , align:'center', hidden: true },
|
||||||
{ name : 'JOBTLNAME' , align:'center', hidden: true }
|
{ name : 'JOBTLNAME' , align:'center', hidden: true }
|
||||||
|
|||||||
@@ -88,8 +88,7 @@ function detail(key){
|
|||||||
$(tag+"[name="+name+"]").val(data[name.toUpperCase()] ? data[name.toUpperCase()].trim():"");
|
$(tag+"[name="+name+"]").val(data[name.toUpperCase()] ? data[name.toUpperCase()].trim():"");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("input[name=REGDYMS]").inputmask("9999-99-99 99:99:99",{'autoUnmask':true});
|
$("input[name=LASTAMNDYMS]").inputmask("9999-99-99 99:99:99",{'autoUnmask':true});
|
||||||
$("input[name=LASTLOGINYMS]").inputmask("9999-99-99 99:99:99",{'autoUnmask':true});
|
|
||||||
/* $("input[name=SECONDMENTSTDT]").inputmask("9999-99-99",{'autoUnmask':true});
|
/* $("input[name=SECONDMENTSTDT]").inputmask("9999-99-99",{'autoUnmask':true});
|
||||||
$("input[name=SECONDMENTENDT]").inputmask("9999-99-99",{'autoUnmask':true}); */
|
$("input[name=SECONDMENTENDT]").inputmask("9999-99-99",{'autoUnmask':true}); */
|
||||||
|
|
||||||
@@ -217,7 +216,6 @@ $(document).ready(function() {
|
|||||||
dataType:"json",
|
dataType:"json",
|
||||||
data:{cmd: 'UPDATE_PASSWORD', userId : $("input[name=userId]").val()},
|
data:{cmd: 'UPDATE_PASSWORD', userId : $("input[name=userId]").val()},
|
||||||
success:function(json){
|
success:function(json){
|
||||||
$('select[name="status"]').val("1")
|
|
||||||
alert(json.result);
|
alert(json.result);
|
||||||
},
|
},
|
||||||
error:function(e){
|
error:function(e){
|
||||||
@@ -279,10 +277,10 @@ $(document).ready(function() {
|
|||||||
<table class="table_row" cellspacing="0">
|
<table class="table_row" cellspacing="0">
|
||||||
<input type="hidden" name="jobclcd">
|
<input type="hidden" name="jobclcd">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:180px;"><%= localeMessage.getString("login.userId") %> <span class=\"required-mark\">*</span></th><td ><input type="text" name="userId"/> </td>
|
<th style="width:180px;"><%= localeMessage.getString("login.userId") %></th><td ><input type="text" name="userId"/> </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th><%= localeMessage.getString("user.name") %> <span class=\"required-mark\">*</span></th><td><input type="text" name="userName" /></td>
|
<th><%= localeMessage.getString("user.name") %> </th><td><input type="text" name="userName" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="datailT">
|
<tr class="datailT">
|
||||||
<th><%= localeMessage.getString("user.auth") %> </th><td><input type="text" name="roleidnfiname" /></td>
|
<th><%= localeMessage.getString("user.auth") %> </th><td><input type="text" name="roleidnfiname" /></td>
|
||||||
@@ -319,6 +317,7 @@ $(document).ready(function() {
|
|||||||
<td>
|
<td>
|
||||||
<div class="select-style">
|
<div class="select-style">
|
||||||
<select name="status">
|
<select name="status">
|
||||||
|
<option value=""><%= localeMessage.getString("code.normal") %></option>
|
||||||
<option value="1"><%= localeMessage.getString("code.normal") %></option>
|
<option value="1"><%= localeMessage.getString("code.normal") %></option>
|
||||||
<option value="2"><%= localeMessage.getString("code.lock") %></option>
|
<option value="2"><%= localeMessage.getString("code.lock") %></option>
|
||||||
</select>
|
</select>
|
||||||
@@ -335,10 +334,7 @@ $(document).ready(function() {
|
|||||||
<th><%= localeMessage.getString("user.fieldAgentName") %> </th><td><input type="text" name="spotprxyname" /></td>
|
<th><%= localeMessage.getString("user.fieldAgentName") %> </th><td><input type="text" name="spotprxyname" /></td>
|
||||||
</tr> --%>
|
</tr> --%>
|
||||||
<tr>
|
<tr>
|
||||||
<th><%= localeMessage.getString("user.createOn") %> </th><td><input type="text" name="REGDYMS" readonly/></td>
|
<th><%= localeMessage.getString("user.createOn") %> </th><td><input type="text" name="LASTAMNDYMS" readonly/></td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th><%= localeMessage.getString("user.lastLoginYms") %> </th><td><input type="text" name="LASTLOGINYMS" readonly/></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<%-- <tr>
|
<%-- <tr>
|
||||||
<th><%= localeMessage.getString("user.secondmentbrncd") %> </th><td><input type="text" name="SECONDMENTBRNCD" readonly/></td>
|
<th><%= localeMessage.getString("user.secondmentbrncd") %> </th><td><input type="text" name="SECONDMENTBRNCD" readonly/></td>
|
||||||
|
|||||||
@@ -531,88 +531,6 @@
|
|||||||
}
|
}
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 사유 입력 모달 - 확인 시 입력한 사유 문자열을 onConfirm(reason)으로 전달
|
|
||||||
* @param {string} message - 안내 메시지
|
|
||||||
* @param {object} options - (title, confirmText, cancelText, placeholder, required, onConfirm, onCancel)
|
|
||||||
* required 기본 true (빈 사유 차단)
|
|
||||||
*/
|
|
||||||
function showReasonPrompt(message, options) {
|
|
||||||
options = options || {};
|
|
||||||
var title = options.title || '사유 입력';
|
|
||||||
var confirmText = options.confirmText || '확인';
|
|
||||||
var cancelText = options.cancelText || '취소';
|
|
||||||
var placeholder = options.placeholder || '사유를 입력하세요.';
|
|
||||||
var required = options.required !== false;
|
|
||||||
var onConfirm = options.onConfirm || function(){};
|
|
||||||
var onCancel = options.onCancel || function(){};
|
|
||||||
|
|
||||||
// 기존 모달 제거
|
|
||||||
$('#commonReasonModal').remove();
|
|
||||||
|
|
||||||
var iconHtml = getAlertIcon('warning');
|
|
||||||
|
|
||||||
var modalHtml =
|
|
||||||
'<div id="commonReasonModal" class="common-alert-overlay">' +
|
|
||||||
'<div class="common-alert-modal alert-warning">' +
|
|
||||||
'<div class="common-alert-header">' +
|
|
||||||
'<span class="common-alert-icon">' + iconHtml + '</span>' +
|
|
||||||
'<span class="common-alert-title">' + title + '</span>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="common-alert-body">' +
|
|
||||||
'<p class="common-alert-message">' + message + '</p>' +
|
|
||||||
'<textarea id="commonReasonInput" maxlength="200" placeholder="' + placeholder + '" style="width:100%;height:80px;margin-top:10px;box-sizing:border-box;font-size:13px;padding:8px;border:1px solid #ddd;border-radius:4px;resize:vertical;"></textarea>' +
|
|
||||||
'<p id="commonReasonError" style="display:none;color:#f44336;font-size:12px;margin:6px 0 0;">사유를 입력해 주세요.</p>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="common-alert-footer">' +
|
|
||||||
'<button type="button" class="common-confirm-cancel-btn" id="commonReasonCancelBtn">' + cancelText + '</button>' +
|
|
||||||
'<button type="button" class="common-alert-btn" id="commonReasonOkBtn">' + confirmText + '</button>' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>';
|
|
||||||
|
|
||||||
$('body').append(modalHtml);
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
$('#commonReasonModal').addClass('show');
|
|
||||||
$('#commonReasonInput').focus();
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
// 확인 버튼
|
|
||||||
$('#commonReasonOkBtn').on('click', function() {
|
|
||||||
var reason = $.trim($('#commonReasonInput').val());
|
|
||||||
if (required && reason === '') {
|
|
||||||
$('#commonReasonError').show();
|
|
||||||
$('#commonReasonInput').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
closeCommonReason(function() { onConfirm(reason); });
|
|
||||||
});
|
|
||||||
|
|
||||||
// 취소 버튼
|
|
||||||
$('#commonReasonCancelBtn').on('click', function() {
|
|
||||||
closeCommonReason(onCancel);
|
|
||||||
});
|
|
||||||
|
|
||||||
// ESC 키로 취소
|
|
||||||
$(document).on('keydown.commonReason', function(e) {
|
|
||||||
if (e.keyCode === 27) {
|
|
||||||
closeCommonReason(onCancel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeCommonReason(callback) {
|
|
||||||
$('#commonReasonModal').removeClass('show');
|
|
||||||
setTimeout(function() {
|
|
||||||
$('#commonReasonModal').remove();
|
|
||||||
$(document).off('keydown.commonReason');
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- 공용 Alert 모달 스타일 -->
|
<!-- 공용 Alert 모달 스타일 -->
|
||||||
|
|||||||
@@ -91,10 +91,7 @@
|
|||||||
data: $('#loginForm').serialize(),
|
data: $('#loginForm').serialize(),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
if (response.changePassword) {
|
if (response.smsAuthRequired) {
|
||||||
showChangeInitPassword(response);
|
|
||||||
}
|
|
||||||
else if (response.smsAuthRequired) {
|
|
||||||
// SMS 인증 필요
|
// SMS 인증 필요
|
||||||
showSmsAuthModal(response);
|
showSmsAuthModal(response);
|
||||||
} else if (response.success) {
|
} else if (response.success) {
|
||||||
@@ -111,13 +108,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showChangeInitPassword(data) {
|
|
||||||
$('input[name="resetUserId"]').val($('input[name="userId"]').val());
|
|
||||||
$('input[name="resetPassword"]').val($('input[name="password"]').val());
|
|
||||||
$('#changeInitPassword').hide();
|
|
||||||
$('#pwdChgModal').modal('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
// SMS 인증 모달 표시
|
// SMS 인증 모달 표시
|
||||||
function showSmsAuthModal(data) {
|
function showSmsAuthModal(data) {
|
||||||
@@ -228,39 +218,44 @@
|
|||||||
clearInterval(resendTimer);
|
clearInterval(resendTimer);
|
||||||
$('#smsAuthModal').modal('hide');
|
$('#smsAuthModal').modal('hide');
|
||||||
}
|
}
|
||||||
|
function changePwd(){
|
||||||
function checkPwd(){
|
|
||||||
if ($("input[name=resetUserId]").val() == null || $("input[name=resetUserId]").val().length == 0 ){
|
if ($("input[name=resetUserId]").val() == null || $("input[name=resetUserId]").val().length == 0 ){
|
||||||
alert("<%= localeMessage.getString("login.checkid") %>");
|
alert("<%= localeMessage.getString("login.checkid") %>");
|
||||||
$("input[name=resetUserId]").trigger("focus");
|
$("input[name=resetUserId]").trigger("focus");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if ($("input[name=resetPassword]").val() == null || $("input[name=resetPassword]").val().trim().length == 0 ){
|
if ($("input[name=resetPassword]").val() == null || $("input[name=resetPassword]").val().trim().length == 0 ){
|
||||||
alert("<%= localeMessage.getString("login.checkpwd1") %>");
|
alert("<%= localeMessage.getString("login.checkpwd1") %>");
|
||||||
$("input[name=resetPassword]").trigger("focus");
|
$("input[name=resetPassword]").trigger("focus");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if ($("input[name=changePassword]").val() == null || $("input[name=changePassword]").val().trim().length == 0 ){
|
if ($("input[name=changePassword]").val() == null || $("input[name=changePassword]").val().trim().length == 0 ){
|
||||||
alert("<%= localeMessage.getString("login.checkpwd2") %>");
|
alert("<%= localeMessage.getString("login.checkpwd2") %>");
|
||||||
$("input[name=changePassword]").trigger("focus");
|
$("input[name=changePassword]").trigger("focus");
|
||||||
return false;
|
return ;
|
||||||
}
|
}
|
||||||
if ($("input[name=confirmPassword]").val() == null || $("input[name=confirmPassword]").val().trim().length == 0 ){
|
if ($("input[name=confirmPassword]").val() == null || $("input[name=confirmPassword]").val().trim().length == 0 ){
|
||||||
alert("<%= localeMessage.getString("login.checkpwd3") %>");
|
alert("<%= localeMessage.getString("login.checkpwd3") %>");
|
||||||
return false;
|
return ;
|
||||||
}
|
}
|
||||||
if ($("input[name=changePassword]").val() != $("input[name=confirmPassword]").val()){
|
if ($("input[name=confirmPassword]").val() != $("input[name=confirmPassword]").val()){
|
||||||
alert("<%= localeMessage.getString("login.checkpwd4") %>");
|
alert("<%= localeMessage.getString("login.checkpwd4") %>");
|
||||||
$("input[name=confirmPassword]").trigger("focus");
|
$("input[name=confirmPassword]").trigger("focus");
|
||||||
return false;
|
return ;
|
||||||
}
|
}
|
||||||
if ($("input[name=resetUserId]").val() == $("input[name=changePassword]").val()){
|
if ($("input[name=resetUserId]").val() == $("input[name=changePassword]").val()){
|
||||||
alert("<%= localeMessage.getString("login.checkpwd5") %>");
|
alert("<%= localeMessage.getString("login.checkpwd5") %>");
|
||||||
$("input[name=changePassword]").trigger("focus");
|
$("input[name=changePassword]").trigger("focus");
|
||||||
return false;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
//if (idCheck.checked){
|
||||||
|
// setCookie("key",id);
|
||||||
|
//}
|
||||||
|
<%-- $("form").attr("action","<c:url value="/changePassword.do"/>");
|
||||||
|
//$("form").action = "<%=request.getContextPath()%>/changePassword.do";
|
||||||
|
--%>
|
||||||
|
$("form").submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
@@ -276,22 +271,14 @@
|
|||||||
});
|
});
|
||||||
$("input[name=changePassword]").keydown(function(event){
|
$("input[name=changePassword]").keydown(function(event){
|
||||||
if ( event.which == 13 ) {
|
if ( event.which == 13 ) {
|
||||||
$('#modalLoginForm').submit();
|
changePwd();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("input[name=confirmPassword]").keydown(function(event){
|
$("input[name=confirmPassword]").keydown(function(event){
|
||||||
if ( event.which == 13 ) {
|
if ( event.which == 13 ) {
|
||||||
$('#modalLoginForm').submit();
|
changePwd();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Password Change 링크로 직접 열 때만 초기화 (JS에서 modal('show') 호출 시 relatedTarget 없음)
|
|
||||||
$('#pwdChgModal').on('show.bs.modal', function(event) {
|
|
||||||
if (event.relatedTarget) {
|
|
||||||
$('#modalLoginForm')[0].reset();
|
|
||||||
$('#changeInitPassword').show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("select[name=serviceType]").change(function(){
|
$("select[name=serviceType]").change(function(){
|
||||||
fncPreMain();
|
fncPreMain();
|
||||||
});
|
});
|
||||||
@@ -299,7 +286,9 @@
|
|||||||
$("#btn_login").click(function(){
|
$("#btn_login").click(function(){
|
||||||
fncPreMain();
|
fncPreMain();
|
||||||
});
|
});
|
||||||
|
$("#changePwd").click(function(){
|
||||||
|
changePwd();
|
||||||
|
});
|
||||||
$("#btn_sso_login").click(function(){
|
$("#btn_sso_login").click(function(){
|
||||||
fncSsoLogin();
|
fncSsoLogin();
|
||||||
});
|
});
|
||||||
@@ -377,7 +366,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 비밀번호 변경 모달 -->
|
|
||||||
<div class="modal fade" id="pwdChgModal" tabindex="-1" role="dialog" aria-labelledby="pwdChgModalLabel" aria-hidden="true">
|
<div class="modal fade" id="pwdChgModal" tabindex="-1" role="dialog" aria-labelledby="pwdChgModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -387,15 +376,13 @@
|
|||||||
<span aria-hidden="true">X</span>
|
<span aria-hidden="true">X</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<form id="modalLoginForm" action="<c:url value="/changePassword.do"/>" method="post" onsubmit="return checkPwd()" novalidate>
|
<form name="form" id="modalLoginForm" action="<c:url value="/changePassword.do"/>" method="post">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div id="changeInitPassword">
|
<div class="form-group d-flex">
|
||||||
<div class="form-group d-flex">
|
<input type="text" name="resetUserId" class="form-control rounded-left" placeholder="User Id" required>
|
||||||
<input type="text" name="resetUserId" class="form-control rounded-left" placeholder="User Id" required>
|
</div>
|
||||||
</div>
|
<div class="form-group d-flex">
|
||||||
<div class="form-group d-flex">
|
<input type="password" name="resetPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderCurrentPassword") %>" autocomplete="off" required>
|
||||||
<input type="password" name="resetPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderCurrentPassword") %>" autocomplete="off" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<p><%= localeMessage.getString("login.toChangePasswordMessage") %></p>
|
<p><%= localeMessage.getString("login.toChangePasswordMessage") %></p>
|
||||||
<div class="form-group d-flex">
|
<div class="form-group d-flex">
|
||||||
@@ -404,12 +391,9 @@
|
|||||||
<div class="form-group d-flex">
|
<div class="form-group d-flex">
|
||||||
<input type="password" name="confirmPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderConfirmationPassword") %>" autocomplete="off" required>
|
<input type="password" name="confirmPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderConfirmationPassword") %>" autocomplete="off" required>
|
||||||
</div>
|
</div>
|
||||||
<span style="font-size:0.8em; color:red">
|
|
||||||
※ 7글자 이상 & 영문/숫자/특수문자 2종류 이상
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="submit" id="changePwd" class="form-control btn btn-primary rounded submit px-3">변경</button>
|
<input type="button" id ="changePwd" class="form-control btn btn-primary rounded submit px-3" value="변경">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -52,13 +52,6 @@
|
|||||||
var urlParam = window.document.location.search;
|
var urlParam = window.document.location.search;
|
||||||
var mod = "";
|
var mod = "";
|
||||||
var strServiceType = "<%=request.getParameter("serviceType")%>";
|
var strServiceType = "<%=request.getParameter("serviceType")%>";
|
||||||
function getServiceType() {
|
|
||||||
var serviceType = sessionStorage.getItem("serviceType");
|
|
||||||
if (!serviceType || serviceType == "undefined" || serviceType == "null") {
|
|
||||||
serviceType = localStorage.getItem("serviceType") || "";
|
|
||||||
}
|
|
||||||
return serviceType;
|
|
||||||
}
|
|
||||||
if(urlParam != ""){
|
if(urlParam != ""){
|
||||||
if(urlParam.indexOf("mod=") > -1){
|
if(urlParam.indexOf("mod=") > -1){
|
||||||
mod = urlParam.substring((urlParam.indexOf("mod=") + 4), urlParam.lastIndexOf("&"));
|
mod = urlParam.substring((urlParam.indexOf("mod=") + 4), urlParam.lastIndexOf("&"));
|
||||||
@@ -74,18 +67,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var url = '<%=topPage%>';
|
var url = '<%=topPage%>';
|
||||||
var serviceType = getServiceType();
|
if (url.indexOf("?")>=0){
|
||||||
if (serviceType) {
|
url = url + "&serviceType="+ sessionStorage["serviceType"];
|
||||||
if (url.indexOf("?")>=0){
|
}else{
|
||||||
url = url + "&serviceType="+ serviceType;
|
url = url + "?serviceType="+ sessionStorage["serviceType"];
|
||||||
}else{
|
|
||||||
url = url + "?serviceType="+ serviceType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#topFrame").attr('src',url);
|
$("#topFrame").attr('src',url);
|
||||||
|
|
||||||
$(".topMenu").load(function(){ // iframe이 모두 load된후 제어
|
$(".topMenu").load(function(){ // iframe이 모두 load된후 제어
|
||||||
$(".topMenu").contents().find('.gnb').on("mouseenter", function(e){
|
$(".topMenu").contents().find('.gnb').on("mouseenter", function(e){
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
<%@page import="com.eactive.eai.rms.common.util.StringUtils" %>
|
<%@page import="com.eactive.eai.rms.common.util.StringUtils" %>
|
||||||
<%@page import="com.eactive.eai.rms.common.datasource.DataSourceType" %>
|
<%@page import="com.eactive.eai.rms.common.datasource.DataSourceType" %>
|
||||||
<%@page import="com.eactive.eai.rms.common.datasource.DataSourceTypeManager" %>
|
<%@page import="com.eactive.eai.rms.common.datasource.DataSourceTypeManager" %>
|
||||||
<%@page import="com.eactive.eai.common.util.ApplicationContextProvider" %>
|
|
||||||
<%@page import="com.eactive.eai.rms.data.entity.man.role.RoleMenuAuthService" %>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||||
@@ -18,12 +16,6 @@
|
|||||||
<%
|
<%
|
||||||
String serviceKey = SessionManager.getServiceTypeKey(request);
|
String serviceKey = SessionManager.getServiceTypeKey(request);
|
||||||
String serviceText = DataSourceTypeManager.getDataSourceType(serviceKey).getText();
|
String serviceText = DataSourceTypeManager.getDataSourceType(serviceKey).getText();
|
||||||
|
|
||||||
final String SITEMAP_MENU_ID = "0510013";
|
|
||||||
RoleMenuAuthService roleMenuAuthService = ApplicationContextProvider.getContext().getBean(RoleMenuAuthService.class);
|
|
||||||
String sitemapMenuAuth = roleMenuAuthService.getRoleList(SessionManager.getUserId(request), SITEMAP_MENU_ID, serviceKey);
|
|
||||||
boolean showSitemapLink = "R".equals(sitemapMenuAuth) || "W".equals(sitemapMenuAuth);
|
|
||||||
|
|
||||||
String roleScreenId = (String) request.getAttribute("roleScreenId");
|
String roleScreenId = (String) request.getAttribute("roleScreenId");
|
||||||
String mainPage = (String) request.getAttribute("mainPage");
|
String mainPage = (String) request.getAttribute("mainPage");
|
||||||
String menuId = (String) request.getAttribute("menuId");
|
String menuId = (String) request.getAttribute("menuId");
|
||||||
@@ -248,12 +240,6 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="<c:url value="/css/web_ui.css"/>"/>
|
<link rel="stylesheet" type="text/css" media="screen" href="<c:url value="/css/web_ui.css"/>"/>
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="<c:url value="/css/theme_${themeColor}.css"/>"/>
|
<link rel="stylesheet" type="text/css" media="screen" href="<c:url value="/css/theme_${themeColor}.css"/>"/>
|
||||||
<style>
|
|
||||||
.topmenu_box .sitemap-link { display: inline-block; width: 80px; height: 80px; line-height: 80px; box-sizing: border-box; font-size: 14px; color: #666; text-align: center; opacity: 0.7; transition: all 0.3s; margin-top: 0px; }
|
|
||||||
.topmenu_box .sitemap-link:hover { opacity: 1; }
|
|
||||||
.topmenu_box .logout-link { line-height: 80px; margin-top:0; }
|
|
||||||
.topmenu_box > ul li:last-child > a:before { display: none; }
|
|
||||||
</style>
|
|
||||||
<script language="javascript" src="<c:url value="/js/jquery-1.12.1.min.js"/>"></script>
|
<script language="javascript" src="<c:url value="/js/jquery-1.12.1.min.js"/>"></script>
|
||||||
<script language="javascript" src="<c:url value="/js/prefixfree.min.js"/>"></script>
|
<script language="javascript" src="<c:url value="/js/prefixfree.min.js"/>"></script>
|
||||||
<script language="javascript" src="<c:url value="/js/jquery.cookie.js"/>"></script>
|
<script language="javascript" src="<c:url value="/js/jquery.cookie.js"/>"></script>
|
||||||
@@ -317,11 +303,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//왼쪽메뉴, 메인 페이지 이동
|
//왼쪽메뉴, 메인 페이지 이동
|
||||||
function goPage2(page1, page2, page2_id) {
|
function goPage2(page1, page2, page2_id) {
|
||||||
parent.leftFrame.location.href = goNavUrl(page1);
|
parent.leftFrame.location.href = goNavUrl(page1);
|
||||||
parent.mainFrame.location.href = goNavUrl(page2);
|
parent.mainFrame.location.href = goNavUrl(page2);
|
||||||
}
|
}
|
||||||
|
|
||||||
var sessionAjax = createAjaxRequest();
|
var sessionAjax = createAjaxRequest();
|
||||||
|
|
||||||
function getAjaxData() {
|
function getAjaxData() {
|
||||||
@@ -543,7 +529,6 @@
|
|||||||
console.log("selectLocaleValue : " + selectLocaleValue);
|
console.log("selectLocaleValue : " + selectLocaleValue);
|
||||||
parent.changeLocale($(this).val());
|
parent.changeLocale($(this).val());
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
@@ -566,28 +551,21 @@
|
|||||||
</h1><!-- /monitoring/images/top_logo.png -->
|
</h1><!-- /monitoring/images/top_logo.png -->
|
||||||
<div class="topmenu_box">
|
<div class="topmenu_box">
|
||||||
<ul>
|
<ul>
|
||||||
<li style="width:240px;">
|
<li style="width:240px;" id="newDashboardShow">
|
||||||
<a style="width:240px; cursor: default"
|
<a style="width:240px;"
|
||||||
href="#"><span><%=SessionManager.getUserName(request) %>(<%=SessionManager.getUserId(request) %>-<%=System.getProperty("inst.Name") %>)</span>
|
href="#"><span><%=SessionManager.getUserName(request) %>(<%=SessionManager.getUserId(request) %>-<%=System.getProperty("inst.Name") %>)</span>
|
||||||
<span onClick="javascript:openColorPopup();"><%=localeMessage.getString("screen.customer") %></span>
|
<span onClick="javascript:openColorPopup();"><%=localeMessage.getString("screen.customer") %></span>
|
||||||
<% if (!"".equals(LastLoginYms.trim())) { %>
|
<% if (!"".equals(LastLoginYms.trim())) { %>
|
||||||
<span style="display:block;font-size:10px;"><%=localeMessage.getString("screen.lastLogin") %> : <%=LastLoginYms%> [ <%=LastLoginIp%> ]</span>
|
<span style="display:block;font-size:10px;"><%=localeMessage.getString("screen.lastLogin") %> : <%=LastLoginYms%> [ <%=LastLoginIp%> ]</span>
|
||||||
<% } %>
|
<% } %>
|
||||||
</a></li>
|
</a></li>
|
||||||
<li style="width:100px; line-height:80px; text-align:center;">
|
<li>
|
||||||
<select id="selectLocale" name="locale" style="width:60px; padding: 2px; text-align:center;">
|
<select id="selectLocale" name="locale" style="margin-top: 20px; width:80px">
|
||||||
<option value="en">English</option>
|
<option value="en">English</option>
|
||||||
<option value="ko">한글</option>
|
<option value="ko">한글</option>
|
||||||
</select>
|
</select>
|
||||||
</li>
|
</li>
|
||||||
<% if (showSitemapLink) { %>
|
<li onclick="logout()"><a href="#" class=""><img src="<c:url value="/img/icon_logout.png"/>"
|
||||||
<li>
|
|
||||||
<a href="<c:url value="/common/acl/sitemap/sitemapMan.view"><c:param name="menuId" value="<%=SITEMAP_MENU_ID%>"/><c:param name="serviceType" value="<%=serviceKey%>"/></c:url>" target="mainFrame" class="sitemap-link">
|
|
||||||
<%= localeMessage.getString("screen.sitemap") %>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<% } %>
|
|
||||||
<li onclick="logout()"><a href="#" class="logout-link"><img src="<c:url value="/img/icon_logout.png"/>"
|
|
||||||
alt=""/><%= localeMessage.getString("screen.logout") %>
|
alt=""/><%= localeMessage.getString("screen.logout") %>
|
||||||
</a></li>
|
</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* 문자열 마스킹 처리를 위한 유틸리티
|
* 문자열 마스킹 처리를 위한 유틸리티
|
||||||
*
|
|
||||||
* 보안아키텍처 표준 마스킹 규칙(Java MaskingUtils)과 동일한 결과를 내도록 구현한다.
|
|
||||||
* 이름 2자: 뒤 1자리(가나→가*) / 3자 이상: 앞뒤 제외 가운데 전체(가나다라→가**라)
|
|
||||||
* 이메일 아이디 앞2·뒤2 마스킹, 4자 이하 전체(test→****, test123→**st1**)
|
|
||||||
* 전화 2·3번째 세그먼트 각각 뒤 2자리(010-1234-1234→010-12**-12**)
|
|
||||||
*/
|
*/
|
||||||
const StringMaskingUtil = {
|
const StringMaskingUtil = {
|
||||||
|
|
||||||
@@ -13,51 +8,41 @@ const StringMaskingUtil = {
|
|||||||
return str != null && str !== '';
|
return str != null && str !== '';
|
||||||
},
|
},
|
||||||
|
|
||||||
// '*' 반복 생성
|
// 이름 마스킹 처리
|
||||||
_stars: function(count) {
|
|
||||||
return count > 0 ? '*'.repeat(count) : '';
|
|
||||||
},
|
|
||||||
|
|
||||||
// 세그먼트 뒤 count 자리 마스킹
|
|
||||||
_maskSegmentTail: function(segment, count) {
|
|
||||||
if (segment.length <= count) {
|
|
||||||
return this._stars(segment.length);
|
|
||||||
}
|
|
||||||
return segment.substring(0, segment.length - count) + this._stars(count);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 이름 마스킹 처리 (2자: 뒤 1자리, 3자 이상: 앞뒤 제외 가운데 전체)
|
|
||||||
maskName: function(name) {
|
maskName: function(name) {
|
||||||
if (!this.isValidString(name)) {
|
if (!this.isValidString(name)) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
const len = name.length;
|
return name.length > 1 ?
|
||||||
if (len === 1) {
|
name.substring(0, name.length - 1) + "*" :
|
||||||
return name;
|
name;
|
||||||
}
|
|
||||||
if (len === 2) {
|
|
||||||
return name.charAt(0) + '*';
|
|
||||||
}
|
|
||||||
return name.charAt(0) + this._stars(len - 2) + name.charAt(len - 1);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 이메일 마스킹 처리 (아이디 앞2·뒤2, 4자 이하 전체)
|
// 이메일 마스킹 처리
|
||||||
maskEmail: function(email) {
|
maskEmail: function(email) {
|
||||||
if (!this.isValidString(email) || !email.includes('@')) {
|
if (!this.isValidString(email) || !email.includes('@')) {
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
const atIdx = email.indexOf('@');
|
const parts = email.split('@');
|
||||||
const local = email.substring(0, atIdx);
|
if (parts.length !== 2) {
|
||||||
const domain = email.substring(atIdx);
|
return email;
|
||||||
|
|
||||||
if (local.length <= 4) {
|
|
||||||
return this._stars(local.length) + domain;
|
|
||||||
}
|
}
|
||||||
return this._stars(2) + local.substring(2, local.length - 2) + this._stars(2) + domain;
|
|
||||||
|
const localPart = parts[0];
|
||||||
|
let maskedLocal;
|
||||||
|
|
||||||
|
if (localPart.length <= 3) {
|
||||||
|
maskedLocal = localPart.substring(0, 1) +
|
||||||
|
'*'.repeat(localPart.length - 1);
|
||||||
|
} else {
|
||||||
|
maskedLocal = localPart.substring(0, localPart.length - 3) + '***';
|
||||||
|
}
|
||||||
|
|
||||||
|
return maskedLocal + '@' + parts[1];
|
||||||
},
|
},
|
||||||
|
|
||||||
// 휴대폰/전화 번호 마스킹 처리 (2·3번째 세그먼트 각각 뒤 2자리)
|
// 휴대폰 번호 마스킹 처리
|
||||||
maskMobileNumber: function(number) {
|
maskMobileNumber: function(number) {
|
||||||
if (!this.isValidString(number)) {
|
if (!this.isValidString(number)) {
|
||||||
return number;
|
return number;
|
||||||
@@ -65,10 +50,8 @@ const StringMaskingUtil = {
|
|||||||
|
|
||||||
const parts = number.split('-');
|
const parts = number.split('-');
|
||||||
if (parts.length === 3) {
|
if (parts.length === 3) {
|
||||||
return parts[0] + '-' +
|
return parts[0] + '-****-' + parts[2];
|
||||||
this._maskSegmentTail(parts[1], 2) + '-' +
|
|
||||||
this._maskSegmentTail(parts[2], 2);
|
|
||||||
}
|
}
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -82,10 +82,8 @@
|
|||||||
apiDesc: api.eaiSvcDesc
|
apiDesc: api.eaiSvcDesc
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// addJSONData는 datatype:"local" 그리드의 p.data를 채우지 않아, 헤더 클릭 정렬 시 p.data(빈 배열) 기준으로 다시 그려지며 행이 사라짐.
|
|
||||||
// setGridParam({data:...}).trigger('reloadGrid')로 채워야 정렬이 정상 동작함.
|
|
||||||
$("#selectedApiGrid").jqGrid("clearGridData");
|
$("#selectedApiGrid").jqGrid("clearGridData");
|
||||||
$("#selectedApiGrid").jqGrid('setGridParam', {data: gridData}).trigger('reloadGrid');
|
$("#selectedApiGrid")[0].addJSONData(gridData);
|
||||||
|
|
||||||
var data = json;
|
var data = json;
|
||||||
$("#btn_gen_id").hide();
|
$("#btn_gen_id").hide();
|
||||||
@@ -135,14 +133,15 @@
|
|||||||
var selectedApiGrid = $("#selectedApiGrid");
|
var selectedApiGrid = $("#selectedApiGrid");
|
||||||
selectedApiGrid.jqGrid({
|
selectedApiGrid.jqGrid({
|
||||||
datatype: "local",
|
datatype: "local",
|
||||||
rownumbers: true, // 가상 인덱스
|
gridview: true, // 성능 향상
|
||||||
|
rownumbers: true, // 가상 인덱스
|
||||||
rownumWidth: 40,
|
rownumWidth: 40,
|
||||||
colNames: ['API ID', 'API 이름'],
|
colNames: ['API ID', 'API 이름'],
|
||||||
colModel: [
|
colModel: [
|
||||||
{name: 'apiId', index: 'apiId', width: 100, align: 'center'},
|
{name: 'apiId', index: 'apiId', width: 100, align: 'center'},
|
||||||
{name: 'apiDesc', index: 'apiDesc', width: 100, align: 'center'}
|
{name: 'apiDesc', index: 'apiDesc', width: 100, align: 'center'}
|
||||||
],
|
],
|
||||||
rowNum: 9999,
|
rowNum: -1,
|
||||||
// rowList: [10, 20, 30],
|
// rowList: [10, 20, 30],
|
||||||
// pager: '#selectedApiGridPager',
|
// pager: '#selectedApiGridPager',
|
||||||
// sortname: 'apiId',
|
// sortname: 'apiId',
|
||||||
@@ -157,8 +156,8 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
selectedApiGrid.jqGrid('setLabel', 'rn', 'No'); // 가상 인덱스 ColNames
|
selectedApiGrid.jqGrid('setLabel', 'rn', 'No'); // 가상 인덱스 ColNames
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: url,
|
url: url,
|
||||||
@@ -451,8 +450,8 @@
|
|||||||
</div><!-- end content_top -->
|
</div><!-- end content_top -->
|
||||||
<div class="content_middle">
|
<div class="content_middle">
|
||||||
<div class="search_wrap">
|
<div class="search_wrap">
|
||||||
<!-- <button type="button" class="cssbtn" id="btn_sync_portal" level="W" status="DETAIL"><i class="material-icons">sync</i> 개발자포탈 정보 반영
|
<button type="button" class="cssbtn" id="btn_sync_portal" level="W" status="DETAIL"><i class="material-icons">sync</i> 개발자포탈 정보 반영
|
||||||
</button> -->
|
</button>
|
||||||
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL"><i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %>
|
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL"><i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="cssbtn" id="btn_modify" level="W" status="DETAIL,NEW"><i
|
<button type="button" class="cssbtn" id="btn_modify" level="W" status="DETAIL,NEW"><i
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
var url = '<c:url value="/onl/admin/authserver/scopeMan.json" />';
|
var url = '<c:url value="/onl/admin/authserver/scopeMan.json" />';
|
||||||
var url_view = '<c:url value="/onl/admin/authserver/scopeMan.view" />';
|
var url_view = '<c:url value="/onl/admin/authserver/scopeMan.view" />';
|
||||||
var api_url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view" />';
|
var api_url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view" />';
|
||||||
|
var mapping_url = '<c:url value="/onl/admin/authserver/apiScopeMan.json" />';
|
||||||
|
|
||||||
var isDetail = false;
|
var isDetail = false;
|
||||||
function isValid(){
|
function isValid(){
|
||||||
@@ -64,9 +65,9 @@ function mappingInfo(key){
|
|||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : "POST",
|
type : "POST",
|
||||||
url: url,
|
url: mapping_url,
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
data: {cmd: 'API_LIST', searchScopeId : key},
|
data: {cmd: 'LIST', searchScopeId : key},
|
||||||
success: function(json){
|
success: function(json){
|
||||||
var mappingData = json.rows;
|
var mappingData = json.rows;
|
||||||
|
|
||||||
@@ -130,6 +131,45 @@ function init(key, callback){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveApiGridData(scopeId, returnUrl) {
|
||||||
|
var postData = [];
|
||||||
|
var rows = $("#selectedApiGrid").jqGrid('getRowData');
|
||||||
|
|
||||||
|
$.each(rows, function(index, item) {
|
||||||
|
item.scopeId = scopeId;
|
||||||
|
});
|
||||||
|
|
||||||
|
postData.push({
|
||||||
|
name: "apiList",
|
||||||
|
value: JSON.stringify(rows)
|
||||||
|
});
|
||||||
|
|
||||||
|
postData.push({ name: "cmd" , value:"INSERT_APILIST" });
|
||||||
|
postData.push({ name: "scopeId" , value:scopeId });
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type : "POST",
|
||||||
|
url:mapping_url,
|
||||||
|
data: postData,
|
||||||
|
beforeSend: function() {
|
||||||
|
$("[id^='btn_']").prop("disabled", true);
|
||||||
|
$("#btn_modify").text("처리중 . . . . .");
|
||||||
|
},
|
||||||
|
success:function(args){
|
||||||
|
alert("저장 되었습니다.");
|
||||||
|
|
||||||
|
goNav(returnUrl);//LIST로 이동
|
||||||
|
},
|
||||||
|
error:function(e){
|
||||||
|
alert(e.responseText);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$("[id^='btn_']").prop("disabled", false);
|
||||||
|
$("#btn_modify").text("수정");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var returnUrl = getReturnUrlForReturn();
|
var returnUrl = getReturnUrlForReturn();
|
||||||
var key ="${param.scopeId}";
|
var key ="${param.scopeId}";
|
||||||
@@ -142,39 +182,28 @@ $(document).ready(function() {
|
|||||||
if (!isValid()){
|
if (!isValid()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var scopeId = $('input[name=scopeId]').val();
|
|
||||||
var postData = $('#ajaxForm').serializeArray();
|
var postData = $('#ajaxForm').serializeArray();
|
||||||
|
|
||||||
var rows = $("#selectedApiGrid").jqGrid('getRowData');
|
|
||||||
$.each(rows, function(index, item) {
|
|
||||||
item.scopeId = scopeId;
|
|
||||||
});
|
|
||||||
postData.push({ name: "apiList" , value: JSON.stringify(rows) });
|
|
||||||
|
|
||||||
if (isDetail){
|
if (isDetail){
|
||||||
postData.push({ name: "cmd" , value:"UPDATE"});
|
postData.push({ name: "cmd" , value:"UPDATE"});
|
||||||
}else{
|
}else{
|
||||||
postData.push({ name: "cmd" , value:"INSERT"});
|
postData.push({ name: "cmd" , value:"INSERT"});
|
||||||
}
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : "POST",
|
type : "POST",
|
||||||
url:url,
|
url:url,
|
||||||
data:postData,
|
data:postData,
|
||||||
beforeSend: function() {
|
|
||||||
$("[id^='btn_']").prop("disabled", true);
|
|
||||||
$("#btn_modify").text("처리중 . . . . .");
|
|
||||||
},
|
|
||||||
success:function(args){
|
success:function(args){
|
||||||
alert("저장 되었습니다.");
|
alert("SCOPE 정보가 저장 되었습니다. 이어서 API 리스트를 저장합니다.");
|
||||||
goNav(returnUrl);//LIST로 이동
|
|
||||||
|
if(!isDetail) { // INSERT 일 경우 ScopeId를 업데이트
|
||||||
|
key = $('input[name=scopeId]').val();
|
||||||
|
}
|
||||||
|
saveApiGridData(key, returnUrl); // API LIST 저장.
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
error:function(e){
|
error:function(e){
|
||||||
alert(e.responseText);
|
alert(e.responseText);
|
||||||
},
|
|
||||||
complete: function() {
|
|
||||||
$("[id^='btn_']").prop("disabled", false);
|
|
||||||
$("#btn_modify").text("수정");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -250,29 +250,6 @@ var url_view = '<c:url value="/onl/admin/common/propertyMan.view" />';
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_pop_encrypt").click(function() {
|
|
||||||
var prpty2Val = $("input[name=prpty2Val]").val();
|
|
||||||
if (prpty2Val == '') {
|
|
||||||
alert("프라퍼티 값을 입력하세요");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var postData = {
|
|
||||||
cmd : "ENCRYPT",
|
|
||||||
prpty2Val : prpty2Val,
|
|
||||||
};
|
|
||||||
$.ajax({
|
|
||||||
type : "POST",
|
|
||||||
url : url,
|
|
||||||
data : postData,
|
|
||||||
success : function(args) {
|
|
||||||
$("input[name=prpty2Val]").val(args);
|
|
||||||
},
|
|
||||||
error : function(e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonControl(key);
|
buttonControl(key);
|
||||||
titleControl(key);
|
titleControl(key);
|
||||||
@@ -312,17 +289,12 @@ var url_view = '<c:url value="/onl/admin/common/propertyMan.view" />';
|
|||||||
<table class="table_row" cellspacing="0">
|
<table class="table_row" cellspacing="0">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:20%;"><%= localeMessage.getString("propertyDetail.propertyKey") %></th>
|
<th style="width:20%;"><%= localeMessage.getString("propertyDetail.propertyKey") %></th>
|
||||||
<td>
|
<td><input type="text" name="prptyName" style="width:calc(100% - 85px);" /> <!-- <img src="<c:url value="/img/btn_pop_input.png"/>" id="btn_pop_input" /></td> -->
|
||||||
<input type="text" name="prptyName" style="width:calc(100% - 85px);" /> <!-- <img src="<c:url value="/img/btn_pop_input.png"/>" id="btn_pop_input" /></td> -->
|
<button type="button" class="cssbtn smallBtn2" id="btn_pop_input" style="vertical-align:middle; font-weight:bold;"><i class="material-icons">input</i><%= localeMessage.getString("button.input") %></button>
|
||||||
<button type="button" class="cssbtn smallBtn2" id="btn_pop_input" style="vertical-align:middle; font-weight:bold;"><i class="material-icons">input</i><%= localeMessage.getString("button.input") %></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:20%;"><%= localeMessage.getString("propertyDetail.propertyValue") %></th>
|
<th><%= localeMessage.getString("propertyDetail.propertyValue") %></th>
|
||||||
<td>
|
<td><input type="text" name="prpty2Val"/></td>
|
||||||
<input type="text" name="prpty2Val" style="width:calc(100% - 85px);"/>
|
|
||||||
<button type="button" class="cssbtn smallBtn2" id="btn_pop_encrypt" style="vertical-align:middle; font-weight:bold;"><i class="material-icons">lock</i><%= localeMessage.getString("button.encode") %></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<!-- grid -->
|
<!-- grid -->
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ $(document).ready(function() {
|
|||||||
datatype:"json",
|
datatype:"json",
|
||||||
mtype: 'POST',
|
mtype: 'POST',
|
||||||
url: url,
|
url: url,
|
||||||
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()},
|
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val()},
|
||||||
colNames:['<%= localeMessage.getString("infAdpConMan.adaNm") %>',
|
colNames:['<%= localeMessage.getString("infAdpConMan.adaNm") %>',
|
||||||
'<%= localeMessage.getString("infAdpConMan.adaDes") %>',
|
'<%= localeMessage.getString("infAdpConMan.adaDes") %>',
|
||||||
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
|
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
|
||||||
@@ -62,7 +62,6 @@ $(document).ready(function() {
|
|||||||
url2 += '&menuId='+'${param.menuId}';
|
url2 += '&menuId='+'${param.menuId}';
|
||||||
//검색값
|
//검색값
|
||||||
url2 += '&searchName='+$("input[name=searchName]").val();
|
url2 += '&searchName='+$("input[name=searchName]").val();
|
||||||
url2 += '&searchUseYn='+$("select[name=searchUseYn]").val();
|
|
||||||
//key값
|
//key값
|
||||||
url2 += '&name='+name;
|
url2 += '&name='+name;
|
||||||
goNav(url2);
|
goNav(url2);
|
||||||
@@ -81,7 +80,7 @@ $(document).ready(function() {
|
|||||||
resizeJqGridWidth('grid','content_middle','1000');
|
resizeJqGridWidth('grid','content_middle','1000');
|
||||||
|
|
||||||
$("#btn_search").click(function(){
|
$("#btn_search").click(function(){
|
||||||
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()}, page:1 }).trigger("reloadGrid");
|
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val()}, page:1 }).trigger("reloadGrid");
|
||||||
});
|
});
|
||||||
$("#btn_new").click(function(){
|
$("#btn_new").click(function(){
|
||||||
var url2 = url_view;
|
var url2 = url_view;
|
||||||
@@ -127,16 +126,6 @@ $(document).ready(function() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th style="width:180px;"><%= localeMessage.getString("infAdpConMan.adaNm") %></th>
|
<th style="width:180px;"><%= localeMessage.getString("infAdpConMan.adaNm") %></th>
|
||||||
<td><input type="text" name="searchName" value="${param.searchName}"></td>
|
<td><input type="text" name="searchName" value="${param.searchName}"></td>
|
||||||
<th style="width:180px;"><%= localeMessage.getString("infAdpConMan.useYn") %></th>
|
|
||||||
<td>
|
|
||||||
<div class="select-style">
|
|
||||||
<select name="searchUseYn">
|
|
||||||
<option value="">전체</option>
|
|
||||||
<option value="1">사용함</option>
|
|
||||||
<option value="0">사용안함</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ $(document).ready(function() {
|
|||||||
datatype:"json",
|
datatype:"json",
|
||||||
mtype: 'POST',
|
mtype: 'POST',
|
||||||
url: url,
|
url: url,
|
||||||
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()},
|
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val()},
|
||||||
colNames:['클라이언트 ID',
|
colNames:['클라이언트 ID',
|
||||||
'클라이언트명',
|
'클라이언트명',
|
||||||
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
|
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
|
||||||
@@ -62,7 +62,6 @@ $(document).ready(function() {
|
|||||||
url2 += '&menuId='+'${param.menuId}';
|
url2 += '&menuId='+'${param.menuId}';
|
||||||
//검색값
|
//검색값
|
||||||
url2 += '&searchName='+$("input[name=searchName]").val();
|
url2 += '&searchName='+$("input[name=searchName]").val();
|
||||||
url2 += '&searchUseYn='+$("select[name=searchUseYn]").val();
|
|
||||||
//key값
|
//key값
|
||||||
url2 += '&name='+name;
|
url2 += '&name='+name;
|
||||||
goNav(url2);
|
goNav(url2);
|
||||||
@@ -81,7 +80,7 @@ $(document).ready(function() {
|
|||||||
resizeJqGridWidth('grid','content_middle','1000');
|
resizeJqGridWidth('grid','content_middle','1000');
|
||||||
|
|
||||||
$("#btn_search").click(function(){
|
$("#btn_search").click(function(){
|
||||||
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()}, page:1 }).trigger("reloadGrid");
|
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val()}, page:1 }).trigger("reloadGrid");
|
||||||
});
|
});
|
||||||
$("#btn_new").click(function(){
|
$("#btn_new").click(function(){
|
||||||
var url2 = url_view;
|
var url2 = url_view;
|
||||||
@@ -91,8 +90,7 @@ $(document).ready(function() {
|
|||||||
url2 += '&menuId='+'${param.menuId}';
|
url2 += '&menuId='+'${param.menuId}';
|
||||||
//검색값
|
//검색값
|
||||||
url2 += '&searchName=';
|
url2 += '&searchName=';
|
||||||
url2 += '&searchUseYn='+$('select[name=searchUseYn]').val();
|
|
||||||
|
|
||||||
goNav(url2);
|
goNav(url2);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -126,16 +124,6 @@ $(document).ready(function() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th style="width:180px;">클라이언트명</th>
|
<th style="width:180px;">클라이언트명</th>
|
||||||
<td><input type="text" name="searchName" value="${param.searchName}"></td>
|
<td><input type="text" name="searchName" value="${param.searchName}"></td>
|
||||||
<th style="width:180px;">사용여부</th>
|
|
||||||
<td>
|
|
||||||
<div class="select-style">
|
|
||||||
<select name="searchUseYn">
|
|
||||||
<option value="">전체</option>
|
|
||||||
<option value="1">사용함</option>
|
|
||||||
<option value="0">사용안함</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -298,7 +298,6 @@ $(document).ready(function() {
|
|||||||
url: url,
|
url: url,
|
||||||
data: postData,
|
data: postData,
|
||||||
success: function(args) {
|
success: function(args) {
|
||||||
console.log('mod', args);
|
|
||||||
showAlert("<%= localeMessage.getString("common.saveMsg") %>", {
|
showAlert("<%= localeMessage.getString("common.saveMsg") %>", {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: '저장 완료',
|
title: '저장 완료',
|
||||||
@@ -494,6 +493,11 @@ $(document).ready(function() {
|
|||||||
<span class="bucket-summary-value" id="summaryThreshold">0<span class="unit">req</span></span>
|
<span class="bucket-summary-value" id="summaryThreshold">0<span class="unit">req</span></span>
|
||||||
<span class="bucket-summary-sub" id="summaryThresholdCalc"></span>
|
<span class="bucket-summary-sub" id="summaryThresholdCalc"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="bucket-summary-item">
|
||||||
|
<span class="bucket-summary-label">적용 API</span>
|
||||||
|
<span class="bucket-summary-value" id="summaryActiveApi">0<span class="unit">개</span></span>
|
||||||
|
<span class="bucket-summary-sub" id="summaryActiveApiList"></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -47,40 +47,27 @@ function groupNameFormat(cellvalue, options, rowObject) {
|
|||||||
return strVal;
|
return strVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$("input[name=searchStartYYYYMMDD],input[name=searchEndYYYYMMDD]").inputmask("yyyy-mm-dd",{'autoUnmask':true});
|
$("input[name=searchStartYYYYMMDD],input[name=searchEndYYYYMMDD]").inputmask("yyyy-mm-dd",{'autoUnmask':true});
|
||||||
$("input[name=searchStartTime],input[name=searchEndTime]").inputmask("hh:mm:ss",{'autoUnmask':true});
|
|
||||||
|
|
||||||
$("input[name=searchStartYYYYMMDD]").each(function(){
|
$("input[name=searchStartYYYYMMDD]").each(function(){
|
||||||
if ($(this).val() == undefined || $(this).val() == null || $(this).val() == ""){
|
if ($(this).val() == undefined || $(this).val() == null || $(this).val() == ""){
|
||||||
$(this).val(getToday());
|
$(this).val(getToday());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("input[name=searchEndYYYYMMDD]").each(function(){
|
$("input[name=searchEndYYYYMMDD]").each(function(){
|
||||||
if ($(this).val() == undefined || $(this).val() == null || $(this).val() == ""){
|
if ($(this).val() == undefined || $(this).val() == null || $(this).val() == ""){
|
||||||
$(this).val(getToday());
|
$(this).val(getToday());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("input[name=searchStartTime]").each(function(){
|
|
||||||
if ($(this).val() == undefined || $(this).val() == null || $(this).val() == ""){
|
var gridPostData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
||||||
$(this).val("000000");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("input[name=searchEndTime]").each(function(){
|
|
||||||
if ($(this).val() == undefined || $(this).val() == null || $(this).val() == ""){
|
|
||||||
$(this).val("235959");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var gridPostData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
|
||||||
|
|
||||||
var start = $("input[name=searchStartYYYYMMDD]").val().replace(/-/gi,"");
|
var start = $("input[name=searchStartYYYYMMDD]").val().replace(/-/gi,"");
|
||||||
var end = $("input[name=searchEndYYYYMMDD]").val().replace(/-/gi,"");
|
var end = $("input[name=searchEndYYYYMMDD]").val().replace(/-/gi,"");
|
||||||
|
|
||||||
gridPostData["searchStartDate"] = start;
|
gridPostData["searchStartDate"] = start;
|
||||||
gridPostData["searchEndDate"] = end;
|
gridPostData["searchEndDate"] = end;
|
||||||
|
|
||||||
@@ -145,20 +132,18 @@ $(document).ready(function() {
|
|||||||
resizeJqGridWidth('grid','content_middle','1000');
|
resizeJqGridWidth('grid','content_middle','1000');
|
||||||
|
|
||||||
$("#btn_search").click(function(){
|
$("#btn_search").click(function(){
|
||||||
var postData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
var postData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
||||||
|
|
||||||
var start = $("input[name=searchStartYYYYMMDD]").val().replace(/-/gi,"");
|
var start = $("input[name=searchStartYYYYMMDD]").val().replace(/-/gi,"");
|
||||||
var end = $("input[name=searchEndYYYYMMDD]").val().replace(/-/gi,"");
|
var end = $("input[name=searchEndYYYYMMDD]").val().replace(/-/gi,"");
|
||||||
var startTime = $("input[name=searchStartTime]").val();
|
|
||||||
var endTime = $("input[name=searchEndTime]").val();
|
if(start > end){
|
||||||
|
|
||||||
if((start + startTime) > (end + endTime)){
|
|
||||||
alert("조회기간을 확인해주세요.");
|
alert("조회기간을 확인해주세요.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$("input[name=searchStartDate]").val(start);
|
$("input[name=searchStartDate]").val(start);
|
||||||
$("input[name=searchEndDate]").val(end);
|
$("input[name=searchEndDate]").val(end);
|
||||||
|
|
||||||
postData["searchStartDate"] = start;
|
postData["searchStartDate"] = start;
|
||||||
postData["searchEndDate"] = end;
|
postData["searchEndDate"] = end;
|
||||||
|
|
||||||
@@ -212,24 +197,14 @@ $(document).ready(function() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:180px;"><%= localeMessage.getString("infConHstMan.date") %></th>
|
<th style="width:180px;"><%= localeMessage.getString("infConHstMan.date") %></th>
|
||||||
<td colspan="5">
|
<td>
|
||||||
<input type="text" name="searchStartYYYYMMDD" id="startDatepicker" readonly="readonly" value="" size="10" style="width:80px; border:1px solid #ebebec;">
|
<input type="text" name="searchStartYYYYMMDD" id="startDatepicker" readonly="readonly" value="" size="10" style="width:80px; border:1px solid #ebebec;">
|
||||||
<input type="text" name="searchStartTime" value="" size="8" style="width:70px; border:1px solid #ebebec;">
|
~
|
||||||
~
|
|
||||||
<input type="text" name="searchEndYYYYMMDD" value="" id="endDatepicker" size="10" readonly="readonly" style="width:80px; border:1px solid #ebebec;">
|
<input type="text" name="searchEndYYYYMMDD" value="" id="endDatepicker" size="10" readonly="readonly" style="width:80px; border:1px solid #ebebec;">
|
||||||
<input type="text" name="searchEndTime" value="" size="8" style="width:70px; border:1px solid #ebebec;">
|
|
||||||
<input type="hidden" name="searchStartDate" value="" style="width:0px;">
|
<input type="hidden" name="searchStartDate" value="" style="width:0px;">
|
||||||
<input type="hidden" name="searchEndDate" value="" style="width:0px;">
|
<input type="hidden" name="searchEndDate" value="" style="width:0px;">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th style="width:180px;"><%= localeMessage.getString("infConHstMan.instNm") %></th>
|
|
||||||
<td><input type="text" name="searchInstanceName" value="${param.searchInstanceName}"></td>
|
|
||||||
<th style="width:180px;"><%= localeMessage.getString("infConHstMan.eaiSvcCd") %></th>
|
|
||||||
<td><input type="text" name="searchApiName" value="${param.searchApiName}"></td>
|
|
||||||
<th style="width:180px;"><%= localeMessage.getString("infConHstMan.adpGrpNm") %></th>
|
|
||||||
<td><input type="text" name="searchAdapterGroupName" value="${param.searchAdapterGroupName}"></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ $(document).ready(function() {
|
|||||||
datatype:"json",
|
datatype:"json",
|
||||||
mtype: 'POST',
|
mtype: 'POST',
|
||||||
url: url,
|
url: url,
|
||||||
postData : { cmd : 'LIST', searchGroupName: $('input[name=searchGroupName]').val(), searchUseYn: $('select[name=searchUseYn]').val()},
|
postData : { cmd : 'LIST', searchGroupName: $('input[name=searchGroupName]').val()},
|
||||||
colNames:['그룹 ID',
|
colNames:['그룹 ID',
|
||||||
'그룹명',
|
'그룹명',
|
||||||
'초당 임계치',
|
'초당 임계치',
|
||||||
@@ -125,7 +125,6 @@ $(document).ready(function() {
|
|||||||
url2 += '&menuId='+'${param.menuId}';
|
url2 += '&menuId='+'${param.menuId}';
|
||||||
//검색값
|
//검색값
|
||||||
url2 += '&searchGroupName='+$("input[name=searchGroupName]").val();
|
url2 += '&searchGroupName='+$("input[name=searchGroupName]").val();
|
||||||
url2 += '&searchUseYn='+$("select[name=searchUseYn]").val();
|
|
||||||
//key값
|
//key값
|
||||||
url2 += '&groupId='+groupId;
|
url2 += '&groupId='+groupId;
|
||||||
goNav(url2);
|
goNav(url2);
|
||||||
@@ -144,7 +143,7 @@ $(document).ready(function() {
|
|||||||
resizeJqGridWidth('grid','content_middle','1000');
|
resizeJqGridWidth('grid','content_middle','1000');
|
||||||
|
|
||||||
$("#btn_search").click(function(){
|
$("#btn_search").click(function(){
|
||||||
$("#grid").setGridParam({ postData: { searchGroupName: $('input[name=searchGroupName]').val(), searchUseYn: $('select[name=searchUseYn]').val()}, page:1 }).trigger("reloadGrid");
|
$("#grid").setGridParam({ postData: { searchGroupName: $('input[name=searchGroupName]').val()}, page:1 }).trigger("reloadGrid");
|
||||||
});
|
});
|
||||||
$("#btn_new").click(function(){
|
$("#btn_new").click(function(){
|
||||||
var url2 = url_view;
|
var url2 = url_view;
|
||||||
@@ -189,16 +188,6 @@ $(document).ready(function() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th style="width:180px;">그룹명</th>
|
<th style="width:180px;">그룹명</th>
|
||||||
<td><input type="text" name="searchGroupName" value="${param.searchGroupName}"></td>
|
<td><input type="text" name="searchGroupName" value="${param.searchGroupName}"></td>
|
||||||
<th style="width:180px;">사용여부</th>
|
|
||||||
<td>
|
|
||||||
<div class="select-style">
|
|
||||||
<select name="searchUseYn">
|
|
||||||
<option value="">전체</option>
|
|
||||||
<option value="1">사용함</option>
|
|
||||||
<option value="0">사용안함</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ $(document).ready(function() {
|
|||||||
datatype:"json",
|
datatype:"json",
|
||||||
mtype: 'POST',
|
mtype: 'POST',
|
||||||
url: url,
|
url: url,
|
||||||
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()},
|
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val()},
|
||||||
colNames:['<%= localeMessage.getString("infIfConMan.ifNm") %>',
|
colNames:['<%= localeMessage.getString("infIfConMan.ifNm") %>',
|
||||||
'<%= localeMessage.getString("infIfConMan.ifDesc") %>',
|
'<%= localeMessage.getString("infIfConMan.ifDesc") %>',
|
||||||
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
|
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
|
||||||
@@ -62,7 +62,6 @@ $(document).ready(function() {
|
|||||||
url2 += '&menuId='+'${param.menuId}';
|
url2 += '&menuId='+'${param.menuId}';
|
||||||
//검색값
|
//검색값
|
||||||
url2 += '&searchName='+$("input[name=searchName]").val();
|
url2 += '&searchName='+$("input[name=searchName]").val();
|
||||||
url2 += '&searchUseYn='+$("select[name=searchUseYn]").val();
|
|
||||||
//key값
|
//key값
|
||||||
url2 += '&name='+name;
|
url2 += '&name='+name;
|
||||||
goNav(url2);
|
goNav(url2);
|
||||||
@@ -81,7 +80,7 @@ $(document).ready(function() {
|
|||||||
resizeJqGridWidth('grid','content_middle','1000');
|
resizeJqGridWidth('grid','content_middle','1000');
|
||||||
|
|
||||||
$("#btn_search").click(function(){
|
$("#btn_search").click(function(){
|
||||||
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()}, page:1 }).trigger("reloadGrid");
|
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val()}, page:1 }).trigger("reloadGrid");
|
||||||
});
|
});
|
||||||
$("#btn_new").click(function(){
|
$("#btn_new").click(function(){
|
||||||
var url2 = url_view;
|
var url2 = url_view;
|
||||||
@@ -127,16 +126,6 @@ $(document).ready(function() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th style="width:180px;"><%= localeMessage.getString("infIfConMan.ifNm") %></th>
|
<th style="width:180px;"><%= localeMessage.getString("infIfConMan.ifNm") %></th>
|
||||||
<td><input type="text" name="searchName" value="${param.searchName}"></td>
|
<td><input type="text" name="searchName" value="${param.searchName}"></td>
|
||||||
<th style="width:180px;"><%= localeMessage.getString("infAdpConMan.useYn") %></th>
|
|
||||||
<td>
|
|
||||||
<div class="select-style">
|
|
||||||
<select name="searchUseYn">
|
|
||||||
<option value="">전체</option>
|
|
||||||
<option value="1">사용함</option>
|
|
||||||
<option value="0">사용안함</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -71,18 +71,18 @@
|
|||||||
|
|
||||||
$('#grid').children().remove();
|
$('#grid').children().remove();
|
||||||
|
|
||||||
const itemTypes = ['Field', 'Grid', 'Group', 'Attr', 'Array'];
|
const itemTypes = ['Field', 'Grid', 'Group', 'Attr'];
|
||||||
|
|
||||||
columns = [ // for columnData prop
|
columns = [ // for columnData prop
|
||||||
{ title: '<%= localeMessage.getString("layoutMan.itemDesc") %>', name: 'loutItemDesc', type: 'text', width:280, resize:true, minWidth:120 },
|
|
||||||
{ title: '<%= localeMessage.getString("layoutMan.itmeEn") %>', name: 'loutItemName', type: 'text', width:280, resize:true, minWidth:120 },
|
{ title: '<%= localeMessage.getString("layoutMan.itmeEn") %>', name: 'loutItemName', type: 'text', width:280, resize:true, minWidth:120 },
|
||||||
{ title: '<%=localeMessage.getString("standardLayout.itemLevel")%>', name: 'loutItemDepth', type: 'numeric', width:50 },
|
{ title: '<%= localeMessage.getString("layoutMan.itemDesc") %>', name: 'loutItemDesc', type: 'text', width:280, resize:true, minWidth:120 },
|
||||||
|
{ title: '<%=localeMessage.getString("standardLayout.itemLevel")%>', name: 'loutItemDepth', type: 'text', width:50 },
|
||||||
{ title: '<%= localeMessage.getString("standardLayout.itemType") %>', name: 'loutItemType', type: 'autocomplete', source: itemTypes, width:70 },
|
{ title: '<%= localeMessage.getString("standardLayout.itemType") %>', name: 'loutItemType', type: 'autocomplete', source: itemTypes, width:70 },
|
||||||
{ title: '<%= localeMessage.getString("standardLayout.arraySize") %>', name: 'loutItemOccCnt', type: 'text', width:90 },
|
{ title: '<%= localeMessage.getString("standardLayout.arraySize") %>', name: 'loutItemOccCnt', type: 'text', width:90 },
|
||||||
{ title: '<%= localeMessage.getString("standardLayout.refField") %>', name: 'loutItemOccRef', type: 'text', width:90 },
|
{ title: '<%= localeMessage.getString("standardLayout.refField") %>', name: 'loutItemOccRef', type: 'text', width:90 },
|
||||||
{ title: '<%=localeMessage.getString("layoutMan.dataType")%>', name: 'loutItemDataType', type: 'autocomplete', source: basicDataTypes, width:160 },
|
{ title: '<%=localeMessage.getString("layoutMan.dataType")%>', name: 'loutItemDataType', type: 'autocomplete', source: basicDataTypes, width:160 },
|
||||||
{ title: '<%=localeMessage.getString("layoutMan.dataLen")%>', name: 'loutItemLength', type: 'numeric', width: 70, align: 'center' },
|
{ title: '<%=localeMessage.getString("layoutMan.dataLen")%>', name: 'loutItemLength', type: 'numeric', width: 70, align: 'center' },
|
||||||
{ title: '<%=localeMessage.getString("layoutMan.decpLen")%>', name: 'loutItemDecimal', type: 'numeric', width: 70 },
|
{ title: '<%=localeMessage.getString("layoutMan.decpLen")%>', name: 'loutItemDecimal', type: 'text', width: 70 },
|
||||||
{ title: '<%=localeMessage.getString("layoutMan.defaultVal")%>', name: 'loutItemDefault', type: 'text', width: 70 },
|
{ title: '<%=localeMessage.getString("layoutMan.defaultVal")%>', name: 'loutItemDefault', type: 'text', width: 70 },
|
||||||
{ title: '<%=localeMessage.getString("layoutMan.mask")%>', name: 'loutItemMaskYn', type: 'checkbox', width: 70 },
|
{ title: '<%=localeMessage.getString("layoutMan.mask")%>', name: 'loutItemMaskYn', type: 'checkbox', width: 70 },
|
||||||
{ title: '<%=localeMessage.getString("layoutMan.moffset")%>', name: 'loutItemMaskOffset', type: 'text', width: 50 },
|
{ title: '<%=localeMessage.getString("layoutMan.moffset")%>', name: 'loutItemMaskOffset', type: 'text', width: 50 },
|
||||||
@@ -182,41 +182,6 @@
|
|||||||
$('#dataTotalLen').text(totalLen);
|
$('#dataTotalLen').text(totalLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusGridCell(colIndex, rowIndex) {
|
|
||||||
var cellName = jexcel.getColumnNameFromId([colIndex, rowIndex]);
|
|
||||||
var cell = grid.getCell(cellName);
|
|
||||||
grid.updateSelection(cell);
|
|
||||||
cell.scrollIntoView({block: 'center', inline: 'center'});
|
|
||||||
grid.openEditor(cell, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var INTEGER_REGEXP = /^(0|[1-9][0-9]*)$/;
|
|
||||||
|
|
||||||
function validateNumberColumns() {
|
|
||||||
var data = grid.getData();
|
|
||||||
var gridColumns = grid.options.columns;
|
|
||||||
|
|
||||||
for (var col = 0; col < gridColumns.length; col++) {
|
|
||||||
if (gridColumns[col].type !== 'numeric') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var row = 0; row < data.length; row++) {
|
|
||||||
var value = data[row][col];
|
|
||||||
if (value == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
value = $.trim(String(value));
|
|
||||||
if (value !== '' && !INTEGER_REGEXP.test(value)) {
|
|
||||||
alert("숫자만 입력할 수 있습니다.");
|
|
||||||
focusGridCell(col, row);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function detail(key) {
|
function detail(key) {
|
||||||
if (!isDetail) {
|
if (!isDetail) {
|
||||||
return
|
return
|
||||||
@@ -356,10 +321,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_modify").click(function(){
|
$("#btn_modify").click(function(){
|
||||||
if (!validateNumberColumns()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var postData = $('#ajaxForm').serializeArray();
|
var postData = $('#ajaxForm').serializeArray();
|
||||||
if (isDetail){
|
if (isDetail){
|
||||||
postData.push({ name: "cmd" , value:"UPDATE"});
|
postData.push({ name: "cmd" , value:"UPDATE"});
|
||||||
|
|||||||
@@ -1,258 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8"%>
|
|
||||||
<%@ page import="java.io.*"%>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
|
|
||||||
%>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
|
|
||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
|
||||||
<script language="javascript" >
|
|
||||||
var url = '<c:url value="/onl/transaction/apim/apiInterfaceMan.json"/>';
|
|
||||||
var url_view = '<c:url value="/onl/transaction/apim/apiInterfaceMan.view"/>';
|
|
||||||
|
|
||||||
var selectName = "searchEaiBzwkDstcd"; // selectBox Name
|
|
||||||
function processSelectedData() {
|
|
||||||
var grid = $("#grid");
|
|
||||||
var selectedRowIds = grid.jqGrid('getGridParam', 'selarrrow');
|
|
||||||
var selectedData = [];
|
|
||||||
|
|
||||||
for(var i = 0; i < selectedRowIds.length; i++) {
|
|
||||||
var rowData = grid.jqGrid('getRowData', selectedRowIds[i]);
|
|
||||||
selectedData.push({
|
|
||||||
bizCode: rowData.eaiBzwkDstcd, // CLINET
|
|
||||||
apiId: rowData.eaiSvcName,
|
|
||||||
apiDesc: rowData.eaiSvcDesc, // SCOPE-API
|
|
||||||
APIFULLPATH: rowData.apiFullPath,
|
|
||||||
BZWKSVCKEYNAME: rowData.bzwksvckeyname
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(selectedData.length === 0) {
|
|
||||||
alert("선택된 항목이 없습니다.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
alert("선택한 " + selectedData.length + "건의 API를 추가합니다.");
|
|
||||||
window.returnValue = selectedData.length === 1 ? selectedData[0] : selectedData;
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateSelectionInfo(gridId) {
|
|
||||||
var grid = $(gridId || "#grid");
|
|
||||||
var selectedRows = grid.jqGrid('getGridParam', 'selarrrow');
|
|
||||||
$("#selected-count").text("총: " + selectedRows.length + " 건");
|
|
||||||
}
|
|
||||||
|
|
||||||
function init( callback) {
|
|
||||||
$.ajax({
|
|
||||||
type : "POST",
|
|
||||||
url:url,
|
|
||||||
dataType:"json",
|
|
||||||
data:{cmd: 'LIST_COMBO'},
|
|
||||||
success:function(json){
|
|
||||||
new makeOptions("BIZCODE","BIZNAME").setObj($("select[name=searchEaiBzwkDstcd]")).setNoValueInclude(true).setNoValue("","전체").setData(json.bizList).setFormat(codeName3OptionFormat).rendering();
|
|
||||||
|
|
||||||
setSearchable(selectName); // 콤보에 searchable 설정
|
|
||||||
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error:function(e){
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
function detail(){
|
|
||||||
var postData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
|
||||||
$("#grid").setGridParam({ url:url,postData: postData }).trigger("reloadGrid");
|
|
||||||
}
|
|
||||||
|
|
||||||
function search(){
|
|
||||||
var postData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
|
||||||
$("#grid").setGridParam({ url:url,postData: postData ,page:1 }).trigger("reloadGrid");
|
|
||||||
}
|
|
||||||
function ioFormatter(cellvalue,options,rowObject){
|
|
||||||
var serviceType = sessionStorage["serviceType"];
|
|
||||||
if(cellvalue == "I"){
|
|
||||||
return "타발";
|
|
||||||
}else if(cellvalue =="O"){
|
|
||||||
return "당발";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function adapterNameShortFormatter(cellvalue,options,rowObject){
|
|
||||||
if(cellvalue == null || cellvalue == '')
|
|
||||||
return ''
|
|
||||||
return cellvalue.substring(1, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
function list(){
|
|
||||||
detail()
|
|
||||||
var gridPostData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
|
||||||
// gridPostData.searchApiEnableYn = 'Y';
|
|
||||||
var urlParams = new URLSearchParams(window.location.search);
|
|
||||||
var selectedApiIds = urlParams.get("selectedApiIds");
|
|
||||||
$('#grid').jqGrid({
|
|
||||||
datatype : "json",
|
|
||||||
mtype : 'POST',
|
|
||||||
url : url,
|
|
||||||
postData : gridPostData,
|
|
||||||
colNames : [ '업무구분',
|
|
||||||
'<%= localeMessage.getString("eaiMessage.eaiSvcName")%>',
|
|
||||||
'<%= localeMessage.getString("eaiMessage.eaiSvcDesc")%>',
|
|
||||||
'API FULL PATH',
|
|
||||||
'업무서비스명',
|
|
||||||
'요청',
|
|
||||||
'응답',
|
|
||||||
'작성자',
|
|
||||||
'가상응답여부',
|
|
||||||
'SyncAsyncType',
|
|
||||||
],
|
|
||||||
colModel : [ { name : 'eaiBzwkDstcd' , align : 'center' , width:'40', sortable:false},
|
|
||||||
{ name : 'eaiSvcName' , align : 'left' , width:'100'},
|
|
||||||
{ name : 'eaiSvcDesc' , align : 'left' },
|
|
||||||
{ name : 'apiFullPath' , align : 'left' , width:'100'},
|
|
||||||
{ name : 'bzwksvckeyname' , align : 'left' , width:'100', hidden: true},
|
|
||||||
{ name : 'fromAdapter' , align : 'center' , width:'40', formatter:adapterNameShortFormatter },
|
|
||||||
{ name : 'toAdapter' , align : 'center' , width:'40', formatter:adapterNameShortFormatter },
|
|
||||||
{ name : 'author' , align : 'center' , width:'60' },
|
|
||||||
{ name : 'simYn' , align : 'center' , width:'40' },
|
|
||||||
{ name : 'syncAsyncType' , align : 'center' , width:'40', hidden: true},
|
|
||||||
],
|
|
||||||
jsonReader : {
|
|
||||||
repeatitems : false
|
|
||||||
},
|
|
||||||
pager : $('#pager'),
|
|
||||||
page : '${param.page}',
|
|
||||||
rowNum : '${rmsDefaultRowNum}',
|
|
||||||
autoheight : true,
|
|
||||||
height : $("#container").height(),
|
|
||||||
autowidth : true,
|
|
||||||
viewrecords : true,
|
|
||||||
multiselect: false,
|
|
||||||
multiboxonly: false,
|
|
||||||
rowList : eval('[${rmsDefaultRowList}]'),
|
|
||||||
loadComplete:function (d){
|
|
||||||
var $grid = $(this);
|
|
||||||
if(selectedApiIds) {
|
|
||||||
const selectedIds = selectedApiIds.split(',');
|
|
||||||
$.each($grid.getDataIDs(), function(_, id) {
|
|
||||||
var rowData = $grid.getRowData(id);
|
|
||||||
if(selectedIds.includes(rowData.eaiSvcName)) {
|
|
||||||
$grid.jqGrid('setSelection', id, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var colModel = $(this).getGridParam("colModel");
|
|
||||||
for(var i = 0 ; i< colModel.length; i++){
|
|
||||||
$(this).setColProp(colModel[i].name, {sortable : false});
|
|
||||||
}
|
|
||||||
updateSelectionInfo("#grid");
|
|
||||||
},
|
|
||||||
onSelectRow: function(rowid, status, e) {
|
|
||||||
updateSelectionInfo("#grid");
|
|
||||||
},
|
|
||||||
onSelectAll: function(rowids, status) {
|
|
||||||
updateSelectionInfo("#grid");
|
|
||||||
},
|
|
||||||
ondblClickRow : function(rowId) {
|
|
||||||
const rowData = $(this).getRowData(rowId);
|
|
||||||
const returnValue = {
|
|
||||||
bizCode: rowData.eaiBzwkDstcd,
|
|
||||||
apiId: rowData.eaiSvcName,
|
|
||||||
apiDesc: rowData.eaiSvcDesc
|
|
||||||
};
|
|
||||||
//alert("선택한 API를 추가합니다.\nAPI ID: " + rowData.eaiSvcName);
|
|
||||||
window.returnValue = returnValue;
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
|
|
||||||
init(list);
|
|
||||||
|
|
||||||
resizeJqGridWidth('grid','content_middle','1000');
|
|
||||||
|
|
||||||
// 업무구분명 선택 시 자동 검색
|
|
||||||
$("select[name=searchEaiBzwkDstcd]").change(function() {
|
|
||||||
search();
|
|
||||||
});
|
|
||||||
$("#btn_search").click(function(){
|
|
||||||
search();
|
|
||||||
});
|
|
||||||
$("input[name^=search]").keydown(function(key){
|
|
||||||
if (key.keyCode == 13){
|
|
||||||
$("#btn_search").click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonControl();
|
|
||||||
|
|
||||||
$("#btn_select").click(function(){
|
|
||||||
processSelectedData();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btn_close").click(function () {
|
|
||||||
window.close();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div>
|
|
||||||
<div class="content_middle" id="content_middle" style="margin-top: 0px">
|
|
||||||
<div class="search_wrap">
|
|
||||||
<button type="button" class="cssbtn" id="btn_search" level="R" ><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
|
||||||
<button type="button" class="cssbtn" id="btn_select" level="R" ><i class="material-icons">check</i> <%= localeMessage.getString("button.check") %></button>
|
|
||||||
<button type="button" class="cssbtn" id="btn_close" level="R" status="DETAIL"><i class="material-icons">close</i> <%= localeMessage.getString("button.close") %></button>
|
|
||||||
</div>
|
|
||||||
<div class="title" id="title" >${rmsMenuName}</div>
|
|
||||||
<!-- 선택 정보 표시 영역 추가 -->
|
|
||||||
<div style="margin-bottom: 5px;">
|
|
||||||
<span id="selected-count" style="color: #666; font-size: 12px;"></span>
|
|
||||||
</div>
|
|
||||||
<table class="search_condition" cellspacing=0;>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th style="width:180px;">업무구분명</th>
|
|
||||||
<td>
|
|
||||||
<select name="searchEaiBzwkDstcd" value="${param.searchEaiBzwkDstcd}">
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<th style="width:180px;"><%= localeMessage.getString("eaiMessage.eaiSvcName")%></th>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="searchEaiSvcName" value="${param.searchEaiSvcName}">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style="width:180px;"><%= localeMessage.getString("eaiMessage.eaiSvcDesc")%></th>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="searchEaiSvcDesc" value="${param.searchEaiSvcDesc}">
|
|
||||||
</td>
|
|
||||||
<th style="width:180px;">API FULL PATH</th>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="searchApiFullPath" value="${param.searchApiFullPath}">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table id="grid" ></table>
|
|
||||||
<div id="pager"></div>
|
|
||||||
</div><!-- end content_middle -->
|
|
||||||
</div><!-- end right_box -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -54,7 +54,6 @@
|
|||||||
const LAYOUT_ITEM_TYPE_GROUP = "Group";
|
const LAYOUT_ITEM_TYPE_GROUP = "Group";
|
||||||
const LAYOUT_ITEM_TYPE_GRID = "Grid";
|
const LAYOUT_ITEM_TYPE_GRID = "Grid";
|
||||||
const LAYOUT_ITEM_TYPE_FIELD = "Field";
|
const LAYOUT_ITEM_TYPE_FIELD = "Field";
|
||||||
const LAYOUT_ITEM_TYPE_ARRAY = "Array";
|
|
||||||
|
|
||||||
var isDetail = false;
|
var isDetail = false;
|
||||||
|
|
||||||
@@ -551,14 +550,6 @@
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 항목 자신이 Array인 경우, 경로/변환명령 끝에 반복 표시 [*]를 추가
|
|
||||||
function addArrayTag(loutItemType, data) {
|
|
||||||
if (loutItemType == LAYOUT_ITEM_TYPE_ARRAY && !data.endsWith("[*]")) {
|
|
||||||
data = data + "[*]";
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
//변환명에 있는 서비스코드와 if서비스 코드 매칭
|
//변환명에 있는 서비스코드와 if서비스 코드 매칭
|
||||||
function validation(){
|
function validation(){
|
||||||
if ($('input[name=cnvsnName]').val() == '') {
|
if ($('input[name=cnvsnName]').val() == '') {
|
||||||
@@ -898,10 +889,10 @@
|
|||||||
let selectValue = "";
|
let selectValue = "";
|
||||||
let targetValue = "";
|
let targetValue = "";
|
||||||
for ( var i = 0; i < sourceData.length; i++) {
|
for ( var i = 0; i < sourceData.length; i++) {
|
||||||
if (sourceData[i]['loutItemType'] != "Field" && sourceData[i]['loutItemType'] != "Attr" && sourceData[i]['loutItemType'] != "Array") continue;
|
if (sourceData[i]['loutItemType'] != "Field" && sourceData[i]['loutItemType'] != "Attr") continue;
|
||||||
selectValue = (sourceData[i]['LOUTITEMPATH']).substr(sourceData[i]['loutName'].length+1);
|
selectValue = (sourceData[i]['LOUTITEMPATH']).substr(sourceData[i]['loutName'].length+1);
|
||||||
for (var j = 0; j <targetData.length; j++) {
|
for (var j = 0; j <targetData.length; j++) {
|
||||||
if (targetData[j]['loutItemType'] != "Field" && targetData[j]['loutItemType'] != "Attr" && targetData[j]['loutItemType'] != "Array") continue;
|
if (targetData[j]['loutItemType'] != "Field" && targetData[j]['loutItemType'] != "Attr") continue;
|
||||||
targetValue = (targetData[j]['LOUTITEMPATH']).substr(targetData[j]['loutName'].length+1);
|
targetValue = (targetData[j]['LOUTITEMPATH']).substr(targetData[j]['loutName'].length+1);
|
||||||
if (targetValue == selectValue ) {
|
if (targetValue == selectValue ) {
|
||||||
var data = sourceData[i]['LOUTITEMPATH'];
|
var data = sourceData[i]['LOUTITEMPATH'];
|
||||||
@@ -925,8 +916,8 @@
|
|||||||
//field, ATTR 여부 판단
|
//field, ATTR 여부 판단
|
||||||
var sourceRow = sourceGrid.getRowData( srcRowId );
|
var sourceRow = sourceGrid.getRowData( srcRowId );
|
||||||
var targetRow = targetGrid.getRowData( tgtRowId );
|
var targetRow = targetGrid.getRowData( tgtRowId );
|
||||||
if ( (sourceRow["loutItemType"] == 'Field' || sourceRow["loutItemType"] == 'Attr' || sourceRow["loutItemType"] == 'Array') &&
|
if ( (sourceRow["loutItemType"] == 'Field' || sourceRow["loutItemType"] == 'Attr') &&
|
||||||
(targetRow["loutItemType"] == 'Field' || targetRow["loutItemType"] == 'Attr' || targetRow["loutItemType"] == 'Array') ){
|
(targetRow["loutItemType"] == 'Field' || targetRow["loutItemType"] == 'Attr') ){
|
||||||
;
|
;
|
||||||
}else{
|
}else{
|
||||||
alert('<%=localeMessage.getString("transformManDetail.alert3")%>');
|
alert('<%=localeMessage.getString("transformManDetail.alert3")%>');
|
||||||
@@ -945,15 +936,15 @@
|
|||||||
var targetValue = "";
|
var targetValue = "";
|
||||||
var j=tgtIndex-1-1;
|
var j=tgtIndex-1-1;
|
||||||
for ( var i = srcIndex-1; i < sourceData.length; i++) {
|
for ( var i = srcIndex-1; i < sourceData.length; i++) {
|
||||||
if (sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_FIELD && sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_ARRAY) continue;
|
if (sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_FIELD) continue;
|
||||||
j++;
|
j++;
|
||||||
while (targetData.length -1 >= j && targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_FIELD && targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_ARRAY){
|
while (targetData.length -1 >= j &&targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_FIELD){
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
if (targetData.length -1 < j) break;
|
if (targetData.length -1 < j) break;
|
||||||
var targetRowId = targetData[j]['id'];
|
var targetRowId = targetData[j]['id'];
|
||||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNCMDNAME',addArrayTag(sourceData[i]['loutItemType'], addGroupTag(srcGroup,sourceData[i]['LOUTITEMPATH'])));
|
targetGrid.jqGrid('setCell',targetRowId,'CNVSNCMDNAME',addGroupTag(srcGroup,sourceData[i]['LOUTITEMPATH']));
|
||||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNRSULTITEMPATHNAME',addArrayTag(targetData[j]['loutItemType'], addGroupTag(tgtGroup,targetData[j]['LOUTITEMPATH'])));
|
targetGrid.jqGrid('setCell',targetRowId,'CNVSNRSULTITEMPATHNAME',addGroupTag(tgtGroup,targetData[j]['LOUTITEMPATH']));
|
||||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNITEMSERNO',targetData[j]['loutItemSerno']);
|
targetGrid.jqGrid('setCell',targetRowId,'CNVSNITEMSERNO',targetData[j]['loutItemSerno']);
|
||||||
|
|
||||||
const sourceEndpointElementId = sourceGrid.getEndpointElementId(sourceData[i]['id']);
|
const sourceEndpointElementId = sourceGrid.getEndpointElementId(sourceData[i]['id']);
|
||||||
@@ -1024,7 +1015,7 @@
|
|||||||
var targetData = targetGrid.getRowData();
|
var targetData = targetGrid.getRowData();
|
||||||
var gridData = new Array();
|
var gridData = new Array();
|
||||||
for (var i = 0; i <targetData.length; i++) {
|
for (var i = 0; i <targetData.length; i++) {
|
||||||
if ((targetData[i]['loutItemType'] != "Field") && (targetData[i]['loutItemType'] != "Attr") && (targetData[i]['loutItemType'] != "Array")) {
|
if ((targetData[i]['loutItemType'] != "Field") && (targetData[i]['loutItemType'] != "Attr")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (targetData[i]['CNVSNCMDNAME']==null
|
if (targetData[i]['CNVSNCMDNAME']==null
|
||||||
@@ -1167,7 +1158,7 @@
|
|||||||
function srcformatterFunction(cellvalue,options,rowObject){
|
function srcformatterFunction(cellvalue,options,rowObject){
|
||||||
var rowId = options["rowId"];
|
var rowId = options["rowId"];
|
||||||
var loutItemType = rowObject["loutItemType"];
|
var loutItemType = rowObject["loutItemType"];
|
||||||
if (loutItemType == 'Field' || loutItemType == 'Attr' || loutItemType == 'Array'){
|
if (loutItemType == 'Field' || loutItemType == 'Attr'){
|
||||||
return "<div id='div_src_"+rowId+"' name='src_"+rowId+"' style='width:28px;height:17px;background-color: #D12F35; border-color: #ab1717; border-style: solid; border-width: 1px; border-radius: 3px;' />";
|
return "<div id='div_src_"+rowId+"' name='src_"+rowId+"' style='width:28px;height:17px;background-color: #D12F35; border-color: #ab1717; border-style: solid; border-width: 1px; border-radius: 3px;' />";
|
||||||
}else{
|
}else{
|
||||||
return "<div id='div_srcgroup_"+rowId+"' name='srcgroup_"+rowId+"' style='width:28px;height:17px;' />";
|
return "<div id='div_srcgroup_"+rowId+"' name='srcgroup_"+rowId+"' style='width:28px;height:17px;' />";
|
||||||
@@ -1179,7 +1170,7 @@
|
|||||||
function tgtformatterFunction(cellvalue,options,rowObject){
|
function tgtformatterFunction(cellvalue,options,rowObject){
|
||||||
var rowId = options["rowId"];
|
var rowId = options["rowId"];
|
||||||
var loutItemType = rowObject["loutItemType"];
|
var loutItemType = rowObject["loutItemType"];
|
||||||
if (loutItemType == 'Field' || loutItemType == 'Attr' || loutItemType == 'Array'){
|
if (loutItemType == 'Field' || loutItemType == 'Attr'){
|
||||||
return "<div id='div_tgt_"+rowId+"_base' name='div_tgt_"+rowId+"_base' style='width:30px;height:20px; background-color:gray;' >"
|
return "<div id='div_tgt_"+rowId+"_base' name='div_tgt_"+rowId+"_base' style='width:30px;height:20px; background-color:gray;' >"
|
||||||
+ "<div id='div_tgt_"+rowId+"' name='tgt_"+rowId+"' style='width:28px;height:17px; background-color: #3E7E9C; border-color: #217ca7; border-style: solid; border-width: 1px; border-radius: 3px;' onclick='jqGridOnTargetGridEndpointClick(this)'>"
|
+ "<div id='div_tgt_"+rowId+"' name='tgt_"+rowId+"' style='width:28px;height:17px; background-color: #3E7E9C; border-color: #217ca7; border-style: solid; border-width: 1px; border-radius: 3px;' onclick='jqGridOnTargetGridEndpointClick(this)'>"
|
||||||
+ "</div></div>";
|
+ "</div></div>";
|
||||||
@@ -1678,8 +1669,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sourceRow["loutItemType"] != 'Field' && sourceRow["loutItemType"] != 'Attr' && sourceRow["loutItemType"] != 'Array')
|
if ((sourceRow["loutItemType"] != 'Field' && sourceRow["loutItemType"] != 'Attr')
|
||||||
|| (targetRow["loutItemType"] != 'Field' && targetRow["loutItemType"] != 'Attr' && targetRow["loutItemType"] != 'Array')) {
|
|| (targetRow["loutItemType"] != 'Field' && targetRow["loutItemType"] != 'Attr')) {
|
||||||
alert('<%=localeMessage.getString("transformManDetail.alert3")%>');
|
alert('<%=localeMessage.getString("transformManDetail.alert3")%>');
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
@@ -1693,7 +1684,7 @@
|
|||||||
|
|
||||||
if (targetRow['CNVSNCMDNAME'] == '') {
|
if (targetRow['CNVSNCMDNAME'] == '') {
|
||||||
// 변환 명령 값이 한번 설정 되면 변경 되지 않게 함.
|
// 변환 명령 값이 한번 설정 되면 변경 되지 않게 함.
|
||||||
var cnvsnCmdName = addArrayTag(sourceRow["loutItemType"], addGroupTag(srcGroup,sourceRow["LOUTITEMPATH"]));
|
var cnvsnCmdName = addGroupTag(srcGroup,sourceRow["LOUTITEMPATH"]);
|
||||||
// function까지 처리되도록 수정했으나, parameter가 하나인 경우에만 정상처리됨
|
// function까지 처리되도록 수정했으나, parameter가 하나인 경우에만 정상처리됨
|
||||||
if($('#functionCombo').val() != "") {
|
if($('#functionCombo').val() != "") {
|
||||||
cnvsnCmdName = $('#functionCombo').val() + "(" + cnvsnCmdName + ")";
|
cnvsnCmdName = $('#functionCombo').val() + "(" + cnvsnCmdName + ")";
|
||||||
@@ -1702,7 +1693,7 @@
|
|||||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNCMDNAME', cnvsnCmdName);
|
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNCMDNAME', cnvsnCmdName);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNRSULTITEMPATHNAME',addArrayTag(targetRow["loutItemType"], addGroupTag(tgtGroup,targetRow["LOUTITEMPATH"])));
|
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNRSULTITEMPATHNAME',addGroupTag(tgtGroup,targetRow["LOUTITEMPATH"]));
|
||||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNITEMSERNO',targetRow['loutItemSerno']);
|
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNITEMSERNO',targetRow['loutItemSerno']);
|
||||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNSRCITEMS', cnvsnSrcItems);
|
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNSRCITEMS', cnvsnSrcItems);
|
||||||
targetGrid.jqGrid('setCell',tgtRowId,'ISVALIDMAPPING', true);
|
targetGrid.jqGrid('setCell',tgtRowId,'ISVALIDMAPPING', true);
|
||||||
@@ -1894,8 +1885,8 @@
|
|||||||
if (loutItemType == LAYOUT_ITEM_TYPE_GRID || loutItemType == LAYOUT_ITEM_TYPE_GROUP) {
|
if (loutItemType == LAYOUT_ITEM_TYPE_GRID || loutItemType == LAYOUT_ITEM_TYPE_GROUP) {
|
||||||
// group 인 경우
|
// group 인 경우
|
||||||
items = createGridGroupContextMenuItems(grid, rowId);
|
items = createGridGroupContextMenuItems(grid, rowId);
|
||||||
} else if(loutItemType == LAYOUT_ITEM_TYPE_FIELD || loutItemType == LAYOUT_ITEM_TYPE_ARRAY) {
|
} else if(loutItemType == LAYOUT_ITEM_TYPE_FIELD) {
|
||||||
// field, array 인 경우
|
// field 인 경우
|
||||||
items = createFieldContextMenuItems(grid, positionElement.attr('id'));
|
items = createFieldContextMenuItems(grid, positionElement.attr('id'));
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -1947,8 +1938,8 @@
|
|||||||
var key = "";
|
var key = "";
|
||||||
var args = new Object();
|
var args = new Object();
|
||||||
args['eaiSvcName'] = $('input[name=eaiSvcName]').val();
|
args['eaiSvcName'] = $('input[name=eaiSvcName]').val();
|
||||||
var url=url_view; //'<c:url value="/onl/transaction/extnl/interfaceMan.view"/>';
|
var url='<c:url value="/onl/transaction/extnl/interfaceMan.view"/>';
|
||||||
url = url + "?cmd=API_POPUP";
|
url = url + "?cmd=POPUP";
|
||||||
var ret = showModal(url,args,1020,630, function(arg){
|
var ret = showModal(url,args,1020,630, function(arg){
|
||||||
var args = null;
|
var args = null;
|
||||||
if(arg == null || arg == undefined ) {//chrome
|
if(arg == null || arg == undefined ) {//chrome
|
||||||
@@ -1962,11 +1953,11 @@
|
|||||||
|
|
||||||
var ret = args.returnValue;
|
var ret = args.returnValue;
|
||||||
console.log("ret",ret);
|
console.log("ret",ret);
|
||||||
key = ret['apiId'];
|
key = ret['key'];
|
||||||
|
|
||||||
$("input[name=eaiSvcName]").val(key);
|
$("input[name=eaiSvcName]").val(key);
|
||||||
$("input[name=eaiSvcDesc]").val(ret['apiDesc']);
|
$("input[name=eaiSvcDesc]").val(ret['eaiSvcDesc']);
|
||||||
bzwkDstCd = ret['bizCode'];
|
bzwkDstCd = ret['eaiBzwkDstCd'];
|
||||||
|
|
||||||
$("input[name=eaiSvcName]").change();
|
$("input[name=eaiSvcName]").change();
|
||||||
});
|
});
|
||||||
@@ -1998,7 +1989,7 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loutItemType == LAYOUT_ITEM_TYPE_FIELD || loutItemType == LAYOUT_ITEM_TYPE_ARRAY) {
|
if (loutItemType == LAYOUT_ITEM_TYPE_FIELD) {
|
||||||
loutItemPath = loutItemPath.replace(new RegExp("^" + prefix), "");
|
loutItemPath = loutItemPath.replace(new RegExp("^" + prefix), "");
|
||||||
console.debug(grid.getId() + " : loutItemPath : " + loutItemPath);
|
console.debug(grid.getId() + " : loutItemPath : " + loutItemPath);
|
||||||
rowData['GROUP_LOUTITEMPATH'] = loutItemPath;
|
rowData['GROUP_LOUTITEMPATH'] = loutItemPath;
|
||||||
|
|||||||
@@ -19,8 +19,7 @@
|
|||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
<jsp:include page="/jsp/common/include/css.jsp"/>
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
<jsp:include page="/jsp/common/include/script.jsp"/>
|
||||||
|
|
||||||
<script language="javascript" >
|
<script language="javascript" >
|
||||||
var url_view = '<c:url value="/onl/admin/rule/transform2/transform2Man.view" />';
|
|
||||||
var $ = jQuery.noConflict();
|
var $ = jQuery.noConflict();
|
||||||
var bzwkDstCd = "";
|
var bzwkDstCd = "";
|
||||||
|
|
||||||
@@ -82,9 +81,8 @@ $(document).ready(function() {
|
|||||||
var key = "";
|
var key = "";
|
||||||
var args = new Object();
|
var args = new Object();
|
||||||
args['eaiSvcName'] = $('input[name=eaiSvcName]').val();
|
args['eaiSvcName'] = $('input[name=eaiSvcName]').val();
|
||||||
var url=url_view; //'<c:url value="/onl/transaction/extnl/interfaceMan.view"/>';
|
var url='<c:url value="/onl/transaction/extnl/interfaceMan.view"/>';
|
||||||
url = url + "?cmd=API_POPUP";
|
url = url + "?cmd=POPUP";
|
||||||
console.log('[new]', url);
|
|
||||||
var ret = showModal(url,args,1020,630, function(arg){
|
var ret = showModal(url,args,1020,630, function(arg){
|
||||||
var args = null;
|
var args = null;
|
||||||
if(arg == null || arg == undefined ) {//chrome
|
if(arg == null || arg == undefined ) {//chrome
|
||||||
@@ -98,11 +96,11 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
var ret = args.returnValue;
|
var ret = args.returnValue;
|
||||||
console.log("ret",ret);
|
console.log("ret",ret);
|
||||||
key = ret['apiId'];
|
key = ret['key'];
|
||||||
|
|
||||||
$("input[name=eaiSvcName]").val(key);
|
$("input[name=eaiSvcName]").val(key);
|
||||||
$("input[name=eaiSvcDesc]").val(ret['apiDesc']);
|
$("input[name=eaiSvcDesc]").val(ret['eaiSvcDesc']);
|
||||||
bzwkDstCd = ret['bizCode'];
|
bzwkDstCd = ret['eaiBzwkDstCd'];
|
||||||
|
|
||||||
$("input[name=eaiSvcName]").change();
|
$("input[name=eaiSvcName]").change();
|
||||||
//$("select[name=eaiSevrDstcd]").val(ret['eaiSevrDstcd']);
|
//$("select[name=eaiSevrDstcd]").val(ret['eaiSevrDstcd']);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<script language="javascript" >
|
<script language="javascript" >
|
||||||
var url = '<c:url value="/onl/apim/apigroup/apiGroupMan.json"/>';
|
var url = '<c:url value="/onl/apim/apigroup/apiGroupMan.json"/>';
|
||||||
var url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view"/>';
|
var url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view"/>';
|
||||||
var url_popup_view = '<c:url value="/onl/transaction/apim/apiSpecMan.view"/>';
|
var url_popup_view = '<c:url value="/onl/transaction/apim/apiSpecManPopup.view"/>';
|
||||||
|
|
||||||
var isDetail = false;
|
var isDetail = false;
|
||||||
let dialog;
|
let dialog;
|
||||||
@@ -415,12 +415,6 @@
|
|||||||
<input type="text" name="groupName" data-required data-warning="API 그룹 명을 입력하여 주십시오.">
|
<input type="text" name="groupName" data-required data-warning="API 그룹 명을 입력하여 주십시오.">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th style="width:150px;">그룹 설명</th>
|
|
||||||
<td colspan="7">
|
|
||||||
<input type="text" name="groupDesc">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:150px;">공개 여부</th>
|
<th style="width:150px;">공개 여부</th>
|
||||||
<td style="width:100px;">
|
<td style="width:100px;">
|
||||||
@@ -467,6 +461,14 @@
|
|||||||
<img id="mainIconPreview" src="#" alt="Main Icon Preview" style="display:none;height:20px">
|
<img id="mainIconPreview" src="#" alt="Main Icon Preview" style="display:none;height:20px">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
<%--<tr>
|
||||||
|
<th>컨텐츠 내용</th>
|
||||||
|
<td colspan="5">
|
||||||
|
<textarea name="contentDetail" id="contentDetail" rows="10" cols="50"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>--%>
|
||||||
</table>
|
</table>
|
||||||
<div style="margin-top:15px;">
|
<div style="margin-top:15px;">
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 5px ">
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 5px ">
|
||||||
|
|||||||
@@ -56,16 +56,11 @@
|
|||||||
$("#expectEndDate").datepicker().inputmask("yyyy-mm-dd", {'autoUnmask': true});
|
$("#expectEndDate").datepicker().inputmask("yyyy-mm-dd", {'autoUnmask': true});
|
||||||
|
|
||||||
$("#btn_app_approve").click(function () {
|
$("#btn_app_approve").click(function () {
|
||||||
var isDeleteReq = (currentRequestType === 'DELETE');
|
if (confirm("승인하시겠습니까?")) {
|
||||||
var gwAction = (isDeleteReq && $('#chkGwDelete').is(':checked')) ? 'DELETE' : 'BLOCK';
|
|
||||||
var confirmMsg = isDeleteReq
|
|
||||||
? "해지 승인 시 포털 인증키(Credential)는 삭제되며,\n게이트웨이 클라이언트는 [" + (gwAction === 'DELETE' ? "완전 삭제" : "차단(비활성화)") + "] 처리됩니다.\n승인하시겠습니까?"
|
|
||||||
: "승인하시겠습니까?";
|
|
||||||
if (confirm(confirmMsg)) {
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: url,
|
url: url,
|
||||||
data: {cmd: "APPROVE", id: key, gwAction: gwAction},
|
data: {cmd: "APPROVE", id: key},
|
||||||
success: function (args) {
|
success: function (args) {
|
||||||
<%--alert("<%= localeMessage.getString("approval.approveSuccess") %>");--%>
|
<%--alert("<%= localeMessage.getString("approval.approveSuccess") %>");--%>
|
||||||
alert("승인되었습니다.");
|
alert("승인되었습니다.");
|
||||||
@@ -106,32 +101,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_app_force_reject").click(function () {
|
|
||||||
if (!confirm("승인자 목록에 삭제된 사용자가 있어 승인 진행이 불가능한 건입니다.\n강제 반려하시겠습니까?")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var rejectReason = prompt("강제 반려 사유를 입력해 주세요");
|
|
||||||
if (rejectReason != null) {
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
data: {cmd: "FORCE_REJECT", id: key, rejectReason: rejectReason},
|
|
||||||
success: function (args) {
|
|
||||||
alert("강제 반려되었습니다.");
|
|
||||||
if (window.dialogArguments && window.dialogArguments.self) {
|
|
||||||
window.dialogArguments.self.location.reload();
|
|
||||||
} else if (window.opener) {
|
|
||||||
window.opener.location.reload();
|
|
||||||
}
|
|
||||||
window.close();
|
|
||||||
},
|
|
||||||
error: function (e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#btn_app_redeploy').click(function () {
|
$('#btn_app_redeploy').click(function () {
|
||||||
if (confirm("재배포 하시겠습니까?")) {
|
if (confirm("재배포 하시겠습니까?")) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -181,8 +150,6 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var currentRequestType = null; // 현재 신청 유형 (DELETE 승인 시 GW 처리방식 선택 노출용)
|
|
||||||
|
|
||||||
function detail(key) {
|
function detail(key) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
@@ -211,11 +178,10 @@
|
|||||||
$("#createdDate").text(data.createdDate).inputmask("9999-99-99 99:99:99.999", {'autoUnmask': true});
|
$("#createdDate").text(data.createdDate).inputmask("9999-99-99 99:99:99.999", {'autoUnmask': true});
|
||||||
$("#expectEndDate").val(data.expectEndDate);
|
$("#expectEndDate").val(data.expectEndDate);
|
||||||
|
|
||||||
var isCurrentApprover = data.approvers.some(approver =>
|
if (data.approvers.some(approver =>
|
||||||
approver.approverStatus === 'CURRENT' &&
|
approver.approverStatus === 'CURRENT' &&
|
||||||
approver.user && approver.user.USERID === loginUser
|
approver.user.USERID === loginUser
|
||||||
);
|
)) {
|
||||||
if (isCurrentApprover) {
|
|
||||||
document.getElementById("btn_app_approve").style.display = "";
|
document.getElementById("btn_app_approve").style.display = "";
|
||||||
document.getElementById("btn_app_reject").style.display = "";
|
document.getElementById("btn_app_reject").style.display = "";
|
||||||
} else {
|
} else {
|
||||||
@@ -223,29 +189,6 @@
|
|||||||
document.getElementById("btn_app_reject").style.display = "none";
|
document.getElementById("btn_app_reject").style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
// API 이용해지(DELETE) 건: 승인 가능 상태의 현재 승인자에게만 GW 처리방식 선택 노출
|
|
||||||
currentRequestType = data.requestType;
|
|
||||||
var inProgress = data.approvalStatus.code === 'REQUESTED' || data.approvalStatus.code === 'PROCESSING';
|
|
||||||
if (data.requestType === 'DELETE' && isCurrentApprover && inProgress) {
|
|
||||||
$("#gwActionSection").show();
|
|
||||||
} else {
|
|
||||||
$("#gwActionSection").hide();
|
|
||||||
}
|
|
||||||
// 처리 완료된 해지 건은 어떤 방식으로 실행됐는지 표시
|
|
||||||
if (data.requestType === 'DELETE' && data.gwAction) {
|
|
||||||
$("#gwActionResult").text("GW 처리방식: " + (data.gwAction === 'DELETE' ? "완전 삭제" : "차단(비활성화)")).show();
|
|
||||||
} else {
|
|
||||||
$("#gwActionResult").hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 삭제된 승인자(USERID 없음)로 진행 불가한 건: 요청됨/진행중 상태면 승인자가 아니어도 강제 반려 허용
|
|
||||||
var hasDeletedApprover = data.approvers.some(approver =>
|
|
||||||
!approver.user || !approver.user.USERID
|
|
||||||
);
|
|
||||||
var isProgressStatus = data.approvalStatus.code === 'REQUESTED' || data.approvalStatus.code === 'PROCESSING';
|
|
||||||
document.getElementById("btn_app_force_reject").style.display =
|
|
||||||
(hasDeletedApprover && isProgressStatus && !isCurrentApprover) ? "" : "none";
|
|
||||||
|
|
||||||
if (data.approvalStatus.code === 'FAILED') {
|
if (data.approvalStatus.code === 'FAILED') {
|
||||||
document.getElementById("btn_app_redeploy").style.display = "";
|
document.getElementById("btn_app_redeploy").style.display = "";
|
||||||
}
|
}
|
||||||
@@ -357,10 +300,6 @@
|
|||||||
|
|
||||||
<div class="title">Client 정보</div>
|
<div class="title">Client 정보</div>
|
||||||
<table id="client" class="table_row" cellspacing="0">
|
<table id="client" class="table_row" cellspacing="0">
|
||||||
<colgroup>
|
|
||||||
<col style="width:20%"/>
|
|
||||||
<col style="width:80%"/>
|
|
||||||
</colgroup>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:20%;">이름</th>
|
<th style="width:20%;">이름</th>
|
||||||
<td><span id="clientName"></span></td>
|
<td><span id="clientName"></span></td>
|
||||||
@@ -392,13 +331,6 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id="gwActionSection" style="display:none; margin: 12px 0 0 4px; color: #c0392b;">
|
|
||||||
<label style="cursor:pointer;">
|
|
||||||
<input type="checkbox" id="chkGwDelete"/>
|
|
||||||
GW 인증정보 완전 삭제 (미체크 시 차단 처리 — 인증정보 보존, 복구 가능)
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="gwActionResult" style="display:none; margin: 12px 0 0 4px; font-weight: bold;"></div>
|
|
||||||
<div class="popup_button">
|
<div class="popup_button">
|
||||||
<button type="button" class="cssbtn" id="btn_modify" level="W"><i
|
<button type="button" class="cssbtn" id="btn_modify" level="W"><i
|
||||||
class="material-icons">save</i>수정
|
class="material-icons">save</i>수정
|
||||||
@@ -409,9 +341,6 @@
|
|||||||
<button type="button" class="cssbtn" style="display: none;" id="btn_app_reject" level="W"><i
|
<button type="button" class="cssbtn" style="display: none;" id="btn_app_reject" level="W"><i
|
||||||
class="material-icons">close</i>반려
|
class="material-icons">close</i>반려
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="cssbtn" style="display: none;" id="btn_app_force_reject" level="W"><i
|
|
||||||
class="material-icons">block</i>강제 반려
|
|
||||||
</button>
|
|
||||||
<button type="button" class="cssbtn" style="display: none;" id="btn_app_redeploy" level="W"><i
|
<button type="button" class="cssbtn" style="display: none;" id="btn_app_redeploy" level="W"><i
|
||||||
class="material-icons">close</i>재처리
|
class="material-icons">close</i>재처리
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -131,24 +131,6 @@
|
|||||||
// var reverseNumber = records - ((page - 1) * rowNum + i);
|
// var reverseNumber = records - ((page - 1) * rowNum + i);
|
||||||
$(this).setCell(rows[i], 'rowNum', number);
|
$(this).setCell(rows[i], 'rowNum', number);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 승인 상태별 행 배경색: 요청됨(#fff3cd) / 진행중(#d1ecf1) 강조
|
|
||||||
if (d && d.rows) {
|
|
||||||
for (var j = 0; j < d.rows.length; j++) {
|
|
||||||
var st = d.rows[j].approvalStatus || {};
|
|
||||||
var code = st.code || '';
|
|
||||||
var desc = st.description || '';
|
|
||||||
var bg = '';
|
|
||||||
if (code === 'REQUESTED' || desc === '요청됨') {
|
|
||||||
bg = '#fff3cd';
|
|
||||||
} else if (code === 'PROCESSING' || desc === '진행중') {
|
|
||||||
bg = '#d1ecf1';
|
|
||||||
}
|
|
||||||
if (bg) {
|
|
||||||
$('#grid tr#' + $.jgrid.jqID(d.rows[j].id)).css('background-color', bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
loadError: function(jqXHR, textStatus, errorThrown) {
|
loadError: function(jqXHR, textStatus, errorThrown) {
|
||||||
var location = '<%=request.getContextPath()%>/';
|
var location = '<%=request.getContextPath()%>/';
|
||||||
@@ -194,7 +176,7 @@
|
|||||||
<div class="title">승인 요청 목록<span class="tooltip">승인 요청을 관리합니다.</span></div>
|
<div class="title">승인 요청 목록<span class="tooltip">승인 요청을 관리합니다.</span></div>
|
||||||
<c:if test="${hardDeleteEnabled}">
|
<c:if test="${hardDeleteEnabled}">
|
||||||
<div style="background:#fff3cd; border:1px solid #ffc107; padding:8px 15px; margin:5px 0; border-radius:4px; color:#856404;">
|
<div style="background:#fff3cd; border:1px solid #ffc107; padding:8px 15px; margin:5px 0; border-radius:4px; color:#856404;">
|
||||||
<strong>[주의]</strong> 삭제 기능은 <strong>개발(dev) 환경에서만</strong> 동작합니다. 선택 삭제 시 승인 요청과 승인자 이력이 DB에서 영구 삭제됩니다.
|
<strong>[주의]</strong> 선택 삭제 시 승인 요청과 승인자 이력이 DB에서 영구 삭제됩니다.
|
||||||
</div>
|
</div>
|
||||||
</c:if>
|
</c:if>
|
||||||
<form id="ajaxForm" onsubmit="return false;">
|
<form id="ajaxForm" onsubmit="return false;">
|
||||||
|
|||||||
@@ -45,10 +45,6 @@
|
|||||||
padding: 2px 5px;
|
padding: 2px 5px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
.cssbtn:disabled {
|
|
||||||
opacity: 0.45;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<script language="javascript">
|
<script language="javascript">
|
||||||
<%
|
<%
|
||||||
@@ -154,55 +150,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_user_force_reject").click(function() {
|
|
||||||
if (!confirm("승인자 목록에 삭제된 사용자가 있어 승인 진행이 불가능한 건입니다.\n강제 반려하시겠습니까?")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var rejectReason = prompt("강제 반려 사유를 입력해 주세요");
|
|
||||||
if (rejectReason != null) {
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
data: {cmd: "FORCE_REJECT", id: key, rejectReason: rejectReason},
|
|
||||||
success: function(args) {
|
|
||||||
alert("강제 반려되었습니다.");
|
|
||||||
if (window.dialogArguments && window.dialogArguments.self) {
|
|
||||||
window.dialogArguments.self.location.reload();
|
|
||||||
} else if (window.opener) {
|
|
||||||
window.opener.location.reload();
|
|
||||||
}
|
|
||||||
window.close();
|
|
||||||
},
|
|
||||||
error: function(e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btn_user_delete").click(function() {
|
|
||||||
if (!confirm("삭제된 사용자 또는 법인이 포함되어 승인·반려할 수 없는 요청입니다.\n이 승인 요청을 삭제하시겠습니까?")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
data: {cmd: "DELETE", id: key},
|
|
||||||
success: function(args) {
|
|
||||||
alert("삭제되었습니다.");
|
|
||||||
if (window.dialogArguments && window.dialogArguments.self) {
|
|
||||||
window.dialogArguments.self.location.reload();
|
|
||||||
} else if (window.opener) {
|
|
||||||
window.opener.location.reload();
|
|
||||||
}
|
|
||||||
window.close();
|
|
||||||
},
|
|
||||||
error: function(e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#btn_user_redeploy').click(function() {
|
$('#btn_user_redeploy').click(function() {
|
||||||
if (confirm("재배포 하시겠습니까?")) {
|
if (confirm("재배포 하시겠습니까?")) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -270,55 +217,20 @@
|
|||||||
|
|
||||||
// Display Portal User details
|
// Display Portal User details
|
||||||
var portalUser = data.portalUser;
|
var portalUser = data.portalUser;
|
||||||
var portalOrg = portalUser ? portalUser.portalOrgUIs : null;
|
$("#loginId").text(portalUser.loginId);
|
||||||
|
$("#userName").text(portalUser.userName);
|
||||||
// 삭제된 대상 사용자/법인 판별
|
$("#mobileNumber").text(portalUser.mobileNumber);
|
||||||
var userDeleted = !portalUser
|
$("#userStatusDescription").text(portalUser.userStatusDescription);
|
||||||
|| portalUser.userName === '반려된 사용자'
|
$("#roleCodeDescription").text(portalUser.roleCodeDescription);
|
||||||
|| portalUser.userName === '삭제된 사용자';
|
if (data.approvers.some(approver =>
|
||||||
var orgDeleted = !portalOrg
|
|
||||||
|| portalOrg.orgStatus === 'REMOVED'
|
|
||||||
|| portalOrg.orgName === '삭제된법인';
|
|
||||||
var deletedTarget = userDeleted || orgDeleted;
|
|
||||||
|
|
||||||
if (portalUser) {
|
|
||||||
$("#loginId").text(portalUser.loginId);
|
|
||||||
$("#userName").text(portalUser.userName);
|
|
||||||
$("#mobileNumber").text(portalUser.mobileNumber);
|
|
||||||
$("#userStatusDescription").text(portalUser.userStatusDescription);
|
|
||||||
$("#roleCodeDescription").text(portalUser.roleCodeDescription);
|
|
||||||
} else {
|
|
||||||
$("#loginId, #userName, #mobileNumber, #userStatusDescription, #roleCodeDescription").text("삭제된 사용자");
|
|
||||||
}
|
|
||||||
|
|
||||||
var isCurrentApprover = data.approvers.some(approver =>
|
|
||||||
approver.approverStatus === 'CURRENT' &&
|
approver.approverStatus === 'CURRENT' &&
|
||||||
approver.user && approver.user.USERID === loginUser
|
approver.user.USERID === loginUser
|
||||||
);
|
)) {
|
||||||
|
document.getElementById("btn_user_approve").style.display = "";
|
||||||
if (deletedTarget) {
|
document.getElementById("btn_user_reject").style.display = "";
|
||||||
// 삭제된 사용자/법인 포함 → 승인·반려 불가. 버튼은 비활성(disable) 표기, 삭제 버튼 노출
|
|
||||||
$("#btn_user_approve, #btn_user_reject").show().prop("disabled", true);
|
|
||||||
document.getElementById("btn_user_force_reject").style.display = "none";
|
|
||||||
document.getElementById("btn_user_delete").style.display = "";
|
|
||||||
} else {
|
} else {
|
||||||
$("#btn_user_approve, #btn_user_reject").prop("disabled", false);
|
document.getElementById("btn_user_approve").style.display = "none";
|
||||||
document.getElementById("btn_user_delete").style.display = "none";
|
document.getElementById("btn_user_reject").style.display = "none";
|
||||||
if (isCurrentApprover) {
|
|
||||||
document.getElementById("btn_user_approve").style.display = "";
|
|
||||||
document.getElementById("btn_user_reject").style.display = "";
|
|
||||||
} else {
|
|
||||||
document.getElementById("btn_user_approve").style.display = "none";
|
|
||||||
document.getElementById("btn_user_reject").style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 삭제된 승인자(USERID 없음)로 진행 불가한 건: 요청됨/진행중 상태면 승인자가 아니어도 강제 반려 허용
|
|
||||||
var hasDeletedApprover = data.approvers.some(approver =>
|
|
||||||
!approver.user || !approver.user.USERID
|
|
||||||
);
|
|
||||||
var isProgressStatus = data.approvalStatus.code === 'REQUESTED' || data.approvalStatus.code === 'PROCESSING';
|
|
||||||
document.getElementById("btn_user_force_reject").style.display =
|
|
||||||
(hasDeletedApprover && isProgressStatus && !isCurrentApprover) ? "" : "none";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.approvalStatus.description === '배포실패'){
|
if (data.approvalStatus.description === '배포실패'){
|
||||||
@@ -326,27 +238,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Display Portal Org details
|
// Display Portal Org details
|
||||||
if (portalOrg) {
|
var portalOrg = portalUser.portalOrgUIs;
|
||||||
$("#orgName").text(portalOrg.orgName);
|
$("#orgName").text(portalOrg.orgName);
|
||||||
$("#orgStatusDescription").text(portalOrg.orgStatusDescription);
|
$("#orgStatusDescription").text(portalOrg.orgStatusDescription);
|
||||||
$("#serviceName").text(portalOrg.serviceName);
|
$("#serviceName").text(portalOrg.serviceName);
|
||||||
$("#corpRegNo").text(formatCorpRegNo(portalOrg.corpRegNo));
|
$("#corpRegNo").text(formatCorpRegNo(portalOrg.corpRegNo));
|
||||||
$("#compRegNo").text(formatCompanyRegNo(portalOrg.compRegNo));
|
$("#compRegNo").text(formatCompanyRegNo(portalOrg.compRegNo));
|
||||||
|
|
||||||
$("#scPhoneNumber").text(portalOrg.scPhoneNumber); // 고객센터 전화번호
|
$("#scPhoneNumber").text(portalOrg.scPhoneNumber); // 고객센터 전화번호
|
||||||
$("#orgPhoneNumber").text(portalOrg.orgPhoneNumber); // 회사 전화번호
|
$("#orgPhoneNumber").text(portalOrg.orgPhoneNumber); // 회사 전화번호
|
||||||
$("#ceoName").text(portalOrg.ceoName); // 대표자 성명
|
$("#ceoName").text(portalOrg.ceoName); // 대표자 성명
|
||||||
$("#orgIndustryType").text(portalOrg.orgIndustryType || ""); // 업종
|
$("#orgIndustryType").text(portalOrg.orgIndustryType || ""); // 업종
|
||||||
$("#orgAddr").text(portalOrg.orgAddr); // 소재지
|
$("#orgAddr").text(portalOrg.orgAddr); // 소재지
|
||||||
$("#orgSectors").text(portalOrg.orgSectors || ""); // 업태
|
$("#orgSectors").text(portalOrg.orgSectors || ""); // 업태
|
||||||
$("#orgCode").text(portalOrg.orgCode);
|
$("#orgCode").text(portalOrg.orgCode);
|
||||||
$("#ipWhitelist").text(portalOrg.ipWhitelist || "");
|
$("#ipWhitelist").text(portalOrg.ipWhitelist || "");
|
||||||
} else {
|
|
||||||
$("#orgName").text("삭제된법인");
|
|
||||||
$("#orgStatusDescription, #serviceName, #corpRegNo, #compRegNo, #scPhoneNumber, #orgPhoneNumber, #ceoName, #orgIndustryType, #orgAddr, #orgSectors, #orgCode, #ipWhitelist").text("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (portalOrg && portalOrg.compRegFile) {
|
if (portalOrg.compRegFile) {
|
||||||
$("#fileName").text(portalOrg.fileName);
|
$("#fileName").text(portalOrg.fileName);
|
||||||
if (portalOrg.fileName) {
|
if (portalOrg.fileName) {
|
||||||
$("#fileWrapper").show().off('click').on('click', function() {
|
$("#fileWrapper").show().off('click').on('click', function() {
|
||||||
@@ -386,18 +294,15 @@
|
|||||||
|
|
||||||
// 사용자 정보 업데이트
|
// 사용자 정보 업데이트
|
||||||
var portalUser = data.portalUser;
|
var portalUser = data.portalUser;
|
||||||
if (portalUser) {
|
$("#loginId").text(portalUser.loginId);
|
||||||
$("#loginId").text(portalUser.loginId);
|
$("#userName").text(portalUser.userName);
|
||||||
$("#userName").text(portalUser.userName);
|
$("#mobileNumber").text(portalUser.mobileNumber);
|
||||||
$("#mobileNumber").text(portalUser.mobileNumber);
|
$("#userStatusDescription").text(portalUser.userStatusDescription);
|
||||||
$("#userStatusDescription").text(portalUser.userStatusDescription);
|
$("#roleCodeDescription").text(portalUser.roleCodeDescription);
|
||||||
$("#roleCodeDescription").text(portalUser.roleCodeDescription);
|
|
||||||
} else {
|
|
||||||
$("#loginId, #userName, #mobileNumber, #userStatusDescription, #roleCodeDescription").text("삭제된 사용자");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 법인 정보 업데이트
|
// 법인 정보 업데이트
|
||||||
updateOrgInfo(portalUser ? portalUser.portalOrgUIs : null);
|
var portalOrg = portalUser.portalOrgUIs;
|
||||||
|
updateOrgInfo(portalOrg);
|
||||||
|
|
||||||
// 마스킹 상태에 따라 데이터를 다르게 표시
|
// 마스킹 상태에 따라 데이터를 다르게 표시
|
||||||
var isMasked = $("#btn_unmask").attr("status") === "DETAIL";
|
var isMasked = $("#btn_unmask").attr("status") === "DETAIL";
|
||||||
@@ -439,11 +344,6 @@
|
|||||||
|
|
||||||
// 법인 정보 업데이트 함수
|
// 법인 정보 업데이트 함수
|
||||||
function updateOrgInfo(portalOrg) {
|
function updateOrgInfo(portalOrg) {
|
||||||
if (!portalOrg) {
|
|
||||||
$("#orgName").text("삭제된법인");
|
|
||||||
$("#orgStatusDescription, #serviceName, #corpRegNo, #compRegNo, #scPhoneNumber, #orgPhoneNumber, #ceoName, #orgIndustryType, #orgAddr, #orgSectors, #orgCode, #ipWhitelist").text("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$("#orgName").text(portalOrg.orgName);
|
$("#orgName").text(portalOrg.orgName);
|
||||||
$("#orgStatusDescription").text(portalOrg.orgStatusDescription);
|
$("#orgStatusDescription").text(portalOrg.orgStatusDescription);
|
||||||
$("#serviceName").text(portalOrg.serviceName);
|
$("#serviceName").text(portalOrg.serviceName);
|
||||||
@@ -492,21 +392,15 @@
|
|||||||
|
|
||||||
<div class="title">사용자 정보</div>
|
<div class="title">사용자 정보</div>
|
||||||
<table class="table_row" cellspacing="0">
|
<table class="table_row" cellspacing="0">
|
||||||
<colgroup>
|
|
||||||
<col style="width:20%"/>
|
|
||||||
<col style="width:30%"/>
|
|
||||||
<col style="width:20%"/>
|
|
||||||
<col style="width:30%"/>
|
|
||||||
</colgroup>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>이메일 아이디</th>
|
<th style="width:20%;">이메일 아이디</th>
|
||||||
<td colspan="3"><span id="loginId"></span></td>
|
<td style="width:30%;" colspan="3"><span id="loginId"></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>이름</th>
|
<th style="width:20%;">이름</th>
|
||||||
<td><span id="userName"></span></td>
|
<td style="width:30%;"><span id="userName"></span></td>
|
||||||
<th>권한</th>
|
<th style="width:20%;">권한</th>
|
||||||
<td><span id="roleCodeDescription"></span></td>
|
<td style="width:30%;"><span id="roleCodeDescription"></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>핸드폰 번호</th>
|
<th>핸드폰 번호</th>
|
||||||
@@ -586,8 +480,6 @@
|
|||||||
<div class="popup_button">
|
<div class="popup_button">
|
||||||
<button type="button" class="cssbtn" style="display: none;" id="btn_user_approve" level="W"><i class="material-icons">check</i>승인</button>
|
<button type="button" class="cssbtn" style="display: none;" id="btn_user_approve" level="W"><i class="material-icons">check</i>승인</button>
|
||||||
<button type="button" class="cssbtn" style="display: none;" id="btn_user_reject" level="W"><i class="material-icons">close</i>반려</button>
|
<button type="button" class="cssbtn" style="display: none;" id="btn_user_reject" level="W"><i class="material-icons">close</i>반려</button>
|
||||||
<button type="button" class="cssbtn" style="display: none;" id="btn_user_force_reject" level="W"><i class="material-icons">block</i>강제 반려</button>
|
|
||||||
<button type="button" class="cssbtn" style="display: none;" id="btn_user_delete" level="W"><i class="material-icons">delete</i>삭제</button>
|
|
||||||
<button type="button" class="cssbtn" style="display: none;" id="btn_user_redeploy" level="W"><i class="material-icons">close</i>재처리</button>
|
<button type="button" class="cssbtn" style="display: none;" id="btn_user_redeploy" level="W"><i class="material-icons">close</i>재처리</button>
|
||||||
<button type="button" class="cssbtn" id="btn_close" level="R"><i class="material-icons">cancel</i> <%= localeMessage.getString("button.close") %>
|
<button type="button" class="cssbtn" id="btn_close" level="R"><i class="material-icons">cancel</i> <%= localeMessage.getString("button.close") %>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,212 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
|
||||||
<%@ page import="java.io.*" %>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
|
||||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
%>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
|
||||||
<style>
|
|
||||||
.mask-email { color:#1a73e8; font-weight:bold; }
|
|
||||||
.mask-phone { color:#d93025; font-weight:bold; }
|
|
||||||
.mask-digits { color:#9334e6; font-weight:bold; }
|
|
||||||
.msg-cell { display:inline-block; max-width:380px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; vertical-align:middle; }
|
|
||||||
</style>
|
|
||||||
<script language="javascript">
|
|
||||||
var url = '<c:url value="/onl/apim/messagerequest/messageRequestMan.json" />';
|
|
||||||
var url_view = '<c:url value="/onl/apim/messagerequest/messageRequestMan.view" />';
|
|
||||||
|
|
||||||
function escapeHtmlJs(s) { return $('<div>').text(s == null ? '' : s).html(); }
|
|
||||||
function escapeAttr(s) { return escapeHtmlJs(s).replace(/"/g, '"'); }
|
|
||||||
|
|
||||||
// 제목: 없으면 messageCode, 마우스오버에 코드명(코드) 표기
|
|
||||||
function formatSubject(cellvalue, options, rowObject) {
|
|
||||||
var code = rowObject.messageCode || '';
|
|
||||||
var subject = (cellvalue && cellvalue !== '') ? cellvalue : '';
|
|
||||||
var title = rowObject.messageCodeName ? (rowObject.messageCodeName + ' (' + code + ')') : code;
|
|
||||||
if (subject) {
|
|
||||||
// 제목이 있으면 2줄: 제목 + 하단에 메세지코드
|
|
||||||
var codeLine = code ? '<br><span style="color:#888;font-size:0.85em;">' + escapeHtmlJs(code) + '</span>' : '';
|
|
||||||
return '<span title="' + escapeAttr(title) + '">' + escapeHtmlJs(subject) + codeLine + '</span>';
|
|
||||||
}
|
|
||||||
// 제목이 없으면 메세지코드만
|
|
||||||
return '<span title="' + escapeAttr(title) + '">' + escapeHtmlJs(code) + '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 본문: 서버에서 마스킹+escape 된 안전 HTML 그대로 렌더
|
|
||||||
function formatMessage(cellvalue, options, rowObject) {
|
|
||||||
return '<span class="msg-cell">' + (rowObject.messageHtml || '') + '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 수신자 정보: 휴대폰 / 이메일 / 메신저ID (모두 마스킹됨)
|
|
||||||
function formatReceiverInfo(cellvalue, options, rowObject) {
|
|
||||||
var parts = [];
|
|
||||||
if (rowObject.phone) parts.push(escapeHtmlJs(rowObject.phone));
|
|
||||||
if (rowObject.email) parts.push(escapeHtmlJs(rowObject.email));
|
|
||||||
if (rowObject.messengerId) parts.push(escapeHtmlJs(rowObject.messengerId));
|
|
||||||
return parts.join('<br>');
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatRequestDate(cellvalue, options, rowObject) {
|
|
||||||
return '<span title="' + escapeAttr(rowObject.requestDateFull || '') + '">' + escapeHtmlJs(rowObject.requestDateShort || '') + '</span>';
|
|
||||||
}
|
|
||||||
function formatSentDate(cellvalue, options, rowObject) {
|
|
||||||
return '<span title="' + escapeAttr(rowObject.sentDateFull || '') + '">' + escapeHtmlJs(rowObject.sentDateShort || '') + '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url, dataType: "json",
|
|
||||||
data: {cmd: 'LIST_INIT_COMBO'},
|
|
||||||
success: function (json) {
|
|
||||||
new makeOptions("CODE", "NAME").setObj($("select[name=searchRequestStatus]"))
|
|
||||||
.setNoValueInclude(true).setNoValue("", "<%=localeMessage.getString("combo.all")%>")
|
|
||||||
.setData(json.statusList).rendering();
|
|
||||||
new makeOptions("CODE", "NAME").setObj($("select[name=searchMessageCode]"))
|
|
||||||
.setNoValueInclude(true).setNoValue("", "<%=localeMessage.getString("combo.all")%>")
|
|
||||||
.setData(json.messageCodeList).rendering();
|
|
||||||
|
|
||||||
putSelectFromParam();
|
|
||||||
|
|
||||||
// 콤보 로드 후 그리드 생성 (경합 방지)
|
|
||||||
buildGrid();
|
|
||||||
},
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildGrid() {
|
|
||||||
$('#grid').jqGrid({
|
|
||||||
datatype: "json", mtype: 'POST', url: url,
|
|
||||||
postData: getSearchForJqgrid("cmd", "LIST"),
|
|
||||||
colNames: ['id', 'No.', '제목', '메세지 내용', '수신자명', '수신자 정보', '유형', '상태', '요청시간', '발송시간'],
|
|
||||||
colModel: [
|
|
||||||
{name: 'id', align: 'center', key: true, hidden: true},
|
|
||||||
{name: 'rowNum', align: 'center', width: 45, sortable: false},
|
|
||||||
{name: 'subject', align: 'left', width: 160, formatter: formatSubject},
|
|
||||||
{name: 'messageHtml', align: 'left', width: 300, formatter: formatMessage},
|
|
||||||
{name: 'username', align: 'center', width: 80},
|
|
||||||
{name: 'receiverInfo', align: 'left', width: 150, formatter: formatReceiverInfo},
|
|
||||||
{name: 'messageType', align: 'center', width: 60},
|
|
||||||
{name: 'requestStatus', align: 'center', width: 70},
|
|
||||||
{name: 'requestDateShort', align: 'center', width: 110, formatter: formatRequestDate},
|
|
||||||
{name: 'sentDateShort', align: 'center', width: 110, formatter: formatSentDate}
|
|
||||||
],
|
|
||||||
jsonReader: {repeatitems: false},
|
|
||||||
pager: $('#pager'),
|
|
||||||
page: '${param.page}',
|
|
||||||
rowNum: '${rmsDefaultRowNum}',
|
|
||||||
autoheight: true,
|
|
||||||
height: $("#container").height(),
|
|
||||||
autowidth: true,
|
|
||||||
viewrecords: true,
|
|
||||||
rowList: eval('[${rmsDefaultRowList}]'),
|
|
||||||
ondblClickRow: function (rowId) {
|
|
||||||
var rowData = $(this).getRowData(rowId);
|
|
||||||
var id = rowData['id'];
|
|
||||||
var url2 = url_view + '?cmd=DETAIL';
|
|
||||||
url2 += '&page=' + $(this).getGridParam("page");
|
|
||||||
url2 += '&returnUrl=' + getReturnUrl();
|
|
||||||
url2 += '&menuId=' + '${param.menuId}';
|
|
||||||
url2 += '&id=' + id;
|
|
||||||
goNav(url2);
|
|
||||||
},
|
|
||||||
loadComplete: function () {
|
|
||||||
var page = $(this).getGridParam('page');
|
|
||||||
var rowNum = $(this).getGridParam('rowNum');
|
|
||||||
var rows = $(this).getDataIDs();
|
|
||||||
var colModel = $(this).getGridParam("colModel");
|
|
||||||
for (var i = 0; i < rows.length; i++) {
|
|
||||||
var number = ((page - 1) * rowNum + i) + 1;
|
|
||||||
$(this).setCell(rows[i], 'rowNum', number);
|
|
||||||
}
|
|
||||||
// 서버 고정 정렬(요청일 역순) — 컬럼 정렬 비활성
|
|
||||||
for (var i = 0; i < colModel.length; i++) {
|
|
||||||
$(this).setColProp(colModel[i].name, {sortable: false});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
loadError: function (jqXHR, textStatus, errorThrown) {
|
|
||||||
var location = '<%=request.getContextPath()%>/';
|
|
||||||
comloadError(jqXHR, textStatus, errorThrown, location);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
resizeJqGridWidth('grid', 'content_middle', '1000');
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
init();
|
|
||||||
|
|
||||||
$("#btn_search").click(function () {
|
|
||||||
var postData = getSearchForJqgrid("cmd", "LIST");
|
|
||||||
$("#grid").setGridParam({url: url, postData: postData, page: 1}).trigger("reloadGrid");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("select[name^=search]").change(function () { $("#btn_search").click(); });
|
|
||||||
$("input[name^=search]").keydown(function (key) {
|
|
||||||
if (key.keyCode == 13) { $("#btn_search").click(); }
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonControl();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="right_box">
|
|
||||||
<div class="content_top">
|
|
||||||
<ul class="path"><li><a href="#">${rmsMenuPath}</a></li></ul>
|
|
||||||
</div><!-- end content_top -->
|
|
||||||
<div class="content_middle" id="content_middle">
|
|
||||||
<div class="search_wrap">
|
|
||||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
|
||||||
</div>
|
|
||||||
<div class="title">메세지 발송 내역<span class="tooltip">발송 요청 이력을 조회합니다. 개인정보는 마스킹되어 표시됩니다.</span></div>
|
|
||||||
<form id="ajaxForm" onsubmit="return false;">
|
|
||||||
<table class="search_condition" cellspacing=0;>
|
|
||||||
<colgroup>
|
|
||||||
<col style="width:120px;"><col style="width:200px;">
|
|
||||||
<col style="width:120px;"><col style="width:200px;">
|
|
||||||
<col style="width:120px;"><col style="width:200px;">
|
|
||||||
</colgroup>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>상태</th>
|
|
||||||
<td><div class="select-style"><select name="searchRequestStatus"></select></div></td>
|
|
||||||
<th>메세지 코드</th>
|
|
||||||
<td><div class="select-style"><select name="searchMessageCode"></select></div></td>
|
|
||||||
<th>수신자명</th>
|
|
||||||
<td><input type="text" name="searchRecipient" autocomplete="off"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>유형</th>
|
|
||||||
<td>
|
|
||||||
<div class="select-style">
|
|
||||||
<select name="searchMessageType">
|
|
||||||
<option value="">전체</option>
|
|
||||||
<option value="EMAIL">EMAIL</option>
|
|
||||||
<option value="SMS">SMS</option>
|
|
||||||
<option value="MESSENGER">MESSENGER</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<th>요청기간</th>
|
|
||||||
<td colspan="3">
|
|
||||||
<input type="date" name="searchFromDate"> ~ <input type="date" name="searchToDate">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
<table id="grid"></table>
|
|
||||||
<div id="pager"></div>
|
|
||||||
</div><!-- end content_middle -->
|
|
||||||
</div><!-- end right_box -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
|
||||||
<%@ page import="java.io.*" %>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
|
||||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
%>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
|
||||||
<style>
|
|
||||||
.mask-email { color:#1a73e8; font-weight:bold; }
|
|
||||||
.mask-phone { color:#d93025; font-weight:bold; }
|
|
||||||
.mask-digits { color:#9334e6; font-weight:bold; }
|
|
||||||
.msg-detail { white-space:pre-wrap; word-break:break-all; min-height:80px; line-height:1.6; }
|
|
||||||
</style>
|
|
||||||
<script language="javascript">
|
|
||||||
var url = '<c:url value="/onl/apim/messagerequest/messageRequestMan.json" />';
|
|
||||||
var url_view = '<c:url value="/onl/apim/messagerequest/messageRequestMan.view" />';
|
|
||||||
var key = '${param.id}';
|
|
||||||
|
|
||||||
function detail() {
|
|
||||||
if (!key) return;
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url, dataType: "json",
|
|
||||||
data: {cmd: 'DETAIL', id: key},
|
|
||||||
success: function (data) {
|
|
||||||
var codeText = (data.messageCodeName || '') + (data.messageCode ? ' (' + data.messageCode + ')' : '');
|
|
||||||
$('#messageCodeName').text(codeText);
|
|
||||||
$('#subject').text((data.subject && data.subject !== '') ? data.subject : (data.messageCode || ''));
|
|
||||||
$('#messageType').text(data.messageType || '');
|
|
||||||
$('#requestStatus').text(data.requestStatus || '');
|
|
||||||
$('#username').text(data.username || '');
|
|
||||||
$('#email').text(data.email || '');
|
|
||||||
$('#phone').text(data.phone || '');
|
|
||||||
$('#messengerId').text(data.messengerId || '');
|
|
||||||
$('#umsUid').text(data.umsUid || '');
|
|
||||||
$('#eaiInterfaceId').text(data.eaiInterfaceId || '');
|
|
||||||
$('#serviceId').text(data.serviceId || '');
|
|
||||||
$('#requestDate').text(data.requestDateFull || '');
|
|
||||||
$('#sentDate').text(data.sentDateFull || '');
|
|
||||||
// 서버에서 마스킹+escape 된 안전 HTML
|
|
||||||
$('#messageHtml').html(data.messageHtml || '');
|
|
||||||
|
|
||||||
// PENDING 건만 '실패 처리' 노출 (권한 제어는 buttonControl 이 담당)
|
|
||||||
if (data.requestStatus !== 'PENDING') {
|
|
||||||
$('#btn_fail').hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
var returnUrl = getReturnUrlForReturn();
|
|
||||||
|
|
||||||
buttonControl();
|
|
||||||
detail();
|
|
||||||
|
|
||||||
$('#btn_fail').click(function () {
|
|
||||||
if (!confirm('이 건을 FAILED(발송 실패) 상태로 변경하시겠습니까?')) return;
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url, dataType: "json",
|
|
||||||
data: {cmd: 'UPDATE_STATUS', id: key},
|
|
||||||
success: function () {
|
|
||||||
alert("변경되었습니다.");
|
|
||||||
detail();
|
|
||||||
},
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#btn_previous').click(function () { goNav(returnUrl); });
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="right_box">
|
|
||||||
<div class="content_top">
|
|
||||||
<ul class="path"><li><a href="#">${rmsMenuPath}</a></li></ul>
|
|
||||||
</div>
|
|
||||||
<div class="content_middle">
|
|
||||||
<div class="search_wrap">
|
|
||||||
<button type="button" class="cssbtn" id="btn_fail" level="W" status="DETAIL" style="background-color:#dc3545;border-color:#dc3545;color:#fff;"><i class="material-icons">report</i> 실패 처리</button>
|
|
||||||
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
|
||||||
</div>
|
|
||||||
<div class="title" id="title">메세지 발송 내역 상세<span class="tooltip">개인정보는 마스킹되어 표시됩니다.</span></div>
|
|
||||||
<table class="table_row" cellspacing="0">
|
|
||||||
<colgroup>
|
|
||||||
<col style="width:12%"/><col style="width:38%"/>
|
|
||||||
<col style="width:12%"/><col style="width:38%"/>
|
|
||||||
</colgroup>
|
|
||||||
<tr>
|
|
||||||
<th>메세지 코드</th>
|
|
||||||
<td colspan="3"><span id="messageCodeName"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>제목</th>
|
|
||||||
<td colspan="3"><span id="subject"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>유형</th>
|
|
||||||
<td><span id="messageType"></span></td>
|
|
||||||
<th>상태</th>
|
|
||||||
<td><span id="requestStatus"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>수신자명</th>
|
|
||||||
<td><span id="username"></span></td>
|
|
||||||
<th>메신저 ID</th>
|
|
||||||
<td><span id="messengerId"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>이메일</th>
|
|
||||||
<td><span id="email"></span></td>
|
|
||||||
<th>휴대폰</th>
|
|
||||||
<td><span id="phone"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>요청 시간</th>
|
|
||||||
<td><span id="requestDate"></span></td>
|
|
||||||
<th>발송 시간</th>
|
|
||||||
<td><span id="sentDate"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>EAI 인터페이스 ID</th>
|
|
||||||
<td><span id="eaiInterfaceId"></span></td>
|
|
||||||
<th>서비스 ID</th>
|
|
||||||
<td><span id="serviceId"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>UMS UID</th>
|
|
||||||
<td colspan="3"><span id="umsUid"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>메세지 내용</th>
|
|
||||||
<td colspan="3"><div id="messageHtml" class="msg-detail"></div></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -22,8 +22,6 @@
|
|||||||
function formatInquiryStatus(cellvalue, options, rowObject) {
|
function formatInquiryStatus(cellvalue, options, rowObject) {
|
||||||
if (cellvalue == 'PENDING') {
|
if (cellvalue == 'PENDING') {
|
||||||
return '<span style="color: red;">문의중</span>';
|
return '<span style="color: red;">문의중</span>';
|
||||||
} else if (cellvalue == 'REVIEWING') {
|
|
||||||
return '<span >문의검토중</span>'
|
|
||||||
} else if (cellvalue == 'RESPONDED') {
|
} else if (cellvalue == 'RESPONDED') {
|
||||||
return '<span >답변완료</span>'
|
return '<span >답변완료</span>'
|
||||||
} else if (cellvalue == 'CLOSED') {
|
} else if (cellvalue == 'CLOSED') {
|
||||||
@@ -33,17 +31,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatVisibility(cellvalue, options, rowObject) {
|
|
||||||
if (cellvalue == 'PRIVATE') {
|
|
||||||
return '<span style="color:#c0392b; font-weight:bold;">비공개</span>';
|
|
||||||
} else if (cellvalue == 'ALL') {
|
|
||||||
return '전체공개';
|
|
||||||
} else if (cellvalue == 'ORG') {
|
|
||||||
return '법인공개';
|
|
||||||
}
|
|
||||||
return cellvalue;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatFile(cellvalue, options, rowObject) {
|
function formatFile(cellvalue, options, rowObject) {
|
||||||
var iconPath = '${pageContext.request.contextPath}/images/icon_file.png';
|
var iconPath = '${pageContext.request.contextPath}/images/icon_file.png';
|
||||||
var icon = rowObject.hasAttachment ? '<img src="' + iconPath + '" alt="File Attached" style="vertical-align: middle; margin-left: 5px; width: 16px; height: 16px;">' : '';
|
var icon = rowObject.hasAttachment ? '<img src="' + iconPath + '" alt="File Attached" style="vertical-align: middle; margin-left: 5px; width: 16px; height: 16px;">' : '';
|
||||||
@@ -112,14 +99,13 @@
|
|||||||
mtype: 'POST',
|
mtype: 'POST',
|
||||||
url: url,
|
url: url,
|
||||||
postData : { cmd : 'LIST' },
|
postData : { cmd : 'LIST' },
|
||||||
colNames:['No.', 'id', '제목', '법인명', '상태', '공개범위', '작성자', '등록일', '답변자','답변일'],
|
colNames:['No.', 'id', '제목', '법인명', '상태', '작성자', '등록일', '답변자','답변일'],
|
||||||
colModel:[
|
colModel:[
|
||||||
{ name : 'rowNum' , align:'center', width:50, sortable:false },
|
{ name : 'rowNum' , align:'center', width:50, sortable:false },
|
||||||
{ name : 'id' , align:'center', key:true, hidden:true},
|
{ name : 'id' , align:'center', key:true, hidden:true},
|
||||||
{ name : 'inquirySubject' , align:'left' , width:200 , formatter: formatFile},
|
{ name : 'inquirySubject' , align:'left' , width:200 , formatter: formatFile},
|
||||||
{ name : 'orgName' , align:'center' , width:100 , },
|
{ name : 'orgName' , align:'center' , width:100 , },
|
||||||
{ name : 'inquiryStatus' , align:'center', width:70, formatter: formatInquiryStatus },
|
{ name : 'inquiryStatus' , align:'center', width:70, formatter: formatInquiryStatus },
|
||||||
{ name : 'visibility' , align:'center', width:70, formatter: formatVisibility },
|
|
||||||
{ name : 'inquirer.userName', align:'center', width:70 },
|
{ name : 'inquirer.userName', align:'center', width:70 },
|
||||||
{ name : 'createdDate' , align:'center', width:100, formatter: timeStampFormat },
|
{ name : 'createdDate' , align:'center', width:100, formatter: timeStampFormat },
|
||||||
{ name : 'responderName' , align:'center', width:70 },
|
{ name : 'responderName' , align:'center', width:70 },
|
||||||
@@ -221,9 +207,7 @@
|
|||||||
<select name="searchInquiryStatus">
|
<select name="searchInquiryStatus">
|
||||||
<option value="">전체</option>
|
<option value="">전체</option>
|
||||||
<option value="PENDING">문의중</option>
|
<option value="PENDING">문의중</option>
|
||||||
<option value="REVIEWING">문의검토중</option>
|
|
||||||
<option value="RESPONDED">답변완료</option>
|
<option value="RESPONDED">답변완료</option>
|
||||||
<option value="CLOSED">답변종료</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -79,46 +79,12 @@
|
|||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reason-modal-overlay {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
top: 0; left: 0;
|
|
||||||
width: 100%; height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.4);
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.reason-modal-box {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%; left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 20px;
|
|
||||||
width: 400px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
.reason-modal-box h3 {
|
|
||||||
margin: 0 0 12px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.reason-modal-box textarea {
|
|
||||||
width: 100%;
|
|
||||||
min-height: 80px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.reason-modal-actions {
|
|
||||||
margin-top: 12px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<script language="javascript">
|
<script language="javascript">
|
||||||
var url = '<c:url value="/onl/apim/portalinquiry/portalInquiryMan.json" />';
|
var url = '<c:url value="/onl/apim/portalinquiry/portalInquiryMan.json" />';
|
||||||
var url_view = '<c:url value="/onl/apim/portalinquiry/portalInquiryMan.view" />';
|
var url_view = '<c:url value="/onl/apim/portalinquiry/portalInquiryMan.view" />';
|
||||||
var file_download = '<c:url value="/file/download.do" />';
|
var file_download = '<c:url value="/file/download.do" />';
|
||||||
var inquiryStatus = 'PENDING';
|
var inquiryStatus = 'PENDING';
|
||||||
var originalVisibility = 'ORG';
|
|
||||||
var reasonModalCallback = null;
|
|
||||||
|
|
||||||
function decodeHTMLEntities(text) {
|
function decodeHTMLEntities(text) {
|
||||||
var textArea = document.createElement('textarea');
|
var textArea = document.createElement('textarea');
|
||||||
@@ -142,9 +108,7 @@
|
|||||||
|
|
||||||
inquiryStatus = data.inquiryStatus;
|
inquiryStatus = data.inquiryStatus;
|
||||||
if (data.inquiryStatus == 'PENDING') {
|
if (data.inquiryStatus == 'PENDING') {
|
||||||
$("#inquiryStatus").text('문의중');
|
$("#inquiryStatus").text('문의중');
|
||||||
} else if (data.inquiryStatus == 'REVIEWING') {
|
|
||||||
$("#inquiryStatus").text('문의검토중');
|
|
||||||
} else if (data.inquiryStatus == 'RESPONDED') {
|
} else if (data.inquiryStatus == 'RESPONDED') {
|
||||||
$("#inquiryStatus").text('답변완료');
|
$("#inquiryStatus").text('답변완료');
|
||||||
} else if (data.inquiryStatus == 'CLOSED') {
|
} else if (data.inquiryStatus == 'CLOSED') {
|
||||||
@@ -158,24 +122,6 @@
|
|||||||
var decodedContent = decodeHTMLEntities(data.responseDetail);
|
var decodedContent = decodeHTMLEntities(data.responseDetail);
|
||||||
$("#responseDetail").summernote('code', decodedContent || '');
|
$("#responseDetail").summernote('code', decodedContent || '');
|
||||||
|
|
||||||
// 공개범위 / 조회수
|
|
||||||
$('#visibilitySelect').val(data.visibility || 'ORG');
|
|
||||||
originalVisibility = data.visibility || 'ORG';
|
|
||||||
$('#viewCount').text(data.viewCount || 0);
|
|
||||||
|
|
||||||
// 조회수 증가 (sessionStorage dedup — 새로고침 시 중복 증가 억제)
|
|
||||||
var viewedKey = 'inquiry_viewed_' + key;
|
|
||||||
if (!sessionStorage.getItem(viewedKey)) {
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
data: {cmd: 'INCREMENT_VIEW', id: key},
|
|
||||||
success: function () {
|
|
||||||
sessionStorage.setItem(viewedKey, 'true');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 댓글 표시
|
// 댓글 표시
|
||||||
listComment(key);
|
listComment(key);
|
||||||
|
|
||||||
@@ -201,17 +147,8 @@
|
|||||||
if (!data || data.length === 0) return;
|
if (!data || data.length === 0) return;
|
||||||
$.each(data, function (i, comment) {
|
$.each(data, function (i, comment) {
|
||||||
var date = comment.createdDate ? timeStampFormat(comment.createdDate) : '';
|
var date = comment.createdDate ? timeStampFormat(comment.createdDate) : '';
|
||||||
var isPrivate = comment.visibility === 'PRIVATE';
|
|
||||||
var row = $('<div>').addClass('info-row');
|
var row = $('<div>').addClass('info-row');
|
||||||
if (isPrivate) {
|
$('<div>').addClass('info-label').css('color', '#555').text(comment.writerName || '').appendTo(row);
|
||||||
// 비공개 댓글은 색상으로 구별
|
|
||||||
row.css({'background-color': '#FFF5F5', 'border-radius': '4px', 'padding': '4px'});
|
|
||||||
}
|
|
||||||
var labelDiv = $('<div>').addClass('info-label').css('color', '#555').text(comment.writerName || '');
|
|
||||||
if (isPrivate) {
|
|
||||||
$('<span>').text(' 비공개').css({'color': '#c0392b', 'font-size': '0.85em', 'font-weight': 'bold'}).appendTo(labelDiv);
|
|
||||||
}
|
|
||||||
labelDiv.appendTo(row);
|
|
||||||
var content = $('<div>').addClass('info-content');
|
var content = $('<div>').addClass('info-content');
|
||||||
$('<div>').css('white-space', 'pre-wrap').text(comment.commentDetail).appendTo(content);
|
$('<div>').css('white-space', 'pre-wrap').text(comment.commentDetail).appendTo(content);
|
||||||
var meta = $('<div>').css({'font-size': '0.9em', 'color': '#999', 'margin-top': '2px'});
|
var meta = $('<div>').css({'font-size': '0.9em', 'color': '#999', 'margin-top': '2px'});
|
||||||
@@ -222,19 +159,6 @@
|
|||||||
})(comment.id, comment.inquiryId))
|
})(comment.id, comment.inquiryId))
|
||||||
.appendTo(meta);
|
.appendTo(meta);
|
||||||
meta.appendTo(content);
|
meta.appendTo(content);
|
||||||
|
|
||||||
// 댓글 공개범위 변경 컨트롤 (사유 필수)
|
|
||||||
var visCtrl = $('<div>').css({'margin-top': '4px', 'font-size': '0.85em'});
|
|
||||||
var sel = $('<select>').append('<option value="ALL">공개</option>').append('<option value="PRIVATE">비공개</option>');
|
|
||||||
sel.val(comment.visibility || 'ALL');
|
|
||||||
var reasonInput = $('<input>').attr({'type': 'text', 'placeholder': '변경 사유'}).css({'margin-left': '4px'});
|
|
||||||
var applyBtn = $('<button>').attr('type', 'button').addClass('cssbtn smallBtn2').css({'margin-left': '4px', 'font-size': '0.85em', 'padding': '1px 6px'})
|
|
||||||
.text('공개범위변경').on('click', (function(id, inquiryId, selEl, reasonEl) {
|
|
||||||
return function() { changeCommentVisibility(id, inquiryId, selEl.val(), reasonEl.val()); };
|
|
||||||
})(comment.id, comment.inquiryId, sel, reasonInput));
|
|
||||||
visCtrl.append(sel).append(reasonInput).append(applyBtn);
|
|
||||||
visCtrl.appendTo(content);
|
|
||||||
|
|
||||||
content.appendTo(row);
|
content.appendTo(row);
|
||||||
row.appendTo($commentList);
|
row.appendTo($commentList);
|
||||||
});
|
});
|
||||||
@@ -245,84 +169,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function openReasonModal(callback) {
|
|
||||||
reasonModalCallback = callback;
|
|
||||||
$('#reasonModalInput').val('');
|
|
||||||
$('#reasonModal').show();
|
|
||||||
$('#reasonModalInput').focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeReasonModal() {
|
|
||||||
$('#reasonModal').hide();
|
|
||||||
reasonModalCallback = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 답변(summernote) 내용이 실제로 입력됐는지 확인
|
|
||||||
function hasAnswerContent() {
|
|
||||||
var v = $('#responseDetail').summernote('code');
|
|
||||||
var text = $('<div>').html(v || '').text().replace(/ /g, ' ').trim();
|
|
||||||
return text.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveInquiryAnswer(returnUrl) {
|
|
||||||
var postData = $('#ajaxForm').serializeArray();
|
|
||||||
postData.push({name: "cmd", value: "INSERT"});
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
data: postData,
|
|
||||||
success: function (json) {
|
|
||||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
|
||||||
goNav(returnUrl);
|
|
||||||
},
|
|
||||||
error: function (e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 게시물 공개범위 변경(사유 필수). 성공 후 답변 내용이 있으면 이어서 저장.
|
|
||||||
function changeInquiryVisibility(newVis, reason, returnUrl, thenSaveAnswer) {
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
data: {cmd: 'VISIBILITY', serviceType: 'APIGW', targetType: 'INQUIRY', id: $('#id').val(),
|
|
||||||
visibility: newVis, auditReason: reason},
|
|
||||||
success: function () {
|
|
||||||
originalVisibility = newVis;
|
|
||||||
if (thenSaveAnswer) {
|
|
||||||
saveInquiryAnswer(returnUrl);
|
|
||||||
} else {
|
|
||||||
alert('변경되었습니다.');
|
|
||||||
goNav(returnUrl);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function (e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeCommentVisibility(commentId, inquiryId, visibility, reason) {
|
|
||||||
if (!reason || !reason.trim()) {
|
|
||||||
alert('공개범위 변경 사유를 입력하세요.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!confirm('댓글 공개범위를 변경하시겠습니까?')) return;
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
data: {cmd: 'VISIBILITY', serviceType: 'APIGW', targetType: 'COMMENT', id: commentId, visibility: visibility, auditReason: reason},
|
|
||||||
success: function () {
|
|
||||||
alert('변경되었습니다.');
|
|
||||||
listComment(inquiryId);
|
|
||||||
},
|
|
||||||
error: function (e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteComment(commentId, inquiryId) {
|
function deleteComment(commentId, inquiryId) {
|
||||||
if (inquiryStatus == 'CLOSED') {
|
if (inquiryStatus == 'CLOSED') {
|
||||||
alert('답변이 종료되어 삭제할 수 없습니다');
|
alert('답변이 종료되어 삭제할 수 없습니다');
|
||||||
@@ -362,38 +208,24 @@
|
|||||||
alert('답변이 종료되어 수정할 수 없습니다');
|
alert('답변이 종료되어 수정할 수 없습니다');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newVis = $('#visibilitySelect').val();
|
|
||||||
var visChanged = (newVis !== originalVisibility);
|
|
||||||
|
|
||||||
if (visChanged) {
|
|
||||||
// 공개범위 변경 감지 → 사유 입력 모달 (답변 내용이 있으면 함께 저장)
|
|
||||||
var saveAnswerToo = hasAnswerContent();
|
|
||||||
openReasonModal(function (reason) {
|
|
||||||
changeInquiryVisibility(newVis, reason, returnUrl, saveAnswerToo);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 공개범위 변경 없음 → 기존 답변 저장
|
|
||||||
if (!checkRequired("ajaxForm")) return;
|
if (!checkRequired("ajaxForm")) return;
|
||||||
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
||||||
saveInquiryAnswer(returnUrl);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#reasonModalOk").click(function () {
|
var postData = $('#ajaxForm').serializeArray();
|
||||||
var reason = ($('#reasonModalInput').val() || '').trim();
|
postData.push({name: "cmd", value: "INSERT"});
|
||||||
if (!reason) {
|
|
||||||
alert('변경 사유를 입력하세요.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var cb = reasonModalCallback;
|
|
||||||
closeReasonModal();
|
|
||||||
if (cb) cb(reason);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#reasonModalCancel").click(function () {
|
$.ajax({
|
||||||
closeReasonModal();
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
data: postData,
|
||||||
|
success: function (json) {
|
||||||
|
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||||
|
goNav(returnUrl);
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
alert(e.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_comment").click(function () {
|
$("#btn_comment").click(function () {
|
||||||
@@ -476,22 +308,7 @@
|
|||||||
<div class="info-label">작성일</div>
|
<div class="info-label">작성일</div>
|
||||||
<div id="createdDate" class="info-content"></div>
|
<div id="createdDate" class="info-content"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-row">
|
<div class="info-row" id="attachFileRow" style="display: none;">
|
||||||
<div class="info-label">조회수</div>
|
|
||||||
<div id="viewCount" class="info-content">0</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-label">공개범위</div>
|
|
||||||
<div class="info-content" style="display:flex; gap:8px; align-items:center;">
|
|
||||||
<select id="visibilitySelect">
|
|
||||||
<option value="ALL">전체공개</option>
|
|
||||||
<option value="ORG">법인공개</option>
|
|
||||||
<option value="PRIVATE">비공개</option>
|
|
||||||
</select>
|
|
||||||
<span style="font-size:0.85em; color:#999;">변경 후 상단 [수정] 버튼을 누르면 사유 입력창이 표시됩니다.</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-row" id="attachFileRow" style="display: none;">
|
|
||||||
<div class="info-label">첨부파일</div>
|
<div class="info-label">첨부파일</div>
|
||||||
<div id="attachFiles" class="info-content"></div>
|
<div id="attachFiles" class="info-content"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -539,17 +356,5 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 공개범위 변경 사유 입력 모달 -->
|
|
||||||
<div id="reasonModal" class="reason-modal-overlay">
|
|
||||||
<div class="reason-modal-box">
|
|
||||||
<h3>공개범위 변경 사유</h3>
|
|
||||||
<textarea id="reasonModalInput" placeholder="변경 사유를 입력하세요."></textarea>
|
|
||||||
<div class="reason-modal-actions">
|
|
||||||
<button type="button" class="cssbtn" id="reasonModalOk">확인</button>
|
|
||||||
<button type="button" class="cssbtn" id="reasonModalCancel">취소</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,550 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
|
||||||
<%@ page import="java.io.*" %>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
|
||||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
%>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/portal.jsp"/>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
/* ── 스윔레인 보드 ── */
|
|
||||||
.menu-board { display: flex; gap: 12px; align-items: flex-start; }
|
|
||||||
.menu-lane-strip { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 10px; flex: 1 1 auto; }
|
|
||||||
.menu-lane { background: #f1f3f5; border-radius: 10px; min-width: 230px; max-width: 230px; flex: 0 0 230px; }
|
|
||||||
.menu-lane.unplaced { background: #fff4e6; border: 1px dashed #fd7e14; }
|
|
||||||
.lane-header { display: flex; align-items: center; gap: 6px; padding: 10px 12px;
|
|
||||||
border-bottom: 1px solid #dee2e6; cursor: grab; }
|
|
||||||
.menu-lane.unplaced .lane-header { cursor: default; }
|
|
||||||
.lane-title { font-weight: 700; font-size: 14px; flex: 1 1 auto; overflow: hidden;
|
|
||||||
text-overflow: ellipsis; white-space: nowrap; }
|
|
||||||
.lane-body { list-style: none; margin: 0; padding: 8px; min-height: 60px; }
|
|
||||||
.menu-card { background: #fff; border: 1px solid #dee2e6; border-radius: 8px;
|
|
||||||
padding: 8px 10px; margin-bottom: 8px; cursor: grab;
|
|
||||||
box-shadow: 0 1px 2px rgba(0,0,0,0.06); }
|
|
||||||
.menu-card.hidden-item, .menu-lane.hidden-item > .lane-header { opacity: 0.45; }
|
|
||||||
.menu-card .card-name { font-size: 13px; font-weight: 600; }
|
|
||||||
.menu-card .card-id { font-size: 11px; color: #868e96; }
|
|
||||||
.menu-card .card-path { font-size: 11px; color: #495057; word-break: break-all; }
|
|
||||||
.card-actions, .lane-actions { display: flex; gap: 4px; }
|
|
||||||
.icon-btn { border: none; background: transparent; padding: 1px 3px; cursor: pointer;
|
|
||||||
font-size: 14px; color: #495057; }
|
|
||||||
.icon-btn:hover { color: #0d6efd; }
|
|
||||||
.icon-btn.danger:hover { color: #dc3545; }
|
|
||||||
.badge-src { font-size: 10px; }
|
|
||||||
.role-check-group { display: flex; flex-wrap: wrap; gap: 4px 12px; }
|
|
||||||
.role-check-group .form-check { min-width: 45%; }
|
|
||||||
.dflt-hint { font-size: 11px; color: #868e96; }
|
|
||||||
.board-toolbar { display: flex; gap: 6px; margin-bottom: 10px; align-items: center; }
|
|
||||||
.board-toolbar .spacer { flex: 1 1 auto; }
|
|
||||||
.sortable-placeholder { border: 2px dashed #adb5bd; border-radius: 8px; height: 48px;
|
|
||||||
margin-bottom: 8px; background: #e9ecef; }
|
|
||||||
.lane-placeholder { border: 2px dashed #adb5bd; border-radius: 10px; min-width: 230px; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script language="javascript">
|
|
||||||
// AuthorizeInterceptor 는 serviceType 을 "요청 파라미터"에서 읽으므로
|
|
||||||
// 모든 .json 호출 URL 에 serviceType 을 부착한다 (누락 시 권한 조회 실패 → Access denied)
|
|
||||||
var url = urlAddServiceType('<c:url value="/onl/apim/portalmenu/portalMenuMan.json" />');
|
|
||||||
|
|
||||||
// 화면 상태 (저장 버튼 클릭 시에만 서버 반영 — 드래그/토글은 클라이언트 상태만 변경)
|
|
||||||
var state = { itemsById: {}, lanes: [], unplaced: [], roles: [] };
|
|
||||||
var dirty = false;
|
|
||||||
|
|
||||||
function escapeHtml(s) {
|
|
||||||
return String(s == null ? '' : s)
|
|
||||||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
||||||
.replace(/"/g, '"').replace(/'/g, ''');
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadAll(afterFn) {
|
|
||||||
$.post(url, { cmd: 'LIST_ALL' }, function (data) {
|
|
||||||
buildState(data);
|
|
||||||
render();
|
|
||||||
dirty = false;
|
|
||||||
if (afterFn) afterFn();
|
|
||||||
}, 'json').fail(ajaxFail);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildState(data) {
|
|
||||||
state.itemsById = {};
|
|
||||||
state.roles = data.roles || [];
|
|
||||||
(data.items || []).forEach(function (it) { state.itemsById[it.menuId] = it; });
|
|
||||||
|
|
||||||
var placedTop = [], childrenByParent = {}, unplaced = [];
|
|
||||||
(data.items || []).forEach(function (it) {
|
|
||||||
if (!it.placed) { unplaced.push(it.menuId); return; }
|
|
||||||
if (!it.parentId) {
|
|
||||||
placedTop.push(it);
|
|
||||||
} else {
|
|
||||||
(childrenByParent[it.parentId] = childrenByParent[it.parentId] || []).push(it);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
placedTop.sort(function (a, b) { return (a.sortOrder || 0) - (b.sortOrder || 0); });
|
|
||||||
|
|
||||||
state.lanes = placedTop.map(function (top) {
|
|
||||||
var kids = (childrenByParent[top.menuId] || [])
|
|
||||||
.sort(function (a, b) { return (a.sortOrder || 0) - (b.sortOrder || 0); })
|
|
||||||
.map(function (c) { return { menuId: c.menuId, visibleYn: c.visibleYn || 'Y' }; });
|
|
||||||
delete childrenByParent[top.menuId];
|
|
||||||
return { menuId: top.menuId, visibleYn: top.visibleYn || 'Y', children: kids };
|
|
||||||
});
|
|
||||||
// 부모가 미배치/부재인 고아 배치는 미배치로 강등
|
|
||||||
Object.keys(childrenByParent).forEach(function (pid) {
|
|
||||||
childrenByParent[pid].forEach(function (c) { unplaced.push(c.menuId); });
|
|
||||||
});
|
|
||||||
state.unplaced = unplaced;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 렌더 ──
|
|
||||||
function cardHtml(menuId, visibleYn, inLane) {
|
|
||||||
var it = state.itemsById[menuId];
|
|
||||||
if (!it) return '';
|
|
||||||
var hidden = visibleYn === 'N';
|
|
||||||
var srcBadge = it.sourceType === 'PORTAL'
|
|
||||||
? '<span class="badge text-bg-secondary badge-src">기본</span>'
|
|
||||||
: '<span class="badge text-bg-warning badge-src">커스텀</span>';
|
|
||||||
var grpBadge = it.groupYn === 'Y' ? ' <span class="badge text-bg-info badge-src">그룹</span>' : '';
|
|
||||||
var placeBtn = (!inLane && it.groupYn === 'Y')
|
|
||||||
? '<button type="button" class="icon-btn" title="최상위 레인으로 배치" onclick="placeAsLane(\'' + menuId + '\')"><i class="bi bi-box-arrow-in-up"></i></button>'
|
|
||||||
: '';
|
|
||||||
var eyeBtn = inLane
|
|
||||||
? '<button type="button" class="icon-btn" title="노출/숨김" onclick="toggleVisible(\'' + menuId + '\')"><i class="bi ' + (hidden ? 'bi-eye-slash' : 'bi-eye') + '"></i></button>'
|
|
||||||
: '';
|
|
||||||
return '<li class="menu-card' + (hidden ? ' hidden-item' : '') + '" data-menu-id="' + escapeHtml(menuId) + '">'
|
|
||||||
+ '<div class="d-flex align-items-start">'
|
|
||||||
+ '<div class="flex-grow-1">'
|
|
||||||
+ '<div class="card-name">' + escapeHtml(it.menuName) + ' ' + srcBadge + grpBadge + '</div>'
|
|
||||||
+ '<div class="card-id">' + escapeHtml(it.menuId) + '</div>'
|
|
||||||
+ (it.menuPath ? '<div class="card-path">' + escapeHtml(it.menuPath) + '</div>' : '')
|
|
||||||
+ '</div>'
|
|
||||||
+ '<div class="card-actions">'
|
|
||||||
+ placeBtn + eyeBtn
|
|
||||||
+ '<button type="button" class="icon-btn" title="수정" onclick="openModal(\'' + menuId + '\')"><i class="bi bi-pencil"></i></button>'
|
|
||||||
+ '<button type="button" class="icon-btn danger" level="W" title="' + (it.sourceType === 'PORTAL' ? '미배치로 이동' : '삭제') + '" onclick="minusItem(\'' + menuId + '\')"><i class="bi bi-dash-circle"></i></button>'
|
|
||||||
+ '</div></div></li>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function laneHtml(lane) {
|
|
||||||
var it = state.itemsById[lane.menuId];
|
|
||||||
if (!it) return '';
|
|
||||||
var hidden = lane.visibleYn === 'N';
|
|
||||||
var sectionBadge = it.menuSection === 'MYPAGE'
|
|
||||||
? '<span class="badge text-bg-primary badge-src">마이페이지</span>'
|
|
||||||
: '<span class="badge text-bg-success badge-src">GNB</span>';
|
|
||||||
var srcBadge = it.sourceType === 'PORTAL' ? '' : ' <span class="badge text-bg-warning badge-src">커스텀</span>';
|
|
||||||
var cards = lane.children.map(function (c) { return cardHtml(c.menuId, c.visibleYn, true); }).join('');
|
|
||||||
return '<div class="menu-lane' + (hidden ? ' hidden-item' : '') + '" data-menu-id="' + escapeHtml(lane.menuId) + '">'
|
|
||||||
+ '<div class="lane-header lane-drag-handle">'
|
|
||||||
+ '<span class="lane-title">' + escapeHtml(it.menuName) + '</span>'
|
|
||||||
+ sectionBadge + srcBadge
|
|
||||||
+ '<div class="lane-actions">'
|
|
||||||
+ '<button type="button" class="icon-btn" title="노출/숨김" onclick="toggleVisible(\'' + lane.menuId + '\')"><i class="bi ' + (hidden ? 'bi-eye-slash' : 'bi-eye') + '"></i></button>'
|
|
||||||
+ '<button type="button" class="icon-btn" title="수정" onclick="openModal(\'' + lane.menuId + '\')"><i class="bi bi-pencil"></i></button>'
|
|
||||||
+ '<button type="button" class="icon-btn danger" level="W" title="레인 미배치" onclick="unplaceLane(\'' + lane.menuId + '\')"><i class="bi bi-dash-circle"></i></button>'
|
|
||||||
+ '</div></div>'
|
|
||||||
+ '<ul class="lane-body" data-lane-id="' + escapeHtml(lane.menuId) + '">' + cards + '</ul>'
|
|
||||||
+ '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function render() {
|
|
||||||
var strip = state.lanes.map(laneHtml).join('');
|
|
||||||
$('#laneStrip').html(strip);
|
|
||||||
$('#unplacedBody').html(state.unplaced.map(function (id) { return cardHtml(id, 'Y', false); }).join(''));
|
|
||||||
initSortables();
|
|
||||||
buttonControl();
|
|
||||||
}
|
|
||||||
|
|
||||||
function initSortables() {
|
|
||||||
$('#laneStrip').sortable({
|
|
||||||
items: '.menu-lane',
|
|
||||||
handle: '.lane-drag-handle',
|
|
||||||
placeholder: 'lane-placeholder',
|
|
||||||
tolerance: 'pointer',
|
|
||||||
update: function () { syncFromDom(); }
|
|
||||||
});
|
|
||||||
$('.lane-body, #unplacedBody').sortable({
|
|
||||||
connectWith: '.lane-body, #unplacedBody',
|
|
||||||
items: '.menu-card',
|
|
||||||
placeholder: 'sortable-placeholder',
|
|
||||||
tolerance: 'pointer',
|
|
||||||
stop: function () { syncFromDom(); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 드래그 종료 후 DOM 순서 → 상태 동기화 (visible 값은 기존 상태 유지)
|
|
||||||
function syncFromDom() {
|
|
||||||
var visibleMap = {};
|
|
||||||
state.lanes.forEach(function (l) {
|
|
||||||
visibleMap[l.menuId] = l.visibleYn;
|
|
||||||
l.children.forEach(function (c) { visibleMap[c.menuId] = c.visibleYn; });
|
|
||||||
});
|
|
||||||
|
|
||||||
var lanes = [];
|
|
||||||
$('#laneStrip .menu-lane').each(function () {
|
|
||||||
var laneId = $(this).data('menu-id');
|
|
||||||
var children = [];
|
|
||||||
$(this).find('.lane-body .menu-card').each(function () {
|
|
||||||
var id = $(this).data('menu-id');
|
|
||||||
children.push({ menuId: id, visibleYn: visibleMap[id] || 'Y' });
|
|
||||||
});
|
|
||||||
lanes.push({ menuId: laneId, visibleYn: visibleMap[laneId] || 'Y', children: children });
|
|
||||||
});
|
|
||||||
var unplaced = [];
|
|
||||||
$('#unplacedBody .menu-card').each(function () { unplaced.push($(this).data('menu-id')); });
|
|
||||||
|
|
||||||
state.lanes = lanes;
|
|
||||||
state.unplaced = unplaced;
|
|
||||||
dirty = true;
|
|
||||||
render();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 카드/레인 조작 ──
|
|
||||||
function toggleVisible(menuId) {
|
|
||||||
state.lanes.forEach(function (l) {
|
|
||||||
if (l.menuId === menuId) l.visibleYn = (l.visibleYn === 'N' ? 'Y' : 'N');
|
|
||||||
l.children.forEach(function (c) {
|
|
||||||
if (c.menuId === menuId) c.visibleYn = (c.visibleYn === 'N' ? 'Y' : 'N');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
dirty = true;
|
|
||||||
render();
|
|
||||||
}
|
|
||||||
|
|
||||||
function placeAsLane(menuId) {
|
|
||||||
state.unplaced = state.unplaced.filter(function (id) { return id !== menuId; });
|
|
||||||
state.lanes.push({ menuId: menuId, visibleYn: 'Y', children: [] });
|
|
||||||
dirty = true;
|
|
||||||
render();
|
|
||||||
}
|
|
||||||
|
|
||||||
function minusItem(menuId) {
|
|
||||||
var it = state.itemsById[menuId];
|
|
||||||
if (!it) return;
|
|
||||||
if (it.sourceType === 'PORTAL') {
|
|
||||||
removeFromBoard(menuId);
|
|
||||||
if (state.unplaced.indexOf(menuId) < 0) state.unplaced.push(menuId);
|
|
||||||
dirty = true;
|
|
||||||
render();
|
|
||||||
} else {
|
|
||||||
if (!confirm('커스텀 항목은 미배치 시 삭제됩니다.\n[' + it.menuName + '] 을(를) 삭제하시겠습니까?')) return;
|
|
||||||
$.post(url, { cmd: 'DELETE', menuId: menuId }, function () {
|
|
||||||
removeFromBoard(menuId);
|
|
||||||
state.unplaced = state.unplaced.filter(function (id) { return id !== menuId; });
|
|
||||||
delete state.itemsById[menuId];
|
|
||||||
dirty = true;
|
|
||||||
render();
|
|
||||||
}, 'json').fail(ajaxFail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function unplaceLane(laneId) {
|
|
||||||
var lane = null;
|
|
||||||
state.lanes = state.lanes.filter(function (l) {
|
|
||||||
if (l.menuId === laneId) { lane = l; return false; }
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
if (!lane) return;
|
|
||||||
lane.children.forEach(function (c) {
|
|
||||||
if (state.unplaced.indexOf(c.menuId) < 0) state.unplaced.push(c.menuId);
|
|
||||||
});
|
|
||||||
var it = state.itemsById[laneId];
|
|
||||||
if (it && it.sourceType !== 'PORTAL') {
|
|
||||||
if (confirm('커스텀 항목은 미배치 시 삭제됩니다.\n[' + it.menuName + '] 항목을 삭제하시겠습니까?')) {
|
|
||||||
$.post(url, { cmd: 'DELETE', menuId: laneId }, function () {
|
|
||||||
delete state.itemsById[laneId];
|
|
||||||
render();
|
|
||||||
}, 'json').fail(ajaxFail);
|
|
||||||
} else {
|
|
||||||
state.unplaced.push(laneId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (state.unplaced.indexOf(laneId) < 0) state.unplaced.push(laneId);
|
|
||||||
}
|
|
||||||
dirty = true;
|
|
||||||
render();
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeFromBoard(menuId) {
|
|
||||||
state.lanes = state.lanes.filter(function (l) { return l.menuId !== menuId; });
|
|
||||||
state.lanes.forEach(function (l) {
|
|
||||||
l.children = l.children.filter(function (c) { return c.menuId !== menuId; });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 저장 / 초기화 / 캐시 Reload ──
|
|
||||||
function savePlacements() {
|
|
||||||
// 미배치 상태의 커스텀 항목은 저장 시 삭제 처리 (스펙: 커스텀은 미배치=삭제)
|
|
||||||
var unplacedAdmin = state.unplaced.filter(function (id) {
|
|
||||||
var it = state.itemsById[id];
|
|
||||||
return it && it.sourceType !== 'PORTAL';
|
|
||||||
});
|
|
||||||
if (unplacedAdmin.length > 0) {
|
|
||||||
var names = unplacedAdmin.map(function (id) { return state.itemsById[id].menuName; }).join(', ');
|
|
||||||
if (!confirm('미배치된 커스텀 항목은 저장 시 삭제됩니다: ' + names + '\n계속하시겠습니까?')) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rows = [];
|
|
||||||
state.lanes.forEach(function (l, i) {
|
|
||||||
rows.push({ menuId: l.menuId, parentId: null, sortOrder: (i + 1) * 10, visibleYn: l.visibleYn });
|
|
||||||
l.children.forEach(function (c, j) {
|
|
||||||
rows.push({ menuId: c.menuId, parentId: l.menuId, sortOrder: (j + 1) * 10, visibleYn: c.visibleYn });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var deleteCalls = unplacedAdmin.map(function (id) {
|
|
||||||
return $.post(url, { cmd: 'DELETE', menuId: id });
|
|
||||||
});
|
|
||||||
$.when.apply($, deleteCalls).always(function () {
|
|
||||||
$.ajax({
|
|
||||||
url: url + '&cmd=TRANSACTION_PLACEMENT',
|
|
||||||
type: 'POST',
|
|
||||||
contentType: 'application/json; charset=utf-8',
|
|
||||||
data: JSON.stringify(rows)
|
|
||||||
}).done(function () {
|
|
||||||
dirty = false;
|
|
||||||
loadAll(function () {
|
|
||||||
if (confirm('배치가 저장되었습니다.\n포탈 메뉴 캐시를 즉시 반영(Reload)하시겠습니까?\n(미반영 시 캐시 TTL 후 자동 반영)')) {
|
|
||||||
reloadPortalCache();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).fail(ajaxFail);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeMenus() {
|
|
||||||
if (!confirm('메뉴 초기화 시 포탈 기본(menu.yml) 값으로 복원되고\n커스텀 항목은 모두 삭제됩니다. 계속하시겠습니까?')) return;
|
|
||||||
$.post(url, { cmd: 'INITIALIZE' }, function () {
|
|
||||||
loadAll(function () { alert('메뉴가 초기화되었습니다.'); });
|
|
||||||
}, 'json').fail(ajaxFail);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadPortalCache() {
|
|
||||||
$.post(url, { cmd: 'TRANSACTION_RELOAD' }, function (result) {
|
|
||||||
if (result && result.success) {
|
|
||||||
alert('포탈 메뉴 캐시 리로드 완료 (항목 ' + result.itemCount + '건, ' + result.reloadedAt + ')');
|
|
||||||
} else {
|
|
||||||
alert('캐시 리로드 실패: ' + (result ? result.message : '알 수 없는 오류'));
|
|
||||||
}
|
|
||||||
}, 'json').fail(ajaxFail);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ajaxFail(xhr) {
|
|
||||||
var msg = '처리 중 오류가 발생했습니다.';
|
|
||||||
try {
|
|
||||||
var body = JSON.parse(xhr.responseText);
|
|
||||||
if (body.errorMsg) msg = body.errorMsg;
|
|
||||||
else if (body.message) msg = body.message;
|
|
||||||
} catch (e) { /* ignore */ }
|
|
||||||
alert(msg + ' (HTTP ' + xhr.status + ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 추가/수정 모달 ──
|
|
||||||
var menuModal;
|
|
||||||
|
|
||||||
function roleChecksHtml(namePrefix, checkedCsv) {
|
|
||||||
var checked = (checkedCsv || '').split(',').map(function (s) { return s.trim(); }).filter(Boolean);
|
|
||||||
var html = '';
|
|
||||||
var all = [{ roleCode: 'AUTHENTICATED', roleName: '로그인 사용자', roleType: '-' }].concat(state.roles);
|
|
||||||
all.forEach(function (r) {
|
|
||||||
var id = namePrefix + '_' + r.roleCode;
|
|
||||||
html += '<div class="form-check form-check-sm">'
|
|
||||||
+ '<input class="form-check-input" type="checkbox" name="' + namePrefix + '" id="' + id + '" value="' + escapeHtml(r.roleCode) + '"'
|
|
||||||
+ (checked.indexOf(r.roleCode) >= 0 ? ' checked' : '') + '>'
|
|
||||||
+ '<label class="form-check-label" for="' + id + '" style="font-size:12px;">'
|
|
||||||
+ escapeHtml(r.roleName) + ' <span class="text-muted">(' + escapeHtml(r.roleCode) + ')</span></label>'
|
|
||||||
+ '</div>';
|
|
||||||
});
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openModal(menuId) {
|
|
||||||
var isNew = !menuId;
|
|
||||||
var it = isNew ? { sourceType: 'ADMIN', groupYn: 'N', menuSection: 'GNB', newWindowYn: 'N' }
|
|
||||||
: state.itemsById[menuId];
|
|
||||||
if (!it) return;
|
|
||||||
var isPortal = it.sourceType === 'PORTAL';
|
|
||||||
|
|
||||||
$('#modalTitle').text(isNew ? '메뉴 추가' : '메뉴 수정' + (isPortal ? ' (기본 항목)' : ''));
|
|
||||||
$('#fMenuId').val(it.menuId || '').prop('readonly', !isNew);
|
|
||||||
$('#fMenuName').val(it.menuName || '');
|
|
||||||
$('#fMenuPath').val(it.menuPath || '');
|
|
||||||
$('#fIconClass').val(it.iconClass || '');
|
|
||||||
$('#fMenuSection').val(it.menuSection || 'GNB').prop('disabled', isPortal);
|
|
||||||
$('#fGroupYn').prop('checked', it.groupYn === 'Y').prop('disabled', isPortal);
|
|
||||||
$('#fNewWindowYn').prop('checked', it.newWindowYn === 'Y');
|
|
||||||
$('#exposeRoleChecks').html(roleChecksHtml('exposeRole', it.exposeRoles));
|
|
||||||
$('#accessRoleChecks').html(roleChecksHtml('accessRole', it.accessRoles));
|
|
||||||
|
|
||||||
// 기본 항목: 기본값(DFLT_*) 병기
|
|
||||||
if (isPortal) {
|
|
||||||
$('#hintMenuName').text('기본값: ' + (it.dfltMenuName || '-'));
|
|
||||||
$('#hintMenuPath').text('기본값: ' + (it.dfltMenuPath || '-'));
|
|
||||||
$('#hintExposeRoles').text('기본값: ' + (it.dfltExposeRoles || '전체 노출'));
|
|
||||||
$('#hintAccessRoles').text('기본값: ' + (it.dfltAccessRoles || '제한 없음'));
|
|
||||||
$('.dflt-hint').show();
|
|
||||||
} else {
|
|
||||||
$('.dflt-hint').hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#modalMode').val(isNew ? 'INSERT' : 'UPDATE');
|
|
||||||
menuModal.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitModal() {
|
|
||||||
var cmd = $('#modalMode').val();
|
|
||||||
var data = {
|
|
||||||
cmd: cmd,
|
|
||||||
menuId: $('#fMenuId').val().trim(),
|
|
||||||
menuName: $('#fMenuName').val().trim(),
|
|
||||||
menuPath: $('#fMenuPath').val().trim(),
|
|
||||||
iconClass: $('#fIconClass').val().trim(),
|
|
||||||
menuSection: $('#fMenuSection').val(),
|
|
||||||
groupYn: $('#fGroupYn').is(':checked') ? 'Y' : 'N',
|
|
||||||
newWindowYn: $('#fNewWindowYn').is(':checked') ? 'Y' : 'N',
|
|
||||||
exposeRoles: $('input[name=exposeRole]:checked').map(function () { return this.value; }).get().join(','),
|
|
||||||
accessRoles: $('input[name=accessRole]:checked').map(function () { return this.value; }).get().join(',')
|
|
||||||
};
|
|
||||||
if (!data.menuId) { alert('메뉴 ID 를 입력하세요.'); return; }
|
|
||||||
if (cmd === 'INSERT' && !/^[a-z0-9-]+$/.test(data.menuId)) {
|
|
||||||
alert('메뉴 ID 는 kebab-case(소문자/숫자/하이픈)만 허용합니다.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!data.menuName) { alert('노출명을 입력하세요.'); return; }
|
|
||||||
|
|
||||||
$.post(url, data, function () {
|
|
||||||
menuModal.hide();
|
|
||||||
loadAll();
|
|
||||||
}, 'json').fail(ajaxFail);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
menuModal = new bootstrap.Modal(document.getElementById('menuModal'));
|
|
||||||
loadAll();
|
|
||||||
|
|
||||||
window.addEventListener('beforeunload', function (e) {
|
|
||||||
if (dirty) { e.preventDefault(); e.returnValue = ''; }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="right_box">
|
|
||||||
<div class="content_top">
|
|
||||||
<ul class="path">
|
|
||||||
<li><a href="#">${rmsMenuPath}</a></li>
|
|
||||||
</ul>
|
|
||||||
</div><!-- end content_top -->
|
|
||||||
<div class="content_middle" id="content_middle">
|
|
||||||
|
|
||||||
<div class="title">포탈 메뉴 관리</div>
|
|
||||||
|
|
||||||
<div class="board-toolbar">
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" level="W" onclick="openModal()">
|
|
||||||
<i class="bi bi-plus-lg"></i> 메뉴 추가</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger" level="W" onclick="initializeMenus()">
|
|
||||||
<i class="bi bi-arrow-counterclockwise"></i> 메뉴 초기화</button>
|
|
||||||
<span class="spacer"></span>
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" level="W" onclick="reloadPortalCache()">
|
|
||||||
<i class="bi bi-arrow-repeat"></i> 캐시 Reload</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-success" level="W" onclick="savePlacements()">
|
|
||||||
<i class="bi bi-save"></i> 저장</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="background:#e7f1ff; border:1px solid #0d6efd33; padding:8px 15px; margin-bottom:10px; border-radius:6px; font-size:12px; color:#31507a;">
|
|
||||||
드래그로 위치를 조절한 뒤 <strong>저장</strong> 버튼으로 일괄 반영합니다.
|
|
||||||
기본 항목([기본] 배지)은 [-] 시 <strong>미배치</strong>로만 이동하고, 커스텀 항목은 미배치 시 <strong>삭제</strong>됩니다.
|
|
||||||
저장 후 <strong>캐시 Reload</strong> 를 실행해야 포탈에 즉시 반영됩니다(미실행 시 TTL 경과 후 반영).
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="menu-board">
|
|
||||||
<div class="menu-lane-strip" id="laneStrip"><!-- 렌더링 --></div>
|
|
||||||
<div class="menu-lane unplaced">
|
|
||||||
<div class="lane-header">
|
|
||||||
<span class="lane-title">미배치</span>
|
|
||||||
<span class="badge text-bg-warning badge-src">보관함</span>
|
|
||||||
</div>
|
|
||||||
<ul class="lane-body" id="unplacedBody"><!-- 렌더링 --></ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 추가/수정 모달 -->
|
|
||||||
<div class="modal fade" id="menuModal" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="modalTitle">메뉴 추가</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="닫기"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<input type="hidden" id="modalMode" value="INSERT">
|
|
||||||
<div class="row g-3">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label" for="fMenuId">메뉴 ID (kebab-case)</label>
|
|
||||||
<input type="text" class="form-control form-control-sm" id="fMenuId" placeholder="ex) custom-link">
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label" for="fMenuName">노출명</label>
|
|
||||||
<input type="text" class="form-control form-control-sm" id="fMenuName">
|
|
||||||
<div class="dflt-hint" id="hintMenuName"></div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label" for="fMenuPath">Path (그룹은 생략 가능)</label>
|
|
||||||
<input type="text" class="form-control form-control-sm" id="fMenuPath" placeholder="/example 또는 https://...">
|
|
||||||
<div class="dflt-hint" id="hintMenuPath"></div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label" for="fIconClass">아이콘 클래스 (마이페이지용, ex: fa-users)</label>
|
|
||||||
<input type="text" class="form-control form-control-sm" id="fIconClass">
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label class="form-label" for="fMenuSection">섹션</label>
|
|
||||||
<select class="form-select form-select-sm" id="fMenuSection">
|
|
||||||
<option value="GNB">GNB (상단 메뉴)</option>
|
|
||||||
<option value="MYPAGE">마이페이지</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 d-flex align-items-end">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="fGroupYn">
|
|
||||||
<label class="form-check-label" for="fGroupYn">그룹(상위 메뉴)</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 d-flex align-items-end">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="fNewWindowYn">
|
|
||||||
<label class="form-check-label" for="fNewWindowYn">새 창 열기</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">노출 권한 (미선택 = 전체 노출)</label>
|
|
||||||
<div class="role-check-group" id="exposeRoleChecks"></div>
|
|
||||||
<div class="dflt-hint" id="hintExposeRoles"></div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label">접근 권한 (미선택 = 제한 없음)</label>
|
|
||||||
<div class="role-check-group" id="accessRoleChecks"></div>
|
|
||||||
<div class="dflt-hint" id="hintAccessRoles"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">취소</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" level="W" onclick="submitModal()">저장</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div><!-- end content_middle -->
|
|
||||||
</div><!-- end right_box -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -18,43 +18,15 @@
|
|||||||
var url = '<c:url value="/onl/apim/portalnotice/portalNoticeMan.json" />';
|
var url = '<c:url value="/onl/apim/portalnotice/portalNoticeMan.json" />';
|
||||||
var url_view = '<c:url value="/onl/apim/portalnotice/portalNoticeMan.view" />';
|
var url_view = '<c:url value="/onl/apim/portalnotice/portalNoticeMan.view" />';
|
||||||
var combo;
|
var combo;
|
||||||
|
|
||||||
// 코드 상수 — PortalNoticeUI 와 동기화
|
|
||||||
var NOTICE_TYPE_INCIDENT = '3';
|
|
||||||
|
|
||||||
// IncidentState 라벨 — 상세 화면과 동일하게 유지
|
|
||||||
var STATE_LABELS = {
|
|
||||||
'INVESTIGATING': '조사중',
|
|
||||||
'IDENTIFIED': '원인 파악',
|
|
||||||
'MONITORING': '모니터링',
|
|
||||||
'RESOLVED': '해소',
|
|
||||||
'CANCELED': '취소'
|
|
||||||
};
|
|
||||||
|
|
||||||
function formatIncidentState(cellvalue, options, rowObject) {
|
|
||||||
if (!cellvalue) return '';
|
|
||||||
var label = STATE_LABELS[cellvalue] || cellvalue;
|
|
||||||
var closed = (cellvalue === 'RESOLVED' || cellvalue === 'CANCELED');
|
|
||||||
return closed
|
|
||||||
? '<span title="' + cellvalue + '">' + label + '</span>'
|
|
||||||
: '<span style="color: red;" title="' + cellvalue + '">' + label + '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatNoticeType(cellvalue, options, rowObject) {
|
function formatNoticeType(cellvalue, options, rowObject) {
|
||||||
var name = cellvalue;
|
var name = "";
|
||||||
if (combo && combo.noticeTypeList) {
|
for (var i = 0; i < combo.noticeTypeList.length; i++) {
|
||||||
for (var i = 0; i < combo.noticeTypeList.length; i++) {
|
if (combo.noticeTypeList[i].CODE == cellvalue) {
|
||||||
if (combo.noticeTypeList[i].CODE == cellvalue) {
|
return combo.noticeTypeList[i].NAME;
|
||||||
name = combo.noticeTypeList[i].NAME;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 장애인데 종료 시각이 없으면 아직 진행 중이다
|
return cellvalue;
|
||||||
if (cellvalue == NOTICE_TYPE_INCIDENT && rowObject && !rowObject.endAt) {
|
|
||||||
return '<span style="color: red;">' + name + '-진행중</span>';
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatuseYn(cellvalue, options, rowObject) {
|
function formatuseYn(cellvalue, options, rowObject) {
|
||||||
@@ -74,39 +46,8 @@
|
|||||||
var icon = rowObject.hasAttachment ? '<img src="' + iconPath + '" alt="File Attached" style="vertical-align: middle; margin-left: 5px; width: 16px; height: 16px;">' : '';
|
var icon = rowObject.hasAttachment ? '<img src="' + iconPath + '" alt="File Attached" style="vertical-align: middle; margin-left: 5px; width: 16px; height: 16px;">' : '';
|
||||||
return cellvalue + icon;
|
return cellvalue + icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteSelectedRows() {
|
|
||||||
var selectedIds = $("#grid").jqGrid('getGridParam', 'selarrrow');
|
|
||||||
|
|
||||||
if (selectedIds.length === 0) {
|
|
||||||
alert('항목을 선택하세요.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!confirm('선택된 ' + selectedIds.length + '개 항목을 삭제하시겠습니까?')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
dataType: "json",
|
|
||||||
data: {
|
|
||||||
cmd: 'DELETE_BULK',
|
|
||||||
ids: selectedIds.join(',')
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
alert('삭제되었습니다.');
|
|
||||||
$("#grid").jqGrid('clearGridData', true);
|
|
||||||
$("#grid").trigger("reloadGrid");
|
|
||||||
},
|
|
||||||
error: function(e) {
|
|
||||||
alert('삭제 중 오류가 발생했습니다.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function init(){
|
function init(){
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : "POST",
|
type : "POST",
|
||||||
@@ -117,11 +58,8 @@
|
|||||||
console.log('init', json);
|
console.log('init', json);
|
||||||
combo = json;
|
combo = json;
|
||||||
new makeOptions("CODE","NAME").setObj($("select[name=searchNoticeType]")).setNoValueInclude(true).setNoValue('','<%=localeMessage.getString("combo.all")%>').setData(json.noticeTypeList).rendering();
|
new makeOptions("CODE","NAME").setObj($("select[name=searchNoticeType]")).setNoValueInclude(true).setNoValue('','<%=localeMessage.getString("combo.all")%>').setData(json.noticeTypeList).rendering();
|
||||||
|
|
||||||
putSelectFromParam();
|
putSelectFromParam();
|
||||||
|
|
||||||
// 콤보(combo)가 채워진 뒤에 그리드를 생성해야 formatNoticeType 경합이 발생하지 않음
|
|
||||||
buildGrid();
|
|
||||||
},
|
},
|
||||||
error:function(e){
|
error:function(e){
|
||||||
alert(e.responseText);
|
alert(e.responseText);
|
||||||
@@ -129,8 +67,8 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildGrid(){
|
$(document).ready(function() {
|
||||||
|
|
||||||
$('#grid').jqGrid({
|
$('#grid').jqGrid({
|
||||||
datatype:"json",
|
datatype:"json",
|
||||||
mtype: 'POST',
|
mtype: 'POST',
|
||||||
@@ -141,15 +79,14 @@
|
|||||||
searchNoticeSubject: $('input[name=searchNoticeSubject]').val(),
|
searchNoticeSubject: $('input[name=searchNoticeSubject]').val(),
|
||||||
searchNoticeDetail: $('input[name=searchNoticeDetail]').val()
|
searchNoticeDetail: $('input[name=searchNoticeDetail]').val()
|
||||||
},
|
},
|
||||||
colNames:['id', 'No.', '게시유형', '제목', '고정여부', '사용', '장애상태', '마지막 수정일', '등록일', '등록자', '조회수'],
|
colNames:['id', 'No.', '게시유형', '제목', '고정여부', '사용', '마지막 수정일', '등록일', '등록자', '조회수'],
|
||||||
colModel:[
|
colModel:[
|
||||||
{ name : 'id' , align:'center', key:true, hidden:true},
|
{ name : 'id' , align:'center', key:true, hidden:true},
|
||||||
{ name : 'rowNum' , align:'center', width:60 },
|
{ name : 'rowNum' , align:'center', width:60 },
|
||||||
{ name : 'noticeType' , align:'center', width:100, formatter: formatNoticeType },
|
{ name : 'noticeType' , align:'center', width:60, formatter: formatNoticeType },
|
||||||
{ name : 'noticeSubject' , align:'left' , width:300, formatter: formatFile },
|
{ name : 'noticeSubject' , align:'left' , width:300, formatter: formatFile },
|
||||||
{ name : 'fixYn' , align:'center', width:60, formatter: formatFixYn },
|
{ name : 'fixYn' , align:'center', width:60, formatter: formatFixYn },
|
||||||
{ name : 'useYn' , align:'center', width:60, formatter: formatuseYn },
|
{ name : 'useYn' , align:'center', width:60, formatter: formatuseYn },
|
||||||
{ name : 'state' , align:'center', width:90, sortable:false, formatter: formatIncidentState },
|
|
||||||
{ name : 'lastModifiedDate', align:'center', width:120 , formatter: timeStampFormat},
|
{ name : 'lastModifiedDate', align:'center', width:120 , formatter: timeStampFormat},
|
||||||
{ name : 'createdDate' , align:'center', width:120, formatter: timeStampFormat },
|
{ name : 'createdDate' , align:'center', width:120, formatter: timeStampFormat },
|
||||||
{ name : 'inquirerName' , align:'center', width:100 },
|
{ name : 'inquirerName' , align:'center', width:100 },
|
||||||
@@ -166,8 +103,6 @@
|
|||||||
autowidth: true,
|
autowidth: true,
|
||||||
viewrecords: true,
|
viewrecords: true,
|
||||||
rowList : eval('[${rmsDefaultRowList}]'),
|
rowList : eval('[${rmsDefaultRowList}]'),
|
||||||
multiselect: true,
|
|
||||||
multiboxonly: true,
|
|
||||||
ondblClickRow: function(rowId) {
|
ondblClickRow: function(rowId) {
|
||||||
var rowData = $(this).getRowData(rowId);
|
var rowData = $(this).getRowData(rowId);
|
||||||
var id = rowData['id'];
|
var id = rowData['id'];
|
||||||
@@ -204,14 +139,10 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
resizeJqGridWidth('grid','content_middle','1000');
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
|
|
||||||
// 콤보 로드 → 콤보 성공 콜백에서 buildGrid() 호출 (경합 방지)
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
resizeJqGridWidth('grid','content_middle','1000');
|
||||||
|
|
||||||
$("#btn_search").click(function(){
|
$("#btn_search").click(function(){
|
||||||
var postData = getSearchForJqgrid("cmd","LIST");
|
var postData = getSearchForJqgrid("cmd","LIST");
|
||||||
$("#grid").setGridParam({ url:url,postData: postData ,page:1 }).trigger("reloadGrid");
|
$("#grid").setGridParam({ url:url,postData: postData ,page:1 }).trigger("reloadGrid");
|
||||||
@@ -226,10 +157,6 @@
|
|||||||
goNav(url2);
|
goNav(url2);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_delete_selected").click(function(){
|
|
||||||
deleteSelectedRows();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("select[name=searchUseYn], input[name^=search]").keydown(function(key){
|
$("select[name=searchUseYn], input[name^=search]").keydown(function(key){
|
||||||
if (key.keyCode == 13){
|
if (key.keyCode == 13){
|
||||||
$("#btn_search").click();
|
$("#btn_search").click();
|
||||||
@@ -252,7 +179,6 @@
|
|||||||
<div class="search_wrap">
|
<div class="search_wrap">
|
||||||
<button type="button" class="cssbtn" id="btn_new" level="W"><i class="material-icons">add</i> <%= localeMessage.getString("button.new") %></button>
|
<button type="button" class="cssbtn" id="btn_new" level="W"><i class="material-icons">add</i> <%= localeMessage.getString("button.new") %></button>
|
||||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
||||||
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i class="material-icons">delete_forever</i> 선택 삭제</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="title">공지사항 목록<span class="tooltip">공지사항을 관리합니다.</span></div>
|
<div class="title">공지사항 목록<span class="tooltip">공지사항을 관리합니다.</span></div>
|
||||||
<form id="ajaxForm" onsubmit="return false;">
|
<form id="ajaxForm" onsubmit="return false;">
|
||||||
|
|||||||
@@ -32,35 +32,10 @@
|
|||||||
// 영향 API 목록 (UI 상태)
|
// 영향 API 목록 (UI 상태)
|
||||||
var affectedApis = [];
|
var affectedApis = [];
|
||||||
|
|
||||||
// 장애 타임라인 (UI 상태)
|
|
||||||
var currentIncidentId = null;
|
|
||||||
var currentIncidentState = null;
|
|
||||||
|
|
||||||
// 종결 상태 — 재전이 불가 (재발은 새 장애로 등록)
|
|
||||||
var TERMINAL_STATES = ['RESOLVED', 'CANCELED'];
|
|
||||||
|
|
||||||
// IncidentState 라벨 — 상태 콤보 문구와 동일하게 유지
|
|
||||||
var STATE_LABELS = {
|
|
||||||
'INVESTIGATING': '조사중',
|
|
||||||
'IDENTIFIED': '원인 파악',
|
|
||||||
'MONITORING': '모니터링',
|
|
||||||
'RESOLVED': '해소',
|
|
||||||
'CANCELED': '취소'
|
|
||||||
};
|
|
||||||
|
|
||||||
function isIncidentType(t) {
|
function isIncidentType(t) {
|
||||||
return t === NOTICE_TYPE_INCIDENT || t === NOTICE_TYPE_MAINTENANCE;
|
return t === NOTICE_TYPE_INCIDENT || t === NOTICE_TYPE_MAINTENANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stateLabel(code) {
|
|
||||||
if (!code) return '';
|
|
||||||
return (STATE_LABELS[code] || code) + ' (' + code + ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
function escapeHtml(text) {
|
|
||||||
return $('<div>').text(text == null ? '' : text).html();
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
var key = "${param.id}";
|
var key = "${param.id}";
|
||||||
isDetail = key != "" && key != "null";
|
isDetail = key != "" && key != "null";
|
||||||
@@ -101,28 +76,12 @@
|
|||||||
// INCIDENT 만 상태 영역 표시
|
// INCIDENT 만 상태 영역 표시
|
||||||
if (t === NOTICE_TYPE_INCIDENT) {
|
if (t === NOTICE_TYPE_INCIDENT) {
|
||||||
$('.incident-state-row').show();
|
$('.incident-state-row').show();
|
||||||
$('.incident-endat-hint').show();
|
|
||||||
} else {
|
} else {
|
||||||
$('.incident-state-row').hide();
|
$('.incident-state-row').hide();
|
||||||
$('.incident-endat-hint').hide();
|
|
||||||
}
|
}
|
||||||
// 장애는 종결(해소·취소) 후에만 종료 시각을 손볼 수 있다. 진행 중에는 상태를 따른다.
|
|
||||||
var closed = $.inArray(currentIncidentState, TERMINAL_STATES) >= 0;
|
|
||||||
$('#endAt').prop('readonly', t === NOTICE_TYPE_INCIDENT && !closed);
|
|
||||||
$('.incident-endat-hint').text(closed
|
|
||||||
? '※ 종결된 장애입니다. 실제 복구 시각으로 수정할 수 있습니다.'
|
|
||||||
: '※ 타임라인에서 해소·취소로 전이하면 자동 입력됩니다.');
|
|
||||||
} else {
|
} else {
|
||||||
$('.incident-row').hide();
|
$('.incident-row').hide();
|
||||||
$('.incident-state-row').hide();
|
$('.incident-state-row').hide();
|
||||||
$('.incident-endat-hint').hide();
|
|
||||||
$('#endAt').prop('readonly', false);
|
|
||||||
}
|
|
||||||
// 타임라인은 등록된 장애(수정 모드)에서만 다룬다
|
|
||||||
if (t === NOTICE_TYPE_INCIDENT && isDetail && currentIncidentId) {
|
|
||||||
$('#timelineSection').show();
|
|
||||||
} else {
|
|
||||||
$('#timelineSection').hide();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,150 +192,6 @@
|
|||||||
renderAffectedApis();
|
renderAffectedApis();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ───────────────────── 장애 처리 타임라인 ─────────────────────
|
|
||||||
|
|
||||||
/** 현재 상태 기준으로 전이 가능한 선택지만 남긴다. 실제 차단은 서버가 한다. */
|
|
||||||
function applyStateChangeGuard() {
|
|
||||||
var terminal = $.inArray(currentIncidentState, TERMINAL_STATES) >= 0;
|
|
||||||
|
|
||||||
$('#timelineStateChange').prop('disabled', terminal);
|
|
||||||
if (terminal) {
|
|
||||||
$('#timelineStateChange').prop('checked', false);
|
|
||||||
$('#timelineNextState').prop('disabled', true).val('');
|
|
||||||
}
|
|
||||||
$('#timelineClosedHint').toggle(terminal);
|
|
||||||
$('#timelineResolveHint').toggle(!terminal);
|
|
||||||
|
|
||||||
// 현재와 동일한 상태로는 전이할 수 없다
|
|
||||||
$('#timelineNextState option').each(function() {
|
|
||||||
var v = $(this).val();
|
|
||||||
$(this).prop('disabled', v !== '' && v === currentIncidentState);
|
|
||||||
});
|
|
||||||
if ($('#timelineNextState').val() === currentIncidentState) {
|
|
||||||
$('#timelineNextState').val('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadTimeline() {
|
|
||||||
if (!currentIncidentId) {
|
|
||||||
renderTimeline([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url, dataType: "json",
|
|
||||||
data: {cmd: 'TIMELINE_LIST', incidentId: currentIncidentId},
|
|
||||||
success: function (rows) { renderTimeline(rows || []); },
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTimeline(rows) {
|
|
||||||
var $tb = $('#timelineTbody');
|
|
||||||
$tb.empty();
|
|
||||||
if (!rows.length) {
|
|
||||||
$tb.append('<tr><td colspan="6" style="text-align:center;color:#999;">등록된 타임라인이 없습니다.</td></tr>');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.each(rows, function(_, row) {
|
|
||||||
var author = row.authorType === 'SYSTEM' ? 'System' : 'Admin';
|
|
||||||
var visible = row.visibleYn === 'Y';
|
|
||||||
var $tr = $('<tr>');
|
|
||||||
$tr.append('<td style="text-align:center;white-space:nowrap;">' + escapeHtml(row.eventAt) + '</td>');
|
|
||||||
$tr.append('<td style="text-align:center;">' + author + '</td>');
|
|
||||||
$tr.append('<td style="text-align:center;white-space:nowrap;">' + (row.stateAfter ? escapeHtml(stateLabel(row.stateAfter)) : '-') + '</td>');
|
|
||||||
$tr.append('<td>' + escapeHtml(row.body).replace(/\n/g, '<br>') + '</td>');
|
|
||||||
|
|
||||||
// 현재 상태(라벨) + 눌렀을 때 바뀔 상태(버튼) 를 나눠 표기 — 버튼 하나면 의미가 모호하다
|
|
||||||
var $visibleTd = $('<td style="text-align:center;white-space:nowrap;">');
|
|
||||||
$('<span>')
|
|
||||||
.text(visible ? '공개중' : '비공개')
|
|
||||||
.css({color: visible ? '#1B8C4A' : '#999', 'margin-right': '5px'})
|
|
||||||
.appendTo($visibleTd);
|
|
||||||
$('<button type="button" class="cssbtn" level="W" status="DETAIL" style="min-width:0;padding:3px 8px;">')
|
|
||||||
.text(visible ? '비공개로' : '공개로')
|
|
||||||
.click(function() { toggleTimelineVisible(row.timelineId, visible ? 'N' : 'Y'); })
|
|
||||||
.appendTo($visibleTd);
|
|
||||||
$tr.append($visibleTd);
|
|
||||||
|
|
||||||
var $deleteTd = $('<td style="text-align:center;">');
|
|
||||||
$('<button type="button" class="cssbtn smallBtn" level="W" status="DETAIL" style="min-width:0;width:90%;">')
|
|
||||||
.text('삭제')
|
|
||||||
.click(function() { deleteTimeline(row.timelineId); })
|
|
||||||
.appendTo($deleteTd);
|
|
||||||
$tr.append($deleteTd);
|
|
||||||
|
|
||||||
$tb.append($tr);
|
|
||||||
});
|
|
||||||
buttonControl(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addTimeline() {
|
|
||||||
if (!currentIncidentId) {
|
|
||||||
alert('장애 정보를 먼저 저장하여 주십시오.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var body = $('#timelineBody').val();
|
|
||||||
if (!body || !$.trim(body)) {
|
|
||||||
alert('타임라인 메세지를 입력하여 주십시오.');
|
|
||||||
$('#timelineBody').focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var stateChange = $('#timelineStateChange').is(':checked');
|
|
||||||
var nextState = $('#timelineNextState').val();
|
|
||||||
if (stateChange && !nextState) {
|
|
||||||
alert('변경할 상태를 선택하여 주십시오.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url, dataType: "json",
|
|
||||||
data: {cmd: 'TIMELINE_ADD', incidentId: currentIncidentId, body: body,
|
|
||||||
stateChange: stateChange, nextState: nextState},
|
|
||||||
success: function (data) {
|
|
||||||
$('#timelineBody').val('');
|
|
||||||
$('#timelineStateChange').prop('checked', false).trigger('change');
|
|
||||||
// 상태 전이 시 서버가 상태/이전 상태/종료 시각을 함께 갱신한다
|
|
||||||
$('#stateText').text(data.state ? stateLabel(data.state) : '');
|
|
||||||
$('#previousState').text(data.previousState ? stateLabel(data.previousState) : '없음');
|
|
||||||
$('#endAt').val(data.endAt || '');
|
|
||||||
currentIncidentState = data.state || null;
|
|
||||||
applyStateChangeGuard();
|
|
||||||
// 종결 전이 직후부터 종료 시각을 손볼 수 있어야 한다
|
|
||||||
toggleIncidentFields();
|
|
||||||
loadTimeline();
|
|
||||||
},
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleTimelineVisible(timelineId, visibleYn) {
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url,
|
|
||||||
data: {cmd: 'TIMELINE_VISIBLE', timelineId: timelineId, visibleYn: visibleYn},
|
|
||||||
success: loadTimeline,
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteTimeline(timelineId) {
|
|
||||||
if (confirm("<%= localeMessage.getString("common.checkDelete")%>") != true) return;
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url,
|
|
||||||
data: {cmd: 'TIMELINE_DELETE', timelineId: timelineId},
|
|
||||||
success: loadTimeline,
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 장애/점검 공지는 최초 게시 후 게시유형을 바꿀 수 없다. */
|
|
||||||
function lockNoticeType(noticeType) {
|
|
||||||
if (!isIncidentType(noticeType)) return;
|
|
||||||
$('#noticeType').prop('disabled', true);
|
|
||||||
if (!$('#noticeTypeHidden').length) {
|
|
||||||
$('#ajaxForm').append('<input type="hidden" id="noticeTypeHidden" name="noticeType">');
|
|
||||||
}
|
|
||||||
$('#noticeTypeHidden').val(noticeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
function detail(key) {
|
function detail(key) {
|
||||||
if (!isDetail) return;
|
if (!isDetail) return;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -392,28 +207,17 @@
|
|||||||
var decodedContent = decodeHTMLEntities(data.noticeDetail);
|
var decodedContent = decodeHTMLEntities(data.noticeDetail);
|
||||||
$('#contents').summernote('code', decodedContent);
|
$('#contents').summernote('code', decodedContent);
|
||||||
|
|
||||||
// 게시유형은 최초 저장 후 변경 불가 (disabled 는 전송되지 않아 hidden 으로 값을 유지)
|
|
||||||
lockNoticeType(data.noticeType);
|
|
||||||
|
|
||||||
// 장애/점검 필드
|
// 장애/점검 필드
|
||||||
$('#summary').val(data.summary || '');
|
$('#summary').val(data.summary || '');
|
||||||
$('#startedAt').val(data.startedAt || '');
|
$('#startedAt').val(data.startedAt || '');
|
||||||
$('#endAt').val(data.endAt || '');
|
$('#endAt').val(data.endAt || '');
|
||||||
// 상태/이전 상태는 타임라인 게시로만 바뀐다 (직접 수정 불가)
|
$('#state').val(data.state || 'INVESTIGATING');
|
||||||
$('#stateText').text(data.state ? stateLabel(data.state) : '');
|
$('#previousState').text(data.previousState || '없음');
|
||||||
$('#previousState').text(data.previousState ? stateLabel(data.previousState) : '없음');
|
|
||||||
affectedApis = (data.affectedApis || []).map(function(a){
|
affectedApis = (data.affectedApis || []).map(function(a){
|
||||||
return {apiId: a.apiId, apiName: a.apiName || ''};
|
return {apiId: a.apiId, apiName: a.apiName || ''};
|
||||||
});
|
});
|
||||||
renderAffectedApis();
|
renderAffectedApis();
|
||||||
|
|
||||||
currentIncidentId = data.incidentId || null;
|
|
||||||
currentIncidentState = data.state || null;
|
|
||||||
applyStateChangeGuard();
|
|
||||||
toggleIncidentFields();
|
toggleIncidentFields();
|
||||||
if (data.noticeType === NOTICE_TYPE_INCIDENT && currentIncidentId) {
|
|
||||||
loadTimeline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.fileInfo) {
|
if (data.fileInfo) {
|
||||||
fileInfo = {
|
fileInfo = {
|
||||||
@@ -441,13 +245,6 @@
|
|||||||
$('#btn_addAffectedApi').click(openApiPopup);
|
$('#btn_addAffectedApi').click(openApiPopup);
|
||||||
$('#btn_removeAffectedApi').click(removeSelectedAffectedApis);
|
$('#btn_removeAffectedApi').click(removeSelectedAffectedApis);
|
||||||
|
|
||||||
$('#timelineStateChange').on('change', function() {
|
|
||||||
var checked = $(this).is(':checked');
|
|
||||||
$('#timelineNextState').prop('disabled', !checked);
|
|
||||||
if (!checked) $('#timelineNextState').val('');
|
|
||||||
});
|
|
||||||
$('#btn_addTimeline').click(addTimeline);
|
|
||||||
|
|
||||||
$('#fileInput').change(function(e) {
|
$('#fileInput').change(function(e) {
|
||||||
var file = e.target.files[0];
|
var file = e.target.files[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
@@ -476,11 +273,6 @@
|
|||||||
alert('점검 종료 시각을 입력해 주십시오.');
|
alert('점검 종료 시각을 입력해 주십시오.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// datetime-local 값은 'YYYY-MM-DDTHH:mm' 이라 문자열 비교로 선후가 가려진다
|
|
||||||
if ($('#endAt').val() && $('#endAt').val() < $('#startedAt').val()) {
|
|
||||||
alert('종료 시각은 시작 시각보다 빠를 수 없습니다.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (affectedApis.length === 0) {
|
if (affectedApis.length === 0) {
|
||||||
alert('영향 API를 1건 이상 선택해 주십시오.');
|
alert('영향 API를 1건 이상 선택해 주십시오.');
|
||||||
return;
|
return;
|
||||||
@@ -602,15 +394,21 @@
|
|||||||
<th>종료</th>
|
<th>종료</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="datetime-local" id="endAt" name="endAt" style="width:90%" placeholder="해소시 자동 채움">
|
<input type="datetime-local" id="endAt" name="endAt" style="width:90%" placeholder="해소시 자동 채움">
|
||||||
<div class="incident-endat-hint" style="display:none;color:#888;font-size:12px;margin-top:3px;">
|
|
||||||
※ 타임라인에서 해소·취소로 전이하면 자동 입력됩니다.
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- 상태/이전 상태는 타임라인 게시로만 전이한다 (직접 수정 불가) -->
|
|
||||||
<tr class="incident-row incident-state-row" style="display:none;">
|
<tr class="incident-row incident-state-row" style="display:none;">
|
||||||
<th>상태</th>
|
<th>상태</th>
|
||||||
<td><span id="stateText"></span></td>
|
<td>
|
||||||
|
<div class="select-style">
|
||||||
|
<select id="state" name="state">
|
||||||
|
<option value="INVESTIGATING">INVESTIGATING - 조사중</option>
|
||||||
|
<option value="IDENTIFIED">IDENTIFIED - 원인 파악</option>
|
||||||
|
<option value="MONITORING">MONITORING - 모니터링</option>
|
||||||
|
<option value="RESOLVED">RESOLVED - 해소</option>
|
||||||
|
<option value="CANCELED">CANCELED - 취소</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<th>이전 상태</th>
|
<th>이전 상태</th>
|
||||||
<td><span id="previousState">없음</span></td>
|
<td><span id="previousState">없음</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -637,61 +435,6 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- 타임라인은 [수정] 저장과 별개로 게시 즉시 반영되므로 폼 밖에 둔다 -->
|
|
||||||
<div id="timelineSection" style="display:none;margin-top:20px;">
|
|
||||||
<div class="title">타임라인</div>
|
|
||||||
<table class="table_row" cellspacing="0" style="width:100%;">
|
|
||||||
<colgroup>
|
|
||||||
<col style="width: 130px"/>
|
|
||||||
<col style="width: 80px"/>
|
|
||||||
<col style="width: 140px"/>
|
|
||||||
<col/>
|
|
||||||
<col style="width: 160px"/>
|
|
||||||
<col style="width: 80px"/>
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>시간</th>
|
|
||||||
<th>작성자</th>
|
|
||||||
<th>상태</th>
|
|
||||||
<th>메세지</th>
|
|
||||||
<th>개발자포탈 공개</th>
|
|
||||||
<th>삭제</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="timelineTbody">
|
|
||||||
<tr><td colspan="6" style="text-align:center;color:#999;">등록된 타임라인이 없습니다.</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div style="margin-top:8px;display:flex;align-items:center;gap:8px;">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="timelineStateChange"> 상태 변경
|
|
||||||
</label>
|
|
||||||
<div class="select-style" style="width:220px;">
|
|
||||||
<select id="timelineNextState" disabled>
|
|
||||||
<option value="">(현재 상태 유지)</option>
|
|
||||||
<option value="INVESTIGATING">INVESTIGATING - 조사중</option>
|
|
||||||
<option value="IDENTIFIED">IDENTIFIED - 원인 파악</option>
|
|
||||||
<option value="MONITORING">MONITORING - 모니터링</option>
|
|
||||||
<option value="RESOLVED">RESOLVED - 해소</option>
|
|
||||||
<option value="CANCELED">CANCELED - 취소</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<span id="timelineResolveHint" style="color:#888;font-size:12px;">※ 해소(RESOLVED)·취소(CANCELED)로 전이하면 종료 시각이 자동 입력됩니다.</span>
|
|
||||||
<span id="timelineClosedHint" style="display:none;color:#C0392B;font-size:12px;">
|
|
||||||
※ 종결된 장애입니다. 상태 변경 불가 — 재발 시 새 장애로 등록하십시오.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div style="margin-top:5px;display:flex;gap:5px;">
|
|
||||||
<textarea id="timelineBody" style="flex:1;height:60px;"
|
|
||||||
placeholder="타임라인 메세지 입력 예 : 모니터링 5분간 정상 응답 확인 후 완료 상태 전이 예정"></textarea>
|
|
||||||
<button type="button" class="cssbtn" id="btn_addTimeline" level="W" status="DETAIL">
|
|
||||||
<i class="material-icons">send</i> 게시
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -312,9 +312,7 @@ $(document).ready(function() {
|
|||||||
<div class="content_middle" id="content_middle">
|
<div class="content_middle" id="content_middle">
|
||||||
<div class="search_wrap">
|
<div class="search_wrap">
|
||||||
<button type="button" class="cssbtn" id="btn_new" level="W"><i class="material-icons">add</i> <%= localeMessage.getString("button.new") %></button>
|
<button type="button" class="cssbtn" id="btn_new" level="W"><i class="material-icons">add</i> <%= localeMessage.getString("button.new") %></button>
|
||||||
<c:if test="${hardDeleteEnabled}">
|
|
||||||
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i class="material-icons">delete_forever</i> 선택 삭제</button>
|
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i class="material-icons">delete_forever</i> 선택 삭제</button>
|
||||||
</c:if>
|
|
||||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
||||||
</div>
|
</div>
|
||||||
<%--법인정보관리--%>
|
<%--법인정보관리--%>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||||
<%@ page import="java.io.*"%>
|
<%@ page import="java.io.*"%>
|
||||||
<%@ page import="com.eactive.eai.rms.common.util.CommonUtil"%>
|
|
||||||
<%@ page import="com.eactive.eai.rms.common.context.MonitoringContext"%>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
|
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||||
@@ -9,9 +7,6 @@
|
|||||||
response.setHeader("Pragma", "No-cache");
|
response.setHeader("Pragma", "No-cache");
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
response.setHeader("Cache-Control", "no-cache");
|
||||||
response.setHeader("Expires", "0");
|
response.setHeader("Expires", "0");
|
||||||
|
|
||||||
MonitoringContext monitoringContext = (MonitoringContext)CommonUtil.getBean(request, "monitoringContext");
|
|
||||||
String reverseProxyUrl = monitoringContext.getStringProperty(MonitoringContext.RMS_WEBHOOK_REVERSE_PROXY_URL, "");
|
|
||||||
%>
|
%>
|
||||||
<%!
|
<%!
|
||||||
public String getRequiredLabel(String label) {
|
public String getRequiredLabel(String label) {
|
||||||
@@ -138,15 +133,10 @@
|
|||||||
$("#btn_delete").hide();
|
$("#btn_delete").hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
$("select[name=approvalStatus]").val(portalOrgData.approvalStatus);
|
$("#approvalStatus").val(portalOrgData.approvalStatus);
|
||||||
// 승인상태는 읽기전용(수정 불가) - 값은 그대로 제출되도록 disabled 대신 잠금 처리
|
|
||||||
$("select[name=approvalStatus]")
|
|
||||||
.css({'pointer-events':'none', 'background-color':'#eee'})
|
|
||||||
.attr('tabindex', '-1');
|
|
||||||
$("#compRegNo").val(formatCompanyRegNo(portalOrgData.compRegNo));
|
$("#compRegNo").val(formatCompanyRegNo(portalOrgData.compRegNo));
|
||||||
$("#corpRegNo").val(formatCorpRegNo(portalOrgData.corpRegNo));
|
$("#corpRegNo").val(formatCorpRegNo(portalOrgData.corpRegNo));
|
||||||
$("#createdDate").inputmask("9999-99-99 99:99:99", {'autoUnmask': true});
|
$("#createdDate").inputmask("9999-99-99 99:99:99", {'autoUnmask': true});
|
||||||
$("#reverseProxyPath").val(portalOrgData.reverseProxyPath);
|
|
||||||
|
|
||||||
// 전화번호 처리
|
// 전화번호 처리
|
||||||
if (portalOrgData.scPhoneNumber) {
|
if (portalOrgData.scPhoneNumber) {
|
||||||
@@ -414,6 +404,47 @@
|
|||||||
downloadFile(fileId, '1'); // fileSn은 '1'로 가정
|
downloadFile(fileId, '1'); // fileSn은 '1'로 가정
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// OBP 파트너코드 조회 버튼 클릭
|
||||||
|
$("#btn_query_obp").click(function() {
|
||||||
|
var compRegNo = $("#compRegNo").val();
|
||||||
|
if (!compRegNo) {
|
||||||
|
jSuites.notification({ name: '알림', message: '사업자등록번호를 먼저 입력해주세요.', error: true });
|
||||||
|
$("#compRegNo").focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 하이픈 제거
|
||||||
|
compRegNo = compRegNo.replace(/-/g, '');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
cmd: 'QUERY_OBP_PARTNER_CODE',
|
||||||
|
compRegNo: compRegNo
|
||||||
|
},
|
||||||
|
beforeSend: function() {
|
||||||
|
$("#btn_query_obp").prop("disabled", true).html('<i class="material-icons">hourglass_empty</i> 조회중...');
|
||||||
|
},
|
||||||
|
success: function(json) {
|
||||||
|
if (json.success) {
|
||||||
|
$("#orgCode").val(json.partnerCode);
|
||||||
|
jSuites.notification({ name: '성공', message: '파트너코드가 조회되었습니다: ' + json.partnerCode });
|
||||||
|
} else {
|
||||||
|
jSuites.notification({ name: '실패', message: json.message, error: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(e) {
|
||||||
|
jSuites.notification({ name: '오류', message: '파트너코드 조회 중 오류가 발생했습니다.', error: true });
|
||||||
|
console.error(e.responseText);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$("#btn_query_obp").prop("disabled", false).html('<i class="material-icons">search</i> 파트너코드 조회');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$("#btn_modify").click(function(){
|
$("#btn_modify").click(function(){
|
||||||
if (!checkRequired("ajaxForm")) return;
|
if (!checkRequired("ajaxForm")) return;
|
||||||
|
|
||||||
@@ -484,7 +515,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 저장 확인/사유 입력은 유효성 검사 및 FormData 구성 후 처리 (하단 submit 분기)
|
if (confirm("<%= localeMessage.getString("common.checkSave")%>") !== true)
|
||||||
|
return;
|
||||||
|
|
||||||
// FormData 생성 전에 분리된 전화번호 필드 제거
|
// FormData 생성 전에 분리된 전화번호 필드 제거
|
||||||
$("#scPhonePrefix, #scPhoneMiddle, #scPhoneLast, #orgPhonePrefix, #orgPhoneMiddle, #orgPhoneLast").removeAttr('name');
|
$("#scPhonePrefix, #scPhoneMiddle, #scPhoneLast, #orgPhonePrefix, #orgPhoneMiddle, #orgPhoneLast").removeAttr('name');
|
||||||
@@ -519,47 +551,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// cmd 및 사유(auditReason) 첨부 후 전송
|
// cmd 파라미터 추가
|
||||||
function submitOrg(cmd, auditReason) {
|
formData.append("cmd", isDetail ? "UPDATE" : "INSERT");
|
||||||
formData.append("cmd", cmd);
|
|
||||||
// 감사로그(AUDIT_LOG) 발화를 위한 systemCode. 법인/가입자 리포지토리는 고정 EMS 스키마라 스키마 전환 영향 없음
|
$.ajax({
|
||||||
formData.append("serviceType", "APIGW");
|
type : "POST",
|
||||||
if (auditReason) {
|
url:url,
|
||||||
formData.append("auditReason", auditReason);
|
data: formData,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
success:function(json){
|
||||||
|
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||||
|
goNav(returnUrl);
|
||||||
|
},
|
||||||
|
error:function(e){
|
||||||
|
alert(e.responseText);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
$.ajax({
|
|
||||||
type : "POST",
|
|
||||||
url:url,
|
|
||||||
data: formData,
|
|
||||||
processData: false,
|
|
||||||
contentType: false,
|
|
||||||
success:function(json){
|
|
||||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
|
||||||
goNav(returnUrl);
|
|
||||||
},
|
|
||||||
error:function(e){
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDetail) {
|
|
||||||
// 수정: 상태를 REMOVED로 바꾼 경우 삭제(cmd=DELETE)로 감사 기록 + 익명화
|
|
||||||
var targetCmd = ($("#orgStatus").val() === 'REMOVED') ? "DELETE" : "UPDATE";
|
|
||||||
var isRemove = (targetCmd === "DELETE");
|
|
||||||
showReasonPrompt(
|
|
||||||
isRemove ? "해당 법인을 삭제(탈퇴) 처리합니다. 사유를 입력해 주세요." : "법인 정보를 수정합니다. 사유를 입력해 주세요.",
|
|
||||||
{
|
|
||||||
title: isRemove ? "삭제 사유" : "수정 사유",
|
|
||||||
onConfirm: function(reason) { submitOrg(targetCmd, reason); }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// 신규 등록: 사유 불필요
|
|
||||||
if (confirm("<%= localeMessage.getString("common.checkSave")%>") !== true) return;
|
|
||||||
submitOrg("INSERT", null);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_previous").click(function() {
|
$("#btn_previous").click(function() {
|
||||||
@@ -568,28 +576,25 @@
|
|||||||
|
|
||||||
$("#btn_delete").click(function(){
|
$("#btn_delete").click(function(){
|
||||||
|
|
||||||
showReasonPrompt("해당 법인을 삭제 처리합니다. 사유를 입력해 주세요.", {
|
if(confirm("<%= localeMessage.getString("common.confirmMsg")%>")){
|
||||||
title: "삭제 사유",
|
var postData = $('#ajaxForm').serializeArray();
|
||||||
onConfirm: function(reason) {
|
postData.push({name: "cmd" , value:"DELETE"});
|
||||||
var postData = $('#ajaxForm').serializeArray();
|
|
||||||
postData.push({name: "cmd" , value:"DELETE"});
|
|
||||||
postData.push({name: "serviceType", value: "APIGW"});
|
|
||||||
postData.push({name: "auditReason", value: reason});
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : "POST",
|
type : "POST",
|
||||||
url:url,
|
url:url,
|
||||||
data:postData,
|
data:postData,
|
||||||
success:function(args){
|
success:function(args){
|
||||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||||
goNav(returnUrl);
|
goNav(returnUrl);
|
||||||
},
|
},
|
||||||
error:function(e){
|
error:function(e){
|
||||||
alert(e.responseText);
|
alert(e.responseText);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}else{
|
||||||
});
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -625,7 +630,10 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th style="width:15%;"><%= localeMessage.getString("portalOrg.orgCode") %></th>
|
<th style="width:15%;"><%= localeMessage.getString("portalOrg.orgCode") %></th>
|
||||||
<td colspan="3" style="width:35%;">
|
<td colspan="3" style="width:35%;">
|
||||||
<input type="text" name="orgCode" id="orgCode"/>
|
<div style="display: flex; align-items: center;">
|
||||||
|
<input type="text" name="orgCode" id="orgCode" style="width: 200px; margin-right: 10px;"/>
|
||||||
|
<button type="button" class="cssbtn smallBtn" id="btn_query_obp"><i class="material-icons">search</i> 파트너코드 조회</button>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<th><%= localeMessage.getString("portalOrg.orgIndustryType") %></th> <%--업종--%>
|
<th><%= localeMessage.getString("portalOrg.orgIndustryType") %></th> <%--업종--%>
|
||||||
<td><input type="text" name="orgIndustryType" id="orgIndustryType" maxlength="50" /></td>
|
<td><input type="text" name="orgIndustryType" id="orgIndustryType" maxlength="50" /></td>
|
||||||
@@ -730,16 +738,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th><%= localeMessage.getString("portalOrg.reverseProxyPath") %></th>
|
|
||||||
<td colspan="3">
|
|
||||||
<%=reverseProxyUrl %>/<input type="text" name="reverseProxyPath" id="reverseProxyPath" style="width:100px; "/>
|
|
||||||
</td>
|
|
||||||
<th></th>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr><%--사업자등록증--%>
|
<tr><%--사업자등록증--%>
|
||||||
<th><%= localeMessage.getString("portalOrg.compRegFile") %></th>
|
<th><%= localeMessage.getString("portalOrg.compRegFile") %></th>
|
||||||
<td colspan="5" style="padding-top: 5px; padding-bottom: 5px;">
|
<td colspan="5" style="padding-top: 5px; padding-bottom: 5px;">
|
||||||
|
|||||||
@@ -26,38 +26,7 @@ function formatFile(cellvalue, options, rowObject) {
|
|||||||
return cellvalue + icon;
|
return cellvalue + icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteSelectedRows() {
|
$(document).ready(function() {
|
||||||
var selectedIds = $("#grid").jqGrid('getGridParam', 'selarrrow');
|
|
||||||
|
|
||||||
if (selectedIds.length === 0) {
|
|
||||||
alert('항목을 선택하세요.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!confirm('선택된 ' + selectedIds.length + '개 항목을 삭제하시겠습니까?')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
dataType: "json",
|
|
||||||
data: {
|
|
||||||
cmd: 'DELETE_BULK',
|
|
||||||
ids: selectedIds.join(',')
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
alert('삭제되었습니다.');
|
|
||||||
$("#grid").jqGrid('clearGridData', true);
|
|
||||||
$("#grid").trigger("reloadGrid");
|
|
||||||
},
|
|
||||||
error: function(e) {
|
|
||||||
alert('삭제 중 오류가 발생했습니다.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
$('#grid').jqGrid({
|
$('#grid').jqGrid({
|
||||||
datatype:"json",
|
datatype:"json",
|
||||||
mtype: 'POST',
|
mtype: 'POST',
|
||||||
@@ -76,7 +45,7 @@ $(document).ready(function() {
|
|||||||
],
|
],
|
||||||
jsonReader: {
|
jsonReader: {
|
||||||
repeatitems:false
|
repeatitems:false
|
||||||
},
|
},
|
||||||
pager : $('#pager'),
|
pager : $('#pager'),
|
||||||
page : '${param.page}',
|
page : '${param.page}',
|
||||||
rowNum : '${rmsDefaultRowNum}',
|
rowNum : '${rmsDefaultRowNum}',
|
||||||
@@ -85,8 +54,6 @@ $(document).ready(function() {
|
|||||||
autowidth: true,
|
autowidth: true,
|
||||||
viewrecords: true,
|
viewrecords: true,
|
||||||
rowList : eval('[${rmsDefaultRowList}]'),
|
rowList : eval('[${rmsDefaultRowList}]'),
|
||||||
multiselect: true,
|
|
||||||
multiboxonly: true,
|
|
||||||
ondblClickRow: function(rowId) {
|
ondblClickRow: function(rowId) {
|
||||||
var rowData = $(this).getRowData(rowId);
|
var rowData = $(this).getRowData(rowId);
|
||||||
var id = rowData['id'];
|
var id = rowData['id'];
|
||||||
@@ -127,14 +94,10 @@ $(document).ready(function() {
|
|||||||
resizeJqGridWidth('grid','content_middle','1000');
|
resizeJqGridWidth('grid','content_middle','1000');
|
||||||
|
|
||||||
$("#btn_search").click(function(){
|
$("#btn_search").click(function(){
|
||||||
var postData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
var postData = getSearchForJqgrid("cmd","LIST"); //jqgrid에서는 object 로
|
||||||
$("#grid").setGridParam({ url:url,postData: postData ,page:1 }).trigger("reloadGrid");
|
$("#grid").setGridParam({ url:url,postData: postData ,page:1 }).trigger("reloadGrid");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_delete_selected").click(function(){
|
|
||||||
deleteSelectedRows();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("input[name^=search]").keydown(function(key){
|
$("input[name^=search]").keydown(function(key){
|
||||||
if (key.keyCode == 13){
|
if (key.keyCode == 13){
|
||||||
$("#btn_search").click();
|
$("#btn_search").click();
|
||||||
@@ -157,9 +120,8 @@ $(document).ready(function() {
|
|||||||
<div class="content_middle" id="content_middle">
|
<div class="content_middle" id="content_middle">
|
||||||
<div class="search_wrap">
|
<div class="search_wrap">
|
||||||
<button type="button" class="cssbtn" id="btn_search" level="R" ><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
<button type="button" class="cssbtn" id="btn_search" level="R" ><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
||||||
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i class="material-icons">delete_forever</i> 선택 삭제</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="title">피드백/개선요청 신청 목록</div>
|
<div class="title">사업제휴 신청 목록</div>
|
||||||
<form id="ajaxForm" onsubmit="return false;">
|
<form id="ajaxForm" onsubmit="return false;">
|
||||||
<table class="search_condition" cellspacing=0;>
|
<table class="search_condition" cellspacing=0;>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -92,27 +92,6 @@ $(document).ready(function() {
|
|||||||
goNav(returnUrl);//LIST로 이동
|
goNav(returnUrl);//LIST로 이동
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_delete").click(function(){
|
|
||||||
if (!confirm('선택한 항목을 삭제하시겠습니까?')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
dataType: "json",
|
|
||||||
data: { cmd: 'DELETE', id: key },
|
|
||||||
success: function(data) {
|
|
||||||
alert('삭제되었습니다.');
|
|
||||||
var returnUrl = getReturnUrlForReturn();
|
|
||||||
goNav(returnUrl);//LIST로 이동
|
|
||||||
},
|
|
||||||
error: function(e) {
|
|
||||||
alert('삭제 중 오류가 발생했습니다.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btn_unmask").click(function () {
|
$("#btn_unmask").click(function () {
|
||||||
const reason = prompt("마스킹 해제 사유를 입력하세요:");
|
const reason = prompt("마스킹 해제 사유를 입력하세요:");
|
||||||
|
|
||||||
@@ -155,10 +134,9 @@ $(document).ready(function() {
|
|||||||
<div class="content_middle">
|
<div class="content_middle">
|
||||||
<div class="search_wrap">
|
<div class="search_wrap">
|
||||||
<button type="button" class="cssbtn" id="btn_unmask" level="W" status="DETAIL"><i class="material-icons">lock_open</i> 마스킹해제</button>
|
<button type="button" class="cssbtn" id="btn_unmask" level="W" status="DETAIL"><i class="material-icons">lock_open</i> 마스킹해제</button>
|
||||||
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i class="material-icons">delete_forever</i> 삭제</button>
|
|
||||||
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="title">피드백/개선요청 신청 상세</div>
|
<div class="title">사업제휴 신청 상세</div>
|
||||||
|
|
||||||
<table id="grid" ></table>
|
<table id="grid" ></table>
|
||||||
<div id="pager"></div>
|
<div id="pager"></div>
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
var url = '<c:url value="/onl/apim/portalproperty/propertyMan.json" />';
|
var url = '<c:url value="/onl/apim/portalproperty/propertyMan.json" />';
|
||||||
var url_view = '<c:url value="/onl/apim/portalproperty/propertyMan.view" />';
|
var url_view = '<c:url value="/onl/apim/portalproperty/propertyMan.view" />';
|
||||||
var lastsel2;
|
var lastsel2;
|
||||||
var clickedCol; //클릭한 셀의 컬럼 인덱스(포커스 이동용)
|
|
||||||
|
|
||||||
function isValid() {
|
function isValid() {
|
||||||
if ($('input[name=prptyGroupName]').val() == "") {
|
if ($('input[name=prptyGroupName]').val() == "") {
|
||||||
@@ -87,11 +86,9 @@
|
|||||||
editurl: "clientArray",
|
editurl: "clientArray",
|
||||||
colNames: ['<%= localeMessage.getString("propertyDetail.propertyKey") %>',
|
colNames: ['<%= localeMessage.getString("propertyDetail.propertyKey") %>',
|
||||||
'<%= localeMessage.getString("propertyDetail.propertyValue") %>',
|
'<%= localeMessage.getString("propertyDetail.propertyValue") %>',
|
||||||
'설명',
|
|
||||||
'<%= localeMessage.getString("propertyDetail.delYn") %>'],
|
'<%= localeMessage.getString("propertyDetail.delYn") %>'],
|
||||||
colModel: [{name: 'PRPTYNAME', width: 50, align: 'left', editable: true},
|
colModel: [{name: 'PRPTYNAME', width: 50, align: 'left', editable: true},
|
||||||
{name: 'PRPTY2VAL', width: 150, align: 'left', editable: true},
|
{name: 'PRPTY2VAL', width: 200, align: 'left', editable: true},
|
||||||
{name: 'PRPTYDESC', width: 200, align: 'left', editable: true, edittype: 'textarea', editoptions: {rows: 2}},
|
|
||||||
{
|
{
|
||||||
name: 'DELETEYN',
|
name: 'DELETEYN',
|
||||||
width: 20,
|
width: 20,
|
||||||
@@ -104,10 +101,6 @@
|
|||||||
},
|
},
|
||||||
loadComplete: function () {
|
loadComplete: function () {
|
||||||
},
|
},
|
||||||
onCellSelect: function (rowid, iCol) {
|
|
||||||
//onSelectRow보다 먼저 발화 → 클릭한 컬럼 인덱스 저장
|
|
||||||
clickedCol = iCol;
|
|
||||||
},
|
|
||||||
onSelectRow: function (rowid, status) {
|
onSelectRow: function (rowid, status) {
|
||||||
if (lastsel2 != undefined) {
|
if (lastsel2 != undefined) {
|
||||||
if ($("#grid tr#" + lastsel2).attr("editable") == 1) { //editable=1 means row in edit mode
|
if ($("#grid tr#" + lastsel2).attr("editable") == 1) { //editable=1 means row in edit mode
|
||||||
@@ -115,8 +108,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$('#grid').restoreRow(lastsel2);
|
$('#grid').restoreRow(lastsel2);
|
||||||
//focusField로 클릭한 셀에 포커스(미지정 시 첫 편집 컬럼으로 감)
|
$('#grid').editRow(rowid, true);
|
||||||
$('#grid').editRow(rowid, {keys: true, focusField: clickedCol});
|
|
||||||
lastsel2 = rowid;
|
lastsel2 = rowid;
|
||||||
},
|
},
|
||||||
onSortCol: function () {
|
onSortCol: function () {
|
||||||
@@ -266,7 +258,6 @@
|
|||||||
var data = new Object();
|
var data = new Object();
|
||||||
data["PRPTYNAME"] = $("input[name=prptyName]").val();
|
data["PRPTYNAME"] = $("input[name=prptyName]").val();
|
||||||
data["PRPTY2VAL"] = $("input[name=prpty2Val]").val();
|
data["PRPTY2VAL"] = $("input[name=prpty2Val]").val();
|
||||||
data["PRPTYDESC"] = $("input[name=prptyDesc]").val();
|
|
||||||
|
|
||||||
var rows = $("#grid")[0].rows;
|
var rows = $("#grid")[0].rows;
|
||||||
var index = Number($(rows[rows.length - 1]).attr("id"));
|
var index = Number($(rows[rows.length - 1]).attr("id"));
|
||||||
@@ -349,11 +340,6 @@
|
|||||||
<td colspan="3"><input type="text" name="prpty2Val"/>
|
<td colspan="3"><input type="text" name="prpty2Val"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th>설명</th>
|
|
||||||
<td colspan="3"><input type="text" name="prptyDesc"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
<!-- grid -->
|
<!-- grid -->
|
||||||
<table id="grid"></table>
|
<table id="grid"></table>
|
||||||
|
|||||||
@@ -29,16 +29,6 @@
|
|||||||
// 원본 행 데이터를 ID로 조회하기 위한 맵
|
// 원본 행 데이터를 ID로 조회하기 위한 맵
|
||||||
var gridRowDataMap = {};
|
var gridRowDataMap = {};
|
||||||
|
|
||||||
// 휴대폰번호 중복 조회 모드 여부
|
|
||||||
var isDupView = false;
|
|
||||||
|
|
||||||
// 현재 검색조건 + 중복 조회 모드 플래그를 합쳐 LIST 요청 파라미터를 생성
|
|
||||||
function buildListPostData() {
|
|
||||||
var postData = getSearchForJqgrid("cmd", "LIST");
|
|
||||||
postData.onlyDuplicateMobile = isDupView;
|
|
||||||
return postData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 선택된 사용자 삭제 - 상태에 따라 Soft/Hard Delete 자동 분기 */
|
/* 선택된 사용자 삭제 - 상태에 따라 Soft/Hard Delete 자동 분기 */
|
||||||
function deleteSelectedUsers() {
|
function deleteSelectedUsers() {
|
||||||
var selectedIds = $("#grid").jqGrid('getGridParam', 'selarrrow');
|
var selectedIds = $("#grid").jqGrid('getGridParam', 'selarrrow');
|
||||||
@@ -176,13 +166,6 @@
|
|||||||
|
|
||||||
$('#grid').jqGrid('setColProp', 'approvalStatus', {editoptions: {value: select_approvalStatus}});
|
$('#grid').jqGrid('setColProp', 'approvalStatus', {editoptions: {value: select_approvalStatus}});
|
||||||
$('#grid').jqGrid('setColProp', 'userStatus', {editoptions: {value: select_userStatus}});
|
$('#grid').jqGrid('setColProp', 'userStatus', {editoptions: {value: select_userStatus}});
|
||||||
|
|
||||||
// 휴대폰번호 중복 허용안함(기능 ON) + 중복 사용자 존재 시 배너 노출
|
|
||||||
if (json.mobileDuplicateCheckEnabled && json.mobileDuplicateUserCount > 0) {
|
|
||||||
$("#dupMobileCount").text(json.mobileDuplicateUserCount);
|
|
||||||
$("#dupMobileBanner").show();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#grid').trigger('reloadGrid');
|
$('#grid').trigger('reloadGrid');
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -193,7 +176,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var gridPostData = buildListPostData();
|
var gridPostData = getSearchForJqgrid("cmd", "LIST");
|
||||||
|
|
||||||
$('#grid').jqGrid({
|
$('#grid').jqGrid({
|
||||||
datatype: "json",
|
datatype: "json",
|
||||||
@@ -205,7 +188,7 @@
|
|||||||
'<%= localeMessage.getString("portalUser.orgName") %>',
|
'<%= localeMessage.getString("portalUser.orgName") %>',
|
||||||
'<%= localeMessage.getString("portalUser.name") %>',
|
'<%= localeMessage.getString("portalUser.name") %>',
|
||||||
'<%= localeMessage.getString("portalUser.userId") %>',
|
'<%= localeMessage.getString("portalUser.userId") %>',
|
||||||
'<%= localeMessage.getString("portalUser.mobileNumber") %>',
|
<%--'<%= localeMessage.getString("portalUser.mobile") %>',--%>
|
||||||
'<%= localeMessage.getString("portalUser.roleName") %>',
|
'<%= localeMessage.getString("portalUser.roleName") %>',
|
||||||
'<%= localeMessage.getString("portalUser.userStatus") %>',
|
'<%= localeMessage.getString("portalUser.userStatus") %>',
|
||||||
'<%= localeMessage.getString("portalUser.createOn") %>',
|
'<%= localeMessage.getString("portalUser.createOn") %>',
|
||||||
@@ -218,7 +201,7 @@
|
|||||||
{name: 'portalOrgUIs.orgName', align: 'center', width: "120"},
|
{name: 'portalOrgUIs.orgName', align: 'center', width: "120"},
|
||||||
{name: 'userName', align: 'center', width: "80" },
|
{name: 'userName', align: 'center', width: "80" },
|
||||||
{name: 'loginId', align: 'center', width: "150" },
|
{name: 'loginId', align: 'center', width: "150" },
|
||||||
{name: 'mobileNumber', align: 'center', width: "110", hidden: true},
|
// {name: 'mobileNumber', align: 'center', width: "100" },
|
||||||
{name: 'roleCodeDescription', align: 'center', width: "80"},
|
{name: 'roleCodeDescription', align: 'center', width: "80"},
|
||||||
{name: 'userStatusDescription', align: 'center', width: "50"},
|
{name: 'userStatusDescription', align: 'center', width: "50"},
|
||||||
{name: 'createdDate', align: 'center', width: "100", formatter: timeStampFormat},
|
{name: 'createdDate', align: 'center', width: "100", formatter: timeStampFormat},
|
||||||
@@ -291,20 +274,9 @@
|
|||||||
init();
|
init();
|
||||||
|
|
||||||
$("#btn_search").click(function () {
|
$("#btn_search").click(function () {
|
||||||
$("#grid").setGridParam({url: url, postData: buildListPostData(), page: 1}).trigger("reloadGrid");
|
var postData = getSearchForJqgrid("cmd", "LIST");
|
||||||
});
|
|
||||||
|
|
||||||
// 중복 휴대폰번호 사용자만 보기 / 전체 보기 토글
|
$("#grid").setGridParam({url: url, postData: postData, page: 1}).trigger("reloadGrid");
|
||||||
$("#btn_dup_toggle").click(function () {
|
|
||||||
isDupView = !isDupView;
|
|
||||||
if (isDupView) {
|
|
||||||
$(this).text("전체 보기");
|
|
||||||
$("#grid").jqGrid('showCol', 'mobileNumber');
|
|
||||||
} else {
|
|
||||||
$(this).text("중복만 보기");
|
|
||||||
$("#grid").jqGrid('hideCol', 'mobileNumber');
|
|
||||||
}
|
|
||||||
$("#grid").setGridParam({url: url, postData: buildListPostData(), page: 1}).trigger("reloadGrid");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_new").click(function () {
|
$("#btn_new").click(function () {
|
||||||
@@ -347,11 +319,9 @@
|
|||||||
<button type="button" class="cssbtn" id="btn_new" level="W"><i
|
<button type="button" class="cssbtn" id="btn_new" level="W"><i
|
||||||
class="material-icons">add</i> <%= localeMessage.getString("button.new") %>
|
class="material-icons">add</i> <%= localeMessage.getString("button.new") %>
|
||||||
</button>
|
</button>
|
||||||
<c:if test="${hardDeleteEnabled}">
|
|
||||||
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i
|
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i
|
||||||
class="material-icons">delete_forever</i> 선택 삭제
|
class="material-icons">delete_forever</i> 선택 삭제
|
||||||
</button>
|
</button>
|
||||||
</c:if>
|
|
||||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i
|
<button type="button" class="cssbtn" id="btn_search" level="R"><i
|
||||||
class="material-icons">search</i> <%= localeMessage.getString("button.search") %>
|
class="material-icons">search</i> <%= localeMessage.getString("button.search") %>
|
||||||
</button>
|
</button>
|
||||||
@@ -364,11 +334,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<div id="dupMobileBanner" style="display:none; background:#f8d7da; border:1px solid #dc3545; padding:8px 15px; margin:5px 0; border-radius:4px; color:#721c24;">
|
|
||||||
<strong>⚠ 중복 휴대폰번호 사용자 <span id="dupMobileCount">0</span>건 발견</strong>
|
|
||||||
<button type="button" class="cssbtn" id="btn_dup_toggle" style="margin-left:10px;">중복만 보기</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table class="search_condition" cellspacing=0;>
|
<table class="search_condition" cellspacing=0;>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -400,16 +365,15 @@
|
|||||||
<td><input type="text" name="searchUserName"></td>
|
<td><input type="text" name="searchUserName"></td>
|
||||||
|
|
||||||
<th style="width:10%; min-width:100px;">
|
<th style="width:10%; min-width:100px;">
|
||||||
<%= localeMessage.getString("portalUser.userId") %><span style="color:#dc3545;">(*)</span>
|
<%= localeMessage.getString("portalUser.userId") %>
|
||||||
</th>
|
</th>
|
||||||
<td><input type="text" name="searchUserId" value="${param.searchUserId}"></td>
|
<td><input type="text" name="searchUserId" value="${param.searchUserId}"></td>
|
||||||
<th style="width:10%; min-width:100px;"><%= localeMessage.getString("portalUser.mobileNumber") %><span style="color:#dc3545;">(*)</span>
|
<th style="width:10%; min-width:100px;"><%= localeMessage.getString("portalUser.mobileNumber") %>
|
||||||
</th>
|
</th>
|
||||||
<td><input type="text" name="searchMobileNumber" value="${param.searchMobileNumber}"></td>
|
<td><input type="text" name="searchMobileNumber" value="${param.searchMobileNumber}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div style="color:#dc3545; font-size:12px; margin:4px 2px;">(*) 암호화 항목 · 부분검색 불가(전체 일치)</div>
|
|
||||||
|
|
||||||
<table id="grid"></table>
|
<table id="grid"></table>
|
||||||
<div id="pager"></div>
|
<div id="pager"></div>
|
||||||
|
|||||||
@@ -165,10 +165,6 @@
|
|||||||
$("#userStatus").val(data.userStatus);
|
$("#userStatus").val(data.userStatus);
|
||||||
$("#roleCode").val(data.roleCode).trigger('change');
|
$("#roleCode").val(data.roleCode).trigger('change');
|
||||||
$("#approvalStatus").val(data.approvalStatus);
|
$("#approvalStatus").val(data.approvalStatus);
|
||||||
// 승인상태는 읽기전용(수정 불가) - 값은 그대로 제출되도록 disabled 대신 잠금 처리
|
|
||||||
$("#approvalStatus")
|
|
||||||
.css({'pointer-events':'none', 'background-color':'#eee'})
|
|
||||||
.attr('tabindex', '-1');
|
|
||||||
|
|
||||||
// 탈퇴 상태 처리
|
// 탈퇴 상태 처리
|
||||||
if (originalUserStatus === STATUS.REMOVED) {
|
if (originalUserStatus === STATUS.REMOVED) {
|
||||||
@@ -285,7 +281,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fullLoginId = id + "@" + domain;
|
const fullLoginId = id + "@" + domain;
|
||||||
const emailPattern = /^[A-Za-z0-9._%+-]*@[A-Za-z0-9][-A-Za-z0-9.]+\.[A-Za-z]{2,}$/;
|
const emailPattern = /^[A-Za-z0-9._-]*@[A-Za-z0-9][-A-Za-z0-9.]+\.[A-Za-z]{2,}$/;
|
||||||
if (!emailPattern.test(fullLoginId)) {
|
if (!emailPattern.test(fullLoginId)) {
|
||||||
alert(fullLoginId + " 은 올바른 이메일 형식이 아닙니다.");
|
alert(fullLoginId + " 은 올바른 이메일 형식이 아닙니다.");
|
||||||
return;
|
return;
|
||||||
@@ -317,7 +313,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function validateEmailId(input) {
|
function validateEmailId(input) {
|
||||||
input.value = input.value.replace(/[^A-Za-z0-9._%+-]/g, '');
|
input.value = input.value.replace(/[^A-Za-z0-9._-]/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateDomainInput(input) {
|
function validateDomainInput(input) {
|
||||||
@@ -492,49 +488,29 @@
|
|||||||
formData.push({name: 'mobileNumber', value: mobileNumber});
|
formData.push({name: 'mobileNumber', value: mobileNumber});
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmd 및 사유(auditReason) 첨부 후 전송
|
formData.push({
|
||||||
function submitUser(cmd, auditReason) {
|
name: 'cmd',
|
||||||
formData.push({ name: 'cmd', value: cmd });
|
value: isDetail ? "UPDATE" : "INSERT"
|
||||||
// 감사로그(AUDIT_LOG) 발화를 위한 systemCode. 가입자 리포지토리는 고정 EMS 스키마라 스키마 전환 영향 없음
|
});
|
||||||
formData.push({ name: 'serviceType', value: 'APIGW' });
|
|
||||||
if (auditReason) {
|
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
||||||
formData.push({ name: 'auditReason', value: auditReason });
|
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
data: formData,
|
||||||
|
success: function (json) {
|
||||||
|
if (json.status === "fail") {
|
||||||
|
alert(json.errorMsg || "저장에 실패했습니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||||
|
goNav(returnUrl);
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
alert(e.responseText);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
data: formData,
|
|
||||||
success: function (json) {
|
|
||||||
if (json.status === "fail") {
|
|
||||||
alert(json.errorMsg || "저장에 실패했습니다.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
|
||||||
goNav(returnUrl);
|
|
||||||
},
|
|
||||||
error: function (e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDetail) {
|
|
||||||
// 수정: 상태를 REMOVED로 바꾼 경우 삭제(cmd=DELETE)로 감사 기록 + 익명화
|
|
||||||
var targetCmd = ($("#userStatus").val() === 'REMOVED') ? "DELETE" : "UPDATE";
|
|
||||||
var isRemove = (targetCmd === "DELETE");
|
|
||||||
showReasonPrompt(
|
|
||||||
isRemove ? "해당 가입자를 삭제(탈퇴) 처리합니다. 사유를 입력해 주세요." : "가입자 정보를 수정합니다. 사유를 입력해 주세요.",
|
|
||||||
{
|
|
||||||
title: isRemove ? "삭제 사유" : "수정 사유",
|
|
||||||
onConfirm: function(reason) { submitUser(targetCmd, reason); }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// 신규 등록: 사유 불필요. 초기 패스워드는 비밀번호 초기화와 동일(이메일ID + subfix)
|
|
||||||
if (!confirm("가입자를 등록하시겠습니까?\n초기 패스워드는 '이메일ID${passwordInitSubfix}' 입니다.")) return;
|
|
||||||
submitUser("INSERT", null);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_previous").click(function () {
|
$("#btn_previous").click(function () {
|
||||||
@@ -542,32 +518,27 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_delete").click(function () {
|
$("#btn_delete").click(function () {
|
||||||
showReasonPrompt("해당 가입자를 삭제 처리합니다. 사유를 입력해 주세요.", {
|
if (!confirm("<%= localeMessage.getString("common.confirmMsg")%>")) return;
|
||||||
title: "삭제 사유",
|
|
||||||
onConfirm: function(reason) {
|
$.ajax({
|
||||||
$.ajax({
|
type: "POST",
|
||||||
type: "POST",
|
url: url,
|
||||||
url: url,
|
data: {
|
||||||
data: {
|
cmd: "DELETE",
|
||||||
cmd: "DELETE",
|
id: $('input[name=id]').val()
|
||||||
id: $('input[name=id]').val(),
|
},
|
||||||
serviceType: "APIGW",
|
success: function () {
|
||||||
auditReason: reason
|
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||||
},
|
goNav(returnUrl);
|
||||||
success: function () {
|
},
|
||||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
error: function (e) {
|
||||||
goNav(returnUrl);
|
alert(e.responseText);
|
||||||
},
|
|
||||||
error: function (e) {
|
|
||||||
alert(e.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn_password_reset").click(function () {
|
$("#btn_password_reset").click(function () {
|
||||||
if (!confirm("패스워드를 초기화 하시겠습니까?\n초기 패스워드는 '이메일ID${passwordInitSubfix}' 입니다.")) return;
|
if (!confirm("패스워드를 초기화 하시겠습니까?\n초기 패스워드는 '!' + 이메일ID 입니다.")) return;
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
|||||||
@@ -172,9 +172,6 @@ $(document).ready(function() {
|
|||||||
<form id="ajaxForm">
|
<form id="ajaxForm">
|
||||||
<input type="hidden" name="id">
|
<input type="hidden" name="id">
|
||||||
<table class="table_row" cellspacing="0">
|
<table class="table_row" cellspacing="0">
|
||||||
<colgroup>
|
|
||||||
<col width="200px">
|
|
||||||
</colgroup>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th><%= localeMessage.getString("messageTemplate.messageCode") %> <font color="red"> *</font></th>
|
<th><%= localeMessage.getString("messageTemplate.messageCode") %> <font color="red"> *</font></th>
|
||||||
<td><input type="text" name="messageCode" data-required data-warning="메세지 코드는 필수입니다"/></td>
|
<td><input type="text" name="messageCode" data-required data-warning="메세지 코드는 필수입니다"/></td>
|
||||||
|
|||||||
@@ -1,242 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
|
||||||
<%@ page import="java.io.*" %>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
|
||||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
%>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
|
||||||
<style>
|
|
||||||
.url-cell { display:inline-block; max-width:380px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; vertical-align:middle; }
|
|
||||||
.succ-y { color:#1a73e8; font-weight:bold; }
|
|
||||||
.succ-n { color:#d93025; font-weight:bold; }
|
|
||||||
</style>
|
|
||||||
<script language="javascript">
|
|
||||||
var url = '<c:url value="/onl/apim/webhook/webhookSendLogMan.json" />';
|
|
||||||
var url_view = '<c:url value="/onl/apim/webhook/webhookSendLogMan.view" />';
|
|
||||||
var combo;
|
|
||||||
|
|
||||||
function escapeHtmlJs(s) { return $('<div>').text(s == null ? '' : s).html(); }
|
|
||||||
function escapeAttr(s) { return escapeHtmlJs(s).replace(/"/g, '"'); }
|
|
||||||
|
|
||||||
function formatTargetUrl(cellvalue, options, rowObject) {
|
|
||||||
var v = cellvalue || '';
|
|
||||||
return '<span class="url-cell" title="' + escapeAttr(v) + '">' + escapeHtmlJs(v) + '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 이벤트유형 코드 → 모니터링 공통코드(EVENT_TYPE) 코드명
|
|
||||||
function formatEventType(cellvalue, options, rowObject) {
|
|
||||||
if (!combo || !combo.eventTypeList) {
|
|
||||||
return escapeHtmlJs(cellvalue);
|
|
||||||
}
|
|
||||||
for (var i = 0; i < combo.eventTypeList.length; i++) {
|
|
||||||
if (combo.eventTypeList[i].CODE == cellvalue) {
|
|
||||||
return escapeHtmlJs(combo.eventTypeList[i].NAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return escapeHtmlJs(cellvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatSuccess(cellvalue, options, rowObject) {
|
|
||||||
if (cellvalue === true) return '<span class="succ-y">성공</span>';
|
|
||||||
if (cellvalue === false) return '<span class="succ-n">실패</span>';
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
|
|
||||||
$("#startDatepicker").datepicker().inputmask("yyyy-mm-dd",{'autoUnmask':true});
|
|
||||||
$("#endDatepicker").datepicker().inputmask("yyyy-mm-dd",{'autoUnmask':true});
|
|
||||||
|
|
||||||
var today = getToday();
|
|
||||||
|
|
||||||
$("input[name=searchStartYYYYMMDD]").val(today.substring(0,6)+"01");
|
|
||||||
$("input[name=searchEndYYYYMMDD]").val(today);
|
|
||||||
$("input[name=searchStartDate]").val(today.substring(0,6)+"01");
|
|
||||||
$("input[name=searchEndDate]").val(today);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url, dataType: "json",
|
|
||||||
data: {cmd: 'LIST_INIT_COMBO'},
|
|
||||||
success: function (json) {
|
|
||||||
combo = json;
|
|
||||||
new makeOptions("CODE", "NAME").setObj($("select[name=searchEventType]"))
|
|
||||||
.setNoValueInclude(true).setNoValue("", "<%=localeMessage.getString("combo.all")%>")
|
|
||||||
.setData(json.eventTypeList).rendering();
|
|
||||||
|
|
||||||
// 뒤로가기 등으로 이전 검색조건 파라미터가 있으면 기본값을 덮어씀
|
|
||||||
putSelectFromParam();
|
|
||||||
|
|
||||||
// 콤보(이벤트유형) 로드 후 그리드 생성 — formatEventType 경합 방지
|
|
||||||
buildGrid();
|
|
||||||
},
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildGrid() {
|
|
||||||
$('#grid').jqGrid({
|
|
||||||
datatype: "json",
|
|
||||||
mtype: 'POST',
|
|
||||||
url: url,
|
|
||||||
postData: getSearchForJqgrid("cmd", "LIST"),
|
|
||||||
colNames: ['id', 'No.', '기관명', '이벤트유형', 'Target URL', 'Proxy URL', 'Status', '성공여부', '발송서버', '발송일시'],
|
|
||||||
colModel: [
|
|
||||||
{name: 'id', align: 'center', key: true, hidden: true},
|
|
||||||
{name: 'rowNum', align: 'center', width: 45, sortable: false},
|
|
||||||
{name: 'orgName', align: 'left', width: 140},
|
|
||||||
{name: 'eventType', align: 'center', width: 120, formatter: formatEventType},
|
|
||||||
{name: 'targetUrl', align: 'left', width: 300, formatter: formatTargetUrl},
|
|
||||||
{name: 'proxyUrl', align: 'left', width: 300, formatter: formatTargetUrl},
|
|
||||||
{name: 'statusCode', align: 'center', width: 60},
|
|
||||||
{name: 'success', align: 'center', width: 70, formatter: formatSuccess},
|
|
||||||
{name: 'sendBy', align: 'center', width: 100},
|
|
||||||
{name: 'sentAt', align: 'center', width: 140}
|
|
||||||
],
|
|
||||||
jsonReader: {repeatitems: false},
|
|
||||||
pager: $('#pager'),
|
|
||||||
page: '${param.page}',
|
|
||||||
rowNum: '${rmsDefaultRowNum}',
|
|
||||||
autoheight: true,
|
|
||||||
height: $("#container").height(),
|
|
||||||
autowidth: true,
|
|
||||||
viewrecords: true,
|
|
||||||
rowList: eval('[${rmsDefaultRowList}]'),
|
|
||||||
ondblClickRow: function (rowId) {
|
|
||||||
var rowData = $(this).getRowData(rowId);
|
|
||||||
var id = rowData['id'];
|
|
||||||
var url2 = url_view + '?cmd=DETAIL';
|
|
||||||
url2 += '&page=' + $(this).getGridParam("page");
|
|
||||||
url2 += '&returnUrl=' + getReturnUrl();
|
|
||||||
url2 += '&menuId=' + '${param.menuId}';
|
|
||||||
url2 += '&id=' + id;
|
|
||||||
url2 += '&' + getSearchUrl();
|
|
||||||
goNav(url2);
|
|
||||||
},
|
|
||||||
loadComplete: function () {
|
|
||||||
var page = $(this).getGridParam('page');
|
|
||||||
var rowNum = $(this).getGridParam('rowNum');
|
|
||||||
var rows = $(this).getDataIDs();
|
|
||||||
var colModel = $(this).getGridParam("colModel");
|
|
||||||
for (var i = 0; i < rows.length; i++) {
|
|
||||||
var number = ((page - 1) * rowNum + i) + 1;
|
|
||||||
$(this).setCell(rows[i], 'rowNum', number);
|
|
||||||
}
|
|
||||||
// 서버 고정 정렬(등록일시 역순) — 컬럼 정렬 비활성
|
|
||||||
for (var i = 0; i < colModel.length; i++) {
|
|
||||||
$(this).setColProp(colModel[i].name, {sortable: false});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
loadError: function (jqXHR, textStatus, errorThrown) {
|
|
||||||
var location = '<%=request.getContextPath()%>/';
|
|
||||||
comloadError(jqXHR, textStatus, errorThrown, location);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
resizeJqGridWidth('grid', 'content_middle', '1000');
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
init();
|
|
||||||
|
|
||||||
$("#btn_search").click(function () {
|
|
||||||
var start = $("input[name=searchStartYYYYMMDD]").val().replace(/-/gi, "");
|
|
||||||
var end = $("input[name=searchEndYYYYMMDD]").val().replace(/-/gi, "");
|
|
||||||
|
|
||||||
if (start && start > getToday()) {
|
|
||||||
alert("시작일이 오늘 이후입니다. 시작일을 확인해주세요.");
|
|
||||||
$("input[name=searchStartYYYYMMDD]").focus();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (start && end && start > end) {
|
|
||||||
alert("조회기간 종료일은 시작일보다 커야합니다.");
|
|
||||||
$("input[name=searchEndYYYYMMDD]").focus();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$("input[name=searchStartDate]").val(start);
|
|
||||||
$("input[name=searchEndDate]").val(end);
|
|
||||||
|
|
||||||
var postData = getSearchForJqgrid("cmd", "LIST");
|
|
||||||
$("#grid").setGridParam({url: url, postData: postData, page: 1}).trigger("reloadGrid");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("select[name^=search]").change(function () { $("#btn_search").click(); });
|
|
||||||
$("input[name^=search]").keydown(function (key) {
|
|
||||||
if (key.keyCode == 13) { $("#btn_search").click(); }
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
buttonControl();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="right_box">
|
|
||||||
<div class="content_top">
|
|
||||||
<ul class="path"><li><a href="#">${rmsMenuPath}</a></li></ul>
|
|
||||||
</div><!-- end content_top -->
|
|
||||||
<div class="content_middle" id="content_middle">
|
|
||||||
<div class="search_wrap">
|
|
||||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
|
||||||
</div>
|
|
||||||
<div class="title">웹훅 발송 로그<span class="tooltip">외부로 발송된 웹훅 이력을 조회합니다.</span></div>
|
|
||||||
<form id="ajaxForm" onsubmit="return false;">
|
|
||||||
<table class="search_condition" cellspacing=0;>
|
|
||||||
<colgroup>
|
|
||||||
<col style="width:120px;"><col style="width:200px;">
|
|
||||||
<col style="width:120px;"><col style="width:200px;">
|
|
||||||
<col style="width:120px;"><col style="width:200px;">
|
|
||||||
</colgroup>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>기관명</th>
|
|
||||||
<td><input type="text" name="searchOrgName" autocomplete="off"></td>
|
|
||||||
<th>이벤트유형</th>
|
|
||||||
<td>
|
|
||||||
<div class="select-style">
|
|
||||||
<select name="searchEventType"></select>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<th>성공여부</th>
|
|
||||||
<td>
|
|
||||||
<div class="select-style">
|
|
||||||
<select name="searchSuccess">
|
|
||||||
<option value="">전체</option>
|
|
||||||
<option value="Y">성공</option>
|
|
||||||
<option value="N">실패</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Target URL</th>
|
|
||||||
<td><input type="text" name="searchTargetUrl" autocomplete="off" style="width:95%;"></td>
|
|
||||||
<th>발송기간</th>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="searchStartYYYYMMDD" id="startDatepicker" readonly="readonly" value="" size="10" style="width:40%; border:1px solid #ebebec;">
|
|
||||||
~
|
|
||||||
<input type="text" name="searchEndYYYYMMDD" value="" id="endDatepicker" size="10" readonly="readonly" style="width:40%; border:1px solid #ebebec;">
|
|
||||||
<input type="hidden" name="searchStartDate" value="">
|
|
||||||
<input type="hidden" name="searchEndDate" value="">
|
|
||||||
</td>
|
|
||||||
<th></th>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
<table id="grid"></table>
|
|
||||||
<div id="pager"></div>
|
|
||||||
</div><!-- end content_middle -->
|
|
||||||
</div><!-- end right_box -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
|
||||||
<%@ page import="java.io.*" %>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
|
||||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
%>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
|
||||||
<style>
|
|
||||||
.succ-y { color:#1a73e8; font-weight:bold; }
|
|
||||||
.succ-n { color:#d93025; font-weight:bold; }
|
|
||||||
.pre-wrap { white-space:pre-wrap; word-break:break-all; min-height:60px; line-height:1.5; }
|
|
||||||
</style>
|
|
||||||
<script language="javascript">
|
|
||||||
var url = '<c:url value="/onl/apim/webhook/webhookSendLogMan.json" />';
|
|
||||||
var url_view = '<c:url value="/onl/apim/webhook/webhookSendLogMan.view" />';
|
|
||||||
var key = '${param.id}';
|
|
||||||
|
|
||||||
function escapeHtmlJs(s) { return $('<div>').text(s == null ? '' : s).html(); }
|
|
||||||
|
|
||||||
function detail() {
|
|
||||||
if (!key) return;
|
|
||||||
$.ajax({
|
|
||||||
type: "POST", url: url, dataType: "json",
|
|
||||||
data: {cmd: 'DETAIL', id: key},
|
|
||||||
success: function (data) {
|
|
||||||
$('#id').text(data.id != null ? data.id : '');
|
|
||||||
$('#orgName').text(data.orgName || '');
|
|
||||||
$('#eventType').text(data.eventTypeName || data.eventType || '')
|
|
||||||
.attr('title', data.eventType || '');
|
|
||||||
$('#targetUrl').text(data.targetUrl || '');
|
|
||||||
$('#proxyUrl').text(data.proxyUrl || '');
|
|
||||||
$('#statusCode').text(data.statusCode != null ? data.statusCode : '');
|
|
||||||
$('#retryCount').text(data.retryCount != null ? data.retryCount : '');
|
|
||||||
$('#sendBy').text(data.sendBy || '');
|
|
||||||
$('#sentAt').text(data.sentAt || '');
|
|
||||||
$('#signature').text(data.signature || '');
|
|
||||||
$('#errorMessage').text(data.errorMessage || '');
|
|
||||||
$('#payload').text(data.payload || '');
|
|
||||||
$('#responseBody').text(data.responseBody || '');
|
|
||||||
|
|
||||||
if (data.success === true) {
|
|
||||||
$('#success').html('<span class="succ-y">성공</span>');
|
|
||||||
} else if (data.success === false) {
|
|
||||||
$('#success').html('<span class="succ-n">실패</span>');
|
|
||||||
} else {
|
|
||||||
$('#success').text('');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function (e) { alert(e.responseText); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
var returnUrl = getReturnUrlForReturn();
|
|
||||||
|
|
||||||
buttonControl();
|
|
||||||
detail();
|
|
||||||
|
|
||||||
$('#btn_previous').click(function () { goNav(returnUrl); });
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="right_box">
|
|
||||||
<div class="content_top">
|
|
||||||
<ul class="path"><li><a href="#">${rmsMenuPath}</a></li></ul>
|
|
||||||
</div>
|
|
||||||
<div class="content_middle">
|
|
||||||
<div class="search_wrap">
|
|
||||||
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
|
||||||
</div>
|
|
||||||
<div class="title" id="title">웹훅 발송 로그 상세</div>
|
|
||||||
<table class="table_row" cellspacing="0">
|
|
||||||
<colgroup>
|
|
||||||
<col style="width:12%"/><col style="width:38%"/>
|
|
||||||
<col style="width:12%"/><col style="width:38%"/>
|
|
||||||
</colgroup>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<td><span id="id"></span></td>
|
|
||||||
<th>기관명</th>
|
|
||||||
<td><span id="orgName"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>이벤트유형</th>
|
|
||||||
<td><span id="eventType"></span></td>
|
|
||||||
<th>Status Code</th>
|
|
||||||
<td><span id="statusCode"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Target URL</th>
|
|
||||||
<td><span id="targetUrl"></span></td>
|
|
||||||
<th>Proxy URL</th>
|
|
||||||
<td><span id="proxyUrl"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>성공여부</th>
|
|
||||||
<td><span id="success"></span></td>
|
|
||||||
<th>재시도횟수</th>
|
|
||||||
<td><span id="retryCount"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>발송서버</th>
|
|
||||||
<td><span id="sendBy"></span></td>
|
|
||||||
<th>발송일시</th>
|
|
||||||
<td><span id="sentAt"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Signature</th>
|
|
||||||
<td colspan="3"><span id="signature"></span></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Payload</th>
|
|
||||||
<td colspan="3"><div id="payload" class="pre-wrap"></div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Response Body</th>
|
|
||||||
<td colspan="3"><div id="responseBody" class="pre-wrap"></div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>에러 메세지</th>
|
|
||||||
<td colspan="3"><div id="errorMessage" class="pre-wrap"></div></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -66,27 +66,22 @@
|
|||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c} ({d}%)'
|
||||||
return params.name + ': ' + params.value.toLocaleString() + ' (' + params.percent + '%)';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
orient: 'vertical',
|
orient: 'horizontal',
|
||||||
right: 30,
|
bottom: 10,
|
||||||
top: 'middle',
|
|
||||||
data: ['성공', 'Timeout', '시스템오류']
|
data: ['성공', 'Timeout', '시스템오류']
|
||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: '총건수',
|
name: '총건수',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
radius: ['38%', '65%'],
|
radius: ['40%', '70%'],
|
||||||
center: ['44%', '55%'],
|
center: ['50%', '50%'],
|
||||||
avoidLabelOverlap: true,
|
avoidLabelOverlap: true,
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c}'
|
||||||
return params.name + ': ' + params.value.toLocaleString();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
label: {
|
label: {
|
||||||
@@ -103,6 +98,18 @@
|
|||||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center',
|
||||||
|
style: {
|
||||||
|
text: '0',
|
||||||
|
textAlign: 'center',
|
||||||
|
fill: '#333',
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,7 +119,7 @@
|
|||||||
|
|
||||||
// 호출량 차트
|
// 호출량 차트
|
||||||
var callOption = {
|
var callOption = {
|
||||||
title: { text: '호출량 추이', left: 'center', top: 10, textStyle: { fontSize: 14 } },
|
title: { text: '호출량 추이', left: 'center', textStyle: { fontSize: 14 } },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
||||||
@@ -184,9 +191,13 @@
|
|||||||
{ value: totalTimeout, name: 'Timeout' },
|
{ value: totalTimeout, name: 'Timeout' },
|
||||||
{ value: totalSystemErr, name: '시스템오류' }
|
{ value: totalSystemErr, name: '시스템오류' }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
style: {
|
||||||
|
text: grandTotal.toLocaleString()
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
$("#totalDonutCenterText").text(grandTotal.toLocaleString());
|
|
||||||
|
|
||||||
|
|
||||||
// 호출량 차트 업데이트
|
// 호출량 차트 업데이트
|
||||||
@@ -444,9 +455,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -493,9 +501,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -582,18 +587,10 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="title" id="title">API 일별 통계</div>
|
<div class="title" id="title">API 일별 통계</div>
|
||||||
<table class="search_condition" cellspacing="0" style="table-layout:fixed;">
|
<table class="search_condition" cellspacing="0">
|
||||||
<colgroup>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
</colgroup>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>조회기간</th>
|
<th style="width:100px;">조회기간</th>
|
||||||
<td colspan="5">
|
<td colspan="5">
|
||||||
<input type="text" name="searchStartDateTime" value="${param.searchStartDateTime}" style="width:100px;">
|
<input type="text" name="searchStartDateTime" value="${param.searchStartDateTime}" style="width:100px;">
|
||||||
~
|
~
|
||||||
@@ -602,29 +599,29 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>API명</th>
|
<th style="width:100px;">API명</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchApiName" value="${param.searchApiName}">
|
<input type="text" name="searchApiName" value="${param.searchApiName}">
|
||||||
</td>
|
</td>
|
||||||
<th>업무구분</th>
|
<th style="width:100px;">업무구분</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchBizDivCode" value="${param.searchBizDivCode}">
|
<input type="text" name="searchBizDivCode" value="${param.searchBizDivCode}">
|
||||||
</td>
|
</td>
|
||||||
<th>인스턴스</th>
|
<th style="width:100px;">인스턴스</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchGwInstanceId" value="${param.searchGwInstanceId}">
|
<input type="text" name="searchGwInstanceId" value="${param.searchGwInstanceId}">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>클라이언트ID</th>
|
<th style="width:100px;">클라이언트ID</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchClientId" value="${param.searchClientId}">
|
<input type="text" name="searchClientId" value="${param.searchClientId}">
|
||||||
</td>
|
</td>
|
||||||
<th>Inbound Adapter</th>
|
<th style="width:100px;">Inbound Adapter</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchInboundAdapter" value="${param.searchInboundAdapter}">
|
<input type="text" name="searchInboundAdapter" value="${param.searchInboundAdapter}">
|
||||||
</td>
|
</td>
|
||||||
<th>Outbound Adapter</th>
|
<th style="width:100px;">Outbound Adapter</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchOutboundAdapter" value="${param.searchOutboundAdapter}">
|
<input type="text" name="searchOutboundAdapter" value="${param.searchOutboundAdapter}">
|
||||||
</td>
|
</td>
|
||||||
@@ -633,10 +630,7 @@
|
|||||||
</table>
|
</table>
|
||||||
<!-- 도넛 차트 (상단 50%씩) -->
|
<!-- 도넛 차트 (상단 50%씩) -->
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<div class="chart" style="position:relative; padding:0;">
|
<div id="totalDonutChart" class="chart"></div>
|
||||||
<div id="totalDonutChart" style="width:100%; height:100%;"></div>
|
|
||||||
<div id="totalDonutCenterText" style="position:absolute; left:44.5%; top:55%; transform:translate(-50%,-50%); font-size:24px; font-weight:bold; color:#333; pointer-events:none; z-index:10;">0</div>
|
|
||||||
</div>
|
|
||||||
<div id="callChart" class="chart"></div>
|
<div id="callChart" class="chart"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -67,27 +67,22 @@
|
|||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c} ({d}%)'
|
||||||
return params.name + ': ' + params.value.toLocaleString() + ' (' + params.percent + '%)';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
orient: 'vertical',
|
orient: 'horizontal',
|
||||||
right: 30,
|
bottom: 10,
|
||||||
top: 'middle',
|
|
||||||
data: ['성공', 'Timeout', '시스템오류']
|
data: ['성공', 'Timeout', '시스템오류']
|
||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: '총건수',
|
name: '총건수',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
radius: ['38%', '65%'],
|
radius: ['40%', '70%'],
|
||||||
center: ['44%', '55%'],
|
center: ['50%', '50%'],
|
||||||
avoidLabelOverlap: true,
|
avoidLabelOverlap: true,
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c}'
|
||||||
return params.name + ': ' + params.value.toLocaleString();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
label: {
|
label: {
|
||||||
@@ -104,6 +99,18 @@
|
|||||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center',
|
||||||
|
style: {
|
||||||
|
text: '0',
|
||||||
|
textAlign: 'center',
|
||||||
|
fill: '#333',
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -113,7 +120,7 @@
|
|||||||
|
|
||||||
// 호출량 차트
|
// 호출량 차트
|
||||||
var callOption = {
|
var callOption = {
|
||||||
title: { text: '호출량 추이', left: 'center', top: 10, textStyle: { fontSize: 14 } },
|
title: { text: '호출량 추이', left: 'center', textStyle: { fontSize: 14 } },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
||||||
@@ -220,9 +227,13 @@
|
|||||||
{ value: totalTimeout, name: 'Timeout' },
|
{ value: totalTimeout, name: 'Timeout' },
|
||||||
{ value: totalSystemErr, name: '시스템오류' }
|
{ value: totalSystemErr, name: '시스템오류' }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
style: {
|
||||||
|
text: grandTotal.toLocaleString()
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
$("#totalDonutCenterText").text(grandTotal.toLocaleString());
|
|
||||||
|
|
||||||
|
|
||||||
// 호출량 차트 업데이트
|
// 호출량 차트 업데이트
|
||||||
@@ -446,9 +457,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -495,9 +503,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -562,47 +567,41 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="title" id="title">API 시간별 통계</div>
|
<div class="title" id="title">API 시간별 통계</div>
|
||||||
<table class="search_condition" cellspacing="0" style="table-layout:fixed;">
|
<table class="search_condition" cellspacing="0">
|
||||||
<colgroup>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
</colgroup>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>조회일자</th>
|
<th style="width:100px;">조회일자</th>
|
||||||
<td colspan="5">
|
<td colspan="3">
|
||||||
<input type="text" name="searchDate" value="${param.searchDate}" style="width:100px;">
|
<input type="text" name="searchDate" value="${param.searchDate}" style="width:100px;">
|
||||||
<span style="color:#888; font-size:12px; margin-left:10px;">(선택일 00시 ~ 23시 조회)</span>
|
<span style="color:#888; font-size:12px; margin-left:10px;">(선택일 00시 ~ 23시 조회)</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>API명</th>
|
<th style="width:100px;">API명</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchApiName" value="${param.searchApiName}">
|
<input type="text" name="searchApiName" value="${param.searchApiName}">
|
||||||
</td>
|
</td>
|
||||||
<th>업무구분</th>
|
<th style="width:100px;">인스턴스</th>
|
||||||
<td>
|
|
||||||
<input type="text" name="searchBizDivCode" value="${param.searchBizDivCode}">
|
|
||||||
</td>
|
|
||||||
<th>인스턴스</th>
|
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchGwInstanceId" value="${param.searchGwInstanceId}">
|
<input type="text" name="searchGwInstanceId" value="${param.searchGwInstanceId}">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>클라이언트ID</th>
|
<th style="width:100px;">업무구분</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="searchBizDivCode" value="${param.searchBizDivCode}">
|
||||||
|
</td>
|
||||||
|
<th style="width:100px;">클라이언트ID</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchClientId" value="${param.searchClientId}">
|
<input type="text" name="searchClientId" value="${param.searchClientId}">
|
||||||
</td>
|
</td>
|
||||||
<th>Inbound Adapter</th>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th style="width:100px;">Inbound Adapter</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchInboundAdapter" value="${param.searchInboundAdapter}">
|
<input type="text" name="searchInboundAdapter" value="${param.searchInboundAdapter}">
|
||||||
</td>
|
</td>
|
||||||
<th>Outbound Adapter</th>
|
<th style="width:100px;">Outbound Adapter</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchOutboundAdapter" value="${param.searchOutboundAdapter}">
|
<input type="text" name="searchOutboundAdapter" value="${param.searchOutboundAdapter}">
|
||||||
</td>
|
</td>
|
||||||
@@ -611,10 +610,7 @@
|
|||||||
</table>
|
</table>
|
||||||
<!-- 도넛 차트 (상단 50%씩) -->
|
<!-- 도넛 차트 (상단 50%씩) -->
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<div class="chart" style="position:relative; padding:0;">
|
<div id="totalDonutChart" class="chart"></div>
|
||||||
<div id="totalDonutChart" style="width:100%; height:100%;"></div>
|
|
||||||
<div id="totalDonutCenterText" style="position:absolute; left:44.5%; top:55%; transform:translate(-50%,-50%); font-size:24px; font-weight:bold; color:#333; pointer-events:none; z-index:10;">0</div>
|
|
||||||
</div>
|
|
||||||
<div id="callChart" class="chart"></div>
|
<div id="callChart" class="chart"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -59,27 +59,22 @@
|
|||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c} ({d}%)'
|
||||||
return params.name + ': ' + params.value.toLocaleString() + ' (' + params.percent + '%)';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
orient: 'vertical',
|
orient: 'horizontal',
|
||||||
right: 30,
|
bottom: 10,
|
||||||
top: 'middle',
|
|
||||||
data: ['성공', 'Timeout', '시스템오류']
|
data: ['성공', 'Timeout', '시스템오류']
|
||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: '총건수',
|
name: '총건수',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
radius: ['38%', '65%'],
|
radius: ['40%', '70%'],
|
||||||
center: ['44%', '55%'],
|
center: ['50%', '50%'],
|
||||||
avoidLabelOverlap: true,
|
avoidLabelOverlap: true,
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c}'
|
||||||
return params.name + ': ' + params.value.toLocaleString();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
label: {
|
label: {
|
||||||
@@ -96,6 +91,18 @@
|
|||||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center',
|
||||||
|
style: {
|
||||||
|
text: '0',
|
||||||
|
textAlign: 'center',
|
||||||
|
fill: '#333',
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,8 +111,8 @@
|
|||||||
|
|
||||||
|
|
||||||
// 호출량 차트
|
// 호출량 차트
|
||||||
var callOption = {
|
var callOption = {
|
||||||
title: { text: '호출량 추이', left: 'center', top: 10, textStyle: { fontSize: 14 } },
|
title: { text: '호출량 추이', left: 'center', textStyle: { fontSize: 14 } },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
||||||
@@ -182,9 +189,13 @@
|
|||||||
{ value: totalTimeout, name: 'Timeout' },
|
{ value: totalTimeout, name: 'Timeout' },
|
||||||
{ value: totalSystemErr, name: '시스템오류' }
|
{ value: totalSystemErr, name: '시스템오류' }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
style: {
|
||||||
|
text: grandTotal.toLocaleString()
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
$("#totalDonutCenterText").text(grandTotal.toLocaleString());
|
|
||||||
|
|
||||||
|
|
||||||
// 호출량 차트 업데이트
|
// 호출량 차트 업데이트
|
||||||
@@ -459,9 +470,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -508,9 +516,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -520,26 +525,35 @@
|
|||||||
$("input[name=searchStartDate], input[name=searchEndDate]").inputmask("9999-99-99", { 'autoUnmask': true });
|
$("input[name=searchStartDate], input[name=searchEndDate]").inputmask("9999-99-99", { 'autoUnmask': true });
|
||||||
$("input[name=searchStartTime], input[name=searchEndTime]").inputmask("99:99", { 'autoUnmask': true });
|
$("input[name=searchStartTime], input[name=searchEndTime]").inputmask("99:99", { 'autoUnmask': true });
|
||||||
|
|
||||||
// 기본값 설정 (현재 시간(분) 기준 1시간 전 ~ 현재 시간(분))
|
// 기본값 설정 (현재 시간 기준 1시간 전 정각 ~ 현재 정각)
|
||||||
var now = new Date();
|
var now = new Date();
|
||||||
var oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);
|
var endHour = now.getHours();
|
||||||
|
var startHour = endHour - 1;
|
||||||
|
var startDate, endDate;
|
||||||
|
|
||||||
function formatDate(d) {
|
if (startHour < 0) {
|
||||||
return d.getFullYear() + '-' +
|
startHour = 23;
|
||||||
String(d.getMonth() + 1).padStart(2, '0') + '-' +
|
var yesterday = new Date(now);
|
||||||
String(d.getDate()).padStart(2, '0');
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
}
|
startDate = yesterday.getFullYear() + '-' +
|
||||||
function formatTime(d) {
|
String(yesterday.getMonth() + 1).padStart(2, '0') + '-' +
|
||||||
return String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0');
|
String(yesterday.getDate()).padStart(2, '0');
|
||||||
|
endDate = now.getFullYear() + '-' +
|
||||||
|
String(now.getMonth() + 1).padStart(2, '0') + '-' +
|
||||||
|
String(now.getDate()).padStart(2, '0');
|
||||||
|
} else {
|
||||||
|
var today = getToday();
|
||||||
|
startDate = today;
|
||||||
|
endDate = today;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$("input[name=searchStartDate]").val()) {
|
if (!$("input[name=searchStartDate]").val()) {
|
||||||
$("input[name=searchStartDate]").val(formatDate(oneHourAgo));
|
$("input[name=searchStartDate]").val(startDate);
|
||||||
$("input[name=searchStartTime]").val(formatTime(oneHourAgo));
|
$("input[name=searchStartTime]").val(String(startHour).padStart(2, '0') + ':00');
|
||||||
}
|
}
|
||||||
if (!$("input[name=searchEndDate]").val()) {
|
if (!$("input[name=searchEndDate]").val()) {
|
||||||
$("input[name=searchEndDate]").val(formatDate(now));
|
$("input[name=searchEndDate]").val(endDate);
|
||||||
$("input[name=searchEndTime]").val(formatTime(now));
|
$("input[name=searchEndTime]").val(String(endHour).padStart(2, '0') + ':00');
|
||||||
}
|
}
|
||||||
|
|
||||||
initCharts();
|
initCharts();
|
||||||
@@ -614,10 +628,7 @@
|
|||||||
</table>
|
</table>
|
||||||
<!-- 도넛 차트 (상단 50%씩) -->
|
<!-- 도넛 차트 (상단 50%씩) -->
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<div class="chart" style="position:relative; padding:0;">
|
<div id="totalDonutChart" class="chart"></div>
|
||||||
<div id="totalDonutChart" style="width:100%; height:100%;"></div>
|
|
||||||
<div id="totalDonutCenterText" style="position:absolute; left:44.5%; top:55%; transform:translate(-50%,-50%); font-size:24px; font-weight:bold; color:#333; pointer-events:none; z-index:10;">0</div>
|
|
||||||
</div>
|
|
||||||
<div id="callChart" class="chart"></div>
|
<div id="callChart" class="chart"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -634,17 +645,7 @@
|
|||||||
<div id="pagerSummary"></div>
|
<div id="pagerSummary"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 상세 그리드 -->
|
|
||||||
<div style="margin-top: 20px;">
|
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
|
||||||
<div class="title" style="margin: 0;">상세 통계</div>
|
|
||||||
<button type="button" class="cssbtn" id="btn_excel_export" level="R">
|
|
||||||
<i class="material-icons">file_download</i> Excel 다운로드 (상세)
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<table id="grid"></table>
|
|
||||||
<div id="pager"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -66,27 +66,22 @@
|
|||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c} ({d}%)'
|
||||||
return params.name + ': ' + params.value.toLocaleString() + ' (' + params.percent + '%)';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
orient: 'vertical',
|
orient: 'horizontal',
|
||||||
right: 30,
|
bottom: 10,
|
||||||
top: 'middle',
|
|
||||||
data: ['성공', 'Timeout', '시스템오류']
|
data: ['성공', 'Timeout', '시스템오류']
|
||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: '총건수',
|
name: '총건수',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
radius: ['38%', '65%'],
|
radius: ['40%', '70%'],
|
||||||
center: ['44%', '55%'],
|
center: ['50%', '50%'],
|
||||||
avoidLabelOverlap: true,
|
avoidLabelOverlap: true,
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c}'
|
||||||
return params.name + ': ' + params.value.toLocaleString();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
label: {
|
label: {
|
||||||
@@ -103,6 +98,18 @@
|
|||||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center',
|
||||||
|
style: {
|
||||||
|
text: '0',
|
||||||
|
textAlign: 'center',
|
||||||
|
fill: '#333',
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,7 +119,7 @@
|
|||||||
|
|
||||||
// 호출량 차트
|
// 호출량 차트
|
||||||
var callOption = {
|
var callOption = {
|
||||||
title: { text: '호출량 추이', left: 'center', top: 10, textStyle: { fontSize: 14 } },
|
title: { text: '호출량 추이', left: 'center', textStyle: { fontSize: 14 } },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
||||||
@@ -182,9 +189,13 @@
|
|||||||
{ value: totalTimeout, name: 'Timeout' },
|
{ value: totalTimeout, name: 'Timeout' },
|
||||||
{ value: totalSystemErr, name: '시스템오류' }
|
{ value: totalSystemErr, name: '시스템오류' }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
style: {
|
||||||
|
text: grandTotal.toLocaleString()
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
$("#totalDonutCenterText").text(grandTotal.toLocaleString());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -449,9 +460,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -498,9 +506,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -573,19 +578,11 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="title" id="title">API 월별 통계</div>
|
<div class="title" id="title">API 월별 통계</div>
|
||||||
<table class="search_condition" cellspacing="0" style="table-layout:fixed;">
|
<table class="search_condition" cellspacing="0">
|
||||||
<colgroup>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
</colgroup>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>조회기간</th>
|
<th style="width:100px;">조회기간</th>
|
||||||
<td colspan="5">
|
<td colspan="3">
|
||||||
<input type="text" name="searchStartDateTime" value="${param.searchStartDateTime}" style="width:100px;" placeholder="YYYY-MM">
|
<input type="text" name="searchStartDateTime" value="${param.searchStartDateTime}" style="width:100px;" placeholder="YYYY-MM">
|
||||||
~
|
~
|
||||||
<input type="text" name="searchEndDateTime" value="${param.searchEndDateTime}" style="width:100px;" placeholder="YYYY-MM">
|
<input type="text" name="searchEndDateTime" value="${param.searchEndDateTime}" style="width:100px;" placeholder="YYYY-MM">
|
||||||
@@ -593,29 +590,31 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>API명</th>
|
<th style="width:100px;">API명</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchApiName" value="${param.searchApiName}">
|
<input type="text" name="searchApiName" value="${param.searchApiName}">
|
||||||
</td>
|
</td>
|
||||||
<th>업무구분</th>
|
<th style="width:100px;">인스턴스</th>
|
||||||
<td>
|
|
||||||
<input type="text" name="searchBizDivCode" value="${param.searchBizDivCode}">
|
|
||||||
</td>
|
|
||||||
<th>인스턴스</th>
|
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchGwInstanceId" value="${param.searchGwInstanceId}">
|
<input type="text" name="searchGwInstanceId" value="${param.searchGwInstanceId}">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>클라이언트ID</th>
|
<th style="width:100px;">업무구분</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="searchBizDivCode" value="${param.searchBizDivCode}">
|
||||||
|
</td>
|
||||||
|
<th style="width:100px;">클라이언트ID</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchClientId" value="${param.searchClientId}">
|
<input type="text" name="searchClientId" value="${param.searchClientId}">
|
||||||
</td>
|
</td>
|
||||||
<th>Inbound Adapter</th>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th style="width:100px;">Inbound Adapter</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchInboundAdapter" value="${param.searchInboundAdapter}">
|
<input type="text" name="searchInboundAdapter" value="${param.searchInboundAdapter}">
|
||||||
</td>
|
</td>
|
||||||
<th>Outbound Adapter</th>
|
<th style="width:100px;">Outbound Adapter</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchOutboundAdapter" value="${param.searchOutboundAdapter}">
|
<input type="text" name="searchOutboundAdapter" value="${param.searchOutboundAdapter}">
|
||||||
</td>
|
</td>
|
||||||
@@ -624,10 +623,7 @@
|
|||||||
</table>
|
</table>
|
||||||
<!-- 도넛 차트 (상단 50%씩) -->
|
<!-- 도넛 차트 (상단 50%씩) -->
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<div class="chart" style="position:relative; padding:0;">
|
<div id="totalDonutChart" class="chart"></div>
|
||||||
<div id="totalDonutChart" style="width:100%; height:100%;"></div>
|
|
||||||
<div id="totalDonutCenterText" style="position:absolute; left:44.5%; top:55%; transform:translate(-50%,-50%); font-size:24px; font-weight:bold; color:#333; pointer-events:none; z-index:10;">0</div>
|
|
||||||
</div>
|
|
||||||
<div id="callChart" class="chart"></div>
|
<div id="callChart" class="chart"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -66,27 +66,22 @@
|
|||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c} ({d}%)'
|
||||||
return params.name + ': ' + params.value.toLocaleString() + ' (' + params.percent + '%)';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
orient: 'vertical',
|
orient: 'horizontal',
|
||||||
right: 30,
|
bottom: 10,
|
||||||
top: 'middle',
|
|
||||||
data: ['성공', 'Timeout', '시스템오류']
|
data: ['성공', 'Timeout', '시스템오류']
|
||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: '총건수',
|
name: '총건수',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
radius: ['38%', '65%'],
|
radius: ['40%', '70%'],
|
||||||
center: ['44%', '55%'],
|
center: ['50%', '50%'],
|
||||||
avoidLabelOverlap: true,
|
avoidLabelOverlap: true,
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
formatter: function (params) {
|
formatter: '{b}: {c}'
|
||||||
return params.name + ': ' + params.value.toLocaleString();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
label: {
|
label: {
|
||||||
@@ -103,6 +98,18 @@
|
|||||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center',
|
||||||
|
style: {
|
||||||
|
text: '0',
|
||||||
|
textAlign: 'center',
|
||||||
|
fill: '#333',
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,7 +119,7 @@
|
|||||||
|
|
||||||
// 호출량 차트
|
// 호출량 차트
|
||||||
var callOption = {
|
var callOption = {
|
||||||
title: { text: '호출량 추이', left: 'center', top: 10, textStyle: { fontSize: 14 } },
|
title: { text: '호출량 추이', left: 'center', textStyle: { fontSize: 14 } },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
axisPointer: { type: 'cross', label: { backgroundColor: '#6a7985' } }
|
||||||
@@ -184,9 +191,13 @@
|
|||||||
{ value: totalTimeout, name: 'Timeout' },
|
{ value: totalTimeout, name: 'Timeout' },
|
||||||
{ value: totalSystemErr, name: '시스템오류' }
|
{ value: totalSystemErr, name: '시스템오류' }
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
graphic: [{
|
||||||
|
style: {
|
||||||
|
text: grandTotal.toLocaleString()
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
$("#totalDonutCenterText").text(grandTotal.toLocaleString());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -425,9 +436,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -474,9 +482,6 @@
|
|||||||
for (var i = 0; i < colModel.length; i++) {
|
for (var i = 0; i < colModel.length; i++) {
|
||||||
$(this).setColProp(colModel[i].name, { sortable: false });
|
$(this).setColProp(colModel[i].name, { sortable: false });
|
||||||
}
|
}
|
||||||
// 조회(reloadGrid) 시 컬럼 폭이 고정폭(shrinkToFit:false)으로 남아
|
|
||||||
// 실제 컨테이너 폭과 어긋나 가로 스크롤이 생기는 것을 방지
|
|
||||||
$(this).jqGrid('setGridWidth', $('#content_middle').width(), true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -544,48 +549,42 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="title" id="title">API 연간 통계</div>
|
<div class="title" id="title">API 연간 통계</div>
|
||||||
<table class="search_condition" cellspacing="0" style="table-layout:fixed;">
|
<table class="search_condition" cellspacing="0">
|
||||||
<colgroup>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
<col style="width:150px;">
|
|
||||||
<col>
|
|
||||||
</colgroup>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>조회기간</th>
|
<th style="width:100px;">조회기간</th>
|
||||||
<td colspan="5">
|
<td colspan="3">
|
||||||
<input type="text" name="searchStartDateTime" value="${param.searchStartDateTime}" style="width:100px;" placeholder="YYYY">
|
<input type="text" name="searchStartDateTime" value="${param.searchStartDateTime}" style="width:100px;" placeholder="YYYY">
|
||||||
~
|
~
|
||||||
<input type="text" name="searchEndDateTime" value="${param.searchEndDateTime}" style="width:100px;" placeholder="YYYY">
|
<input type="text" name="searchEndDateTime" value="${param.searchEndDateTime}" style="width:100px;" placeholder="YYYY">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>API명</th>
|
<th style="width:100px;">API명</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchApiName" value="${param.searchApiName}">
|
<input type="text" name="searchApiName" value="${param.searchApiName}">
|
||||||
</td>
|
</td>
|
||||||
<th>업무구분</th>
|
<th style="width:100px;">인스턴스</th>
|
||||||
<td>
|
|
||||||
<input type="text" name="searchBizDivCode" value="${param.searchBizDivCode}">
|
|
||||||
</td>
|
|
||||||
<th>인스턴스</th>
|
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchGwInstanceId" value="${param.searchGwInstanceId}">
|
<input type="text" name="searchGwInstanceId" value="${param.searchGwInstanceId}">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>클라이언트ID</th>
|
<th style="width:100px;">업무구분</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="searchBizDivCode" value="${param.searchBizDivCode}">
|
||||||
|
</td>
|
||||||
|
<th style="width:100px;">클라이언트ID</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchClientId" value="${param.searchClientId}">
|
<input type="text" name="searchClientId" value="${param.searchClientId}">
|
||||||
</td>
|
</td>
|
||||||
<th>Inbound Adapter</th>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th style="width:100px;">Inbound Adapter</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchInboundAdapter" value="${param.searchInboundAdapter}">
|
<input type="text" name="searchInboundAdapter" value="${param.searchInboundAdapter}">
|
||||||
</td>
|
</td>
|
||||||
<th>Outbound Adapter</th>
|
<th style="width:100px;">Outbound Adapter</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="searchOutboundAdapter" value="${param.searchOutboundAdapter}">
|
<input type="text" name="searchOutboundAdapter" value="${param.searchOutboundAdapter}">
|
||||||
</td>
|
</td>
|
||||||
@@ -594,10 +593,7 @@
|
|||||||
</table>
|
</table>
|
||||||
<!-- 도넛 차트 (상단 50%씩) -->
|
<!-- 도넛 차트 (상단 50%씩) -->
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<div class="chart" style="position:relative; padding:0;">
|
<div id="totalDonutChart" class="chart"></div>
|
||||||
<div id="totalDonutChart" style="width:100%; height:100%;"></div>
|
|
||||||
<div id="totalDonutCenterText" style="position:absolute; left:44.5%; top:55%; transform:translate(-50%,-50%); font-size:24px; font-weight:bold; color:#333; pointer-events:none; z-index:10;">0</div>
|
|
||||||
</div>
|
|
||||||
<div id="callChart" class="chart"></div>
|
<div id="callChart" class="chart"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -222,7 +222,7 @@
|
|||||||
$("input[name=searchStartDate], input[name=searchEndDate]").datepicker();
|
$("input[name=searchStartDate], input[name=searchEndDate]").datepicker();
|
||||||
|
|
||||||
var today = getToday();
|
var today = getToday();
|
||||||
var startDate = today.substring(0,6)+"01";
|
var startDate = today;
|
||||||
var endDate = today;
|
var endDate = today;
|
||||||
|
|
||||||
|
|
||||||
@@ -234,7 +234,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
list();
|
list();
|
||||||
search();
|
|
||||||
|
|
||||||
resizeJqGridWidth('grid', 'content_middle', '1200');
|
resizeJqGridWidth('grid', 'content_middle', '1200');
|
||||||
|
|
||||||
@@ -242,10 +241,6 @@
|
|||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("input[name=searchType]").click(function() {
|
|
||||||
search();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btn_excel").click(function() {
|
$("#btn_excel").click(function() {
|
||||||
exportToExcel();
|
exportToExcel();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -76,15 +76,6 @@
|
|||||||
return cellvalue.substring(1, 4);
|
return cellvalue.substring(1, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
function apiStatusFormatter(cellvalue, options, rowObject) {
|
|
||||||
switch (cellvalue) {
|
|
||||||
case 'E': return '장애';
|
|
||||||
case 'D': return '지연';
|
|
||||||
case 'C': return '점검';
|
|
||||||
default: return '정상';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function list() {
|
function list() {
|
||||||
detail()
|
detail()
|
||||||
var gridPostData = getSearchForJqgrid("cmd", "LIST"); //jqgrid에서는 object 로
|
var gridPostData = getSearchForJqgrid("cmd", "LIST"); //jqgrid에서는 object 로
|
||||||
@@ -99,7 +90,6 @@
|
|||||||
'API FULL PATH',
|
'API FULL PATH',
|
||||||
'요청',
|
'요청',
|
||||||
'응답',
|
'응답',
|
||||||
'상태',
|
|
||||||
'작성자',
|
'작성자',
|
||||||
'가상응답여부',
|
'가상응답여부',
|
||||||
'변경일시(*)',
|
'변경일시(*)',
|
||||||
@@ -109,12 +99,11 @@
|
|||||||
{name: 'eaiSvcName', align: 'left', width: '100', sortable: true},
|
{name: 'eaiSvcName', align: 'left', width: '100', sortable: true},
|
||||||
{name: 'eaiSvcDesc', align: 'left', sortable: false},
|
{name: 'eaiSvcDesc', align: 'left', sortable: false},
|
||||||
{name: 'apiFullPath', align: 'left', sortable: false},
|
{name: 'apiFullPath', align: 'left', sortable: false},
|
||||||
{name: 'fromAdapter', align: 'center', width: '30', formatter: adapterNameShortFormatter, sortable: false},
|
{name: 'fromAdapter', align: 'center', width: '40', formatter: adapterNameShortFormatter, sortable: false},
|
||||||
{name: 'toAdapter', align: 'center', width: '30', formatter: adapterNameShortFormatter, sortable: false},
|
{name: 'toAdapter', align: 'center', width: '40', formatter: adapterNameShortFormatter, sortable: false},
|
||||||
{name: 'statusCode', align: 'center', width: '30', formatter: apiStatusFormatter, sortable: false},
|
{name: 'author', align: 'center', width: '60', sortable: false},
|
||||||
{name: 'author', align: 'center', width: '40', sortable: false},
|
|
||||||
{name : 'simYn', align : 'center' , width:'40', hidden: true },
|
{name : 'simYn', align : 'center' , width:'40', hidden: true },
|
||||||
{name : 'lastModifiedDate', align : 'center' , width:'60', sortable: true},
|
{name : 'lastModifiedDate', align : 'center' , width:'40', sortable: true},
|
||||||
{name: 'syncAsyncType', align: 'center', width: '40', hidden: true},
|
{name: 'syncAsyncType', align: 'center', width: '40', hidden: true},
|
||||||
],
|
],
|
||||||
jsonReader: {
|
jsonReader: {
|
||||||
|
|||||||
@@ -77,31 +77,13 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* iframe 모달(showModal) 콘텐츠 패딩 제거 — iframe 이 다이얼로그 폭을 최대한 사용해 내부 가로스크롤 방지 */
|
|
||||||
.ui-dialog .ui-dialog-content { padding: 0 !important; }
|
|
||||||
|
|
||||||
/* OpenAPI Spec 버튼 상태 색상 (PTL_API_SPEC_INFO 기준) */
|
|
||||||
#btn_openapi_spec.spec-exists { background:#ffe08a !important; border-color:#f0c040 !important; color:#5a4600 !important; }
|
|
||||||
#btn_openapi_spec.spec-public { background:#b8e6a0 !important; border-color:#7cc257 !important; color:#2c4a15 !important; }
|
|
||||||
/* 호버 상태 안내 레이어 */
|
|
||||||
#specStatusLayer {
|
|
||||||
position: fixed; z-index: 100000; display: none;
|
|
||||||
background: rgba(30,30,30,0.92); color: #fff;
|
|
||||||
padding: 8px 12px; border-radius: 6px;
|
|
||||||
font-size: 12px; line-height: 1.6; max-width: 340px;
|
|
||||||
white-space: pre-line; pointer-events: none;
|
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script language="javascript" >
|
<script language="javascript" >
|
||||||
var isDetail = false;
|
var isDetail = false;
|
||||||
var url ='<c:url value="/onl/transaction/apim/apiInterfaceMan.json" />';
|
var url ='<c:url value="/onl/transaction/apim/apiInterfaceMan.json" />';
|
||||||
const url_excel ='<c:url value="/onl/transaction/apim/apiInterfaceMan.excel" />';
|
const url_excel ='<c:url value="/onl/transaction/apim/apiInterfaceMan.excel" />';
|
||||||
var url_spec = '<c:url value="/onl/transaction/apim/apiSpecMan.view"/>';
|
var url_spec = '<c:url value="/onl/transaction/apim/apiSpecMan.view"/>';
|
||||||
var url_openapi_spec = '<c:url value="/onl/transaction/apim/djbApiSpecMan.view"/>';
|
|
||||||
var url_openapi_spec_json = '<c:url value="/onl/transaction/apim/djbApiSpecMan.json"/>';
|
|
||||||
var returnUrl ;
|
var returnUrl ;
|
||||||
let headerValues = [];
|
let headerValues = [];
|
||||||
let headerNames = [];
|
let headerNames = [];
|
||||||
@@ -316,7 +298,7 @@
|
|||||||
if(!isStandardMessage){
|
if(!isStandardMessage){
|
||||||
$(adapterSettings.adapterUrlId).text(adapterInfo.urlPath);
|
$(adapterSettings.adapterUrlId).text(adapterInfo.urlPath);
|
||||||
} else {
|
} else {
|
||||||
//$(adapterSettings.methodSelectId).val('');
|
$(adapterSettings.methodSelectId).val('');
|
||||||
$(adapterSettings.restPathInputId).val('');
|
$(adapterSettings.restPathInputId).val('');
|
||||||
$(adapterSettings.adapterUrlId).text('');
|
$(adapterSettings.adapterUrlId).text('');
|
||||||
}
|
}
|
||||||
@@ -504,7 +486,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(data.errResponseTransform != null && data.errResponseTransform != '' && data.errTransformYn == 'Y') {
|
if(data.errResponseTransform != null && data.errResponseTransform != '' && data.errTransformYn == 'Y') {
|
||||||
$('#toggleTransformYn').bootstrapToggle('on');
|
|
||||||
$('#toggleErrTransformYn').bootstrapToggle('on');
|
$('#toggleErrTransformYn').bootstrapToggle('on');
|
||||||
$('#rowErrResponseTransform').show();
|
$('#rowErrResponseTransform').show();
|
||||||
} else {
|
} else {
|
||||||
@@ -554,8 +535,6 @@
|
|||||||
|
|
||||||
$('#inboundHttpMethod').trigger('change');
|
$('#inboundHttpMethod').trigger('change');
|
||||||
$('#outboundHttpMethod').trigger('change');
|
$('#outboundHttpMethod').trigger('change');
|
||||||
|
|
||||||
applyOpenApiSpecStatus(); // OpenAPI Spec 버튼 색상(PTL_API_SPEC_INFO)
|
|
||||||
},
|
},
|
||||||
error:function(e){
|
error:function(e){
|
||||||
alert(e.responseText);
|
alert(e.responseText);
|
||||||
@@ -892,10 +871,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
var postData = $('#ajaxForm').serializeArray();
|
var postData = $('#ajaxForm').serializeArray();
|
||||||
|
|
||||||
console.log('modify', postData);
|
|
||||||
console.log('method', $('#inboundHttpMethod').val());
|
|
||||||
|
|
||||||
if (isDetail){
|
if (isDetail){
|
||||||
postData.push({ name: "cmd" , value:"UPDATE"});
|
postData.push({ name: "cmd" , value:"UPDATE"});
|
||||||
}else{
|
}else{
|
||||||
@@ -1013,64 +988,6 @@
|
|||||||
showModal(popupUrl, args, 1200, 800);
|
showModal(popupUrl, args, 1200, 800);
|
||||||
}
|
}
|
||||||
|
|
||||||
// v2: OpenAPI Spec — 기본은 모달(iframe), Shift+클릭은 새 창.
|
|
||||||
// 컨텍스트는 전부 query string 으로 전달(dialogArguments 미사용).
|
|
||||||
function showOpenApiSpecPopup(e) {
|
|
||||||
var eaiSvcName = getFullSvcName();
|
|
||||||
var eaiSvcDesc = $('#eaiSvcDesc').val();
|
|
||||||
var apipath = $('#apiFullPath').val(); // METHOD|URL ('|' 포함 → 인코딩 필수)
|
|
||||||
var contentType = $('#contentType').val();
|
|
||||||
var baseUrl = url_openapi_spec
|
|
||||||
+ '?cmd=DETAIL'
|
|
||||||
+ '&eaiSvcName=' + encodeURIComponent(eaiSvcName)
|
|
||||||
+ '&apipath=' + encodeURIComponent(apipath)
|
|
||||||
+ '&eaiSvcDesc=' + encodeURIComponent(eaiSvcDesc)
|
|
||||||
+ '&contentType=' + encodeURIComponent(contentType);
|
|
||||||
if (e && e.shiftKey) {
|
|
||||||
// Shift+클릭: 새 창. window.open 은 serviceType/menuId 자동 부착 안 되므로 직접 붙임.
|
|
||||||
window.open(urlAddServiceType(baseUrl + '&menuId=' + encodeURIComponent(getMenuId())), '_blank');
|
|
||||||
} else {
|
|
||||||
// 기본: 모달 + iframe. showModal 이 serviceType/menuId/pop 을 자동 부착.
|
|
||||||
// 콘텐츠 고정폭 1600 + 다이얼로그 chrome(패딩/보더 ~40px) 때문에 iframe 내부폭이 1600 미만이면 가로스크롤 발생.
|
|
||||||
// 뷰포트 내에서 최대한 크게 열어(캡 1720) iframe 내부폭이 1600 이상 확보되게 한다.
|
|
||||||
var vw = $(window).width(), vh = $(window).height();
|
|
||||||
var modalW = Math.min(vw - 12, 1720);
|
|
||||||
var modalH = Math.min(vh - 20, 900);
|
|
||||||
// 스펙 편집 모달 닫힘 시 버튼 색상 재조회(공개여부/등록여부 변경 반영)
|
|
||||||
showModal(baseUrl, { title: 'OpenAPI Spec' }, modalW, modalH, function(){ applyOpenApiSpecStatus(); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenAPI Spec 버튼 색상 = PTL_API_SPEC_INFO(api_id = getFullSvcName()) 상태.
|
|
||||||
// - 미등록: 기본색 - 등록·비공개(display_yn≠Y): 노랑 - 등록·공개(display_yn=Y): 하늘
|
|
||||||
function applyOpenApiSpecStatus() {
|
|
||||||
var $btn = $('#btn_openapi_spec');
|
|
||||||
$btn.removeClass('spec-exists spec-public').data('specMsg', '');
|
|
||||||
var eaiSvcName = getFullSvcName();
|
|
||||||
if (!eaiSvcName || eaiSvcName.length < 2) return;
|
|
||||||
$.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: url_openapi_spec_json,
|
|
||||||
dataType: 'json',
|
|
||||||
data: { cmd: 'SPEC_STATUS', eaiSvcName: eaiSvcName },
|
|
||||||
success: function(res) {
|
|
||||||
var exists = res && (res.exists === true || res.exists === 'true');
|
|
||||||
var isPublic = res && (res.displayYn === 'Y');
|
|
||||||
var msg;
|
|
||||||
if (!exists) {
|
|
||||||
msg = 'OpenAPI Spec 미등록\n버튼을 눌러 스펙을 생성/편집하세요.';
|
|
||||||
} else if (isPublic) {
|
|
||||||
$btn.addClass('spec-public');
|
|
||||||
msg = 'OpenAPI Spec 등록됨 · 포탈 공개중 (display_yn = Y)\n포탈 메인/문서에 노출됩니다.';
|
|
||||||
} else {
|
|
||||||
$btn.addClass('spec-exists');
|
|
||||||
msg = 'OpenAPI Spec 등록됨 · 비공개 (display_yn ≠ Y)\n포탈에는 노출되지 않습니다.';
|
|
||||||
}
|
|
||||||
$btn.data('specMsg', msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
makeValidate();
|
makeValidate();
|
||||||
// var bootstrapButton = $.fn.button.noConflict()
|
// var bootstrapButton = $.fn.button.noConflict()
|
||||||
@@ -1085,31 +1002,9 @@
|
|||||||
}
|
}
|
||||||
init(url,key,detail);
|
init(url,key,detail);
|
||||||
|
|
||||||
// v1: 기존 API 스펙 (모달) — 기능 비교용 복원
|
|
||||||
$("#btn_api_spec").click(function() {
|
$("#btn_api_spec").click(function() {
|
||||||
showApiSpecPopup();
|
showApiSpecPopup();
|
||||||
});
|
});
|
||||||
// v2: 신규 OpenAPI Spec (새 탭)
|
|
||||||
$("#btn_openapi_spec").click(function(e) {
|
|
||||||
showOpenApiSpecPopup(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
// OpenAPI Spec 버튼 호버 시 현재 상태 안내 레이어
|
|
||||||
if ($('#specStatusLayer').length === 0) {
|
|
||||||
$('body').append('<div id="specStatusLayer"></div>');
|
|
||||||
}
|
|
||||||
$("#btn_openapi_spec")
|
|
||||||
.on('mouseenter', function() {
|
|
||||||
var msg = $(this).data('specMsg');
|
|
||||||
if (!msg) return;
|
|
||||||
$('#specStatusLayer').text(msg).css('display', 'block');
|
|
||||||
})
|
|
||||||
.on('mousemove', function(e) {
|
|
||||||
$('#specStatusLayer').css({ left: (e.clientX + 14) + 'px', top: (e.clientY + 16) + 'px' });
|
|
||||||
})
|
|
||||||
.on('mouseleave', function() {
|
|
||||||
$('#specStatusLayer').hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btn_modify").click(modifyApi);
|
$("#btn_modify").click(modifyApi);
|
||||||
$("#btn_delete").click(function(){
|
$("#btn_delete").click(function(){
|
||||||
@@ -1608,10 +1503,7 @@
|
|||||||
<button type="button" class="cssbtn" id="btn_json_export" level="R" status="DETAIL,NEW"><i class="material-icons">download</i> <%=localeMessage.getString("button.exportJson")%></button></button>
|
<button type="button" class="cssbtn" id="btn_json_export" level="R" status="DETAIL,NEW"><i class="material-icons">download</i> <%=localeMessage.getString("button.exportJson")%></button></button>
|
||||||
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL"><i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %></button>
|
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL"><i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %></button>
|
||||||
<button type="button" class="cssbtn" id="btn_modify" level="R" status="DETAIL,NEW"><i class="material-icons">save</i> <%= localeMessage.getString("button.modify") %></button>
|
<button type="button" class="cssbtn" id="btn_modify" level="R" status="DETAIL,NEW"><i class="material-icons">save</i> <%= localeMessage.getString("button.modify") %></button>
|
||||||
<!-- v1: 기존 API 스펙 (모달) — 기능 비교용 복원 -->
|
<button type="button" class="cssbtn" id="btn_api_spec" level="R" status="DETAIL,NEW"><i class="material-icons">description</i> API 스펙</button>
|
||||||
<button type="button" class="cssbtn" id="btn_api_spec" level="R" status="DETAIL"><i class="material-icons">description</i> API 스펙(삭제예정)</button>
|
|
||||||
<!-- v2: 신규 OpenAPI Spec (새 탭) -->
|
|
||||||
<button type="button" class="cssbtn" id="btn_openapi_spec" level="R" status="DETAIL"><i class="material-icons">api</i> OpenAPI Spec</button>
|
|
||||||
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="title" id="title" style="font-size:1.4em">${rmsMenuName}</div>
|
<div class="title" id="title" style="font-size:1.4em">${rmsMenuName}</div>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</style>
|
</style>
|
||||||
<script language="javascript">
|
<script language="javascript">
|
||||||
var url = '<c:url value="/onl/transaction/apim/apiSpecMan.json" />';
|
var url = '<c:url value="/onl/transaction/apim/apiSpecMan.json" />';
|
||||||
var url_org ='<c:url value="/onl/transaction/apim/apiSpecMan.view" />';
|
var url_org ='<c:url value="/onl/transaction/apim/apiSpecManPopup.view" />';
|
||||||
var isDetail = false;
|
var isDetail = false;
|
||||||
var sampleRequestEditor, sampleResponseEditor, testbedSpecEditor;
|
var sampleRequestEditor, sampleResponseEditor, testbedSpecEditor;
|
||||||
|
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8"%>
|
|
||||||
<%@ page import="java.io.*"%>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
%>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>API 그룹 선택</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
||||||
<jsp:include page="/jsp/common/include/css_custom.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
|
||||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
|
||||||
<script language="javascript">
|
|
||||||
var url = '<c:url value="/onl/apim/apigroup/apiGroupMan.json" />';
|
|
||||||
|
|
||||||
function search() {
|
|
||||||
var postData = getSearchForJqgrid("cmd", "LIST");
|
|
||||||
$("#grid").setGridParam({url: url, postData: postData, page: 1}).trigger("reloadGrid");
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
var urlParams = new URLSearchParams(window.location.search);
|
|
||||||
var selectedGroupIds = urlParams.get("selectedGroupIds");
|
|
||||||
|
|
||||||
if (selectedGroupIds) {
|
|
||||||
selectedGroupIds = selectedGroupIds.split(','); // 콤마로 구분된 ID들을 배열로 변환
|
|
||||||
} else {
|
|
||||||
selectedGroupIds = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#grid').jqGrid({
|
|
||||||
datatype: "json",
|
|
||||||
mtype: 'POST',
|
|
||||||
url: url,
|
|
||||||
postData: getSearchForJqgrid("cmd", "LIST"),
|
|
||||||
colNames: ['API 그룹 ID', 'API 그룹 명', '설명'],
|
|
||||||
colModel: [
|
|
||||||
{name: 'id', hidden: true},
|
|
||||||
{name: 'groupName', align: 'center', width: "180"},
|
|
||||||
{name: 'groupDesc', align: 'left', width: "200"}
|
|
||||||
],
|
|
||||||
jsonReader: {
|
|
||||||
repeatitems: false
|
|
||||||
},
|
|
||||||
pager: $('#pager'),
|
|
||||||
page: '${param.page}',
|
|
||||||
rowNum: '${rmsDefaultRowNum}',
|
|
||||||
autoheight: true,
|
|
||||||
height: 'auto',
|
|
||||||
width: 410,
|
|
||||||
autowidth: false,
|
|
||||||
viewrecords: true,
|
|
||||||
shrinkToFit: false,
|
|
||||||
multiselect: true,
|
|
||||||
multiboxonly: false,
|
|
||||||
loadComplete: function(data) {
|
|
||||||
var $grid = $(this);
|
|
||||||
$.each($grid.getDataIDs(), function(_, id) {
|
|
||||||
var rowData = $grid.getRowData(id);
|
|
||||||
if ($.inArray(rowData.id, selectedGroupIds) !== -1) {
|
|
||||||
$grid.jqGrid('setSelection', id, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btn_search").click(search);
|
|
||||||
|
|
||||||
$("#btn_save").click(function() {
|
|
||||||
var selectedRows = $('#grid').getGridParam('selarrrow');
|
|
||||||
|
|
||||||
var selectedGroups = [];
|
|
||||||
if (selectedRows.length > 0) {
|
|
||||||
selectedGroups = selectedRows.map(function(rowid) {
|
|
||||||
var rowData = $('#grid').getRowData(rowid);
|
|
||||||
return {
|
|
||||||
id: rowData.id,
|
|
||||||
groupName: rowData.groupName
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 부모 창의 selectApiGroup 함수 호출
|
|
||||||
if (window.parent && typeof window.parent.selectApiGroup === "function") {
|
|
||||||
window.parent.selectApiGroup(selectedGroups);
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btn_close").click(function () {
|
|
||||||
window.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 검색어 입력 후 엔터 키 처리
|
|
||||||
$("input[name=searchGroupName]").keydown(function(key) {
|
|
||||||
if (key.keyCode == 13) {
|
|
||||||
search();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="popup_box">
|
|
||||||
<div class="search_wrap">
|
|
||||||
<button type="button" class="cssbtn" id="btn_save" level="W">
|
|
||||||
<i class="material-icons">save</i> <%= localeMessage.getString("button.save") %>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="cssbtn" id="btn_search" level="R">
|
|
||||||
<i class="material-icons">search</i> <%= localeMessage.getString("button.search") %>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="cssbtn" id="btn_close" level="R" status="DETAIL"><i
|
|
||||||
class="material-icons">close</i> <%= localeMessage.getString("button.close") %>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="title"></div>
|
|
||||||
<table class="search_condition" cellspacing="0">
|
|
||||||
<tr>
|
|
||||||
<th style="width:80px;">API 그룹 명</th>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="searchGroupName" value="${param.searchGroupName}">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<table id="grid"></table>
|
|
||||||
<div id="pager"></div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
|
||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
|
||||||
<%
|
|
||||||
response.setHeader("Pragma", "No-cache");
|
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
|
||||||
response.setHeader("Expires", "0");
|
|
||||||
%>
|
|
||||||
<!doctype html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=1600" />
|
|
||||||
<title>OpenAPI Spec 에디터</title>
|
|
||||||
|
|
||||||
<%-- Tailwind (벤더된 Play CDN JS, 오프라인) --%>
|
|
||||||
<script src="<c:url value='/plugins/openapi/tailwind.js'/>"></script>
|
|
||||||
<script>
|
|
||||||
tailwind.config = { theme: { extend: { colors: { brand: {
|
|
||||||
50:'#eff6ff', 100:'#dbeafe', 500:'#3b82f6', 600:'#2563eb', 700:'#1d4ed8'
|
|
||||||
} } } } };
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<%-- Swagger UI 5 (벤더) --%>
|
|
||||||
<link rel="stylesheet" href="<c:url value='/plugins/swaggerUI/swagger-ui.css'/>" />
|
|
||||||
<script src="<c:url value='/plugins/swaggerUI/swagger-ui-bundle.js'/>"></script>
|
|
||||||
<script src="<c:url value='/plugins/swaggerUI/swagger-ui-standalone-preset.js'/>"></script>
|
|
||||||
<script src="<c:url value='/plugins/swaggerUI/djb-swagger-i18n.js'/>" charset="UTF-8"></script>
|
|
||||||
|
|
||||||
<%-- js-yaml (벤더) --%>
|
|
||||||
<script src="<c:url value='/plugins/openapi/js-yaml.min.js'/>"></script>
|
|
||||||
|
|
||||||
<%-- CodeMirror (YAML 편집기 — Monaco 대체, admin addon) --%>
|
|
||||||
<link rel="stylesheet" href="<c:url value='/addon/codemirror/lib/codemirror.css'/>" />
|
|
||||||
<script src="<c:url value='/addon/codemirror/lib/codemirror.js'/>"></script>
|
|
||||||
<script src="<c:url value='/addon/codemirror/mode/yaml/yaml.js'/>"></script>
|
|
||||||
<script src="<c:url value='/addon/codemirror/mode/javascript/javascript.js'/>"></script>
|
|
||||||
|
|
||||||
<%-- jQuery + Summernote(lite, 무-Bootstrap) — 설명 리치 에디터 --%>
|
|
||||||
<link rel="stylesheet" href="<c:url value='/addon/summernote/summernote-lite.css'/>" />
|
|
||||||
<%-- 개발자포탈과 동일한 에디터 콘텐츠 스타일(.editor-content, Noto Sans KR 16px) --%>
|
|
||||||
<link rel="stylesheet" href="<c:url value='/js/djb/apispec/editor-content.css'/>" />
|
|
||||||
<script src="<c:url value='/js/jquery-1.12.1.min.js'/>"></script>
|
|
||||||
<script src="<c:url value='/addon/summernote/summernote-lite.min.js'/>"></script>
|
|
||||||
<script src="<c:url value='/addon/summernote/lang/summernote-ko-KR.js'/>"></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="<c:url value='/js/djb/apispec/styles.css'/>" />
|
|
||||||
<style>
|
|
||||||
/* 페이지 자체 세로 스크롤 제거 — 뷰포트 고정, 내부 패널만 스크롤 */
|
|
||||||
html, body { height: 100%; margin: 0; overflow-x: auto; overflow-y: hidden; }
|
|
||||||
#djb-wrap { height: 100vh; display: flex; flex-direction: column; }
|
|
||||||
#djb-wrap > header, #djb-wrap > nav { flex: 0 0 auto; }
|
|
||||||
#body { flex: 1 1 auto; min-height: 0 !important; overflow: hidden; }
|
|
||||||
#form-panel { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
|
|
||||||
#form-content { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
|
|
||||||
#preview-panel { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
|
|
||||||
#preview-swagger, #preview-monaco { flex: 1 1 auto; min-height: 0; height: auto !important; overflow: auto; }
|
|
||||||
#preview-monaco .CodeMirror { height: 100%; }
|
|
||||||
/* 패널 내부 sticky 는 flex 행으로 (스크롤 컨테이너는 form-content / preview) */
|
|
||||||
#form-panel > .sticky, #preview-panel > .sticky { position: static !important; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.DJB_CTX = {
|
|
||||||
eaiSvcName: "${param.eaiSvcName}",
|
|
||||||
apiName: "${param.eaiSvcDesc}",
|
|
||||||
detailUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.json'/>?cmd=DETAIL_SPEC&serviceType=APIGW",
|
|
||||||
saveUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.json'/>?cmd=SAVE&serviceType=APIGW",
|
|
||||||
swaggerBase: "<c:url value='/plugins/swaggerUI/'/>",
|
|
||||||
gwAddress: "${gwAddress}",
|
|
||||||
useProxy: ${useProxy},
|
|
||||||
tokenUseProxy: ${tokenUseProxy},
|
|
||||||
exportEnabled: ${exportEnabled},
|
|
||||||
orgPopupUrl: "<c:url value='/onl/transaction/apim/apiSpecMan.view'/>",
|
|
||||||
groupPopupUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.view'/>?cmd=GROUP_POPUP",
|
|
||||||
jsonUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.json'/>"
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body class="bg-slate-50 text-slate-800 antialiased" style="min-width:1600px;">
|
|
||||||
|
|
||||||
<div id="djb-wrap" class="mx-auto" style="width:1600px;">
|
|
||||||
|
|
||||||
<!-- ===== Header ===== -->
|
|
||||||
<header class="h-14 flex items-center justify-between px-6 bg-white border-b border-slate-200 sticky top-0 z-30">
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<div class="font-semibold text-slate-900">OpenAPI Spec 에디터</div>
|
|
||||||
<span class="text-slate-300">|</span>
|
|
||||||
<span class="text-sm text-slate-500">인터페이스:</span>
|
|
||||||
<span class="text-sm font-medium text-slate-800" id="hdr-project-name">${param.eaiSvcName}</span>
|
|
||||||
<span class="ml-2 px-2 py-0.5 text-[11px] rounded-full bg-slate-100 text-slate-600 border border-slate-200" id="hdr-version">v1.0.0</span>
|
|
||||||
<span id="hdr-source" class="hidden ml-1 px-2 py-0.5 text-[11px] rounded-full bg-emerald-50 text-emerald-700 border border-emerald-200"></span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<button id="btn-newwin" class="hidden px-3 py-1.5 text-sm rounded border border-slate-300 bg-white hover:bg-slate-50">새창으로 띄우기</button>
|
|
||||||
<button id="btn-regen" class="px-3 py-1.5 text-sm rounded border border-slate-300 bg-white hover:bg-slate-50">자동 생성(초기화)</button>
|
|
||||||
<button id="btn-save" class="px-3 py-1.5 text-sm rounded bg-emerald-600 text-white hover:bg-emerald-700">저장</button>
|
|
||||||
<%-- 내보내기 버튼은 PTL_PROPERTY(djb.openapi.export.enabled=true) 일 때만 노출. 기본 미노출. --%>
|
|
||||||
<c:if test="${exportEnabled}">
|
|
||||||
<div class="relative">
|
|
||||||
<button id="btn-export" class="px-3 py-1.5 text-sm rounded bg-brand-600 text-white hover:bg-brand-700">내보내기 ▾</button>
|
|
||||||
<div id="export-menu" class="hidden absolute right-0 mt-1 w-44 bg-white border border-slate-200 rounded shadow-lg z-40">
|
|
||||||
<button data-export="yaml" class="block w-full text-left px-3 py-2 text-sm hover:bg-slate-50">YAML 다운로드</button>
|
|
||||||
<button data-export="json" class="block w-full text-left px-3 py-2 text-sm hover:bg-slate-50">JSON 다운로드</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</c:if>
|
|
||||||
<button id="btn-close" class="px-3 py-1.5 text-sm rounded border border-slate-300 bg-white hover:bg-slate-50">닫기</button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- ===== Stepper ===== -->
|
|
||||||
<nav class="bg-white border-b border-slate-200 sticky z-20" style="top:56px;">
|
|
||||||
<div class="h-1 bg-slate-100">
|
|
||||||
<div id="stepper-progress" class="h-1 bg-brand-500 transition-all duration-300" style="width:16.66%"></div>
|
|
||||||
</div>
|
|
||||||
<ol id="stepper" class="grid grid-cols-5 px-2"></ol>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- ===== Body ===== -->
|
|
||||||
<main id="body" class="flex" style="min-height: calc(100vh - 56px - 72px);">
|
|
||||||
<section id="form-panel" class="bg-white border-r border-slate-200 transition-all duration-300" style="width:960px;">
|
|
||||||
<div class="flex items-center justify-between px-6 py-3 border-b border-slate-100 sticky bg-white z-10" style="top:128px;">
|
|
||||||
<div class="flex items-baseline gap-3">
|
|
||||||
<span class="text-xs uppercase tracking-wide text-slate-400">Step <span id="form-step-num">1</span> / 5</span>
|
|
||||||
<h2 class="text-base font-semibold text-slate-800" id="form-step-title">기본정보</h2>
|
|
||||||
</div>
|
|
||||||
<button id="btn-toggle-preview-from-form" class="hidden text-xs px-2 py-1 rounded border border-slate-200 text-slate-600 hover:bg-slate-50">▶ 미리보기 다시 열기</button>
|
|
||||||
</div>
|
|
||||||
<div id="form-content" class="px-6 py-5"></div>
|
|
||||||
<div class="sticky bottom-0 bg-white border-t border-slate-200 px-6 py-3 flex items-center justify-between">
|
|
||||||
<button id="btn-prev" class="px-4 py-2 text-sm rounded border border-slate-300 bg-white hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed">◀ 이전</button>
|
|
||||||
<div class="text-xs text-slate-500" id="footer-hint">필수 항목을 채우고 다음 단계로 이동하세요</div>
|
|
||||||
<button id="btn-next" class="px-4 py-2 text-sm rounded bg-brand-600 text-white hover:bg-brand-700">다음 ▶</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<aside id="preview-panel" class="bg-slate-50 transition-all duration-300" style="width:640px;">
|
|
||||||
<div class="flex items-center justify-between px-4 py-2 border-b border-slate-200 bg-white sticky z-10" style="top:128px;">
|
|
||||||
<div class="flex items-center gap-1">
|
|
||||||
<button data-ptab="swagger" class="preview-tab px-3 py-1.5 text-sm rounded-t border-b-2 border-brand-600 text-brand-700 font-medium">Swagger UI</button>
|
|
||||||
<button data-ptab="yaml-ro" class="preview-tab px-3 py-1.5 text-sm rounded-t border-b-2 border-transparent text-slate-600 hover:text-slate-800">YAML 보기</button>
|
|
||||||
<button data-ptab="yaml-edit" class="preview-tab px-3 py-1.5 text-sm rounded-t border-b-2 border-transparent text-slate-600 hover:text-slate-800">스펙 편집</button>
|
|
||||||
</div>
|
|
||||||
<button id="btn-toggle-preview" class="text-xs px-2 py-1 rounded border border-slate-200 text-slate-600 hover:bg-slate-100">패널 숨기기 ▶</button>
|
|
||||||
</div>
|
|
||||||
<div id="yaml-edit-bar" class="hidden flex items-center justify-between bg-amber-50 border-b border-amber-200 px-4 py-2 text-xs">
|
|
||||||
<span class="text-amber-800">YAML 을 직접 편집한 뒤 [Form 에 적용] 을 눌러 양식에 동기화하세요.</span>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<button id="btn-yaml-revert" class="px-2 py-1 rounded border border-amber-300 bg-white hover:bg-amber-100">변경 취소</button>
|
|
||||||
<button id="btn-yaml-apply" class="px-2 py-1 rounded bg-amber-600 text-white hover:bg-amber-700">Form 에 적용</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="preview-swagger" class="overflow-auto" style="height: calc(100vh - 56px - 72px - 41px);"></div>
|
|
||||||
<div id="preview-monaco" class="hidden" style="height: calc(100vh - 56px - 72px - 41px);"></div>
|
|
||||||
</aside>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="toast" class="fixed bottom-5 left-1/2 -translate-x-1/2 hidden px-4 py-2 rounded bg-slate-900 text-white text-sm shadow-lg z-50"></div>
|
|
||||||
|
|
||||||
<!-- Security scheme modal -->
|
|
||||||
<div id="sec-modal" class="hidden fixed inset-0 z-50 bg-slate-900/40 flex items-center justify-center">
|
|
||||||
<div class="bg-white rounded-lg shadow-xl w-[640px] max-h-[80vh] overflow-auto">
|
|
||||||
<div class="flex items-center justify-between px-5 py-3 border-b border-slate-200">
|
|
||||||
<h3 class="font-semibold text-slate-800">보안 스킴 추가</h3>
|
|
||||||
<button class="text-slate-400 hover:text-slate-700" data-sec-close>✕</button>
|
|
||||||
</div>
|
|
||||||
<div class="p-5" id="sec-modal-body"></div>
|
|
||||||
<div class="px-5 py-3 border-t border-slate-200 flex justify-end gap-2 bg-slate-50">
|
|
||||||
<button class="px-3 py-1.5 text-sm rounded border border-slate-300 bg-white" data-sec-close>취소</button>
|
|
||||||
<button id="btn-sec-save" class="px-3 py-1.5 text-sm rounded bg-brand-600 text-white">추가</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="<c:url value='/js/djb/apispec/sample-data.js'/>"></script>
|
|
||||||
<script src="<c:url value='/js/djb/apispec/app.js'/>"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -380,15 +380,15 @@
|
|||||||
{name: 'TRACKASISKEY2CTNT', hidden: true},
|
{name: 'TRACKASISKEY2CTNT', hidden: true},
|
||||||
|
|
||||||
{name: 'EAISVCSERNO_TMP', align: 'left', width: '220', formatter: trimFormatter},
|
{name: 'EAISVCSERNO_TMP', align: 'left', width: '220', formatter: trimFormatter},
|
||||||
{name: 'KEYMGTMSGCTNT', align: 'left', width: '300'},
|
{name: 'KEYMGTMSGCTNT', align: 'left', width: '240'},
|
||||||
{name: 'LOGPRCSSSERNO_TMP', align: 'center', width: '40'},
|
{name: 'LOGPRCSSSERNO_TMP', align: 'center', width: '40'},
|
||||||
{name: 'TELGMRECVTRANCD', align: 'left', width: '135', hidden: true},
|
{name: 'TELGMRECVTRANCD', align: 'left', width: '135', hidden: true},
|
||||||
{name: 'EAISVCNAME', align: 'left', width: '160'},
|
{name: 'EAISVCNAME', align: 'left', width: '130'},
|
||||||
{name: 'EAISVCDESC', align: 'left', width: '280'},
|
{name: 'EAISVCDESC', align: 'left', width: '280'},
|
||||||
{name: 'EAIBZWKDSTCD_TMP', align: 'center', width: '50'},
|
{name: 'EAIBZWKDSTCD_TMP', align: 'center', width: '50'},
|
||||||
{name: 'EXTBIZCD', align: 'center', width: '50', hidden: isApiGw},
|
{name: 'EXTBIZCD', align: 'center', width: '50', hidden: isApiGw},
|
||||||
{name: 'REFKEY', align: 'left', width: '280', hidden: isApiGw},
|
{name: 'REFKEY', align: 'left', width: '280', hidden: isApiGw},
|
||||||
{name: 'CLIENTNAME', align: 'left', width: '120', hidden: !isApiGw},
|
{name: 'CLIENTNAME', align: 'left', width: '260', hidden: !isApiGw},
|
||||||
{name: 'ORGNAME', align: 'left', width: '100', hidden: !isApiGw, formatter: orgNameFormatter},
|
{name: 'ORGNAME', align: 'left', width: '100', hidden: !isApiGw, formatter: orgNameFormatter},
|
||||||
{name: 'MSGDPSTYMS_TMP', align: 'center', width: '150', formatter: timeStampFormat2},
|
{name: 'MSGDPSTYMS_TMP', align: 'center', width: '150', formatter: timeStampFormat2},
|
||||||
{name: 'MSGPRCSSYMS', align: 'center', width: '150', formatter: timeStampFormat2},
|
{name: 'MSGPRCSSYMS', align: 'center', width: '150', formatter: timeStampFormat2},
|
||||||
|
|||||||
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,122 +0,0 @@
|
|||||||
/*!
|
|
||||||
* djb-swagger-i18n.js
|
|
||||||
* Swagger UI 영문 라벨을 한글로 치환하는 i18n 패치 (방법 B - DOM patch)
|
|
||||||
* 배포 경로 권장: static/plugins/swaggerUI/djb-swagger-i18n.js
|
|
||||||
* index.html 의 swagger-initializer.js 직전 또는 직후에 <script> 로 로드
|
|
||||||
*
|
|
||||||
* ?lang=en 쿼리스트링이 있으면 패치 비활성화 (원문 보기)
|
|
||||||
* 매핑 카탈로그는 01-i18n-mapping/i18n-strings.csv 와 동기 유지
|
|
||||||
*/
|
|
||||||
(function (window) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// ── 비활성화 옵션 ──
|
|
||||||
if (/[?&]lang=en\b/.test(window.location.search)) return;
|
|
||||||
|
|
||||||
// ── 매핑 (key 는 디버깅용, 실제 비교는 EN 문자열 일치) ──
|
|
||||||
var I18N_MAP = {
|
|
||||||
// P0 — OAuth2 모달 본문
|
|
||||||
'auth.modal.title': { en: 'Available authorizations', ko: '사용 가능한 인증' },
|
|
||||||
'auth.scopes.description': {
|
|
||||||
en: 'Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.',
|
|
||||||
ko: '스코프는 최종 사용자를 대신하여 애플리케이션이 데이터에 접근할 수 있는 권한 수준을 부여합니다. 각 API는 하나 이상의 스코프를 선언할 수 있습니다.'
|
|
||||||
},
|
|
||||||
'auth.scopes.swagger_grant': {
|
|
||||||
en: 'API requires the following scopes. Select which ones you want to grant to Swagger UI.',
|
|
||||||
ko: '이 API 는 아래 스코프가 필요합니다. Swagger UI 에 부여할 스코프를 선택하세요.'
|
|
||||||
},
|
|
||||||
'auth.flow.clientCredentials': { en: 'OAuth2 client credentials flow', ko: 'OAuth2 클라이언트 자격증명 흐름' },
|
|
||||||
'auth.flow.implicit': { en: 'OAuth2 implicit flow', ko: 'OAuth2 암묵적 흐름' },
|
|
||||||
'auth.flow.password': { en: 'OAuth2 password flow', ko: 'OAuth2 비밀번호 흐름' },
|
|
||||||
'auth.flow.authorizationCode': { en: 'OAuth2 authorization code flow', ko: 'OAuth2 인가 코드 흐름' },
|
|
||||||
'auth.field.tokenUrl': { en: 'Token URL:', ko: '토큰 URL:' },
|
|
||||||
'auth.field.flow': { en: 'Flow:', ko: '흐름:' },
|
|
||||||
'auth.field.clientId': { en: 'client_id:', ko: '클라이언트 ID (client_id):' },
|
|
||||||
'auth.field.clientSecret': { en: 'client_secret:',ko: '클라이언트 시크릿 (client_secret):' },
|
|
||||||
'auth.field.scopes': { en: 'Scopes:', ko: '스코프:' },
|
|
||||||
'auth.action.selectAll': { en: 'select all', ko: '모두 선택' },
|
|
||||||
'auth.action.selectNone': { en: 'select none', ko: '선택 해제' },
|
|
||||||
'auth.action.authorize': { en: 'Authorize', ko: '인증' },
|
|
||||||
'auth.action.close': { en: 'Close', ko: '닫기' },
|
|
||||||
'auth.action.logout': { en: 'Logout', ko: '로그아웃' },
|
|
||||||
'auth.modal.authorized': { en: 'authorized', ko: '인증됨' },
|
|
||||||
|
|
||||||
// P1 — 기타 인증 흐름
|
|
||||||
'auth.scheme.apiKey': { en: 'API key', ko: 'API 키' },
|
|
||||||
'auth.field.name': { en: 'name:', ko: '이름:' },
|
|
||||||
'auth.field.in': { en: 'in:', ko: '위치:' },
|
|
||||||
'auth.field.value': { en: 'Value:', ko: '값:' },
|
|
||||||
'basic.field.username': { en: 'Username:',ko: '사용자 ID:' },
|
|
||||||
'basic.field.password': { en: 'Password:',ko: '비밀번호:' }
|
|
||||||
// P2 (오퍼레이션/응답) 는 필요 시 추가
|
|
||||||
};
|
|
||||||
|
|
||||||
// 빠른 lookup 을 위해 EN → KO 인덱스 사전 생성
|
|
||||||
var EN_TO_KO = Object.create(null);
|
|
||||||
Object.keys(I18N_MAP).forEach(function (k) {
|
|
||||||
var e = I18N_MAP[k];
|
|
||||||
EN_TO_KO[e.en] = e.ko;
|
|
||||||
});
|
|
||||||
|
|
||||||
// ── 치환 대상 노드 식별 + 치환 ──
|
|
||||||
function translateNode(node) {
|
|
||||||
if (!node) return;
|
|
||||||
if (node.nodeType === Node.TEXT_NODE) {
|
|
||||||
var raw = node.nodeValue;
|
|
||||||
if (!raw) return;
|
|
||||||
var trimmed = raw.trim();
|
|
||||||
if (!trimmed) return;
|
|
||||||
// 1) 완전 일치 (가장 안전)
|
|
||||||
if (EN_TO_KO[trimmed]) {
|
|
||||||
node.nodeValue = raw.replace(trimmed, EN_TO_KO[trimmed]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 2) 라벨 colon 패턴: "Token URL:" 같이 끝이 ":" 인 짧은 라벨
|
|
||||||
// (불필요 — 1번 완전 일치로 대부분 커버)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
||||||
if (node.tagName === 'SCRIPT' || node.tagName === 'STYLE') return;
|
|
||||||
|
|
||||||
// input placeholder / button title 도 일부 케이스에 대비
|
|
||||||
if (node.tagName === 'INPUT' && node.placeholder && EN_TO_KO[node.placeholder.trim()]) {
|
|
||||||
node.placeholder = EN_TO_KO[node.placeholder.trim()];
|
|
||||||
}
|
|
||||||
|
|
||||||
var i, child = node.childNodes, len = child.length;
|
|
||||||
for (i = 0; i < len; i++) translateNode(child[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function translateAll() {
|
|
||||||
var root = document.getElementById('swagger-ui') || document.body;
|
|
||||||
translateNode(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── MutationObserver — SwaggerUI 가 동적으로 DOM 을 다시 그릴 때마다 재적용 ──
|
|
||||||
var observer = new MutationObserver(function (mutations) {
|
|
||||||
for (var i = 0; i < mutations.length; i++) {
|
|
||||||
var m = mutations[i];
|
|
||||||
if (m.addedNodes && m.addedNodes.length) {
|
|
||||||
for (var j = 0; j < m.addedNodes.length; j++) translateNode(m.addedNodes[j]);
|
|
||||||
}
|
|
||||||
if (m.type === 'characterData') {
|
|
||||||
translateNode(m.target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function start() {
|
|
||||||
translateAll();
|
|
||||||
observer.observe(document.body, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true,
|
|
||||||
characterData: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.readyState === 'loading') {
|
|
||||||
document.addEventListener('DOMContentLoaded', start);
|
|
||||||
} else {
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
})(window);
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+14
-19
@@ -4,7 +4,7 @@ plugins {
|
|||||||
id 'eclipse-wtp'
|
id 'eclipse-wtp'
|
||||||
id 'idea'
|
id 'idea'
|
||||||
id 'war'
|
id 'war'
|
||||||
id 'org.cyclonedx.bom' version '3.2.4'
|
id 'com.diffplug.eclipse.apt' version '3.41.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'com.eactive'
|
group 'com.eactive'
|
||||||
@@ -49,6 +49,10 @@ compileJava {
|
|||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
options.compilerArgs = ['-parameters']
|
options.compilerArgs = ['-parameters']
|
||||||
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
|
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
|
||||||
|
|
||||||
|
aptOptions {
|
||||||
|
processorArgs = [ 'querydsl.generatedAnnotationClass' : 'com.querydsl.core.annotations.Generated' ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
war {
|
war {
|
||||||
@@ -85,11 +89,10 @@ dependencies {
|
|||||||
implementation project(':elink-online-emsclient')
|
implementation project(':elink-online-emsclient')
|
||||||
implementation project(':elink-portal-common')
|
implementation project(':elink-portal-common')
|
||||||
//implementation project(':kjb-safedb')
|
//implementation project(':kjb-safedb')
|
||||||
//implementation project(":eapim-admin-djb")
|
implementation project(":eapim-admin-djb")
|
||||||
|
|
||||||
/* Custom Libs (damo-manager.jar 는 Tomcat lib 가 런타임 제공 → compileOnly, WAR 미포함) */
|
/* Custom Libs */
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'], exclude: ['damo-manager.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
compileOnly files('libs/damo-manager.jar')
|
|
||||||
|
|
||||||
//implementation "org.dom4j:dom4j:2.1.3"
|
//implementation "org.dom4j:dom4j:2.1.3"
|
||||||
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
||||||
@@ -118,12 +121,6 @@ dependencies {
|
|||||||
//implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.13.1'
|
//implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.13.1'
|
||||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1'
|
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1'
|
||||||
|
|
||||||
// apistatus-draft.yml (자동 탐지 초안 양식) 로딩용.
|
|
||||||
// admin 은 Spring Boot 가 아니라 yml 자동 바인딩이 없어 직접 파싱한다.
|
|
||||||
// 2.x 를 쓴다 - 1.x 는 CVE-2022-1471(Constructor 역직렬화 RCE) 및
|
|
||||||
// CVE-2022-25857/38749~38752(DoS) 영향. 로딩도 SafeConstructor 로 한다.
|
|
||||||
implementation 'org.yaml:snakeyaml:2.4'
|
|
||||||
|
|
||||||
implementation "javax.jms:javax.jms-api:2.0"
|
implementation "javax.jms:javax.jms-api:2.0"
|
||||||
implementation "org.snmp4j:snmp4j:1.10.1"
|
implementation "org.snmp4j:snmp4j:1.10.1"
|
||||||
implementation "com.googlecode.json-simple:json-simple:1.1.1"
|
implementation "com.googlecode.json-simple:json-simple:1.1.1"
|
||||||
@@ -259,11 +256,11 @@ eclipse {
|
|||||||
}
|
}
|
||||||
synchronizationTasks settingEclipseEncoding, initDirs
|
synchronizationTasks settingEclipseEncoding, initDirs
|
||||||
jdt {
|
jdt {
|
||||||
// apt {
|
apt {
|
||||||
// // generated 된 패스 경로를 .setting/org.eclipse.jdt.apt.core.prefs 의 org.eclipse.jdt.apt.genSrcDir에 적용한다.
|
// generated 된 패스 경로를 .setting/org.eclipse.jdt.apt.core.prefs 의 org.eclipse.jdt.apt.genSrcDir에 적용한다.
|
||||||
// // project > properties > Java Compiler > Annoation Processing 화면에서 확인 가능하다.
|
// project > properties > Java Compiler > Annoation Processing 화면에서 확인 가능하다.
|
||||||
// genSrcDir = file(generatedJavaDir)
|
genSrcDir = file(generatedJavaDir)
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
project {
|
project {
|
||||||
if (!natures.contains('org.eclipse.buildship.core.gradleprojectnature')) {
|
if (!natures.contains('org.eclipse.buildship.core.gradleprojectnature')) {
|
||||||
@@ -277,6 +274,4 @@ tasks.withType(JavaCompile) {
|
|||||||
options.fork = true // 컴파일을 별도 프로세스로 분리
|
options.fork = true // 컴파일을 별도 프로세스로 분리
|
||||||
options.forkOptions.memoryMaximumSize = '4g' // 컴파일러에 2GB 할당 (필요시 4g로 증량)
|
options.forkOptions.memoryMaximumSize = '4g' // 컴파일러에 2GB 할당 (필요시 4g로 증량)
|
||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
}
|
}
|
||||||
// CycloneDX SBOM -> xlsx 변환 (gradle sbomXlsx)
|
|
||||||
apply from: "$projectDir/gradle/sbom-xlsx.gradle"
|
|
||||||
+34
-61
@@ -1,9 +1,9 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
id 'eclipse'
|
|
||||||
id 'eclipse-wtp'
|
|
||||||
id 'idea'
|
id 'idea'
|
||||||
id 'war'
|
id 'war'
|
||||||
|
id 'project-report'
|
||||||
|
id 'checkstyle'
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'com.eactive'
|
group 'com.eactive'
|
||||||
@@ -14,19 +14,17 @@ def quartzVersion = "2.2.1"
|
|||||||
def queryDslVersion = "5.0.0"
|
def queryDslVersion = "5.0.0"
|
||||||
def hibernateVersion = "5.6.15.Final"
|
def hibernateVersion = "5.6.15.Final"
|
||||||
|
|
||||||
def nexusUrl = "https://nexus.eactive.synology.me:8090"
|
/*def nexusUrl = "https://nexus.eactive.synology.me:8090"*/
|
||||||
//def useOnJboss = false
|
//def useOnJboss = false
|
||||||
|
|
||||||
def generatedJavaDir = "$buildDir/generated/java"
|
def generatedJavaDir = "$buildDir/generated/java"
|
||||||
|
|
||||||
allprojects {
|
/*repositories {
|
||||||
repositories {
|
maven {
|
||||||
maven {
|
url "${nexusUrl}/repository/maven-public/"
|
||||||
url "${nexusUrl}/repository/maven-public/"
|
allowInsecureProtocol = true
|
||||||
allowInsecureProtocol = true
|
}
|
||||||
}
|
}*/
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
project.webAppDirName = 'WebContent'
|
project.webAppDirName = 'WebContent'
|
||||||
|
|
||||||
@@ -36,6 +34,10 @@ java {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkstyle {
|
||||||
|
toolVersion = '8.45.1'
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
java {
|
java {
|
||||||
@@ -46,7 +48,10 @@ sourceSets {
|
|||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
options.compilerArgs = ['-parameters']
|
options.compilerArgs = [
|
||||||
|
'-parameters',
|
||||||
|
'-Aquerydsl.generatedAnnotationClass=com.querydsl.core.annotations.Generated'
|
||||||
|
]
|
||||||
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
|
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +67,7 @@ war {
|
|||||||
// rootSpec.exclude '**/persistence.xml'
|
// rootSpec.exclude '**/persistence.xml'
|
||||||
exclude '**/context.xml'
|
exclude '**/context.xml'
|
||||||
exclude '**/context-*.xml'
|
exclude '**/context-*.xml'
|
||||||
|
exclude '**/context_*.xml'
|
||||||
archiveFileName = "eapim-admin.war"
|
archiveFileName = "eapim-admin.war"
|
||||||
duplicatesStrategy = DuplicatesStrategy.WARN
|
duplicatesStrategy = DuplicatesStrategy.WARN
|
||||||
}
|
}
|
||||||
@@ -83,12 +89,11 @@ dependencies {
|
|||||||
implementation project(':elink-online-common')
|
implementation project(':elink-online-common')
|
||||||
implementation project(':elink-online-emsclient')
|
implementation project(':elink-online-emsclient')
|
||||||
implementation project(':elink-portal-common')
|
implementation project(':elink-portal-common')
|
||||||
//implementation project(':kjb-safedb')
|
implementation project(':kjb-safedb')
|
||||||
implementation project(":eapim-admin-djb")
|
implementation project(":eapim-admin-kjb")
|
||||||
|
|
||||||
/* Custom Libs (damo-manager.jar 는 Tomcat lib 가 런타임 제공 → compileOnly, WAR 미포함) */
|
/* Custom Libs */
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'], exclude: ['damo-manager.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
compileOnly files('libs/damo-manager.jar')
|
|
||||||
|
|
||||||
//implementation "org.dom4j:dom4j:2.1.3"
|
//implementation "org.dom4j:dom4j:2.1.3"
|
||||||
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
||||||
@@ -121,7 +126,7 @@ dependencies {
|
|||||||
implementation "org.snmp4j:snmp4j:1.10.1"
|
implementation "org.snmp4j:snmp4j:1.10.1"
|
||||||
implementation "com.googlecode.json-simple:json-simple:1.1.1"
|
implementation "com.googlecode.json-simple:json-simple:1.1.1"
|
||||||
|
|
||||||
implementation "io.netty:netty-all:4.1.94.Final"
|
implementation "io.netty:netty-all:4.1.0.Final"
|
||||||
|
|
||||||
compileOnly "org.apache.mina:mina-filter-ssl:1.1.6"
|
compileOnly "org.apache.mina:mina-filter-ssl:1.1.6"
|
||||||
compileOnly "org.apache.mina:mina-core:1.1.6"
|
compileOnly "org.apache.mina:mina-core:1.1.6"
|
||||||
@@ -198,11 +203,12 @@ dependencies {
|
|||||||
implementation 'software.amazon.awssdk:sso:2.20.142'
|
implementation 'software.amazon.awssdk:sso:2.20.142'
|
||||||
implementation 'software.amazon.awssdk:sts:2.20.142'
|
implementation 'software.amazon.awssdk:sts:2.20.142'
|
||||||
|
|
||||||
implementation group: 'commons-net', name: 'commons-net', version: '3.5'
|
implementation ('io.kubernetes:client-java:18.0.1') {
|
||||||
|
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||||
|
exclude group: 'org.slf4j', module: 'logback-classic'
|
||||||
|
}
|
||||||
|
|
||||||
// JDK 8 의 rt.jar 에는 org.w3c.dom.ElementTraversal 이 없어 xercesImpl 가 NCDFE 를 일으킴.
|
implementation group: 'commons-net', name: 'commons-net', version: '3.5'
|
||||||
// xml-apis 1.4.01 에 그 클래스가 포함됨. 직접 의존성으로 묶어 WAR 에 패키징되도록 함.
|
|
||||||
implementation 'xml-apis:xml-apis:1.4.01'
|
|
||||||
|
|
||||||
testRuntimeOnly 'com.h2database:h2:2.1.214'
|
testRuntimeOnly 'com.h2database:h2:2.1.214'
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
||||||
@@ -223,51 +229,18 @@ configurations.all {
|
|||||||
cacheDynamicVersionsFor 10, 'minutes'
|
cacheDynamicVersionsFor 10, 'minutes'
|
||||||
// Do not cache changing modules
|
// Do not cache changing modules
|
||||||
cacheChangingModulesFor 0, 'seconds'
|
cacheChangingModulesFor 0, 'seconds'
|
||||||
|
|
||||||
// JDK 8 의 rt.jar 에는 org.w3c.dom.ElementTraversal 이 없음.
|
|
||||||
// 일부 transitive 가 끌어오는 xml-apis:1.0.b2 (2002, DOM L2) 는 이 클래스를 포함하지 않아
|
|
||||||
// xercesImpl 가 NoClassDefFoundError 를 일으킴 → 1.4.01 로 강제 통일.
|
|
||||||
force 'xml-apis:xml-apis:1.4.01'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
task settingEclipseEncoding {
|
|
||||||
if (project.file('.settings').exists()) {
|
|
||||||
File f = file('.settings/org.eclipse.core.resources.prefs')
|
|
||||||
f.write('eclipse.preferences.version=1\n')
|
|
||||||
f.append('encoding/<project>=utf-8')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task initDirs() {
|
task initDirs() {
|
||||||
file(generatedJavaDir).mkdirs()
|
file(generatedJavaDir).mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
eclipse {
|
|
||||||
wtp {
|
|
||||||
component {
|
|
||||||
contextPath = 'monitoring'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
synchronizationTasks settingEclipseEncoding, initDirs
|
|
||||||
jdt {
|
|
||||||
apt {
|
|
||||||
// generated 된 패스 경로를 .setting/org.eclipse.jdt.apt.core.prefs 의 org.eclipse.jdt.apt.genSrcDir에 적용한다.
|
|
||||||
// project > properties > Java Compiler > Annoation Processing 화면에서 확인 가능하다.
|
|
||||||
genSrcDir = file(generatedJavaDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
project {
|
|
||||||
if (!natures.contains('org.eclipse.buildship.core.gradleprojectnature')) {
|
|
||||||
natures.add('org.eclipse.buildship.core.gradleprojectnature')
|
|
||||||
buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(Checkstyle) {
|
||||||
options.fork = true // 컴파일을 별도 프로세스로 분리
|
reports {
|
||||||
options.forkOptions.memoryMaximumSize = '4g' // 컴파일러에 2GB 할당 (필요시 4g로 증량)
|
xml.required = false
|
||||||
options.encoding = 'UTF-8'
|
html.required = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,326 +0,0 @@
|
|||||||
/*
|
|
||||||
* CycloneDX SBOM(bom.json) -> Excel(xlsx) 변환 태스크.
|
|
||||||
*
|
|
||||||
* gradle sbomXlsx # cyclonedxBom 실행 후 변환
|
|
||||||
* gradle sbomXlsx -PsbomJson=path.json # 기존 bom.json 사용(cyclonedxBom 생략)
|
|
||||||
* gradle sbomXlsx -PsbomOut=out.xlsx # 출력 경로 지정
|
|
||||||
*
|
|
||||||
* buildscript 블록이 이 스크립트에만 적용되므로 POI 의존성이 메인 빌드
|
|
||||||
* classpath 나 WAR 산출물에는 포함되지 않는다.
|
|
||||||
*
|
|
||||||
* 시트: 요약 / WAR 기준
|
|
||||||
* 산출 기준은 war 태스크의 classpath(= runtimeClasspath) 이므로
|
|
||||||
* test·annotationProcessor·developmentOnly·compileOnly 의존은 모두 제외된다.
|
|
||||||
* bom.json 은 라이선스/해시/설명/직접-전이 판별을 위한 메타 소스로만 쓴다.
|
|
||||||
*/
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url "https://nexus.eactive.synology.me:8090/repository/maven-public/"
|
|
||||||
allowInsecureProtocol = true
|
|
||||||
}
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'org.apache.poi:poi-ooxml:3.17'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
import groovy.json.JsonSlurper
|
|
||||||
import org.apache.poi.ss.usermodel.BorderStyle
|
|
||||||
import org.apache.poi.ss.usermodel.FillPatternType
|
|
||||||
import org.apache.poi.ss.usermodel.HorizontalAlignment
|
|
||||||
import org.apache.poi.ss.usermodel.IndexedColors
|
|
||||||
import org.apache.poi.ss.usermodel.VerticalAlignment
|
|
||||||
import org.apache.poi.ss.util.CellRangeAddress
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook
|
|
||||||
|
|
||||||
// 엑셀 셀 문자열 상한(32767)보다 여유를 둔 절단 길이
|
|
||||||
ext.SBOM_CELL_LIMIT = 32000
|
|
||||||
|
|
||||||
task sbomXlsx {
|
|
||||||
group = 'sbom'
|
|
||||||
description = 'CycloneDX bom.json 을 WAR 수록 기준 xlsx 로 변환한다'
|
|
||||||
|
|
||||||
// -PsbomJson 으로 기존 산출물을 지정하면 재생성하지 않는다
|
|
||||||
if (!project.hasProperty('sbomJson')) {
|
|
||||||
dependsOn 'cyclonedxBom'
|
|
||||||
}
|
|
||||||
|
|
||||||
doLast {
|
|
||||||
File src = resolveBomJson(project)
|
|
||||||
File out = project.hasProperty('sbomOut')
|
|
||||||
? project.file(project.property('sbomOut'))
|
|
||||||
: new File(project.buildDir, "reports/sbom/${sbomFileName(project)}")
|
|
||||||
out.parentFile.mkdirs()
|
|
||||||
|
|
||||||
def bom = new JsonSlurper().parse(src, 'UTF-8')
|
|
||||||
def deploy = collectDeployJars(project)
|
|
||||||
def warRows = joinWarRows(deploy.jars, indexComponents(bom))
|
|
||||||
|
|
||||||
def wb = new XSSFWorkbook()
|
|
||||||
def st = createStyles(wb)
|
|
||||||
writeSummarySheet(wb, st, bom, warRows, src, deploy.label)
|
|
||||||
writeWarSheet(wb, st, warRows)
|
|
||||||
|
|
||||||
out.withOutputStream { os -> wb.write(os) }
|
|
||||||
wb.close()
|
|
||||||
|
|
||||||
int unmatched = warRows.count { it.matched == 'N' }
|
|
||||||
logger.lifecycle("SBOM xlsx 생성: ${out.absolutePath} " +
|
|
||||||
"(배포 수록 ${warRows.size()}개, SBOM 미매칭 ${unmatched}개, 원본 ${src.name})")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 산출 파일명: 배포 패키지명 기준 (war 있으면 war 파일명, 없으면 project 이름[-버전]) */
|
|
||||||
String sbomFileName(Project p) {
|
|
||||||
def warTask = p.tasks.findByName('war')
|
|
||||||
if (warTask != null) {
|
|
||||||
String archive = warTask.archiveFileName.get()
|
|
||||||
return archive.replaceAll(/\.(war|jar|ear)$/, '') + '-sbom.xlsx'
|
|
||||||
}
|
|
||||||
String ver = (p.version == null || p.version.toString() in ['', 'unspecified']) ? '' : "-${p.version}"
|
|
||||||
return "${p.name}${ver}-sbom.xlsx"
|
|
||||||
}
|
|
||||||
|
|
||||||
/** bom.json 위치 결정: -PsbomJson > cyclonedxBom 산출 경로 후보 */
|
|
||||||
File resolveBomJson(Project p) {
|
|
||||||
if (p.hasProperty('sbomJson')) {
|
|
||||||
File f = p.file(p.property('sbomJson'))
|
|
||||||
if (!f.exists()) {
|
|
||||||
throw new GradleException("bom.json 없음: ${f.absolutePath}")
|
|
||||||
}
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
def candidates = [
|
|
||||||
new File(p.buildDir, 'reports/cyclonedx/bom.json'),
|
|
||||||
new File(p.buildDir, 'reports/bom.json'),
|
|
||||||
]
|
|
||||||
File found = candidates.find { it.exists() }
|
|
||||||
if (found == null) {
|
|
||||||
throw new GradleException(
|
|
||||||
"bom.json 을 찾지 못했다. 확인한 경로: " + candidates*.absolutePath.join(', ') +
|
|
||||||
"\n'gradle cyclonedxBom' 실행 후 재시도하거나 -PsbomJson=<경로> 로 지정한다.")
|
|
||||||
}
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 실제 배포물에 packaging 되는 jar 목록.
|
|
||||||
* war 프로젝트는 war 태스크 classpath(= runtimeClasspath), 그 외는 runtimeClasspath 를
|
|
||||||
* 기준으로 하므로 test/annotationProcessor/developmentOnly/compileOnly 는 자동으로 빠진다.
|
|
||||||
*
|
|
||||||
* @return [label: 기준 설명, jars: 행 목록]
|
|
||||||
*/
|
|
||||||
Map collectDeployJars(Project p) {
|
|
||||||
def cfg = p.configurations.findByName('runtimeClasspath')
|
|
||||||
if (cfg == null) {
|
|
||||||
p.logger.warn("[${p.name}] runtimeClasspath 가 없어 배포 기준 시트를 비운다")
|
|
||||||
return [label: '(없음)', jars: []]
|
|
||||||
}
|
|
||||||
|
|
||||||
def warTask = p.tasks.findByName('war')
|
|
||||||
def files
|
|
||||||
String label
|
|
||||||
if (warTask != null) {
|
|
||||||
files = warTask.classpath.files
|
|
||||||
label = 'WAR WEB-INF/lib (war 태스크 classpath)'
|
|
||||||
} else {
|
|
||||||
files = cfg.files
|
|
||||||
label = 'runtimeClasspath (war 태스크 없음)'
|
|
||||||
}
|
|
||||||
|
|
||||||
def coordByFile = [:]
|
|
||||||
cfg.resolvedConfiguration.resolvedArtifacts.each { a ->
|
|
||||||
def id = a.moduleVersion.id
|
|
||||||
coordByFile[a.file] = [group: id.group, name: id.name, version: id.version]
|
|
||||||
}
|
|
||||||
def jars = files.findAll { it.name.endsWith('.jar') }.collect { f ->
|
|
||||||
def c = coordByFile[f]
|
|
||||||
[
|
|
||||||
file : f.name,
|
|
||||||
group : c?.group ?: '',
|
|
||||||
name : c?.name ?: f.name.replaceAll(/\.jar$/, ''),
|
|
||||||
version: c?.version ?: '',
|
|
||||||
coord : c ? "${c.group}:${c.name}:${c.version}".toString() : '',
|
|
||||||
]
|
|
||||||
}.sort { it.file }
|
|
||||||
|
|
||||||
return [label: label, jars: jars]
|
|
||||||
}
|
|
||||||
|
|
||||||
/** bom.json 컴포넌트를 'group:name:version' 키로 색인 (라이선스/해시/설명/직접-전이) */
|
|
||||||
Map indexComponents(bom) {
|
|
||||||
String rootRef = bom.metadata?.component?.'bom-ref'
|
|
||||||
Set directRefs = (bom.dependencies?.find { it.ref == rootRef }?.dependsOn ?: []) as Set
|
|
||||||
|
|
||||||
def index = [:]
|
|
||||||
bom.components?.each { c ->
|
|
||||||
def hashes = [:]
|
|
||||||
c.hashes?.each { h -> hashes[h.alg] = h.content }
|
|
||||||
|
|
||||||
def licenses = (c.licenses ?: []).collect { l ->
|
|
||||||
l.license?.id ?: l.license?.name ?: l.expression ?: ''
|
|
||||||
}.findAll { it }
|
|
||||||
|
|
||||||
index["${c.group ?: ''}:${c.name ?: ''}:${c.version ?: ''}".toString()] = [
|
|
||||||
direct : directRefs.contains(c.'bom-ref') ? '직접' : '전이',
|
|
||||||
licenses : licenses.join('; '),
|
|
||||||
licenseList: licenses.isEmpty() ? ['(미상)'] : licenses,
|
|
||||||
purl : c.purl ?: '',
|
|
||||||
sha256 : hashes['SHA-256'] ?: '',
|
|
||||||
sha1 : hashes['SHA-1'] ?: '',
|
|
||||||
description: c.description ?: '',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return index
|
|
||||||
}
|
|
||||||
|
|
||||||
/** WAR jar 목록에 SBOM 메타를 좌표로 결합 */
|
|
||||||
List joinWarRows(List warJars, Map index) {
|
|
||||||
def result = []
|
|
||||||
warJars.eachWithIndex { j, i ->
|
|
||||||
def m = j.coord ? index[j.coord] : null
|
|
||||||
result << [
|
|
||||||
no : i + 1,
|
|
||||||
file : j.file,
|
|
||||||
group : j.group,
|
|
||||||
name : j.name,
|
|
||||||
version : j.version,
|
|
||||||
direct : m?.direct ?: '',
|
|
||||||
licenses : m?.licenses ?: '',
|
|
||||||
licenseList: m?.licenseList ?: ['(미상)'],
|
|
||||||
purl : m?.purl ?: '',
|
|
||||||
sha256 : m?.sha256 ?: '',
|
|
||||||
sha1 : m?.sha1 ?: '',
|
|
||||||
matched : (m != null) ? 'Y' : 'N',
|
|
||||||
description: m?.description ?: '',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
Map createStyles(wb) {
|
|
||||||
def headFont = wb.createFont()
|
|
||||||
headFont.setBold(true)
|
|
||||||
headFont.setColor(IndexedColors.WHITE.getIndex())
|
|
||||||
|
|
||||||
def head = wb.createCellStyle()
|
|
||||||
head.setFont(headFont)
|
|
||||||
head.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex())
|
|
||||||
head.setFillPattern(FillPatternType.SOLID_FOREGROUND)
|
|
||||||
head.setAlignment(HorizontalAlignment.CENTER)
|
|
||||||
head.setVerticalAlignment(VerticalAlignment.CENTER)
|
|
||||||
head.setBorderBottom(BorderStyle.THIN)
|
|
||||||
|
|
||||||
def body = wb.createCellStyle()
|
|
||||||
body.setVerticalAlignment(VerticalAlignment.TOP)
|
|
||||||
|
|
||||||
def wrap = wb.createCellStyle()
|
|
||||||
wrap.setVerticalAlignment(VerticalAlignment.TOP)
|
|
||||||
wrap.setWrapText(true)
|
|
||||||
|
|
||||||
def labelFont = wb.createFont()
|
|
||||||
labelFont.setBold(true)
|
|
||||||
def label = wb.createCellStyle()
|
|
||||||
label.setFont(labelFont)
|
|
||||||
|
|
||||||
return [head: head, body: body, wrap: wrap, label: label]
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 헤더 행 생성 + 폭 지정 + 틀고정 */
|
|
||||||
def writeHeader(sheet, style, List<String> headers, List<Integer> widths) {
|
|
||||||
def row = sheet.createRow(0)
|
|
||||||
row.setHeightInPoints(20f)
|
|
||||||
headers.eachWithIndex { h, i ->
|
|
||||||
def cell = row.createCell(i)
|
|
||||||
cell.setCellValue(h)
|
|
||||||
cell.setCellStyle(style)
|
|
||||||
sheet.setColumnWidth(i, widths[i] * 256)
|
|
||||||
}
|
|
||||||
sheet.createFreezePane(0, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
def cellOf(row, int idx, value, style) {
|
|
||||||
def cell = row.createCell(idx)
|
|
||||||
String s = (value == null) ? '' : value.toString()
|
|
||||||
if (s.length() > SBOM_CELL_LIMIT) {
|
|
||||||
s = s.substring(0, SBOM_CELL_LIMIT) + '…(생략)'
|
|
||||||
}
|
|
||||||
cell.setCellValue(s)
|
|
||||||
cell.setCellStyle(style)
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
|
|
||||||
def writeSummarySheet(wb, st, bom, List warRows, File src, String basisLabel) {
|
|
||||||
def sheet = wb.createSheet('요약')
|
|
||||||
def comp = bom.metadata?.component ?: [:]
|
|
||||||
def tool = bom.metadata?.tools?.components?.getAt(0)
|
|
||||||
Set licenseKinds = warRows.collectMany { it.licenseList } as Set
|
|
||||||
|
|
||||||
def items = [
|
|
||||||
['대상 프로젝트', "${comp.group ?: ''}:${comp.name ?: ''}:${comp.version ?: ''}"],
|
|
||||||
['산출 기준', "${basisLabel} — test/annotationProcessor/compileOnly 제외"],
|
|
||||||
['BOM 포맷', "${bom.bomFormat ?: ''} ${bom.specVersion ?: ''}"],
|
|
||||||
['serialNumber', bom.serialNumber ?: ''],
|
|
||||||
['생성 시각', bom.metadata?.timestamp ?: ''],
|
|
||||||
['생성 도구', tool ? "${tool.name} ${tool.version}" : ''],
|
|
||||||
['원본 파일', src.absolutePath],
|
|
||||||
['배포 수록 jar', warRows.size()],
|
|
||||||
[' └ 직접 의존', warRows.count { it.direct == '직접' }],
|
|
||||||
[' └ 전이 의존', warRows.count { it.direct == '전이' }],
|
|
||||||
[' └ SBOM 미매칭', warRows.count { it.matched == 'N' }],
|
|
||||||
['라이선스 종류', licenseKinds.size()],
|
|
||||||
['라이선스 미상', warRows.count { it.licenses.isEmpty() }],
|
|
||||||
]
|
|
||||||
|
|
||||||
writeHeader(sheet, st.head, ['항목', '값'], [30, 90])
|
|
||||||
items.eachWithIndex { item, i ->
|
|
||||||
def row = sheet.createRow(i + 1)
|
|
||||||
cellOf(row, 0, item[0], st.label)
|
|
||||||
cellOf(row, 1, item[1], st.body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 라이선스 분포 (요약 하단)
|
|
||||||
def byLicense = [:].withDefault { 0 }
|
|
||||||
warRows.each { r -> r.licenseList.each { lic -> byLicense[lic] = byLicense[lic] + 1 } }
|
|
||||||
def sorted = byLicense.entrySet().sort { a, b -> (b.value <=> a.value) ?: (a.key <=> b.key) }
|
|
||||||
|
|
||||||
int base = items.size() + 2
|
|
||||||
def hdr = sheet.createRow(base)
|
|
||||||
cellOf(hdr, 0, '라이선스', st.head)
|
|
||||||
cellOf(hdr, 1, 'jar 수', st.head)
|
|
||||||
sorted.eachWithIndex { e, i ->
|
|
||||||
def row = sheet.createRow(base + 1 + i)
|
|
||||||
cellOf(row, 0, e.key, st.body)
|
|
||||||
cellOf(row, 1, e.value, st.body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 실제 배포물(WAR WEB-INF/lib) 기준 시트 */
|
|
||||||
def writeWarSheet(wb, st, List warRows) {
|
|
||||||
def sheet = wb.createSheet('WAR 기준')
|
|
||||||
def headers = ['No', 'jar 파일명', 'Group', 'Name', 'Version', '구분',
|
|
||||||
'License', 'purl', 'SHA-256', 'SHA-1', 'SBOM매칭', 'Description']
|
|
||||||
def widths = [6, 46, 32, 34, 16, 7, 30, 60, 40, 30, 10, 60]
|
|
||||||
writeHeader(sheet, st.head, headers, widths)
|
|
||||||
|
|
||||||
warRows.eachWithIndex { r, i ->
|
|
||||||
def row = sheet.createRow(i + 1)
|
|
||||||
cellOf(row, 0, r.no, st.body)
|
|
||||||
cellOf(row, 1, r.file, st.body)
|
|
||||||
cellOf(row, 2, r.group, st.body)
|
|
||||||
cellOf(row, 3, r.name, st.body)
|
|
||||||
cellOf(row, 4, r.version, st.body)
|
|
||||||
cellOf(row, 5, r.direct, st.body)
|
|
||||||
cellOf(row, 6, r.licenses, st.body)
|
|
||||||
cellOf(row, 7, r.purl, st.body)
|
|
||||||
cellOf(row, 8, r.sha256, st.body)
|
|
||||||
cellOf(row, 9, r.sha1, st.body)
|
|
||||||
cellOf(row, 10, r.matched, st.body)
|
|
||||||
cellOf(row, 11, r.description, st.wrap)
|
|
||||||
}
|
|
||||||
if (!warRows.isEmpty()) {
|
|
||||||
sheet.setAutoFilter(new CellRangeAddress(0, warRows.size(), 0, headers.size() - 1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
+2
-2
@@ -7,7 +7,7 @@ include 'elink-online-common'
|
|||||||
include 'elink-online-emsclient'
|
include 'elink-online-emsclient'
|
||||||
include 'elink-portal-common'
|
include 'elink-portal-common'
|
||||||
//include 'kjb-safedb'
|
//include 'kjb-safedb'
|
||||||
//include 'eapim-admin-djb'
|
include 'eapim-admin-djb'
|
||||||
|
|
||||||
project (':elink-online-core-jpa').projectDir = new File(settingsDir, "../eapim-online/elink-online-core-jpa")
|
project (':elink-online-core-jpa').projectDir = new File(settingsDir, "../eapim-online/elink-online-core-jpa")
|
||||||
project (':elink-online-core').projectDir = new File(settingsDir, "../eapim-online/elink-online-core")
|
project (':elink-online-core').projectDir = new File(settingsDir, "../eapim-online/elink-online-core")
|
||||||
@@ -16,4 +16,4 @@ project (':elink-online-common').projectDir = new File(settingsDir, "../eapim-on
|
|||||||
project (':elink-online-emsclient').projectDir = new File(settingsDir, "../eapim-online/elink-online-emsclient")
|
project (':elink-online-emsclient').projectDir = new File(settingsDir, "../eapim-online/elink-online-emsclient")
|
||||||
project (':elink-portal-common').projectDir = new File(settingsDir, "../elink-portal-common")
|
project (':elink-portal-common').projectDir = new File(settingsDir, "../elink-portal-common")
|
||||||
//project (':kjb-safedb').projectDir = new File(settingsDir, "../kjb-safedb")
|
//project (':kjb-safedb').projectDir = new File(settingsDir, "../kjb-safedb")
|
||||||
//project (':eapim-admin-djb').projectDir = new File(settingsDir, "../eapim-admin-djb")
|
project (':eapim-admin-djb').projectDir = new File(settingsDir, "../eapim-admin-djb")
|
||||||
+1
-3
@@ -41,12 +41,10 @@ public class AuditLogInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
if (isAuditableUsecase.isAuditable(userId, command, logType, systemCode)) {
|
if (isAuditableUsecase.isAuditable(userId, command, logType, systemCode)) {
|
||||||
String parameters = getParametersAsString(request);
|
String parameters = getParametersAsString(request);
|
||||||
String message = request.getParameter("auditReason");
|
|
||||||
log
|
log
|
||||||
.debug("audit log save : logType={}, cmd={}, user={}, parameters={}", logType, command,
|
.debug("audit log save : logType={}, cmd={}, user={}, parameters={}", logType, command,
|
||||||
userId, parameters);
|
userId, parameters);
|
||||||
saveAuditLogUseCase
|
saveAuditLogUseCase.log(systemCode, logType, command, remoteAddress, userId, parameters);
|
||||||
.log(systemCode, logType, command, remoteAddress, userId, parameters, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-3
@@ -51,9 +51,6 @@ public class AuditLogPageRepositoryImpl implements AuditLogPageRepository {
|
|||||||
if (StringUtils.isNotBlank(command.getSearchRemoteAddress())) {
|
if (StringUtils.isNotBlank(command.getSearchRemoteAddress())) {
|
||||||
jpaQuery.where(qAuditLogEntity.remoteAddress.containsIgnoreCase(command.getSearchRemoteAddress()));
|
jpaQuery.where(qAuditLogEntity.remoteAddress.containsIgnoreCase(command.getSearchRemoteAddress()));
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(command.getSearchParameters())) {
|
|
||||||
jpaQuery.where(qAuditLogEntity.parameters.containsIgnoreCase(command.getSearchParameters()));
|
|
||||||
}
|
|
||||||
|
|
||||||
long totalCount = jpaQuery.fetchOne();
|
long totalCount = jpaQuery.fetchOne();
|
||||||
List<AuditLogEntity> auditLogs = jpaQuery
|
List<AuditLogEntity> auditLogs = jpaQuery
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ public class AuditLog {
|
|||||||
|
|
||||||
private String logTypeText;
|
private String logTypeText;
|
||||||
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
private String parameters;
|
private String parameters;
|
||||||
|
|
||||||
private LocalDateTime lastModifiedDate;
|
private LocalDateTime lastModifiedDate;
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ package com.eactive.eai.rms.common.acl.audit.port.in;
|
|||||||
public interface SaveAuditLogUseCase {
|
public interface SaveAuditLogUseCase {
|
||||||
|
|
||||||
public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
|
public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
|
||||||
String parameters, String message);
|
String parameters);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -18,7 +18,6 @@ public class SelectListAuditLogCommand {
|
|||||||
|
|
||||||
private String searchUserId;
|
private String searchUserId;
|
||||||
private String searchRemoteAddress;
|
private String searchRemoteAddress;
|
||||||
private String searchParameters;
|
|
||||||
|
|
||||||
@JsonFormat(pattern = "yyyyMMddHHmmss")
|
@JsonFormat(pattern = "yyyyMMddHHmmss")
|
||||||
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
||||||
|
|||||||
@@ -59,16 +59,15 @@ class AuditLogService
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
|
public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
|
||||||
String parameters, String message) {
|
String parameters) {
|
||||||
|
|
||||||
AuditLog auditLog = new AuditLog(systemCode, logType, command, userId, remoteAddress);
|
AuditLog auditLog = new AuditLog(systemCode, logType, command, userId, remoteAddress);
|
||||||
String auditPointKey = AuditPoint.generateKey(logType, systemCode, command);
|
String auditPointKey = AuditPoint.generateKey(logType, systemCode, command);
|
||||||
AuditPoint auditPoint = auditPoints.get(auditPointKey);
|
AuditPoint auditPoint = auditPoints.get(auditPointKey);
|
||||||
|
|
||||||
auditLog.setLogTypeText(auditPoint.getLogTypeText());
|
auditLog.setLogTypeText(auditPoint.getLogTypeText());
|
||||||
auditLog.setLastModifiedDate(LocalDateTime.now());
|
auditLog.setLastModifiedDate(LocalDateTime.now());
|
||||||
auditLog.setParameters(parameters);
|
auditLog.setParameters(parameters);
|
||||||
auditLog.setMessage(message);
|
|
||||||
|
|
||||||
saveAuditLogPort.save(auditLog);
|
saveAuditLogPort.save(auditLog);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
package com.eactive.eai.rms.common.acl.sitemap;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.ui.Model;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
|
|
||||||
import com.eactive.eai.rms.common.base.BaseAnnotationController;
|
|
||||||
import com.eactive.eai.rms.common.login.SessionManager;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SitemapController extends BaseAnnotationController {
|
|
||||||
|
|
||||||
private final SitemapService sitemapService;
|
|
||||||
|
|
||||||
@GetMapping(value = "/common/acl/sitemap/sitemapMan.view")
|
|
||||||
public String view(@RequestParam(value = "serviceType", required = false) String serviceType,
|
|
||||||
HttpServletRequest request, Model model) {
|
|
||||||
List<String> roleIds = SessionManager.getRoleId(request);
|
|
||||||
model.addAttribute("sitemapTree", sitemapService.getSitemapTree(roleIds, serviceType));
|
|
||||||
return "/common/acl/sitemap/sitemapMan";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.eactive.eai.rms.common.acl.sitemap;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode;
|
|
||||||
|
|
||||||
public interface SitemapService {
|
|
||||||
|
|
||||||
public List<SitemapNode> getSitemapTree(List<String> roleIds, String serviceType);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
package com.eactive.eai.rms.common.acl.sitemap;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode;
|
|
||||||
import com.eactive.eai.rms.common.base.BaseService;
|
|
||||||
import com.eactive.eai.rms.data.entity.man.menu.Menu;
|
|
||||||
import com.eactive.eai.rms.data.entity.man.menu.MenuService;
|
|
||||||
import com.eactive.eai.rms.data.entity.man.role.RoleMenuAuthService;
|
|
||||||
|
|
||||||
@Service("sitemapService")
|
|
||||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
|
||||||
public class SitemapServiceImpl extends BaseService implements SitemapService {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private MenuService menuService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RoleMenuAuthService roleMenuAuthService;
|
|
||||||
|
|
||||||
public List<SitemapNode> getSitemapTree(List<String> roleIds, String serviceType) {
|
|
||||||
Menu root = menuService.getById("ROOT_DEV");
|
|
||||||
Menu langRoot = findLangRoot(root);
|
|
||||||
List<SitemapNode> tree = new ArrayList<>();
|
|
||||||
if (langRoot == null) {
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> serviceTypeMenuIds = StringUtils.isBlank(serviceType)
|
|
||||||
? null
|
|
||||||
: new HashSet<>(roleMenuAuthService.findMenuIdsByRoleIdsAndServiceType(roleIds, serviceType));
|
|
||||||
|
|
||||||
for (Menu menu : sortedChildren(langRoot)) {
|
|
||||||
if (isVisible(menu) && matchesServiceType(menu, serviceTypeMenuIds)) {
|
|
||||||
tree.add(buildNode(menu, serviceTypeMenuIds));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 엔티티의 childMenus는 menuId 기준으로 정렬되어 있어, 실제 메뉴(운영화면 GNB)와 동일하게 sortOrder 기준으로 재정렬한다.
|
|
||||||
private List<Menu> sortedChildren(Menu menu) {
|
|
||||||
List<Menu> children = new ArrayList<>(menu.getChildMenus());
|
|
||||||
children.sort(Comparator.comparing(Menu::getSortOrder, Comparator.nullsLast(Comparator.naturalOrder())));
|
|
||||||
return children;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MenuService.getMenuList()의 GNB 렌더링과 동일하게 "ROOT"(한글)/"ROOT_EN"(영문) 이름의 언어별 루트를 찾는다.
|
|
||||||
private Menu findLangRoot(Menu root) {
|
|
||||||
String lang = LocaleContextHolder.getLocale().getLanguage();
|
|
||||||
String langRootName = (StringUtils.isBlank(lang) || "ko".equalsIgnoreCase(lang))
|
|
||||||
? "ROOT"
|
|
||||||
: "ROOT_" + lang.toUpperCase();
|
|
||||||
|
|
||||||
return root.getChildMenus().stream()
|
|
||||||
.filter(m -> langRootName.equalsIgnoreCase(m.getMenuName()))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SitemapNode buildNode(Menu menu, Set<String> serviceTypeMenuIds) {
|
|
||||||
SitemapNode node = new SitemapNode(menu);
|
|
||||||
for (Menu child : sortedChildren(menu)) {
|
|
||||||
if (isVisible(child) && matchesServiceType(child, serviceTypeMenuIds)) {
|
|
||||||
node.getChildren().add(buildNode(child, serviceTypeMenuIds));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isVisible(Menu menu) {
|
|
||||||
return "Y".equalsIgnoreCase(menu.getDisplayYn()) && "Y".equalsIgnoreCase(menu.getUseYn());
|
|
||||||
}
|
|
||||||
|
|
||||||
// serviceType 필터가 없으면 통과. 있으면 자신이나 하위메뉴 중 하나라도 해당 serviceType 권한이 있어야 통과(상위메뉴 누락 방지).
|
|
||||||
private boolean matchesServiceType(Menu menu, Set<String> serviceTypeMenuIds) {
|
|
||||||
if (serviceTypeMenuIds == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (serviceTypeMenuIds.contains(menu.getMenuId())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return menu.getChildMenus().stream().anyMatch(child -> matchesServiceType(child, serviceTypeMenuIds));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.eactive.eai.rms.common.acl.sitemap.ui;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.eactive.eai.rms.data.entity.man.menu.Menu;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class SitemapNode {
|
|
||||||
|
|
||||||
private String menuId;
|
|
||||||
|
|
||||||
private String menuName;
|
|
||||||
|
|
||||||
private String menuUrl;
|
|
||||||
|
|
||||||
private List<SitemapNode> children = new ArrayList<>();
|
|
||||||
|
|
||||||
public SitemapNode(Menu menu) {
|
|
||||||
this.menuId = menu.getMenuId();
|
|
||||||
this.menuName = menu.getMenuName();
|
|
||||||
this.menuUrl = menu.getMenuUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
public SitemapNode() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,7 +33,6 @@ import com.eactive.eai.rms.data.entity.man.role.Role;
|
|||||||
import com.eactive.eai.rms.data.entity.man.role.RoleService;
|
import com.eactive.eai.rms.data.entity.man.role.RoleService;
|
||||||
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.UserBusinessService;
|
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.UserBusinessService;
|
||||||
import com.eactive.eai.rms.onl.common.exception.BizException;
|
import com.eactive.eai.rms.onl.common.exception.BizException;
|
||||||
import com.eactive.ext.djb.DamoManager;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
@@ -42,8 +41,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class UserManService extends BaseService {
|
public class UserManService extends BaseService {
|
||||||
|
|
||||||
private static final String USER_STATUS_NORMAL = "1";
|
|
||||||
|
|
||||||
private final UserInfoService userInfoService;
|
private final UserInfoService userInfoService;
|
||||||
private final UserRoleService userRoleService;
|
private final UserRoleService userRoleService;
|
||||||
private final UserBusinessService userBusinessService;
|
private final UserBusinessService userBusinessService;
|
||||||
@@ -100,12 +97,9 @@ public class UserManService extends BaseService {
|
|||||||
|
|
||||||
UserInfo userInfo = userUIMapper.toEntity(userUI);
|
UserInfo userInfo = userUIMapper.toEntity(userUI);
|
||||||
userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER);
|
userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER);
|
||||||
userInfo.setStatus(USER_STATUS_NORMAL);
|
|
||||||
|
|
||||||
String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256,userUI.getUserId()+subfix));
|
userInfo.setPassword(Seed.encrypt(userUI.getUserId()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Error encrypting password", e);
|
throw new RuntimeException("Error encrypting password", e);
|
||||||
}
|
}
|
||||||
@@ -134,12 +128,6 @@ public class UserManService extends BaseService {
|
|||||||
public void update(UserUI userUI) {
|
public void update(UserUI userUI) {
|
||||||
UserInfo userInfo = userInfoService.getById(userUI.getUserId());
|
UserInfo userInfo = userInfoService.getById(userUI.getUserId());
|
||||||
userUIMapper.updateToEntity(userUI, userInfo);
|
userUIMapper.updateToEntity(userUI, userInfo);
|
||||||
|
|
||||||
// 계정상태를 정상으로 저장하면 로그인 실패횟수 초기화
|
|
||||||
if (USER_STATUS_NORMAL.equals(userInfo.getStatus())) {
|
|
||||||
userInfo.setLoginfailcount(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
userInfoService.save(userInfo);
|
userInfoService.save(userInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,15 +139,9 @@ public class UserManService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updatePassword(UserUI userUI) throws Exception {
|
public void updatePassword(UserUI userUI) throws Exception {
|
||||||
String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
|
|
||||||
UserInfo userInfo = userInfoService.getById(userUI.getUserId());
|
UserInfo userInfo = userInfoService.getById(userUI.getUserId());
|
||||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256, userUI.getUserId()+subfix));
|
userInfo.setPassword(Seed.encrypt(userUI.getUserId()));
|
||||||
userUIMapper.updateToEntity(userUI, userInfo);
|
userUIMapper.updateToEntity(userUI, userInfo);
|
||||||
|
|
||||||
// 비밀번호 초기화 시 계정상태를 정상으로 변경하고 로그인 실패횟수 초기화
|
|
||||||
userInfo.setLoginfailcount(0);
|
|
||||||
userInfo.setStatus(USER_STATUS_NORMAL);
|
|
||||||
|
|
||||||
userInfoService.save(userInfo);
|
userInfoService.save(userInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import com.eactive.eai.rms.data.entity.man.user.UserServiceType;
|
|||||||
import com.eactive.eai.rms.data.entity.man.user.UserServiceTypeId;
|
import com.eactive.eai.rms.data.entity.man.user.UserServiceTypeId;
|
||||||
import com.eactive.eai.rms.data.entity.man.user.UserServiceTypeService;
|
import com.eactive.eai.rms.data.entity.man.user.UserServiceTypeService;
|
||||||
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.UserBusinessService;
|
import com.eactive.eai.rms.data.entity.onl.bzwkdstcd.UserBusinessService;
|
||||||
import com.eactive.ext.djb.DamoManager;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -125,7 +124,7 @@ public class UserSyncService extends BaseService {
|
|||||||
UserInfo userInfo = new UserInfo();
|
UserInfo userInfo = new UserInfo();
|
||||||
userInfo.setUserid(userId);
|
userInfo.setUserid(userId);
|
||||||
userInfo.setUsername(userInfoMap.get("EMPY_NM").toString());
|
userInfo.setUsername(userInfoMap.get("EMPY_NM").toString());
|
||||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256,userId));
|
userInfo.setPassword(Seed.encrypt(userId));
|
||||||
userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER);
|
userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER);
|
||||||
|
|
||||||
userInfoService.save(userInfo);
|
userInfoService.save(userInfo);
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ public interface UserUIMapper extends GenericMapper<UserUI, UserInfo> {
|
|||||||
@Mapping(source = "secondmentstdt", target = "SECONDMENTSTDT")
|
@Mapping(source = "secondmentstdt", target = "SECONDMENTSTDT")
|
||||||
@Mapping(source = "secondmentendt", target = "SECONDMENTENDT")
|
@Mapping(source = "secondmentendt", target = "SECONDMENTENDT")
|
||||||
@Mapping(source = "allowip", target = "allowIp")
|
@Mapping(source = "allowip", target = "allowIp")
|
||||||
@Mapping(source = "lastloginyms", target = "LASTLOGINYMS")
|
|
||||||
@Mapping(source = "regdyms", target = "REGDYMS")
|
|
||||||
UserUI toVo(UserInfo entity);
|
UserUI toVo(UserInfo entity);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -82,14 +82,4 @@ public class UserUI {
|
|||||||
|
|
||||||
@JsonProperty("STATUS")
|
@JsonProperty("STATUS")
|
||||||
private String status; // 사용자계정상태
|
private String status; // 사용자계정상태
|
||||||
|
|
||||||
@JsonProperty("LASTLOGINYMS")
|
|
||||||
@JsonFormat(pattern = LocalDateTimeFormatters.FORMAT_YYYYMMDDHHMMSS_14)
|
|
||||||
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
|
||||||
private LocalDateTime LASTLOGINYMS; // 최종로그인일시
|
|
||||||
|
|
||||||
@JsonProperty("REGDYMS")
|
|
||||||
@JsonFormat(pattern = LocalDateTimeFormatters.FORMAT_YYYYMMDDHHMMSS_14)
|
|
||||||
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
|
||||||
private LocalDateTime REGDYMS; // 등록일시
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,21 +255,12 @@ public interface MonitoringContext {
|
|||||||
// 이중 로그인 허용여부
|
// 이중 로그인 허용여부
|
||||||
public static final String RMS_DUAL_LOGIN_ENABLED = "rms.DUAL_LOGIN_ENABLED";
|
public static final String RMS_DUAL_LOGIN_ENABLED = "rms.DUAL_LOGIN_ENABLED";
|
||||||
|
|
||||||
// 자동 로그아웃 타임아웃 (단위: 분, 기본값: 60)
|
// 자동 로그아웃 타임아웃 (단위: 분, 기본값: 10)
|
||||||
public static final String RMS_AUTO_LOGOUT_TIMEOUT = "rms.auto.logout.timeout";
|
public static final String RMS_AUTO_LOGOUT_TIMEOUT = "rms.auto.logout.timeout";
|
||||||
|
|
||||||
// 웹훅
|
// 웹훅 재전송 설정
|
||||||
public static final String RMS_WEBHOOK_REVERSE_PROXY_URL = "rms.webhook.reverse_proxy.url";
|
public static final String API_WEBHOOK_RETRY_COUNT = "api.webhook.retry_count";
|
||||||
public static final String RMS_WEBHOOK_RETRY_COUNT = "rms.webhook.retry_count";
|
public static final String API_WEBHOOK_RETRY_TIME = "api.webhook.retry_time";
|
||||||
public static final String RMS_WEBHOOK_RETRY_TIME = "rms.webhook.retry_time";
|
|
||||||
|
|
||||||
//비밀번호 초기화 접미사
|
|
||||||
public static final String RMS_PASSWORD_INIT_SUBFIX = "rms.password.init.subfix";
|
|
||||||
|
|
||||||
// 최대 로그인 실패 허용횟수 (0이면 계정 잠금 미적용)
|
|
||||||
public static final String RMS_PASSWORD_FAIL_COUNT = "rms.password.fail.count";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import com.eactive.eai.rms.common.util.ContainerUtil;
|
|||||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.MonitoringPropertyId;
|
import com.eactive.eai.rms.data.entity.man.monitoringProperty.MonitoringPropertyId;
|
||||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyGroupService;
|
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyGroupService;
|
||||||
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyService;
|
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyService;
|
||||||
import com.eactive.eai.rms.ext.djb.common.DjbPropertyHolder;
|
import com.eactive.ext.kjb.common.KjbPropertyHolder;
|
||||||
import com.eactive.eai.rms.ext.djb.common.DjbPropertyInjector;
|
import com.eactive.ext.kjb.util.KjbPropertyInjector;
|
||||||
|
|
||||||
@Service("monitoringContext")
|
@Service("monitoringContext")
|
||||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||||
@@ -36,7 +36,7 @@ class MonitoringContextImpl implements MonitoringContext {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private MonitoringContextDAO monitoringContextDAO;
|
private MonitoringContextDAO monitoringContextDAO;
|
||||||
|
|
||||||
private Properties properties = new Properties();
|
private Properties properties = null;
|
||||||
|
|
||||||
private String instancePropertyGroupName;
|
private String instancePropertyGroupName;
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ class MonitoringContextImpl implements MonitoringContext {
|
|||||||
|
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
init();
|
init();
|
||||||
DjbPropertyHolder.reload();
|
KjbPropertyHolder.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh(String propName) {
|
public void refresh(String propName) {
|
||||||
@@ -73,10 +73,7 @@ class MonitoringContextImpl implements MonitoringContext {
|
|||||||
String hostIp = InetAddress.getLocalHost().getHostAddress();
|
String hostIp = InetAddress.getLocalHost().getHostAddress();
|
||||||
this.instancePropertyGroupName = String
|
this.instancePropertyGroupName = String
|
||||||
.format(MonitoringPropertyGroupService.MONITORING_PROPERTY_KEY_FORMAT, hostIp);
|
.format(MonitoringPropertyGroupService.MONITORING_PROPERTY_KEY_FORMAT, hostIp);
|
||||||
Properties loaded = monitoringContextDAO.getProperties(instancePropertyGroupName);
|
this.properties = monitoringContextDAO.getProperties(instancePropertyGroupName);
|
||||||
if (loaded != null) {
|
|
||||||
this.properties = loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
String eaiAgentId = System.getProperty(EAI_AGENTID);
|
String eaiAgentId = System.getProperty(EAI_AGENTID);
|
||||||
if (StringUtils.isBlank(eaiAgentId)) {
|
if (StringUtils.isBlank(eaiAgentId)) {
|
||||||
@@ -88,9 +85,9 @@ class MonitoringContextImpl implements MonitoringContext {
|
|||||||
|
|
||||||
setPortMapper(monitoringContextDAO.getPortMap());
|
setPortMapper(monitoringContextDAO.getPortMap());
|
||||||
|
|
||||||
// DjbPropertyHolder 초기화
|
// KjbPropertyHolder 초기화
|
||||||
DjbPropertyInjector injector = new DjbPropertyInjector(monitoringPropertyService, "Monitoring");
|
KjbPropertyInjector injector = new KjbPropertyInjector(monitoringPropertyService, "Monitoring");
|
||||||
DjbPropertyHolder.initialize(injector::inject);
|
KjbPropertyHolder.initialize(injector::inject);
|
||||||
|
|
||||||
logger.info("SSO AgentId : " + System.getProperty(EAI_AGENTID));
|
logger.info("SSO AgentId : " + System.getProperty(EAI_AGENTID));
|
||||||
|
|
||||||
|
|||||||
@@ -53,11 +53,9 @@ class RequestWrapper extends HttpServletRequestWrapper {
|
|||||||
"^data:image/.*",
|
"^data:image/.*",
|
||||||
Pattern.CASE_INSENSITIVE);
|
Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
// XSS 문자 변환을 건너뛸 파라미터 목록 (리치 텍스트 에디터 콘텐츠, 메시지 템플릿 본문 등)
|
// XSS 문자 변환을 건너뛸 파라미터 목록 (리치 텍스트 에디터 콘텐츠 등)
|
||||||
// XSS 패턴 필터링은 적용하지만 <, >, & 등으로 변환하지 않음
|
// XSS 패턴 필터링은 적용하지만 <, > 등으로 변환하지 않음
|
||||||
// (메시지 템플릿은 SMS/메신저 평문으로 전송되므로 '&'가 '&'로 깨지면 안 됨)
|
private static final String[] SKIP_CHAR_CONVERT_PARAMS = {"contents", "content", "description"};
|
||||||
private static final String[] SKIP_CHAR_CONVERT_PARAMS = {"contents", "content", "description",
|
|
||||||
"subjectTemplate", "smsTemplate", "emailTemplate", "messengerTemplate"};
|
|
||||||
|
|
||||||
// 현재 처리 중인 파라미터명 (cleanXSS에서 문자 변환 여부 결정에 사용)
|
// 현재 처리 중인 파라미터명 (cleanXSS에서 문자 변환 여부 결정에 사용)
|
||||||
private ThreadLocal<String> currentParameter = new ThreadLocal<>();
|
private ThreadLocal<String> currentParameter = new ThreadLocal<>();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user