hubez-admin partner-git master -> hubez-git transfer 202205241800
3
frontend/.babelrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env"]
|
||||
}
|
||||
2
frontend/.browserslistrc
Normal file
@@ -0,0 +1,2 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
1
frontend/.env
Normal file
@@ -0,0 +1 @@
|
||||
VUE_APP_TEST_PROP=local env value
|
||||
4
frontend/.env.dev
Normal 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
@@ -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
@@ -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
@@ -0,0 +1 @@
|
||||
/npm-v6.10.0/
|
||||
7
frontend/.prettierrc.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
// tabWidth: 4,
|
||||
// useTabs: true,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
printWidth: 120
|
||||
}
|
||||
34
frontend/README.md
Normal 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
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
]
|
||||
}
|
||||
30
frontend/jest.config.js
Normal 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
49
frontend/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
5
frontend/postcss.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
BIN
frontend/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
16
frontend/public/index.html
Normal 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
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<router-view/>
|
||||
</template>
|
||||
72
frontend/src/assets/css/common.css
Normal 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;
|
||||
}
|
||||
71
frontend/src/assets/css/contents.css
Normal 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;}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
109
frontend/src/assets/css/layout.css
Normal 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;}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
977
frontend/src/assets/css/style.css
Normal 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 */
|
||||
BIN
frontend/src/assets/font/SpoqaHanSansNeo-Bold.woff
Normal file
BIN
frontend/src/assets/font/SpoqaHanSansNeo-Light.woff
Normal file
BIN
frontend/src/assets/font/SpoqaHanSansNeo-Medium.woff
Normal file
BIN
frontend/src/assets/font/SpoqaHanSansNeo-Regular.woff
Normal file
BIN
frontend/src/assets/font/SpoqaHanSansNeo-Thin.woff
Normal file
BIN
frontend/src/assets/images/admin-logo.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
frontend/src/assets/images/arrow-down.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
frontend/src/assets/images/arrow-white.png
Normal file
|
After Width: | Height: | Size: 1012 B |
BIN
frontend/src/assets/images/flogo.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
frontend/src/assets/images/icon-attract-on.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
frontend/src/assets/images/icon-attract.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/src/assets/images/icon-calculate-on.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/src/assets/images/icon-calculate.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/src/assets/images/icon-channel-on.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/src/assets/images/icon-channel.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
frontend/src/assets/images/icon-chk-n-square.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/src/assets/images/icon-chk-n.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/src/assets/images/icon-chk-square.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/src/assets/images/icon-chk.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
frontend/src/assets/images/icon-close.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
frontend/src/assets/images/icon-customer-on.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/src/assets/images/icon-customer.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/src/assets/images/icon-key-on.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/src/assets/images/icon-key.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/src/assets/images/icon-lock.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/src/assets/images/icon-moniter-on.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
frontend/src/assets/images/icon-moniter.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
frontend/src/assets/images/icon-radio-chk.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/src/assets/images/icon-radio.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
frontend/src/assets/images/icon-risk-on.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/src/assets/images/icon-risk.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/src/assets/images/icon-search.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/src/assets/images/icon-select-down.png
Normal file
|
After Width: | Height: | Size: 237 B |
BIN
frontend/src/assets/images/icon-service-on.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/src/assets/images/icon-service.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/src/assets/images/icon-stats-on.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/src/assets/images/icon-stats.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/src/assets/images/icon-system-on.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/src/assets/images/icon-system.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/src/assets/images/login-bg.jpg
Normal file
|
After Width: | Height: | Size: 408 KiB |
BIN
frontend/src/assets/images/logo.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
frontend/src/assets/images/user-bg.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
frontend/src/assets/images/user-icon.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
66
frontend/src/assets/js/script.js
Normal 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
|
||||
}
|
||||
BIN
frontend/src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
9
frontend/src/common/comm-api.js
Normal 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
|
||||
}
|
||||
10
frontend/src/common/config.js
Normal 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 };
|
||||
143
frontend/src/common/excel.js
Normal 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;
|
||||
105
frontend/src/common/http-client.js
Normal 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;
|
||||
1
frontend/src/common/ko.js
Normal 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});
|
||||
38
frontend/src/common/token-service.js
Normal 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;
|
||||
117
frontend/src/common/utils.js
Normal 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';
|
||||
}
|
||||
};
|
||||
228
frontend/src/common/vue-mixins.js
Normal 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 };
|
||||
45
frontend/src/components/ButtonBranch.vue
Normal 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>
|
||||
199
frontend/src/components/CreateBrandViewer.vue
Normal 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>
|
||||
679
frontend/src/components/CustomGrid.vue
Normal 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>
|
||||
139
frontend/src/components/Datepicker.vue
Normal 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;
|
||||
}
|
||||
25
frontend/src/components/HubWebFooter.vue
Normal 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>
|
||||
87
frontend/src/components/HubWebHeader.vue
Normal 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>
|
||||
56
frontend/src/components/Lnb.vue
Normal 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>
|
||||
307
frontend/src/components/LoginPopup.vue
Normal 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>
|
||||
132
frontend/src/components/NavBar.vue
Normal 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>
|
||||
133
frontend/src/components/Pagination.vue
Normal 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>
|
||||
391
frontend/src/components/SystemPopup.vue
Normal 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>
|
||||
61
frontend/src/components/TreeMenu.vue
Normal 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>
|
||||
293
frontend/src/components/TuiGrid.vue
Normal 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>
|
||||
27
frontend/src/components/TuiGridPerPage.vue
Normal 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>
|
||||
116
frontend/src/components/TuiGridSample_it_will_be_delete.vue
Normal 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>
|
||||
235
frontend/src/components/address/AddressCustomPopup.vue
Normal 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>
|
||||
332
frontend/src/components/address/index.vue
Normal 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>
|
||||
1
frontend/src/components/vuejs-datepicker.js
Normal file
19
frontend/src/main.js
Normal 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')
|
||||
|
||||
11
frontend/src/modules/attractMgt/router/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import ChannelList from '../views/ChannelList'
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/attractMgt/channelList',
|
||||
component: ChannelList,
|
||||
name: 'channelList',
|
||||
meta: { public: true }
|
||||
}
|
||||
]
|
||||
|
||||
107
frontend/src/modules/attractMgt/views/ChannelList.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div class="contents">
|
||||
<div class="contents_wrap">
|
||||
<div class="top_wrap">
|
||||
<h3 class="title">유치채널 목록조회</h3>
|
||||
<p class="breadcrumb">시스템관리 > 권한 관리</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>
|
||||
12
frontend/src/modules/calculate/router/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import CalcList from '../views/CalcList'
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/calculate/calcList',
|
||||
component: CalcList,
|
||||
name: 'calcList',
|
||||
meta: { public: true }
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
165
frontend/src/modules/calculate/views/CalcList.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
|
||||
<div class="contents">
|
||||
<div class="contents_wrap">
|
||||
<div class="top_wrap">
|
||||
<h3 class="title">정산이력목록조회</h3>
|
||||
<p class="breadcrumb">시스템관리 > 관리자/유치채널 관리</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>
|
||||
12
frontend/src/modules/channelMgt/router/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import TmpltList from '../views/TmpltList'
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/channelMgt/tmpltList',
|
||||
component: TmpltList,
|
||||
name: 'tmpltList',
|
||||
meta: { public: true }
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
165
frontend/src/modules/channelMgt/views/TmpltList.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
|
||||
<div class="contents">
|
||||
<div class="contents_wrap">
|
||||
<div class="top_wrap">
|
||||
<h3 class="title">알림톡 템플릿 목록 조회</h3>
|
||||
<p class="breadcrumb">시스템관리 > 관리자/유치채널 관리</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>
|
||||
33
frontend/src/modules/custMgt/router/index.js
Normal 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 }
|
||||
},
|
||||
|
||||
]
|
||||
|
||||