sk_fems_ui commit
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
34
.eslintrc.js
Normal file
@ -0,0 +1,34 @@
|
||||
// .eslintrc.js
|
||||
module.exports = {
|
||||
// 현재 eslintrc 파일을 기준으로 ESLint 규칙을 적용
|
||||
root: true,
|
||||
// 추가적인 규칙들을 적용
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:vue/essential',
|
||||
'prettier',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
// 코드 정리 플러그인 추가
|
||||
plugins: ['prettier'],
|
||||
// 사용자 편의 규칙 추가
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
// 아래 규칙들은 개인 선호에 따라 prettier 문법 적용
|
||||
// https://prettier.io/docs/en/options.html
|
||||
{
|
||||
singleQuote: true,
|
||||
semi: true,
|
||||
useTabs: true,
|
||||
tabWidth: 2,
|
||||
trailingComma: 'all',
|
||||
printWidth: 80,
|
||||
bracketSpacing: true,
|
||||
arrowParens: 'avoid',
|
||||
endOfLine: 'auto',
|
||||
},
|
||||
],
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
},
|
||||
};
|
90
.gitignore
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
# Logs
|
||||
/logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# Nuxt generate
|
||||
dist
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# IDE / Editor
|
||||
.idea
|
||||
|
||||
# Service worker
|
||||
sw.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Vim swap files
|
||||
*.swp
|
63
.gitlab-ci.yml
Normal file
@ -0,0 +1,63 @@
|
||||
image: docker:19.03.7
|
||||
|
||||
services:
|
||||
- docker:19.03.7-dind
|
||||
|
||||
stages:
|
||||
- install
|
||||
- build_docker_image
|
||||
- build_docker_clear
|
||||
cache:
|
||||
paths:
|
||||
- node_modules/
|
||||
|
||||
before_script:
|
||||
- node -v
|
||||
- npm install
|
||||
|
||||
install_dependencies:
|
||||
image: node:14.19.3
|
||||
stage: install
|
||||
only:
|
||||
- main
|
||||
tags:
|
||||
- test
|
||||
script:
|
||||
- echo "=====node install start====="
|
||||
- pwd
|
||||
- npm ci
|
||||
- npm run build
|
||||
- echo "=====node install end ====="
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules/
|
||||
|
||||
docker-build-main:
|
||||
variables:
|
||||
# do not clone again
|
||||
GIT_STRATEGY: none
|
||||
stage: build_docker_image
|
||||
only:
|
||||
- main
|
||||
tags:
|
||||
- test
|
||||
script:
|
||||
# make docker image and push to local docker
|
||||
- echo "=====node build_docker_image start====="
|
||||
- sudo docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
- sudo docker build -t $CI_REGISTRY/root/registry/skfems/ui .
|
||||
- sudo docker push $CI_REGISTRY/root/registry/skfems/ui
|
||||
- sudo docker rmi $CI_REGISTRY/root/registry/skfems/ui
|
||||
- echo "=====node build_docker_image end====="
|
||||
|
||||
clear-files:
|
||||
stage: build_docker_clear
|
||||
only:
|
||||
- main
|
||||
tags:
|
||||
- test
|
||||
script:
|
||||
# 빌드 완료후 빌드시 Root 계정으로 생성된 자료 클리어 처리(아래 부분을 수행 안하면, 다음번 파이브라인 처리시 권한 문제로 수행 안됨)
|
||||
- sudo rm -rf .nuxt
|
||||
- sudo rm -rf dist
|
||||
- sudo rm -rf node_modules
|
17
.project
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>sk_fems_ui</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
7
.settings/.jsdtscope
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
|
||||
<classpathentry kind="src" path=""/>
|
||||
<classpathentry kind="output" path=""/>
|
||||
</classpath>
|
1
.settings/org.eclipse.wst.jsdt.ui.superType.container
Normal file
@ -0,0 +1 @@
|
||||
org.eclipse.wst.jsdt.launching.JRE_CONTAINER
|
1
.settings/org.eclipse.wst.jsdt.ui.superType.name
Normal file
@ -0,0 +1 @@
|
||||
Global
|
14
Dockerfile
Normal file
@ -0,0 +1,14 @@
|
||||
# Package stage
|
||||
FROM node:14-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD dist/ /app/dist/
|
||||
|
||||
RUN npm install -g serve
|
||||
|
||||
#ENV HOST 0.0.0.0
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["serve", "-s", "dist", "-p", "3000"]
|
21
Dockerfile.comm
Normal file
@ -0,0 +1,21 @@
|
||||
# Package stage
|
||||
FROM node:14-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD dist/_nuxt/ /app/dist/_nuxt/
|
||||
ADD dist/comm/ /app/dist/comm/
|
||||
ADD dist/login/ /app/dist/login/
|
||||
COPY dist/*.html /app/dist/
|
||||
COPY dist/*.ico /app/dist/
|
||||
COPY dist/*.png /app/dist/
|
||||
COPY dist/*.svg /app/dist/
|
||||
COPY dist/.* /app/dist/
|
||||
|
||||
RUN npm install -g serve
|
||||
|
||||
#ENV HOST 0.0.0.0
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["serve", "-s", "dist", "-p", "3000"]
|
21
Dockerfile.comm.auth
Normal file
@ -0,0 +1,21 @@
|
||||
# Package stage
|
||||
FROM node:14-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD dist/_nuxt/ /app/dist/_nuxt/
|
||||
ADD dist/comm/auth/ /app/dist/comm/auth/
|
||||
ADD dist/login/ /app/dist/login/
|
||||
COPY dist/*.html /app/dist/
|
||||
COPY dist/*.ico /app/dist/
|
||||
COPY dist/*.png /app/dist/
|
||||
COPY dist/*.svg /app/dist/
|
||||
COPY dist/.* /app/dist/
|
||||
|
||||
RUN npm install -g serve
|
||||
|
||||
#ENV HOST 0.0.0.0
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["serve", "-s", "dist", "-p", "3000"]
|
21
Dockerfile.comm.base
Normal file
@ -0,0 +1,21 @@
|
||||
# Package stage
|
||||
FROM node:14-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD dist/_nuxt/ /app/dist/_nuxt/
|
||||
ADD dist/comm/base/ /app/dist/comm/base/
|
||||
ADD dist/login/ /app/dist/login/
|
||||
COPY dist/*.html /app/dist/
|
||||
COPY dist/*.ico /app/dist/
|
||||
COPY dist/*.png /app/dist/
|
||||
COPY dist/*.svg /app/dist/
|
||||
COPY dist/.* /app/dist/
|
||||
|
||||
RUN npm install -g serve
|
||||
|
||||
#ENV HOST 0.0.0.0
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["serve", "-s", "dist", "-p", "3000"]
|
21
Dockerfile.ems
Normal file
@ -0,0 +1,21 @@
|
||||
# Package stage
|
||||
FROM node:14-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD dist/_nuxt/ /app/dist/_nuxt/
|
||||
ADD dist/ems/ /app/dist/ems/
|
||||
ADD dist/login/ /app/dist/login/
|
||||
COPY dist/*.html /app/dist/
|
||||
COPY dist/*.ico /app/dist/
|
||||
COPY dist/*.png /app/dist/
|
||||
COPY dist/*.svg /app/dist/
|
||||
COPY dist/.* /app/dist/
|
||||
|
||||
RUN npm install -g serve
|
||||
|
||||
#ENV HOST 0.0.0.0
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["serve", "-s", "dist", "-p", "3000"]
|
21
Dockerfile.ems.base
Normal file
@ -0,0 +1,21 @@
|
||||
# Package stage
|
||||
FROM node:14-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD dist/_nuxt/ /app/dist/_nuxt/
|
||||
ADD dist/ems/base/ /app/dist/ems/base/
|
||||
ADD dist/login/ /app/dist/login/
|
||||
COPY dist/*.html /app/dist/
|
||||
COPY dist/*.ico /app/dist/
|
||||
COPY dist/*.png /app/dist/
|
||||
COPY dist/*.svg /app/dist/
|
||||
COPY dist/.* /app/dist/
|
||||
|
||||
RUN npm install -g serve
|
||||
|
||||
#ENV HOST 0.0.0.0
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["serve", "-s", "dist", "-p", "3000"]
|
21
Dockerfile.ems.fopm
Normal file
@ -0,0 +1,21 @@
|
||||
# Package stage
|
||||
FROM node:14-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD dist/_nuxt/ /app/dist/_nuxt/
|
||||
ADD dist/ems/fopm/ /app/dist/ems/fopm/
|
||||
ADD dist/login/ /app/dist/login/
|
||||
COPY dist/*.html /app/dist/
|
||||
COPY dist/*.ico /app/dist/
|
||||
COPY dist/*.png /app/dist/
|
||||
COPY dist/*.svg /app/dist/
|
||||
COPY dist/.* /app/dist/
|
||||
|
||||
RUN npm install -g serve
|
||||
|
||||
#ENV HOST 0.0.0.0
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["serve", "-s", "dist", "-p", "3000"]
|
42
README.md
Normal file
@ -0,0 +1,42 @@
|
||||
# FEMS
|
||||
|
||||
## Build Setup
|
||||
|
||||
```bash
|
||||
# install dependencies
|
||||
$ npm install
|
||||
|
||||
# serve with hot reload at localhost:3000
|
||||
$ npm run dev
|
||||
|
||||
# build for production and launch server
|
||||
$ npm run build
|
||||
$ npm run start
|
||||
|
||||
# generate static project
|
||||
$ npm run generate
|
||||
```
|
||||
|
||||
For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org).
|
||||
|
||||
# VSCode && ESLint Prettier 적용 settings.json 옵션 추가
|
||||
"editor.formatOnSave": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"eslint.alwaysShowStatus": true,
|
||||
"eslint.workingDirectories": [
|
||||
{"mode": "auto"}
|
||||
],
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"typescript"
|
||||
],
|
||||
|
||||
# 프로젝트 install 후 기동시 버전 mismatch 일때
|
||||
vue-server-renderer, vue-template-compiler 를 현재 vue 버전에 맞게 수동 인스톨
|
||||
Ex) npm install vue-server-renderer@2.6.14
|
||||
Ex) npm install vue-template-compiler@2.6.14
|
||||
|
||||
# 프로젝트 Clean 작업
|
||||
rm package-lock.json; rm .nuxt; rm node_modules;
|
7
assets/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# ASSETS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains your un-compiled assets such as LESS, SASS, or JavaScript.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked).
|
46
assets/css/SpoqaHanSansNeo.css
Normal file
@ -0,0 +1,46 @@
|
||||
@font-face {
|
||||
font-family: 'Spoqa Han Sans Neo';
|
||||
font-weight: 700;
|
||||
src: local('Spoqa Han Sans Neo Bold'),
|
||||
url('../font/SpoqaHanSansNeo-Bold.woff2') format('woff2'),
|
||||
url('../font/SpoqaHanSansNeo-Bold.woff') format('woff'),
|
||||
url('../font/SpoqaHanSansNeo-Bold.ttf') format('truetype');
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'Spoqa Han Sans Neo';
|
||||
font-weight: 500;
|
||||
src: local('Spoqa Han Sans Neo Medium'),
|
||||
url('../font/SpoqaHanSansNeo-Medium.woff2') format('woff2'),
|
||||
url('../font/SpoqaHanSansNeo-Medium.woff') format('woff'),
|
||||
url('../font/SpoqaHanSansNeo-Medium.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Spoqa Han Sans Neo';
|
||||
font-weight: 400;
|
||||
src: local('Spoqa Han Sans Neo Regular'),
|
||||
url('../font/SpoqaHanSansNeo-Regular.woff2') format('woff2'),
|
||||
url('../font/SpoqaHanSansNeo-Regular.woff') format('woff'),
|
||||
url('../font/SpoqaHanSansNeo-Regular.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Spoqa Han Sans Neo';
|
||||
font-weight: 300;
|
||||
src: local('Spoqa Han Sans Neo Light'),
|
||||
url('../font/SpoqaHanSansNeo-Light.woff2') format('woff2'),
|
||||
url('../font/SpoqaHanSansNeo-Light.woff') format('woff'),
|
||||
url('../font/SpoqaHanSansNeo-Light.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Spoqa Han Sans Neo';
|
||||
font-weight: 100;
|
||||
src: local('Spoqa Han Sans Neo Thin'),
|
||||
url('../font/SpoqaHanSansNeo-Thin.woff2') format('woff2'),
|
||||
url('../font/SpoqaHanSansNeo-Thin.woff') format('woff'),
|
||||
url('../font/SpoqaHanSansNeo-Thin.ttf') format('truetype');
|
||||
}
|
||||
|
BIN
assets/font/SpoqaHanSansNeo-Bold.eot
Normal file
BIN
assets/font/SpoqaHanSansNeo-Bold.ttf
Normal file
BIN
assets/font/SpoqaHanSansNeo-Bold.woff
Normal file
BIN
assets/font/SpoqaHanSansNeo-Bold.woff2
Normal file
BIN
assets/font/SpoqaHanSansNeo-Light.eot
Normal file
BIN
assets/font/SpoqaHanSansNeo-Light.ttf
Normal file
BIN
assets/font/SpoqaHanSansNeo-Light.woff
Normal file
BIN
assets/font/SpoqaHanSansNeo-Light.woff2
Normal file
BIN
assets/font/SpoqaHanSansNeo-Medium.eot
Normal file
BIN
assets/font/SpoqaHanSansNeo-Medium.ttf
Normal file
BIN
assets/font/SpoqaHanSansNeo-Medium.woff
Normal file
BIN
assets/font/SpoqaHanSansNeo-Medium.woff2
Normal file
BIN
assets/font/SpoqaHanSansNeo-Regular.eot
Normal file
BIN
assets/font/SpoqaHanSansNeo-Regular.ttf
Normal file
BIN
assets/font/SpoqaHanSansNeo-Regular.woff
Normal file
BIN
assets/font/SpoqaHanSansNeo-Regular.woff2
Normal file
BIN
assets/font/SpoqaHanSansNeo-Thin.eot
Normal file
BIN
assets/font/SpoqaHanSansNeo-Thin.ttf
Normal file
BIN
assets/font/SpoqaHanSansNeo-Thin.woff
Normal file
BIN
assets/font/SpoqaHanSansNeo-Thin.woff2
Normal file
BIN
assets/images/ico_grid_list.png
Normal file
After Width: | Height: | Size: 157 B |
BIN
assets/images/ico_grid_list_active.png
Normal file
After Width: | Height: | Size: 159 B |
BIN
assets/images/ico_grid_open.png
Normal file
After Width: | Height: | Size: 149 B |
BIN
assets/images/ico_grid_open_active.png
Normal file
After Width: | Height: | Size: 152 B |
BIN
assets/images/icon/ico-cal-month.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/icon/ico-cal-month_before.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/images/icon/ico-cal-year.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/icon/ico-enrgMap.png
Normal file
After Width: | Height: | Size: 796 B |
BIN
assets/images/icon/ico-theme-dark.png
Normal file
After Width: | Height: | Size: 359 B |
BIN
assets/images/icon/ico-theme-light.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
assets/images/login_dm.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/images/login_lm.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/images/logo_dm.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
assets/images/logo_lm.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
assets/images/temp/DataSetMngPage.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
assets/images/temp/EnrgEffcEqpmDetlMntrPage.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
assets/images/temp/EnrgEffcTotSummPage.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
assets/images/temp/EnrgMapPage.png
Normal file
After Width: | Height: | Size: 361 KiB |
BIN
assets/images/temp/EnrgReptMngPage.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
assets/images/temp/EnrgUseEqpmDetlMntrPage.png
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
assets/images/temp/EnrgUsePalnPage.png
Normal file
After Width: | Height: | Size: 114 KiB |
BIN
assets/images/temp/EnrgUseTotSummPage.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
assets/images/temp/EqpmIndMntrPage.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
assets/images/temp/TagTrndPage.png
Normal file
After Width: | Height: | Size: 114 KiB |
1314
assets/scss/common.scss
Normal file
75
assets/scss/common/button.scss
Normal file
@ -0,0 +1,75 @@
|
||||
.v-btn {
|
||||
background-color: #144985;
|
||||
&-radius {
|
||||
&__20 {
|
||||
border-radius: 20px !important;
|
||||
}
|
||||
&__50per {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
}
|
||||
&__full {
|
||||
width: 100%;
|
||||
}
|
||||
&__round {
|
||||
min-width: 100px !important;
|
||||
padding: 8px 25px !important;
|
||||
border-radius: 20px !important;
|
||||
}
|
||||
&__excel {
|
||||
background-color: #47535c !important;
|
||||
}
|
||||
&-bg {
|
||||
&__transparent {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
&__blue {
|
||||
background-color: $--color-primary__blue;
|
||||
}
|
||||
&__white-blue {
|
||||
background-color: $--color-white;
|
||||
color: $--color-primary__blue;
|
||||
}
|
||||
}
|
||||
&__transparent {
|
||||
border: 0;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
&.v-btn--icon.v-btn--tile {
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@each $theme in dark, light {
|
||||
@include theme($theme);
|
||||
.v-application.#{$theme}-mode {
|
||||
.v-btn-bg__w-g5 {
|
||||
background-color: $--theme-color-w-g5;
|
||||
i {
|
||||
color: $--theme-color-g5-w;
|
||||
}
|
||||
}
|
||||
.v-btn {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-btn-backgroundColor"
|
||||
);
|
||||
color: map-deep-get($color, "white", "0");
|
||||
|
||||
&.v-btn--disabled {
|
||||
opacity: 0.4;
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-btn-backgroundColor"
|
||||
) !important;
|
||||
color: map-deep-get($color, "white", "0") !important;
|
||||
|
||||
.v-icon {
|
||||
color: map-deep-get($color, "white", "0") !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
assets/scss/common/card.scss
Normal file
@ -0,0 +1,15 @@
|
||||
.v-card {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@each $theme in dark, light {
|
||||
// @include theme($theme);
|
||||
.v-application.#{$theme}-mode {
|
||||
.v-card {
|
||||
color: map-deep-get($config, #{$theme}, "card-default-color");
|
||||
.v-card__subtitle {
|
||||
color: map-deep-get($config, #{$theme}, "card-subtitle");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
assets/scss/common/fonts.scss
Normal file
@ -0,0 +1,52 @@
|
||||
.ft {
|
||||
&-size {
|
||||
&_12 { font-size: 12px !important; }
|
||||
&_13 { font-size: 13px !important; }
|
||||
&_14 { font-size: 14px !important; }
|
||||
&_15 { font-size: 15px !important; }
|
||||
&_16 { font-size: 16px !important; }
|
||||
&_20 { font-size: 20px !important; }
|
||||
&_24 { font-size: 24px !important; }
|
||||
&_32 { font-size: 32px !important; }
|
||||
&_40 { font-size: 40px !important; }
|
||||
}
|
||||
&-wt {
|
||||
&_100 { font-weight: 100; }
|
||||
&_200 { font-weight: 200; }
|
||||
&_300 { font-weight: 300; }
|
||||
&_400 { font-weight: 400; }
|
||||
&_500 { font-weight: 500; }
|
||||
&_600 { font-weight: 600; }
|
||||
&_700 { font-weight: 700; }
|
||||
&_800 { font-weight: 800; }
|
||||
&_900 { font-weight: 900; }
|
||||
}
|
||||
|
||||
&-clr {
|
||||
&_g-9 { color: $--color-gray_9; }
|
||||
&_g-7 { color: $--color-gray_7; }
|
||||
&_g-c { color: $--color-gray_C; }
|
||||
&_g-555 { color: $--color-gray_555 }
|
||||
&_g-999 { color: $--color-gray_999; }
|
||||
&_g-aaa { color: $--color-gray_aaa; }
|
||||
&_blue { color: $--color-primary__blue; }
|
||||
&_green { color: $--color-primary__green; }
|
||||
&_yellow { color: $--color-sub__yellow; }
|
||||
&_red { color: $--color-warning__red; }
|
||||
}
|
||||
}
|
||||
|
||||
@each $theme in dark, light{
|
||||
@include theme($theme);
|
||||
.v-application.#{$theme}-mode{
|
||||
color: $--theme-color-w-g5;
|
||||
.ft {
|
||||
&-clr {
|
||||
&_gc-g9 { color: $--theme-color-gc-g9; }
|
||||
&_g5-gc { color: $--theme-color-g5-gc; }
|
||||
&_g7-g9 { color: $--theme-color-g7-g9; }
|
||||
&_g9-g7 { color: $--theme-color-g9-g7; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
376
assets/scss/common/grid.scss
Normal file
@ -0,0 +1,376 @@
|
||||
.tui-grid {
|
||||
&-layer-state {
|
||||
z-index: 5 !important;
|
||||
}
|
||||
|
||||
// &-layer-selection {
|
||||
// width: calc(100% - 2px) !important;
|
||||
// }
|
||||
|
||||
&-container {
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
&-content-area {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
// &-body-container {
|
||||
// width: 100% !important;
|
||||
// }
|
||||
|
||||
// &-table {
|
||||
// width: 100% !important;
|
||||
// }
|
||||
|
||||
// &-lside-area .tui-grid-body-area {
|
||||
// margin-right: -11px;
|
||||
// }
|
||||
|
||||
&-lside-area .tui-grid-scrollbar-left-bottom {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-rside-area {
|
||||
.tui-grid-header-area,
|
||||
.tui-grid-summary-area {
|
||||
margin-right: $scrollbar-width;
|
||||
}
|
||||
}
|
||||
|
||||
&-border-line-top,
|
||||
&-border-line-bottom,
|
||||
&-border-line-right {
|
||||
border: 0 !important;
|
||||
}
|
||||
&-cell {
|
||||
border-width: 1px !important;
|
||||
}
|
||||
&-cell-header {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
&-cell-header,
|
||||
&-cell-content,
|
||||
&-cell.tui-grid-cell-summary {
|
||||
font-family: "Spoqa Han Sans Neo";
|
||||
font-size: 0.875rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem;
|
||||
letter-spacing: 0.0178571429em;
|
||||
}
|
||||
}
|
||||
.treeGrid {
|
||||
.tui-grid {
|
||||
&-header-area {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-cell {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tui-grid-scrollbar-right-top{
|
||||
z-index:5;
|
||||
}
|
||||
|
||||
@each $theme in dark, light {
|
||||
@include theme($theme);
|
||||
.v-application.#{$theme}-mode {
|
||||
.tui-grid {
|
||||
&-container,
|
||||
&-summary-area {
|
||||
& ::-webkit-scrollbar {
|
||||
width: $scrollbar-width !important;
|
||||
height: $scrollbar-width !important;
|
||||
-webkit-appearance: initial;
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"scrollbar-track"
|
||||
) !important;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
& ::-webkit-scrollbar-track {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"scrollbar-track"
|
||||
) !important;
|
||||
}
|
||||
|
||||
& ::-webkit-scrollbar-thumb {
|
||||
width: 50px !important;
|
||||
height: 50px !important;
|
||||
background-color: map-deep-get($config, #{$theme}, "scrollbar-thumb");
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&-rside-area {
|
||||
background-color: map-deep-get($config, #{$theme}, "scrollbar-track");
|
||||
}
|
||||
|
||||
&-scrollbar-left-bottom {
|
||||
background-color: map-deep-get($config, #{$theme}, "cardBackground");
|
||||
border-color: map-deep-get($config, #{$theme}, "cardBackground");
|
||||
}
|
||||
|
||||
&-scrollbar-right-top {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-header-backgroundColor"
|
||||
);
|
||||
border-left-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-border-horziontal-color"
|
||||
);
|
||||
border-right-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-border-horziontal-color"
|
||||
);
|
||||
border-bottom-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-border-vertical-color"
|
||||
);
|
||||
}
|
||||
|
||||
&-scrollbar-right-bottom {
|
||||
width: $scrollbar-width !important;
|
||||
height: $scrollbar-width !important;
|
||||
// display: none !important;
|
||||
border-color: map-deep-get($config, #{$theme}, "scrollbar-track");
|
||||
background-color: map-deep-get($config, #{$theme}, "scrollbar-track");
|
||||
// border: none !important;
|
||||
// bottom: -1px;
|
||||
// right: -2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&-scrollbar-frozen-border,
|
||||
&-scrollbar-y-outer-border,
|
||||
&-scrollbar-y-inner-border {
|
||||
background-color: transparent !important;
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
&-body-area {
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
&-container,
|
||||
&-layer-state,
|
||||
&-body-area,
|
||||
&-summary-area,
|
||||
&-cell {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-cell-backgroundColor"
|
||||
);
|
||||
border-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-border-vertical-color"
|
||||
);
|
||||
}
|
||||
|
||||
&-cell-summary {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-header-area,
|
||||
&-cell-header {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-header-backgroundColor"
|
||||
);
|
||||
border-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-border-vertical-color"
|
||||
);
|
||||
color: map-deep-get($config, #{$theme}, "activate");
|
||||
}
|
||||
|
||||
&-row-odd,
|
||||
&-row-even {
|
||||
.tui-grid-cell-content {
|
||||
color: map-deep-get($config, #{$theme}, "tui-grid-cell-color");
|
||||
}
|
||||
|
||||
&:hover {
|
||||
> .tui-grid-cell {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-cell-hover-backgroundColor"
|
||||
);
|
||||
|
||||
.tui-grid-cell-content {
|
||||
color: map-deep-get($config, #{$theme}, "activate");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-cell {
|
||||
&.row-insert {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-cell-insert-color"
|
||||
);
|
||||
}
|
||||
&.row-modify {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-cell-modify-color"
|
||||
);
|
||||
}
|
||||
&.row-removed {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-cell-removed-color"
|
||||
);
|
||||
}
|
||||
&.row-disabled {
|
||||
color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-cell-disabled-color"
|
||||
);
|
||||
|
||||
.tui-grid-cell-content {
|
||||
color: map-deep-get($config, #{$theme}, "tui-grid-cell-disabled-color");
|
||||
}
|
||||
}
|
||||
&.row-selected {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"tui-grid-cell-selected-color"
|
||||
);
|
||||
|
||||
.tui-grid-cell-content {
|
||||
color: map-deep-get($config, #{$theme}, "activate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-layer-focus-border {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&-cell-has-tree {
|
||||
.tui-grid-cell-content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-tree-extra-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
.tui-grid-tree-depth
|
||||
{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
left: 0 !important;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&-btn-tree {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 0;
|
||||
padding-left: 0;
|
||||
margin-right: 6px;
|
||||
top: 0;
|
||||
left: 0 !important;
|
||||
i {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-tree-icon {
|
||||
margin-top: 0;
|
||||
top: 0;
|
||||
i {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 0;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
@if $theme == dark {
|
||||
background-image: url("data:image/svg+xml,%3Csvg id='ico_tree_item' xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cdefs%3E%3Cstyle%3E .cls-1, .cls-4 %7B fill: none; %7D .cls-1 %7B stroke: %23fff; opacity: 0.3; %7D .cls-2 %7B fill: %23fff; %7D .cls-3 %7B stroke: none; %7D %3C/style%3E%3C/defs%3E%3Cg id='사각형_703' data-name='사각형 703' class='cls-1'%3E%3Crect class='cls-3' width='16' height='16' rx='3'/%3E%3Crect class='cls-4' x='0.5' y='0.5' width='15' height='15' rx='2.5'/%3E%3C/g%3E%3Crect id='사각형_1384' data-name='사각형 1384' class='cls-2' width='8' height='1' rx='0.5' transform='translate(4 4.5)'/%3E%3Crect id='사각형_1386' data-name='사각형 1386' class='cls-2' width='8' height='1' rx='0.5' transform='translate(4 7.5)'/%3E%3Crect id='사각형_1387' data-name='사각형 1387' class='cls-2' width='8' height='1' rx='0.5' transform='translate(4 10.5)'/%3E%3C/svg%3E%0A");
|
||||
} @else {
|
||||
background-image: url("data:image/svg+xml,%3Csvg id='ico_tree_item' xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cdefs%3E%3Cstyle%3E .cls-2%7Bfill:%23a4aac3%7D %3C/style%3E%3C/defs%3E%3Cg id='사각형_703' data-name='사각형 703' style='stroke:%23a4aac3;fill:none'%3E%3Crect width='16' height='16' rx='3' style='stroke:none'/%3E%3Crect x='.5' y='.5' width='15' height='15' rx='2.5' style='fill:none'/%3E%3C/g%3E%3Crect id='사각형_1384' data-name='사각형 1384' class='cls-2' width='8' height='1' rx='.5' transform='translate(4 4.5)'/%3E%3Crect id='사각형_1386' data-name='사각형 1386' class='cls-2' width='8' height='1' rx='.5' transform='translate(4 7.5)'/%3E%3Crect id='사각형_1387' data-name='사각형 1387' class='cls-2' width='8' height='1' rx='.5' transform='translate(4 10.5)'/%3E%3C/svg%3E%0A");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-tree-button-expand {
|
||||
.tui-grid-btn-tree {
|
||||
i {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-position: 0 0;
|
||||
@if $theme == dark {
|
||||
background-image: url("data:image/svg+xml,%3Csvg id='btn_tree_item_close' xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cdefs%3E%3Cstyle%3E .cls-1 %7B fill: %230d0f17; stroke: %23fff; opacity: 0.3; %7D .cls-2 %7B fill: %23fff; %7D .cls-3 %7B stroke: none; %7D .cls-4 %7B fill: none; %7D %3C/style%3E%3C/defs%3E%3Cg id='사각형_703' data-name='사각형 703' class='cls-1'%3E%3Crect class='cls-3' width='16' height='16' rx='3'/%3E%3Crect class='cls-4' x='0.5' y='0.5' width='15' height='15' rx='2.5'/%3E%3C/g%3E%3Crect id='사각형_1384' data-name='사각형 1384' class='cls-2' width='8' height='2' rx='1' transform='translate(4 7)'/%3E%3C/svg%3E%0A");
|
||||
} @else {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cg data-name='사각형 703' style='fill:%23f1f3f9;stroke:%23a4aac3'%3E%3Crect width='16' height='16' rx='3' style='stroke:none'/%3E%3Crect x='.5' y='.5' width='15' height='15' rx='2.5' style='fill:none'/%3E%3C/g%3E%3Crect data-name='사각형 1384' width='8' height='2' rx='1' transform='translate(4 7)' style='fill:%23a4aac3'/%3E%3C/svg%3E ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-tree-button-collapse {
|
||||
.tui-grid-btn-tree {
|
||||
i {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-position: 0 0;
|
||||
@if $theme == dark {
|
||||
background-image: url("data:image/svg+xml,%3Csvg id='btn_tree_item_open' xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cdefs%3E%3Cstyle%3E .cls-2%7Bfill:%23fff%7D %3C/style%3E%3C/defs%3E%3Cg id='사각형_703' data-name='사각형 703' style='fill:%230d0f17;stroke:%23fff;opacity:.3'%3E%3Crect width='16' height='16' rx='3' style='stroke:none'/%3E%3Crect x='.5' y='.5' width='15' height='15' rx='2.5' style='fill:none'/%3E%3C/g%3E%3Crect id='사각형_1384' data-name='사각형 1384' class='cls-2' width='8' height='2' rx='1' transform='translate(4 7)'/%3E%3Crect id='사각형_1385' data-name='사각형 1385' class='cls-2' width='2' height='8' rx='1' transform='translate(7 4)'/%3E%3C/svg%3E%0A");
|
||||
} @else {
|
||||
background-image: url("data:image/svg+xml,%3Csvg id='btn_tree_item_open' xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cdefs%3E%3Cstyle%3E .cls-2%7Bfill:%23a4aac3%7D %3C/style%3E%3C/defs%3E%3Cg id='사각형_703' data-name='사각형 703' style='fill:%23f1f3f9;stroke:%23a4aac3'%3E%3Crect width='16' height='16' rx='3' style='stroke:none'/%3E%3Crect x='.5' y='.5' width='15' height='15' rx='2.5' style='fill:none'/%3E%3C/g%3E%3Crect id='사각형_1384' data-name='사각형 1384' class='cls-2' width='8' height='2' rx='1' transform='translate(4 7)'/%3E%3Crect id='사각형_1385' data-name='사각형 1385' class='cls-2' width='2' height='8' rx='1' transform='translate(7 4)'/%3E%3C/svg%3E ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-tree-button-expand,
|
||||
&-tree-button-collapse {
|
||||
.tui-grid-tree-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-frozen-border {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
[class*="tui-grid-tree-wrapper"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
257
assets/scss/common/input.scss
Normal file
@ -0,0 +1,257 @@
|
||||
.v-select__custom {
|
||||
&.v-text-field.v-text-field--solo:not(.v-text-field--solo-flat)
|
||||
> .v-input__control
|
||||
> .v-input__slot {
|
||||
box-shadow: none;
|
||||
}
|
||||
&.v-text-field.v-text-field--solo .v-input__control {
|
||||
min-height: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
&.v-input input {
|
||||
min-height: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.v-input--selection-controls {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.v-input__slot {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.v-input__custom {
|
||||
.v-input__slot {
|
||||
&:before,
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.v-input__slot {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.v-text-field .v-input__append-inner,
|
||||
.v-text-field .v-input__prepend-inner {
|
||||
align-self: center !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.v-select__widget {
|
||||
&.v-text-field.v-text-field--solo:not(.v-text-field--solo-flat)
|
||||
> .v-input__control
|
||||
> .v-input__slot {
|
||||
box-shadow: none;
|
||||
}
|
||||
&.v-text-field.v-text-field--solo .v-input__control {
|
||||
min-height: 30px !important;
|
||||
height: 30px !important;
|
||||
}
|
||||
&.v-input input {
|
||||
min-height: 30px !important;
|
||||
height: 30px !important;
|
||||
}
|
||||
&.v-text-field--outlined > .v-input__control > .v-input__slot {
|
||||
align-items: stretch;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.v-input--selection-controls {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.v-input__slot {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 30px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.size {
|
||||
&-mini {
|
||||
width: 110px;
|
||||
height: 30px;
|
||||
flex: 0 0 auto;
|
||||
&.v-text-field.v-text-field--solo .v-input__control {
|
||||
min-height: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.v-text-field > .v-input__control > .v-input__slot:after,
|
||||
.v-text-field > .v-input__control > .v-input__slot:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v-input__slot {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.v-input {
|
||||
margin-top: 0 !important;
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.v-input__append-inner {
|
||||
.v-icon {
|
||||
color: currentColor !important;
|
||||
}
|
||||
}
|
||||
|
||||
@each $theme in dark, light {
|
||||
@include theme($theme);
|
||||
.v-application.#{$theme}-mode {
|
||||
.v-input {
|
||||
border-radius: 4px;
|
||||
|
||||
&:not(.v-input--radio-group, .v-input--checkbox) {
|
||||
.v-input__slot {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-backgroundColor"
|
||||
);
|
||||
}
|
||||
}
|
||||
.v-input__slot {
|
||||
fieldset {
|
||||
color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-fieldset-color"
|
||||
) !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
fieldset {
|
||||
color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-fieldset-hover-color"
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.v-input__append-inner {
|
||||
color: map-deep-get($config, #{$theme}, "v-input-icon-color");
|
||||
}
|
||||
}
|
||||
|
||||
&--is-readonly {
|
||||
border-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-readonly-border-color"
|
||||
);
|
||||
&:not(.v-input--radio-group, .v-input--checkbox) {
|
||||
.v-input__slot {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-readonly-backgroundColor"
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--is-disabled {
|
||||
border-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-readonly-border-color"
|
||||
);
|
||||
&:not(.v-input--radio-group, .v-input--checkbox) {
|
||||
.v-input__slot {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-disabled-backgroundColor"
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
input {
|
||||
color: map-deep-get($config, #{$theme}, "v-input-disabled-color");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-select {
|
||||
.v-label {
|
||||
color: map-deep-get($config, #{$theme}, "v-select-label-color");
|
||||
}
|
||||
|
||||
&.v-input--is-disabled {
|
||||
.v-label {
|
||||
color: map-deep-get($config, #{$theme}, "v-input-disabled-color");
|
||||
}
|
||||
.v-icon.v-icon--disabled {
|
||||
color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-disabled-color"
|
||||
) !important;
|
||||
}
|
||||
.v-select__selection--disabled {
|
||||
color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-input-disabled-color"
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-radio {
|
||||
.v-label {
|
||||
color: map-deep-get($config, #{$theme}, "non-activate");
|
||||
}
|
||||
&.v-item--active {
|
||||
.v-label {
|
||||
color: map-deep-get($config, #{$theme}, "activate");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-radio {
|
||||
.v-icon {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.v-label {
|
||||
color: map-deep-get($config, #{$theme}, "non-activate");
|
||||
}
|
||||
|
||||
&.v-item--active {
|
||||
.v-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.v-label {
|
||||
color: map-deep-get($config, #{$theme}, "activate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-input--checkbox {
|
||||
.v-icon {
|
||||
@if $theme == dark {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
} @else {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-textarea{
|
||||
textarea{
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
}
|
33
assets/scss/common/numericInput.scss
Normal file
@ -0,0 +1,33 @@
|
||||
.vue-numeric-input {
|
||||
min-height:36px;
|
||||
}
|
||||
.vue-numeric-input .numeric-input {
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
height:100%;
|
||||
border-color: rgba(255, 255, 255, 0.4);
|
||||
background: rgba(57, 64, 94, 0.3);
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
border-color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.vue-numeric-input.updown .btn-decrement .btn-icon {
|
||||
border-color: #fff transparent #fff !important;
|
||||
}
|
||||
|
||||
.vue-numeric-input.updown .btn-increment .btn-icon{
|
||||
border-color: transparent transparent #fff !important;
|
||||
}
|
88
assets/scss/common/tabs.scss
Normal file
@ -0,0 +1,88 @@
|
||||
// .v-tabs {
|
||||
// height: 38px;
|
||||
// flex: 0;
|
||||
// & + .v-tabs-items {
|
||||
// height: calc(100% - 38px) !important;
|
||||
// width: 100%;
|
||||
// background-color: transparent !important;
|
||||
// }
|
||||
// &-bar {
|
||||
// height: 38px;
|
||||
// background-color: transparent !important;
|
||||
// border-bottom: 1px solid $--color-hover_d;
|
||||
// }
|
||||
// .v-tab {
|
||||
// margin: 0 !important;
|
||||
// }
|
||||
// }
|
||||
|
||||
@each $theme in dark, light {
|
||||
.v-application.#{$theme}-mode {
|
||||
.v-tabs {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
.v-slide-group__wrapper {
|
||||
overflow: visible !important;
|
||||
contain: initial !important;
|
||||
}
|
||||
|
||||
.v-tab {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px 6px 0 0;
|
||||
border-bottom-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-tabs-active-border-color"
|
||||
);
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-tabs-backgroundColor"
|
||||
);
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
transform: translateY(1px);
|
||||
letter-spacing: 0;
|
||||
+ .v-tab {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.v-tab--active {
|
||||
border-top-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-tabs-active-border-color"
|
||||
);
|
||||
border-right-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-tabs-active-border-color"
|
||||
);
|
||||
border-left-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-tabs-active-border-color"
|
||||
);
|
||||
border-bottom-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-tabs-active-backgroundColor"
|
||||
);
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
"v-tabs-active-backgroundColor"
|
||||
);
|
||||
}
|
||||
}
|
||||
.v-tabs-items {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border-top: 1px
|
||||
solid
|
||||
map-deep-get($config, #{$theme}, "v-tabs-active-border-color");
|
||||
}
|
||||
}
|
||||
}
|
98
assets/scss/common/text.scss
Normal file
@ -0,0 +1,98 @@
|
||||
.txt {
|
||||
&__bar {
|
||||
display: flex;
|
||||
&:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 2px;
|
||||
height: 14px;
|
||||
background-color: #ccc;
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
&.log {
|
||||
&:before {
|
||||
background-color: $--color-primary__green;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-title-1 {
|
||||
font-size: 2.5rem; // 40px;
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.custom-title-2 {
|
||||
font-size: 1.75rem; // 28px
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.custom-title-2-5 {
|
||||
font-size: 1.5rem; // 28px
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.custom-title-3 {
|
||||
font-size: 1.15rem; // 28px
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.custom-title-4 {
|
||||
font-size: 1.125rem !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.25 !important;
|
||||
}
|
||||
.custom-title-6 {
|
||||
font-size: 1.0rem !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.25 !important;
|
||||
}
|
||||
.custom-title-8 {
|
||||
font-size: 0.75rem !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.0 !important;
|
||||
}
|
||||
|
||||
.custom-text-1 {
|
||||
font-size: 1.125rem; // 18px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.custom-text-2 {
|
||||
opacity: 0.6;
|
||||
font-family: SpoqaHanSansNeo;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
font-stretch: normal;
|
||||
font-style: normal;
|
||||
line-height: 2.17;
|
||||
letter-spacing: normal;
|
||||
text-align: right;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.text-color--white-0 {
|
||||
color: map-deep-get($color, "white", "0") !important;
|
||||
}
|
||||
|
||||
@each $theme in dark, light {
|
||||
.v-application.#{$theme}-mode {
|
||||
.text-color--activate {
|
||||
color: map-deep-get($config, #{$theme}, "activate");
|
||||
}
|
||||
|
||||
.text-color--non-activate {
|
||||
color: map-deep-get($config, #{$theme}, "non-activate");
|
||||
}
|
||||
|
||||
.text-color--sub {
|
||||
color: map-deep-get($config, #{$theme}, "text-subcolor");
|
||||
}
|
||||
}
|
||||
}
|
21
assets/scss/functions.scss
Normal file
@ -0,0 +1,21 @@
|
||||
@function setStyle($map, $object, $style) {
|
||||
@if map-has-key($map, $object) {
|
||||
@return map-get(map-get($map, $object), $style);
|
||||
}
|
||||
@warn "The key ´#{$object} is not available in the map.";
|
||||
@return null;
|
||||
}
|
||||
|
||||
/// Map deep get
|
||||
/// @author Kitty Giraudel
|
||||
/// @access public
|
||||
/// @param {Map} $map - Map
|
||||
/// @param {Arglist} $keys - Key chain
|
||||
/// @return {*} - Desired value
|
||||
|
||||
@function map-deep-get($map, $keys...) {
|
||||
@each $key in $keys {
|
||||
$map: map-get($map, $key);
|
||||
}
|
||||
@return $map;
|
||||
}
|
15
assets/scss/mixin.scss
Normal file
@ -0,0 +1,15 @@
|
||||
@import './var.scss';
|
||||
@import './functions.scss';
|
||||
@mixin theme($key) {
|
||||
$--theme-font-color: #{setStyle($config, $key, fontColor)} !global;
|
||||
$--theme-bg-page: #{setStyle($config, $key, pageBackground)} !global;
|
||||
$--theme-bg-card: #{setStyle($config, $key, cardBackground)} !global;
|
||||
$--theme-hover-color: #{setStyle($config, $key, hover)} !global;
|
||||
$--theme-button-close-color: #{setStyle($config, $key, btnClose)} !global;
|
||||
$--theme-color-w-g5: #{setStyle($config, $key, w-g5)} !global;
|
||||
$--theme-color-g5-w: #{setStyle($config, $key, g5-w)} !global;
|
||||
$--theme-color-gc-g9: #{setStyle($config, $key, gc-g9)} !global;
|
||||
$--theme-color-g5-gc: #{setStyle($config, $key, g5-gc)} !global;
|
||||
$--theme-color-g7-g9: #{setStyle($config, $key, g7-g9)} !global;
|
||||
$--theme-color-g9-g7: #{setStyle($config, $key, g9-g7)} !global;
|
||||
}
|
15
assets/scss/theme.scss
Normal file
@ -0,0 +1,15 @@
|
||||
// @import './var.scss';
|
||||
// @import './functions.scss';
|
||||
// @import './mixin.scss';
|
||||
|
||||
|
||||
|
||||
|
||||
// @each $theme in dark, light{
|
||||
// @include theme($theme);
|
||||
// .v-application.#{$theme}-mode{
|
||||
// span {
|
||||
// color: $--theme-font-color;
|
||||
// }
|
||||
// }
|
||||
// }
|
210
assets/scss/var.scss
Normal file
@ -0,0 +1,210 @@
|
||||
$--color-primary__blue: #278bff !important;
|
||||
$--color-primary__green: #26bf6b !important;
|
||||
$--color-sub__yellow: #ff9541 !important;
|
||||
$--color-warning__red: #ff5050 !important;
|
||||
$--color-white: #fff !important;
|
||||
$--color-black: #333 !important;
|
||||
$--color-gray_C: #cccccc !important;
|
||||
$--color-gray_9: #95a0a9 !important;
|
||||
$--color-gray_7: #767d83 !important;
|
||||
$--color-gray_999: #999 !important;
|
||||
$--color-gray_555: #555 !important;
|
||||
$--color-gray_aaa: #aaa !important;
|
||||
$--color-hover_d: #47535c !important;
|
||||
$--color-hover_l: #f0f5fc !important;
|
||||
|
||||
$--theme-font-color: "";
|
||||
$--theme-bg-page: "";
|
||||
$--theme-bg-card: "";
|
||||
$--theme-hover-color: "";
|
||||
$--theme-button-close-color: "";
|
||||
$--theme-color-w-g5: "";
|
||||
$--theme-color-gc-g9: "";
|
||||
$--theme-color-g5-gc: "";
|
||||
$--theme-color-g7-g9: "";
|
||||
$--theme-color-g9-g7: "";
|
||||
|
||||
$scrollbar-width: 11px; // 스크롤 바
|
||||
$column-spacer: 20px; // 검색 영역 열 간격
|
||||
$row-spacer: 14px; // 검색 영역 행 간격
|
||||
|
||||
$color: (
|
||||
"black": (
|
||||
"0": #000,
|
||||
"1": #111
|
||||
),
|
||||
"white": (
|
||||
"0": #fff
|
||||
),
|
||||
"week": (
|
||||
"sun": #fb5a83,
|
||||
"sat": #2d8cf6
|
||||
)
|
||||
);
|
||||
|
||||
$config: (
|
||||
dark: (
|
||||
w-g5: $--color-white,
|
||||
g5-w: $--color-gray_555,
|
||||
gc-g9: $--color-gray_C,
|
||||
g5-gc: $--color-gray_555,
|
||||
g7-g9: $--color-gray_7,
|
||||
g9-g7: $--color-gray_9,
|
||||
pageBackground: #23272b,
|
||||
cardBackground: #242940,
|
||||
hover: #47535c,
|
||||
btnClose: #24282c,
|
||||
scrollbar-track: #2f334a,
|
||||
scrollbar-thumb: #575b72,
|
||||
card-default-color: #fff,
|
||||
card-subtitle: rgba(255, 255, 255, 0.6),
|
||||
activate: #fff,
|
||||
non-activate: rgba(255, 255, 255, 0.6),
|
||||
text-subcolor: rgba(255, 255, 255, 0.6),
|
||||
border-color: rgba(255, 255, 255, 0.1),
|
||||
router-header: #1d2133,
|
||||
router-tab-item: #2d3355,
|
||||
router-tab-item-active: #18579e,
|
||||
router-tab-item-color: #fff,
|
||||
router-tab-item-active-color: #fff,
|
||||
router-tab-item-icon-color: rgba(255, 255, 255, 0.5),
|
||||
router-tab-item-icon-active-color: #fff,
|
||||
router-tab-item-hover-color: #3896ff,
|
||||
router-tab-slot-end-button-backgroundColor: #144985,
|
||||
v-btn-backgroundColor: #144985,
|
||||
v-box: #383f5d,
|
||||
v-banner-border-color: rgba(255, 255, 255, 0.1),
|
||||
v-treeview-node-root-backgroundColor: #18579e,
|
||||
v-treeview-node-root-label-color: #fff,
|
||||
v-treeview-node-root-label-active-color: #fff,
|
||||
v-treeview-node-root-icon-color: #fff,
|
||||
v-treeview-node-root-icon-active-color: #fff,
|
||||
v-treeview-node-subroot-backgroundColor: #2d3355,
|
||||
v-treeview-node-label-color: rgba(255, 255, 255, 0.6),
|
||||
v-treeview-node-label-active-color: #fff,
|
||||
v-treeview-leaf-active-backgroundColor: rgba(45, 51, 85, 0.5),
|
||||
v-treeview-leaf-active-color: #3896ff,
|
||||
v-treeview-icon-color: rgba(255, 255, 255, 0.6),
|
||||
v-treeview-icon-active-color: #fff,
|
||||
v-input-backgroundColor: rgba(13, 15, 23, 0.3),
|
||||
v-input-fieldset-color: rgba(255, 255, 255, 0.32),
|
||||
v-input-fieldset-hover-color: rgba(255, 255, 255, 1),
|
||||
v-input-icon-color: #fff,
|
||||
v-input-readonly-border-color: rgba(255, 255, 255, 0.3),
|
||||
v-input-readonly-backgroundColor: rgba(57, 64, 94, 0.3),
|
||||
v-input-disabled-backgroundColor: rgba(57, 64, 94, 0.3),
|
||||
v-input-disabled-color: rgba(255, 255, 255, 0.2),
|
||||
v-select-label-color: #fff,
|
||||
v-calendar-weekday-backgroundColor: #383f5d,
|
||||
v-calendar-weekday-color: #fff,
|
||||
v-calendar-weekday-border-color: rgba(255, 255, 255, 0.1),
|
||||
v-calendar-day-color: #fff,
|
||||
v-calendar-day-in-not-month-color: rgba(255, 255, 255, 0.05),
|
||||
v-calendar-is-today-background-color: #2d4571,
|
||||
tui-grid-header-backgroundColor: #383f5d,
|
||||
tui-grid-border-horziontal-color: #383f5d,
|
||||
tui-grid-border-vertical-color: rgba(255, 255, 255, 0.1),
|
||||
tui-grid-cell-backgroundColor: #242940,
|
||||
tui-grid-cell-color: #fff,
|
||||
tui-grid-cell-insert-color: #13636c,
|
||||
tui-grid-cell-selected-color: #1a4e87,
|
||||
tui-grid-cell-modify-color: #13636c,
|
||||
tui-grid-cell-removed-color: #f6637b,
|
||||
tui-grid-cell-disabled-color: rgb(170, 170, 170),
|
||||
tui-grid-cell-hover-backgroundColor: #31375b,
|
||||
v-tabs-items-border-color: rgba(255, 255, 255, 0.7),
|
||||
v-tabs-backgroundColor: rgba(57, 64, 94, 0.5),
|
||||
v-tabs-active-backgroundColor: #242940,
|
||||
v-tabs-active-border-color: rgba(255, 255, 255, 0.7),
|
||||
v-dialog-card-text-color: #fff,
|
||||
tui-datepicker-backgroundColor: #0d0f17,
|
||||
tui-datepicker-border-color: rgba(255, 255, 255, 0.3),
|
||||
tui-datepicker-selectable-hover-color: #2d3355,
|
||||
tui-datepicker-selected-color: #1a4e87,
|
||||
tui-datepicker-calendar-color: #fff,
|
||||
tui-editor-contents-color: #111,
|
||||
admin-menu-expanded-list-backgroundColor: #144985
|
||||
),
|
||||
light: (
|
||||
w-g5: $--color-gray_555,
|
||||
g5-w: $--color-white,
|
||||
gc-g9: $--color-gray_999,
|
||||
g5-gc: $--color-gray_C,
|
||||
g7-g9: $--color-gray_9,
|
||||
g9-g7: $--color-gray_7,
|
||||
fontColor: #333,
|
||||
pageBackground: #ececef,
|
||||
cardBackground: #fefefe,
|
||||
hover: #f0f5fc,
|
||||
btnClose: #f1f0f8,
|
||||
scrollbar-track: #e9e9e9,
|
||||
scrollbar-thumb: #bbbbbb,
|
||||
card-default-color: #111,
|
||||
card-subtitle: #555,
|
||||
activate: #111,
|
||||
non-activate: #555,
|
||||
text-subcolor: #999,
|
||||
border-color: #ddd,
|
||||
router-header: #fff,
|
||||
router-tab-item: #e1e7f3,
|
||||
router-tab-item-active: #4777d9,
|
||||
router-tab-item-color: #111,
|
||||
router-tab-item-active-color: #fff,
|
||||
router-tab-item-icon-color: #838aa6,
|
||||
router-tab-item-icon-active-color: #fff,
|
||||
router-tab-item-hover-color: #366dbe,
|
||||
router-tab-slot-end-button-backgroundColor: #3f4d7d,
|
||||
v-btn-backgroundColor: #4777d9,
|
||||
v-box: #f0f3fa,
|
||||
v-banner-border-color: #ddd,
|
||||
v-treeview-node-root-backgroundColor: #4777d9,
|
||||
v-treeview-node-root-label-color: #111,
|
||||
v-treeview-node-root-label-active-color: #fff,
|
||||
v-treeview-node-root-icon-color: #555,
|
||||
v-treeview-node-root-icon-active-color: #fff,
|
||||
v-treeview-node-subroot-backgroundColor: #e1e7f3,
|
||||
v-treeview-node-label-color: #555,
|
||||
v-treeview-node-label-active-color: #111,
|
||||
v-treeview-leaf-active-backgroundColor: #edf1f7,
|
||||
v-treeview-leaf-active-color: #366dbe,
|
||||
v-treeview-icon-color: #a4aac3,
|
||||
v-treeview-icon-active-color: #616885,
|
||||
v-input-backgroundColor: #ffffff,
|
||||
v-input-fieldset-color: #b4b8c9,
|
||||
v-input-fieldset-hover-color: #b4b8c9,
|
||||
v-input-icon-color: #555,
|
||||
v-input-readonly-border-color: #b4b8c9,
|
||||
v-input-readonly-backgroundColor: #f5f5f5,
|
||||
v-input-disabled-backgroundColor: #eee,
|
||||
v-input-disabled-color: #bbb,
|
||||
v-select-label-color: #111,
|
||||
v-calendar-weekday-backgroundColor: #e0e0e0,
|
||||
v-calendar-weekday-color: #111,
|
||||
v-calendar-weekday-border-color: #d4d4d4,
|
||||
v-calendar-day-color: #111,
|
||||
v-calendar-day-in-not-month-color: #f8f8f8,
|
||||
v-calendar-is-today-background-color: #e3eaf3,
|
||||
tui-grid-header-backgroundColor: #e0e0e0,
|
||||
tui-grid-border-horziontal-color: #e0e0e0,
|
||||
tui-grid-border-vertical-color: #d4d4d4,
|
||||
tui-grid-cell-backgroundColor: #fff,
|
||||
tui-grid-cell-color: #555,
|
||||
tui-grid-cell-insert-color: #13636c,
|
||||
tui-grid-cell-selected-color: #ecf2fa,
|
||||
tui-grid-cell-modify-color: #e6f5f7,
|
||||
tui-grid-cell-removed-color: #fddde1,
|
||||
tui-grid-cell-hover-backgroundColor: #f5f5f5,
|
||||
v-tabs-items-border-color: #989db1,
|
||||
v-tabs-backgroundColor: #ddd,
|
||||
v-tabs-active-backgroundColor: #fff,
|
||||
v-tabs-active-border-color: #989db1,
|
||||
v-dialog-card-text-color: #111,
|
||||
tui-datepicker-backgroundColor: #fff,
|
||||
tui-datepicker-border-color: #b4b8c9,
|
||||
tui-datepicker-selectable-hover-color: #e1e7f3,
|
||||
tui-datepicker-selected-color: #4777d9,
|
||||
tui-datepicker-calendar-color: #111,
|
||||
tui-editor-contents-color: #111,
|
||||
admin-menu-expanded-list-backgroundColor: #3f4d7d
|
||||
)
|
||||
);
|
56
assets/variables.scss
Normal file
@ -0,0 +1,56 @@
|
||||
// Ref: https://github.com/nuxt-community/vuetify-module#customvariables
|
||||
//
|
||||
// The variables you want to modify
|
||||
// $font-size-root: 20px;
|
||||
$body-font-family: "Spoqa Han Sans Neo", "Roboto", "sans-serif" !default;
|
||||
$grid-gutter: 10px;
|
||||
$material-dark: (
|
||||
"background": #383f5d,
|
||||
"cards": #242940,
|
||||
"navigation-drawer": #1a1d2d,
|
||||
"chips": rgba(255, 255, 255, 0.1)
|
||||
);
|
||||
|
||||
$material-light: (
|
||||
"background": #f0f3fa,
|
||||
"cards": #fff,
|
||||
"navigation-drawer": #fff,
|
||||
"chips": #eee
|
||||
);
|
||||
|
||||
$treeview-node-padding: 10px;
|
||||
$treeview-node-height: 40px;
|
||||
|
||||
$banner-start-padding: 10px;
|
||||
$banner-end-padding: 10px;
|
||||
$banner-y-padding: 12px;
|
||||
|
||||
$card-border-radius: 10px;
|
||||
$card-title-font-size: 1.25rem;
|
||||
$card-title-font-weight: 700;
|
||||
$card-title-line-height: 1.5;
|
||||
$card-subtitle-padding: 20px;
|
||||
|
||||
$timeline-dot-small-size: 10px;
|
||||
|
||||
$data-table-regular-row-height: 36px;
|
||||
|
||||
$input-font-size: 14px;
|
||||
$input-max-height: 36px;
|
||||
$text-field-filled-full-width-outlined-slot-min-height: 36px;
|
||||
$text-field-solo-control-min-height: 36px;
|
||||
$text-field-line-height: 1.285;
|
||||
$text-field-enclosed-prepend-append-margin-top: 0;
|
||||
$text-field-enclosed-details-padding: 0 8px;
|
||||
|
||||
$tab-font-size: 1rem; // 16px;
|
||||
$tab-font-weight: 400;
|
||||
$tabs-bar-height: 45px;
|
||||
$tabs-item-padding: 12px;
|
||||
|
||||
$list-border-radius: 4px;
|
||||
$list-padding: 0;
|
||||
$list-item-min-height: 36px;
|
||||
$list-item-padding: 0;
|
||||
$list-item-title-font-size: 0.875rem; // 14px;
|
||||
$list-item-content-padding: 10px 7px;
|
79
components/Logo.vue
Normal file
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div class="VueToNuxtLogo">
|
||||
<div class="Triangle Triangle--two" />
|
||||
<div class="Triangle Triangle--one" />
|
||||
<div class="Triangle Triangle--three" />
|
||||
<div class="Triangle Triangle--four" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.VueToNuxtLogo {
|
||||
display: inline-block;
|
||||
animation: turn 2s linear forwards 1s;
|
||||
transform: rotateX(180deg);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 180px;
|
||||
width: 245px;
|
||||
}
|
||||
|
||||
.Triangle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.Triangle--one {
|
||||
border-left: 105px solid transparent;
|
||||
border-right: 105px solid transparent;
|
||||
border-bottom: 180px solid #41b883;
|
||||
}
|
||||
|
||||
.Triangle--two {
|
||||
top: 30px;
|
||||
left: 35px;
|
||||
animation: goright 0.5s linear forwards 3.5s;
|
||||
border-left: 87.5px solid transparent;
|
||||
border-right: 87.5px solid transparent;
|
||||
border-bottom: 150px solid #3b8070;
|
||||
}
|
||||
|
||||
.Triangle--three {
|
||||
top: 60px;
|
||||
left: 35px;
|
||||
animation: goright 0.5s linear forwards 3.5s;
|
||||
border-left: 70px solid transparent;
|
||||
border-right: 70px solid transparent;
|
||||
border-bottom: 120px solid #35495e;
|
||||
}
|
||||
|
||||
.Triangle--four {
|
||||
top: 120px;
|
||||
left: 70px;
|
||||
animation: godown 0.5s linear forwards 3s;
|
||||
border-left: 35px solid transparent;
|
||||
border-right: 35px solid transparent;
|
||||
border-bottom: 60px solid #fff;
|
||||
}
|
||||
|
||||
@keyframes turn {
|
||||
100% {
|
||||
transform: rotateX(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes godown {
|
||||
100% {
|
||||
top: 180px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes goright {
|
||||
100% {
|
||||
left: 70px;
|
||||
}
|
||||
}
|
||||
</style>
|
209
components/Pagination.vue
Normal file
@ -0,0 +1,209 @@
|
||||
<template>
|
||||
<div class="ly-pager d-flex">
|
||||
<v-row class="con-pager" align="center" justify="start">
|
||||
<!-- <span class="grey--text">{{ $m('CAP.PAGE_ROW', '페이지 행당') }} : </span> -->
|
||||
<v-menu offset-y>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-btn
|
||||
dark
|
||||
text
|
||||
color="primary"
|
||||
class="ml-2"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>
|
||||
{{ itemsPerPage }}
|
||||
<v-icon>mdi-chevron-down</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list v-if="useLimit">
|
||||
<v-list-item
|
||||
v-for="(number, index) in itemsPerPageArray"
|
||||
:key="index"
|
||||
@click="changePageLeng(number)"
|
||||
>
|
||||
<v-list-item-title>{{ number }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-btn fab small class="mr-1 btn-pager" @click="firstToPage">
|
||||
<v-icon>mdi-chevron-double-left</v-icon>
|
||||
</v-btn>
|
||||
<v-btn fab small class="mr-1 btn-pager" @click="prevPage">
|
||||
<v-icon>mdi-chevron-left</v-icon>
|
||||
</v-btn>
|
||||
<!-- <span class="mr-4 grey--text mr-1"> {{ numberOfPages }} / {{ lastPage }} </span> -->
|
||||
<span class="mr-4 mr-1"> {{ numberOfPages }} / {{ lastPage }} </span>
|
||||
<v-btn fab small class="ml-1 btn-pager" @click="nextPage">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</v-btn>
|
||||
<v-btn fab small class="mr-1 btn-pager" @click="lastToPage">
|
||||
<v-icon>mdi-chevron-double-right</v-icon>
|
||||
</v-btn>
|
||||
<div class="mr-1 btn-pager">
|
||||
<v-text-field v-model="moveToPage" type="number" label="page" />
|
||||
</div>
|
||||
<v-btn fab small class="mr-1" @click="movePage">
|
||||
{{ $m('CAP.MOVE', '이동') }}
|
||||
</v-btn>
|
||||
</v-row>
|
||||
<slot name="btn"> </slot>
|
||||
<!-- <Alert ref="alert" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
useLimit: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
totalCount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
pageNum: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
itemsPerPageArray: {
|
||||
type: Array,
|
||||
default: () => [20, 50, 100],
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
moveToPage: '',
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
page: function() {
|
||||
return this.numberOfPages + '-' + this.lastPage;
|
||||
},
|
||||
lastPage: function() {
|
||||
//grid data가 없을 경우 1 리턴
|
||||
if (this.totalCount == 0) return 1;
|
||||
|
||||
let pageLength = Math.floor(this.totalCount / this.itemsPerPage);
|
||||
if (this.totalCount % this.itemsPerPage > 0) {
|
||||
pageLength++;
|
||||
}
|
||||
return pageLength;
|
||||
},
|
||||
itemsPerPage: function() {
|
||||
return this.limit;
|
||||
},
|
||||
numberOfPages: function() {
|
||||
return Number(this.pageNum);
|
||||
},
|
||||
plusPage: function() {
|
||||
return Number(this.pageNum) + 1;
|
||||
},
|
||||
minusPage: function() {
|
||||
return Number(this.pageNum) - 1;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
totalCount: function(newData) {
|
||||
return (this.moveToPage = newData > 0 ? this.moveToPage : '');
|
||||
},
|
||||
|
||||
moveToPage: function() {
|
||||
return (this.moveToPage = this.moveToPage.replaceAll(/[^0-9]/g, ''));
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
nextPage: function() {
|
||||
if (this.lastPage >= this.plusPage) {
|
||||
this.$emit('loadData', this.plusPage, this.itemsPerPage);
|
||||
}
|
||||
},
|
||||
|
||||
prevPage: function() {
|
||||
if (0 != this.minusPage) {
|
||||
this.$emit('loadData', this.minusPage, this.itemsPerPage);
|
||||
}
|
||||
},
|
||||
|
||||
movePage: function() {
|
||||
if (0 < this.moveToPage && this.moveToPage <= this.lastPage) {
|
||||
this.$emit('loadData', Number(this.moveToPage), this.itemsPerPage);
|
||||
} else {
|
||||
this.$refs.alert.done = () => {
|
||||
this.$emit('refresh');
|
||||
};
|
||||
this.$refs.alert.open(
|
||||
this.$m('COD.CNFM', '확인'),
|
||||
this.$m('CAP.PAGE_MOVE_CNFM', '이동할 페이지 정보를 확인 하세요'),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
changePageLeng: function(limit) {
|
||||
//부모 컴포넌트에서 loadData(데이터 조회) 구현
|
||||
//this.$emit('loadData', this.pageNum, limit);
|
||||
// limit 변경 시 1 페이지로 초기화
|
||||
this.$emit('loadData', 1, limit);
|
||||
},
|
||||
|
||||
firstToPage: function() {
|
||||
if (0 != this.minusPage) {
|
||||
this.$emit('loadData', 1, this.itemsPerPage);
|
||||
}
|
||||
},
|
||||
|
||||
lastToPage: function() {
|
||||
if (this.lastPage >= this.plusPage) {
|
||||
this.$emit('loadData', this.lastPage, this.itemsPerPage);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.btn-pager {
|
||||
margin: 4px;
|
||||
input {
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
.v-btn--fab.v-size--small {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
.v-text-field__details {
|
||||
display: none;
|
||||
}
|
||||
.con-pager {
|
||||
margin-top: 12px;
|
||||
margin-bottom: -12px;
|
||||
}
|
||||
.ly-pager {
|
||||
margin: auto;
|
||||
}
|
||||
.v-btn {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.v-btn--text {
|
||||
margin-right: 6px;
|
||||
}
|
||||
// .grey--text {
|
||||
// margin-left: 16px;
|
||||
// }
|
||||
.mr-4 {
|
||||
margin-left: 14px;
|
||||
}
|
||||
.v-btn__content {
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
7
components/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# COMPONENTS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
The components directory contains your Vue.js Components.
|
||||
|
||||
_Nuxt.js doesn't supercharge these components._
|
18
components/VuetifyLogo.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<img class="VuetifyLogo" alt="Vuetify Logo" src="/vuetify-logo.svg" />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.VuetifyLogo {
|
||||
height: 180px;
|
||||
width: 180px;
|
||||
transform: rotateY(560deg);
|
||||
animation: turn 3.5s ease-out forwards 1s;
|
||||
}
|
||||
|
||||
@keyframes turn {
|
||||
100% {
|
||||
transform: rotateY(0deg);
|
||||
}
|
||||
}
|
||||
</style>
|
181
components/common/AdminMenu.vue
Normal file
@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<v-menu offset-y nudge-bottom="8" :left="true">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
depressed
|
||||
:ripple="false"
|
||||
:class="{ miniVariant }"
|
||||
:style="btnStyle"
|
||||
>
|
||||
<v-icon size="32" :class="{ 'mr-2': !miniVariant }"
|
||||
>$icoAdminMenu</v-icon
|
||||
>
|
||||
<span class="body-1 mr-1">{{ userNm }}</span>
|
||||
<v-icon>mdi-chevron-down</v-icon>
|
||||
</v-btn>
|
||||
<!-- <AlertPopup
|
||||
ref="alertPop"
|
||||
v-show='false'
|
||||
:item="item"
|
||||
|
||||
/> -->
|
||||
</template>
|
||||
|
||||
<v-list class="pa-2">
|
||||
<!-- <v-list-item class="mb-1">-->
|
||||
<!-- <div class="d-flex align-center">-->
|
||||
<!-- <v-avatar class="mr-1" size="20">-->
|
||||
<!-- <v-icon color="white">mdi-account-outline</v-icon>-->
|
||||
<!-- </v-avatar>-->
|
||||
<!-- <div class="d-flex flex-column">-->
|
||||
<!-- <span class="body-2 white--text">관리자</span>-->
|
||||
<!-- <!– <nuxt-link class="d-flex align-center mypage" to="/">-->
|
||||
<!-- <span class="clr-ccc-aaa">마이페이지</span>-->
|
||||
<!-- <v-icon class="ico-right">mdi-chevron-right</v-icon>-->
|
||||
<!-- </nuxt-link> –>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </v-list-item>-->
|
||||
<v-list-item>
|
||||
<v-btn @click="pswdChange" small elevation="0">
|
||||
<v-icon class="mr-1" size="20">mdi-account-outline</v-icon>
|
||||
<span class="body-2">비밀번호 변경</span>
|
||||
</v-btn>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-btn @click="logout" small elevation="0">
|
||||
<v-icon class="mr-1" size="20">mdi-logout</v-icon>
|
||||
<span class="body-2">로그아웃</span>
|
||||
</v-btn>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
<script>
|
||||
import $cookie from 'vue-cookie';
|
||||
import { mapState } from 'vuex';
|
||||
// import AlertPopup from "~/components/common/modal/AlertPopup";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
miniVariant: Boolean,
|
||||
userNm: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
comId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
// AlertPopup
|
||||
//ChangePswdPop
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
logoutUrl: '/login',
|
||||
item: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['isDarkMode']),
|
||||
btnStyle() {
|
||||
return this.isDarkMode ? { color: '#fff' } : { color: '#111' };
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
logout() {
|
||||
$cookie.delete('FEMS_SESSION');
|
||||
// alert("정상적으로 로그아웃 되었습니다.");
|
||||
// this.item={
|
||||
// label:'로그아웃',
|
||||
// message:'정상적으로 로그아웃 되었습니다.'
|
||||
// }
|
||||
// this.$refs['alertPop'].dialog = true;
|
||||
|
||||
this.$nextTick(() => {
|
||||
window.location.href = this.logoutUrl + '?' + this.comId;
|
||||
});
|
||||
},
|
||||
pswdChange() {
|
||||
this.$parent.$parent.$parent.$parent.$refs['changePswdPop'].dialog = true;
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/var.scss';
|
||||
@each $theme in dark, light {
|
||||
.v-application.#{$theme}-mode {
|
||||
.mdi-account {
|
||||
color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
'tui-datepicker-calendar-color'
|
||||
) !important;
|
||||
}
|
||||
|
||||
.v-list {
|
||||
background-color: map-deep-get(
|
||||
$config,
|
||||
#{$theme},
|
||||
'admin-menu-expanded-list-backgroundColor'
|
||||
);
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-menu__content {
|
||||
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.v-list {
|
||||
.v-btn {
|
||||
padding: 0 !important;
|
||||
margin-bottom: 0;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
color: #46c0ff;
|
||||
}
|
||||
|
||||
> span {
|
||||
color: currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-btn {
|
||||
width: 100%;
|
||||
min-width: auto !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px !important;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&,
|
||||
&:before {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
::v-deep {
|
||||
.v-btn__content {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
&.miniVariant {
|
||||
::v-deep {
|
||||
.v-btn__content > .body-1,
|
||||
.v-btn__content > .mdi-chevron-down {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
77
components/common/BtnXlsx.vue
Normal file
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div id="btnExeclDownload">
|
||||
<v-btn class="v-btn__round v-btn__excel" @click="downloadExcelFile">
|
||||
<v-icon>mdi-microsoft-excel</v-icon>
|
||||
엑셀
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import XLSX from 'xlsx';
|
||||
|
||||
export default {
|
||||
name: 'btnExeclDownload',
|
||||
props: {
|
||||
xlsHeader: {
|
||||
// JSON 데이터로 만들 시 필요
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
xlsRowData: {
|
||||
// JSON 데이터로 만들 시 필요
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
tableId: {
|
||||
// 성성된 테이블 그대로 쓸 경우 그리드에 id 지정 후 바인딩
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
fileName: {
|
||||
// 테이블이 하나일 경우, 현재 활성화 메뉴명을 가져와도 될듯,.
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
sheetName: {
|
||||
// 지정된 시트명이 없으면 'Sheet1'
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
xlsData: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setExcelData() {
|
||||
let tmpData = [];
|
||||
let tmpMap = {};
|
||||
this.xlsRowData.map(item => {
|
||||
this.xlsHeader.map(v => {
|
||||
return Object.assign(tmpMap, { [v.header]: item[v.name] || '' });
|
||||
});
|
||||
tmpData = tmpData.concat(tmpMap);
|
||||
tmpMap = {};
|
||||
});
|
||||
this.xlsData = tmpData;
|
||||
tmpData = null;
|
||||
tmpMap = null;
|
||||
},
|
||||
async downloadExcelFile() {
|
||||
if (!this.tableId) await this.setExcelData(); // 들어온 JSON 데이타 가공
|
||||
|
||||
const workBook = XLSX.utils.book_new(); // 새 시트 생성
|
||||
const excelData = this.tableId
|
||||
? // 테이블 그대로 가져올때
|
||||
XLSX.utils.table_to_sheet(document.getElementById(this.tableId))
|
||||
: // JSON 형식으로 가져올때
|
||||
XLSX.utils.json_to_sheet(this.xlsData);
|
||||
const sheetName = this.sheetName || null;
|
||||
XLSX.utils.book_append_sheet(workBook, excelData, sheetName); // 시트 명명, 데이터 지정
|
||||
XLSX.writeFile(workBook, `${this.fileName}.xlsx`); // 엑셀파일 만듬
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
339
components/common/Calendar.vue
Normal file
@ -0,0 +1,339 @@
|
||||
<template>
|
||||
<div class="custom-vc-calender">
|
||||
<div class="custom-vc-calender-title text-center" v-if="headerVisible">
|
||||
<span>{{ selectedYear }}년 {{ selectedMonth }}월</span>
|
||||
</div>
|
||||
<vc-calendar
|
||||
ref="myCalendar"
|
||||
:attributes="calendarAttributes"
|
||||
class="custom-calendar"
|
||||
>
|
||||
<!-- disable-page-swipe
|
||||
is-expanded -->
|
||||
<template v-slot:day-content="{ day, attributes }">
|
||||
<div class="plusButton" style="overflow:auto">
|
||||
<!-- <p class="plusButton mr-1" >+</p> -->
|
||||
<span
|
||||
:class="['day-label', { 'is-holiday': hldyValues(day.day) }]"
|
||||
@click="addPlan(day.year, day.month, day.day)"
|
||||
>{{ day.day }}</span
|
||||
>
|
||||
<span v-for="attr in attributes" :key="attr.key" class="day-hldyNm">
|
||||
{{ attr.customData.title }}
|
||||
</span>
|
||||
<div class="">
|
||||
<p
|
||||
v-for="attr in attributes"
|
||||
:key="attr.key"
|
||||
:class="attr.customData.planColor"
|
||||
@click="updatePlan(attr.customData.planSeq)"
|
||||
>
|
||||
{{ attr.customData.planTitle }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</vc-calendar>
|
||||
<component
|
||||
ref="planPop"
|
||||
:is="'PlanPop'"
|
||||
v-show="false"
|
||||
:detailList="detailList"
|
||||
:label="planLabel"
|
||||
:parentPrgmId="parentPrgmId"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import Utility from '~/plugins/utility';
|
||||
import PlanPop from '@/components/common/modal/PlanPop';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
gridName: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
headerVisible: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
pageData(state) {
|
||||
return state.pageData[this.parentPrgmId];
|
||||
},
|
||||
}),
|
||||
gridData() {
|
||||
return this.pageData[this.gridName].data;
|
||||
},
|
||||
planData() {
|
||||
return this.pageData.planData;
|
||||
},
|
||||
calendarDtValue() {
|
||||
const dt = this.pageData['fromDt'];
|
||||
return dt;
|
||||
},
|
||||
selectedYear() {
|
||||
return Utility.setFormatDate(this.calendarDtValue, 'YYYY');
|
||||
//return this.calendarDtValue.split("-")[0];
|
||||
},
|
||||
selectedMonth() {
|
||||
return Utility.setFormatDate(this.calendarDtValue, 'MM');
|
||||
//return this.calendarDtValue.split("-")[1];
|
||||
},
|
||||
hldyValues() {
|
||||
const filter = this.gridData.filter(
|
||||
data => data.hldyFg === '1' || data.hldyNm,
|
||||
);
|
||||
const map = filter.map(item => {
|
||||
const dt = item.dt.split(' ')[0];
|
||||
const dtArr = dt.split('-');
|
||||
const dd = dtArr[2] * 1;
|
||||
return dd;
|
||||
});
|
||||
|
||||
return day => {
|
||||
return map.includes(day);
|
||||
};
|
||||
},
|
||||
calendarAttributes() {
|
||||
if (this.planData.length > 0) {
|
||||
let attrArr = [];
|
||||
this.planData.forEach((item, idx) => {
|
||||
const dt = item.dt.split(' ')[0];
|
||||
const dtArr = dt.split('-');
|
||||
const yy = dtArr[0] * 1;
|
||||
const mm = dtArr[1] * 1 - 1;
|
||||
const dd = dtArr[2] * 1;
|
||||
attrArr.push({
|
||||
key: idx,
|
||||
customData: {
|
||||
title: item.hldyNm,
|
||||
hldyFg: item.hldyFg,
|
||||
planTitle: item.planTitle,
|
||||
planSeq: item.planSeq,
|
||||
planColor:
|
||||
// item.endDt < Utility.setFormatDate(new Date(), 'YYYY-MM-DD')
|
||||
// ? 'grey':
|
||||
item.planColor,
|
||||
},
|
||||
dates: new Date(yy, mm, dd),
|
||||
});
|
||||
});
|
||||
return attrArr;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
calendarDtValue(val) {
|
||||
// if (val) {
|
||||
// this.$refs.myCalendar.move(this.calendarDtValue);
|
||||
// }
|
||||
if (val) {
|
||||
const yy = Utility.setFormatDate(this.calendarDtValue, 'YYYY');
|
||||
const mm = Utility.setFormatDate(this.calendarDtValue, 'MM') - 1;
|
||||
this.$refs.myCalendar.showPageRange(new Date(yy, mm, 1));
|
||||
}
|
||||
},
|
||||
},
|
||||
components: {
|
||||
PlanPop,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
detailList: myDetail,
|
||||
planPopDisableFlag: false,
|
||||
planLabel: '일정',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
addPlan(year, month, day) {
|
||||
this.planLabel = '일정 등록';
|
||||
this.$refs['planPop'].popUpAction = 'insert';
|
||||
// this.$refs['planPop'].strtDt = year + '-' + month + '-' + day;
|
||||
// this.$refs['planPop'].endDt = year + '-' + month + '-' + day;
|
||||
// this.$refs['planPop'].strtDt = year + '-' + String(month).padStart(2, '0') + '-' + String(day).padStart(2, '0');
|
||||
// this.$refs['planPop'].endDt = year + '-' + String(month).padStart(2, '0') + '-' + String(day).padStart(2, '0');
|
||||
this.$refs['planPop'].strtDt = '';
|
||||
this.$refs['planPop'].endDt = '';
|
||||
this.$refs['planPop'].addPlanData = {
|
||||
year : year,
|
||||
month : month,
|
||||
day : day
|
||||
}
|
||||
this.$refs['planPop'].blocId = this.pageData.blocMstrList[
|
||||
this.pageData.blocId
|
||||
].blocId;
|
||||
this.$refs['planPop'].dialog = true;
|
||||
},
|
||||
updatePlan(val) {
|
||||
this.$refs['planPop'].popUpAction = 'update';
|
||||
this.$refs['planPop'].planSeq = val;
|
||||
this.$refs['planPop'].strtDt = '';
|
||||
this.$refs['planPop'].endDt = '';
|
||||
this.$refs['planPop'].blocId = this.pageData.blocMstrList[
|
||||
this.pageData.blocId
|
||||
].blocId;
|
||||
this.$refs['planPop'].dialog = true;
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
};
|
||||
const myDetail = [];
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/var.scss';
|
||||
@import '@/assets/scss/mixin.scss';
|
||||
::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
display: none;
|
||||
}
|
||||
.custom-vc-calender {
|
||||
&-title {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
::v-deep {
|
||||
.custom-calendar.vc-container {
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
.vc-header,
|
||||
.vc-arrows-container {
|
||||
display: none;
|
||||
}
|
||||
.vc-weeks {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
> div {
|
||||
flex: 1 0 calc(100% / 7);
|
||||
}
|
||||
}
|
||||
.vc-weekday {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
}
|
||||
.vc-day {
|
||||
height: 10.889vh;
|
||||
min-height: auto;
|
||||
|
||||
.day-label {
|
||||
font-size: 1rem;
|
||||
line-height: 1.235;
|
||||
}
|
||||
.day-hldyNm {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
max-width: 80%;
|
||||
float: right;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
> div {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
.vc-day.is-not-in-month {
|
||||
* {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
.plusButton:hover > span:first-child {
|
||||
font-weight: bolder;
|
||||
cursor: pointer;
|
||||
}
|
||||
.red {
|
||||
//background-color: rgba(229,62,62,var(--bg-opacity));
|
||||
background-color: #e53e3e !important;
|
||||
color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25;
|
||||
text-align: left;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.blue {
|
||||
//background-color: rgba(66,153,225,var(--bg-opacity));
|
||||
background-color: #4299e1 !important;
|
||||
color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25;
|
||||
text-align: left;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.puple {
|
||||
//background-color: rgba(102,126,234,var(--bg-opacity));
|
||||
background-color: #667eea !important;
|
||||
color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25;
|
||||
text-align: left;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.green {
|
||||
//background-color: rgba(56,178,172,var(--bg-opacity));
|
||||
background-color: #38b2ac !important;
|
||||
color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25;
|
||||
text-align: left;
|
||||
margin-bottom: 0.25rem;
|
||||
width: 90%;
|
||||
}
|
||||
.orange {
|
||||
//background-color: rgba(237,137,54,var(--bg-opacity));
|
||||
background-color: #ed8936 !important;
|
||||
color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25;
|
||||
text-align: left;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.pink {
|
||||
//background-color: rgba(237,100,166,var(--bg-opacity));
|
||||
background-color: #ed64a6 !important;
|
||||
color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25;
|
||||
text-align: left;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.grey {
|
||||
background-color: #6d6d6d;
|
||||
color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25;
|
||||
text-align: left;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
409
components/common/Chart.vue
Normal file
@ -0,0 +1,409 @@
|
||||
<template>
|
||||
<div class="chart-wrap">
|
||||
<v-chart
|
||||
class="chart"
|
||||
:option="chartOption"
|
||||
ref="VChart"
|
||||
@click="onClick"
|
||||
@dblclick="onDblClick"
|
||||
@click.right="onRightClick"
|
||||
@legendselectchanged="onLegendSelectChanged"
|
||||
autoresize
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VChart from 'vue-echarts';
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VChart,
|
||||
},
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
widgetId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
widgetData: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
modalId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
modalDataKey: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
chartName: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
chartColor: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
legendSeletedList: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isDarkMode: 'isDarkMode',
|
||||
|
||||
chartOption(state) {
|
||||
var dark_Col = [
|
||||
'#01AE6A',
|
||||
'#FFB046',
|
||||
'#F6637B',
|
||||
'#944FE9',
|
||||
'#4385E3',
|
||||
'#00AA8C',
|
||||
'#FF8808',
|
||||
'#EA5E9A',
|
||||
'#B742D9',
|
||||
'#6363DA',
|
||||
'#79B100',
|
||||
'#D66500',
|
||||
'#DC5ABC',
|
||||
'#764FD7',
|
||||
'#009DD1',
|
||||
'#3BAD43',
|
||||
'#D75E3D',
|
||||
'#CF4DCA',
|
||||
'#A148D9',
|
||||
'#5972DF',
|
||||
];
|
||||
var darkCol_1_5 = [
|
||||
'#01AE6A',
|
||||
'#089362',
|
||||
'#0F7959',
|
||||
'#165E51',
|
||||
'#19514D',
|
||||
];
|
||||
var darkCol_1_10 = [
|
||||
'#01AE6A',
|
||||
'#04A166',
|
||||
'#089362',
|
||||
'#0B865D',
|
||||
'#0F7959',
|
||||
'#126C55',
|
||||
'#165E51',
|
||||
'#19514D',
|
||||
'#1D4448',
|
||||
'#1F3D46',
|
||||
];
|
||||
var darkCol_2_5 = [
|
||||
'#FFB046',
|
||||
'#D39545',
|
||||
'#A77A44',
|
||||
'#7C5F42',
|
||||
'#665242',
|
||||
];
|
||||
var darkCol_2_10 = [
|
||||
'#FFB046',
|
||||
'#EAA345',
|
||||
'#D39545',
|
||||
'#BE8844',
|
||||
'#A77A44',
|
||||
'#926D43',
|
||||
'#7C5F42',
|
||||
'#665242',
|
||||
'#4C4141',
|
||||
'#453D41',
|
||||
];
|
||||
var darkCol_3_5 = [
|
||||
'#F6637B',
|
||||
'#CC576F',
|
||||
'#A24C63',
|
||||
'#784058',
|
||||
'#633B52',
|
||||
];
|
||||
var darkCol_3_10 = [
|
||||
'#F6637B',
|
||||
'#E15D75',
|
||||
'#CC576F',
|
||||
'#B75269',
|
||||
'#A24C63',
|
||||
'#8D465E',
|
||||
'#784058',
|
||||
'#633B52',
|
||||
'#4E354C',
|
||||
'#433249',
|
||||
];
|
||||
var darkCol_4_5 = [
|
||||
'#944FE9',
|
||||
'#7E47C7',
|
||||
'#6740A5',
|
||||
'#513884',
|
||||
'#463473',
|
||||
];
|
||||
var darkCol_4_10 = [
|
||||
'#944FE9',
|
||||
'#894BD8',
|
||||
'#7E47C7',
|
||||
'#7344B7',
|
||||
'#6740A5',
|
||||
'#5C3C95',
|
||||
'#513884',
|
||||
'#463473',
|
||||
'#3A3162',
|
||||
'#352F59',
|
||||
];
|
||||
var darkCol_5_5 = [
|
||||
'#4385E3',
|
||||
'#3D73C2',
|
||||
'#3760A2',
|
||||
'#304E81',
|
||||
'#2D4571',
|
||||
];
|
||||
var darkCol_5_10 = [
|
||||
'#4385E3',
|
||||
'#407CD3',
|
||||
'#3D73C2',
|
||||
'#3A6AB2',
|
||||
'#3760A2',
|
||||
'#345792',
|
||||
'#304E81',
|
||||
'#2D4571',
|
||||
'#2A3B61',
|
||||
'#293758',
|
||||
];
|
||||
var darkCol_dashGauge = [
|
||||
[0.125, '#009245'],
|
||||
[0.25, '#39b54a'],
|
||||
[0.375, '#d9e021'],
|
||||
[0.5, '#fcee21'],
|
||||
[0.625, '#fbb03b'],
|
||||
[0.75, '#f7931e'],
|
||||
[0.875, '#f15a24'],
|
||||
[1.0, '#ed1c24'],
|
||||
];
|
||||
var darkCol_dashUseStatus = ['#2fad35', '#fb8200', '#fb5a8b'];
|
||||
var darkCol_dashTodayUsageCost = ['#01ae6a', '#ffb046', '#f6637b'];
|
||||
var darkCol_dashEnrgUsage = ['#01ae6a', '#4385e3'];
|
||||
var darkCol_dashReadplcStatus = ['#01ae6a', '#ffb046', '#f6637b'];
|
||||
var lightCol_dashReadplcStatus = ['#3cc380', '#ffb13b', '#f98694'];
|
||||
|
||||
var light_Col = [
|
||||
'#3CC380',
|
||||
'#FFB13B',
|
||||
'#F98694',
|
||||
'#CF74E5',
|
||||
'#6A9BF4',
|
||||
'#29BCA2',
|
||||
'#EC8D3B',
|
||||
'#FC749D',
|
||||
'#CF74E5',
|
||||
'#7E84FF',
|
||||
'#83BE01',
|
||||
'#D58B03',
|
||||
'#FF7E71',
|
||||
'#BE6DF0',
|
||||
'#3FAED2',
|
||||
'#5DBF63',
|
||||
'#D1886C',
|
||||
'#ED71B7',
|
||||
'#977EE6',
|
||||
'#7A8EE2',
|
||||
];
|
||||
var lightCol_1_5 = [
|
||||
'#3CC380',
|
||||
'#5BCD94',
|
||||
'#7BD6A9',
|
||||
'#99E0BD',
|
||||
'#B1E7CC',
|
||||
];
|
||||
var lightCol_1_10 = [
|
||||
'#3CC380',
|
||||
'#4BC88A',
|
||||
'#5BCD94',
|
||||
'#6BD19E',
|
||||
'#7BD6A9',
|
||||
'#8ADBB3',
|
||||
'#99E0BD',
|
||||
'#A9E5C7',
|
||||
'#B9E9D1',
|
||||
'#C9EEDC',
|
||||
];
|
||||
var lightCol_2_5 = [
|
||||
'#FFB13B',
|
||||
'#FFBE5B',
|
||||
'#FFCA7A',
|
||||
'#FFD699',
|
||||
'#FFE0B1',
|
||||
];
|
||||
var lightCol_2_10 = [
|
||||
'#FFB13B',
|
||||
'#FFB74A',
|
||||
'#FFBE5B',
|
||||
'#FFC46A',
|
||||
'#FFCA7A',
|
||||
'#FFD089',
|
||||
'#FFD699',
|
||||
'#FFDDA9',
|
||||
'#FFE3B8',
|
||||
'#FFE9C8',
|
||||
];
|
||||
var lightCol_3_5 = [
|
||||
'#F98694',
|
||||
'#FA99A5',
|
||||
'#FBADB6',
|
||||
'#FCC0C7',
|
||||
'#FDCFD4',
|
||||
];
|
||||
var lightCol_3_10 = [
|
||||
'#F98694',
|
||||
'#F98F9C',
|
||||
'#FA99A5',
|
||||
'#FAA3AE',
|
||||
'#FBADB6',
|
||||
'#FBB6BF',
|
||||
'#FCC0C7',
|
||||
'#FCCAD0',
|
||||
'#FDD3D8',
|
||||
'#FDDDE1',
|
||||
];
|
||||
var lightCol_4_5 = [
|
||||
'#CF74E5',
|
||||
'#D78AE9',
|
||||
'#DEA1ED',
|
||||
'#E6B7F1',
|
||||
'#ECC7F5',
|
||||
];
|
||||
var lightCol_4_10 = [
|
||||
'#CF74E5',
|
||||
'#D37FE7',
|
||||
'#D78AE9',
|
||||
'#DA95EB',
|
||||
'#DEA1ED',
|
||||
'#E2ACEF',
|
||||
'#E6B7F1',
|
||||
'#EAC2F4',
|
||||
'#EECDF6',
|
||||
'#F2D8F8',
|
||||
];
|
||||
var lightCol_5_5 = [
|
||||
'#6A9BF4',
|
||||
'#82ABF6',
|
||||
'#9ABBF8',
|
||||
'#B1CBF9',
|
||||
'#C3D7FB',
|
||||
];
|
||||
var lightCol_5_10 = [
|
||||
'#6A9BF4',
|
||||
'#76A3F5',
|
||||
'#82ABF6',
|
||||
'#8EB3F7',
|
||||
'#9ABBF8',
|
||||
'#A6C3F8',
|
||||
'#B1CBF9',
|
||||
'#BED3FA',
|
||||
'#C9DBFB',
|
||||
'#D6E3FC',
|
||||
];
|
||||
var lightCol_dashGauge = [
|
||||
[0.125, '#58c06f'],
|
||||
[0.25, '#7cd574'],
|
||||
[0.375, '#fbe462'],
|
||||
[0.5, '#ffd771'],
|
||||
[0.625, '#ffad7f'],
|
||||
[0.75, '#ff966e'],
|
||||
[0.875, '#ff706e'],
|
||||
[1.0, '#ff6689'],
|
||||
];
|
||||
var lightCol_dashUseStatus = ['#00c875', '#fdab3d', '#ff7b8b'];
|
||||
var lightCol_dashTodayUsageCost = ['#3cc380', '#cf74e5', '#ffb13b'];
|
||||
var lightCol_dashEnrgUsage = ['#ce83e0', '#78a3f3'];
|
||||
var lightCol_dashReadplcStatus = ['#3cc380', '#ffb13b', '#f98694'];
|
||||
|
||||
var tmpChrtOp;
|
||||
if (this.widgetId || this.widgetData) {
|
||||
tmpChrtOp =
|
||||
state.pageData[this.parentPrgmId][this.widgetId][this.widgetData][
|
||||
this.chartName
|
||||
];
|
||||
} else if(this.modalId || this.modalDataKey) {
|
||||
tmpChrtOp =
|
||||
state.pageData[this.parentPrgmId][this.modalId][this.modalDataKey][this.chartName];
|
||||
} else {
|
||||
tmpChrtOp = state.pageData[this.parentPrgmId][this.chartName];
|
||||
}
|
||||
|
||||
if (this.chartColor != undefined) {
|
||||
if (this.isDarkMode) {
|
||||
tmpChrtOp.color = eval('darkCol_' + this.chartColor);
|
||||
} else {
|
||||
tmpChrtOp.color = eval('lightCol_' + this.chartColor);
|
||||
}
|
||||
} else {
|
||||
if (this.isDarkMode) {
|
||||
tmpChrtOp.color = dark_Col;
|
||||
} else {
|
||||
tmpChrtOp.color = light_Col;
|
||||
}
|
||||
}
|
||||
return tmpChrtOp;
|
||||
},
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
onClick(event, instance, ECharts) {
|
||||
console.log('onClick : ', event);
|
||||
this.$emit('click', event);
|
||||
},
|
||||
onDblClick(event, instance, ECharts) {
|
||||
console.log('onDblClick : ', event);
|
||||
this.$emit('dblclick', event);
|
||||
},
|
||||
onRightClick(event, instance, ECharts) {
|
||||
console.log('onRightClick : ', event);
|
||||
this.$emit('rclick', event);
|
||||
},
|
||||
onLegendSelect(params) {
|
||||
const myChart = this.$refs.VChart;
|
||||
for (const key of params) {
|
||||
//차트 instance에 'legendSelect' action 전달
|
||||
myChart.dispatchAction({
|
||||
type: 'legendSelect',
|
||||
name: key,
|
||||
});
|
||||
}
|
||||
},
|
||||
onLegendUnSelect(params) {
|
||||
const myChart = this.$refs.VChart;
|
||||
for (const key of params) {
|
||||
//차트 instance에 'legendUnSelect' action 전달
|
||||
myChart.dispatchAction({
|
||||
type: 'legendUnSelect',
|
||||
name: key,
|
||||
});
|
||||
}
|
||||
},
|
||||
onLegendSelectChanged(params) {
|
||||
const obj = params.selected;
|
||||
this.legendSeletedList = obj;
|
||||
},
|
||||
onGetChangedLegendSeletedList() {
|
||||
return this.legendSeletedList;
|
||||
},
|
||||
onGetLegendSelectedList() {
|
||||
const myChart = this.$refs.VChart;
|
||||
return myChart.getOption().legend[0].selected;
|
||||
},
|
||||
clear() {
|
||||
const myChart = this.$refs.VChart;
|
||||
myChart.clear();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
103
components/common/CheckBox.vue
Normal file
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small :color="required ? '#fb8200' : 'primary'" class="mr-1"
|
||||
>mdi-record-circle</v-icon
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<v-checkbox
|
||||
v-model="chkValue"
|
||||
:disabled="disabledFlag"
|
||||
:readonly="readonly || false"
|
||||
:required="required || false"
|
||||
:false-value="false"
|
||||
:color="isDarkMode ? '#fff' : '#4777d9'"
|
||||
@change="modifyValue"
|
||||
></v-checkbox>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
isDarkMode: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
valueNm: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 7,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chkValue: false,
|
||||
testData: false,
|
||||
disabledFlag: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam: state => state.pageData,
|
||||
myBindingDara(state) {
|
||||
return state.pageData[this.parentPrgmId][this.valueNm];
|
||||
},
|
||||
}),
|
||||
},
|
||||
watch: {
|
||||
myBindingDara: {
|
||||
deep: true,
|
||||
handler(val) {
|
||||
this.chkValue = val;
|
||||
},
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.chkValue = this.searchParam[this.parentPrgmId][this.valueNm];
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
modifyValue(e) {
|
||||
return this.setPageData({ [this.valueNm]: e });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
145
components/common/CheckBoxLabelChange.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="location == 'front'" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon v-if="icon" x-small :color="required ? '#fb8200' : 'primary'" class="mr-1"
|
||||
>mdi-record-circle</v-icon
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="textCols" @click="modifyValue">
|
||||
<v-checkbox
|
||||
v-model="chkValue"
|
||||
:disabled="disabledFlag"
|
||||
:readonly="readonly || false"
|
||||
:required="required || false"
|
||||
:false-value="false"
|
||||
:color="isDarkMode ? '#fff' : '#4777d9'"
|
||||
@change="modifyValue"
|
||||
|
||||
></v-checkbox>
|
||||
</v-col>
|
||||
<v-col v-if="location == 'rear'" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon v-if="icon" x-small :color="required ? '#fb8200' : 'primary'" class="mr-1"
|
||||
>mdi-record-circle</v-icon
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
require: false,
|
||||
},
|
||||
isDarkMode: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
valueNm: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 7,
|
||||
},
|
||||
icon: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: true,
|
||||
},
|
||||
location: {
|
||||
type: String,
|
||||
require: false,
|
||||
default: 'front'
|
||||
},
|
||||
disabledCheckOption: {
|
||||
type: String,
|
||||
require: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chkValue: false,
|
||||
testData: false,
|
||||
disabledFlag: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam: state => state.pageData,
|
||||
myBindingData(state) {
|
||||
return state.pageData[this.parentPrgmId][this.valueNm];
|
||||
},
|
||||
bindingDisabledCheckOption(state) {
|
||||
if(state.pageData[this.parentPrgmId][this.disabledCheckOption]!=undefined){
|
||||
return state.pageData[this.parentPrgmId][this.disabledCheckOption];
|
||||
}
|
||||
|
||||
}
|
||||
}),
|
||||
},
|
||||
watch: {
|
||||
myBindingData: {
|
||||
deep: true,
|
||||
handler(val) {
|
||||
this.chkValue = val;
|
||||
},
|
||||
},
|
||||
bindingDisabledCheckOption(val) {
|
||||
this.disabledFlag = val;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.chkValue = this.searchParam[this.parentPrgmId][this.valueNm];
|
||||
if(this.searchParam[this.parentPrgmId][this.disabledCheckOption]!=undefined){
|
||||
this.disabledFlag = this.searchParam[this.parentPrgmId][this.disabledCheckOption]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
modifyValue(e) {
|
||||
if(this.disabledFlag==true&&e.target != undefined){
|
||||
alert('기간이 한 시간 이내일 경우만 선택할 수 있습니다.')
|
||||
}else{
|
||||
if(e.target == undefined){
|
||||
return this.setPageData({ [this.valueNm]: e });
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
98
components/common/CommonRadio.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<!-- <v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small color="primary" class="mr-1">mdi-record-circle</v-icon>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col> -->
|
||||
<v-radio-group
|
||||
v-model="selected"
|
||||
required:rules="radioRules"
|
||||
row
|
||||
hide-details
|
||||
dense
|
||||
>
|
||||
<v-radio
|
||||
v-for="item in radioList"
|
||||
:key="item.label"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
</v-radio-group>
|
||||
<!-- @change="updateBlocCode($event)" -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations, mapActions } from 'vuex';
|
||||
import Utility from '~/plugins/utility';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 7,
|
||||
},
|
||||
radioList: {
|
||||
type: Array,
|
||||
require: true,
|
||||
},
|
||||
radioValue: {
|
||||
type: String,
|
||||
require: false,
|
||||
default: 'commRadio',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
labelPrepend: true,
|
||||
// selected:"CYC_DAY"
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isDarkMode: 'isDarkMode',
|
||||
searchParam: state => state.pageData,
|
||||
}),
|
||||
selected: {
|
||||
get() {
|
||||
return this.searchParam[this.parentPrgmId][this.radioValue];
|
||||
},
|
||||
set(value) {
|
||||
return this.setPageData({ [this.radioValue]: value });
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selected(value) {
|
||||
// 주기에 따른 오늘 기준 기본 날짜 세팅
|
||||
this.setDefaultDate(value);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// this.setDefaultDate(this.searchParam[this.parentPrgmId].cmCycle);
|
||||
},
|
||||
async mounted() {},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
...mapActions({}),
|
||||
setDefaultDate(value) {
|
||||
this.setPageData({ [this.radioValue]: value });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
442
components/common/Datepicker.vue
Normal file
@ -0,0 +1,442 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small :color="required ? '#fb8200' : 'primary'" class="mr-1"
|
||||
>mdi-record-circle</v-icon
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<div class="datepicker-container">
|
||||
<v-text-field
|
||||
id="startpicker"
|
||||
ref="startpicker"
|
||||
v-model="fromDtValue"
|
||||
:class="isRange ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="startpicker-container" id="startpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<div v-show="isRange" class="mx-3" :style="{ lineHeight: 0 }">~</div>
|
||||
<v-text-field
|
||||
v-show="isRange"
|
||||
id="endpicker"
|
||||
ref="endpicker"
|
||||
v-model="toDtValue"
|
||||
:class="isRange ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="endpicker-container" id="endpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
import TuiDatepicker from 'tui-date-picker';
|
||||
import Utility from '~/plugins/utility';
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
require: false,
|
||||
},
|
||||
timePicker: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 8,
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
isRangeOption:{
|
||||
type:Boolean,
|
||||
require:false,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
today: new Date(),
|
||||
startDatepickerInstance: null,
|
||||
endDatepickerInstance: null,
|
||||
startDtValue: null,
|
||||
endDtValue: null,
|
||||
cmCycleFlag: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam(state) {
|
||||
return state.pageData[this.parentPrgmId];
|
||||
},
|
||||
}),
|
||||
myCmCycle() {
|
||||
return this.searchParam.cmCycle;
|
||||
},
|
||||
myOptions() {
|
||||
let returnObj = {};
|
||||
switch (this.myCmCycle) {
|
||||
case 'CYC_YEAR':
|
||||
returnObj = {
|
||||
type: 'year',
|
||||
viewFormat: 'YYYY',
|
||||
pickerFormat: 'YYYY',
|
||||
sendFormat: 'YYYY',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_MONTH':
|
||||
returnObj = {
|
||||
type: 'month',
|
||||
viewFormat: 'YYYY-MM',
|
||||
pickerFormat: 'YYYY-MM',
|
||||
sendFormat: 'YYYYMM',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_DAY':
|
||||
returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD',
|
||||
pickerFormat: 'yyyy-MM-dd',
|
||||
sendFormat: 'YYYYMMDD',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_HOUR':
|
||||
returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD' + (this.timePicker ? ' HH:mm:ss' : ''),
|
||||
pickerFormat: 'yyyy-MM-dd' + (this.timePicker ? ' HH:mm A' : ''),
|
||||
sendFormat: this.timePicker ? 'YYYY-MM-DD HH:mm:ss' : 'YYYYMMDD',
|
||||
};
|
||||
// returnObj = { type: "day", format: "YYYY-MM-DD HH:mm:ss" };
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return returnObj;
|
||||
},
|
||||
// maxDate() {
|
||||
// return Utility.setFormatDate("today", this.myOptions.format);
|
||||
// },
|
||||
fromDtValue() {
|
||||
return Utility.setFormatDate(
|
||||
this.searchParam.fromDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
},
|
||||
toDtValue() {
|
||||
return Utility.setFormatDate(
|
||||
this.searchParam.toDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
},
|
||||
toDtChange(){
|
||||
return {
|
||||
isCheck:this.searchParam.isCheck ,
|
||||
toDt : Utility.setFormatDate(
|
||||
this.searchParam.toDt,
|
||||
this.myOptions.viewFormat,
|
||||
)};
|
||||
},
|
||||
fromDtChange(){
|
||||
return {
|
||||
isCheck:this.searchParam.isCheck ,
|
||||
fromDt : Utility.setFormatDate(
|
||||
this.searchParam.fromDt,
|
||||
this.myOptions.viewFormat,
|
||||
)};
|
||||
},
|
||||
defaultRange() {
|
||||
return this.searchParam.defaultRange
|
||||
? this.searchParam.defaultRange[this.myCmCycle]
|
||||
: null;
|
||||
},
|
||||
isRange() {
|
||||
return (
|
||||
(this.defaultRange !== null && this.defaultRange > 0 && this.isRangeOption) ||
|
||||
this.defaultRange === 'no limite'
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
myCmCycle() {
|
||||
this.cmCycleFlag = false;
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
this.startDatepickerInstance.setType(this.myOptions.type);
|
||||
this.endDatepickerInstance.setType(this.myOptions.type);
|
||||
},
|
||||
fromDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.toDtValueChkRang(newVal);
|
||||
this.startDatepickerInstance.setDate(new Date(newVal));
|
||||
} else {
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
},
|
||||
toDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.fromDtValueChkRang(newVal);
|
||||
this.endDatepickerInstance.setDate(new Date(newVal));
|
||||
}
|
||||
},
|
||||
fromDtChange:{
|
||||
deep:true,
|
||||
handler(){
|
||||
if(this.fromDtChange.isCheck){
|
||||
this.fromDtChanged(this.fromDtChange.fromDt);
|
||||
this.setPageData({
|
||||
isCheck : false
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
toDtChange:{
|
||||
deep:true,
|
||||
handler(){
|
||||
if(this.toDtChange.isCheck){
|
||||
this.toDtChanged(this.toDtChange.toDt);
|
||||
this.setPageData({
|
||||
isCheck : false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.timePicker) {
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 00:00:00',
|
||||
toDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 23:59:59',
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const startContainer = document.getElementById('startpicker-container');
|
||||
const startTarget = document.getElementById('startpicker');
|
||||
const endContainer = document.getElementById('endpicker-container');
|
||||
const endTarget = document.getElementById('endpicker');
|
||||
|
||||
// datepicker 생성
|
||||
this.startDatepickerInstance = new TuiDatepicker(startContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: startTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성
|
||||
this.endDatepickerInstance = new TuiDatepicker(endContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: endTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성 끝
|
||||
|
||||
// datepicker 초기값 생성
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
// datepicker 초기값 생성 끝
|
||||
|
||||
// datepicker 변경시 이벤트 추가
|
||||
this.startDatepickerInstance.on('change', () => this.getStartDt());
|
||||
this.endDatepickerInstance.on('change', () => this.getEndDt());
|
||||
// datepicker 이벤트는 mount 될때 추가 해주어야 한다.
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
getStartDt() {
|
||||
const dt = this.startDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
getEndDt() {
|
||||
const dt = this.endDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
toDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
toDtChanged(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.fromDtValueChkRang(newVal);
|
||||
this.endDatepickerInstance.setDate(new Date(newVal));
|
||||
}
|
||||
},
|
||||
fromDtChanged(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.toDtValueChkRang(newVal);
|
||||
this.startDatepickerInstance.setDate(new Date(newVal));
|
||||
} else {
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
},
|
||||
fromDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.fromDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = compareDt.diff(defaultDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && compareDt.isAfter(defaultDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
// if(this.cmCycleFlag){
|
||||
this.setPageData({ isFind: true });
|
||||
// }
|
||||
// this.cmCycleFlag = true;
|
||||
} else {
|
||||
this.setPageData({
|
||||
fromDt: Utility.setBeforetDate(
|
||||
this.searchParam,
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
toDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.toDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = defaultDt.diff(compareDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && defaultDt.isAfter(compareDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
this.setPageData({ isFind: true });
|
||||
} else {
|
||||
this.setPageData({
|
||||
toDt: Utility.setAftertDate(
|
||||
this.searchParam,
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.datepicker-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
.v-input {
|
||||
.v-input__append-outer {
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
|
||||
#startpicker-container,
|
||||
#endpicker-container {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 36px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-input__custom {
|
||||
flex: 0 0 auto;
|
||||
&.half {
|
||||
width: calc(50% - 20px);
|
||||
}
|
||||
}
|
||||
::v-deep {
|
||||
.tui-timepicker-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background-color: #edf4fc;
|
||||
.tui-timepicker-column.tui-timepicker-colon {
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
525
components/common/DatepickerTimeSelectBox.vue
Normal file
@ -0,0 +1,525 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small :color="required ? '#fb8200' : 'primary'" class="mr-1"
|
||||
>mdi-record-circle</v-icon
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<div class="datepicker-container">
|
||||
<v-text-field
|
||||
id="startpicker"
|
||||
ref="startpicker"
|
||||
v-model="fromDtValue"
|
||||
:class="(isRange && !selectBoxTimeItemList.selectTimeValue1) ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="startpicker-container" id="startpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<component
|
||||
v-if="selectBoxTimeItemList.selectTimeValue1"
|
||||
:parentPrgmId="parentPrgmId"
|
||||
:is="'SelectBoxTime'"
|
||||
ref="SelectBox1"
|
||||
:propsValue="selectTimeValue1"
|
||||
:itemList="selectTimeValueList1"
|
||||
:minInterval="selectBoxTimeItemList.minInterval ? selectBoxTimeItemList.minInterval : 1"
|
||||
@update:propsValue="selectTimeValue1 = $event"
|
||||
/>
|
||||
<div v-show="isRange" class="mx-3" :style="{ lineHeight: 0 }">~</div>
|
||||
<v-text-field
|
||||
v-show="isRange"
|
||||
id="endpicker"
|
||||
ref="endpicker"
|
||||
v-model="toDtValue"
|
||||
:class="(isRange && !selectBoxTimeItemList.selectTimeValue2) ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="endpicker-container" id="endpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<component
|
||||
v-if="selectBoxTimeItemList.selectTimeValue2"
|
||||
:parentPrgmId="parentPrgmId"
|
||||
:is="'SelectBoxTime'"
|
||||
ref="SelectBox2"
|
||||
:propsValue="selectTimeValue2"
|
||||
:itemList="selectTimeValueList2"
|
||||
:minInterval="selectBoxTimeItemList.minInterval ? selectBoxTimeItemList.minInterval : 1"
|
||||
@update:propsValue="selectTimeValue2 = $event"
|
||||
/>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
import TuiDatepicker from 'tui-date-picker';
|
||||
import Utility from '~/plugins/utility';
|
||||
import SelectBoxTime from '@/components/common/select/SelectBoxTime';
|
||||
import DateUtility from '~/plugins/dateUtility'
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
require: false,
|
||||
},
|
||||
timePicker: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 8,
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
isRangeOption:{
|
||||
type:Boolean,
|
||||
require:false,
|
||||
default: true
|
||||
},
|
||||
selectBoxTimeItemList: {
|
||||
type: Object,
|
||||
require: false,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
selectFromDtUntilTodayFg: {
|
||||
type:Boolean,
|
||||
require:false,
|
||||
default: false
|
||||
},
|
||||
selectToDtUntilTodayFg: {
|
||||
type:Boolean,
|
||||
require:false,
|
||||
default: false
|
||||
},
|
||||
|
||||
},
|
||||
components: {
|
||||
SelectBoxTime
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
today: new Date(),
|
||||
startDatepickerInstance: null,
|
||||
endDatepickerInstance: null,
|
||||
startDtValue: null,
|
||||
endDtValue: null,
|
||||
fromDtOldVal: null,
|
||||
toDtOldVal: null,
|
||||
cmCycleFlag: false,
|
||||
selectTimeValue1: this.selectBoxTimeItemList.selectTimeValue1 != undefined ? this.selectBoxTimeItemList.selectTimeValue1 : null, // selectBoxTime에 필요한 prop
|
||||
selectTimeValueList1: this.selectBoxTimeItemList.selectTimeValueList1 != undefined ? this.selectBoxTimeItemList.selectTimeValueList1 : [], // selectBoxTime에 필요한 prop
|
||||
selectTimeValue2: this.selectBoxTimeItemList.selectTimeValue2 != undefined ? this.selectBoxTimeItemList.selectTimeValue2 : null, // selectBoxTime에 필요한 prop
|
||||
selectTimeValueList2: this.selectBoxTimeItemList.selectTimeValueList2 != undefined ? this.selectBoxTimeItemList.selectTimeValueList2 : [], // selectBoxTime에 필요한 prop
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam(state) {
|
||||
return state.pageData[this.parentPrgmId];
|
||||
},
|
||||
}),
|
||||
myCmCycle() {
|
||||
return this.searchParam.cmCycle;
|
||||
},
|
||||
myOptions() {
|
||||
let returnObj = {};
|
||||
switch (this.myCmCycle) {
|
||||
case 'CYC_YEAR':
|
||||
returnObj = {
|
||||
type: 'year',
|
||||
viewFormat: 'YYYY',
|
||||
pickerFormat: 'YYYY',
|
||||
sendFormat: 'YYYY',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_MONTH':
|
||||
returnObj = {
|
||||
type: 'month',
|
||||
viewFormat: 'YYYY-MM',
|
||||
pickerFormat: 'YYYY-MM',
|
||||
sendFormat: 'YYYYMM',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_DAY':
|
||||
returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD',
|
||||
pickerFormat: 'yyyy-MM-dd',
|
||||
sendFormat: 'YYYYMMDD',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_HOUR':
|
||||
returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD' + (this.timePicker ? ' HH:mm:ss' : ''),
|
||||
pickerFormat: 'yyyy-MM-dd' + (this.timePicker ? ' HH:mm A' : ''),
|
||||
sendFormat: this.timePicker ? 'YYYY-MM-DD HH:mm:ss' : 'YYYYMMDD',
|
||||
};
|
||||
// returnObj = { type: "day", format: "YYYY-MM-DD HH:mm:ss" };
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return returnObj;
|
||||
},
|
||||
// maxDate() {
|
||||
// return Utility.setFormatDate("today", this.myOptions.format);
|
||||
// },
|
||||
fromDtValue(val) {
|
||||
let selectVal = Utility.setFormatDate(
|
||||
this.searchParam.fromDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
if(this.selectFromDtUntilTodayFg){
|
||||
let today = Utility.setFormatDate(new Date(), "YYYY-MM-DD");
|
||||
let dayDiff = DateUtility.diff(selectVal,today,'days');
|
||||
if(dayDiff < 0){
|
||||
alert('오늘 날짜까지 검색이 가능합니다.');
|
||||
selectVal = today;
|
||||
if(this.fromDtOldVal == today){
|
||||
this.toDtValueChkRang(selectVal);
|
||||
this.startDatepickerInstance.setDate(new Date(selectVal));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.fromDtOldVal == null){
|
||||
this.fromDtOldVal = selectVal;
|
||||
}
|
||||
return selectVal;
|
||||
// console.log('fromDtValue!!!',);
|
||||
// return Utility.setFormatDate(
|
||||
// this.searchParam.fromDt,
|
||||
// this.myOptions.viewFormat,
|
||||
// );
|
||||
},
|
||||
toDtValue() {
|
||||
let selectVal = Utility.setFormatDate(
|
||||
this.searchParam.toDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
if(this.selectToDtUntilTodayFg){
|
||||
let today = Utility.setFormatDate(new Date(), "YYYY-MM-DD");
|
||||
let dayDiff = DateUtility.diff(selectVal,today,'days');
|
||||
if(dayDiff < 0){
|
||||
alert('오늘 날짜까지 검색이 가능합니다.');
|
||||
selectVal = today;
|
||||
if(this.toDtOldVal == today){
|
||||
this.fromDtValueChkRang(selectVal);
|
||||
this.endDatepickerInstance.setDate(new Date(selectVal));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(this.toDtOldVal == null){
|
||||
this.toDtOldVal = selectVal;
|
||||
}
|
||||
return selectVal;
|
||||
// return Utility.setFormatDate(
|
||||
// this.searchParam.toDt,
|
||||
// this.myOptions.viewFormat,
|
||||
// );
|
||||
},
|
||||
defaultRange() {
|
||||
return this.searchParam.defaultRange
|
||||
? this.searchParam.defaultRange[this.myCmCycle]
|
||||
: null;
|
||||
},
|
||||
isRange() {
|
||||
return (
|
||||
(this.defaultRange !== null && this.defaultRange > 0 && this.isRangeOption) ||
|
||||
this.defaultRange === 'no limite'
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectTimeValue1(val){
|
||||
if(this.selectBoxTimeItemList.selectTimeValue2 != undefined){
|
||||
this.setSelectTimeValue2(val);
|
||||
}else{
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
},
|
||||
selectTimeValue2(val){
|
||||
this.setSelectTimeValue1(val);
|
||||
// this.setPageData({ isFind: true });
|
||||
},
|
||||
myCmCycle() {
|
||||
this.cmCycleFlag = false;
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
this.startDatepickerInstance.setType(this.myOptions.type);
|
||||
this.endDatepickerInstance.setType(this.myOptions.type);
|
||||
},
|
||||
fromDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.toDtValueChkRang(newVal);
|
||||
this.startDatepickerInstance.setDate(new Date(newVal));
|
||||
this.fromDtOldVal = newVal;
|
||||
this.setSelectTimeValue1(this.selectTimeValue2, 'check');
|
||||
this.setSelectTimeValue2(this.selectTimeValue1, 'check');
|
||||
} else {
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
},
|
||||
toDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.fromDtValueChkRang(newVal);
|
||||
this.endDatepickerInstance.setDate(new Date(newVal));
|
||||
this.toDtOldVal = newVal;
|
||||
this.setSelectTimeValue1(this.selectTimeValue2, 'check');
|
||||
this.setSelectTimeValue2(this.selectTimeValue1, 'check');
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.timePicker) {
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 00:00:00',
|
||||
toDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 23:59:59',
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const startContainer = document.getElementById('startpicker-container');
|
||||
const startTarget = document.getElementById('startpicker');
|
||||
const endContainer = document.getElementById('endpicker-container');
|
||||
const endTarget = document.getElementById('endpicker');
|
||||
|
||||
// datepicker 생성
|
||||
this.startDatepickerInstance = new TuiDatepicker(startContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: startTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성
|
||||
this.endDatepickerInstance = new TuiDatepicker(endContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: endTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성 끝
|
||||
|
||||
// datepicker 초기값 생성
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
// datepicker 초기값 생성 끝
|
||||
|
||||
// datepicker 변경시 이벤트 추가
|
||||
this.startDatepickerInstance.on('change', () => this.getStartDt());
|
||||
this.endDatepickerInstance.on('change', () => this.getEndDt());
|
||||
// datepicker 이벤트는 mount 될때 추가 해주어야 한다.
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
getStartDt() {
|
||||
const dt = this.startDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
getEndDt() {
|
||||
const dt = this.endDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
toDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
fromDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.fromDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = compareDt.diff(defaultDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && compareDt.isAfter(defaultDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
// if(this.cmCycleFlag){
|
||||
this.setPageData({ isFind: true });
|
||||
// }
|
||||
// this.cmCycleFlag = true;
|
||||
} else {
|
||||
this.setPageData({
|
||||
fromDt: Utility.setBeforetDate(
|
||||
this.searchParam,
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
toDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.toDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = defaultDt.diff(compareDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && defaultDt.isAfter(compareDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
this.setPageData({ isFind: true });
|
||||
} else {
|
||||
this.setPageData({
|
||||
toDt: Utility.setAftertDate(
|
||||
this.searchParam,
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
setSelectTimeValue2(val, type='default'){
|
||||
this.setPageData({selectTimeValue1:val});
|
||||
let toDt = this.toDtOldVal;
|
||||
let fromDt = this.fromDtOldVal;
|
||||
let dayDiff = DateUtility.diff(fromDt,toDt,'days');
|
||||
let selectTimeValueList2 = this.selectTimeValueList2.map(item => {
|
||||
return item.value;
|
||||
});
|
||||
if(dayDiff <= 0 && selectTimeValueList2.indexOf(this.selectTimeValue2) < selectTimeValueList2.indexOf(val)){
|
||||
// this.selectTimeValue2 = selectTimeValueList2[selectTimeValueList2.indexOf(val)];
|
||||
this.selectTimeValue2 = val;
|
||||
this.setPageData({selectTimeValue2:val});
|
||||
}else{
|
||||
if(type=='default'){
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
}
|
||||
},
|
||||
setSelectTimeValue1(val, type='default'){
|
||||
this.setPageData({selectTimeValue2:val});
|
||||
let toDt = this.toDtOldVal;
|
||||
let fromDt = this.fromDtOldVal;
|
||||
let dayDiff = DateUtility.diff(fromDt,toDt,'days');
|
||||
let selectTimeValueList2 = this.selectTimeValueList2.map(item => {
|
||||
return item.value;
|
||||
});
|
||||
if(dayDiff <= 0 && selectTimeValueList2.indexOf(val) < selectTimeValueList2.indexOf(this.selectTimeValue1)){
|
||||
// this.selectTimeValue1 = selectTimeValueList2[selectTimeValueList2.indexOf(val)];
|
||||
this.selectTimeValue1 = val;
|
||||
// this.selectTimeValue1 = this.selectTimeValueList2[selectTimeValueList2.indexOf(val) + 1]
|
||||
this.setPageData({selectTimeValue1:val});
|
||||
}else{
|
||||
if(type=='default'){
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.datepicker-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
.v-input {
|
||||
.v-input__append-outer {
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
|
||||
#startpicker-container,
|
||||
#endpicker-container {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 36px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-input__custom {
|
||||
flex: 0 0 auto;
|
||||
&.half {
|
||||
width: calc(50% - 20px);
|
||||
}
|
||||
}
|
||||
::v-deep {
|
||||
.tui-timepicker-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background-color: #edf4fc;
|
||||
.tui-timepicker-column.tui-timepicker-colon {
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
442
components/common/DatepickerTopView.vue
Normal file
@ -0,0 +1,442 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small :color="required ? '#fb8200' : 'primary'" class="mr-1"
|
||||
>mdi-record-circle</v-icon
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<div class="datepicker-container">
|
||||
<v-text-field
|
||||
id="startpicker"
|
||||
ref="startpicker"
|
||||
v-model="fromDtValue"
|
||||
:class="isRange ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="startpicker-container" id="startpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<div v-show="isRange" class="mx-3" :style="{ lineHeight: 0 }">~</div>
|
||||
<v-text-field
|
||||
v-show="isRange"
|
||||
id="endpicker"
|
||||
ref="endpicker"
|
||||
v-model="toDtValue"
|
||||
:class="isRange ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="endpicker-container" id="endpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
import TuiDatepicker from 'tui-date-picker';
|
||||
import Utility from '~/plugins/utility';
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
require: false,
|
||||
},
|
||||
timePicker: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 8,
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
isRangeOption:{
|
||||
type:Boolean,
|
||||
require:false,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
today: new Date(),
|
||||
startDatepickerInstance: null,
|
||||
endDatepickerInstance: null,
|
||||
startDtValue: null,
|
||||
endDtValue: null,
|
||||
cmCycleFlag: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam(state) {
|
||||
return state.pageData[this.parentPrgmId];
|
||||
},
|
||||
}),
|
||||
myCmCycle() {
|
||||
return this.searchParam.cmCycle;
|
||||
},
|
||||
myOptions() {
|
||||
let returnObj = {};
|
||||
switch (this.myCmCycle) {
|
||||
case 'CYC_YEAR':
|
||||
returnObj = {
|
||||
type: 'year',
|
||||
viewFormat: 'YYYY',
|
||||
pickerFormat: 'YYYY',
|
||||
sendFormat: 'YYYY',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_MONTH':
|
||||
returnObj = {
|
||||
type: 'month',
|
||||
viewFormat: 'YYYY-MM',
|
||||
pickerFormat: 'YYYY-MM',
|
||||
sendFormat: 'YYYYMM',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_DAY':
|
||||
returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD',
|
||||
pickerFormat: 'yyyy-MM-dd',
|
||||
sendFormat: 'YYYYMMDD',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_HOUR':
|
||||
returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD' + (this.timePicker ? ' HH:mm:ss' : ''),
|
||||
pickerFormat: 'yyyy-MM-dd' + (this.timePicker ? ' HH:mm A' : ''),
|
||||
sendFormat: this.timePicker ? 'YYYY-MM-DD HH:mm:ss' : 'YYYYMMDD',
|
||||
};
|
||||
// returnObj = { type: "day", format: "YYYY-MM-DD HH:mm:ss" };
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return returnObj;
|
||||
},
|
||||
// maxDate() {
|
||||
// return Utility.setFormatDate("today", this.myOptions.format);
|
||||
// },
|
||||
fromDtValue() {
|
||||
return Utility.setFormatDate(
|
||||
this.searchParam.fromDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
},
|
||||
toDtValue() {
|
||||
return Utility.setFormatDate(
|
||||
this.searchParam.toDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
},
|
||||
toDtChange(){
|
||||
return {
|
||||
isCheck:this.searchParam.isCheck ,
|
||||
toDt : Utility.setFormatDate(
|
||||
this.searchParam.toDt,
|
||||
this.myOptions.viewFormat,
|
||||
)};
|
||||
},
|
||||
fromDtChange(){
|
||||
return {
|
||||
isCheck:this.searchParam.isCheck ,
|
||||
fromDt : Utility.setFormatDate(
|
||||
this.searchParam.fromDt,
|
||||
this.myOptions.viewFormat,
|
||||
)};
|
||||
},
|
||||
defaultRange() {
|
||||
return this.searchParam.defaultRange
|
||||
? this.searchParam.defaultRange[this.myCmCycle]
|
||||
: null;
|
||||
},
|
||||
isRange() {
|
||||
return (
|
||||
(this.defaultRange !== null && this.defaultRange > 0 && this.isRangeOption) ||
|
||||
this.defaultRange === 'no limite'
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
myCmCycle() {
|
||||
this.cmCycleFlag = false;
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
this.startDatepickerInstance.setType(this.myOptions.type);
|
||||
this.endDatepickerInstance.setType(this.myOptions.type);
|
||||
},
|
||||
fromDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.toDtValueChkRang(newVal);
|
||||
this.startDatepickerInstance.setDate(new Date(newVal));
|
||||
} else {
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
},
|
||||
toDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.fromDtValueChkRang(newVal);
|
||||
this.endDatepickerInstance.setDate(new Date(newVal));
|
||||
}
|
||||
},
|
||||
fromDtChange:{
|
||||
deep:true,
|
||||
handler(){
|
||||
if(this.fromDtChange.isCheck){
|
||||
this.fromDtChanged(this.fromDtChange.fromDt);
|
||||
this.setPageData({
|
||||
isCheck : false
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
toDtChange:{
|
||||
deep:true,
|
||||
handler(){
|
||||
if(this.toDtChange.isCheck){
|
||||
this.toDtChanged(this.toDtChange.toDt);
|
||||
this.setPageData({
|
||||
isCheck : false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.timePicker) {
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 00:00:00',
|
||||
toDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 23:59:59',
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const startContainer = document.getElementById('startpicker-container');
|
||||
const startTarget = document.getElementById('startpicker');
|
||||
const endContainer = document.getElementById('endpicker-container');
|
||||
const endTarget = document.getElementById('endpicker');
|
||||
|
||||
// datepicker 생성
|
||||
this.startDatepickerInstance = new TuiDatepicker(startContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: startTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성
|
||||
this.endDatepickerInstance = new TuiDatepicker(endContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: endTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성 끝
|
||||
|
||||
// datepicker 초기값 생성
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
// datepicker 초기값 생성 끝
|
||||
|
||||
// datepicker 변경시 이벤트 추가
|
||||
this.startDatepickerInstance.on('change', () => this.getStartDt());
|
||||
this.endDatepickerInstance.on('change', () => this.getEndDt());
|
||||
// datepicker 이벤트는 mount 될때 추가 해주어야 한다.
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
getStartDt() {
|
||||
const dt = this.startDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
getEndDt() {
|
||||
const dt = this.endDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
toDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
toDtChanged(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.fromDtValueChkRang(newVal);
|
||||
this.endDatepickerInstance.setDate(new Date(newVal));
|
||||
}
|
||||
},
|
||||
fromDtChanged(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.toDtValueChkRang(newVal);
|
||||
this.startDatepickerInstance.setDate(new Date(newVal));
|
||||
} else {
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
},
|
||||
fromDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.fromDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = compareDt.diff(defaultDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && compareDt.isAfter(defaultDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
// if(this.cmCycleFlag){
|
||||
this.setPageData({ isFind: true });
|
||||
// }
|
||||
// this.cmCycleFlag = true;
|
||||
} else {
|
||||
this.setPageData({
|
||||
fromDt: Utility.setBeforetDate(
|
||||
this.searchParam,
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
toDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.toDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = defaultDt.diff(compareDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && defaultDt.isAfter(compareDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
this.setPageData({ isFind: true });
|
||||
} else {
|
||||
this.setPageData({
|
||||
toDt: Utility.setAftertDate(
|
||||
this.searchParam,
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.datepicker-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
.v-input {
|
||||
.v-input__append-outer {
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
|
||||
#startpicker-container,
|
||||
#endpicker-container {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: -260px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-input__custom {
|
||||
flex: 0 0 auto;
|
||||
&.half {
|
||||
width: calc(50% - 20px);
|
||||
}
|
||||
}
|
||||
::v-deep {
|
||||
.tui-timepicker-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background-color: #edf4fc;
|
||||
.tui-timepicker-column.tui-timepicker-colon {
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
396
components/common/DatepickerWidget.vue
Normal file
@ -0,0 +1,396 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small color="primary" class="mr-1">mdi-record-circle</v-icon>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<div class="datepicker-container">
|
||||
<v-text-field
|
||||
id="startpicker"
|
||||
ref="startpicker"
|
||||
v-model="fromDtValue"
|
||||
:class="isRange ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="startpicker-container" id="startpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<div v-show="isRange" class="mx-3" :style="{ lineHeight: 0 }">~</div>
|
||||
<v-text-field
|
||||
v-show="isRange"
|
||||
id="endpicker"
|
||||
ref="endpicker"
|
||||
v-model="toDtValue"
|
||||
:class="isRange ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="endpicker-container" id="endpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
import TuiDatepicker from 'tui-date-picker';
|
||||
import Utility from '~/plugins/utility';
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
require: false,
|
||||
},
|
||||
timePicker: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 8,
|
||||
},
|
||||
widgetPage: {
|
||||
type: String,
|
||||
require: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
today: new Date(),
|
||||
startDatepickerInstance: null,
|
||||
endDatepickerInstance: null,
|
||||
startDtValue: null,
|
||||
endDtValue: null,
|
||||
cmCycleFlag: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam(state) {
|
||||
return state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
];
|
||||
},
|
||||
}),
|
||||
myCmCycle() {
|
||||
return this.$store.state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
].cmCycle;
|
||||
},
|
||||
myOptions() {
|
||||
let returnObj = {};
|
||||
switch (this.myCmCycle) {
|
||||
case 'CYC_YEAR':
|
||||
returnObj = {
|
||||
type: 'year',
|
||||
viewFormat: 'YYYY',
|
||||
pickerFormat: 'YYYY',
|
||||
sendFormat: 'YYYY',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_MONTH':
|
||||
returnObj = {
|
||||
type: 'month',
|
||||
viewFormat: 'YYYY-MM',
|
||||
pickerFormat: 'YYYY-MM',
|
||||
sendFormat: 'YYYYMM',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_DAY':
|
||||
returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD',
|
||||
pickerFormat: 'yyyy-MM-dd',
|
||||
sendFormat: 'YYYYMMDD',
|
||||
};
|
||||
break;
|
||||
|
||||
case 'CYC_HOUR':
|
||||
returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD' + (this.timePicker ? ' HH:mm:ss' : ''),
|
||||
pickerFormat: 'yyyy-MM-dd' + (this.timePicker ? ' HH:mm A' : ''),
|
||||
sendFormat: this.timePicker ? 'YYYY-MM-DD HH:mm:ss' : 'YYYYMMDD',
|
||||
};
|
||||
// returnObj = { type: "day", format: "YYYY-MM-DD HH:mm:ss" };
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return returnObj;
|
||||
},
|
||||
// maxDate() {
|
||||
// return Utility.setFormatDate("today", this.myOptions.format);
|
||||
// },
|
||||
fromDtValue() {
|
||||
return Utility.setFormatDate(
|
||||
this.$store.state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
].fromDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
},
|
||||
toDtValue() {
|
||||
return Utility.setFormatDate(
|
||||
// this.$store.state.pageData[this.parentPrgmId][this.widgetPage][this.widgetPage+'Data'].toDt,
|
||||
this.$store.state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
].toDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
},
|
||||
defaultRange() {
|
||||
return this.$store.state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
].defaultRange
|
||||
? this.$store.state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
].defaultRange[this.myCmCycle]
|
||||
: null;
|
||||
},
|
||||
isRange() {
|
||||
return (
|
||||
(this.defaultRange !== null && this.defaultRange > 0) ||
|
||||
this.defaultRange === 'no limite'
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
myCmCycle() {
|
||||
this.cmCycleFlag = false;
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
this.startDatepickerInstance.setType(this.myOptions.type);
|
||||
this.endDatepickerInstance.setType(this.myOptions.type);
|
||||
},
|
||||
fromDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.toDtValueChkRang(newVal);
|
||||
this.startDatepickerInstance.setDate(new Date(newVal));
|
||||
} else {
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
},
|
||||
toDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.fromDtValueChkRang(newVal);
|
||||
this.endDatepickerInstance.setDate(new Date(newVal));
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.timePicker) {
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 00:00:00',
|
||||
toDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 23:59:59',
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const startContainer = document.getElementById('startpicker-container');
|
||||
const startTarget = document.getElementById('startpicker');
|
||||
const endContainer = document.getElementById('endpicker-container');
|
||||
const endTarget = document.getElementById('endpicker');
|
||||
|
||||
// datepicker 생성
|
||||
this.startDatepickerInstance = new TuiDatepicker(startContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: startTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성
|
||||
this.endDatepickerInstance = new TuiDatepicker(endContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: endTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성 끝
|
||||
|
||||
// datepicker 초기값 생성
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
// datepicker 초기값 생성 끝
|
||||
|
||||
// datepicker 변경시 이벤트 추가
|
||||
this.startDatepickerInstance.on('change', () => this.getStartDt());
|
||||
this.endDatepickerInstance.on('change', () => this.getEndDt());
|
||||
// datepicker 이벤트는 mount 될때 추가 해주어야 한다.
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
getStartDt() {
|
||||
const dt = this.startDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
getEndDt() {
|
||||
const dt = this.endDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
toDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
fromDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.fromDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = compareDt.diff(defaultDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && compareDt.isAfter(defaultDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
// if(this.cmCycleFlag){
|
||||
this.setPageData({ isFind: true });
|
||||
// }
|
||||
// this.cmCycleFlag = true;
|
||||
} else {
|
||||
// this.setPageData({
|
||||
// fromDt: Utility.setBeforetDate(
|
||||
// this.$store.state.pageData[this.parentPrgmId][this.widgetPage][this.widgetPage+'Data'].fromDt,
|
||||
// compareDt,
|
||||
// this.myOptions.sendFormat
|
||||
// )
|
||||
// });
|
||||
this.$store.state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
].fromDt = Utility.setBeforetDate(
|
||||
this.$store.state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
],
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
);
|
||||
}
|
||||
},
|
||||
toDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.toDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = defaultDt.diff(compareDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && defaultDt.isAfter(compareDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
this.setPageData({ isFind: true });
|
||||
} else {
|
||||
this.setPageData({
|
||||
toDt: Utility.setAftertDate(
|
||||
this.$store.state.pageData[this.parentPrgmId][this.widgetPage][
|
||||
this.widgetPage + 'Data'
|
||||
],
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.datepicker-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
.v-input {
|
||||
.v-input__append-outer {
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
|
||||
#startpicker-container,
|
||||
#endpicker-container {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 36px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-input__custom {
|
||||
flex: 0 0 auto;
|
||||
&.half {
|
||||
width: calc(50% - 20px);
|
||||
}
|
||||
}
|
||||
::v-deep {
|
||||
.tui-timepicker-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background-color: #edf4fc;
|
||||
.tui-timepicker-column.tui-timepicker-colon {
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
711
components/common/Grid.vue
Normal file
@ -0,0 +1,711 @@
|
||||
<template>
|
||||
<tui-grid
|
||||
:ref="['tuigrid' + gridName]"
|
||||
:data="chkGridData"
|
||||
:columns="chkGridColumns"
|
||||
:options="chkGridOptions"
|
||||
@focusChange="focusChangeEvt"
|
||||
@click="startEditing"
|
||||
@editingFinish="editingFinish"
|
||||
@dblclick="dblClick"
|
||||
@mouseover="mouseoverEvent"
|
||||
@mouseout="mouseoutEvent"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
gridName: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
dataPath: {
|
||||
type: Object,
|
||||
require: false,
|
||||
default: null,
|
||||
},
|
||||
editorGrid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
require: false,
|
||||
},
|
||||
innerTabGridInfo: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
selectedRowDataWatchFlag: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
preventFocusChangeEventFlag: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
// gridInstance Array
|
||||
preventFocusChangeEventTargetGridList: {
|
||||
type: Array,
|
||||
require: false,
|
||||
default: null,
|
||||
},
|
||||
columnClickEventFlag: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
mouseoverEvent: {
|
||||
type: Function,
|
||||
default() {
|
||||
return 'Default Function';
|
||||
},
|
||||
},
|
||||
mouseoutEvent: {
|
||||
type: Function,
|
||||
default() {
|
||||
return 'Default Function';
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
gridInstance: null,
|
||||
gridHeight: null,
|
||||
selecrRowKey: null,
|
||||
originData: [],
|
||||
editorStartKey: null,
|
||||
editorEndKey: null,
|
||||
scrollBody: null,
|
||||
gridScrollTop: 0,
|
||||
gridScrollLeft: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
pageData: state => state.pageData,
|
||||
gridData(state) {
|
||||
return this.dataPath
|
||||
? this.dataPath[this.gridName]
|
||||
: state.pageData[this.parentPrgmId][this.gridName];
|
||||
},
|
||||
drawer: state => state.drawer,
|
||||
activePrgmId(state) {
|
||||
return state.activeMenuInfo.prgmId;
|
||||
},
|
||||
}),
|
||||
chkGridData() {
|
||||
// return this.pageData[this.parentPrgmId][this.gridName].data;
|
||||
return this.gridData.data;
|
||||
},
|
||||
chkGridColumns() {
|
||||
return this.gridData.column;
|
||||
},
|
||||
chkGridOptions() {
|
||||
const options = {
|
||||
...this.gridData.option,
|
||||
};
|
||||
options.treeColumnOptions = {
|
||||
useIcon: false,
|
||||
...options.treeColumnOptions,
|
||||
};
|
||||
|
||||
return options;
|
||||
},
|
||||
defaultRow() {
|
||||
return this.gridData.defaultRow;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
chkGridData(val) {
|
||||
this.$refs['tuigrid' + this.gridName].invoke('resetData', val);
|
||||
},
|
||||
innerTabGridInfo(val) {
|
||||
const _this = this;
|
||||
setTimeout(() => {
|
||||
_this.refreshLayout();
|
||||
}, 500);
|
||||
},
|
||||
activePrgmId(val) {
|
||||
const _this = this;
|
||||
setTimeout(() => {
|
||||
_this.refreshLayout();
|
||||
}, 700);
|
||||
if (val == this.parentPrgmId) {
|
||||
setTimeout(() => {
|
||||
if (!_this.innerTabGridInfo) {
|
||||
//_this.refreshLayout();
|
||||
_this.scrollBody.scrollTop = _this.gridScrollTop;
|
||||
_this.scrollBody.scrollLeft = _this.gridScrollLeft;
|
||||
} else {
|
||||
if (_this.innerTabGridInfo.tab == _this.innerTabGridInfo.idx) {
|
||||
//_this.refreshLayout();
|
||||
_this.scrollBody.scrollTop = _this.gridScrollTop;
|
||||
_this.scrollBody.scrollLeft = _this.gridScrollLeft;
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
},
|
||||
drawer() {
|
||||
const _this = this;
|
||||
setTimeout(() => {
|
||||
_this.refreshLayout();
|
||||
}, 500);
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
async mounted() {
|
||||
// console.log(this.dataPath);
|
||||
if (this.gridName) {
|
||||
this.gridInstance = this.$refs['tuigrid' + this.gridName];
|
||||
|
||||
this.scrollBody = document
|
||||
.getElementsByClassName('tui-grid-rside-area')
|
||||
[
|
||||
document.getElementsByClassName('tui-grid-rside-area').length - 1
|
||||
].getElementsByClassName('tui-grid-body-area')[0];
|
||||
|
||||
this.scrollBody.addEventListener('scroll', e => {
|
||||
this.gridScrollTop = e.target.scrollTop;
|
||||
this.gridScrollLeft = e.target.scrollLeft;
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
setPageData: 'setPageData',
|
||||
setGridData: 'setGridData',
|
||||
}),
|
||||
// true : 현재 행 혹은 연결된 그리드가 수정중인 상태
|
||||
checkGridState() {
|
||||
var rowStatList = ['I', 'U', 'D'];
|
||||
var row = this.gridInstance.invoke('getFocusedCell');
|
||||
|
||||
if (row) {
|
||||
var rowData = this.gridInstance.invoke('getRow', row.rowKey);
|
||||
if (rowData) {
|
||||
var rowStat = rowData['rowStat'];
|
||||
if (rowStatList.includes(rowStat)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.preventFocusChangeEventTargetGridList) {
|
||||
for (var gridInstance of this.preventFocusChangeEventTargetGridList) {
|
||||
var dataArr = gridInstance.save();
|
||||
|
||||
if (dataArr.length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
preventFocusChangeEvent(e) {
|
||||
var result = false;
|
||||
|
||||
if (this.preventFocusChangeEventFlag) {
|
||||
if (this.checkGridState()) {
|
||||
e.stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
columnClickEvent(e) {
|
||||
var result = false;
|
||||
|
||||
if (this.columnClickEventFlag) {
|
||||
return true;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getCheckedRowsEvt() {
|
||||
const checkedRowDataList = this.gridInstance.invoke('getCheckedRows');
|
||||
return checkedRowDataList;
|
||||
},
|
||||
dblClick(nativeEvent) {
|
||||
if (this.preventFocusChangeEvent(nativeEvent)) {
|
||||
return;
|
||||
}
|
||||
this.$emit(
|
||||
'dblClick',
|
||||
this.gridInstance.invoke('dblclick'),
|
||||
nativeEvent,
|
||||
this.gridName,
|
||||
);
|
||||
},
|
||||
uncheckEvt(rowData, instance) {
|
||||
this.gridInstance.invoke('uncheck', rowData.rowKey, instance);
|
||||
},
|
||||
checkEvt(rowData, instance) {
|
||||
this.gridInstance.invoke('check', rowData.rowKey, instance);
|
||||
},
|
||||
setSelectionRange(rowKey) {
|
||||
const rowDatas = this.gridInstance.invoke('getData');
|
||||
rowDatas.forEach(item => {
|
||||
if (item.rowKey == rowKey) {
|
||||
this.gridInstance.invoke(
|
||||
'addRowClassName',
|
||||
item.rowKey,
|
||||
'row-selected',
|
||||
);
|
||||
} else {
|
||||
this.gridInstance.invoke(
|
||||
'removeRowClassName',
|
||||
item.rowKey,
|
||||
'row-selected',
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
focusChangeEvt(e) {
|
||||
// console.log('focusChangeEvt1...')
|
||||
if (this.preventFocusChangeEvent(e)) {
|
||||
// console.log('prevent focusChangeEvt')
|
||||
return;
|
||||
}
|
||||
// console.log('focusChangeEvt2...')
|
||||
// cell 선택시 row 선택 method
|
||||
if (e.rowKey >= 0) {
|
||||
this.$emit(
|
||||
'getRowsData',
|
||||
this.gridInstance.invoke('getRow', e.rowKey),
|
||||
this.gridName,
|
||||
e.columnName,
|
||||
);
|
||||
this.selecrRowKey = e.rowKey;
|
||||
this.setSelectionRange(e.rowKey);
|
||||
}
|
||||
this.sendSelectedRowData(e.rowKey);
|
||||
},
|
||||
startEditing(e) {
|
||||
// console.log('startEditing1...')
|
||||
if (this.preventFocusChangeEvent(e)) {
|
||||
// console.log('prevent startEditing')
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.columnClickEvent(e)) {
|
||||
this.$emit('columnClick', e, this.gridName);
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log('startEditing2...')
|
||||
if (this.editorGrid && e.rowKey >= 0) {
|
||||
this.editorStartKey = e.rowKey;
|
||||
// console.log("E::", this.gridInstance.invoke("getRow", e.rowKey));
|
||||
this.gridInstance.invoke('startEditing', e.rowKey, e.columnName);
|
||||
this.$emit(
|
||||
'getRowsData',
|
||||
this.gridInstance.invoke('getRow', e.rowKey),
|
||||
this.gridName,
|
||||
e.columnName,
|
||||
);
|
||||
this.setSelectionRange(e.rowKey);
|
||||
}
|
||||
},
|
||||
async editingFinish(e) {
|
||||
// console.log("Editing END E::", e);
|
||||
// editor 간 이동시 수정되는 문제 수정
|
||||
// e.rowEditingFg: grid의 한 row를 한번에 수정할 시 각각의 cell 마다 click 이벤트가 발생하지 않아 this.editorStartKey값이 제대로 입력 되지 않는 경우를 대비하여 만든 Fg
|
||||
if (this.editorGrid) {
|
||||
this.editorEndKey = Number.isInteger(e.rowKey) ? e.rowKey : null;
|
||||
if (e.rowEditingFg == undefined && this.editorStartKey >= 0) {
|
||||
if (this.editorStartKey != this.editorEndKey) {
|
||||
this.editorStartKey = null;
|
||||
this.editorEndKey = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
const rowIdxKey = this.editorGrid ? this.editorEndKey : this.gridInstance.invoke('getFocusedCell').rowKey
|
||||
// editor 간 이동시 수정되는 문제 수정 끝
|
||||
|
||||
const columnName = e.columnName;
|
||||
const value = e.value;
|
||||
const editingData = {
|
||||
...e,
|
||||
rowKey: rowIdxKey,
|
||||
};
|
||||
const isBaseRow = this.isBaseDataRow(rowIdxKey);
|
||||
// console.log("END E::", rowIdxKey, e);
|
||||
const rowStat = this.gridInstance.invoke('getRow', rowIdxKey).rowStat;
|
||||
if (rowStat == 'D') {
|
||||
this.gridInstance.invoke(
|
||||
'removeRowClassName',
|
||||
rowIdxKey,
|
||||
'row-removed',
|
||||
);
|
||||
}
|
||||
|
||||
await this.gridInstance.invoke(
|
||||
e.rowEditingFg != undefined ? 'setValue' : this.editorGrid ? 'finishEditing' : 'setValue',
|
||||
rowIdxKey,
|
||||
columnName,
|
||||
value,
|
||||
);
|
||||
|
||||
|
||||
if (isBaseRow) {
|
||||
const isSameData = await this.compareData(editingData);
|
||||
if (isSameData) {
|
||||
this.gridInstance.invoke(
|
||||
'removeRowClassName',
|
||||
rowIdxKey,
|
||||
'row-modify',
|
||||
);
|
||||
this.updateData('clear', rowIdxKey);
|
||||
} else {
|
||||
this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-modify');
|
||||
this.updateData('modify', rowIdxKey);
|
||||
}
|
||||
}
|
||||
if (
|
||||
e.ignoreUpdateDataInfoFlag === undefined ||
|
||||
e.ignoreUpdateDataInfoFlag === false
|
||||
) {
|
||||
this.$emit('updateDataInfo', {
|
||||
rowIdxKey: rowIdxKey,
|
||||
rowStat: rowStat,
|
||||
columnName: columnName,
|
||||
value: value,
|
||||
rowData: this.gridInstance.invoke('getRow', rowIdxKey),
|
||||
});
|
||||
}
|
||||
this.sendSelectedRowData();
|
||||
},
|
||||
async addRow(setData, argRowKey) {
|
||||
// 그리드가 수정중인 상태면 addRow를 하지 않음
|
||||
if (this.preventFocusChangeEventFlag) {
|
||||
if (this.checkGridState()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const addData = !setData
|
||||
? this.defaultRow
|
||||
: Object.assign(this.defaultRow, setData);
|
||||
// 열 앞에 데이터 추가
|
||||
// if (argRowKey != undefined && argRowKey != null) {
|
||||
this.gridInstance.invoke('appendRow', addData, {
|
||||
focus: true,
|
||||
});
|
||||
// } else {
|
||||
// this.gridInstance.invoke('prependRow', addData, {
|
||||
// focus: true,
|
||||
// });
|
||||
// }
|
||||
// this.gridInstance.invoke('prependRow', addData, {
|
||||
// focus: true,
|
||||
// });
|
||||
this.$nextTick(() => {
|
||||
var addRowKey = this.gridInstance.invoke('getFocusedCell').rowKey;
|
||||
if (argRowKey) {
|
||||
addRowKey = argRowKey;
|
||||
}
|
||||
this.gridInstance.invoke(
|
||||
'removeRowClassName',
|
||||
addRowKey,
|
||||
'row-removed',
|
||||
);
|
||||
this.gridInstance.invoke('addRowClassName', addRowKey, 'row-insert');
|
||||
this.updateData('insert', addRowKey);
|
||||
});
|
||||
},
|
||||
async appendRow() {
|
||||
this.gridInstance.invoke('appendRow', {
|
||||
focus: true,
|
||||
});
|
||||
},
|
||||
async addTreeRow(setData) {
|
||||
// tree append의 경우 무한루프가 발행하는 버그현상으로 appendRows로 추가
|
||||
const addData = !setData
|
||||
? this.defaultRow
|
||||
: Object.assign(this.defaultRow, setData);
|
||||
|
||||
this.gridInstance.invoke('appendRows', [addData]);
|
||||
this.$nextTick(() => {
|
||||
const rowDatas = this.gridInstance.invoke('getData');
|
||||
const addRowKey = rowDatas[rowDatas.length - 1].rowKey;
|
||||
this.gridInstance.invoke(
|
||||
'removeRowClassName',
|
||||
addRowKey,
|
||||
'row-removed',
|
||||
);
|
||||
this.gridInstance.invoke('addRowClassName', addRowKey, 'row-insert');
|
||||
this.updateData('insert', addRowKey);
|
||||
this.gridInstance.invoke('focus', addRowKey);
|
||||
});
|
||||
},
|
||||
async removeRow(delType, argRowKey) {
|
||||
var rowIdxKey = this.gridInstance.invoke('getFocusedCell').rowKey;
|
||||
if (typeof argRowKey == 'number') {
|
||||
rowIdxKey = argRowKey;
|
||||
}
|
||||
const rowStat = this.gridInstance.invoke('getRow', rowIdxKey).rowStat;
|
||||
if (rowStat === 'D') {
|
||||
this.gridInstance.invoke(
|
||||
'removeRowClassName',
|
||||
rowIdxKey,
|
||||
'row-removed',
|
||||
);
|
||||
this.updateData('clear', rowIdxKey);
|
||||
} else {
|
||||
if (!this.isBaseDataRow(rowIdxKey)) {
|
||||
this.gridInstance.invoke('removeRow', rowIdxKey);
|
||||
let nextFocus = Number(rowIdxKey) - 1;
|
||||
if (!this.isBaseDataRow(nextFocus)) nextFocus = 0;
|
||||
this.gridInstance.invoke('focus', nextFocus);
|
||||
} else {
|
||||
this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-removed');
|
||||
this.updateData('delete', rowIdxKey);
|
||||
|
||||
if (delType == 'immediately')
|
||||
this.gridInstance.invoke('removeRow', rowIdxKey);
|
||||
}
|
||||
}
|
||||
},
|
||||
async removeTreeRow(delType) {
|
||||
const rowIdxKey = this.gridInstance.invoke('getFocusedCell').rowKey;
|
||||
const rowStat = this.gridInstance.invoke('getRow', rowIdxKey).rowStat;
|
||||
if (rowStat === 'D') {
|
||||
this.gridInstance.invoke(
|
||||
'removeRowClassName',
|
||||
rowIdxKey,
|
||||
'row-removed',
|
||||
);
|
||||
this.updateData('clear', rowIdxKey);
|
||||
} else {
|
||||
if (!this.isBaseDataRow(rowIdxKey)) {
|
||||
this.updateData('clear', rowIdxKey);
|
||||
this.gridInstance.invoke('removeRow', rowIdxKey);
|
||||
let nextFocus = Number(rowIdxKey) - 1;
|
||||
if (!this.isBaseDataRow(nextFocus)) nextFocus = 0;
|
||||
this.gridInstance.invoke('focus', nextFocus);
|
||||
} else {
|
||||
this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-removed');
|
||||
this.updateData('delete', rowIdxKey);
|
||||
|
||||
if (delType == 'immediately')
|
||||
this.gridInstance.invoke('removeRow', rowIdxKey);
|
||||
}
|
||||
}
|
||||
},
|
||||
isBaseDataRow(rowKey) {
|
||||
// 기존데이터 여부 확인 (추가된 데이터 X)
|
||||
const findRow = this.gridInstance.invoke('findRows', { rowKey: rowKey });
|
||||
return findRow && findRow[0] && findRow[0].rowStat != 'I' ? true : false;
|
||||
},
|
||||
compareData(data) {
|
||||
// rowStat key값 제거
|
||||
const dataKeyArr = Object.keys(this.defaultRow);
|
||||
const rowStatIdx = dataKeyArr.indexOf('rowStat');
|
||||
dataKeyArr.splice(rowStatIdx, 1);
|
||||
// rowStat key값 제거 끝
|
||||
|
||||
const selectedRowData = this.gridInstance.invoke('getRow', data.rowKey);
|
||||
this.getOriginData();
|
||||
|
||||
const rowData = this.originData.find(item => {
|
||||
return item.rowKey == data.rowKey;
|
||||
});
|
||||
let count = 0;
|
||||
// console.log("dataKeyArr", dataKeyArr);
|
||||
// console.log("selectedRowData", selectedRowData);
|
||||
for (let i = 0; i < dataKeyArr.length; i++) {
|
||||
// console.log(dataKeyArr[i], selectedRowData[dataKeyArr[i]], rowData[dataKeyArr[i]]);
|
||||
if (selectedRowData[dataKeyArr[i]] == rowData[dataKeyArr[i]]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return dataKeyArr.length == count ? true : false;
|
||||
},
|
||||
getOriginData() {
|
||||
this.chkGridData.forEach(item => {
|
||||
this.originData.push(item);
|
||||
if (item._children) {
|
||||
this.getChildrenData(item._children);
|
||||
}
|
||||
});
|
||||
},
|
||||
getChildrenData(children) {
|
||||
children.forEach(item => {
|
||||
this.originData.push(item);
|
||||
if (item._children) {
|
||||
this.getChildrenData(item._children);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateData(updateType, rowIdxKey) {
|
||||
let type = '';
|
||||
switch (updateType) {
|
||||
case 'insert':
|
||||
type = 'I';
|
||||
break;
|
||||
case 'modify':
|
||||
type = 'U';
|
||||
break;
|
||||
case 'delete':
|
||||
type = 'D';
|
||||
break;
|
||||
case 'clear':
|
||||
type = null;
|
||||
break;
|
||||
}
|
||||
this.gridInstance.invoke('setValue', rowIdxKey, 'rowStat', type);
|
||||
},
|
||||
// 지정 로우 선택상태
|
||||
focus(rowInfo) {
|
||||
this.gridInstance.invoke(
|
||||
'focus',
|
||||
rowInfo.rowKey,
|
||||
rowInfo.columnName,
|
||||
rowInfo.setScroll,
|
||||
);
|
||||
},
|
||||
// 트리 전체 접기
|
||||
expandAll() {
|
||||
this.gridInstance.invoke('expandAll');
|
||||
},
|
||||
// 트리 전체 펼치기
|
||||
collapseAll() {
|
||||
this.gridInstance.invoke('collapseAll');
|
||||
},
|
||||
save() {
|
||||
const saveTargetRows = this.gridInstance.invoke('getModifiedRows');
|
||||
// createdRows | deletedRows | updatedRows
|
||||
const createdRows = saveTargetRows.createdRows;
|
||||
const deletedRows = saveTargetRows.deletedRows;
|
||||
const updatedRows = saveTargetRows.updatedRows;
|
||||
const dataArr = [...createdRows, ...deletedRows, ...updatedRows]
|
||||
.filter(item => item.rowStat)
|
||||
.map(item => {
|
||||
delete item.rowKey;
|
||||
return item;
|
||||
});
|
||||
// console.log("dataArr::", dataArr, saveTargetRows);
|
||||
return dataArr;
|
||||
},
|
||||
getData() {
|
||||
return this.gridInstance.invoke('getData');
|
||||
},
|
||||
getCheckedRows() {
|
||||
return this.gridInstance.invoke('getCheckedRows');
|
||||
},
|
||||
getCheckedRowKeys() {
|
||||
return this.gridInstance.invoke('getCheckedRowKeys');
|
||||
},
|
||||
setCheck(list) {
|
||||
// console.log("setCheck:: ", list);
|
||||
list.map(item => this.gridInstance.invoke('check', item));
|
||||
},
|
||||
refreshLayout() {
|
||||
this.gridInstance.invoke('refreshLayout');
|
||||
},
|
||||
refreshGrid(){
|
||||
// console.log("refreshLayout",this.$refs['tuigrid' + this.gridName])
|
||||
var store = this.$refs['tuigrid' + this.gridName].gridInstance.store;
|
||||
var containerEl = this.$refs['tuigrid' + this.gridName].$el;
|
||||
// var containerEl = document.querySelector('.tui-grid-container')
|
||||
var parentEl = containerEl.parentElement;
|
||||
|
||||
|
||||
|
||||
// console.log("containerEl : ",containerEl);
|
||||
// console.log('parentEl : ', parentEl)
|
||||
// function refreshLayout(store, containerEl, parentEl) {
|
||||
var dimension = store.dimension;
|
||||
var autoWidth = dimension.autoWidth, fitToParentHeight = dimension.fitToParentHeight;
|
||||
var clientHeight = containerEl.clientHeight, clientWidth = containerEl.clientWidth, scrollTop = containerEl.scrollTop, scrollLeft = containerEl.scrollLeft;
|
||||
var _a = containerEl.getBoundingClientRect(), top = _a.top, left = _a.left;
|
||||
this.setOffsetTop(store, top + scrollTop);
|
||||
// store.dimension.setOffsetTop = top + scrollTop;
|
||||
this.setOffsetLeft(store, left + scrollLeft);
|
||||
// store.dimension.headerHeight = left + scrollLeft;
|
||||
this.setWidth(store, clientWidth, autoWidth);
|
||||
// store.dimension.autoWidth = autoWidth;
|
||||
// store.dimension.width = clientWidth;
|
||||
// console.log("###",getComputedStyle(parentEl));
|
||||
// console.log("fitToParentHeight : ",fitToParentHeight);
|
||||
// console.log("parentEl : ",parentEl)
|
||||
// console.log("parentEl.clientHeight" , parentEl.clientHeight)
|
||||
// console.log("clientHeight : ",clientHeight);
|
||||
if (parentEl && parentEl.clientHeight !== clientHeight) {
|
||||
var _b = getComputedStyle(parentEl), paddingTop = _b.paddingTop, paddingBottom = _b.paddingBottom;
|
||||
this.setHeight(store, parentEl.clientHeight - (parseFloat(paddingTop) + parseFloat(paddingBottom)));
|
||||
}
|
||||
// }
|
||||
},
|
||||
setOffsetTop(store, offsetTop) {
|
||||
// console.log("setOffsetTop");
|
||||
store.dimension.offsetTop = offsetTop;
|
||||
},
|
||||
setWidth(_a, width, autoWidth) {
|
||||
// console.log("setWidth");
|
||||
var dimension = _a.dimension;
|
||||
dimension.autoWidth = autoWidth;
|
||||
dimension.width = width;
|
||||
},
|
||||
setHeaderHeight(store, height) {
|
||||
// console.log("setHeaderHeight")
|
||||
store.dimension.headerHeight = height;
|
||||
},
|
||||
setOffsetLeft(store, offsetLeft) {
|
||||
// console.log("setOffsetLeft")
|
||||
store.dimension.offsetLeft = offsetLeft;
|
||||
},
|
||||
setHeight(_a,height){
|
||||
// console.log("setHeight");
|
||||
var dimension = _a.dimension;
|
||||
var headerHeight = dimension.headerHeight, summaryHeight = dimension.summaryHeight, tableBorderWidth = dimension.tableBorderWidth;
|
||||
dimension.bodyHeight = height - headerHeight - summaryHeight - tableBorderWidth;
|
||||
},
|
||||
sendSelectedRowData(eventRowKey) {
|
||||
if (this.selectedRowDataWatchFlag) {
|
||||
var rowKey =
|
||||
eventRowKey === undefined
|
||||
? this.gridInstance.invoke('getFocusedCell').rowKey
|
||||
: eventRowKey;
|
||||
var rowData = this.gridInstance.invoke('getRow', rowKey);
|
||||
this.$emit('sendSelectedRowStatInfo', rowData);
|
||||
}
|
||||
},
|
||||
disableRow(rowKey, withCheckBox = false) {
|
||||
this.gridInstance.invoke('disableRow', rowKey, withCheckBox);
|
||||
},
|
||||
async disabledRow(addRowKey) {
|
||||
this.$nextTick(() => {
|
||||
this.gridInstance.invoke(
|
||||
'removeRowClassName',
|
||||
addRowKey,
|
||||
'row-removed',
|
||||
);
|
||||
this.gridInstance.invoke('addRowClassName', addRowKey, 'row-disabled');
|
||||
});
|
||||
},
|
||||
// resetData() {
|
||||
// // console.log("resetData = ", this.tuigridProps.data);
|
||||
// this.$refs.tuigrid.invoke("resetData", this.tuigridProps.data);
|
||||
// }
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
::v-deep .tui-grid-container {
|
||||
.tui-grid-content-area {
|
||||
.tui-grid-cell-content {
|
||||
input[type='number'] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
245
components/common/Grid2.vue
Normal file
@ -0,0 +1,245 @@
|
||||
<template>
|
||||
<tui-grid
|
||||
:ref="['tuigrid' + gridName]"
|
||||
:data="chkGridData"
|
||||
:columns="chkGridColumns"
|
||||
:options="chkGridOptions"
|
||||
@focusChange="focusChangeEvt"
|
||||
@click="startEditing"
|
||||
@editingFinish="editingFinish"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations, mapActions } from 'vuex';
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
gridName: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
dataPath: {
|
||||
type: Object,
|
||||
require: false,
|
||||
default: null,
|
||||
},
|
||||
editorGrid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
require: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
gridInstance: null,
|
||||
gridHeight: null,
|
||||
selecrRowKey: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
// pageData: state => state.pageData
|
||||
pageData(state) {
|
||||
return this.dataPath
|
||||
? this.dataPath[this.gridName]
|
||||
: state.pageData[this.parentPrgmId][this.gridName];
|
||||
},
|
||||
}),
|
||||
chkGridData() {
|
||||
return this.pageData.data;
|
||||
},
|
||||
chkGridColumns() {
|
||||
return this.pageData.column;
|
||||
},
|
||||
chkGridOptions() {
|
||||
return this.pageData.option;
|
||||
},
|
||||
defaultRow() {
|
||||
return this.pageData.defaultRow;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
chkGridData(val) {
|
||||
this.$refs['tuigrid' + this.gridName].invoke('resetData', val);
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
async mounted() {
|
||||
// console.log(this.dataPath);
|
||||
if (this.gridName) {
|
||||
this.gridInstance = this.$refs['tuigrid' + this.gridName];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
setPageData: 'setPageData',
|
||||
setGridData: 'setGridData',
|
||||
}),
|
||||
getCheckedRowsEvt() {
|
||||
const checkedRowDataList = this.gridInstance.invoke('getCheckedRows');
|
||||
return checkedRowDataList;
|
||||
},
|
||||
uncheckEvt(rowData, instance) {
|
||||
this.gridInstance.invoke('uncheck', rowData.rowKey, instance);
|
||||
},
|
||||
checkEvt(rowData, instance) {
|
||||
this.gridInstance.invoke('check', rowData.rowKey, instance);
|
||||
},
|
||||
focusChangeEvt(e) {
|
||||
// cell 선택시 row 선택 method
|
||||
if (!this.editorGrid) {
|
||||
this.$emit('getRowsData', this.gridInstance.invoke('getRow', e.rowKey));
|
||||
this.selecrRowKey = e.rowKey;
|
||||
const rowIndxKey = this.gridInstance.invoke('getIndexOfRow', e.rowKey);
|
||||
this.gridInstance.invoke('setSelectionRange', {
|
||||
start: [rowIndxKey, 0],
|
||||
end: [rowIndxKey, this.gridInstance.columns.length],
|
||||
});
|
||||
}
|
||||
},
|
||||
startEditing(e) {
|
||||
if (this.editorGrid) {
|
||||
this.gridInstance.invoke('startEditing', e.rowKey, e.columnName);
|
||||
const rowIndxKey = this.gridInstance.invoke('getIndexOfRow', e.rowKey);
|
||||
this.gridInstance.invoke('setSelectionRange', {
|
||||
start: [rowIndxKey, 0],
|
||||
end: [rowIndxKey, this.gridInstance.columns.length],
|
||||
});
|
||||
}
|
||||
},
|
||||
editingFinish(e) {
|
||||
// console.log("editingFinish::e", e);
|
||||
const rowIdxKey = e.rowKey;
|
||||
const columnName = e.columnName;
|
||||
const value = e.value;
|
||||
const isAddRow = this.isBaseDataRow(rowIdxKey);
|
||||
|
||||
this.gridInstance.invoke('setValue', rowIdxKey, columnName, value);
|
||||
if (isAddRow != -1) {
|
||||
const isSameData = this.compareData(e);
|
||||
if (!isSameData) {
|
||||
this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-modify');
|
||||
this.updateData('modify', rowIdxKey);
|
||||
}
|
||||
}
|
||||
},
|
||||
async addRow() {
|
||||
// 열 앞에 데이터 추가
|
||||
this.gridInstance.invoke('prependRow', this.defaultRow, {
|
||||
focus: true,
|
||||
});
|
||||
|
||||
// const aa = this.gridInstance.invoke("getModifiedRows");
|
||||
// console.log("this.gridInstance", this.gridInstance, aa);
|
||||
this.$nextTick(() => {
|
||||
const addRowKey = this.gridInstance.invoke('getFocusedCell').rowKey;
|
||||
// console.log("addRowKey :: ", addRowKey);
|
||||
this.gridInstance.invoke('addRowClassName', addRowKey, 'row-insert');
|
||||
this.updateData('insert', addRowKey);
|
||||
});
|
||||
},
|
||||
removeRow() {
|
||||
const rowIdxKey = this.gridInstance.invoke('getFocusedCell').rowKey;
|
||||
this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-removed');
|
||||
this.gridInstance.invoke('disableRow', rowIdxKey);
|
||||
|
||||
this.updateData('delete', rowIdxKey);
|
||||
},
|
||||
externalDataEdit(obj) {
|
||||
const rowIdxKey = this.gridInstance.invoke('getFocusedCell').rowKey;
|
||||
const columnName = obj.name;
|
||||
const value = obj.value;
|
||||
const isAddRow = this.isBaseDataRow(rowIdxKey);
|
||||
|
||||
this.gridInstance.invoke('setValue', rowIdxKey, columnName, value);
|
||||
if (isAddRow != -1) {
|
||||
this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-modify');
|
||||
this.updateData('modify', rowIdxKey);
|
||||
}
|
||||
},
|
||||
isBaseDataRow(rowKey) {
|
||||
// 기존데이터 여부 확인 (추가된 데이터 X)
|
||||
return this.chkGridData.map(item => item.rowKey).indexOf(rowKey);
|
||||
},
|
||||
compareData(data) {
|
||||
const rowData = this.chkGridData.filter(item => {
|
||||
return item.rowKey == data.rowKey;
|
||||
})[0];
|
||||
// console.log(rowData);
|
||||
return rowData[data.columnName] == data.value;
|
||||
},
|
||||
updateData(updateType, rowIdxKey) {
|
||||
let type = '';
|
||||
switch (updateType) {
|
||||
case 'insert':
|
||||
type = 'I';
|
||||
break;
|
||||
case 'modify':
|
||||
type = 'U';
|
||||
break;
|
||||
case 'delete':
|
||||
type = 'D';
|
||||
break;
|
||||
}
|
||||
this.gridInstance.invoke('setValue', rowIdxKey, 'rowStat', type);
|
||||
},
|
||||
// 지정 로우 선택상태
|
||||
focus(rowInfo) {
|
||||
this.gridInstance.invoke(
|
||||
'focus',
|
||||
rowInfo.rowKey,
|
||||
rowInfo.columnName,
|
||||
rowInfo.setScroll,
|
||||
);
|
||||
},
|
||||
// 트리 전체 접기
|
||||
expandAll() {
|
||||
this.gridInstance.invoke('expandAll');
|
||||
},
|
||||
// 트리 전체 펼치기
|
||||
collapseAll() {
|
||||
this.gridInstance.invoke('collapseAll');
|
||||
},
|
||||
save() {
|
||||
const saveTargetRows = this.gridInstance.invoke('getModifiedRows');
|
||||
// createdRows | deletedRows | updatedRows
|
||||
const createdRows = saveTargetRows.createdRows.map(item => {
|
||||
delete item.rowKey;
|
||||
return item;
|
||||
});
|
||||
const deletedRows = saveTargetRows.deletedRows.map(item => {
|
||||
delete item.rowKey;
|
||||
return item;
|
||||
});
|
||||
const updatedRows = saveTargetRows.updatedRows.map(item => {
|
||||
delete item.rowKey;
|
||||
return item;
|
||||
});
|
||||
const dataArr = createdRows.concat(deletedRows).concat(updatedRows);
|
||||
return dataArr;
|
||||
// this.$emit("saveGrid", saveTargetRows);
|
||||
},
|
||||
// resetData() {
|
||||
// // console.log("resetData = ", this.tuigridProps.data);
|
||||
// this.$refs.tuigrid.invoke("resetData", this.tuigridProps.data);
|
||||
// }
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
::v-deep .tui-grid-cell {
|
||||
&.row-insert {
|
||||
background-color: #13636c !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
&.row-modify {
|
||||
background-color: #13636c;
|
||||
}
|
||||
&.row-removed {
|
||||
background-color: red;
|
||||
}
|
||||
}
|
||||
</style>
|
354
components/common/PastRsltDatePicker.vue
Normal file
@ -0,0 +1,354 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small color="primary" class="mr-1">mdi-record-circle</v-icon>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<div class="datepicker-container">
|
||||
<v-text-field
|
||||
id="startpicker"
|
||||
ref="startpicker"
|
||||
v-model="fromDtValue"
|
||||
:class="isRange ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="startpicker-container" id="startpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<div v-show="isRange" class="mx-3" :style="{ lineHeight: 0 }">~</div>
|
||||
<v-text-field
|
||||
v-show="isRange"
|
||||
id="endpicker"
|
||||
ref="endpicker"
|
||||
v-model="toDtValue"
|
||||
:class="isRange ? 'v-input__custom half' : 'v-input__custom'"
|
||||
:hide-details="true"
|
||||
readonly
|
||||
outlined
|
||||
>
|
||||
<template #append>
|
||||
<v-icon size="20">$icoCalendar</v-icon>
|
||||
</template>
|
||||
<template #append-outer>
|
||||
<div ref="endpicker-container" id="endpicker-container"></div>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
import TuiDatepicker from 'tui-date-picker';
|
||||
import Utility from '~/plugins/utility';
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
require: false,
|
||||
},
|
||||
timePicker: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 8,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
today: new Date(),
|
||||
startDatepickerInstance: null,
|
||||
endDatepickerInstance: null,
|
||||
startDtValue: null,
|
||||
endDtValue: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam(state) {
|
||||
return state.pageData[this.parentPrgmId];
|
||||
},
|
||||
}),
|
||||
myCmCycle() {
|
||||
return this.searchParam.cmCycle;
|
||||
},
|
||||
myOptions() {
|
||||
let returnObj = {
|
||||
type: 'date',
|
||||
viewFormat: 'YYYY-MM-DD',
|
||||
pickerFormat: 'yyyy-MM-dd',
|
||||
sendFormat: 'YYYYMMDD',
|
||||
};
|
||||
return returnObj;
|
||||
},
|
||||
// maxDate() {
|
||||
// return Utility.setFormatDate("today", this.myOptions.format);
|
||||
// },
|
||||
fromDtValue() {
|
||||
return Utility.setFormatDate(
|
||||
this.searchParam.fromDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
},
|
||||
toDtValue() {
|
||||
return Utility.setFormatDate(
|
||||
this.searchParam.toDt,
|
||||
this.myOptions.viewFormat,
|
||||
);
|
||||
},
|
||||
defaultRange() {
|
||||
return this.searchParam.defaultRange
|
||||
? this.searchParam.defaultRange[this.myCmCycle]
|
||||
: null;
|
||||
},
|
||||
isRange() {
|
||||
return (
|
||||
(this.defaultRange !== null && this.defaultRange > 0) ||
|
||||
this.defaultRange === 'no limite'
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
myCmCycle() {
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
this.startDatepickerInstance.setType(this.myOptions.type);
|
||||
this.endDatepickerInstance.setType(this.myOptions.type);
|
||||
},
|
||||
fromDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.toDtValueChkRang(newVal);
|
||||
this.startDatepickerInstance.setDate(new Date(newVal));
|
||||
} else {
|
||||
this.setPageData({ isFind: true });
|
||||
}
|
||||
},
|
||||
toDtValue(newVal, oldVal) {
|
||||
if (
|
||||
this.isRange &&
|
||||
this.defaultRange !== 'no limite' &&
|
||||
newVal !== 'Invalid Date' &&
|
||||
newVal !== oldVal
|
||||
) {
|
||||
this.fromDtValueChkRang(newVal);
|
||||
this.endDatepickerInstance.setDate(new Date(newVal));
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.timePicker) {
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 00:00:00',
|
||||
toDt: Utility.setFormatDate(this.today, 'YYYY-MM-DD') + ' 23:59:59',
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const startContainer = document.getElementById('startpicker-container');
|
||||
const startTarget = document.getElementById('startpicker');
|
||||
const endContainer = document.getElementById('endpicker-container');
|
||||
const endTarget = document.getElementById('endpicker');
|
||||
|
||||
// datepicker 생성
|
||||
this.startDatepickerInstance = new TuiDatepicker(startContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: startTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성
|
||||
this.endDatepickerInstance = new TuiDatepicker(endContainer, {
|
||||
date: this.today,
|
||||
language: 'ko',
|
||||
type: this.myOptions.type, // "date", // type: date || month || year
|
||||
input: {
|
||||
element: endTarget,
|
||||
format: this.myOptions.pickerFormat, //"YYYY-MM-DD" //this.format
|
||||
},
|
||||
timePicker: this.timePicker,
|
||||
calendar: {
|
||||
showToday: false,
|
||||
},
|
||||
});
|
||||
// datepicker 생성 끝
|
||||
|
||||
// datepicker 초기값 생성
|
||||
this.startDatepickerInstance.setDate(new Date(this.fromDtValue));
|
||||
// datepicker 초기값 생성 끝
|
||||
|
||||
// datepicker 변경시 이벤트 추가
|
||||
this.startDatepickerInstance.on('change', () => this.getStartDt());
|
||||
this.endDatepickerInstance.on('change', () => this.getEndDt());
|
||||
// datepicker 이벤트는 mount 될때 추가 해주어야 한다.
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
setDatePicker(type, compareDate, formatDate, formatTime) {
|
||||
let returnDt = null;
|
||||
const dayjs = require('dayjs');
|
||||
|
||||
const compareDt = dayjs(compareDate);
|
||||
const formatType = formatDate + (formatTime ? ' ' + formatTime : '');
|
||||
const defaultRange = this.defaultRange;
|
||||
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
|
||||
if (type == 'toDt') {
|
||||
returnDt = compareDt.add(myRange, rangeKey).subtract(1, 'day');
|
||||
} else {
|
||||
returnDt = compareDt.subtract(myRange, rangeKey).add(1, 'day');
|
||||
}
|
||||
|
||||
return returnDt.format(formatType);
|
||||
},
|
||||
getStartDt() {
|
||||
const dt = this.startDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
fromDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
getEndDt() {
|
||||
const dt = this.endDatepickerInstance.getDate();
|
||||
this.setPageData({
|
||||
toDt: Utility.setFormatDate(dt, this.myOptions.sendFormat),
|
||||
});
|
||||
},
|
||||
fromDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.fromDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = compareDt.diff(defaultDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && compareDt.isAfter(defaultDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
// if(this.cmCycleFlag){
|
||||
this.setPageData({ isFind: true });
|
||||
// }
|
||||
// this.cmCycleFlag = true;
|
||||
} else {
|
||||
this.setPageData({
|
||||
fromDt: this.setDatePicker(
|
||||
'fromDt',
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
toDtValueChkRang(newDt) {
|
||||
const defaultDt = this.$dayjs(this.toDtValue);
|
||||
const compareDt = this.$dayjs(newDt);
|
||||
const newDefault = Utility.setNewDefaultRange(
|
||||
this.myCmCycle,
|
||||
this.defaultRange,
|
||||
);
|
||||
const myRange = newDefault.range;
|
||||
const rangeKey = newDefault.key;
|
||||
const rangeGap = defaultDt.diff(compareDt, rangeKey);
|
||||
|
||||
if (
|
||||
(myRange > rangeGap && defaultDt.isAfter(compareDt)) ||
|
||||
defaultDt.format(this.myOptions.sendFormat) ===
|
||||
compareDt.format(this.myOptions.sendFormat)
|
||||
) {
|
||||
this.setPageData({ isFind: true });
|
||||
} else {
|
||||
this.setPageData({
|
||||
toDt: this.setDatePicker(
|
||||
'toDt',
|
||||
compareDt,
|
||||
this.myOptions.sendFormat,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.datepicker-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
.v-input {
|
||||
.v-input__append-outer {
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
|
||||
#startpicker-container,
|
||||
#endpicker-container {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 36px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.v-input__custom {
|
||||
flex: 0 0 auto;
|
||||
&.half {
|
||||
width: calc(50% - 20px);
|
||||
}
|
||||
}
|
||||
::v-deep {
|
||||
.tui-timepicker-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background-color: #edf4fc;
|
||||
.tui-timepicker-column.tui-timepicker-colon {
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
138
components/common/RadioCmCycle.vue
Normal file
@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small color="primary" class="mr-1">mdi-record-circle</v-icon>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? 'auto' : ''">
|
||||
<v-radio-group
|
||||
v-model="selected"
|
||||
required:rules="radioRules"
|
||||
row
|
||||
dense
|
||||
:hide-details="true"
|
||||
>
|
||||
<v-radio
|
||||
label="월별"
|
||||
value="CYC_YEAR"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="일별"
|
||||
value="CYC_MONTH"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="시간별"
|
||||
value="CYC_DAY"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
</v-radio-group>
|
||||
<!-- @change="updateBlocCode($event)" -->
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations, mapActions } from 'vuex';
|
||||
import Utility from '~/plugins/utility';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
require: false,
|
||||
default: '주기',
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 7,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
labelPrepend: true,
|
||||
// selected:"CYC_DAY"
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam: state => state.pageData,
|
||||
isDarkMode: 'isDarkMode',
|
||||
}),
|
||||
selected: {
|
||||
get() {
|
||||
return this.searchParam[this.parentPrgmId].cmCycle;
|
||||
},
|
||||
set(value) {
|
||||
this.setDefaultDate(value);
|
||||
return this.setPageData({ cmCycle: value });
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
created() {
|
||||
// this.setDefaultDate(this.searchParam[this.parentPrgmId].cmCycle);
|
||||
},
|
||||
async mounted() {},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
...mapActions({}),
|
||||
setDefaultDate(value) {
|
||||
// console.log("주기에 따른 오늘 기준 기본 날짜 세팅");
|
||||
const today = Utility.setFormatDate('today', 'YYYY-MM-DD');
|
||||
let srartDate = '';
|
||||
let endDate = '';
|
||||
// console.log(value);
|
||||
switch (value) {
|
||||
case 'CYC_YEAR':
|
||||
// endDate = today;
|
||||
srartDate = Utility.setFormatDate(today, 'YYYY');
|
||||
break;
|
||||
|
||||
case 'CYC_MONTH':
|
||||
// endDate = today;
|
||||
srartDate = Utility.setFormatDate(today, 'YYYY-MM');
|
||||
// endDate = today;
|
||||
// srartDate = Utility.setBeforetDate(
|
||||
// this.searchParam[this.parentPrgmId],
|
||||
// endDate,
|
||||
// "YYYYMMDD"
|
||||
// );
|
||||
break;
|
||||
|
||||
case 'CYC_DAY':
|
||||
// endDate = today;
|
||||
srartDate = today;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.setPageData({ fromDt: srartDate });
|
||||
// console.log(this.searchParam[this.parentPrgmId].cmCycle);
|
||||
// console.log(this.searchParam[this.parentPrgmId].dateRange);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
113
components/common/RadioStandard.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small color="primary" class="mr-1">mdi-record-circle</v-icon>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<v-radio-group
|
||||
v-model="selected"
|
||||
required:rules="radioRules"
|
||||
row
|
||||
hide-details
|
||||
dense
|
||||
>
|
||||
<v-radio
|
||||
label="태그"
|
||||
value="tag"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="검침개소"
|
||||
value="readPlc"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="공정"
|
||||
value="ecc"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="설비"
|
||||
value="eqpm"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
</v-radio-group>
|
||||
<!-- @change="updateBlocCode($event)" -->
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations, mapActions } from 'vuex';
|
||||
import Utility from '~/plugins/utility';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 7,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
label: '기준',
|
||||
labelPrepend: true,
|
||||
// selected:"CYC_DAY"
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isDarkMode: 'isDarkMode',
|
||||
searchParam: state => state.pageData,
|
||||
}),
|
||||
selected: {
|
||||
get() {
|
||||
return this.searchParam[this.parentPrgmId].rdbStandard;
|
||||
},
|
||||
set(value) {
|
||||
return this.setPageData({ rdbStandard: value });
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selected(value) {
|
||||
// 주기에 따른 오늘 기준 기본 날짜 세팅
|
||||
this.setDefaultDate(value);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// this.setDefaultDate(this.searchParam[this.parentPrgmId].cmCycle);
|
||||
},
|
||||
async mounted() {},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
...mapActions({}),
|
||||
setDefaultDate(value) {
|
||||
this.setPageData({ rdbStandard: value });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
99
components/common/RadioUseCost.vue
Normal file
@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
<v-icon x-small color="primary" class="mr-1">mdi-record-circle</v-icon>
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<v-radio-group
|
||||
v-model="selected"
|
||||
required:rules="radioRules"
|
||||
row
|
||||
hide-details
|
||||
dense
|
||||
>
|
||||
<v-radio
|
||||
label="사용량"
|
||||
value="use"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="비용"
|
||||
value="cost"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
</v-radio-group>
|
||||
<!-- @change="updateBlocCode($event)" -->
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations, mapActions } from 'vuex';
|
||||
import Utility from '~/plugins/utility';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 7,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
label: '구분',
|
||||
labelPrepend: true,
|
||||
// selected:"CYC_DAY"
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isDarkMode: 'isDarkMode',
|
||||
searchParam: state => state.pageData,
|
||||
}),
|
||||
selected: {
|
||||
get() {
|
||||
return this.searchParam[this.parentPrgmId].rdbUseCost;
|
||||
},
|
||||
set(value) {
|
||||
return this.setPageData({ rdbUseCost: value });
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selected(value) {
|
||||
// 주기에 따른 오늘 기준 기본 날짜 세팅
|
||||
this.setDefaultDate(value);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// this.setDefaultDate(this.searchParam[this.parentPrgmId].cmCycle);
|
||||
},
|
||||
async mounted() {},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
...mapActions({}),
|
||||
setDefaultDate(value) {
|
||||
this.setPageData({ rdbUseCost: value });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
97
components/common/RadioView.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<v-row class="search-box" align="center" no-gutters>
|
||||
<v-col v-if="label" :cols="labelCols">
|
||||
<label for="" class="search-box-label">
|
||||
{{ label }}
|
||||
</label>
|
||||
</v-col>
|
||||
<v-col :cols="label ? textCols : ''">
|
||||
<v-radio-group
|
||||
v-model="selectedView"
|
||||
required:rules="radioRules"
|
||||
row
|
||||
dense
|
||||
:hide-details="true"
|
||||
>
|
||||
<v-radio
|
||||
label="전체"
|
||||
value="viewAll"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="차트"
|
||||
value="viewChart"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
<v-radio
|
||||
label="그리드"
|
||||
value="viewGrid"
|
||||
:ripple="false"
|
||||
:color="isDarkMode ? '#1b74d7' : '#4777d9'"
|
||||
on-icon="mdi-record-circle"
|
||||
></v-radio>
|
||||
</v-radio-group>
|
||||
<!-- @change="updateBlocCode($event)" -->
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations, mapActions } from 'vuex';
|
||||
import Utility from '~/plugins/utility';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
parentPrgmId: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
labelCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 4,
|
||||
},
|
||||
textCols: {
|
||||
type: Number,
|
||||
require: false,
|
||||
default: 8,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
label: '',
|
||||
labelPrepend: true,
|
||||
// selected:"CYC_DAY"
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
searchParam: state => state.pageData,
|
||||
isDarkMode: 'isDarkMode',
|
||||
}),
|
||||
selectedView: {
|
||||
get() {
|
||||
return this.searchParam[this.parentPrgmId].viewCheck;
|
||||
},
|
||||
set(value) {
|
||||
return this.setPageData({ viewCheck: value });
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
created() {
|
||||
// this.setDefaultDate(this.searchParam[this.parentPrgmId].cmCycle);
|
||||
},
|
||||
async mounted() {},
|
||||
methods: {
|
||||
...mapMutations({ setPageData: 'setPageData' }),
|
||||
...mapActions({}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
89
components/common/ThemeSwitch.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<v-switch
|
||||
class="theme-switch"
|
||||
v-model="mode"
|
||||
@change="themeChange"
|
||||
></v-switch>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
mode: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isDarkMode: 'isDarkMode',
|
||||
}),
|
||||
},
|
||||
created() {
|
||||
this.mode = this.isDarkMode;
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
setThemeChange: 'setThemeChange',
|
||||
}),
|
||||
themeChange() {
|
||||
this.$vuetify.theme.isDark = this.mode;
|
||||
this.setThemeChange(this.mode);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.theme-switch {
|
||||
display: inline-flex;
|
||||
width: 47px;
|
||||
height: 30px;
|
||||
::v-deep {
|
||||
.v-input__control,
|
||||
.v-input__slot {
|
||||
height: 100%;
|
||||
}
|
||||
.v-input--selection-controls__input {
|
||||
width: 100%;
|
||||
margin-right: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.v-input--switch__track {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50px;
|
||||
position: initial;
|
||||
background-color: #f1f0f8;
|
||||
}
|
||||
input {
|
||||
min-height: initial;
|
||||
}
|
||||
.v-input--selection-controls__ripple {
|
||||
display: none;
|
||||
}
|
||||
.v-input--switch__thumb {
|
||||
position: absolute;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 50%;
|
||||
background-color: #f2f2f2;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
background-image: url(../../assets/images/icon/ico-theme-light.png);
|
||||
background-size: 18px 18px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
&.v-input--is-label-active {
|
||||
::v-deep {
|
||||
.v-input--switch__track {
|
||||
background-color: #383f5d;
|
||||
}
|
||||
.v-input--switch__thumb {
|
||||
transform: translate(38px, 0);
|
||||
background-image: url(../../assets/images/icon/ico-theme-dark.png);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|