hubez-admin partner-git master -> hubez-git transfer 202205241800

This commit is contained in:
hyunjin35
2022-05-24 18:12:19 +09:00
parent 013e992bc7
commit ad80b88089
309 changed files with 50355 additions and 91 deletions

3
frontend/.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}

2
frontend/.browserslistrc Normal file
View File

@@ -0,0 +1,2 @@
> 1%
last 2 versions

1
frontend/.env Normal file
View File

@@ -0,0 +1 @@
VUE_APP_TEST_PROP=local env value

4
frontend/.env.dev Normal file
View File

@@ -0,0 +1,4 @@
NODE_ENV = "dev"
BASE_URL: "/"
VUE_APP_TARGET_URL=https://console.ums-dev.uplus.co.kr/
VUE_APP_PORT=3000

4
frontend/.env.production Normal file
View File

@@ -0,0 +1,4 @@
NODE_ENV = "production"
BASE_URL: "/"
VUE_APP_TARGET_URL=https://console.ums-dev.uplus.co.kr/
VUE_APP_PORT=4000

21
frontend/.eslintrc.js Normal file
View File

@@ -0,0 +1,21 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
},
globals:{
'$': true,
'jQuery': true
},
parserOptions: {
parser: 'babel-eslint'
}
}

1
frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/npm-v6.10.0/

7
frontend/.prettierrc.js Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
// tabWidth: 4,
// useTabs: true,
semi: true,
singleQuote: true,
printWidth: 120
}

34
frontend/README.md Normal file
View File

@@ -0,0 +1,34 @@
# hubez-admin-web
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn run serve
```
### Compiles and minifies for production
```
yarn run build
```
### Run your tests
```
yarn run test
```
### Lints and fixes files
```
yarn run lint
```
### Run your unit tests
```
yarn run test:unit
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

5
frontend/babel.config.js Normal file
View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
}

30
frontend/jest.config.js Normal file
View File

@@ -0,0 +1,30 @@
module.exports = {
moduleFileExtensions: [
'js',
'jsx',
'json',
'vue'
],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
transformIgnorePatterns: [
'/node_modules/'
],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: [
'jest-serializer-vue'
],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
testURL: 'http://localhost/',
watchPlugins: [
'jest-watch-typeahead/filename',
'jest-watch-typeahead/testname'
]
}

15621
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

49
frontend/package.json Normal file
View File

@@ -0,0 +1,49 @@
{
"name": "hub-web-easy",
"version": "0.1.0",
"private": true,
"proxy":"http://localhost:7070",
"scripts": {
"serve": "vue-cli-service serve --port 3000",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit"
},
"dependencies": {
"@toast-ui/vue-grid": "2.1.0",
"axios": "^0.19.0",
"core-js": "^2.6.5",
"element-ui": "^2.15.0",
"file-saver": "^2.0.2",
"js-base64": "^2.5.1",
"moment": "^2.24.0",
"sticky-sidebar": "^3.3.1",
"tui-grid": "4.5.2",
"v-runtime-template": "^1.10.0",
"vue": "^2.6.10",
"vue-custom-scrollbar": "^1.4.0",
"vue-router": "^3.0.3",
"vue-scrollbar": "^1.0.4",
"vue-tiny-slider": "^0.1.35",
"vuejs-daum-postcode": "^1.0.4",
"vuex": "^3.0.1",
"xlsx": "^0.15.3"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.9.0",
"@vue/cli-plugin-eslint": "^3.9.0",
"@vue/cli-plugin-unit-jest": "^3.9.0",
"@vue/cli-service": "^3.9.0",
"@vue/test-utils": "1.0.0-beta.29",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "^10.0.1",
"babel-jest": "^23.6.0",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"less": "^4.1.0",
"less-loader": "^7.2.1",
"sass": "^1.18.0",
"sass-loader": "^7.1.0",
"vue-template-compiler": "^2.6.10"
}
}

View File

@@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>hubez-admin-web</title>
</head>
<body>
<noscript>
<strong>We're sorry but hubez-admin-web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

3
frontend/src/App.vue Normal file
View File

@@ -0,0 +1,3 @@
<template>
<router-view/>
</template>

View File

@@ -0,0 +1,72 @@
/* CSS Document */
a {text-decoration: none;}
ul,li {list-style: none;}
input,button {outline: none;}
input {padding: 15px; box-sizing: border-box; font-family: 'SpoqaHanSansNeo'; font-weight: 500; font-size: 14px;}
input::placeholder {font-family: 'SpoqaHanSansNeo'; font-weight: 500; font-size: 14px;}
button {cursor: pointer;font-family: 'SpoqaHanSansNeo'; font-weight: 500; font-size: 14px;}
html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
abbr, address, cite, code,
del, dfn, em, img, ins, kbd, q, samp,
small, strong, sub, sup, var,
b, i,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, figcaption, figure,
footer, header, hgroup, menu, nav, section, summary,
time, mark, audio, video {
margin:0; padding:0; box-sizing:border-box;
word-break: keep-all;
word-wrap: break-word;
}
a{box-sizing:border-box;}
article,aside,details,figcaption,figure,
footer,header,hgroup,menu,nav,section {
display:block;
}
table {
border-collapse:collapse;
border:0 none;
}
input, select, option{
font-family: 'SpoqaHanSansNeo';
}
input:focus{
outline: 1px solid #000;
}
select:focus{
outline: 1px solid #000;
}
input[type="checkbox"] + label{
cursor: pointer;
}
input:disabled{
background-color: #eeeeee;
}
input[type="radio"]{
display:none;
}
input[type="radio"] + label{
position: relative;
padding-left:25px;
cursor: pointer;
}
input[type="radio"] + label::before{
content: '';
position:absolute;
width:20px;
height:21px;
top:50%;
transform: translate(0,-50%);
left:0;
background:url(../images/icon-radio.png) no-repeat center/100% auto;
}
input[type="radio"]:checked + label::before{
background:url(../images/icon-radio-chk.png) no-repeat center/100% auto;
}

View File

@@ -0,0 +1,71 @@
/* CSS Document */
/*======================
======================*/
.btn-pcolor {background: #eb008b; border-radius: 6px; border: none; color: #fff; font-weight: 700; font-size: 16px;}
.btn-pcolor:hover{background: #b9006d;}
.btn-p2color {background: #2e2b46; border-radius: 6px; border: none; color: #fff; font-weight: 700; font-size: 16px;}
.btn-default {background: #fff; border-radius: 6px; border: 1px solid #a1a1a1; color: #5b5879; font-weight: 700; font-size: 16px;}
.btn-default:hover{border-color:#000;}
/*======================
.login-wrap
======================*/
.login-wrap {width: 100%; height: 100vh; background: url("../images/login-bg.jpg") no-repeat center center; background-size: cover;}
.bg-wrap {width: 100%; min-height: 100vh; background: #f0effa;}
.login-box {width: 520px; position: absolute; top: calc(50% - 80px); left: 50%; transform: translate(-50%,-50%); -webkit-transform: translate(-50%,-50%); -o-transform: translate(-50%,-50%); -moz-transform: translate(-50%,-50%);}
.adm-login.login-box {background: #fff; border-radius: 21px; box-shadow: 0 5px 13px rgba(56,56,56,0.05); padding: 65px 65px 40px 65px; box-sizing: border-box;}
.adm-login.login-box .wbox {border-radius: 0; box-shadow: none; padding: 0;}
.login-box .wbox {background: #fff; border-radius: 21px; box-shadow: 0 5px 13px rgba(56,56,56,0.05); padding: 50px 65px 40px 65px; box-sizing: border-box;}
.login-box .desc {font-size: 14px; color: #a6a6a6; letter-spacing: -1px; line-height: 140%; text-align: center; word-break: keep-all; padding-bottom: 20px;}
.login-box input {background: #f6f6f9; border-radius: 2px; padding: 15px; box-sizing: border-box; line-height: 20px; border: none; outline: none; width: 100%;}
.login-box input::placeholder {font-size: 16px; line-height: 20px; color: #acacac; font-weight: 500; }
.login-box input[type="checkbox"] {display: none;}
.login-box input[type="checkbox"] + label {cursor: pointer; display: flex; align-items: center; color: #333333; font-size: 16px; font-weight: 400; letter-spacing: -1px;}
.login-box input[type="checkbox"] + label:before {content: ""; width: 24px; height: 24px; display: inline-block; background: url("../images/icon-chk-n.png") no-repeat left center; background-size: contain; margin-right: 8px;}
.login-box input[type="checkbox"]:checked + label:before {background: url("../images/icon-chk.png") no-repeat left center; background-size: contain;}
.login-box .btn-pcolor {width: 100%; height: 55px; margin: 15px 0;}
.login-box li {list-style: none; margin: 10px 0; display: flex; justify-content: space-between; align-items: center; min-height: 50px;}
.login-box li.bg-g {background: #f6f6f9;}
.login-box .login-notice {}
.login-box .login-notice li {color: #a6a6a6; font-size: 14px; letter-spacing: -1px; font-weight: 400; position: relative; padding-left: 10px; min-height: auto;}
.login-box .login-notice li:before {content: ""; display: block; position: absolute; left: 0; top: 50%; margin-top: -1.5px; width: 3px; height: 3px; background: #e3e3ea;}
.login-box .login-notice li + li {margin-top: 10px;}
.login-box .title {font-size: 24px; color: #333333; margin: 0 auto 30px; text-align: center; font-weight: 500;}
.login-box .login-form {border-bottom: 1px solid #e3e3ea; padding-bottom: 10px; box-sizing: border-box; margin-bottom: 30px;}
.login-box .login-form li .btn-pwreset {border: none; background: url("../images/icon-lock.png") no-repeat left 3px #fff; background-size: contain; padding-left: 25px; height: 32px; color: #333333; font-size: 16px; font-weight: 400; letter-spacing: -1px; cursor: pointer;}
.text-auth .btn-p2color {border-radius: 2px; margin-left: 7px; width: 190px; height: 50px;}
.text-auth .btn-pcolor {width: 49%;}
.text-auth .btn-default {width: 49%; height: 55px;}
.text-auth .bg-g {}
.text-auth .time {padding: 15px 17px; color: #d92f89; font-size: 16px;}
.pw-reset .btn-pcolor {width: 64%;}
.pw-reset .btn-default {width: 34%; height: 55px;}

View File

@@ -0,0 +1,109 @@
/* CSS Document */
/*======================
SpoqaHanSansNeo
======================*/
@font-face {
font-family: 'SpoqaHanSansNeo';
src: url('../font/SpoqaHanSansNeo-Thin.woff') format('woff');
font-weight: 100;
font-style: normal;
}
@font-face {
font-family: 'SpoqaHanSansNeo';
src: url('../font/SpoqaHanSansNeo-Light.woff') format('woff');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'SpoqaHanSansNeo';
src: url('../font/SpoqaHanSansNeo-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'SpoqaHanSansNeo';
src: url('../font/SpoqaHanSansNeo-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'SpoqaHanSansNeo';
src: url('../font/SpoqaHanSansNeo-Bold.woff') format('woff');
font-weight: 700;
font-style: normal;
}
* {margin: 0; padding: 0; }
body,html {font-family: 'SpoqaHanSansNeo'; font-weight: 500; font-size: 14px;}
body{
min-width:1600px;
}
.div-cont {width: 1200px; padding: 0 30px; box-sizing: border-box; margin: auto;}
/*======================
#logo
======================*/
.login-box .logo {width: 280px; height: 72px; position: relative; margin: 0 auto 30px; background: url("../images/logo.png") no-repeat center center; background-size: contain;}
/*======================
#footer-wrap
======================*/
.login-wrap .footer-wrap {position: absolute; bottom: 0; left: 0;}
.bg-wrap .footer-wrap {position: absolute; bottom: 0; left: 0;}
.footer-wrap {width: 100%; background: #fff;}
.footer {display: flex; justify-content: space-between; align-items: flex-start; padding-top: 45px; padding-bottom: 45px;}
.footer .flogo {}
.footer .f-info {}
.footer .f-info > ul {display: flex; align-items: center; flex-wrap: wrap;}
.footer .f-info > ul li {list-style: none; margin-right: 30px; position: relative;}
.footer .f-info > ul li + li:before {content: ""; display: block; width: 1px; height: 14px; background: #7b7b7b; position: absolute; left: -15px; top: 50%; margin-top: -7px;}
.footer .f-info p {font-size: 14px; color: #7b7b7b; line-height: 170%; font-weight: 400;}
.footer .f-info a {font-size: 14px; color: #7b7b7b; line-height: 170%; text-decoration: none;}
/*======================
.popup
======================*/
.dimmed {width: 100vw; height: 100vh; position: fixed; top: 0; left: 0; background: rgba(0,0,0,0.4); display: none;}
.dimmed.open {display: block !important;}
.popup-wrap {display: none;}
.popup-wrap.open {display: block !important;}
.popup {width: 390px; border-radius: 8px; background: #fff; padding: 0 30px; box-sizing: border-box; border: 1px solid rgba(197,197,197,0.36); box-shadow: 2px 2px 8px rgba(171,171,171,0.30); position: fixed; top: 50%; left: 50%; transform: translate(-50%,-50%); -webkit-transform: translate(-50%,-50%); -moz-transform: translate(-50%,-50%); -o-transform: translate(-50%,-50%); display: none;}
.popup.open {display: block !important;}
.popup .pop-head {padding: 30px 0 25px;}
.popup .pop-head .pop-tit {font-size: 18px; color: #222222; letter-spacing: -1px; line-height: 100%;}
.popup .btn-close {width: 30px; height: 30px; position: absolute; top: 0; right: 0; background: url("../images/icon-close.png") no-repeat center center; background-size: 11px; border: none;}
.popup .pop-cont {}
.popup .pop-cont p {font-size: 16px; color: #666666; font-weight: 400; letter-spacing: -0.8px; line-height: 100%;}
.popup .pop-cont p + p {margin-top: 10px;}
.popup .pop-btn1 {display: flex; justify-content: flex-end; align-items: center; margin: 35px 0 25px;}
.popup .pop-btn2 {display: flex; justify-content: space-between; align-items: center; margin: 35px 0 25px;}
.popup .pop-btn1 button {width: 49%; height: 42px; font-size: 16px; font-weight: 400; letter-spacing: -1.1px;}
.popup .pop-btn2 button {width: 49%; height: 42px; font-size: 16px; font-weight: 400; letter-spacing: -1.1px;}

View File

@@ -0,0 +1,977 @@
.main_wrap {
background-color: #f0effa;
width: 100%;
min-height: 100vh;
position: relative;
padding: 70px 0 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}
header {
height: 70px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 20;
background-color: #f0effa;
}
header .logo {
width: 180px;
height: 26px;
background: url(../images/admin-logo.png) no-repeat center/100% auto;
font-size: 0;
margin: 23px 0 0 23px;
position: relative;
}
header .logo a {
display: block;
width: 100%;
height: 100%;
}
header .logo span {
font-size: 12px;
position: absolute;
right: -80px;
bottom: 0;
color: #b9b6d2;
line-height: 1;
letter-spacing: -0.025em;
}
header .user_wrap {
font-size: 14px;
color: #303035;
position: relative;
}
header .user_wrap a {
color: #303035;
}
header .user_wrap .user {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
width: 258px;
height: 63px;
background: url(../images/user-bg.png) no-repeat center/100% auto;
}
header .user_wrap .user p {
position: relative;
padding: 8px 12px 0 40px;
margin-right: 12px;
}
header .user_wrap .user p:after {
content: '';
width: 1px;
height: 12px;
background-color: #bab7d3;
position: absolute;
right: 0;
top: 12px;
}
header .user_wrap .user .btn_user {
padding: 8px 0 0 28px;
position: relative;
}
header .user_wrap .user .btn_user:before {
content: '';
position: absolute;
top: 8px;
left: 0;
width: 20px;
height: 20px;
background: url(../images/user-icon.png) no-repeat center/100% auto;
}
header .user_wrap .user .btn_user:after {
content: '';
position: absolute;
top: 16px;
right: -17px;
width: 11px;
height: 6px;
background: url(../images/arrow-down.png) no-repeat center/100% auto;
}
header .user_wrap .user.clicked + .user_info {
display: block;
}
header .user_wrap .user.clicked .btn_user:after {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
header .user_wrap .user_info {
border: 1px solid #cbcbcb;
background-color: #fff;
-webkit-box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.18);
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.18);
border-radius: 12px;
width: 108px;
height: 84px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
position: absolute;
top: 40px;
right: 24px;
display: none;
}
header .user_wrap .user_info a {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 50%;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
header .user_wrap .user_info .modify {
color: #d92f89;
padding-top: 15px;
}
header .user_wrap .user_info .logout {
color: #333333;
padding-top: 5px;
}
.main_menu {
overflow: hidden;
background-color: #7572a5;
border-radius: 24px;
width: 240px;
position: relative;
margin-bottom: 25px;
padding:25px 0;
}
.main_menu:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 50px;
height: 100%;
background-color: #34344f;
border-radius: 25px;
}
.main_menu > li {
padding: 0 0 0 50px;
position: relative;
}
.main_menu > li > a {
color: rgba(255, 255, 255, 0.5);
font-size: 16px;
display: block;
position: relative;
padding: 10px;
transition: all 0.3s;
}
.main_menu > li > a:after {
content: '';
position: absolute;
top: 50%;
right: 15px;
transform-origin: center;
transition: transform 0.3s;
width: 11px;
height: 6px;
background: url(../images/arrow-white.png) no-repeat center/100% auto;
opacity: 0.5;
-webkit-transform: translateY(-50%) rotate(180deg);
transform: translateY(-50%) rotate(180deg);
}
.main_menu > li.is-current > a {
color: #fff;
}
.main_menu > li.is-current > a:before {
opacity: 1;
}
.main_menu > li.is-current > a:after {
opacity: 1;
-webkit-transform: translateY(-50%) rotate(0deg);
transform: translateY(-50%) rotate(0deg);
}
.main_menu > li.is-current .sub_menu {
display: block;
}
.main_menu > li.is-current:last-child .sub_menu {
margin-bottom: 0;
}
.main_menu .sub_menu {
background-color: #fff;
border-radius: 10px;
padding: 18px 10px;
transition: all 0.3s;
}
.main_menu .sub_menu > li {
padding: 0 0 15px 5px;
position: relative;
}
.main_menu .sub_menu > li:last-child {
padding-bottom: 0;
}
.main_menu .sub_menu > li:before {
content: '';
position: absolute;
top: 7px;
left: 0;
width: 3px;
height: 3px;
background-color: #bcb8e1;
}
.main_menu .sub_menu > li > a {
font-size: 14px;
color: #68647a;
display: block;
}
.main_menu .is-current .sub_menu > li:hover > a,.main_menu .is-current .sub_menu > li > a.selected { color:#000000; }
/* 추가 */
.main_menu > li .menu_btn { position: absolute; left:0; top:0; font-size: 0; width: 50px; height: 43px; transition: all 0.3s; cursor: pointer; }
.main_menu > li.customer .menu_btn { background: url(../images/icon-customer.png) no-repeat center/auto; }
.main_menu > li.attract .menu_btn { background: url(../images/icon-attract.png) no-repeat center/auto; }
.main_menu > li.service .menu_btn { background: url(../images/icon-service.png) no-repeat center/auto; }
.main_menu > li.calculate .menu_btn { background: url(../images/icon-calculate.png) no-repeat center/auto; }
.main_menu > li.channel .menu_btn { background: url(../images/icon-channel.png) no-repeat center/auto; }
.main_menu > li.key .menu_btn { background: url(../images/icon-key.png) no-repeat center/auto; }
.main_menu > li.moniter .menu_btn { background: url(../images/icon-moniter.png) no-repeat center/auto; }
.main_menu > li.risk .menu_btn { background: url(../images/icon-risk.png) no-repeat center/auto; }
.main_menu > li.stats .menu_btn { background: url(../images/icon-stats.png) no-repeat center/auto; }
.main_menu > li.system .menu_btn { background: url(../images/icon-system.png) no-repeat center/auto; }
.main_menu > li:hover > a { background: #646193; color: #fff; }
.main_menu > li.customer:hover .menu_btn { background: url(../images/icon-customer-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.attract:hover .menu_btn { background: url(../images/icon-attract-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.service:hover .menu_btn { background: url(../images/icon-service-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.calculate:hover .menu_btn { background: url(../images/icon-calculate-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.channel:hover .menu_btn { background: url(../images/icon-channel-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.key:hover .menu_btn { background: url(../images/icon-key-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.moniter:hover .menu_btn { background: url(../images/icon-moniter-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.risk:hover .menu_btn { background: url(../images/icon-risk-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.stats:hover .menu_btn { background: url(../images/icon-stats-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.system:hover .menu_btn { background: url(../images/icon-system-on.png) no-repeat center/auto #4a496c; }
.main_menu > li.customer.is-current .menu_btn { background-image: url(../images/icon-customer-on.png); }
.main_menu > li.attract.is-current .menu_btn { background-image: url(../images/icon-attract-on.png); }
.main_menu > li.service.is-current .menu_btn { background-image: url(../images/icon-service-on.png); }
.main_menu > li.calculate.is-current .menu_btn { background-image: url(../images/icon-calculate-on.png); }
.main_menu > li.channel.is-current .menu_btn { background-image: url(../images/icon-channel-on.png); }
.main_menu > li.key.is-current .menu_btn { background-image: url(../images/icon-key-on.png); }
.main_menu > li.moniter.is-current .menu_btn { background-image: url(../images/icon-moniter-on.png); }
.main_menu > li.risk.is-current .menu_btn { background-image: url(../images/icon-risk-on.png); }
.main_menu > li.stats.is-current .menu_btn { background-image: url(../images/icon-stats-on.png); }
.main_menu > li.system.is-current .menu_btn { background-image: url(../images/icon-system-on.png); }
.main_menu > li .sub_menu_wrap { padding:0 10px 10px; display:none; }
.main_menu > li.is-current .sub_menu_wrap { display: block; }
.contents {
padding: 0 4.16vw;
width: 100%;
-webkit-box-flex: 1;
-ms-flex: 1 1 0px;
flex: 1 1 0;
}
.contents_wrap {
-webkit-box-shadow: 8px 8px 8px rgba(80, 80, 80, 0.08);
box-shadow: 8px 8px 8px rgba(80, 80, 80, 0.08);
background-color: #fff;
width: 100%;
border-radius: 24px;
padding: 15px 0;
margin-bottom: 70px;
}
.contents_wrap .search_form {
padding: 0 40px;
}
.contents .top_wrap {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
border-bottom: 1px solid #d5d3e6;
padding: 0 40px;
margin-bottom: 27px;
}
.contents .top_wrap .title {
font-size: 18px;
color: #1b1b1b;
letter-spacing: -0.025em;
padding-bottom: 14px;
border-bottom: 4px solid #eb008b;
margin-bottom: -1px;
}
.contents .top_wrap .breadcrumb {
font-size: 13px;
color: #9493a1;
letter-spacing: -0.025em;
}
.contents .search_wrap {
background-color: #f6f6f8;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding: 20px 30px 40px;
-webkit-box-align: end;
-ms-flex-align: end;
align-items: flex-end;
border-radius: 4px;
margin-bottom: 50px;
}
.contents .search_wrap button.grey {
background-color: #35354f;
width: 122px;
font-size: 18px;
padding: 0 8px;
margin-left: 0;
}
.contents .select_box {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
margin-right: 10px;
width: 13.67%;
}
.contents .select_box .label {
font-size: 13px;
letter-spacing: -0.025em;
margin-bottom: 6px;
color: #a3a3a3;
}
.contents .select_box select {
width: 100%;
height: 40px;
border: 1px solid #c9c9c9;
font-size: 14px;
color: #000;
border-radius: 4px;
padding:0 10px;
-webkit-appearance:none;
-moz-appearance:none;
-o-appearance:none;
appearance:none;
background:#fff url('../images/icon-select-down.png')no-repeat right 10px center;
}
.contents .select_box option {
color: #000;
}
.contents .input_box {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
margin-right: 10px;
width: 22.64%;
}
.contents .input_box .label {
font-size: 13px;
letter-spacing: -0.025em;
margin-bottom: 6px;
color: #a3a3a3;
}
.contents .input_box input {
width: 100%;
height: 40px;
border: 1px solid #c9c9c9;
position: relative;
background: url(../images/icon-search.png) no-repeat 6% center/14px auto;
background-color: #fff;
padding-left: 43px;
border-radius: 4px;
}
.contents .input_box input::-webkit-input-placeholder {
color: #c9c9c9;
}
.contents .input_box input:-ms-input-placeholder {
color: #c9c9c9;
}
.contents .input_box input::-ms-input-placeholder {
color: #c9c9c9;
}
.contents .input_box input::placeholder {
color: #c9c9c9;
}
.contents .input_box.id {
position: relative;
margin-left: 10px;
}
.contents .input_box.id:before {
content: '';
position: absolute;
top: 25px;
left: -10px;
width: 1px;
height: 36px;
background-color: #e8e8f1;
}
.contents .button {
height: 40px;
color: #fff;
border-radius: 4px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
border: none;
min-width: 80px;
margin-left: 10px;
}
.contents .button.grey {
background-color: #35354f;
font-size: 16px;
}
.contents .button.grey:hover {
background-color: #0a0b24;
}
.contents .button.blue {
background-color: #333589;
font-size: 16px;
padding: 0 15px;
}
.contents .button.blue:hover {
background-color: #0a0b24;
}
.contents .button.white {
border: 1px solid #c9c9c9;
font-size: 16px;
background-color: #fff;
color: #000;
}
.contents .button.white:hover {
border-color: #000;
}
.contents .info {
padding: 0 30px;
margin-bottom: 10px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}
.contents .info .count {
font-size: 16px;
position: relative;
padding-left: 10px;
}
.contents .info .count span {
color: #eb008b;
}
.contents .info .count:before {
content: '';
position: absolute;
top: 10px;
left: 0;
width: 3px;
height: 3px;
background-color: #eb008b;
}
.contents .info .button_group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.contents .info .title {
font-size: 18px;
position: relative;
padding-left: 10px;
margin-top: 9px;
}
.contents .info .title:before {
content: '';
position: absolute;
top: 10px;
left: 0;
width: 3px;
height: 3px;
background-color: #eb008b;
}
.contents .table {
color: #333333;
padding: 0 30px;
margin-bottom: 65px;
}
.contents .table table {
width: 100%;
text-align: center;
border-top: 2px solid #69677e;
border-bottom: 1px solid #a4a4b0;
}
.contents .table table thead {
background-color: #f7f7f7;
}
.contents .table table tbody tr:last-child {
border-bottom: none;
}
.contents .table table th {
font-weight: 500;
height: 50px;
position: relative;
}
.contents .table table tr {
padding: 10px;
height: 50px;
border-bottom: 1px solid #dadae6;
}
.contents .table table tr:hover {
background-color: #fafaff;
}
.contents .table table td {
position: relative;
}
.contents .table table td a {
text-decoration: underline;
color: #333333;
}
.contents .table table td a:hover {
color: #eb008b;
}
.contents .table table td.stop {
color: #a5a5a5;
}
.contents .table table td.two_btn_group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
height: 50px;
}
.contents .table table input[type="checkbox"] {
display: none;
}
.contents .table table input[type="checkbox"] + label {
width: 20px;
height: 30px;
display: block;
background: url(../images/icon-chk-n-square.png) no-repeat center/100% auto;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.contents .table table input[type="checkbox"]:checked + label {
background: url(../images/icon-chk-square.png) no-repeat center/100% auto;
}
.contents .table.table_form {
font-size: 16px;
margin-bottom: 24px;
}
.contents .table.table_form th {
background-color: #f7f7f7;
width: 9%;
text-align: left;
padding-left: 20px;
}
.contents .table.table_form th.center {
text-align: center;
padding-left: 0;
}
.contents .table.table_form td {
text-align: left;
}
.contents .table.table_form td.check {
padding: 20px;
width: 15%;
vertical-align: text-top;
}
.contents .table.table_form td.check p {
margin-bottom: 15px;
}
.contents .table.table_form input[type="checkbox"] + div > label:first-child {
width: 20px;
height: 30px;
display: block;
background: url(../images/icon-chk-n-square.png) no-repeat center/100% auto;
margin-right: 10px;
}
.contents .table.table_form input[type="checkbox"]:checked + div > label:first-child {
background: url(../images/icon-chk-square.png) no-repeat center/100% auto;
margin-right: 10px;
}
.contents .table.table_form .label_group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.contents .table.table_form .tr_checkbox {
border-bottom: none;
}
.contents .table.table_form .tr_checkbox .check:first-child {
background-color: #f7f7f7;
}
.contents .table.table_form .tr_input input[type="text"] {
border: 1px solid #c9c9c9;
border-radius: 4px;
height: 40px;
margin-left: 10px;
}
.contents .table.table_form .tr_input.w30 input[type="text"] {
width: 30%;
}
.contents .table.table_form .tr_input.w75 input[type="text"] {
width: 75%;
}
.contents .table.table_form .tr_input.w100 input[type="text"] {
width: 98%;
}
.contents .table.table_form .tr_input input[type="radio"] + label:nth-child(2) {
margin: 0 30px 0 10px;
}
.contents .pop-btn2 {
text-align: end;
padding: 0 30px;
margin-bottom: 9px;
}
.contents .pop-btn2 button {
width: 160px;
height: 42px;
}
.contents .pop-btn2 .btn-pcolor {
margin-left: 8px;
}
.popup .pop-cont-detail {
font-size: 16px;
color: #666666;
border-radius: 12px;
background-color: #f5f6f8;
padding: 15px;
margin-top: 13px;
}
.popup .pop-cont-detail li {
position: relative;
padding-left: 10px;
}
.popup .pop-cont-detail li:before {
content: '';
position: absolute;
top: 50%;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%);
left: 0;
width: 2px;
height: 2px;
background-color: #c7c7c7;
}
.popup.popup_form {
width: 525px;
}
.popup.popup_form .pop-head {
border-bottom: 1px solid #d5d3e6;
padding-bottom: 0;
margin-bottom: 25px;
}
.popup.popup_form .pop-tit {
display: inline-block;
border-bottom: 4px solid #eb008b;
padding-bottom: 20px;
margin-bottom: -1px;
}
.popup.popup_form .pop-btn2 {
-webkit-box-pack: end;
-ms-flex-pack: end;
justify-content: flex-end;
}
.popup.popup_form .pop-btn2 button {
width: 30%;
}
.popup.popup_form .pop-btn2 button:last-child {
margin-left: 10px;
}
.popup.popup_form table {
width: 100%;
border-top: 1px solid #dadae6;
border-bottom: 1px solid #dadae6;
}
.popup.popup_form table tr {
border-bottom: 1px solid #dadae6;
height: 50px;
}
.popup.popup_form table tr:last-child {
border-bottom: none;
}
.popup.popup_form table th {
width: 30%;
background-color: #f7f7f7;
font-size: 16px;
color: #333333;
text-align: left;
padding-left: 20px;
}
.popup.popup_form table td {
padding: 0 0 0 10px;
}
.popup.popup_form table td input {
width: 100%;
height: 40px;
border: 1px solid #c9c9c9;
border-radius: 4px;
font-size: 16px;
}
.popup.popup_form table td input::-webkit-input-placeholder {
color: #c9c9c9;
}
.popup.popup_form table td input:-ms-input-placeholder {
color: #c9c9c9;
}
.popup.popup_form table td input::-ms-input-placeholder {
color: #c9c9c9;
}
.popup.popup_form table td input::placeholder {
color: #c9c9c9;
}
.popup.popup_form table input[type="radio"] + label {
font-size: 16px;
vertical-align: text-top;
}
.popup.popup_form table input[type="radio"] + label:nth-child(2) {
margin-right: 40px;
}
.popup.popup_form table select {
width: 100%;
height: 40px;
border: 1px solid #c9c9c9;
border-radius: 4px;
padding: 0 10px;
font-size: 16px;
color: #333333;
}
.popup.popup_form table .input_search {
height: 50px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.popup.popup_form table .input_search input[type="text"] {
position: relative;
background: url(../images/icon-search.png) no-repeat 6% center/14px auto;
background-color: #fff;
padding-left: 40px;
border-radius: 4px;
width: 72%;
}
.popup.popup_form table .input_search input[type="text"]::-webkit-input-placeholder {
color: #c9c9c9;
}
.popup.popup_form table .input_search input[type="text"]:-ms-input-placeholder {
color: #c9c9c9;
}
.popup.popup_form table .input_search input[type="text"]::-ms-input-placeholder {
color: #c9c9c9;
}
.popup.popup_form table .input_search input[type="text"]::placeholder {
color: #c9c9c9;
}
.popup.popup_form table .button {
height: 40px;
color: #fff;
border-radius: 4px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
border: none;
min-width: 80px;
margin-left: 10px;
}
.popup.popup_form table .button.grey {
background-color: #35354f;
font-size: 16px;
}
.popup.popup_form table .button.grey:hover {
background-color: #0a0b24;
}
/*# sourceMappingURL=style.css.map */

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,66 @@
/*(function(){
const menuList = document.querySelectorAll('.main_menu .is-sub');
for(const menu of menuList){
menu.addEventListener('click', (e)=> {
if(e.target.classList.contains('menu_target') || e.target.classList.contains('menu_btn')){
const menuListCheck = e.target.parentNode;
if(menuListCheck.classList.contains('is-current')){
menuListCheck.classList.remove('is-current');
} else {
for(const other of menuList){
other.classList.remove('is-current');
}
menuListCheck.classList.add('is-current');
}
}
})
}
})();*/
/*const ModalOpen = target =>{
console.log("ModalOpen");
var dimmed = document.getElementsByClassName('dimmed');
var wrap = document.getElementsByClassName('popup-wrap');
var obj = document.getElementsByClassName(target);
dimmed[0].style.display = 'block';
wrap[0].style.display = 'block';
obj[0].style.display = 'block';
}*/
// eslint-disable-next-line no-unused-vars
/*function ModalOpen(target) {
var dimmed = document.getElementsByClassName('dimmed');
var wrap = document.getElementsByClassName('popup-wrap');
var obj = document.getElementsByClassName(target);
dimmed[0].style.display = 'block';
wrap[0].style.display = 'block';
obj[0].style.display = 'block';
}*/
// eslint-disable-next-line no-unused-vars
/*function ModalClose() {
var dimmed = document.getElementsByClassName('dimmed');
var wrap = document.getElementsByClassName('popup-wrap');
var obj = wrap[0].childElementCount
dimmed[0].style.display = 'none';
wrap[0].style.display = 'none';
for(var i = 0; i < obj; i++) {
var target = document.getElementsByClassName('popup');
target[i].style.display = 'none';
}
}
// eslint-disable-next-line no-unused-vars
function userInfoToggle(){
var click = "clicked";
var userBtn = document.querySelector('.user_wrap .user');
if(userBtn.classList.contains(click)){
userBtn.classList.remove(click);
}
else{
userBtn.classList.add(click);
}
}*/
export default{
ModalOpen
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,9 @@
import httpClient from '@/common/http-client';
// 주소찾기
const getAddressList = params => {
return httpClient.get('/api/comm/address', { params: params })
}
export default {
getAddressList
}

View File

@@ -0,0 +1,10 @@
const { VUE_APP_TEST_PROP, NODE_ENV = '' } = process.env;
const environment = NODE_ENV.toLowerCase();
const testProp = VUE_APP_TEST_PROP;
const consts = {
tokenPart1: 'JwtPart1'
}
export { environment, testProp, consts };

View File

@@ -0,0 +1,143 @@
import xlsx from 'xlsx';
const xlsxUtils = {
filename: '',
data: [],
header: [],
options: {},
summary: {
isUse: false,
position: '',
data: null,
title: { replaceKeys: [], name: '' }
},
visibleDataOrder: [],
instance: undefined,
createInstance() {
return new Promise((resolve, reject) => {
this.instance = document.createElement('table');
resolve();
});
},
createHeader() {
return new Promise((resolve, reject) => {
let header = this.header;
/*
if (!Array.isArray(this.header[0])) {
header.push(this.header);
} else {
header = this.header;
}
*/
let thead = document.createElement('thead');
for (let row of header) {
let tr = document.createElement('tr');
for (let h of row) {
let rowspan = h.rowspan || '1';
let colspan = h.colspan || '1';
let th = document.createElement('th');
th.setAttribute('rowspan', rowspan);
th.setAttribute('colspan', colspan);
//th.setAttribute('align', 'center');
th.innerText = h.name;
tr.appendChild(th);
}
thead.appendChild(tr);
}
this.instance.appendChild(thead);
resolve();
});
},
createDataRows() {
return new Promise((resolve, reject) => {
let tbody = document.createElement('tbody');
if (this.options.summary != undefined && this.options.summary.isUse) {
this.summary = this.options.summary;
}
if (this.summary.isUse && this.summary.position === 'first') {
this.appendDataRow(tbody, this.summary.data, true);
}
this.appendDataRow(tbody, this.data, false);
if (this.summary.isUse && this.summary.position === 'last') {
this.appendDataRow(tbody, this.summary.data, true);
}
this.instance.appendChild(tbody);
resolve();
});
},
appendDataRow(tbody, data, isSummary) {
for (let row of data) {
let tr = document.createElement('tr');
if (isSummary) {
let td = document.createElement('td');
td.innerText = this.summary.title.name;
td.setAttribute('colspan', this.summary.title.replaceKeys.length);
//td.setAttribute('align', 'center');
tr.appendChild(td);
}
for (let cellkey of this.visibleDataOrder) {
if (isSummary && this.summary.title.replaceKeys.indexOf(cellkey) > -1) continue;
let td = document.createElement('td');
td.innerText = row[cellkey];
tr.appendChild(td);
}
tbody.appendChild(tr);
}
return tbody;
},
getVisibleDataOrder() {
let dataOrder = [];
if (Array.isArray(this.options.dataOrder)) {
dataOrder = this.options.dataOrder;
} else if (this.options.dataOrder === 'header') {
for (let row of this.header) {
for (let h of row) {
if (h.key != undefined && h.key != null && h.key !== '') {
dataOrder.push(h.key);
}
}
}
} else {
dataOrder = Object.keys(this.data[0]);
}
this.visibleDataOrder = dataOrder;
},
export(data, filename, options) {
this.data = data;
this.filename = filename;
this.header = options.header;
this.options = options;
this.getVisibleDataOrder();
return new Promise((resolve, reject) => {
this.createInstance().then(() => {
this.createHeader().then(() => {
this.createDataRows().then(() => {
this.exportTableToXlsx();
resolve();
});
});
});
});
},
exportTableToXlsx() {
let config = { raw: true, type: 'string' };
let ws = xlsx.utils.table_to_sheet(this.instance, config);
let wb = xlsx.utils.book_new();
xlsx.utils.book_append_sheet(wb, ws, 'Sheet1');
xlsx.writeFile(wb, this.filename);
}
};
export default xlsxUtils;

View File

@@ -0,0 +1,105 @@
import axios from 'axios';
import { testProp } from './config';
const config = {
//baseURL: 'http://localhost:7070',
// baseURL: apiBaseUrl,
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
timeout: 120000 // timeout은 120초로 설정
};
const httpClient = axios.create(config);
const authInterceptor = config => {
// frontend와 backend의 origin이 다른 경우
// devServer.proxy 설정을 하던지 baseURL과 withCredentials 설정을 해야 한다.
// cookie, header 등에 자격정보 설정이 필요한 api는 true 설정으로 호출해야 하고
// 자격정보 설정이 필요없는 api는 withCredentials=false 설정으로 호출해야 한다.
// config.withCredentials = !config.url.startsWith('/api/public/');
console.log("Test Url : "+ config.url);
/*if(config.url == '/api/auth/login'){
config.baseURL = "http://localhost:3000";
}*/
return config;
};
const loggerInterceptor = config => {
console.log('testProp:', testProp);
console.log('request url:', config.url, 'params:', config.data);
return config;
};
let loadOverlap = [];
const loadingLayer = (type, config) => {
/*
get: httpClient.get(url, { params: { ... }, headers: {"show-layer": "Yes"} }) // in 2nd property
post: httpClient.post(url, params, { headers: {"show-layer": "Yes"} }) // 3rd property
*/
if (config.headers['Show-Layer'] == 'Yes') {
if (type) {
loadOverlap.push('add');
} else {
loadOverlap.pop();
}
if (loadOverlap.length > 0) {
document.querySelector('html > body').style.overflow = 'hidden'; // 스크롤 block
document.getElementsByClassName('loading_layer')[0].style.display = 'block';
} else {
document.querySelector('html > body').style.removeProperty('overflow'); // 스크롤 allow
document.getElementsByClassName('loading_layer')[0].style.display = 'none';
}
}
};
/*const loadingLayerInterceptor = config => {
loadingLayer(true, config);
return config;
};*/
/** Adding the request interceptors */
httpClient.interceptors.request.use(authInterceptor);
httpClient.interceptors.request.use(loggerInterceptor);
//httpClient.interceptors.request.use(loadingLayerInterceptor);
/** Adding the response interceptors */
httpClient.interceptors.response.use(
response => {
//loadingLayer(false, response.config);
console.log('response status:', response.status, 'data:', response.data);
return response;
},
error => {
console.log(error);
if (error.response != undefined && error.response != null) loadingLayer(false, error.response.config);
else loadingLayer(false, error.config);
if (error.code === 'ECONNABORTED') {
alert('서비스가 지연되고 있습니다. 잠시 후 확인하시고 다시 시도해주세요.');
return Promise.reject(error);
} else if (error.response.status == 401 || error.response.status == 418) {
alert('세션이 만료되었습니다.');
window.top.location.href = '/login';
} else if (error.response.status == 500) {
if (error.response.data != null && error.response.data.message == '511 NETWORK_AUTHENTICATION_REQUIRED') {
alert('웹템플릿 IP가 브랜드포털에 등록이 필요합니다. 기술지원에 문의해주세요.');
return Promise.reject(error);
} else {
window.top.location.href = '/view/error/500';
}
} else if (error.response.status == 511) {
alert('웹템플릿 IP가 브랜드포털에 등록이 필요합니다. 기술지원에 문의해주세요.');
return Promise.reject(error);
} else if (error.message == 'Network Error') {
alert('네트워크 오류가 발생했습니다. 잠시 후 다시 시도해주세요.');
return Promise.reject(error);
} else {
console.log('response error:', error);
return Promise.reject(error);
}
}
);
export default httpClient;

View File

@@ -0,0 +1 @@
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):((t=t||self).vdp_translation_ko=t.vdp_translation_ko||{},t.vdp_translation_ko.js=n())}(this,function(){"use strict";function t(t,n){for(var e=0;e<n.length;e++){var r=n[e];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}var n=new(function(){function n(t,e,r,o){!function(t,n){if(!(t instanceof n))throw new TypeError("Cannot call a class as a function")}(this,n),this.language=t,this.months=e,this.monthsAbbr=r,this.days=o,this.rtl=!1,this.ymd=!1,this.yearSuffix=""}var e,r,o;return e=n,(r=[{key:"language",get:function(){return this._language},set:function(t){if("string"!=typeof t)throw new TypeError("Language must be a string");this._language=t}},{key:"months",get:function(){return this._months},set:function(t){if(12!==t.length)throw new RangeError("There must be 12 months for ".concat(this.language," language"));this._months=t}},{key:"monthsAbbr",get:function(){return this._monthsAbbr},set:function(t){if(12!==t.length)throw new RangeError("There must be 12 abbreviated months for ".concat(this.language," language"));this._monthsAbbr=t}},{key:"days",get:function(){return this._days},set:function(t){if(7!==t.length)throw new RangeError("There must be 7 days for ".concat(this.language," language"));this._days=t}}])&&t(e.prototype,r),o&&t(e,o),n}())("Korean",["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],["일","월","화","수","목","금","토"]);return n.yearSuffix="년",n.ymd=!0,n});

View File

@@ -0,0 +1,38 @@
import * as utils from './utils';
import { consts } from './config';
// const KEY_TOKEN = 'access_token';
const tokenSvc = {
getToken() {
// return store.getters['login/getToken'];
// var payload = sessionStorage.getItem(KEY_TOKEN);
var jwtPart1 = utils.getCookie(consts.tokenPart1);
if (!jwtPart1)
return null;
var payload = utils.base64decode(jwtPart1.split('.').pop());
return JSON.parse(payload);
},
removeToken() {
var name = consts.tokenPart1;
document.cookie = name + '=; expires=Thu, 01 Jan 1999 00:00:10 GMT;';
}
// saveToken(jwtPart1) {
// if (!jwtPart1)
// return;
// var payload = utils.base64decode(jwtPart1.split('.').pop());
// console.log('save token:', payload);
// // store.commit('login/saveToken', token);
// sessionStorage.setItem(KEY_TOKEN, payload);
// },
// removeToken() {
// // store.commit('login/removeToken');
// sessionStorage.removeItem(KEY_TOKEN);
// }
};
export default tokenSvc;

View File

@@ -0,0 +1,117 @@
/**
* @description This method is responsile for creating the object with mirror key and values
* and also add prefix to values if available
* @param {Array<string>} arr Array of strings
* @param {string} prefix prefix
* @returns {Object} object with mirror keys generated from the array of strings
*/
export const reflectKeys = (arr = [], prefix) =>
arr.reduce((obj, key) => {
const value = prefix ? prefix + ' ' + key : key;
obj[key] = value;
return obj;
}, {});
export const form2obj = function(form) {
var queryStr = serializeForm(form);
return qstr2obj(queryStr);
};
/*!
* Serialize all form data into a query string
* (c) 2018 Chris Ferdinandi, MIT License, https://gomakethings.com
* @param {Node} form The form to serialize
* @return {String} The serialized form data
*/
export const serializeForm = function(form) {
// Setup our serialized data
var serialized = [];
// Loop through each field in the form
for (var i = 0; i < form.elements.length; i++) {
var field = form.elements[i];
// Don't serialize fields without a name, submits, buttons, file and reset inputs, and disabled fields
if (
!field.name ||
field.disabled ||
field.type === 'file' ||
field.type === 'reset' ||
field.type === 'submit' ||
field.type === 'button'
)
continue;
// If a multi-select, get all selections
if (field.type === 'select-multiple') {
for (var n = 0; n < field.options.length; n++) {
if (!field.options[n].selected) continue;
serialized.push(encodeURIComponent(field.name) + '=' + encodeURIComponent(field.options[n].value));
}
}
// Convert field data to a query string
else if ((field.type !== 'checkbox' && field.type !== 'radio') || field.checked) {
serialized.push(encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value));
}
}
return serialized.join('&');
};
export const qstr2obj = function(qstr) {
let obj = {};
if (qstr) {
qstr.split('&').map(item => {
const [k, v] = item.split('=');
v ? (obj[k] = v) : null;
});
}
return obj;
};
export const getCookie = function(name) {
var value = '; ' + document.cookie;
var parts = value.split('; ' + name + '=');
if (parts.length == 2)
return parts
.pop()
.split(';')
.shift();
};
import { Base64 } from 'js-base64';
export const base64encode = function(str) {
return Base64.encode(str);
};
export const base64decode = function(b64) {
return Base64.decode(b64);
};
export const getGwSuccessCode = function() {
return '10000';
};
export const isGwSuccess = function(code) {
return getGwSuccessCode() == code;
};
let loadOverlap = [];
export const loadingLayer = (type) => {
if (type) {
loadOverlap.push('add');
} else {
loadOverlap.pop();
}
if (loadOverlap.length > 0) {
document.querySelector('html > body').style.overflow = 'hidden'; // 스크롤 block
document.getElementsByClassName('loading_layer')[0].style.display = 'block';
} else {
document.querySelector('html > body').style.removeProperty('overflow'); // 스크롤 allow
document.getElementsByClassName('loading_layer')[0].style.display = 'none';
}
};

View File

@@ -0,0 +1,228 @@
const coreUiMixin = {
directives: {
focus: {
inserted: function(el) {
el.focus();
}
}
},
methods: {
clearInput: function(evt) {
var me = evt.target;
var vname = me.previousElementSibling.name;
this.$data[vname] = '';
me.previousElementSibling.focus();
},
showPhoneNumber: function(str) {
str = str.replace(/[\-\s\/]+/g, '');
if (str.length > 12 || str.length < 10) {
return str;
}
var result =
str.substring(0, str.length - 8) +
'-' +
str.substring(str.length - 8, str.length - 4) +
'-' +
str.substring(str.length - 4, str.length);
return result;
},
/*
openLayer: function(event, callback) {
var myId = event.target.getAttribute('data-id');
var myLayer = document.querySelector('[layer-id="' + myId + '"]');
var btnClose = document.querySelector('[layer-id="' + myId + '"] .btn_close');
myLayer.classList.add('active');
btnClose.addEventListener("click", function() {
myLayer.classList.remove('active');
if (callback != undefined && callback != null) {
callback('');
}
});
if (callback != undefined && callback != null) {
callback(myId);
}
},
*/
openLayer: function(layerId) {
if (layerId == undefined || layerId == null || layerId == '') {
alert('layerId를 설정해 주세요.');
} else {
this.$emit('changeLayerId', layerId);
}
},
closeLayer() {
this.$emit('changeLayerId', '');
},
numberComma(num) {
if (typeof num == undefined || num == null) {
return '';
}
num = num + '';
let point = num.length % 3;
let len = num.length;
let str = num.substring(0, point);
while (point < len) {
if (str != '') {
str += ',';
}
str += num.substring(point, point + 3);
point += 3;
}
return str;
}
}
};
var chkPattern = {
data: function() {
return {};
},
methods: {
setLenth: function(e, len) {
this.cut(e, len);
},
onlyNum: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[0-9]*$/g.exec(str)) {
e.target.value = str.replace(/[^0-9]/gi, '');
}
},
only11Num: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[0-9]*$/g.exec(str)) {
str = str.replace(/[^0-9]/gi, '');
}
if (str.length > 11) {
str = str.substring(0, 11);
}
e.target.value = str;
},
onlyEmail: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[a-zA-Z0-9_\.\-@._-]*$/g.exec(str)) {
e.target.value = str.replace(/[^a-zA-Z0-9_\.\-@._-]/gi, '');
}
},
onlyName: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[ㄱ-힣a-zA-Z]*$/g.exec(str)) {
e.target.value = str.replace(/[^ㄱ-힣a-zA-Z]/gi, '');
}
},
onlyTitle: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[ㄱ-힣a-zA-Z0-9]*$/g.exec(str)) {
e.target.value = str.replace(/[^ㄱ-힣a-zA-Z0-9]/gi, '');
}
},
onlyText: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[ㄱ-힣a-zA-Z0-9_-]*$/g.exec(str)) {
e.target.value = str.replace(/[^ㄱ-힣a-zA-Z0-9_-]/gi, '');
}
},
onlyPassword: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[A-Za-z0-9!@#$%^&*]*$/g.exec(str)) {
e.target.value = str.replace(/[^A-Za-z0-9!@#$%^&*]/gi, '');
}
},
onlyId: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[A-Za-z0-9]*$/g.exec(str)) {
e.target.value = str.replace(/[^A-Za-z0-9]/gi, '');
}
},
onlyIp: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[0-9,.*]*$/g.exec(str)) {
e.target.value = str.replace(/[^0-9,.*]/gi, '');
}
},
onlyRoleNm_Space: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[ㄱ-힣a-zA-Z0-9/\s]*$/g.exec(str)) {
e.target.value = str.replace(/[^ㄱ-힣a-zA-Z0-9/\s]/gi, '');
}
},
onlyRoleId_UnderBar: function(e, len) {
this.cut(e, len);
var str = e.target.value;
if (!/^[a-zA-Z0-9_]*$/g.exec(str)) {
e.target.value = str.replace(/[^a-zA-Z0-9_]/gi, '');
}
},
cut: function(e, len) {
if (typeof len != 'undefined') {
var str = e.target.value;
if (this.bytes(str) > len) {
e.target.value = this.cutBytes(str, len);
}
}
},
cutBytes: function(str, len) {
var count = 0;
for (var i = 0; i < str.length; i++) {
if (escape(str.charAt(i)).length >= 4) count += 2;
else if (escape(str.charAt(i)) != '%0D') count++;
if (count > len) {
if (escape(str.charAt(i)) == '%0A') i--;
break;
}
}
return str.substring(0, i);
},
bytes: function(str) {
var length = 0;
for (var i = 0; i < str.length; i++) {
if (escape(str.charAt(i)).length >= 4) length += 2;
else if (escape(str.charAt(i)) == '%A7') length += 2;
else {
if (escape(str.charAt(i)) != '%0D') length++;
}
}
return length;
},
checkPhone: function(str) {
str = str.replace(/[\-\s\/]+/g, '');
if (str.charAt(0) != '0') {
str = '0' + str;
}
if (str.length < 10 || str.length > 12) {
return '';
}
if (isNaN(str)) {
return '';
}
//if (str.substr(0,2)!="01" && str.substr(0,3)!="070" && str.substr(0,4)!="0505" && str.substr(0,4)!="0503"){return ""; }
//sif (str.substr(0,3)!="010"){return ""; }
return str;
},
checkExcelFile: function(fileObj) {
let reg = /(.*?)\.(xls|xlsx)$/;
if (fileObj == undefined || fileObj == null)
return false;
if (!fileObj.name.match(reg))
return false;
return true;
}
}
};
export { coreUiMixin, chkPattern };

View File

@@ -0,0 +1,45 @@
<template>
<div class="container template_free">
<article id="content" class="content"></article>
<div tabindex="0" class="layer active">
<div tabindex="0" class="layer_cont error">
<div class="layer_body">
<div class="title_wrap center mar_b50">
<h5 class="h5_title" v-html="message">{{ message }}</h5>
</div>
<div class="btn_wrap mar_t20 center">
<a v-for="(branch, index) in branchList" :key="index" href="javascript:void(0);" class="btn mid" :class="branch.class" @click="branch.callback"><span>{{ branch.text }}</span></a>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
/*
branchList: [
{
text: "저장",
class: "bd_black",
callback: callback
},
.....
]
*/
export default {
name: "buttonBranch",
props: {
message: String,
branchList: {
text: Array,
class: String,
callback: Function
}
},
data() {
return {
}
}
}
</script>

View File

@@ -0,0 +1,199 @@
<template>
<section>
<!-- <div class="emulator_wrap"> -->
<div class="inner_emul">
<strong class="blind">미리보기</strong>
<div class="emulator_area">
<div class="emulator_cont">
<div class="img_area description">
<img :src="bgImageData" v-if="bgImageData && !retrivebgFlag">
<img :src="this.bgImageUrl" v-else-if="retrivebgFlag">
<img src="@/assets/images/common/img_placeholder02.png" v-else>
</div>
<div class="rcs_profile_area">
<img :src="profileImageData" v-if="profileImageData && !retriveProfileFlag">
<img :src="this.profileImageUrl" v-else-if="retriveProfileFlag">
<img src="@/assets/images/common/img_profile_blank.png" v-else>
</div>
<strong class="rcs_brand_name">{{this.brandInfoData.name}}</strong>
<div class="rcs_icon_area">
<span
v-for="(item, index) in visibleMenuItemList"
:key="index"
class="rcs_icon"
:class="`icon_${item.code.toLowerCase()}`"
></span>
</div>
<div class="rcs_desc_area" v-html="this.brandInfoData.descr"></div>
<div class="rcs_detail_area">
<dl>
<dt>전화번호</dt>
<dd>{{this.brandInfoData.tel}}</dd>
<dt>웹사이트</dt>
<dd>{{this.brandInfoData.url}}</dd>
<dt>이메일</dt>
<dd v-if="this.brandInfoData.email === '@'"></dd>
<dd v-else>{{this.brandInfoData.email}}</dd>
<dt>주소</dt>
<dd>{{this.brandInfoData.addrRegnNo}}{{this.brandInfoData.addrMngNo}}{{this.brandInfoData.addrDtl}}</dd>
</dl>
</div>
</div>
</div>
</div>
<!-- </div> -->
</section>
</template>
<script>
// 스크립트를 정의하는 부분
// 개발자 작업 영역
//import { getImageUrl } from '@/service/code'
// [ECMA6] export default 된 부분이 외부에서 import로 사용할 수 있게 된다.
export default {
// .vue 내부에서 사용되는 model
// model 기반으로 vue는 동작된다.
props: {
brandInfoData: {
type: Object
}
},
data() {
return {
bgImageData: '',
profileImageData: '',
profileImageUrl: '',
bgImageUrl: '',
retriveProfileFlag: false,
retrivebgFlag: false
}
},
created() {
// DOM이 만들어 지기 전 실행 되는 곳
// Data를 사전에 준비할 경우 사용된다.
},
mounted() {
// DOM에 해당 .vue가 들어가게 되면 실행 되는 곳
// onload 상태와 동일하다. DOM 이후에 조작할 경우 이곳에서 수행
},
watch: {
'brandInfoData.descr'() {
this.brandInfoData.descr = this.brandInfoData.descr.replace(/\(|\)|on.*\(|eval\(|javascript/gi,'')
.split('\n')
.join('<br />')
},
'brandInfoData.profileImgFile'() {
if (this.brandInfoData.profileImgFile) {
let reader = new FileReader()
let vm = this
let file = this.brandInfoData.profileImgFile
reader.onload = e => {
vm.profileImageData = e.target.result
}
reader.readAsDataURL(file)
} else {
this.profileImageData = ''
}
},
'brandInfoData.bgImgFile'() {
if (this.brandInfoData.bgImgFile) {
let reader = new FileReader()
let vm = this
let file = this.brandInfoData.bgImgFile
reader.onload = e => {
vm.bgImageData = e.target.result
}
reader.readAsDataURL(file)
} else {
this.bgImageData = ''
}
},
'brandInfoData.profileImgFileId'() {
if (
!jglib.isEmpty(this.brandInfoData.profileImgFileId) &&
!jglib.isEmpty(this.brandInfoData.profileImgFileNo)
) {
this.retriveProfileFlag = true
let reqObj = {
fileId: this.brandInfoData.profileImgFileId,
fileNo: this.brandInfoData.profileImgFileNo
}
getImageUrl(reqObj).then(res => {
this.profileImageUrl = res.downloadUrl
})
} else {
this.retriveProfileFlag = false
this.profileImageUrl = ''
}
},
'brandInfoData.bgImgFileId'() {
if (
!jglib.isEmpty(this.brandInfoData.bgImgFileId) &&
!jglib.isEmpty(this.brandInfoData.bgImgFileNo)
) {
this.retrivebgFlag = true
let reqObj = {
fileId: this.brandInfoData.bgImgFileId,
fileNo: this.brandInfoData.bgImgFileNo
}
getImageUrl(reqObj).then(res => {
this.bgImageUrl = res.downloadUrl
})
} else {
this.retrivebgFlag = false
this.bgImageUrl = ''
}
}
},
computed: {
// 값이 자주 변경됨에 따라, 관련되어 데이터 혹은 view가 바뀌어야 할 경우 사용
// method를 바로 연결하면 tic 단위로 계속 실행되기 때문에, 값이 변경할 때만 수행되고,
// cache로 남는 computed를 활용하는 것이 성능에 좋음
visibleMenuItemList() {
if (this.brandInfoData.menuItemList) {
return this.brandInfoData.menuItemList.filter(res => {
return res.visible
})
} else {
return []
}
}
},
methods: {
// .vue 내부에서 사용되는 함수를 정의한다.
// 이벤트에 따라 실행하거나, 내부적으로 사용되는 함수들을 정의한다.
getImageUrl: function(reqData) {
if (!isUseAPI()) {
return new Promise((resolve, reject) => {
let res = {
code: '99999999',
msg: 'not available in mockup'
}
resolve(res)
})
}
return new Promise((resolve, reject) => {
request({
url: `/file/${reqData.fileId}/${reqData.fileNo}`,
method: 'get'
})
.then(res => {
let imgData = {
fileName: res.result.fileName,
downloadUrl: res.result.downloadUrl
}
resolve(imgData)
})
.catch(res => {
reject('error in filedownload')
})
})
}
}
}
</script>

View File

@@ -0,0 +1,679 @@
<template>
<section>
<div class="box_scroll" :class="addCls">
<table class="tbl_col_type cgrid" ref="customTable" :class="addTbCls" :style="applyTbStyle">
<v-runtime-template :template="colsData"></v-runtime-template>
<v-runtime-template :template="headerData"></v-runtime-template>
<v-runtime-template :template="bodyData" @hook:updated="setEvents"></v-runtime-template>
</table>
</div>
<v-runtime-template v-if="pagination == true" :template="pagingData"></v-runtime-template>
</section>
</template>
<script>
import httpClient from '@/common/http-client';
import VRuntimeTemplate from 'v-runtime-template';
export default {
name: 'customGrid',
props: [
'url', // 연동 url
'initialRequest', // false일 시 초기 렌더링 시 백엔드에 요청 하지 않음. 이 경우 readData를 호출하여 그리드 데이터를 할당해 줘야 함
'pagination', // 페이지 네비게이션 사용 여부
'perPage', // 페이지 당 개수
'header', // 사용자정의 header가 있을 경우
'columns', // 컬럼 정보
'noDataStr', // 데이터가 없을 때
'isCheckbox', // 기본 체크박스 그리드일 경우 true
'addBodyAlign', // TOP, BOTTOM
'addBodyTmplt', // 추가되는 html
'addTableStyle', // 추가되는 그리드 style
'addTbCls', // 추가되는 테이블 클래스
'addCls', // 추가되는 클래스
'totalItems' // 부모창에 표시할 총 컨텐츠 개수 변수 명 (더 좋은 방법 있으면 알려주세요.)
],
components: {
VRuntimeTemplate
},
data() {
return {
getParams: {},
applyTbStyle: 'table-layout: fixed;',
prevCallOrderKey: '',
callOrderKey: '',
callOrderDesc: true,
colsLen: 0,
pageCount: 10,
curPerPage: 5,
currentIndex: 1,
totalCount: 0,
bodyList: [],
events: [],
colsData: '',
headerData: '',
bodyData: '',
pagingData: ''
};
},
created() {
this.cleanData();
if (this.initialRequest == true) {
this.readData();
}
},
watch: {
perPage() {
this.currentIndex = 1;
this.curPerPage = this.perPage;
this.readData();
}
},
methods: {
getData() {
return this.bodyList;
},
cleanData() {
if (typeof this.perPage == undefined || this.perPage == null) {
this.curPerPage = 5;
} else {
this.curPerPage = this.perPage;
}
if (typeof this.addTableStyle == undefined || this.addTableStyle == null) {
this.applyTbStyle = 'table-layout: fixed;';
} else {
this.applyTbStyle = this.addTableStyle;
}
this.getParams = {};
this.prevCallOrderKey = '';
this.callOrderKey = '';
this.callOrderDesc = true;
this.colsLen = 0;
this.currentIndex = 1;
this.totalCount = 0;
this.bodyList = [];
this.events = [];
this.colsData = '';
this.headerData = '';
this.bodyData = '';
this.pagingData = '';
},
readData(isKeep) {
if (typeof this.url != undefined && this.url != null && this.url != '') {
if (isKeep == true) {
// nothing
} else {
if (this.pagination == true) {
this.getParams['perPage'] = this.curPerPage;
this.getParams['page'] = this.currentIndex;
} else {
delete this.getParams['perPage'];
delete this.getParams['page'];
}
}
let colStr = this.makeColGroupView();
let headerStr = this.makeHeaderView();
let bodyStr = '';
let pageStr = '';
var vm = this;
console.log(this.url);
httpClient
//.get(this.url, { params: this.getParams, headers: { 'Show-Layer': 'Yes' }})
.post(this.url, this.getParams, {headers: { 'Show-Layer': 'Yes' }})
.then(response => {
let resp = response.data;
console.log(resp);
//if (resp != null && resp.result == true) {
if (resp != null && resp.retCode == '0000') {
let data = resp.data;
//let conts = data.contents;
let conts = data.list;
vm.bodyList = conts;
bodyStr = vm.makeBodyView();
//this.$parent[this.totalItems] = data.pagination.totalCount;
this.$parent[this.totalItems] = data.paging.totalCnt;
/*if (vm.pagination == true) {
vm.currentIndex = data.pagination.page == 0 ? 1 : data.pagination.page;
vm.totalCount = data.pagination.totalCount;
pageStr = vm.makePagingView();
}*/
if (vm.pagination == true) {
vm.currentIndex = data.paging.currentPage == 0 ? 1 : data.paging.currentPage;
vm.totalCount = data.paging.totalCnt;
pageStr = vm.makePagingView();
}
}
vm.setTableView(colStr, headerStr, bodyStr, pageStr);
}).catch(response => {
bodyStr = vm.makeBodyView();
if (vm.pagination == true) {
vm.currentIndex = 1;
vm.totalCount = 0;
pageStr = vm.makePagingView();
}
vm.setTableView(colStr, headerStr, bodyStr, pageStr);
});
}
},
reloadData() {
this.movePage(1, true);
},
search(params, isKeep) {
if (params == undefined || params == null) {
params = {};
this.currentIndex = 1;
this.callOrderKey = '';
}
if (isKeep == undefined || isKeep == null || typeof isKeep != 'boolean') {
isKeep = false;
this.currentIndex = 1;
this.callOrderKey = '';
}
this.getParams = {};
this.getParams = params;
this.readData(isKeep);
},
setTableView(colStr, headerStr, bodyStr, pageStr) {
this.colsData = colStr;
this.headerData = headerStr;
this.bodyData = bodyStr;
this.pagingData = pageStr;
},
setEvents() {
for (var i = 0; i < this.events.length; i++) {
let e = this.events[i];
let cls = e.cls;
let addCls = '';
for (var c = 0; c < cls.getElement().classList.length; c++) {
addCls += '.' + cls.getElement().classList[c];
}
if (addCls != '') {
let selQuery = this.$refs.customTable.querySelectorAll(addCls);
let key = e.key;
if (selQuery.length > 0 && typeof selQuery[key] != undefined && selQuery[key] != null) {
cls.addEvent(selQuery[key]);
}
}
}
},
makeColGroupView() {
this.colsLen = 0;
let colGroup = '';
colGroup += '<colgroup>';
if (this.isCheckbox == true) {
colGroup += '<col style="width: 60px">';
this.colsLen++;
}
for (var i = 0; i < this.columns.length; i++) {
let colData = this.columns[i];
if (colData.hidden != undefined && colData.hidden == true) {
} else {
let cw = colData.width;
if (typeof cw == undefined || cw == null || cw == '') {
cw = '';
} else if (Number(cw) > 0) {
cw += 'px';
}
if (cw == '') {
colGroup += '<col>';
} else {
colGroup += '<col style="width: ' + cw + '">';
}
this.colsLen++;
}
}
colGroup += '</colgroup>';
return colGroup;
},
makeHeaderView() {
let skipHeader = [];
let mustHeader = [];
let tHead = '';
tHead += '<thead>';
if (this.header != undefined && this.header != null && this.header.length > 0) {
tHead += '<tr>';
let rLen = this.header.length + 1;
if (this.isCheckbox == true) {
tHead +=
'<th scope="col" rowspan="' +
rLen +
'"><span class="custom_checkbox"><input type="checkbox" name="checkboxAll" @click="checkAll" id="checkboxAll"> <label for="checkboxAll"></label></span></th>';
}
for (var i = 0; i < this.header.length; i++) {
let hDataList = this.header[i];
for (var j = 0; j < hDataList.length; j++) {
let hData = hDataList[j];
let cdata = hData.childNames;
let hStr = hData.header;
if (typeof hStr == undefined || hStr == null) {
hStr = '';
}
if (typeof cdata == undefined || cdata == null || cdata.length == 0) {
tHead += '<th scope="col" rowspan="' + rLen + '">' + hStr + '</th>';
skipHeader.push(hStr);
} else {
let cLen = cdata.length;
let chId = 'thHeader' + i + '' + j;
tHead +=
'<th scope="colgroup" colspan="' + cLen + '" class="th_line" id="' + chId + '">' + hStr + '</th>';
for (var k = 0; k < cLen; k++) {
mustHeader.push(chId);
}
}
}
}
tHead += '<tr>';
} else {
tHead += '<tr>';
if (this.isCheckbox == true) {
tHead +=
'<th><span class="custom_checkbox"><input type="checkbox" name="checkboxAll" @click="checkAll" id="checkboxAll"> <label for="checkboxAll"></label></span></th>';
}
}
let colIdx = 0;
for (var i = 0; i < this.columns.length; i++) {
let colData = this.columns[i];
if (colData.hidden == true) {
} else {
let cheader = colData.header;
let hd = '';
if (cheader == undefined || cheader == null || cheader == '') {
cheader = '';
} else {
if (skipHeader.length > 0 && skipHeader.includes(cheader)) {
continue;
}
hd = '<th';
if (mustHeader.length > 0) {
let hs = mustHeader[colIdx];
if (hs != undefined && hs != null) {
hd += ' headers="' + hs + '" class="th_line"';
colIdx++;
}
}
if (colData.sort == true) {
let orderKey = colData.name;
let sortHd = ' class="sort_table">';
sortHd += '<strong>';
sortHd += cheader;
sortHd +=
'<a href="javascript:void(0);" class="btn_sort" @click="sortData(\'' + orderKey + '\')">정렬</a>';
sortHd += '</strong>';
hd += sortHd;
} else {
hd += '>' + cheader;
}
}
tHead += hd + '</th>';
}
}
tHead += '</tr></thead>';
return tHead;
},
makeBodyView() {
this.events = [];
let tBody = '';
tBody += '<tbody>';
if (this.bodyList != undefined && this.bodyList != null && this.bodyList.length > 0) {
if (this.addBodyAlign == 'TOP') {
tBody += this.addBodyTmplt;
}
for (var b = 0; b < this.bodyList.length; b++) {
let bData = this.bodyList[b];
let trStr = '<tr>';
if (this.isCheckbox == true) {
trStr +=
'<td><span class="custom_checkbox single"><input type="checkbox" name="checkbox" @click="check" id="checkbox' +
b +
'"> <label for="checkbox' +
b +
'"></label></span></td>';
}
let colIdx = 0;
for (var i = 0; i < this.columns.length; i++) {
let colData = this.columns[i];
if (colData.hidden == true) continue;
let cname = colData.name;
let crenderer = colData.renderer;
let formatter = colData.formatter;
let cdefaultText = colData.defaultText;
let align = colData.align;
let csubtlb = colData.subtlb;
let tooltipTextCol = colData.tooltipTextCol;
let cls = colData.cls;
if (cls == undefined || cls == null) {
cls = '';
}
const customTd = document.createElement('td');
customTd.className = cls;
if (align == 'left' || align == 'right') {
customTd.style.textAlign = align;
}
let cw = colData.width;
if (cw == undefined || cw == null || cw == '') {
cw = '';
} else if (Number(cw) > 0) {
cw += 'px';
}
bData['cgridwidth'] = cw;
if (crenderer != undefined && crenderer != null) {
let customCls = crenderer.type;
bData['rowKey'] = b;
let tdv = this.makeTdText(formatter, bData, cname, cdefaultText);
bData['colValue'] = this.customReplaceStr(tdv);
bData['colName'] = cname;
if (crenderer.options != undefined && crenderer.options != null) {
let opts = { options: crenderer.options };
if (cname == undefined || cname == null || cname == '') {
bData['cgrido'] = opts;
} else {
bData['cgrido' + cname] = opts;
}
}
let initCls = new customCls(bData);
let el = initCls.getElement();
let oh = el.outerHTML;
customTd.innerHTML = this.customReplaceStr(oh);
this.events.push({ cls: initCls, key: b });
} else if (csubtlb != undefined && csubtlb != null) {
customTd.innerHTML = this.makeDoubleRowColumn(csubtlb, bData);
} else {
customTd.innerHTML = this.makeTooltip(
bData,
colData,
this.makeTdText(formatter, bData, cname, cdefaultText)
);
}
trStr += customTd.outerHTML;
colIdx++;
}
trStr += '</tr>';
tBody += trStr;
}
if (this.addBodyAlign == 'BOTTOM') {
tBody += this.addBodyTmplt;
}
} else {
tBody += '<tr><td colspan="' + this.colsLen + '" class="no_data">' + this.noDataStr + '</td></tr>';
}
tBody += '</tbody>';
return tBody;
},
makeDoubleRowColumn(csubtlb, bData) {
let rtnHtml = '<table><tbody>';
for (var j = 0; j < csubtlb.length; j++) {
rtnHtml += '<tr><td>';
let subTlb = csubtlb[j];
let subName = subTlb.name;
let subDefaultText = subTlb.defaultText;
let subFormater = subTlb.formatter;
let tdv = this.makeTdText(subFormater, bData, subName, subDefaultText);
rtnHtml += this.makeTooltip(bData, subTlb, tdv);
rtnHtml += '</td></tr>';
}
rtnHtml += '</tbody></table>';
return rtnHtml;
},
makeTdText(formatter, bData, cname, defaultText) {
if (defaultText != undefined || defaultText != null) return defaultText;
let tdv = bData[cname];
if (formatter != undefined && formatter != null && typeof formatter === 'function') {
tdv = formatter(bData);
if (tdv == undefined || tdv == null) {
tdv = bData[cname];
}
}
if (tdv == undefined || tdv == null || tdv == '') {
tdv = '-';
}
return tdv;
},
makeTooltip(bData, colData, tdv) {
if (colData.tooltip == true && tdv != '' && tdv != '-') {
let inHtml = this.customReplaceStr(tdv);
let tArea = '<div class="tooltip_area';
if (colData.tooltipAreaClass != null && colData.tooltipAreaClass != '') tArea += ' ' + colData.tooltipAreaClass;
tArea += '">';
tArea += '<div @mouseover="hoverTooltip" class="text_info ellipsis';
if (colData.tooltipclass != null && colData.tooltipclass != '') tArea += ' ' + colData.tooltipclass;
tArea += '" style="width:' + bData['cgridwidth'];
tArea += '">';
tArea += inHtml;
tArea += '</div>';
tArea += '<div class="box_text_tooltip text_absolute">';
if (colData.tooltipTextCol != undefined && colData.tooltipTextCol != null && colData.tooltipTextCol != '') {
if (
bData[colData.tooltipTextCol] != undefined &&
bData[colData.tooltipTextCol] != null &&
bData[colData.tooltipTextCol] != ''
) {
tArea += '<p>' + bData[colData.tooltipTextCol] + '</p>';
} else {
tArea += '<p>' + inHtml + '</p>';
}
} else {
tArea += '<p>' + inHtml + '</p>';
}
tArea += '</div>';
tArea += '</div>';
return tArea;
} else {
return this.customReplaceStr(tdv);
}
},
customReplaceStr(str) {
if (str != undefined && str != null) {
str = new String(str);
str = str.replace(/{{/g, '{ { ');
str = str.replace(/}}/g, ' } }');
} else {
str = '';
}
return str;
},
makePagingView() {
let pData = '<div class="paging">';
let totalPage = Math.ceil(this.totalCount / this.curPerPage);
if (totalPage < 1) {
totalPage = 1;
}
let pageGroup = Math.ceil(this.currentIndex / this.pageCount);
let last = pageGroup * this.pageCount;
if (last > totalPage) {
last = totalPage;
}
let first = last - (this.pageCount - 1);
if (first < 1) {
first = 1;
}
let prev = first - 1;
if (prev < 1) {
prev = 1;
}
let next = last + 1;
if (next > totalPage) {
next = totalPage;
}
pData += '<a href="javascript:void(0);" @click="movePage(1)" class="btn_arrow first">처음으로</a>';
pData += '<a href="javascript:void(0);" @click="movePage(' + prev + ')" class="btn_arrow prev">이전으로</a>';
for (var i = first; i <= last; i++) {
let actCls = '';
if (i == this.currentIndex) {
actCls = "class='active'";
}
pData += '<a href="javascript:void(0);" @click="movePage(' + i + ')" ' + actCls + '>' + i + '</a>';
}
pData += '<a href="javascript:void(0);" @click="movePage(' + next + ')" class="btn_arrow next">다음으로</a>';
pData +=
'<a href="javascript:void(0);" @click="movePage(' + totalPage + ')" class="btn_arrow last">마지막으로</a>';
pData += '</div>';
return pData;
},
movePage(idx, refresh) {
if (refresh == undefined || refresh == null) {
refresh = false;
}
if (idx != this.currentIndex || refresh == true) {
this.currentIndex = idx;
this.readData();
}
},
checkedElementDatas() {
let checkEls = this.checkEls();
let checkDatas = [];
for (var i = 0; i < checkEls.length; i++) {
let c = checkEls[i];
if (c.checked === true) {
checkDatas.push(this.bodyList[i]);
}
}
return checkDatas;
},
checkEls() {
let checkEls = this.$refs.customTable.querySelectorAll("input[name='checkbox']");
return checkEls;
},
check() {
let checkEls = this.checkEls();
let cnt = 0;
for (var i = 0; i < checkEls.length; i++) {
let c = checkEls[i];
if (c.checked === true) {
cnt++;
}
}
let chkAll = this.$refs.customTable.querySelectorAll("input[name='checkboxAll']");
let allCheck = false;
if (this.bodyList.length == cnt) {
allCheck = true;
}
for (var i = 0; i < chkAll.length; i++) {
let c = chkAll[i];
c.checked = allCheck;
}
},
checkAll() {
let checkEls = this.checkEls();
for (var i = 0; i < checkEls.length; i++) {
let c = checkEls[i];
c.checked = event.target.checked;
}
},
sortData(orderKey) {
if (typeof orderKey != undefined && orderKey != null && orderKey != '') {
this.currentIndex = 1;
this.callOrderKey = orderKey;
if (this.callOrderKey != null && this.callOrderKey != '') {
if (this.prevCallOrderKey != this.callOrderKey) {
this.callOrderDesc = true;
} else {
this.callOrderDesc = !this.callOrderDesc;
}
this.prevCallOrderKey = this.callOrderKey;
let sort = this.callOrderKey;
if (this.callOrderDesc == false) {
sort += ' ASC';
} else {
sort += ' DESC';
}
this.getParams['sort'] = sort;
} else {
delete this.getParams['sort'];
}
this.readData();
}
},
getPagination() {
let rslt = {
_currentPage: this.currentIndex,
_options: {
itemsPerPage: this.curPerPage,
sort: this.getParams['sort']
}
};
return rslt;
},
hoverTooltip(event) {
var myChild = event.target.querySelector('.box_text_tooltip');
var rect = event.target.getBoundingClientRect();
if (myChild != null) {
myChild.style.top = rect.y + 20 + 'px';
}
}
}
};
</script>
<style>
</style>

View File

@@ -0,0 +1,139 @@
.rtl {
direction: rtl;
}
.vdp-datepicker {
position: relative;
text-align: left;
}
.vdp-datepicker * {
box-sizing: border-box;
}
.vdp-datepicker__calendar {
position: absolute;
z-index: 100;
background: #fff;
width: 300px;
border: 1px solid #ccc;
}
.vdp-datepicker__calendar header {
display: block;
line-height: 40px;
}
.vdp-datepicker__calendar header span {
display: inline-block;
text-align: center;
width: 71.42857142857143%;
float: left;
}
.vdp-datepicker__calendar header .prev,
.vdp-datepicker__calendar header .next {
width: 14.285714285714286%;
float: left;
text-indent: -10000px;
position: relative;
}
.vdp-datepicker__calendar header .prev:after,
.vdp-datepicker__calendar header .next:after {
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
border: 6px solid transparent;
}
.vdp-datepicker__calendar header .prev:after {
border-right: 10px solid #000;
margin-left: -5px;
}
.vdp-datepicker__calendar header .prev.disabled:after {
border-right: 10px solid #ddd;
}
.vdp-datepicker__calendar header .next:after {
border-left: 10px solid #000;
margin-left: 5px;
}
.vdp-datepicker__calendar header .next.disabled:after {
border-left: 10px solid #ddd;
}
.vdp-datepicker__calendar header .prev:not(.disabled),
.vdp-datepicker__calendar header .next:not(.disabled),
.vdp-datepicker__calendar header .up:not(.disabled) {
cursor: pointer;
}
.vdp-datepicker__calendar header .prev:not(.disabled):hover,
.vdp-datepicker__calendar header .next:not(.disabled):hover,
.vdp-datepicker__calendar header .up:not(.disabled):hover {
background: #eee;
}
.vdp-datepicker__calendar .disabled {
color: #ddd;
cursor: default;
}
.vdp-datepicker__calendar .flex-rtl {
display: flex;
width: inherit;
flex-wrap: wrap;
}
.vdp-datepicker__calendar .cell {
display: inline-block;
padding: 0 5px;
width: 14.285714285714286%;
height: 40px;
line-height: 40px;
text-align: center;
vertical-align: middle;
border: 1px solid transparent;
}
.vdp-datepicker__calendar .cell:not(.blank):not(.disabled).day,
.vdp-datepicker__calendar .cell:not(.blank):not(.disabled).month,
.vdp-datepicker__calendar .cell:not(.blank):not(.disabled).year {
cursor: pointer;
}
.vdp-datepicker__calendar .cell:not(.blank):not(.disabled).day:hover,
.vdp-datepicker__calendar .cell:not(.blank):not(.disabled).month:hover,
.vdp-datepicker__calendar .cell:not(.blank):not(.disabled).year:hover {
border: 1px solid #4bd;
}
.vdp-datepicker__calendar .cell.selected {
background: #4bd;
}
.vdp-datepicker__calendar .cell.selected:hover {
background: #4bd;
}
.vdp-datepicker__calendar .cell.selected.highlighted {
background: #4bd;
}
.vdp-datepicker__calendar .cell.highlighted {
background: #cae5ed;
}
.vdp-datepicker__calendar .cell.highlighted.disabled {
color: #a3a3a3;
}
.vdp-datepicker__calendar .cell.grey {
color: #888;
}
.vdp-datepicker__calendar .cell.grey:hover {
background: inherit;
}
.vdp-datepicker__calendar .cell.day-header {
font-size: 75%;
white-space: nowrap;
cursor: inherit;
}
.vdp-datepicker__calendar .cell.day-header:hover {
background: inherit;
}
.vdp-datepicker__calendar .month,
.vdp-datepicker__calendar .year {
width: 33.333%;
}
.vdp-datepicker__clear-button,
.vdp-datepicker__calendar-button {
cursor: pointer;
font-style: normal;
}
.vdp-datepicker__clear-button.disabled,
.vdp-datepicker__calendar-button.disabled {
color: #999;
cursor: default;
}

View File

@@ -0,0 +1,25 @@
<template>
<footer class="footer-wrap">
<div class="footer div-cont">
<div class="f-logo"><a href="/"><img src="../assets/images/flogo.png" alt=""></a></div>
<div class="f-info">
<ul>
<li><p>()엘지유플러스</p></li>
<li><p>주소 서울특별시 용산구 한강대로 32</p></li>
</ul>
<ul>
<li><p>대표이사 황현식</p></li>
<li><p>사업자번호 220-81-39938</p></li>
<li><p>통신판매신고 제2010-서울중구-0968</p></li>
<li><p>고객센터 1544-5992</p></li>
<li><p>e-Mail <a href="mailto:smshelp@lguplus.co.kr">smshelp@lguplus.co.kr</a></p></li>
</ul>
<p>Copyright © LG Uplus Corp. All Rights Reserved.</p>
</div>
</div>
</footer>
</template>
<script>
</script>

View File

@@ -0,0 +1,87 @@
<template>
<header>
<h1 class="logo"><a href="javascript:void(0)">uplus 메시지허브이지<span>BACKOFFICE</span></a></h1>
<div class="user_wrap">
<div class="user" @click="userInfoToggle();">
<p>슈퍼관리자</p>
<a href="javascript:void(0)" class="btn_user">Uplus01</a>
</div>
<div class="user_info">
<a href="superadmin_info.html" class="modify">정보수정</a>
<a href="javascript:void(0)" class="logout" @click="logout();">로그아웃</a>
</div>
</div>
</header>
</template>
<script>
//import tokenSvc from '@/common/token-service';
import { mapGetters } from 'vuex';
import loginApi from '@/modules/login/service/api';
export default {
name: "hubWebHeader",
data() {
return {
menuList: null,
isLogin: false,
isErrPage: false,
navActive: false,
}
},
created() {
},
computed: {
...mapGetters({
getLogin: 'login/isLogin',
getErrorPage: 'login/isErrorPage',
}),
},
watch: {
getLogin(data) {
if (data != null && data != '' && data == true) {
this.isLogin = true;
//this.setMenuData();
} else {
this.isLogin = false;
//this.menuList = null;
}
},
getErrorPage(data) {
if (data != null && data != '' && data == true) {
this.isErrPage = true;
} else {
this.isErrPage = false;
}
},
},
methods: {
userInfoToggle(){
var click = "clicked";
var userBtn = document.querySelector('.user_wrap .user');
if(userBtn.classList.contains(click)){
userBtn.classList.remove(click);
}
else{
userBtn.classList.add(click);
}
},
logout(){
let result = confirm("로그아웃 하시겠습니까?");
if (result) {
loginApi.logout().then(response => {
if(response.data.retCode == '0000'){
//tokenSvc.removeToken();
this.$router.push({
path: "/login"
});
}
});
}
}
}
};
</script>

View File

@@ -0,0 +1,56 @@
<template>
<div>
<div>role: {{role}}</div><br/>
<TreeMenu :nodes="tree.nodes" :depth="0" :label="tree.label"></TreeMenu>
</div>
</template>
<script>
import TreeMenu from './TreeMenu';
import tokenSvc from '@/common/token-service';
let tree = {
label: 'root',
nodes: [
{
label: 'item1',
nodes: [
{
label: 'item1.1'
},
{
label: 'item1.2',
nodes: [
{
label: 'item1.2.1'
}
]
}
]
},
{
label: 'item2'
}
]
};
export default {
components: {
TreeMenu
},
data() {
return {
tree
};
},
computed: {
role() {
return tokenSvc.getToken().principal.authorities[0].authority;
}
},
created() {
console.log('created Lnb');
console.log('node[0]:', this.tree.nodes[0].label);
console.log('role:', tokenSvc.getToken().principal.authorities[0].authority);
}
};
</script>

View File

@@ -0,0 +1,307 @@
<template>
<!-- 버튼 -->
<div class="wrap bg-wrap">
<!-- <div class="popup-btn-wrap">
<button class="trigger" onclick="ModalOpen('modal01');">로그인실패: 확인</button>
<button class="trigger" onclick="ModalOpen('modal02');">로그인실패: 5</button>
<button class="trigger" onclick="ModalOpen('modal03');">로그인실패: 상태</button>
<button class="trigger" onclick="ModalOpen('modal04');">보안 알림</button>
<button class="trigger" onclick="ModalOpen('modal05');">중복 로그인</button>
<button class="trigger" onclick="ModalOpen('modal06');">휴대폰번호 확인</button>
<button class="trigger" onclick="ModalOpen('modal07');">인증번호: 발송</button>
<button class="trigger" onclick="ModalOpen('modal08');">인증번호: 입력</button>
<button class="trigger" onclick="ModalOpen('modal09');">인증실패: 인증번호</button>
<button class="trigger" onclick="ModalOpen('modal10');">인증실패: 시간초과</button>
<button class="trigger" onclick="ModalOpen('modal11');">인증실패: 5</button>
<button class="trigger" onclick="ModalOpen('modal12');">비밀번호 초기화 문자 발송</button>
<button class="trigger" onclick="ModalOpen('modal13');">아이디 오류</button>
<button class="trigger" onclick="ModalOpen('modal14');">비밀번호 오류</button>
<button class="trigger" onclick="ModalOpen('modal15');">비밀번호 패턴 오류</button>
<button class="trigger" onclick="ModalOpen('modal16');">비밀번호 정상 변경</button>
</div> -->
<!-- s: 팝업 -->
<div class="dimmed" @click="ModalClose();"></div>
<div class="popup-wrap">
<!-- 로그인실패: 확인 -->
<div class="popup modal01">
<div class="pop-head">
<h3 class="pop-tit">로그인 실패</h3>
</div>
<div class="pop-cont">
<p>아이디,비밀번호를 확인해주세요.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 로그인실패: 5회 -->
<div class="popup modal02">
<div class="pop-head">
<h3 class="pop-tit">로그인 실패</h3>
</div>
<div class="pop-cont">
<p>로그인 5 실패하였습니다.</p>
<p>비밀번호 초기화 비밀번호를 변경해 주세요.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 로그인실패: 상태 -->
<div class="popup modal03">
<div class="pop-head">
<h3 class="pop-tit">로그인 실패</h3>
</div>
<div class="pop-cont">
<p>아이디 상태를 확인해 주세요.</p>
<p>(사용중인 상태만 로그인 가능합니다.)</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 보안 알림 -->
<div class="popup modal04">
<div class="pop-head">
<h3 class="pop-tit">보안 알림</h3>
</div>
<div class="pop-cont">
<p>비밀번호를 변경하지 않은지 90일이</p>
<p>지났습니다. 비밀번호를 변경하여</p>
<p>이용 부탁드립니다.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">비밀번호 변경하기</button>
</div>
</div>
<!-- 중복 로그인 -->
<div class="popup modal05">
<div class="pop-head">
<h3 class="pop-tit">중복 로그인</h3>
</div>
<div class="pop-cont">
<p>동일한 아이디로 로그인 되어 있습니다.</p>
<p>이전 로그인 세션 종료 로그인하시겠습니까?</p>
<p>확인 이전 로그인한 상태는 로그아웃됩니다.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 휴대폰번호 확인 -->
<div class="popup modal06">
<div class="pop-head">
<h3 class="pop-tit">휴대폰번호 확인</h3>
</div>
<div class="pop-cont">
<p>휴대폰번호를 확인해주세요.</p>
<p>아이디에 등록된 휴대폰번호로만 인증이 가능합니다.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 인증번호: 발송 -->
<div class="popup modal07">
<div class="pop-head">
<h3 class="pop-tit">인증번호 발송</h3>
</div>
<div class="pop-cont">
<p>인증번호를 발송하였습니다.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 인증번호: 입력 -->
<div class="popup modal08">
<div class="pop-head">
<h3 class="pop-tit">인증번호 입력</h3>
</div>
<div class="pop-cont">
<p>인증번호를 입력하세요.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 인증실패: 인증번호 -->
<div class="popup modal09">
<div class="pop-head">
<h3 class="pop-tit">인증실패</h3>
</div>
<div class="pop-cont">
<p>잘못된 인증번호입니다.</p>
<p>5 실패 로그아웃됩니다.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 인증실패: 시간초과 -->
<div class="popup modal10">
<div class="pop-head">
<h3 class="pop-tit">인증실패</h3>
</div>
<div class="pop-cont">
<p>인증시간 초과되었습니다.</p>
<p>다시 휴대폰번호를 입력해주세요.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 인증실패: 5회 -->
<div class="popup modal11">
<div class="pop-head">
<h3 class="pop-tit">인증실패</h3>
</div>
<div class="pop-cont">
<p>인증번호 5 실패하였습니다.</p>
<p>로그아웃되어 다시 로그인해주세요.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 비밀번호 초기화 발송 -->
<div class="popup modal12">
<div class="pop-head">
<h3 class="pop-tit">비밀번호 초기화</h3>
</div>
<div class="pop-cont">
<p>해당 아이디에 저장되어 있는 핸드폰번호로</p>
<p>비밀번호 초기화 문자가 발송되었습니다.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 아이디 오류 -->
<div class="popup modal13">
<div class="pop-head">
<h3 class="pop-tit">아이디 오류</h3>
</div>
<div class="pop-cont">
<p>등록되지 않은 아이디입니다.</p>
<p>아이디를 다시 확인하세요</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 비밀번호 오류 -->
<div class="popup modal14">
<div class="pop-head">
<h3 class="pop-tit">비밀번호 오류</h3>
</div>
<div class="pop-cont">
<p>비밀번호를 확인해주세요.</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 비밀번호 패턴 오류 -->
<div class="popup modal15">
<div class="pop-head">
<h3 class="pop-tit">비밀번호 오류</h3>
</div>
<div class="pop-cont">
<p>비밀번호를 사용할 없습니다.</p>
<p>비밀번호는 영문/숫자/특수기호를 혼합하여</p>
<p>8~16자리로 설정해주세요</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 비밀번호 정상 변경 -->
<div class="popup modal16">
<div class="pop-head">
<h3 class="pop-tit">비밀번호 오류</h3>
</div>
<div class="pop-cont">
<p>비밀번호가 정상적으로 변경되었습니다.</p>
<p>변경된 비밀번호로 다시 로그인 해주세요</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
</div>
<!-- e: 팝업 -->
</div>
</template>
<script>
export default {
data(){
return{
}
},
methods: {
//모달 켜기
ModalOpen(target){
console.log("ModalOpen");
var dimmed = document.getElementsByClassName('dimmed');
var wrap = document.getElementsByClassName('popup-wrap');
var obj = document.getElementsByClassName(target);
dimmed[0].style.display = 'block';
wrap[0].style.display = 'block';
obj[0].style.display = 'block';
},
// 모달 끄기
ModalClose(){
var dimmed = document.getElementsByClassName('dimmed');
var wrap = document.getElementsByClassName('popup-wrap');
var obj = wrap[0].childElementCount
dimmed[0].style.display = 'none';
wrap[0].style.display = 'none';
for(var i = 0; i < obj; i++) {
var target = document.getElementsByClassName('popup');
target[i].style.display = 'none';
}
},
}
}
</script>
<style>
.popup-btn-wrap {width: 500px; margin: auto; padding: 100px 0;}
.popup-btn-wrap button {width: 100%; margin-bottom: 10px; height: 50px; border-radius: 5px; box-shadow: none; border: 1px solid #000; }
.popup-btn-wrap button:hover {background: #000; color: #fff;}
</style>

View File

@@ -0,0 +1,132 @@
<template>
<nav>
<ul v-if="menuList.length > 0" class="main_menu">
<!-- 선택한 메뉴 li.is-current -->
<li v-for="child in menuList" :key="child.menuNo" :class="child.classNm">
<div class="menu_btn" ></div>
<a class="menu_target" @click="clickTest" :data-menu-no="child.menuNo">{{child.menuNm}}</a>
<div class="sub_menu_wrap">
<ul class="sub_menu" v-if="child.children.length > 0">
<li v-for="child2 in child.children" :key="child2.menuNo">
<a href="javascript:void(0);" @click="clickMenu(child2.menuUrl)" :data-menu-no="child2.menuNo">{{child2.menuNm}}</a>
</li>
</ul>
</div>
</li>
</ul>
</nav>
</template>
<script>
//import "../assets/js/script.js";
import api from '@/service/api.js';
export default {
name: 'Nav',
props: {
},
data() {
return {
isLogin : false,
isAuthChk : false,
menuList: null,
tempList: null
}
},
created() {
// 메뉴 가져오기
this.setMenuData();
},
mounted() {},
computed: {
},
watch: {
},
methods: {
setMenuData() {
api.menus().then(response => {
const rootMenu = response.data.data;
console.log(rootMenu);
if (rootMenu != null && rootMenu.children != null && rootMenu.children.length > 0) {
this.tempList = rootMenu.children;
for(var i=0; i<this.tempList.length; i++){
var menuNo = this.tempList[i].menuNo;
var classNm = '';
switch(menuNo){
case 1001 : classNm = 'customer'; break;
case 1002 : classNm = 'attract'; break;
case 1003 : classNm = 'service'; break;
case 1004 : classNm = 'calculate'; break;
case 1005 : classNm = 'channel'; break;
case 1006 : classNm = 'key'; break;
case 1007 : classNm = 'moniter'; break;
case 1008 : classNm = 'risk'; break;
case 1009 : classNm = 'stats'; break;
case 1010 : classNm = 'system'; break;
default : classNm = 'customer';
}
this.tempList[i].classNm = classNm;
//console.log(classNm);
}
//this.menuList = rootMenu.children;
this.menuList = this.tempList;
//this.$store.commit("login/isLogin", true);
//this.$store.commit("login/isAuthChk", true);
} else {
this.$store.commit("login/isLogin", false);
this.$store.commit("login/isAuthChk", false);
this.menuList = null;
this.$router.push({ path: '/login' });
}
}).catch(response => {
this.$store.commit("login/isLogin", false);
this.$store.commit("login/isAuthChk", false);
this.menuList = null;
this.$router.push({ path: '/login' });
console.log(response);
});
},
clickMenu(link){
this.$router.push({
path: link
});
},
clickTest(e){
const menuList = document.querySelectorAll('.main_menu .is-current');
if(e.target.classList.contains('menu_target') || e.target.classList.contains('menu_btn')){
const menuListCheck = e.target.parentNode;
if(menuListCheck.classList.contains('is-current')){
menuListCheck.classList.remove('is-current');
for(const menu of menuList){
menu.classList.remove('is-current');
}
} else {
for(const other of menuList){
other.classList.remove('is-current');
}
menuListCheck.classList.add('is-current');
}
}
},
}
}
</script>

View File

@@ -0,0 +1,133 @@
<template>
<div class="paging" :class="{className: true}">
<a href="javascript:void(0);" class="btn_arrow first" @click="changePageFirst">처음으로</a>
<a href="javascript:void(0);" class="btn_arrow prev" @click="changeRangePrev">이전으로</a>
<a
href="javascript:void(0);"
v-for="page in visiblePage"
:key="`page-${page}`"
:class="{'active': parseInt(currentPage) === page}"
@click="changePage(page)"
>{{ page }}</a>
<a href="javascript:void(0);" class="btn_arrow next" @click="changeRangeNext">다음으로</a>
<a href="javascript:void(0);" class="btn_arrow last" @click="changePageLast">마지막으로</a>
</div>
</template>
<script>
export default {
name: 'Pagination',
props: {
total: {
type: [Number, String],
default: 0
},
pageSize: {
type: [Number, String],
default: 10
},
currentPage: {
type: [Number, String],
default: 1
},
className: {
type: String,
default: ''
},
rangeMax: {
type: [Number, String],
default: 10
}
},
data() {
return {
range: 0
}
},
created() {},
mounted() {},
computed: {
visiblePage() {
let range = []
for (let i = this.rangeStart; i <= this.rangeEnd; i++) {
range.push(i)
}
return range
},
lastPage() {
return parseInt(this.total) > 0
? Math.ceil(parseInt(this.total) / parseInt(this.pageSize))
: 1
},
rangeStart() {
return parseInt(this.rangeMax) * this.range + 1
},
rangeEnd() {
return parseInt(this.rangeMax) * (this.range + 1) < this.lastPage
? parseInt(this.rangeMax) * (this.range + 1)
: this.lastPage
},
lastRange() {
return parseInt(this.total) > 0
? Math.ceil(
parseInt(this.total) /
(parseInt(this.pageSize) * parseInt(this.rangeMax))
)
: 0
}
},
watch: {
total() {
this.init()
},
currentPage() {
this.setRange()
}
},
methods: {
init() {
this.range = 0
},
setRange() {
this.range = Math.floor(
(parseInt(this.currentPage) - 1) / parseInt(this.rangeMax)
)
},
changePage(page) {
this.$emit('update:currentPage', page)
this.$emit('change', page)
},
changeRangePrev() {
if (this.range > 0) {
this.range -= 1
this.$emit('update:currentPage', this.rangeStart)
this.$emit('change', this.rangeStart)
}
},
changeRangeNext() {
if (this.range < this.lastRange - 1) {
this.range += 1
this.$emit('update:currentPage', this.rangeStart)
this.$emit('change', this.rangeStart)
}
},
changePageFirst() {
this.range = 0
this.$emit('update:currentPage', 1)
this.$emit('change', 1)
},
changePageLast() {
if (parseInt(this.total) > 0) {
this.range = this.lastRange - 1
} else {
this.range = 0
}
this.$emit('update:currentPage', this.lastPage)
this.$emit('change', this.lastPage)
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,391 @@
<template>
<div class="wrap bg-wrap">
<!-- 시스템관리 팝업 -->
<!-- <div class="popup-btn-wrap"> -->
<!-- <button class="trigger" onclick="ModalOpen('modal17');">ID 조회</button>
<button class="trigger" onclick="ModalOpen('modal18');">관리자 ID 조회</button>
<button class="trigger" onclick="ModalOpen('modal19');">유치채널 ID 조회</button>
<button class="trigger" onclick="ModalOpen('modal20');">관리자 등록</button>
<button class="trigger" onclick="ModalOpen('modal21');">관리자 상세정보</button>
<button class="trigger" onclick="ModalOpen('modal22');">유치채널 사용자 등록</button>
<button class="trigger" onclick="ModalOpen('modal23');">유치채널 상세정보</button> -->
<!-- <button class="trigger" @click="ModalOpen('modal20');">관리자 등록</button> -->
<!-- </div> -->
<!-- s: 팝업 -->
<div class="dimmed" @click="ModalClose();"></div>
<div class="popup-wrap">
<!-- 시스템관리 팝업 -->
<!-- ID 조회 -->
<div class="popup modal17">
<div class="pop-head">
<h3 class="pop-tit">ID 조회</h3>
</div>
<div class="pop-cont">
<p>입력하신 마당ID를 조회할 없습니다</p>
</div>
<div class="pop-btn1">
<button class="btn-pcolor" @click="ModalClose();">확인</button>
</div>
</div>
<!-- 관리자 ID 조회 -->
<div class="popup modal18">
<div class="pop-head">
<h3 class="pop-tit">관리자 ID 조회</h3>
</div>
<div class="pop-cont">
<p>선택하신 정보가 아래와 같습니다.</p>
<p>관리자 정보를 입력하시겠습니까?</p>
</div>
<ul class="pop-cont-detail">
<li>마당ID : uplus01</li>
<li>이름 : 홍길동</li>
<li>휴대폰번호 : 01012345555</li>
<li>이메일 : abc@abc.com</li>
</ul>
<div class="pop-btn2">
<button class="btn-default" @click="ModalClose();">취소</button>
<button class="btn-pcolor">확인</button>
</div>
</div>
<!-- 유치채널 ID 조회 -->
<div class="popup modal19">
<div class="pop-head">
<h3 class="pop-tit">유치채널 ID 조회</h3>
</div>
<div class="pop-cont">
<p>선택하신 정보가 아래와 같습니다.</p>
<p>유치채널 정보를 입력하시겠습니까?</p>
</div>
<ul class="pop-cont-detail">
<li>마당ID : uplus01</li>
<li>이름 : 홍길동</li>
<li>휴대폰번호 : 01012345555</li>
<li>이메일 : abc@abc.com</li>
<li>코드 : 1234</li>
</ul>
<div class="pop-btn2">
<button class="btn-default" @click="ModalClose();">취소</button>
<button class="btn-pcolor">확인</button>
</div>
</div>
<!-- 관리자 등록 -->
<div class="popup modal20 popup_form">
<div class="pop-head">
<h3 class="pop-tit">관리자 등록</h3>
</div>
<form autocomplete="off">
<table>
<tbody>
<tr>
<th>마당 ID</th>
<td class="input_search">
<input type="text" placeholder="아이디 입력">
<button type="button" class="button grey" @click="ModalOpen('modal17')">조회</button>
</td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password"></td>
</tr>
<tr>
<th>비밀번호 확인</th>
<td><input type="password"></td>
</tr>
<tr>
<th>이름</th>
<td><input type="text"></td>
</tr>
<tr>
<th>휴대폰번호</th>
<td><input type="text" placeholder="- 자 제외 숫자만 입력"></td>
</tr>
<tr>
<th>이메일</th>
<td><input type="email"></td>
</tr>
<tr>
<th>권한</th>
<td>
<div :class="select_box">
<select name="" id="right">
<option value="">선택</option>
<option value="전체">전체</option>
<option value="운영자">운영자</option>
</select>
</div>
</td>
</tr>
<tr>
<th class="center">상태</th>
<td>
<input type="radio" name="state" value="사용" id="popup_radio1" checked>
<label for="popup_radio1">사용</label>
<input type="radio" name="state" value="정지" id="popup_radio2">
<label for="popup_radio2">정지</label>
</td>
</tr>
</tbody>
</table>
</form>
<div class="pop-btn2">
<button class="btn-default" @click="ModalClose();">취소</button>
<button class="btn-pcolor">저장</button>
</div>
</div>
<!-- 관리자 상세정보 -->
<div class="popup modal21 popup_form">
<div class="pop-head">
<h3 class="pop-tit">관리자 상세정보</h3>
</div>
<form autocomplete="off">
<table>
<tbody>
<tr>
<th>ID</th>
<td><input type="text" disabled value="uplus1"></td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password"></td>
</tr>
<tr>
<th>비밀번호 확인</th>
<td><input type="password"></td>
</tr>
<tr>
<th>이름</th>
<td><input type="text" disabled value="홍길동"></td>
</tr>
<tr>
<th>휴대폰번호</th>
<td><input type="text" disabled value="01012345678"></td>
</tr>
<tr>
<th>이메일</th>
<td><input type="email" disabled value="adm@site.com"></td>
</tr>
<tr>
<th>권한</th>
<td>
<div class="select_box">
<select name="" id="right">
<option value="전체">전체</option>
<option value="운영자">운영자</option>
</select>
</div>
</td>
</tr>
<tr>
<th class="center">상태</th>
<td>
<input type="radio" name="state" value="사용" id="popup_radio1" checked>
<label for="popup_radio1">사용</label>
<input type="radio" name="state" value="정지" id="popup_radio2">
<label for="popup_radio2">정지</label>
</td>
</tr>
</tbody>
</table>
</form>
<div class="pop-btn2">
<button class="btn-default" @click="ModalClose();">취소</button>
<button class="btn-pcolor">저장</button>
</div>
</div>
<!-- 유치채널 사용자 등록 -->
<div class="popup modal22 popup_form">
<div class="pop-head">
<h3 class="pop-tit">유치채널 사용자 등록</h3>
</div>
<form autocomplete="off">
<table>
<tbody>
<tr>
<th>ID</th>
<td class="input_search">
<input type="text" placeholder="아이디 입력">
<button type="button" class="button grey">조회</button>
</td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password"></td>
</tr>
<tr>
<th>비밀번호 확인</th>
<td><input type="password"></td>
</tr>
<tr>
<th>이름(대리점명)</th>
<td><input type="text"></td>
</tr>
<tr>
<th>휴대폰번호</th>
<td><input type="text" placeholder="- 자 제외 숫자만 입력"></td>
</tr>
<tr>
<th>이메일</th>
<td><input type="email"></td>
</tr>
<tr>
<th>코드</th>
<td><input type="text"></td>
</tr>
<tr>
<th>권한</th>
<td><input type="text" disabled value="대리점"></td>
</tr>
<tr>
<th class="center">상태</th>
<td>
<input type="radio" name="state" value="사용" id="popup_radio1" checked>
<label for="popup_radio1">사용</label>
<input type="radio" name="state" value="정지" id="popup_radio2">
<label for="popup_radio2">정지</label>
</td>
</tr>
</tbody>
</table>
</form>
<div class="pop-btn2">
<button class="btn-default" @click="ModalClose();">취소</button>
<button class="btn-pcolor">저장</button>
</div>
</div>
<!-- 유치채널 상세정보 -->
<div class="popup modal23 popup_form">
<div class="pop-head">
<h3 class="pop-tit">유치채널 상세정보</h3>
</div>
<form autocomplete="off">
<table>
<tbody>
<tr>
<th>ID</th>
<td><input type="text" disabled value="uplus1"></td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password"></td>
</tr>
<tr>
<th>비밀번호 확인</th>
<td><input type="password"></td>
</tr>
<tr>
<th>이름(대리점명)</th>
<td><input type="text" disabled value="플러스"></td>
</tr>
<tr>
<th>휴대폰번호</th>
<td><input type="text" disabled value="01012345678"></td>
</tr>
<tr>
<th>이메일</th>
<td><input type="email" disabled value="abc@abc.com"></td>
</tr>
<tr>
<th>코드</th>
<td><input type="text" disabled value="5678"></td>
</tr>
<tr>
<th>권한</th>
<td><input type="text" disabled value="대리점"></td>
</tr>
<tr>
<th class="center">상태</th>
<td>
<input type="radio" name="state" value="사용" id="popup_radio1" checked>
<label for="popup_radio1">사용</label>
<input type="radio" name="state" value="정지" id="popup_radio2">
<label for="popup_radio2">정지</label>
</td>
</tr>
</tbody>
</table>
</form>
<div class="pop-btn2">
<button class="btn-default" @click="ModalClose();">취소</button>
<button class="btn-pcolor">저장</button>
</div>
</div>
<!-- 시스템관리 팝업 -->
</div>
<!-- e: 팝업 -->
</div>
</template>
<script>
export default {
data(){
return{
}
},
methods :{
// 모달 띄우기
ModalOpen(target){
console.log("ModalOpen");
var dimmed = document.getElementsByClassName('dimmed');
var wrap = document.getElementsByClassName('popup-wrap');
var obj = document.getElementsByClassName(target);
dimmed[0].style.display = 'block';
wrap[0].style.display = 'block';
obj[0].style.display = 'block';
},
// 모달 끄기
ModalClose(){
var dimmed = document.getElementsByClassName('dimmed');
var wrap = document.getElementsByClassName('popup-wrap');
var obj = wrap[0].childElementCount
dimmed[0].style.display = 'none';
wrap[0].style.display = 'none';
for(var i = 0; i < obj; i++) {
var target = document.getElementsByClassName('popup');
target[i].style.display = 'none';
}
},
//메뉴바
testClick(){
const menuList = document.querySelectorAll('.main_menu .is-sub');
for(const menu of menuList){
menu.addEventListener('click', (e)=> {
if(e.target.classList.contains('menu_target') || e.target.classList.contains('menu_btn')){
const menuListCheck = e.target.parentNode;
if(menuListCheck.classList.contains('is-current')){
menuListCheck.classList.remove('is-current');
} else {
for(const other of menuList){
other.classList.remove('is-current');
}
menuListCheck.classList.add('is-current');
}
}
})
}
}
}
}
</script>
<style>
.popup-btn-wrap {width: 500px; margin: auto; padding: 100px 0;}
.popup-btn-wrap button {width: 100%; margin-bottom: 10px; height: 50px; border-radius: 5px; box-shadow: none; border: 1px solid #000; }
.popup-btn-wrap button:hover {background: #000; color: #fff;}
</style>

View File

@@ -0,0 +1,61 @@
<template>
<div class="tree-menu">
<div class="label-wrapper" v-if="depth > 0" @click="toggleChildren">
<div :style="indent" :class="labelClasses">
{{ label }}
<b v-if="nodes">[{{showChildren ? '-' : '+'}}]</b>
</div>
</div>
<span v-if="showChildren">
<TreeMenu
v-for="node in nodes"
:key="node.label"
:nodes="node.nodes"
:label="node.label"
:depth="depth + 1"
></TreeMenu>
</span>
</div>
</template>
<script>
export default {
name: "TreeMenu", // recursive component에는 name 설정 필수.
props: ["nodes", "label", "depth"],
data() {
return {
showChildren: true
};
},
computed: {
labelClasses() {
return { "has-children": this.nodes };
},
indent() {
return { transform: `translate(${(this.depth-1) * 50}px)` };
}
},
methods: {
toggleChildren() {
this.showChildren = !this.showChildren;
}
}
};
</script>
<style lang="scss" scoped>
.container {
width: 300px;
margin: 0 auto;
}
.tree-menu {
.label-wrapper {
padding-bottom: 10px;
margin-bottom: 10px;
.has-children {
cursor: pointer;
}
}
}
</style>

View File

@@ -0,0 +1,293 @@
<template>
<grid
ref="tuiGrid"
:class="addClass"
:data="gridProps.data"
:columns="gridProps.columns"
:options="gridProps.options"
:language="gridProps.language"
@click="clicked"
@response="response"
@beforeRequest="beforeRequest"
:summary="gridProps.summary"
/>
<!--
- 공식홈: https://ui.toast.com/tui-grid
- vue git: https://github.com/nhn/toast-ui.vue-grid
- api & sample: https://nhn.github.io/tui.grid/latest/
- 연동 결과는 아래 포맷에 맞추어 주세요.
TuiGrid.java VO 참고
적용 : UserController > user
{
"result": true,
"data": {
"contents": [],
"pagination": {
"page": 1,
"totalCount": 100
}
}
}
-->
</template>
<script>
import 'tui-grid/dist/tui-grid.css';
import 'tui-pagination/dist/tui-pagination.css';
import TuiGrid from 'tui-grid';
import { Grid } from '@toast-ui/vue-grid';
export default {
name: 'tuiGrid',
props: [
'url', // 연동 url
'initialRequest', // false일 시 초기 렌더링 시 백엔드에 요청 하지 않음. 이 경우 readData를 호출하여 그리드 데이터를 할당해 줘야 함
'rowHeaders', // 체크 박스 등 헤더에 필요한 타입 ex) ["checkbox"]
'header', // 옵션 (헤더 병합 등)
'minRowHeight', // 리스트 row 높이
'minBodyHeight', // 테이블 높이
'pagination', // 페이지 네비게이션 사용 여부
'perPage', // 페이지 당 개수
'totalItems', // 부모창에 표시할 총 컨텐츠 개수 변수 명 (더 좋은 방법 있으면 알려주세요.)
'columns', // 컬럼 정보
'showVerticalBorder', // cell 세로라인 표시
'noDataStr', // 데이터가 없을 때
'noSearchStr', // 검색 결과가 없을 때
'scrollX', // 가로 스크롤 사용 여부
'scrollY', // 세로 스크롤 사용 여부
'addClass', // table에 추가할 클래스
'evtClick', // 클릭 이벤트 정보, 해당 커럼을 클릭하면 callback 수행, 이때 해당 row의 데이터를 파라미터로 반환한다. Object Or Array
// ex) evtClick: { column: "idx", callback: clickIdx }
// or evtClick: [ { column: "idx", callback: this.myFnc }, { column: "name", ... } ]
'summary'
],
components: {
grid: Grid
},
data() {
return {
instance: null,
gridProps: null,
currEventListener: null,
currGridEle: null,
currMode: 'normal'
};
},
mounted() {
this.saveGridEventListner();
//if(this.currMode != 'normal')
//this.initGridEventListner();
},
beforeDestroy() {
this.addGridEventListner();
},
created() {
/**
* Use the static method as below
*/
TuiGrid.applyTheme('default', {
outline: {
border: '#333 !important' // 테이블 위아래 선의 색깔 지정
},
row: {
hover: {
background: '#fafafa !important' // row 마우스 오버 시 색깔 지정
}
},
area: {
header: {
border: '#aaaaaa !important' // header 아래 선의 색깔 지정
}
},
cell: {
normal: {
showVerticalBorder: this.showVerticalBorder === true // 각 셀의 세로 선 노출
}
}
});
this.gridProps = {
data: {
api: {
readData: { url: this.url, method: 'GET' }
},
initialRequest: typeof this.initialRequest == 'undefined' ? true : this.initialRequest
},
options: {
rowHeaders: this.rowHeaders,
header: this.header ? this.header : { height: 47 },
minRowHeight: this.minRowHeight ? this.minRowHeight : 56,
minBodyHeight: this.minBodyHeight ? this.minBodyHeight : 56,
showDummyRows: true,
scrollX: this.scrollX === true,
scrollY: this.scrollY === true,
pagination: this.pagination,
pageOptions: {
perPage: this.perPage
}
},
language: {
name: 'ko',
value: {
display: {
noData: this.noDataStr
}
}
},
columns: this.columns,
summary: this.summary
};
},
methods: {
clicked: function(v) {
if (typeof this.evtClick != 'undefined' && this.evtClick != null) {
let data = this.$refs.tuiGrid.invoke('getRow', v.rowKey);
if (Array.isArray(this.evtClick)) {
for (var i = 0; i < this.evtClick.length; i++) {
if (v.columnName == this.evtClick[i].column && typeof this.evtClick[i].callback == 'function') {
this.evtClick[i].callback(data);
}
}
} else if (
this.evtClick.column != null &&
v.columnName == this.evtClick.column &&
typeof this.evtClick.callback == 'function'
) {
this.evtClick.callback(data);
}
}
},
response: function(event) {
let xhr = event.xhr;
let statusCode = xhr.status;
if (statusCode == 200) {
let respData = JSON.parse(xhr.response).data;
this.$parent[this.totalItems] = respData.pagination.totalCount;
let len = respData.contents.length;
if (this.scrollY == false) {
if (len > 0) {
let divLen = 6;
if (this.scrollX == true) {
divLen = 5;
}
// header의 height를 구할 수 있는 방법은? 일단 48
let addLen = len / divLen;
this.getGridInstance().setBodyHeight((len + addLen) * 48);
} else {
this.getGridInstance().setBodyHeight(48);
}
}
} else if (statusCode == 401 || statusCode == 418) {
alert('세션이 만료되었습니다.');
window.top.location.href = '/login';
} else {
window.top.location.href = '/view/error/' + statusCode;
}
},
beforeRequest: function(event) {
if (this.scrollY == false) {
this.getGridInstance().setBodyHeight(90);
}
},
getData: function() {
// 전체 Row 데이터를 가져온다.
return this.getGridInstance().getData();
},
getRow: function(rowKey) {
// 해당 Row의 데이터를 가져온다.
return this.getGridInstance().getRow(rowKey);
},
getPagination: function() {
// 페이지 정보
return this.getGridInstance().getPagination();
},
setPerPage: function(count) {
// 페이지 당 표시 개수 변경
this.getGridInstance().setPerPage(count);
},
readData: function(page, param) {
// 페이지 데이터 갱신 (initialRequest가 false일 경우 초기 데이터 로드시에도 사용)
this.getGridInstance().readData(page, param, true);
},
appendRow: function(rowData, rownum) {
var optionsOpt = {
at: rownum || 0,
extendPrevRowSpan: false,
focus: false
};
this.getGridInstance().appendRow(rowData, optionsOpt);
},
search: function(param) {
// 검색 결과가 없을 경우 텍스트 변경
let noSearchStr = '';
if (typeof this.noSearchStr == 'undefined') {
noSearchStr = '검색 결과가 없습니다.';
}
this.$refs.tuiGrid.language.value.display.noData = noSearchStr;
this.$refs.tuiGrid.setLanguage();
// param을 기반으로 리스트 갱신
this.readData(1, param);
},
gridMethod: function(params) {
return this.$refs.tuiGrid.invoke(...params);
},
getGridInstance() {
if (this.instance == null) {
this.instance = this.$refs.tuiGrid.gridInstance;
}
return this.instance;
},
saveGridEventListner() {
// this.currGridEle = document.querySelector(`div.tui-grid-container.tui-grid-show-lside-area`);
this.currGridEle = document.querySelector(`div.tui-grid-container`);
if (this.currGridEle != null && window.getEventListeners(this.currGridEle).mousedown) {
this.currEventListener = window.getEventListeners(this.currGridEle).mousedown[0].listener;
}
},
removeGridEventListner() {
this.currMode = 'edit';
this.currGridEle.removeEventListener('mousedown', this.currEventListener);
this.currGridEle.setAttribute('tabindex', '0');
this.currGridEle.style.outline = 'none';
this.currGridEle.addEventListener('keydown', this.copyEvent, false);
},
addGridEventListner() {
this.currMode = 'normal';
this.currGridEle.removeAttribute('tabindex');
this.currGridEle.removeEventListener('keydown', this.copyEvent);
this.currGridEle.addEventListener('mousedown', this.currEventListener);
},
initGridEventListner() {
document.querySelector(`div.tui-grid-container`).removeAttribute('tabindex');
document.querySelector(`div.tui-grid-container`).removeEventListener('keydown', this.copyEvent);
document.querySelector(`div.tui-grid-container`).addEventListener('mousedown', this.currEventListener);
},
copyEvent(ev) {
ev = ev || window.event;
var key = ev.which || ev.keyCode; // keyCode detection
var ctrl = ev.ctrlKey ? ev.ctrlKey : key === 17 ? true : false; // ctrl detection
if (key == 67 && ctrl) {
var clipboard = document.querySelector('.tui-grid-clipboard');
clipboard.innerHTML = this.getGridInstance().getFocusedCell().value;
clipboard.focus();
document.execCommand('copy');
}
}
}
};
</script>
<!-- 스타일 추가 CSS 우선순위를 높이기 위해 아래과 같이 .tui-grid-cell를 CSS 선택자에 포함시켜서 사용해야 적용 -->
<style>
.tui-grid-cell.cell-red {
background-color: red;
}
.tui-grid-table {
width: 100% !important;
}
</style>

View File

@@ -0,0 +1,27 @@
<template>
<select v-model="perCnt" @change="perPage">
<option v-for="(cnt, index) in perList" :key="index" :value="cnt">{{cnt}}</option>
</select>
</template>
<script>
export default {
name: "tuiGridPerPage",
props: [
"grid", // tuiGrid의 ref 값
"per", // 초기 tuiGrid의 페이지 당 개수
"perList" // 페이지 당 개수 정보 ex: countList: [5, 10, 50, 100]
],
data() {
return {
perCnt: this.per
}
},
methods: {
perPage: function() {
this.$parent.$refs[this.grid].setPerPage(this.perCnt);
}
}
}
</script>

View File

@@ -0,0 +1,116 @@
`
샘플 문서, 추후 삭제 예정 입니다.
`
<template>
<grid ref="tuiGrid"
:data="gridProps.data"
:columns="gridProps.columns"
:options="gridProps.options"
@click="clicked"
/>
</template>
<script>
import 'tui-grid/dist/tui-grid.css'
import { Grid } from '@toast-ui/vue-grid'
class inputTag {
constructor(props) {
const el = document.createElement('input');
el.type = "text";
el.style.width = "80%";
this.el = el;
this.render(props);
}
getElement() {
return this.el;
}
render(props) {
this.el.value = "test";
//this.el.value = String(props.value.chatbotId);
}
}
class divTag {
constructor(props) {
const div = document.createElement("div");
// props >> 컬럼 데이터. 하위 데이터가 있다면 props.value.xxx로 접근 가능하다.
div.appendChild(document.createElement("div")).textContent = "id: " + props.value.chatbotId
div.appendChild(document.createElement("div")).textContent = "snum: " + props.value.subNum
this.el = div;
}
getElement() {
return this.el;
}
}
export default {
components: {
'grid': Grid
},
data() {
return {
gridProps: null
}
},
created() {
this.gridProps = {
data: {
api: {
readData: { url: '/api/test/test', method: 'GET' },
}
},
pageOptions: {
perPage: 5
},
options: {
header: {
height: 100,
// 헤더 merge
complexColumns: [
{ header: "브랜드 모음", name: 'mergeColumn1', childNames: ["corpId", "mergeBrand", "mergeInfo"] },
{ header: "브랜드", name: 'mergeBrand', childNames: ["brId", "brNm"] },
{ header: "정보", name: 'mergeInfo', childNames: ["useYn", "apprYn", "apprReqYmd", "apprYmd"] }
]
}
},
// 헤더
columns: [
{ name: "corpId", header: "회사 아이디", align: "center" },
{ name: "brId", header: "브랜드 아이디", align: "center" },
{ name: "brNm", header: "브랜드 명", align: "center", sortable: true },
{ name: "useYn", header: "사용 여부", align: "center" },
{ name: "apprYn", header: "승인 여부", align: "center" },
{ name: "apprReqYmd", header: "승인요청 날짜", align: "center", sortable: true },
{ name: "apprYmd", header: "승인 날짜", align: "center", sortable: true },
{ name: "noname", header: "커스텀 1", align: "center", renderer: {
type: inputTag // 별도의 컬럼 구성이 필요한 경우
}},
{ name: "chatbot", header: "커스텀 2", align: "center", renderer: {
type: divTag // 별도의 컬럼 구성이 필요한 경우
}}
]
}
},
mounted() {
this.linkTo();
},
methods: {
linkTo: function() {
this.$refs.tuiGrid.invoke("addCellClassName", "0", "corpId", "cell-red");
},
clicked: function(v) {
var data = this.$refs.tuiGrid.invoke("getRow", v.rowKey);
alert("브랜드 아이디(" + data.brId + ") 클릭");
}
}
}
</script>
<style>
.tui-grid-cell.cell-red {background-color: red}
</style>

View File

@@ -0,0 +1,235 @@
<template>
<div
:class="kind ? 'block' : 'hidden'"
:style="'z-index: ${zIndex};'"
v-if="visible"
class="layer mid active"
>
<div class="layer_cont">
<div class="layer_head">
<h2>{{title}}</h2>
<slot name="header"></slot>
</div>
<div class="layer_body">
<slot>
<p>{{content}}</p>
</slot>
<!--scroll style="max-height:50vh; position: relative;" :settings="scrollSettings">
</scroll-->
</div>
<div class="layer_foot">
<div class="check_wrap" v-if="checkLabel">
<span class="custom_checkbox">
<input type="checkbox" id="checkbox01" v-model="checked">
<label for="checkbox01">{{checkLabel}}</label>
</span>
</div>
<slot name="footer">
<div class="btn_wrap center" v-if="yesBtn" style="margin-bottom: 20px;">
<a href="javascript:void(0)" @click="handleWrapperClick(kind, 'yes')" class="btn mid point">
<span>{{yesBtn}}</span>
</a>
</div>
<div class="btn_wrap center" v-if="noBtn" style="margin-bottom: 20px;">
<a href="javascript:void(0)" @click="handleWrapperClick(kind)" class="btn mid point">
<span>{{noBtn}}</span>
</a>
</div>
<!-- <a href="javascript:void(0)" @click="handleWrapperClick('close')" class="btn_close">
</a> -->
</slot>
</div>
</div>
</div>
</template>
<script>
import Scroll from 'vue-custom-scrollbar'
export default {
name: 'AddressCustomPopup',
components: {
Scroll
},
props: {
visible: {
type: Boolean,
require: true,
default: false
},
title: {
type: String,
require: true
},
checkLabel: {
type: String,
require: true
},
searchProp: {
type: Boolean,
require: true,
default: false
},
kind: {
type: String,
require: true
},
content: {
type: String,
require: false
},
widths: {
type: Object,
require: false,
default() {
return {
widthLg: 'w-1/2',
widthXl: 'w-2/5'
}
}
},
zIndex: {
type: Number,
require: false,
default() {
return 99999
}
},
marginTop: {
type: String,
require: false,
default() {
return '40' // px 단위
}
},
maxHeight: {
type: String,
require: false,
default() {
return '80' // px 단위
}
},
boxPX: {
type: String,
require: false,
default() {
return 'px-4'
}
},
boxPY: {
type: String,
require: false,
default() {
return 'py-8'
}
},
uiframeBox: {
type: Boolean,
require: false,
default: true
},
yesBtn: {
type: String,
require: false
},
noBtn: {
type: String,
require: false
},
close: Function,
inBody: {
type: Boolean,
require: false,
default: false
},
visibleScroll: {
type: Boolean,
default: true
}
},
data() {
return {
contents: false,
checked: true,
scrollSettings: {
suppressScrollY: false
}
}
},
created() {
this.scrollOps();
console.log("AddressCustomPoipup >", this.visible);
},
mounted() {
if (this.inBody) {
document.body.appendChild(this.$el)
}
},
watch: {
visibleScroll() {
this.scrollOps()
}
},
methods: {
handleWrapperClick(id, callback) {
this.$emit('close', {
id: id,
ok: callback === 'yes'
})
},
scrollOps() {
this.scrollSettings.suppressScrollY = !this.visibleScroll
}
}
}
</script>
<style lang="less" scoped>
.block {
animation: fadein 0.5s;
-webkit-animation: fadein 0.5s;
-ms-animation: fadein 0.5s;
}
.height_60 {
height: 60px;
padding-top: 10px;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
margin: 0 1rem;
width: calc(100% - 2rem);
height: 1px;
background: #eff3f6;
}
}
.content_h {
height: calc(100% - 50px);
}
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@-webkit-keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@-ms-keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>

View File

@@ -0,0 +1,332 @@
<template>
<!-- 커스텀팝업 -->
<address-custom-popup
:visible="visible"
@close="closePopup"
kind="custom"
title="우편번호 찾기"
:noBtn="view.noBtnText"
:yesBtn="view.yesBtnText"
:zIndex="500"
boxPY="pb-5"
:visibleScroll="view.visibleScroll"
>
<template v-slot:header>
</template>
<div class="box_search_wrap" v-if="view.visibleSearch">
<div class="box_search_area">
<div class="filter_bundle_wrap">
<div class="filter_bundle">
<div class="cont_bundle full_width">
<span class="custom_input col_10" style="width: 80%">
<input type="text" placeholder="도로명 또는 건물명(아파트)을 입력해주세요"
ref="addressNm"
v-model="addressNm"
@keypress.enter="search">
</span>
<a href="javascript:void(0);" class="btn mid gray square col_2" @click="search"><span>검색</span></a>
</div>
</div>
</div>
</div>
</div>
<div class="mar_t20" v-if="!view.visibleDetails">
<!-- 검색 건수 -->
<p class="mar_t20" v-if="view.visibleTotalcount">
<span class="result_count left full_width">{{ page.totalcount }}</span>건이 검색되었습니다.
</p>
<!-- 디폴트 문구 -->
<div
class="mar_t20"
v-if="isVisibleDescription"
:class="{'line': view.visibleTotalcount}"
>
<p class="txt_17">도로명 주소와 건물번호를 함께 입력하시면 빠르게 결과를 확인하실 있습니다.</p>
<ul class="mar_t10 txt_16 text_gray2">
<li>도로명 + 건물번호 (: 송파대로 570)</li>
<li>도로명( : 강남대로, 중앙1로, 낙산1길)</li>
<li>건물명, 아파트명 (: 반포자이아파트)</li>
</ul>
</div>
<!-- 리스트 -->
<table class="tbl_row_type type3" v-if="!isVisibleDescription">
<colgroup>
<col style="width:100px;">
<col style="width:350px;">
<col style="width:auto;">
</colgroup>
<thead>
<tr>
<th>우편번호</th>
<th scope="row">도로명</th>
<th>지번</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in list" :key="`list-${index}`">
<td><a href="javascript:void(0);" @click="selectAddr(row)"> {{ row.zipCode }}</a></td>
<td><a href="javascript:void(0);" @click="selectAddr(row)"> {{ row.doroAddressNm }}</a></td>
<td><a href="javascript:void(0);" @click="selectAddr(row)"> {{ row.jibunAddressNm }}</a></td>
</tr>
</tbody>
</table>
<!-- 리스트 페이징 -->
<pagination
v-if="!isVisibleDescription"
:total="page.totalcount"
:current-page.sync="page.currentPage"
:pageSize="page.size"
rangeMax="5"
@change="changePage"
class="type2"
></pagination>
</div>
<!-- 상세주소 입력 -->
<div class="search_result" v-if="view.visibleDetails">
<table class="tbl_row_type">
<caption>
<strong>우편번호 찾기</strong>
<p>우편번호, 도로명/지번 주소</p>
</caption>
<colgroup>
<col style="width:120px;">
<col style="width:auto;">
</colgroup>
<tbody>
<tr>
<th scope="row">우편번호</th>
<td>{{ selectedAddr.zipCode }}</td>
</tr>
<tr>
<th scope="row">
도로명
<br>지번
</th>
<td>
<p>{{ selectedAddr.doroAddressNm }}</p>
<p>{{ selectedAddr.jibunAddressNm }}</p>
</td>
</tr>
</tbody>
</table>
</div>
<div class="box_search_area mar_t20" v-if="view.visibleDetails">
<div class="filter_bundle_wrap">
<div class="filter_bundle">
<div class="cont_bundle full_width">
<span class="custom_input full_width" style="width: 100%"><input type="text" placeholder="상세주소를 입력해주세요" v-model="selectedAddr.detail"></span>
</div>
</div>
</div>
<a href="javascript:void(0)" @click="handleWrapperClick" class="btn_close"></a>
</div>
</address-custom-popup>
</template>
<script>
import AddressCustomPopup from './AddressCustomPopup'
import jglib from '@/utils/jglib'
import commApi from '@/common/comm-api'
import Pagination from '@/components/Pagination'
export default {
name: 'AddressPopup',
components: {
AddressCustomPopup,
jglib,
Pagination
},
props: {
visible: {
type: Boolean,
default: true
}
},
data() {
return {
view: {
visibleSearch: true,
visibleTotalcount: false,
visibleDetails: false,
noBtnText: '닫기',
yesBtnText: '',
visibleScroll: false,
pagination: true,
},
addressNm: '',
list: [],
page: {
totalcount: 0,
currentPage: 5,
size: 5
},
selectedAddr: {
doroAddressNm: '',
jibunAddressNm: '',
zipCode: '',
detail: ''
}
}
},
computed: {
isVisibleDescription() {
return parseInt(this.page.totalcount) === 0
}
},
created() {
this.toggleButton(true);
},
mounted() {},
watch: {
'view.visibleDetails'(value) {
if (value) {
this.setVisibleScroll(false)
}
},
isVisibleDescription(value) {
if (!value) {
this.$nextTick(() => {
this.setVisibleScroll(true)
})
}
}
},
methods: {
search() {
// validate
if (jglib.isEmpty(this.addressNm)) {
alert(
'도로명 또는 건물명(아파트)을 입력해주세요'
).then(() => {
this.$refs.addressNm.focus()
})
return false
}
this.view.visibleDetails = false
this.page.currentPage = 1
this.retrieveAddress()
},
retrieveAddress() {
let params = {
page: this.page.currentPage,
psize: this.page.size,
addressNm: this.addressNm
}
commApi
.getAddressList(params)
.then(response => {
var rsp = response.data
if (rsp.success) {
this.list = rsp.data
this.page.totalcount = rsp.search.totalCount
this.view.visibleTotalcount = true
if (this.page.totalcount === 0) {
this.view.visibleDescription = true
} else {
this.view.visibleDescription = false
}
}
})
.catch(err => {
alert(err.desc)
})
},
selectAddr(addr) {
Object.assign(this.selectedAddr, addr)
this.view.visibleSearch = false
this.view.visibleDetails = true
this.toggleButton(false)
},
toggleButton(isClose) {
if (isClose) {
// 닫기 버튼
this.view.noBtnText = '닫기'
this.view.yesBtnText = ''
} else {
// 확인
this.view.noBtnText = ''
this.view.yesBtnText = '확인'
}
},
closePopup(res) {
if(res.id == 'close'){
this.$emit('closeAddressPopup', false);
} else {
if (this.view.visibleDetails && jglib.isEmpty(this.selectedAddr.detail)) {
alert('상세주소를 입력해 주세요.');
} else {
if (res.ok) {
let data = {
zipNo: this.selectedAddr.zipCode,
roadFullAddr: this.selectedAddr.doroAddressNm,
detail: this.selectedAddr.detail
}
this.$emit('getData', data)
} else {
this.$emit('closeAddressPopup', false);
}
}
}
},
changePage(page) {
this.page.currentPage = page
this.retrieveAddress()
},
setVisibleScroll(flag) {
this.view.visibleScroll = flag
},
handleWrapperClick() {
this.$emit('closeAddressPopup', false);
},
}
}
</script>
<style lang="less" scoped>
.layer .search_result .address_list {
border-top: 2px solid #666;
border-bottom: 1px solid #aaa;
letter-spacing: -0.02em;
}
.layer .search_result .address_list li + li {
border-top: 1px solid #ccc;
}
.layer .search_result .address_list li a {
display: flex;
align-items: center;
}
.layer .search_result .address_list li a:hover {
color: #f5f5f5;
}
.layer .search_result .address_list li a > .address {
width: ~'calc(100% - 70px)';
padding: 15px 10px 15px 20px;
box-sizing: border-box;
}
.layer .search_result .address_list li a > .zipcode {
width: 70px;
padding: 20px 20px 20px 0;
box-sizing: border-box;
text-align: right;
}
.layer .search_result .address_list li p {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
line-height: 1.5;
}
.layer .search_result .address_list li p strong.title {
width: 45px;
margin-right: 20px;
}
.layer .search_result .address_list li p span {
width: ~'calc(100% - 65px)';
font-size: 16px;
color: #666;
font-weight: normal;
font-family: 'NotoSansLight';
}
</style>

File diff suppressed because one or more lines are too long

19
frontend/src/main.js Normal file
View File

@@ -0,0 +1,19 @@
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import { coreUiMixin } from "@/common/vue-mixins";
import jglib from '@/utils/jglib';
Vue.config.productionTip = false;
Vue.mixin(coreUiMixin);
Vue.prototype.runModeType = "LIVE";
new Vue({
router,
store,
jglib,
render: h => h(App)
}).$mount('#app')

View File

@@ -0,0 +1,11 @@
import ChannelList from '../views/ChannelList'
export default [
{
path: '/attractMgt/channelList',
component: ChannelList,
name: 'channelList',
meta: { public: true }
}
]

View File

@@ -0,0 +1,107 @@
<template>
<div class="contents">
<div class="contents_wrap">
<div class="top_wrap">
<h3 class="title">유치채널 목록조회</h3>
<p class="breadcrumb">시스템관리 &gt; 권한 관리</p>
</div>
<div class="info">
<div class="count"> <span>4</span></div>
<div class="button_group">
<button type="button" class="button blue add" onclick="location.href='system_right_add.html';">권한 추가</button>
</div>
</div>
<div class="table">
<table>
<colgroup>
<col width="10%"/>
<col width="20%"/>
<col width="20%"/>
<col width="15%"/>
<col width="20%"/>
<col width="15%"/>
</colgroup>
<thead>
<tr>
<th>NO</th>
<th>코드</th>
<th>권한명</th>
<th>상태</th>
<th>등록일</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>4</td>
<td>Admin_01</td>
<td>슈퍼관리자</td>
<td>사용</td>
<td>2022-03-10</td>
<td class="two_btn_group">
<button type="button" class="button grey" onclick="location.href='system_right_modify.html';">수정</button>
<button type="button" class="button white delete">삭제</button>
</td>
</tr>
<tr>
<td>3</td>
<td>Admin_01</td>
<td>슈퍼관리자</td>
<td>사용</td>
<td>2022-03-10</td>
<td class="two_btn_group">
<button type="button" class="button grey">수정</button>
<button type="button" class="button white delete">삭제</button>
</td>
</tr>
<tr>
<td>2</td>
<td>Admin_01</td>
<td>슈퍼관리자</td>
<td>사용</td>
<td>2022-03-10</td>
<td class="two_btn_group">
<button type="button" class="button grey">수정</button>
<button type="button" class="button white delete">삭제</button>
</td>
</tr>
<tr>
<td>1</td>
<td>Admin_01</td>
<td>슈퍼관리자</td>
<td>사용</td>
<td>2022-03-10</td>
<td class="two_btn_group">
<button type="button" class="button grey">수정</button>
<button type="button" class="button white delete">삭제</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'channelList',
data() {
return {
};
},
components: {
},
destroyed() {
},
mounted() {
},
methods: {
}
};
</script>

View File

@@ -0,0 +1,12 @@
import CalcList from '../views/CalcList'
export default [
{
path: '/calculate/calcList',
component: CalcList,
name: 'calcList',
meta: { public: true }
},
]

View File

@@ -0,0 +1,165 @@
<template>
<div class="contents">
<div class="contents_wrap">
<div class="top_wrap">
<h3 class="title">정산이력목록조회</h3>
<p class="breadcrumb">시스템관리 &gt; 관리자/유치채널 관리</p>
</div>
<form autocomplete="off" class="search_form">
<div class="search_wrap">
<div class="select_box">
<label for="right" class="label">권한</label>
<select name="" id="right">
<option value="전체">전체</option>
<option value="대리점">대리점</option>
<option value="운영자">운영자</option>
</select>
</div>
<div class="select_box">
<label for="right" class="label">상태</label>
<select name="" id="right">
<option value="전체">전체</option>
<option value="사용">사용</option>
<option value="중지">중지</option>
</select>
</div>
<div class="input_box id">
<label for="id1" class="label">ID</label>
<input type="text" id="id1" placeholder="검색어 입력"/>
</div>
<div class="input_box">
<label for="name" class="label">이름(대리점명)</label>
<input type="text" id="name" placeholder="검색어 입력"/>
</div>
<button type="button" class="button grey">조회</button>
</div>
</form>
<div class="info">
<div class="count"> <span>100</span></div>
<div class="button_group">
<button type="button" class="button blue admin">관리자 등록</button>
<button type="button" class="button blue channel">유지채널 등록</button>
<button type="button" class="button white delete">삭제</button>
</div>
</div>
<!-- <div class="table">
<table>
<colgroup>
<col width="5%"/>
<col width="15%"/>
<col width="15%"/>
<col width="20%"/>
<col width="20%"/>
<col width="5%"/>
<col width="20%"/>
</colgroup>
<thead>
<tr>
<th><input type="checkbox" id="admin_check1"><label for="admin_check1"></label></th>
<th>NO</th>
<th>권한</th>
<th>이름(대리점명)</th>
<th>ID</th>
<th>상태</th>
<th>등록일</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" checked id="admin_check2"><label for="admin_check2"></label></td>
<td>10</td>
<td>대리점</td>
<td>유플러스</td>
<td><a href="javascript:void(0)">uplus1</a></td>
<td>사용</td>
<td>2022-03-10</td>
</tr>
</tbody>
</table>
</div> -->
<div class="table">
<custom-grid
ref="table"
:totalItems="'totalItems'"
:url="testList.url"
:perPage="testList.perPage"
:initialRequest="testList.initialRequest"
:pagination="testList.pagination"
:isCheckbox="testList.isCheckbox"
:columns="testList.columns"
:noDataStr="testList.noDataStr"
:addCls="testList.addCls"
:header="testList.header"
></custom-grid>
</div>
</div>
</div>
</template>
<script>
import customGrid from '@/components/CustomGrid';
//import api from '../service/api';
export default {
name: 'calcList',
data() {
return {
testList: {
url: '/api/v1/bo/sysMgt/adminList',
perPage: 20,
pagination: true,
isCheckbox: true,
initialRequest: false,
addCls: 'box_OFvis',
header: [
[
{ header: 'NO', childNames: [] },
{ header: '권한', childNames: [] },
{ header: '이름(대리점명)', childNames: [] },
{ header: 'ID', childNames: [] },
{ header: '상태', childNames: [] },
{ header: '등록일', childNames: [] }
]
],
columns: [
{ name: 'no', header: 'NO', align: 'center', width: 60 },
{ name: 'auth', header: '권한', align: 'left', width: 160 },
{ name: 'name', header: '이름(대리점명)', align: 'center', width: 130},
{ name: 'adminId', header: 'ID', align: 'center', width: 130},
{ name: 'adminStat', header: '상태', align: 'center', width: 130},
{ name: 'regDt', header: '등록일', width: 90, cls: 'td_line' }
],
noDataStr: '검색 결과가 없습니다.',
// params: {
// apprResult: '',
// searchType: '',
// searchText: '',
// startDate: '',
// endDate: ''
// },
excelHeader: []
}
};
},
components: {
customGrid: customGrid
},
destroyed() {
},
mounted() {
let isKeep = false;
isKeep = true;
this.search(isKeep);
},
methods: {
search: function(isKeep) {
console.log(this.testList.params);
this.$refs.table.search(this.testList.params, isKeep);
},
}
};
</script>

View File

@@ -0,0 +1,12 @@
import TmpltList from '../views/TmpltList'
export default [
{
path: '/channelMgt/tmpltList',
component: TmpltList,
name: 'tmpltList',
meta: { public: true }
},
]

View File

@@ -0,0 +1,165 @@
<template>
<div class="contents">
<div class="contents_wrap">
<div class="top_wrap">
<h3 class="title">알림톡 템플릿 목록 조회</h3>
<p class="breadcrumb">시스템관리 &gt; 관리자/유치채널 관리</p>
</div>
<form autocomplete="off" class="search_form">
<div class="search_wrap">
<div class="select_box">
<label for="right" class="label">권한</label>
<select name="" id="right">
<option value="전체">전체</option>
<option value="대리점">대리점</option>
<option value="운영자">운영자</option>
</select>
</div>
<div class="select_box">
<label for="right" class="label">상태</label>
<select name="" id="right">
<option value="전체">전체</option>
<option value="사용">사용</option>
<option value="중지">중지</option>
</select>
</div>
<div class="input_box id">
<label for="id1" class="label">ID</label>
<input type="text" id="id1" placeholder="검색어 입력"/>
</div>
<div class="input_box">
<label for="name" class="label">이름(대리점명)</label>
<input type="text" id="name" placeholder="검색어 입력"/>
</div>
<button type="button" class="button grey">조회</button>
</div>
</form>
<div class="info">
<div class="count"> <span>100</span></div>
<div class="button_group">
<button type="button" class="button blue admin">관리자 등록</button>
<button type="button" class="button blue channel">유지채널 등록</button>
<button type="button" class="button white delete">삭제</button>
</div>
</div>
<!-- <div class="table">
<table>
<colgroup>
<col width="5%"/>
<col width="15%"/>
<col width="15%"/>
<col width="20%"/>
<col width="20%"/>
<col width="5%"/>
<col width="20%"/>
</colgroup>
<thead>
<tr>
<th><input type="checkbox" id="admin_check1"><label for="admin_check1"></label></th>
<th>NO</th>
<th>권한</th>
<th>이름(대리점명)</th>
<th>ID</th>
<th>상태</th>
<th>등록일</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" checked id="admin_check2"><label for="admin_check2"></label></td>
<td>10</td>
<td>대리점</td>
<td>유플러스</td>
<td><a href="javascript:void(0)">uplus1</a></td>
<td>사용</td>
<td>2022-03-10</td>
</tr>
</tbody>
</table>
</div> -->
<div class="table">
<custom-grid
ref="table"
:totalItems="'totalItems'"
:url="testList.url"
:perPage="testList.perPage"
:initialRequest="testList.initialRequest"
:pagination="testList.pagination"
:isCheckbox="testList.isCheckbox"
:columns="testList.columns"
:noDataStr="testList.noDataStr"
:addCls="testList.addCls"
:header="testList.header"
></custom-grid>
</div>
</div>
</div>
</template>
<script>
import customGrid from '@/components/CustomGrid';
//import api from '../service/api';
export default {
name: 'temltList',
data() {
return {
testList: {
url: '/api/v1/bo/sysMgt/adminList',
perPage: 20,
pagination: true,
isCheckbox: true,
initialRequest: false,
addCls: 'box_OFvis',
header: [
[
{ header: 'NO', childNames: [] },
{ header: '권한', childNames: [] },
{ header: '이름(대리점명)', childNames: [] },
{ header: 'ID', childNames: [] },
{ header: '상태', childNames: [] },
{ header: '등록일', childNames: [] }
]
],
columns: [
{ name: 'no', header: 'NO', align: 'center', width: 60 },
{ name: 'auth', header: '권한', align: 'left', width: 160 },
{ name: 'name', header: '이름(대리점명)', align: 'center', width: 130},
{ name: 'adminId', header: 'ID', align: 'center', width: 130},
{ name: 'adminStat', header: '상태', align: 'center', width: 130},
{ name: 'regDt', header: '등록일', width: 90, cls: 'td_line' }
],
noDataStr: '검색 결과가 없습니다.',
// params: {
// apprResult: '',
// searchType: '',
// searchText: '',
// startDate: '',
// endDate: ''
// },
excelHeader: []
}
};
},
components: {
customGrid: customGrid
},
destroyed() {
},
mounted() {
let isKeep = false;
isKeep = true;
this.search(isKeep);
},
methods: {
search: function(isKeep) {
console.log(this.testList.params);
this.$refs.table.search(this.testList.params, isKeep);
},
}
};
</script>

View File

@@ -0,0 +1,33 @@
import CustList from '../views/CustList'
import MemberList from '../views/MemberList'
import SubsDetail from '../views/SubsDetail'
import MemberDetail from '../views/MemberDetail'
export default [
{
path: '/custMgt/subsList',
component: CustList,
name: 'subsList',
meta: { public: true }
},
{
path: '/custMgt/memberList',
component: MemberList,
name: 'memberList',
meta: { public: true }
},
{
path: '/custMgt/subsDetail',
component: SubsDetail,
name: 'subsDetail',
meta: { public: true }
},
{
path: '/custMgt/memberDetail',
component: MemberDetail,
name: 'memberDetail',
meta: { public: true }
},
]

Some files were not shown because too many files have changed in this diff Show More