diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 8eb11f7c1c4326c9c107a76f882ac3a20b6d0ad7..ebf3f22b38bc1faa7b4e5b0a0dd990beebc9dd38 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ajou_tt_frontend +# vuetifyapp ## Project setup ``` diff --git a/babel.config.js b/babel.config.js old mode 100644 new mode 100755 diff --git a/package.json b/package.json old mode 100644 new mode 100755 index 77820f2aae2458b89db43633a9fd15121cd5c3ae..5c76465c9ae439bba030042104227b5162275183 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "ajou_tt_frontend", + "name": "vuetifyapp", "version": "0.1.0", "private": true, "scripts": { @@ -9,16 +9,25 @@ }, "dependencies": { "core-js": "^3.3.2", - "vue": "^2.6.10" + "vue": "^2.6.10", + "vue-router": "^3.1.3", + "vuetify": "^2.1.0", + "vuex": "^3.0.1" }, "devDependencies": { "@vue/cli-plugin-babel": "^4.0.0", "@vue/cli-plugin-eslint": "^4.0.0", + "@vue/cli-plugin-router": "^4.0.5", + "@vue/cli-plugin-vuex": "^4.0.5", "@vue/cli-service": "^4.0.0", "babel-eslint": "^10.0.3", "eslint": "^5.16.0", "eslint-plugin-vue": "^5.0.0", - "vue-template-compiler": "^2.6.10" + "sass": "^1.19.0", + "sass-loader": "^8.0.0", + "vue-cli-plugin-vuetify": "^2.0.1", + "vue-template-compiler": "^2.6.10", + "vuetify-loader": "^1.3.0" }, "eslintConfig": { "root": true, @@ -29,9 +38,12 @@ "plugin:vue/essential", "eslint:recommended" ], - "rules": {}, "parserOptions": { "parser": "babel-eslint" + }, + "rules": { + "vue/no-unused-vars": "warning", + "no-console": "off" } }, "postcss": { diff --git a/public/favicon.ico b/public/favicon.ico old mode 100644 new mode 100755 diff --git a/public/index.html b/public/index.html old mode 100644 new mode 100755 index 82a2b0591eeaf8c346616719533e4e0d5944f23b..9a062f832e06329720afa89cbf127bab0c07c4d4 --- a/public/index.html +++ b/public/index.html @@ -5,11 +5,13 @@ <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> - <title>ajou_tt_frontend</title> + <title>vuetify 테스트</title> + <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css"> </head> <body> <noscript> - <strong>We're sorry but ajou_tt_frontend doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> + <strong>We're sorry but vuetifyapp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> diff --git a/src/App.vue b/src/App.vue old mode 100644 new mode 100755 index fcc566279aef926ce288d41de2fd4d841a400705..bc4a822abf06ba3fc089e07e8519aec88d461197 --- a/src/App.vue +++ b/src/App.vue @@ -1,28 +1,34 @@ <template> - <div id="app"> - <img alt="Vue logo" src="./assets/logo.png"> - <HelloWorld msg="Welcome to Your Vue.js App"/> - </div> + <v-app> + <v-app-bar + app + color="primary" + dark + > + <v-card-text class="text-center"> 뷰티파이 테스트용 {{this.$store.state.userID}}</v-card-text> + </v-app-bar> + + <v-content> + <router-view></router-view> + </v-content> + + <v-footer color="#00d1ff"> + <v-card-text class="text-center"> + 뷰티파이로 만들었습니다. + </v-card-text> + </v-footer> + </v-app> </template> <script> -import HelloWorld from './components/HelloWorld.vue' export default { - name: 'app', + name: 'App', + components: { - HelloWorld - } -} -</script> + }, -<style> -#app { - font-family: 'Avenir', Helvetica, Arial, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - text-align: center; - color: #2c3e50; - margin-top: 60px; -} -</style> + data: () => ({ + }), +}; +</script> diff --git a/src/assets/logo.png b/src/assets/logo.png old mode 100644 new mode 100755 diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100755 index 0000000000000000000000000000000000000000..145b6d13089c81fcb16f68ad8f976e389dcd77e3 --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1 @@ +<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg> diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue old mode 100644 new mode 100755 index 879051a29739fdfb17ae82ed23b53fac251c2b7e..35057913523832522ef5ace6e2d339ba5c643995 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -1,58 +1,144 @@ <template> - <div class="hello"> - <h1>{{ msg }}</h1> - <p> - For a guide and recipes on how to configure / customize this project,<br> - check out the - <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>. - </p> - <h3>Installed CLI Plugins</h3> - <ul> - <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li> - <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li> - </ul> - <h3>Essential Links</h3> - <ul> - <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li> - <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li> - <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li> - <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li> - <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li> - </ul> - <h3>Ecosystem</h3> - <ul> - <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li> - <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li> - <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li> - <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li> - <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li> - </ul> - </div> + <v-container> + <v-layout + text-center + wrap + > + <v-flex xs12> + <v-img + :src="require('../assets/logo.svg')" + class="my-3" + contain + height="200" + ></v-img> + </v-flex> + + <v-flex mb-4> + <h1 class="display-2 font-weight-bold mb-3"> + Welcome to Vuetify + </h1> + <p class="subheading font-weight-regular"> + For help and collaboration with other Vuetify developers, + <br>please join our online + <a href="https://community.vuetifyjs.com" target="_blank">Discord Community</a> + </p> + </v-flex> + + <v-flex + mb-5 + xs12 + > + <h2 class="headline font-weight-bold mb-3">What's next?</h2> + + <v-layout justify-center> + <a + v-for="(next, i) in whatsNext" + :key="i" + :href="next.href" + class="subheading mx-3" + target="_blank" + > + {{ next.text }} + </a> + </v-layout> + </v-flex> + + <v-flex + xs12 + mb-5 + > + <h2 class="headline font-weight-bold mb-3">Important Links</h2> + + <v-layout justify-center> + <a + v-for="(link, i) in importantLinks" + :key="i" + :href="link.href" + class="subheading mx-3" + target="_blank" + > + {{ link.text }} + </a> + </v-layout> + </v-flex> + + <v-flex + xs12 + mb-5 + > + <h2 class="headline font-weight-bold mb-3">Ecosystem</h2> + + <v-layout justify-center> + <a + v-for="(eco, i) in ecosystem" + :key="i" + :href="eco.href" + class="subheading mx-3" + target="_blank" + > + {{ eco.text }} + </a> + </v-layout> + </v-flex> + </v-layout> + </v-container> </template> <script> export default { name: 'HelloWorld', - props: { - msg: String - } -} -</script> -<!-- Add "scoped" attribute to limit CSS to this component only --> -<style scoped> -h3 { - margin: 40px 0 0; -} -ul { - list-style-type: none; - padding: 0; -} -li { - display: inline-block; - margin: 0 10px; -} -a { - color: #42b983; -} -</style> + data: () => ({ + ecosystem: [ + { + text: 'vuetify-loader', + href: 'https://github.com/vuetifyjs/vuetify-loader', + }, + { + text: 'github', + href: 'https://github.com/vuetifyjs/vuetify', + }, + { + text: 'awesome-vuetify', + href: 'https://github.com/vuetifyjs/awesome-vuetify', + }, + ], + importantLinks: [ + { + text: 'Documentation', + href: 'https://vuetifyjs.com', + }, + { + text: 'Chat', + href: 'https://community.vuetifyjs.com', + }, + { + text: 'Made with Vuetify', + href: 'https://madewithvuejs.com/vuetify', + }, + { + text: 'Twitter', + href: 'https://twitter.com/vuetifyjs', + }, + { + text: 'Articles', + href: 'https://medium.com/vuetify', + }, + ], + whatsNext: [ + { + text: 'Explore components', + href: 'https://vuetifyjs.com/components/api-explorer', + }, + { + text: 'Select a layout', + href: 'https://vuetifyjs.com/layout/pre-defined', + }, + { + text: 'Frequently Asked Questions', + href: 'https://vuetifyjs.com/getting-started/frequently-asked-questions', + }, + ], + }), +}; +</script> diff --git a/src/components/adder.vue b/src/components/adder.vue new file mode 100755 index 0000000000000000000000000000000000000000..e093c41f04682543ade20000af52075d4993c260 --- /dev/null +++ b/src/components/adder.vue @@ -0,0 +1,100 @@ +<template> +<v-app class="myApp"> + <v-form v-model="isInputValid" class="text-center"> + <v-text-field v-model="num1" :rules="numberRules" label="피연산자 1"></v-text-field> + <v-text-field v-model="num2" :rules="numberRules" label="피연산자 2"> </v-text-field> + <v-btn color="success" v-on:click="cal">계산하기!</v-btn> + </v-form> + <v-alert v-if="inputError" type="error">입력이 정확하지 않습니다.</v-alert> + <v-alert v-if="connectionError" type="error">서버와의 통신에 실패하였습니다.</v-alert> + <v-alert v-if="successMsg" type="success">성공적으로 서버에 요청을 보냈습니다.</v-alert> + <v-card v-if="successMsg"> + <v-card-text>계산 결과는 {{result}}입니다.</v-card-text> + </v-card> +</v-app> +</template> + + +<script> +export default { + name: "adder", + + data() { + return { + num1: "", + num2: "", + result: 0, + isInputValid: false, + inputError: false, + connectionError: false, + successMsg: false, + + numberRules: [ + v => !!v || '입력을 비울 수는 없습니다.', + function(v){ + if(v == 0){ + return true; + } + + if(!!(v*1) == false){ + return "숫자를 입력하십시오." + } + + return true; + } + ] + } + }, + + methods: { + async cal() { + if(!this.isInputValid){ + this.inputError = true; + this.connectionError = false; + this.successMsg = false; + return; + }else{ + this.inputError = false; + } + + let bodyData = { + num1: this.num1, + num2: this.num2 + } + + try { + let requestPromis = + fetch('/', { + method: 'POST', // POST 메소드 지정 + body: JSON.stringify(bodyData), //express가 이해할 수 있는 JSON 형태로 POST 데이터 변환 + headers: { + 'Content-Type': 'application/json' + }, + }); + + let responseData = await requestPromis; + + let responseBodyJsonString = await responseData.json();//json 포맷에 맞는 string으로 반환해 준다. + + let responseBody = JSON.parse(responseBodyJsonString);//string으로 된 포맷을 자바스크립트 오브젝트로 변환 + + this.result = responseBody.result + }catch(e){ + this.connectionError = true; + console.log(e); + return; + } + + this.connectionError = false; + this.successMsg = true; + } + } +} +</script> + +<style lang="css" scoped> + .myApp { + width: 50%; + margin: auto; + } +</style> diff --git a/src/components/hello.vue b/src/components/hello.vue new file mode 100755 index 0000000000000000000000000000000000000000..cbdc95beb5306f53995388e90f34cdd61550101f --- /dev/null +++ b/src/components/hello.vue @@ -0,0 +1,26 @@ +<template> + <v-app> + <h1>환영합니다, {{this.$store.state.userName}}님!</h1> + <p>{{this.$store.state.userID}}로 접속하셨습니다.</p> + </v-app> +</template> + +<script> +export default { + data() { + return { + } + }, + + mounted(){ + if(this.$store.state.userID == ""){ + alert("비정상적인 접근입니다."); + this.$router.push("/"); + return; + } + } +} +</script> + +<style lang="css" scoped> +</style> diff --git a/src/components/login.vue b/src/components/login.vue new file mode 100755 index 0000000000000000000000000000000000000000..9387a5a09a3041ac5b19f1e46e9684a2500d4d95 --- /dev/null +++ b/src/components/login.vue @@ -0,0 +1,101 @@ +<template> +<v-app> + <v-card> + <v-card-text>로그인</v-card-text> + <v-card-text>테스트용 계정, id/pw 둘 다 1234</v-card-text> + <v-form v-model="formValid" ref="loginForm"> + <v-text-field v-model="studentId" label="학번" :rules="[rules.required, rules.numberOnly]"></v-text-field> + <v-text-field v-model="password" label="비밀번호" :rules="[rules.required]"></v-text-field> + <v-btn color="success" @click="onPushLogin"> + <span v-if="!isLogging">로그인</span> + <v-progress-circular v-if="isLogging" indeterminate></v-progress-circular> + </v-btn> + </v-form> + <v-expand-transition> + <v-alert v-show="connectionError" type="error">서버와의 통신에 실패하였습니다.</v-alert> + </v-expand-transition> + <v-expand-transition> + <v-alert v-show="loginError" type="error">등록되지 않은 학번이거나 잘못된 비밀번호입니다.</v-alert> + </v-expand-transition> + <v-card-text>비밀번호가 기억나지 않으십니까?</v-card-text> + </v-card> +</v-app> +</template> + +<script> +import ruleModule from '../plugins/textFieldRules.js'; + +export default { + name: "loginVue", + + data() { + return { + studentId: "", + password: "", + formValid: false, + rules: ruleModule, + isLogging: false, + connectionError: false, + loginError: false + } + }, + + methods: { + async onPushLogin() { + if (this.$refs.loginForm.validate() == false) { + return; + } + + this.isLogging = true; + this.connectionError = false; + this.loginError = false; + + let responseBody; + let id = this.studentId; + + try { + let bodyData = { + id: this.studentId, + pw: this.password + } + + let requestPromis = + fetch('/login', { + method: 'POST', // POST 메소드 지정 + body: JSON.stringify(bodyData), //express가 이해할 수 있는 JSON 형태로 POST 데이터 변환 + headers: { + 'Content-Type': 'application/json' + }, + }); + + let responseData = await requestPromis; + + let responseBodyJsonString = await responseData.json(); //json 포맷에 맞는 string으로 반환해 준다. + + responseBody = JSON.parse(responseBodyJsonString); //string으로 된 포맷을 자바스크립트 오브젝트로 변환 + } catch (e) { + this.isLogging = false; + this.connectionError = true; + this.loginError = false; + return; + } + + this.connectionError = false; + this.isLogging = false; + + if(responseBody.msg != "OK"){ + this.loginError = true; + + return; + } + + this.$store.state.userID = id; + this.$store.state.userName = responseBody.userName; + this.$router.push("/main"); + } + } +} +</script> + +<style lang="css" scoped> +</style> diff --git a/src/main.js b/src/main.js old mode 100644 new mode 100755 index 63eb05f711c8cb5cda45128882fa69c351f105fb..0527e5038e8cd4231dc45230da1dd0e8bc22d469 --- a/src/main.js +++ b/src/main.js @@ -1,8 +1,14 @@ import Vue from 'vue' import App from './App.vue' +import router from './router' +import store from './store' +import vuetify from './plugins/vuetify'; Vue.config.productionTip = false new Vue({ - render: h => h(App), + router, + vuetify, + store, + render: h => h(App) }).$mount('#app') diff --git a/src/plugins/textFieldRules.js b/src/plugins/textFieldRules.js new file mode 100755 index 0000000000000000000000000000000000000000..9f82a1e05bfe5b7f077cc7f133be69eb93d81a7e --- /dev/null +++ b/src/plugins/textFieldRules.js @@ -0,0 +1,54 @@ +export default { + required(v) { + if (!!v == false) { + return "입력을 비울 수 없습니다."; + } + + return true; + }, + + realNumber(v) { + if (v == 0) { + return true; + } + + if (!(v * 1)) { + return "숫자를 입력하십시오."; + } + + return true; + }, + + integer(v) { + if (Number.isInteger(v*1)) { + return true; + } + + return "정수를 입력하십시오."; + }, + + positiveNumber(v) { + if (this.realNumber(v) === true) { + if (v > 0) { + return true; + } else { + return "양수를 입력하십시오."; + } + } else { + return "숫자를 입력하십시오."; + } + }, + + numberOnly(v) { + v = String(v); + + for(let i=0; i<v.length; i++){ + if(isNaN(v[i]*1)){ + return "숫자만 입력해 주십시오."; + } + } + + return true; + + } +}; diff --git a/src/plugins/vuetify.js b/src/plugins/vuetify.js new file mode 100755 index 0000000000000000000000000000000000000000..ec46adba2aaa77b49b11610f823693e1525fac91 --- /dev/null +++ b/src/plugins/vuetify.js @@ -0,0 +1,7 @@ +import Vue from 'vue'; +import Vuetify from 'vuetify/lib'; + +Vue.use(Vuetify); + +export default new Vuetify({ +}); diff --git a/src/router/index.js b/src/router/index.js new file mode 100755 index 0000000000000000000000000000000000000000..988bb69f87204274fa09a181626b4ede9cb179e4 --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,26 @@ +import Vue from 'vue' +import VueRouter from 'vue-router' +import login from '../components/login.vue'; +import hello from '../components/hello.vue'; + +Vue.use(VueRouter) + +const routes = [ + { + path: '/', + name: 'login', + component: login + }, + { + path: "/main", + name: "main", + component: hello + } +] + +const router = new VueRouter({ + mode: "history", + routes +}) + +export default router diff --git a/src/store/index.js b/src/store/index.js new file mode 100755 index 0000000000000000000000000000000000000000..1ef0d6752e2d814e2b39dd47072ffb9b458fa61c --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,18 @@ +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) + +export default new Vuex.Store({ + state: { + userID: "", + userName: "", + test: 3 + }, + mutations: { + }, + actions: { + }, + modules: { + } +}) diff --git a/src/views/About.vue b/src/views/About.vue new file mode 100755 index 0000000000000000000000000000000000000000..3fa28070de24f2055171ca2e20543881cb7fdf1c --- /dev/null +++ b/src/views/About.vue @@ -0,0 +1,5 @@ +<template> + <div class="about"> + <h1>This is an about page</h1> + </div> +</template> diff --git a/src/views/Home.vue b/src/views/Home.vue new file mode 100755 index 0000000000000000000000000000000000000000..fc2e9402a0fbec85a9dd7f273084bfd2196aaa22 --- /dev/null +++ b/src/views/Home.vue @@ -0,0 +1,18 @@ +<template> + <div class="home"> + <img alt="Vue logo" src="../assets/logo.png"> + <HelloWorld msg="Welcome to Your Vue.js App"/> + </div> +</template> + +<script> +// @ is an alias to /src +import HelloWorld from '@/components/HelloWorld.vue' + +export default { + name: 'home', + components: { + HelloWorld + } +} +</script> diff --git a/vue.config.js b/vue.config.js new file mode 100755 index 0000000000000000000000000000000000000000..ef6e86b246abc49a30b8763abba79e6bb9e8cf4e --- /dev/null +++ b/vue.config.js @@ -0,0 +1,5 @@ +module.exports = { + "transpileDependencies": [ + "vuetify" + ] +} \ No newline at end of file