Фронт. Начало + новые методы контроллеров DLC

This commit is contained in:
Данила Мочалов 2023-04-03 01:00:37 +04:00
parent 39f81fd472
commit 8beb5da494
12 changed files with 396 additions and 9 deletions

View File

@ -27,6 +27,11 @@ class ExamResultController extends ExamResultControllerInterface {
const results = await db.query('DELETE FROM exam_result WHERE id=$1', [id]) const results = await db.query('DELETE FROM exam_result WHERE id=$1', [id])
res.json(results.rows[0]) res.json(results.rows[0])
} }
async getAbiturExamResults(req, res) {
const id = req.params.id
const results = await db.query('SELECT * FROM exam_result WHERE abitur_id=$1', [id])
res.json(results.rows)
}
} }
module.exports = new ExamResultController() module.exports = new ExamResultController()

View File

@ -27,6 +27,11 @@ class RequestController extends RequestControllerInterface {
const requests = await db.query('DELETE FROM request WHERE id=$1', [id]) const requests = await db.query('DELETE FROM request WHERE id=$1', [id])
res.json(requests.rows[0]) res.json(requests.rows[0])
} }
async getAbiturRequests(req, res) {
const id = req.params.id
const requests = await db.query('SELECT * FROM request WHERE abitur_id=$1', [id])
res.json(requests.rows)
}
} }
module.exports = new RequestController() module.exports = new RequestController()

View File

@ -12,6 +12,13 @@ const PORT = process.env.PORT || 8080
const app = express() const app = express()
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
res.setHeader('Access-Control-Allow-Headers', 'origin, content-type, accept');
next();
});
app.use(express.json()) app.use(express.json())
app.use('/api', abiturRouter) app.use('/api', abiturRouter)
app.use('/api', examResultRouter) app.use('/api', examResultRouter)

View File

@ -8,6 +8,7 @@
"name": "abitur_list_client", "name": "abitur_list_client",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"axios": "^1.3.4",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"express": "^4.18.2", "express": "^4.18.2",
"pg": "^8.10.0", "pg": "^8.10.0",
@ -3256,6 +3257,11 @@
"lodash": "^4.17.14" "lodash": "^4.17.14"
} }
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/at-least-node": { "node_modules/at-least-node": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz",
@ -3288,6 +3294,16 @@
"postcss": "^8.1.0" "postcss": "^8.1.0"
} }
}, },
"node_modules/axios": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/babel-loader": { "node_modules/babel-loader": {
"version": "8.3.0", "version": "8.3.0",
"resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.3.0.tgz", "resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.3.0.tgz",
@ -3870,6 +3886,17 @@
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
"dev": true "dev": true
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": { "node_modules/commander": {
"version": "8.3.0", "version": "8.3.0",
"resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", "resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz",
@ -4557,6 +4584,14 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz",
@ -5120,7 +5155,6 @@
"version": "1.15.2", "version": "1.15.2",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz", "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"dev": true,
"engines": { "engines": {
"node": ">=4.0" "node": ">=4.0"
}, },
@ -5130,6 +5164,19 @@
} }
} }
}, },
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": { "node_modules/forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz",
@ -7946,6 +7993,11 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/pseudomap": { "node_modules/pseudomap": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz",
@ -12486,6 +12538,11 @@
"lodash": "^4.17.14" "lodash": "^4.17.14"
} }
}, },
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"at-least-node": { "at-least-node": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz",
@ -12506,6 +12563,16 @@
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
} }
}, },
"axios": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
"requires": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"babel-loader": { "babel-loader": {
"version": "8.3.0", "version": "8.3.0",
"resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.3.0.tgz", "resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.3.0.tgz",
@ -12986,6 +13053,14 @@
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
"dev": true "dev": true
}, },
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"commander": { "commander": {
"version": "8.3.0", "version": "8.3.0",
"resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", "resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz",
@ -13514,6 +13589,11 @@
"object-keys": "^1.1.1" "object-keys": "^1.1.1"
} }
}, },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"depd": { "depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz",
@ -13993,8 +14073,17 @@
"follow-redirects": { "follow-redirects": {
"version": "1.15.2", "version": "1.15.2",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz", "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
"dev": true },
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
}, },
"forwarded": { "forwarded": {
"version": "0.2.0", "version": "0.2.0",
@ -16141,6 +16230,11 @@
} }
} }
}, },
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"pseudomap": { "pseudomap": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz",

View File

@ -5,9 +5,10 @@
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"start": "nodemon index.js" "start": "pm2 start index.js --watch"
}, },
"dependencies": { "dependencies": {
"axios": "^1.3.4",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"express": "^4.18.2", "express": "^4.18.2",
"pg": "^8.10.0", "pg": "^8.10.0",

View File

@ -8,5 +8,6 @@ router.get('/examresult', examResultController.getExamResults)
router.get('/examresult/:id', examResultController.getOneExamResult) router.get('/examresult/:id', examResultController.getOneExamResult)
router.put('/examresult', examResultController.updateExamResult) router.put('/examresult', examResultController.updateExamResult)
router.delete('/examresult/:id', examResultController.deleteExamResult) router.delete('/examresult/:id', examResultController.deleteExamResult)
router.get('/examresult/abitur/:id', examResultController.getAbiturExamResults)
module.exports = router module.exports = router

View File

@ -8,5 +8,6 @@ router.get('/request', requestController.getRequests)
router.get('/request/:id', requestController.getRequests) router.get('/request/:id', requestController.getRequests)
router.put('/request', requestController.updateRequest) router.put('/request', requestController.updateRequest)
router.delete('/request/:id', requestController.deleteRequest) router.delete('/request/:id', requestController.deleteRequest)
router.get('/request/abitur/:id', requestController.getAbiturRequests)
module.exports = router module.exports = router

View File

@ -1,11 +1,11 @@
<template lang=""> <template lang="">
<div> <router-view></router-view>
</div>
</template> </template>
<script> <script>
export default { export default {
} }
</script> </script>
<style lang=""> <style lang="">

View File

@ -0,0 +1,154 @@
<template>
<div class='text-center mx-auto m-3'>
<p class='h3'>
Здравствуйте, {{this.firstName}} {{this.lastName}}
</p>
<p class='h5'>Мои результаты:</p>
<ul class='text-start'>
<li v-for='result in examResults'>
<p>
Предмет: {{ result['title']}}
</p>
<p>
Результат: {{ result['result']}}
</p>
<p>
<button @click="deleteResultClick(result['id'])" type="button" class="btn btn-danger ms-3" >
Удалить
</button>
</p>
</li>
</ul>
<button class="btn btn-success mb-3" @click="isAddResultAreaHidden = !isAddResultAreaHidden">Новый результат</button>
<div id="addResultArea" v-if="!isAddResultAreaHidden">
<p class='h5'>Добавить результат</p>
<p>Предмет:</p>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="examResult" data-bs-toggle="dropdown" aria-expanded="false">
{{ selectedExamTitle }}
</button>
<ul class="dropdown-menu" aria-labelledby="examResult">
<li><a class="dropdown-item" href="#" v-on:click="selectedExamTitle = 'Русский язык' ">Русский язык </a>
</li>
<li><a class="dropdown-item" href="#" v-on:click="selectedExamTitle = 'Математика' ">Математика</a>
</li>
<li><a class="dropdown-item" href="#" v-on:click="selectedExamTitle = 'Английский' ">Английский</a>
</li>
</ul>
</div>
<p>Результат:</p>
<input v-model='selectedExamResult' @change='validateExamResult()' type="number" id="examResult" name="examResult">
<p class='mt-5'>
<button v-on:click="onAddExamResultClick" type='button' class='btn btn-primary' >Добавить результат</button>
</p>
</div>
<p class='h5'>Мои заявки:</p>
<ul class='text-start'>
<li v-for='request in requests'>
<p>
Дата: {{ request['date']}}
</p>
<p>
<button @click="" type="button" class="btn btn-warning ms-3" >
Посмотреть
</button>
<p> </p>
</p>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
//info
abiturId: -1,
firstName: '',
lastName: '',
// examsRes
examResults: [],
selectedExamTitle: 'Выберите предмет',
selectedExamResult: 0,
isAddResultAreaHidden: true,
// requests
requests: [],
selectedRequestResults: [],
selectedRequestForm: '',
selectedRequestSpec: ''
}
},
async beforeMount(){
this.abiturId = this.$route.params.abiturId
var response = (await axios.get('http://127.0.0.1:8080/api/abitur/' + this.abiturId)).data
this.firstName = response['first_name']
this.lastName = response['last_name']
response = (await axios.get('http://127.0.0.1:8080/api/examresult/abitur/' + this.abiturId)).data
this.examResults = response
response = (await axios.get('http://127.0.0.1:8080/api/request/abitur/' + this.abiturId)).data
this.requests = response
},
methods: {
validateExamResult() {
if (this.selectedExamResult < 0 || this.selectedExamResult > 100) {
this.selectedExamResult = 0
}
},
async onAddExamResultClick() {
if (this.selectedExamTitle == 'Выберите предмет') return;
let data = JSON.stringify({
"title": this.selectedExamTitle,
"result": this.selectedExamResult,
"abitur_id": this.abiturId
});
let config = {
method: 'post',
maxBodyLength: Infinity,
url: 'http://127.0.0.1:8080/api/examresult',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios.request(config)
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch((error) => {
console.log(error);
});
await this.refresh()
window.location.reload()
},
async deleteResultClick(id) {
await axios.delete('http://127.0.0.1:8080/api/examresult/' + id)
await this.refresh()
window.location.reload()
},
async refresh() {
var response = (await axios.get('http://127.0.0.1:8080/api/examresult/abitur/' + this.abiturId)).data
this.examResults = response
}
}
}
</script>
<style lang="">
</style>

View File

@ -0,0 +1,83 @@
<template lang="">
<div class='text-center mx-auto'>
<p class='h3 m-3'>Авторизация</p>
<p class='h6 m-3'> Имя:</p>
<textarea v-model='firstName' id="firstNameTF" cols="30" rows="1" style="resize: none;"></textarea>
<p class='h6 m-3' > Фамилия:</p>
<textarea v-model='lastName' id="lastNameTF" cols="30" rows="1" style="resize: none;"></textarea>
<p class='h6 m-3'> Отчество:</p>
<textarea v-model='middleName' id="middleNameTF" cols="30" rows="1" style="resize: none;"></textarea>
<p class='mt-5'>
<button v-on:click="enterButtonClick" type='button' class='btn btn-primary'>Войти</button>
</p>
<p>
<button v-on:click="registerButtonClick" type='button' class='btn btn-success'>Регистрация</button>
</p>
<p>
<button type='button' class='btn btn-light'>Войти как администратор</button>
</p>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
firstName: '',
lastName: '',
middleName: '',
abiturId: -1
}
},
methods: {
async enterButtonClick() {
var abiturs = await (await axios.get('http://127.0.0.1:8080/api/abitur', )).data
abiturs.forEach(element => {
if (element['first_name'] == this.firstName && element['last_name'] == this.lastName && element['middle_name'] == this.middleName) {
this.abiturId = element['id']
console.log(this.abiturId)
}
});
this.$router.push(
{
name: "AbiturMain",
params: {
abiturId: this.abiturId
}
}
);
},
async registerButtonClick() {
let data = JSON.stringify({
"first_name": this.firstName,
"last_name": this.lastName,
"middle_name": this.middleName
});
let config = {
method: 'post',
maxBodyLength: Infinity,
url: 'http://127.0.0.1:8080/api/abitur',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios.request(config)
.then((response) => {
this.abiturId =response.data['id']
console.log(this.abiturId)
})
}
}
}
</script>
<style lang="">
</style>

View File

@ -0,0 +1,13 @@
<template>
<div>
</div>
</template>
<script>
export default {
}
</script>
<style lang="">
</style>

View File

@ -1,4 +1,27 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import { createRouter, createWebHistory } from "vue-router"
createApp(App).mount('#app') import Auth from './components/Auth'
import AbiturMain from './components/AbiturMain'
const routes = [
{
path: '/',
component: Auth,
name: 'Auth'
},
{
path: '/abitur/:abiturId',
name: 'AbiturMain',
component: AbiturMain,
props: true
}
]
const router = createRouter({
routes,
history: createWebHistory()
})
createApp(App).use(router).mount('#app')