Commit f8a4c4ae by SHINDAESUB

first commit

parents
TEACHING_RESOLUTION=(3840x2160)
TEACHING_IMAGE_PATH=/home/firefly/2001_0033_neuromorphic/falinux/old_2020/sds/backend/public/image/capture.jpg
\ No newline at end of file
TEACHING_RESOLUTION=(3840x2160)
TEACHING_IMAGE_PATH=/home/firefly/2001_0033_neuromorphic/falinux/old_2020/sds/backend/public/image/capture.jpg
node_modules
public/
# Node.js 설치
## 설치
- curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
- sudo apt-get update
- sudo apt-get install -y nodejs build-essential
## 프로젝트 실행 안될 경우
- 프로젝트 폴더/ rm -rf node_modules
- 프로젝트 폴더/ npm install
## NPM 이상 있을 경우
- sudo npm cache clean --force
- Sudo npm install –g n
- sudo n stable
- sudo npm install –g npm
* 참고 : https://d2fault.github.io/2018/04/30/20180430-install-and-upgrade-nodejs-or-npm/
## 버전확인
- Node : node.js -v
- NPM : npm –v
## Vue 설치
- sudo npm install -g @vue/cli
## cache 삭제
- sudo npm cache verify
- sudo npm cache clean --force
test
\ No newline at end of file
const express = require('express')
const http = require('http')
const path = require('path')
const fs = require('fs');
const dgram = require('dgram');
const dotenv = require('dotenv');
const app = express()
const bodyParser = require('body-parser'); //
dotenv.config({
path: path.resolve(
process.cwd(),
process.env.NODE_ENV == "production" ? ".env" : ".env.dev"
)
});
const server = dgram.createSocket('udp4');
// socket 실행
server.bind(9400);
server.on('listening', function() {
console.log('Socket Port : 9400');
});
server.on('message', function(msg, rinfo) {
udpResultMsg = msg.toString();
});
server.on('close', function() {
console.log('Server UDP Socket close');
});
const client = dgram.createSocket('udp4');
const clientPort= 9300;
// const clientPort= 4403;
// const clientHost = '192.168.52.122'; //inet
const clientHost ='127.0.0.1';
// Error [ERR_SOCKET_DGRAM_NOT_RUNNING]: Not running
client.on('close', function() {
console.log('Client UDP socket close')
});
const jsonFile = fs.readFileSync('./json/projects.json', 'utf8');
// console.log(jsonFile);
const jsonData = JSON.parse(jsonFile);
console.log(jsonData);
//Post 방식은 Get 과 다르기 때문에 body-parser 를 설치해서 사용해야한다.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))
//vue router 연동하기 위한 설정
app.use(require('connect-history-api-fallback')());
app.use(express.static(path.join(__dirname, 'public')));
app.set('port',process.env.PORT || 3000);
/* udp 통신으로 매니저에게 받는 결과값*/
let udpResultMsg = ''
/* udp 통신 기다리는 시간*/
let udpAwaitTime = 0
let newProjectNum = 0
//json 파일 불러오기
app.get('/api/getProjectList',(req,res) => {
res.send(jsonData)
})
//USER - 검수 완료후 티칭 정보 수정
app.post('/api/teachingInfoModify',(req,res) => {
console.log("수정할 번호 req.body.project_num :"+ req.body.project_num)
fs.readFile('./json/projects.json', 'utf8',(err ,data) => {
let showData = JSON.parse(data)
for(var key in showData){
if(showData[key].project_num === req.body.project_num){
if(req.body.result){
showData[key].current_done++
}else{
showData[key].current_reject++
}
showData[key].current_counter++
}
}
fs.writeFile('./json/projects.json', JSON.stringify(showData), (err)=>{
if (err) throw err;
console.log('JSON File Update Complete');
});
})
}),
//ADMIN - project 새 번호 가져오기 : 캡처 이미지 이름과 프로젝트 생성하기 위함
app.get('/api/projectCreateNum',(req,res) => {
fs.readFile('./json/project_num_seq.json', 'utf8', (err ,data) => {
let showData = JSON.parse(data)
newProjectNum = ++showData[0].project_num_seq
console.log("newProjectNum : ",newProjectNum)
if(err)
console.error("읽어오기 실패")
res.json(newProjectNum)
});
}),
// ADMIN - 프로젝트 생성
app.post('/api/projectCreate',(req,res) => {
console.log(" ------------------------- ")
console.log(" 메시지 뭐냐? ",req.body)
console.log(" ------------------------- ")
fs.readFile('./json/projects.json', 'utf8',(err ,data) => {
let showData = JSON.parse(data)
let retrunMsg = ''
showData[newProjectNum-1] = {
project_num: newProjectNum,
project_name: req.body.project.project_name,
total_num: req.body.project.total_num,
project_user: req.body.project.project_user,
project_admin: req.body.project.project_admin,
current_counter: req.body.project.current_counter,
current_done: req.body.project.current_done,
current_reject: req.body.project.current_reject,
image_path: req.body.project.image_path,
start_date: req.body.project.start_date,
end_date: req.body.project.end_date,
project_state: '',
success_teaching:req.body.successRect,
fail_teaching:req.body.failRect
},
retrunMsg = `${req.body.project_name} 저장 되었습니다.`
console.log('showData :' ,showData)
console.log("newProjectNum :",newProjectNum)
fs.writeFile('./json/projects.json', JSON.stringify(showData), (err)=>{
if (err) throw res.send(err)
console.log('"projects.json" File Update Complete');
// res.status(200)
res.send( {result:true ,project_num:newProjectNum })
});
fs.readFile('./json/project_num_seq.json', 'utf8',(err ,data) => {
let showData = JSON.parse(data)
console.log('RESULT newProjectNum :' ,newProjectNum)
console.log('RESULT showData :' ,showData[0].project_num_seq)
showData[0].project_num_seq = newProjectNum
fs.writeFile('./json/project_num_seq.json', JSON.stringify(showData), (err)=>{
if (err) throw res.send(err)
console.log('"project_num_seq.json" File Update Complete');
});
})
})
})
//ADMIN - project 상태 (삭제 ,수정 )변경
app.post('/api/projectUpdate',(req,res) => {
console.log(" ------------------------- ")
console.log(" projectUpdate : ? ",req.body.msg)
console.log(" ------------------------- ")
fs.readFile('./json/projects.json', 'utf8',(err ,data) => {
let showData = JSON.parse(data)
let retrunMsg = ''
for(var key in showData){
if(showData[key].project_num === req.body.project_num){
if(req.body.msg === "remove"){
showData[key].project_state = "req.body.msg"
retrunMsg = `${req.body.project_name} 삭제 되었습니다.`
}else if(req.body.msg === "update"){
showData[key].project_admin = req.body.project_admin
showData[key].project_user = req.body.project_user
showData[key].total_num = req.body.total_num
showData[key].start_date = req.body.start_date
showData[key].end_date = req.body.end_date
retrunMsg = `${req.body.project_name} 수정 되었습니다.`
}else {
res.send(err)
}
}
}
fs.writeFile('./json/projects.json', JSON.stringify(showData), (err)=>{
if (err) throw res.send(err)
console.log('JSON File Update Complete');
// res.status(200)
res.send(retrunMsg)
});
})
})
const wrapper = asyncFn => { return (async (req, res, next) => { try { return await asyncFn(req, res, next); } catch (error) { return next(error); } }); };
//https://kjwsx23.tistory.com/199 express 와 async ,await 이슈
//express async await wrapper 함수를 써서 감싸거나 라이브러리를 써야 한다.
app.get('/api/requestManager',wrapper(async (req,res)=>{
req.query.image_path = process.env.TEACHING_IMAGE_PATH
if(req.query.cmd === "neuro_check") req.query.teaching = `${process.env.TEACHING_IMAGE_PATH}-test-2-${process.env.TEACHING_RESOLUTION}-${req.query.teaching_info}`
//req.query.project_num
console.log("param :",JSON.stringify(req.query) )
sendToManager (JSON.stringify(req.query))
let requestMsg = ''
switch(req.query.cmd){
case "neuro_start":
requestMsg = 'neuro_start_done'
break
case "neuro_ready":
requestMsg = 'neuro_ready_done'
break
case "neuro_capture":
requestMsg = 'capture_done'
break
case "neuro_check" :
requestMsg = 'neuro_result'
break
default:
res.status(404)
}
await responseManager(requestMsg)
.then(data => {
res.status(200).json(data)
})
.catch(error =>{
res.status(404).send(error);
})
}))
//UDP 메세지 보냄 통신
function sendToManager(msg){
client.send(msg, 0, msg.length, clientPort, clientHost, function(err) {
if ( err ) return ;
console.log("UDP send Msg ")
});
}
// await Promise 응답해야됨
function responseManager (requestMsg) {
return new Promise((resolve, reject) => {
let delay = 100; //ms 단위로 체크
let waitingTime = 0 //대기 시간
let timer = setInterval(() => {
if(requestMsg === JSON.parse(udpResultMsg).cmd ){
console.log(`json 데이터는 ? ${JSON.parse(udpResultMsg).cmd}`)
resolve(udpResultMsg)
clearInterval(timer)
}else if(waitingTime === 5000){
reject('No response from Manager')
clearInterval(timer)
}else{
waitingTime = waitingTime + delay
}
},delay)
});
}
http.createServer(app).listen(app.get('port'),function(){
console.log('WebServer Port: ' +app.get('port'))
})
[{"project_num_seq":4}]
\ No newline at end of file
[{"project_num":1,"project_name":"프로젝트 1","total_num":5,"project_user":"테스트 유저","project_admin":"테스트 관리자","current_counter":7,"current_done":0,"current_reject":7,"image_path":"/image/capture.png","start_date":"2020-10-30","end_date":"2020-10-30","project_state":"","teaching":[{"id":0,"x":336,"y":149,"width":122,"height":80,"stroke":"#4689B3","listening":false,"state":null,"lx":458,"ly":229},{"id":1,"x":540,"y":309,"width":87,"height":143,"stroke":"#B3468B","listening":false,"state":null,"lx":627,"ly":452},{"id":2,"x":246,"y":245,"width":118,"height":164,"stroke":"#46A9B3","listening":false,"state":null,"lx":364,"ly":409},{"id":3,"x":544,"y":57,"width":114,"height":116,"stroke":"#76B346","listening":false,"state":null,"lx":658,"ly":173}]},{"project_num":2,"project_name":"프로젝트 2","total_num":7,"project_user":"테스트 유저","project_admin":"테스트 관리자","current_counter":0,"current_done":0,"current_reject":0,"image_path":"/image/capture.png","start_date":"2020-10-30","end_date":"2020-10-30","project_state":"","teaching":[{"id":0,"x":468,"y":140,"width":133,"height":120,"stroke":"#F90081","listening":false,"state":null,"lx":601,"ly":260},{"id":1,"x":237,"y":268,"width":139,"height":127,"stroke":"#00F9A9","listening":false,"state":null,"lx":376,"ly":395},{"id":2,"x":458,"y":336,"width":116,"height":110,"stroke":"#00A2F9","listening":false,"state":null,"lx":574,"ly":446}]},{"project_num":3,"project_name":"프로젝트 3","total_num":10,"project_user":"테스트 유저","project_admin":"테스트 관리자","current_counter":0,"current_done":0,"current_reject":0,"image_path":"/image/capture.png","start_date":"2020-10-30","end_date":"2020-10-30","project_state":"","teaching":[]},{"project_num":4,"project_name":"테스트","total_num":15,"project_user":"테스트 유저","project_admin":"테스트 관리자","current_counter":1,"current_done":0,"current_reject":1,"image_path":"/image/capture.png","start_date":"2020-10-30","end_date":"2020-10-30","project_state":"","teaching":[{"id":0,"x":530,"y":78,"width":63,"height":80,"stroke":"#F9001F","listening":false,"state":null,"lx":593,"ly":158},{"id":1,"x":201,"y":245,"width":171,"height":118,"stroke":"#F300F9","listening":false,"state":null,"lx":372,"ly":363},{"id":2,"x":172,"y":71,"width":169,"height":122,"stroke":"#00F939","listening":false,"state":null,"lx":341,"ly":193}]}]
\ No newline at end of file
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"connect-history-api-fallback": "^1.6.0",
"dotenv": "^10.0.0",
"express": "^4.17.1"
}
}
.DS_Store
node_modules
/dist
/tests/e2e/reports/
selenium-debug.log
chromedriver.log
geckodriver.log
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# front-end
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your unit tests
```
npm run test:unit
```
### Run your end-to-end tests
```
npm run test:e2e
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e",
"lint": "vue-cli-service lint",
"start": "npm run serve",
"build2": "npm run build"
},
"dependencies": {
"chart.js": "^2.9.4",
"core-js": "^3.6.5",
"konva": "^7.1.3",
"register-service-worker": "^1.7.1",
"vue": "^2.6.11",
"vue-chartjs": "^3.5.1",
"vue-konva": "^2.1.6",
"vue-router": "^3.2.0",
"vuetify": "^2.2.11",
"vuex": "^3.4.0"
},
"devDependencies": {
"@mdi/js": "^5.5.55",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-e2e-nightwatch": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-pwa": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-unit-jest": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/test-utils": "^1.0.3",
"babel-eslint": "^10.1.0",
"chromedriver": "85",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"vue-cli-plugin-vuetify": "~2.0.7",
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.3.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {},
"overrides": [
{
"files": [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)"
],
"env": {
"jest": true
}
}
]
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
],
"jest": {
"preset": "@vue/cli-plugin-unit-jest"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></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 <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
</body>
</html>
[
{
"project_num":1,
"total_num":0,
"current_done":0,
"current_reject":0,
"image_path":"image/test1",
"start_date":"2020-08-31",
"end_date":"2020-09-31"
},
{
"project_num":2,
"total_num":0,
"current_done":0,
"current_reject":0,
"image_path":"image/test2",
"start_date":"2020-09-31",
"end_date":"2020-10-31"
},
{
"project_num":3,
"total_num":0,
"current_done":0,
"current_reject":0,
"image_path":"image/test3",
"start_date":"2020-07-12",
"end_date":"2020-09-31"
}
]
\ No newline at end of file
User-agent: *
Disallow:
<template>
<v-app>
<v-main>
<Alert
:open="alertOpen"
:message="message"
:type="type"
/>
<!-- <Progress
:update="progressUpdate"
:open="progressOpen"
:number="progressNumber"
:label="progressLabel"
/> -->
<router-view/>
</v-main>
</v-app>
</template>
<script>
import EventBus from './event-bus'
import Alert from './components/Alert.vue'
export default {
name: 'App',
components: {
Alert
},
created() {
EventBus.$on('openAlert',( massage , type) => {
this.alertOpen = true,
this.message = massage,
this.type = type
}),
EventBus.$on('closeAlert',() => {
this.alertOpen = false
})
},
data: () => ({
alertOpen: false ,
message:'',
type:'',
}),
mounted(){
this.$store.dispatch('getProjectList')
},
};
</script>
<style lang="scss">
:root{
/* Color */
--admin-color: #0091ea;
--user-color: #338a3e; //338a3e
--white : #f2f2f2;
--gray: #6A79A6;
--red: #ff1744;
/* Font Size */
--font-l: 24px;
--font-r: 20px;
--font-m: 18px;
--font-s: 16px;
--font-mc: 14px;
}
html,body{
padding: 0;
margin: 0;
height: 100%;
width: 100%
}
#app {
height: 100%;
width: 100%;
}
</style>
<template>
<v-overlay
:value="openAlert"
:z-index="20"
>
<v-alert
:type="type"
dismissible
@click="closeAlert()"
>
{{ message }}
</v-alert>
</v-overlay>
</template>
<script>
import EventBus from '../event-bus'
export default {
props: {
open:Boolean,
message:String,
type:String,
},
watch: {
open(newVal) {
if (newVal) {
setTimeout(() => {
this.closeAlert()
}, 2000);
}
},
},
computed: {
openAlert: {
get() {
return this.open;
},
set() {
this.closeAlert()
},
},
},
methods:{
closeAlert(){
EventBus.$emit("closeAlert");
}
}
};
</script>
\ No newline at end of file
<script>
// import VueCharts from 'vue-chartjs'
import { Doughnut,mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
//https://www.chartjs.org/docs/latest/charts/line.html 옵션
//https://www.chartjs.org/samples/latest/
export default {
extends: Doughnut, //차트 종류 ex)bar
mixins: [ reactiveProp] ,
props:{
chartdata:Object,
percent: Number,
},
data () {
return {
options: {
title: {
display: false,
// text: 'title'
},
legend: {
position: 'bottom',
display: true,
},
responsive: true,
maintainAspectRatio: false
},
}
},
mounted () {
this.addPlugin({
id: 'my-plugin',
beforeDraw: this.centerText
})
this.renderChart(this.chartData, this.options )
},
methods: {
//가운데 퍼센트 표시하기 위함
centerText(chart){
let width = chart.chart.width;
let height = chart.chart.height;
let ctx = chart.chart.ctx;
ctx.restore();
let fontSize = (height / 150).toFixed(2);
ctx.font = fontSize + "em sans-serif" ;
ctx.textBaseline = "middle";
let text = this.percent+'%';
let textX = Math.round((width - ctx.measureText(text).width) / 2);
let textY = height / 2.2;
ctx.fillText(text, textX, textY);
ctx.save();
}
}
}
</script>
\ No newline at end of file
import Vue from 'vue'
const eventBus = new Vue({})
export default eventBus
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify';
import axios from 'axios'
import VueKonva from 'vue-konva'
Vue.use(VueKonva)
axios.defaults.baseURL = '/api' //모든 요청에 '/api' 붙도록 기본 설정
axios.defaults.headers.common.Accept = 'application/json'//JSON 형식으로만 받는다
axios.interceptors.response.use( //Error 전파하기 위해 인터셉터 응답을 추가한다.
response => response,
(error) => {
return Promise.reject(error)
}
)
//Vue.prototype.$http = axios //vue 컴포넌트에서 this.$http 요청할 수 있게 된다.
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')
<template>
<v-overlay v-if="open" :z-index="10">
<v-card width="1200" color="grey lighten-3" class="d-flex flex-column mx-auto">
<v-toolbar
color="#66bb6a"
elevation="0"
>
<v-toolbar-title class="font-weight-black">
Teaching
</v-toolbar-title>
</v-toolbar>
<v-card-text>
<v-row>
<v-col cols="6">
<Info
:counter="totalCounter"
:info="info"
:list="teachingList"
/>
</v-col>
<v-col>
<Stepper
:counter="totalCounter"
:step="step"
:roading="roading"
:errorMessage="errorMessage"
:percent="percent"
:fail="failResult"
:success="successResult"
:fpga="fpgaResult"
:response="responseResult"
/>
</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn
class="font-weight-bold"
text
color="primary"
:disabled="step === 5 ? false : true"
@click="save()"
>
save
</v-btn>
<v-btn
light
text
:disabled="step === 5 || step === 1 ? false : true"
@click="close()"
>
close
</v-btn>
</v-card-actions>
</v-card>
</v-overlay>
</template>
<script>
import EventBus from '../event-bus'
import Info from './TeachungModal/Info.vue'
import Stepper from './TeachungModal/Stepper.vue'
import teachingService from '@/service/teaching'
export default {
props: {
open:Boolean,
info:Object,
totalCounter:Number
},
data () {
return {
step:1,
counter:0,
roading:false,
errorMessage:'',
teachingList: [],
failResult:0,
successResult:0,
fpgaResult:0,
responseResult:0,
percent:0
}
},
components:{
Info,
Stepper
},
created () {
EventBus.$on('start',() =>{ this.neuroStart()})
EventBus.$on('retry',(step) => {this.retry(step)})
},
methods:{
retry(step){
this.requestInit()
switch (step){
case 2:
this.neuroReady()
break;
case 3:
this.neuroCapture()
break;
case 4:
this.neuroCheck()
break;
case 5:
this.step = 1
this.teachingList = []
this.counter = 0
break;
}
},
requestFail(message){
this.roading = false
this.errorMessage = `Error : ${message}`
},
requestInit(){
this.roading = true
this.errorMessage = ''
},
async neuroStart(){
let msg = new Object()
msg.cmd = "neuro_start"
msg.project_num = this.info.project_num
await teachingService.requestManager(msg)
.then(data => {
console.log(data)
this.step = 2
})
.catch(error =>{
console.log(error.response)
error.response.data !== undefined ? this.requestFail(error.response.data) : this.requestFail(error.response.status)
})
},
async neuroReady(){
let msg = new Object()
msg.cmd = "neuro_ready"
await teachingService.requestManager(msg)
.then(data => {
console.log(data)
this.step = 3
})
.catch(error =>{
console.log(error.response)
error.response.data !== undefined ? this.requestFail(error.response.data) : this.requestFail(error.response.status)
})
},
async neuroCapture(){
let msg = new Object()
msg.cmd = "neuro_capture"
await teachingService.requestManager(msg)
.then(data => {
console.log(data)
this.step = 4
})
.catch(error =>{
console.log(error.response)
error.response.data !== undefined ? this.requestFail(error.response.data) : this.requestFail(error.response.status)
})
},
async neuroCheck(){
let msg = new Object()
msg.cmd = "neuro_check"
msg.project_num = this.info.project_num
msg.teaching_info ='(1113,720,1329,840)-(1626,504,1788,651)-(1953,816,2049,978)'
await teachingService.requestManager(msg)
.then(data => {
this.counter = ++this.counter
let teaching = JSON.parse(data.data)
let result = new Object()
result.counter = this.counter
result.state = teaching['result']
result.response = parseFloat(teaching['proc_time'])
result.fpga = 0
this.teachingList.push(result)
this.counter === this.totalCounter ? this.step = 5 : this.step = 2
})
.catch(error =>{
error.response.data !== undefined ? this.requestFail(error.response.data) : this.requestFail(error.response.status)
})
},
resultCounter(){
this.failResult = 0
this.successResult = 0
this.fpgaResult = 0
this.responseResult = 0
this.percent =0
let stateArr = this.teachingList.map(teaching => { return teaching['state']})
let responseArr = this.teachingList.map(teaching => { return teaching['response']})
let fpgaArr = this.teachingList.map(teaching => { return teaching['fpga'] })
stateArr.forEach(state => { state === 0 ? ++this.failResult : ++this.successResult})
this.fpgaResult = fpgaArr.reduce((stack, el)=>{ return stack + el }, 0)
this.responseResult = responseArr.reduce((stack, el)=>{ return stack + el}, 0)
this.fpgaResult = this.fpgaResult > 0 ? Number(this.fpgaResult.toFixed(7)) : 0
this.responseResult =this.responseResult > 0 ? Number(this.responseResult.toFixed(7)) : 0
this.percent = this.success / this.totalCounter * 100 > 0 ? Number((this.success/ this.totalCounter * 100).toFixed(0)) : 0
},
close(){
this.counter = 0
this.step = 1
this.teachingList = []
EventBus.$emit('projectModalClose')
}
},
watch:{
'step': function(newVal){
if(newVal === 2){
this.requestInit()
this.neuroReady()
}else if(newVal === 3){
this.requestInit()
this.neuroCapture()
}else if(newVal === 4){
this.requestInit()
this.neuroCheck()
}else if(newVal === 5){
this.resultCounter()
}
}
},
beforeDestroy(){
EventBus.$off('start');
EventBus.$off('requestRetry');
}
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<v-card
light
max-height="600"
min-height="600"
>
<v-card-text>
<v-row no-gutters>
<v-col cols='6' class="ma-0 pa-0">
<div class="text-h5 font-weight-black">{{info.project_name}}</div>
<p>{{info.start_date}} - {{info.end_date}} </p>
<p>관리자 <span>: {{info.project_admin }}</span></p>
<p>작업자 <span >: {{info.project_user }}</span></p>
<p>검수 횟수 :<span class="primary--text font-weight-bold"> {{counter }}</span></p>
</v-col>
<v-col cols='6' class="ma-0 pa-0">
<v-img
:src="host"
contain
width="350"
height="190"
color="grey"
>
</v-img>
</v-col>
</v-row>
<v-data-table
light
height="300"
max-height="300"
min-height="300"
:headers="headers"
:items="list"
:items-per-page="5"
no-data-text="검수 이력이 없습니다."
class="elevation-1 mt-5"
:sort-by="['counter']"
:sort-desc="[true]"
:footer-props="{
'items-per-page-text':'페이지 수'
}"
>
<template v-slot:[`item.state`]="{ item }">
<v-chip
:color="item.state === 0 ? 'error' : 'success'"
dark
>
{{ item.state === 0 ? 'Fail' : 'Success' }}
</v-chip>
</template>
</v-data-table>
</v-card-text>
</v-card>
</template>
<script>
export default {
props: {
info:Object,
list:Array,
counter:Number,
},
data () {
return {
headers: [
{ text: '횟수', align: 'start', sortable: false, value: 'counter',},
{ text: '상태', value: 'state' },
{ text: '응답 속도', value: 'response' },
{ text: 'FPGA 속도', value: 'fpga' },
],
}
},
computed:{
host(){
let protocol = location.protocol;
let hostName = location.hostname === 'localhost' ? '192.168.53.196': location.hostname
return protocol+'//'+hostName+':'+8081
}
},
}
</script>
<style>
</style>
\ No newline at end of file
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
Vue.use(Vuetify);
export default new Vuetify({
icons: {
iconfont: 'mdiSvg',
},
});
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.\n' +
'For more details, visit https://goo.gl/AFskqB'
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import List from '../views/User/List.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/list',
name: 'list',
component: List
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
import axios from 'axios'
export default {
async projectCreateNum() {
try{
const result = await axios.get('/projectCreateNum')
return result.data
} catch (error) {
return error.message
}
},
async projectCreate(data) {
try{
const result = await axios.post('/projectCreate',data)
return result
} catch (error) {
return error.message
}
},
async projectCapture (data) {
try{
const result = await axios.get('/requestManager',{ params: data })
return result
} catch (error) {
return error.message
}
},
// axios.get('/neuroCapture',{ params: param })
projectUpdate (data) {
console.log("파라미터 : " ,data)
return new Promise((resolve,reject) =>{
// axios.post('/projectModify',{ params: data })
axios.post('/projectUpdate',data)
.then(({data}) => {
resolve(data)})
.catch((error) => {
reject(new Error(`${error} 요청 실패입니다.`));
})
})
},
projectRemove (data) {
console.log("파라미터 : " ,data)
return new Promise((resolve,reject) =>{
// axios.post('/projectModify',{ params: data })
axios.post('/projectUpdate',data)
.then(({data}) => {
resolve(data)})
.catch((error) => {
reject(new Error(`${error} 요청 실패입니다.`));
})
})
}
}
\ No newline at end of file
export default{
neuroStart (param){
return new Promise((resolve,reject) => {
console.log("param :", param)
console.log("param.cmd :",JSON.parse(param).cmd)
JSON.parse(param).cmd === "neuro_start" ? resolve(param) : reject(new Error("요청 값이 틀립니다."))
})
},
neuroCapture (param){
return new Promise((resolve,reject) => {
console.log("param :", param)
console.log("param.cmd :",JSON.parse(param).cmd)
JSON.parse(testJson).cmd === "capture_done" ? resolve(testJson) : reject(new Error("요청 값이 틀립니다."))
})
},
neuroCheck (param){
return new Promise((resolve,reject) => {
console.log("param :", param)
console.log("JSON.parse(param).cmd :",JSON.parse(param).cmd)
JSON.parse(param).cmd === "neuro_check" ? resolve("검수 성공 ") : reject(new Error("요청 값이 틀립니다."))
})
},
neuroSave (param){
return new Promise((resolve,reject) => {
console.log("param :", param)
JSON.parse(testJson).cmd === "capture_done" ? resolve(testJson) : reject(new Error("요청 값이 틀립니다."))
})
},
}
\ No newline at end of file
import axios from 'axios'
export default {
getProjectList () {
return new Promise((resolve,reject) =>{
axios.get('/getProjectList')
.then(({data}) => {
resolve(data)})
.catch((error) => {
reject(new Error(`${error} 요청 실패입니다.`));
})
})
},
projectModify (data) {
console.log("파라미터 : " ,data)
return new Promise((resolve,reject) =>{
axios.post('/teachingInfoModify',data)
.then(({data}) => {
resolve(data)})
.catch((error) => {
reject(new Error(`${error} 요청 실패입니다.`));
})
})
}
}
\ No newline at end of file
import axios from 'axios'
/* {data} 받으면 data.data. => data. 접근 가능 */
export default{
async requestManager (param) {
try{
const result = await axios.get('/requestManager',{ params: param })
return Promise.resolve(result)
} catch (error) {
return Promise.reject(error)
}
},
}
\ No newline at end of file
import projectService from '@/service/project'
export const getProjectList = ({commit}) => {
projectService.getProjectList()
.then(data => {
commit('projectList',data)
})
}
export const modifyPoject = ({commit}, info) => {
commit('modifyPoject', info)
}
export const projectUpdate = ({commit}, updateData) => {
commit('projectUpdate', updateData)
}
export const projectAdd = ({commit}, newData) => {
commit('projectAdd', newData)
}
export const projectList = state => state.projectList
export const projectListS = state => {
return state.projectList.filter(s => s.project_state === "success")
}
export const projectListW = state => {
return state.projectList.filter(w => w.project_state === "waiting")
}
export const projectListP = state => {
return state.projectList.filter(p => p.project_state === "proceeding")
}
export const projectListC = state => {
return state.projectList.filter(c => c.project_state === "")
}
import Vue from 'vue'
import Vuex from 'vuex'
import * as getters from './getters'
import * as actions from './actions'
import mutations from './mutations'
import createLogger from 'vuex/dist/logger'
/* state 값을 사용할 떄는 부모 컴포넌트, 공통 컴포넌트 에서 관리해야한다.*/
Vue.use(Vuex)
const state = {
projectList : [],
}
export default new Vuex.Store({
state,
getters,
mutations,
actions,
plugins: process.env.NODE_ENV !== 'production'
? [createLogger()]
: []
})
\ No newline at end of file
export default {
projectList (state , data){
// state.projectList.push(data)
state.projectList = data
},
modifyPoject(state , payload){
for(let i in state.projectList){
if(state.projectList[i].project_num === payload.project_num){
state.projectList[i].current_done = payload.current_done
state.projectList[i].current_reject = payload.current_reject
state.projectList[i].current_counter = payload.current_counter
// state.projectList[i].total_num = payload.total_num
}
}
},
projectUpdate(state, payload){
for(let i in state.projectList){
if(state.projectList[i].project_num === payload.project_num){
if(payload.msg === "update"){
state.projectList[i].project_admin = payload.project_admin
state.projectList[i].project_user = payload.project_user
state.projectList[i].total_num = payload.total_num
state.projectList[i].start_date = payload.start_date
state.projectList[i].end_date = payload.end_date
}else{
state.projectList[i].project_state = "remove"
}
}
}
},
projectAdd(state,payload){
state.projectList.push(payload)
}
}
\ No newline at end of file
<template>
<div class="select-page">
<div class="select-page-admin">
<div class="content">
<h1>뉴로모픽<br>관리자</h1>
<p>프로젝트를 생성하고 관리한다.<br><br></p>
<a href="https://www.nemopai.com/neuro/single/neuro/">시작</a>
</div>
</div>
<div class="select-page-user">
<div class="content">
<h1>뉴로모픽<br>사용자</h1>
<p>관리자가 만든 프로젝트를 선택하여<br>검수를 시작한다.<br> </p>
<router-link class="user" to="/list">시작</router-link>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Home',
}
</script>
<style lang="scss">
/* common */
.content {
font-family: 'Source Sans Pro';
color: var(--white);
line-height: 1.5; /* 줄의 높이*/
text-align: center;
img{
max-width: 100px;
min-height: 100px;
}
h1{
font-size: 60px;
}
a{
background-color: var(--white);
border-radius: 50px;
line-height: 50px; /* a태그 높이는 지정 */
width: 200px;
display: inline-block;
margin: 20px 0;
font-size: var(--font-large);
font-weight: bold;
font-size: var(--font-l);
text-decoration: none;
}
}
.select-page{
display: flex;
height: 100vh;
.select-page-admin{
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: var(--admin-color);
width: 100%;
height: 100%;
// &:hover{
// background-color: #9cff57;
// }
.content{
a{
color:var(--admin-color);
}
}
}
.select-page-user{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background-color: var(--user-color);
// &:hover{
// background-color: #9cff57;
// }
.content{
a{
color:var(--user-color);
}
}
}
}
</style>
\ No newline at end of file
<template>
<div class="pj-list d-flex justify-center align-center">
<v-container class="d-flex justify-center align-center">
<v-card
width="1800"
min-height="800"
color="grey lighten-3"
>
<v-toolbar
color="#66bb6a"
elevation="0"
>
<v-toolbar-title class="font-weight-black white--text" >
PROJECT
</v-toolbar-title>
</v-toolbar>
<v-card-text>
<v-row>
<v-col cols="6">
<List
:projectList="projectList"
/>
</v-col>
<v-col cols="6">
<No v-if="Object.keys(selectedProject).length === 0 && JSON.stringify(selectedProject) === JSON.stringify({})"/>
<Info v-else
:selectedProject="selectedProject"
/>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-container>
<TeachingModal
:open="teachingModal"
:info="teachingInfo"
:totalCounter="teachingCounter"
/>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import teachingService from '@/service/teaching'
import EventBus from '../../event-bus'
import List from '../User/List/List.vue'
import Info from '../User/List/Info.vue'
import No from './List/No.vue'
import TeachingModal from '@/modal/TeachingModal'
export default {
data () {
return {
projectHeader: [
{
text: '이름',
align: 'start',
sortable: false,
value: 'project_name',
},
{ text: '관리자', value: 'project_admin', sortable: false,},
{ text: '사용자', value: 'project_user', sortable: false,},
{ text: '생성일자', value: 'start_date', sortable: false,},
{ text: '완료일자', value: 'end_date', sortable: false, },
{ text: '조회', value: 'actions', sortable: false },
],
selectedProject:{},
teachingInfo:{},
teachingCounter:0,
teachingModal:false
}
},
components: {
TeachingModal,
List,
Info,
No
},
created () {
EventBus.$on('projectSelected',(project) =>{
console.log(project)
this.selectedProject = project
})
EventBus.$on('projectListReload',() =>{
this.selectedProject = {}
this.reload()
})
EventBus.$on('projectTeachingStart',(project,counter) => {
this.teachingStart(project,counter)
})
EventBus.$on('projectModalClose',() => {
this.teachingModal = false
})
},
computed: {
...mapGetters([
'projectList'
]),
},
methods: {
reload(){
this.$store.dispatch('getProjectList')
},
async teachingStart(project,counter){
this.teachingInfo = project,
this.teachingCounter = counter,
this.teachingModal = true
// const msg = new Object()
// msg.cmd = "neuro_start"
// msg.project_num = project.project_num
// await teachingService.requestManager(msg)
// .then((response) => {
// console.log(response)
// })
// .catch((error) => {return EventBus.$emit('openAlert',"ERROR : "+ error , 'error') })
// .finally(() => { this.$store.dispatch('offLoading')})
},
start (item) {
console.log("save 아이템 : "+JSON.stringify(item))
const startTeaching=confirm('작업을 시작하시겠습니까?')
if(startTeaching){
const msg = new Object()
msg.cmd = "neuro_start"
msg.project_num = item.project_num
this.$router.push({ name: 'teaching', params: item});
teachingService.requestManager(msg)
this.close()
}
},
},
}
</script>
<style lang="scss">
.pj-list{
background-color: var(--user-color);
height: 100vh;
}
</style>
\ No newline at end of file
<template>
<v-card class="d-flex flex-column" height="770" light>
<v-card-title class="text-h5 font-weight-black">
{{selectedProject.project_name}}
</v-card-title>
<v-card-subtitle>
{{selectedProject.start_date}} - {{selectedProject.end_date}}
</v-card-subtitle>
<v-card-text>
<v-row>
<v-col>
<v-text-field
label="관리자"
readonly
outlined
:value="selectedProject.project_admin"
>
</v-text-field>
</v-col>
<v-col>
<v-text-field
label="사용자"
readonly
outlined
:value="selectedProject.project_admin"
>
</v-text-field>
</v-col>
<v-col>
<v-text-field
label="검수 횟수"
ref="counterInput"
v-model.number="selectedProject.total_num"
outlined
type="number"
min="0"
>
</v-text-field>
</v-col>
</v-row>
<v-row>
<v-img
height="500"
width="500"
:src="selectedProject.image_path"
></v-img>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn
class="font-weight-bold"
outlined
color="primary"
@click="teaching(selectedProject)"
>
Teaching
</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import EventBus from '../../../event-bus'
export default {
props:{
selectedProject:Object
},
methods:{
teaching(project){
if(this.selectedProject.total_num === 0){
EventBus.$emit('openAlert',`검수 횟수를 '0' 이상의 값을 입력해주세요 ` , 'error')
return this.$refs.counterInput.focus()
}else{
EventBus.$emit('projectTeachingStart',project,this.selectedProject.total_num)
}
}
}
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<v-card max-height="770" light>
<v-toolbar
color="#98ee99"
>
<v-toolbar-title class="font-weight-bold white--text ">
List
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon @click="reload()">
<v-icon>mdi-refresh</v-icon>
</v-btn>
</v-toolbar>
<v-data-table
height="646"
max-height="646"
min-height="646"
:headers="projectHeader"
:items="projectList"
no-data-text="프로젝트가 없습니다"
sort-by="createDate"
class="elevation-1"
>
<template v-slot:[`item.actions`]="{ item }">
<v-chip
color="#80d8ff"
@click="selected(item)"
dark
>
선택
</v-chip>
</template>
</v-data-table>
</v-card>
</template>
<script>
import EventBus from '../../../event-bus'
export default {
data () {
return {
projectHeader: [
{
text: '이름',
align: 'start',
sortable: false,
value: 'project_name',
},
{ text: '관리자', value: 'project_admin', sortable: false,},
{ text: '사용자', value: 'project_user', sortable: false,},
{ text: '생성일자', value: 'start_date', sortable: false,},
{ text: '완료일자', value: 'end_date', sortable: false, },
{ text: '조회', value: 'actions', sortable: false },
],
}
},
props:{
projectList:Array,
},
methods:{
reload(){
EventBus.$emit('projectListReload')
},
selected(project){
EventBus.$emit('projectSelected',project)
}
}
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<v-card class="d-flex justify-center align-center" color="grey lighten-2" height="770">
<div class="title font-weight-bold">조회 하실 프로젝트를 선택해주세요</div>
</v-card>
</template>
<script>
export default {
}
</script>
<style>
</style>
\ No newline at end of file
module.exports = {
rules: {
'no-unused-expressions': 'off'
}
}
/**
* A custom Nightwatch assertion. The assertion name is the filename.
*
* Example usage:
* browser.assert.elementCount(selector, count)
*
* For more information on custom assertions see:
* https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-assertions
*
*
* @param {string|object} selectorOrObject
* @param {number} count
*/
exports.assertion = function elementCount (selectorOrObject, count) {
let selector
// when called from a page object element or section
if (typeof selectorOrObject === 'object' && selectorOrObject.selector) {
// eslint-disable-next-line prefer-destructuring
selector = selectorOrObject.selector
} else {
selector = selectorOrObject
}
this.message = `Testing if element <${selector}> has count: ${count}`
this.expected = count
this.pass = val => val === count
this.value = res => res.value
function evaluator (_selector) {
return document.querySelectorAll(_selector).length
}
this.command = cb => this.api.execute(evaluator, [selector], cb)
}
/**
* A very basic Nightwatch custom command. The command name is the filename and the
* exported "command" function is the command.
*
* Example usage:
* browser.customExecute(function() {
* console.log('Hello from the browser window')
* });
*
* For more information on writing custom commands see:
* https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands
*
* @param {*} data
*/
exports.command = function command (data) {
// Other Nightwatch commands are available via "this"
// .execute() inject a snippet of JavaScript into the page for execution.
// the executed script is assumed to be synchronous.
//
// See https://nightwatchjs.org/api/execute.html for more info.
//
this.execute(
// The function argument is converted to a string and sent to the browser
function (argData) { return argData },
// The arguments for the function to be sent to the browser are specified in this array
[data],
function (result) {
// The "result" object contains the result of what we have sent back from the browser window
console.log('custom execute result:', result.value)
}
)
return this
}
/**
* A basic Nightwatch custom command
* which demonstrates usage of ES6 async/await instead of using callbacks.
* The command name is the filename and the exported "command" function is the command.
*
* Example usage:
* browser.openHomepage();
*
* For more information on writing custom commands see:
* https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands
*
*/
module.exports = {
command: async function () {
// Other Nightwatch commands are available via "this"
// .init() simply calls .url() command with the value of the "launch_url" setting
this.init()
this.waitForElementVisible('#app')
const result = await this.elements('css selector', '#app ul')
this.assert.strictEqual(result.value.length, 3)
}
}
/**
* A class-based Nightwatch custom command which is a variation of the openHomepage.js command.
* The command name is the filename and class needs to contain a "command" method.
*
* Example usage:
* browser.openHomepageClass();
*
* For more information on writing custom commands see:
* https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands
*
*/
const assert = require('assert')
module.exports = class {
async command () {
// Other Nightwatch commands are available via "this.api"
this.api.init()
this.api.waitForElementVisible('#app')
const result = await this.api.elements('css selector', '#app ul')
assert.strictEqual(result.value.length, 3)
}
}
///////////////////////////////////////////////////////////////////////////////////
// Refer to the entire list of global config settings here:
// https://github.com/nightwatchjs/nightwatch/blob/master/lib/settings/defaults.js#L16
//
// More info on test globals:
// https://nightwatchjs.org/gettingstarted/configuration/#test-globals
//
///////////////////////////////////////////////////////////////////////////////////
module.exports = {
// this controls whether to abort the test execution when an assertion failed and skip the rest
// it's being used in waitFor commands and expect assertions
abortOnAssertionFailure: true,
// this will overwrite the default polling interval (currently 500ms) for waitFor commands
// and expect assertions that use retry
waitForConditionPollInterval: 500,
// default timeout value in milliseconds for waitFor commands and implicit waitFor value for
// expect assertions
waitForConditionTimeout: 5000,
'default': {
/*
The globals defined here are available everywhere in any test env
*/
/*
myGlobal: function() {
return 'I\'m a method';
}
*/
},
'firefox': {
/*
The globals defined here are available only when the chrome testing env is being used
i.e. when running with --env firefox
*/
/*
* myGlobal: function() {
* return 'Firefox specific global';
* }
*/
},
/////////////////////////////////////////////////////////////////
// Global hooks
// - simple functions which are executed as part of the test run
// - take a callback argument which can be called when an async
// async operation is finished
/////////////////////////////////////////////////////////////////
/**
* executed before the test run has started, so before a session is created
*/
/*
before(cb) {
//console.log('global before')
cb();
},
*/
/**
* executed before every test suite has started
*/
/*
beforeEach(browser, cb) {
//console.log('global beforeEach')
cb();
},
*/
/**
* executed after every test suite has ended
*/
/*
afterEach(browser, cb) {
browser.perform(function() {
//console.log('global afterEach')
cb();
});
},
*/
/**
* executed after the test run has finished
*/
/*
after(cb) {
//console.log('global after')
cb();
},
*/
/////////////////////////////////////////////////////////////////
// Global reporter
// - define your own custom reporter
/////////////////////////////////////////////////////////////////
/*
reporter(results, cb) {
cb();
}
*/
}
/**
* A Nightwatch page object. The page object name is the filename.
*
* Example usage:
* browser.page.homepage.navigate()
*
* For more information on working with page objects see:
* https://nightwatchjs.org/guide/working-with-page-objects/
*
*/
module.exports = {
url: '/',
commands: [],
// A page object can have elements
elements: {
appContainer: '#app'
},
// Or a page objects can also have sections
sections: {
app: {
selector: '#app',
elements: {
logo: 'img'
},
// - a page object section can also have sub-sections
// - elements or sub-sections located here are retrieved using the "app" section as the base
sections: {
headline: {
selector: 'h1'
},
welcome: {
// the equivalent css selector for the "welcome" sub-section would be:
// '#app div.hello'
selector: 'div.hello',
elements: {
cliPluginLinks: {
selector: 'ul',
index: 0
}
}
}
}
}
}
}
////////////////////////////////////////////////////////////////
// For authoring Nightwatch tests, see
// https://nightwatchjs.org/guide
//
// For more information on working with page objects see:
// https://nightwatchjs.org/guide/working-with-page-objects/
////////////////////////////////////////////////////////////////
module.exports = {
beforeEach: (browser) => browser.init(),
'e2e tests using page objects': (browser) => {
const homepage = browser.page.homepage()
homepage.waitForElementVisible('@appContainer')
const app = homepage.section.app
app.assert.elementCount('@logo', 1)
app.expect.section('@welcome').to.be.visible
app.expect.section('@headline').text.to.match(/^Welcome to Your Vue\.js (.*)App$/)
browser.end()
},
'verify if string "e2e-nightwatch" is within the cli plugin links': (browser) => {
const homepage = browser.page.homepage()
const welcomeSection = homepage.section.app.section.welcome
welcomeSection.expect.element('@cliPluginLinks').text.to.contain('e2e-nightwatch')
}
}
// For authoring Nightwatch tests, see
// https://nightwatchjs.org/guide
module.exports = {
'default e2e tests': browser => {
browser
.init()
.waitForElementVisible('#app')
.assert.elementPresent('.hello')
.assert.containsText('h1', 'Welcome to Your Vue.js App')
.assert.elementCount('img', 1)
.end()
},
'example e2e test using a custom command': browser => {
browser
.openHomepage()
.assert.elementPresent('.hello')
.end()
}
}
import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message'
const wrapper = shallowMount(HelloWorld, {
propsData: { msg }
})
expect(wrapper.text()).toMatch(msg)
})
})
module.exports = {
"transpileDependencies": [
"vuetify"
],
devServer: {
proxy: {
'/api/*': {
target: 'http://localhost:3000' // 개발서버
}
}
},
//npm run build 하면 지정된 경로로 생성한다.
outputDir: '../backend/public' ,
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment