Frontend is finished(I think)
This commit is contained in:
parent
cbf4b0b9a3
commit
00c99afbcf
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/frontend/node_modules/
|
17
frontend/README.md
Normal file
17
frontend/README.md
Normal file
@ -0,0 +1,17 @@
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
5
frontend/babel.config.js
Normal file
5
frontend/babel.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Calculator</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/chota@latest">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container" style="max-width:600px">
|
||||
<div class="card row is-full-screen is-center">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<input type="text" id="value1">
|
||||
</div>
|
||||
<div class="col">
|
||||
<select id="operation">
|
||||
<option value="sum" selected>+</option>
|
||||
<option value="sub">-</option>
|
||||
<option value="mul">*</option>
|
||||
<option value="invert">~</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" id="value2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button type="button" id="get-int-result" onclick="calculate('intops')">Result for int</button>
|
||||
</div>
|
||||
<div class="col is-right">
|
||||
<button type="button" id="get-string-result" onclick="calculate('stringops')">Result for string</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card row is-center">
|
||||
<h5 class="is-center" id="result"></h5>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function calculate(ops) {
|
||||
const value1 = document.getElementById("value1").value
|
||||
const value2 = document.getElementById("value2").value
|
||||
const op = document.getElementById("operation").value
|
||||
if (op == 'sum') {
|
||||
document.getElementById("result").innerHTML = await (await fetch(`http://127.0.0.1:8080/sum?value1=${value1}&value2=${value2}&ops=${ops}`)).text()
|
||||
} else if (op == 'sub') {
|
||||
document.getElementById("result").innerHTML = await (await fetch(`http://127.0.0.1:8080/sub?value1=${value1}&value2=${value2}&ops=${ops}`)).text()
|
||||
} else if (op == 'mul') {
|
||||
document.getElementById("result").innerHTML = await (await fetch(`http://127.0.0.1:8080/mul?value=${value1}&count=${value2}&ops=${ops}`)).text()
|
||||
} else {
|
||||
document.getElementById("result").innerHTML = await (await fetch(`http://127.0.0.1:8080/invert?value=${value1}&ops=${ops}`)).text()
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,12 +0,0 @@
|
||||
const fs = require('fs')
|
||||
const http = require('http')
|
||||
|
||||
const requestListener = async function (req, res) {
|
||||
res.writeHead(200);
|
||||
fs.readFile('index.html', 'utf8', (err, data) => {
|
||||
res.end(data);
|
||||
});
|
||||
};
|
||||
|
||||
const server = http.createServer(requestListener)
|
||||
server.listen(5050)
|
19
frontend/jsconfig.json
Normal file
19
frontend/jsconfig.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"baseUrl": "./",
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
}
|
||||
}
|
17567
frontend/package-lock.json
generated
17567
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,29 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"name": "lab4_vue_front",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "node index.js"
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"fs": "0.0.1-security",
|
||||
"http": "0.0.1-security"
|
||||
}
|
||||
"@popperjs/core": "^2.11.7",
|
||||
"axios": "^1.3.4",
|
||||
"core-js": "^3.8.3",
|
||||
"vue": "^3.2.13",
|
||||
"vue-router": "^4.0.3",
|
||||
"vuex": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-router": "~5.0.0",
|
||||
"@vue/cli-plugin-vuex": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead",
|
||||
"not ie 11"
|
||||
]
|
||||
}
|
||||
|
17
frontend/public/index.html
Normal file
17
frontend/public/index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<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">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://unpkg.com/chota@latest">
|
||||
<title>Социальная сеть</title>
|
||||
</head>
|
||||
<body class="container">
|
||||
<script src="https://unpkg.com/@popperjs/core@2"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
23
frontend/src/App.vue
Normal file
23
frontend/src/App.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="nav">
|
||||
<div class="nav-center">
|
||||
|
||||
<router-link to="/customers" class="button primary clear">Профили</router-link>
|
||||
<router-link to="/posts" class="button primary clear">Посты</router-link>
|
||||
<router-link to="/comments" class="button primary clear">Комментарии</router-link>
|
||||
</div>"
|
||||
</div>
|
||||
<router-view></router-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="">
|
||||
|
||||
</style>
|
194
frontend/src/components/Comment.vue
Normal file
194
frontend/src/components/Comment.vue
Normal file
@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row mb-5">
|
||||
<p class='is-center h2'>Комментарии</p>
|
||||
</div>
|
||||
<div class="row mb-5">
|
||||
<div class="col"></div>
|
||||
<div class="col-3">
|
||||
<div class="dropdown row">
|
||||
<button class="button secondary outline dropdown-toggle mb-5" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{{ selectedCustomerUsername }}
|
||||
</button>
|
||||
<ul class="dropdown-menu" >
|
||||
<li v-for="customer in customers">
|
||||
<a class="dropdown-item button secondary outline" href="#" v-on:click="getSelectedCustomer(customer)">
|
||||
{{ customer['username'] }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedCustomerId != 0">
|
||||
<div v-if="!(posts.length == 0)" class="row">
|
||||
<div class="col">
|
||||
<div class="row mb-5 card" v-for="post in posts">
|
||||
<div class="col">
|
||||
<div class="row is-left h3"><p>Автор: <span class="text-primary">{{ post['customerName'] }}</span></p></div>
|
||||
<div class="row text-center">
|
||||
<span class="h1">{{ post['title'] }}</span>
|
||||
</div>
|
||||
<div class="row text-center mb-5">
|
||||
<span class="h3">{{ post['content'] }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<p class="row h2 is-center mb-3">Комментарии</p>
|
||||
<div v-if="!(post['comments'].length == 0)" class="row text-left mb-5 card" v-for="comment in post['comments']">
|
||||
<div class="row mb-1">
|
||||
<span class="h2 text-primary">{{ comment['customerName'] }}</span>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<span class="h3">{{ comment['content'] }}</span>
|
||||
</div>
|
||||
<div v-if="selectedCustomerContainsComment(comment) == true" class="row">
|
||||
<button v-on:click="selectedCommentId = comment['id']; selectedPostTitle = post['title']" class="button primary outline col" data-bs-toggle="modal" data-bs-target="#commentEdit">Изменить комментарий</button>
|
||||
<button v-on:click="deleteComment(comment['id'])" class="button error col">Удалить комментарий</button>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="h3 row is-center mb-1">Пусто</p>
|
||||
<div class="row">
|
||||
<button type="button" v-on:click="selectedPostId = post['id']; selectedPostTitle = post['title'];" class="button secondary outline" data-bs-toggle="modal" data-bs-target="#commentCreate">Добавить комментарий</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="row text-center is-center">
|
||||
Нет постов
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="commentCreate" tabindex="-1" role="dialog" aria-labelledby="commentCreateLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="commentCreateLabel">Создать комментарий</h5>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p>Под именем:</p>
|
||||
<p>{{ selectedCustomerUsername }}</p>
|
||||
<p>К посту:</p>
|
||||
<p>{{ selectedPostTitle }}</p>
|
||||
<p>Комментарий</p>
|
||||
<textarea v-model='contentModal' id="createModalText" cols="30" rows="1"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" v-on:click='createComment'>Создать</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="commentEdit" tabindex="-1" role="dialog" aria-labelledby="commentEditLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="commentEditLabel">Изменить комментарий</h5>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p>Под именем:</p>
|
||||
<p>{{ selectedCustomerUsername }}</p>
|
||||
<p>К посту:</p>
|
||||
<p>{{ selectedPostTitle }}</p>
|
||||
<p>Комментарий</p>
|
||||
<textarea v-model='contentModal' id="editModalText" cols="30" rows="1"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" v-on:click='editComment'>Изменить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
customers: [],
|
||||
selectedCustomerId: 0,
|
||||
selectedCustomerUsername: 'Профиль не выбран',
|
||||
posts: [],
|
||||
selectedPostId: 0,
|
||||
selectedPostTitle: '',
|
||||
contentModal: '',
|
||||
selectedCommentId: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getSelectedCustomer(customer){
|
||||
this.selectedCustomerId = customer['id'];
|
||||
this.selectedCustomerUsername = customer['username'];
|
||||
this.refreshList();
|
||||
},
|
||||
|
||||
selectedCustomerContainsComment(comment) {
|
||||
var customer = this.customers.find(element => element['id'] == this.selectedCustomerId);
|
||||
console.log(customer);
|
||||
if (customer == null) return false;
|
||||
var flag = false;
|
||||
customer['comments'].forEach(commentIn => {
|
||||
if (commentIn['id'] == comment['id']) {
|
||||
flag = true;
|
||||
}
|
||||
});
|
||||
return flag;
|
||||
},
|
||||
|
||||
async createComment() {
|
||||
await axios.post('http://localhost:8080/comment?text=' + this.contentModal + '&ownerId=' + this.selectedCustomerId + '&postId=' + this.selectedPostId);
|
||||
this.refreshList();
|
||||
},
|
||||
async deleteComment(commentId) {
|
||||
await axios.delete('http://localhost:8080/comment/' + commentId);
|
||||
this.refreshList();
|
||||
},
|
||||
async editComment(){
|
||||
await axios.put('http://localhost:8080/comment/' + this.selectedCommentId + '?text=' + this.contentModal);
|
||||
this.refreshList();
|
||||
},
|
||||
async refreshList(){
|
||||
this.customers = [];
|
||||
this.posts = [];
|
||||
const responseCustomer = await axios.get('http://localhost:8080/customer');
|
||||
responseCustomer.data.forEach(element => {
|
||||
this.customers.push(element);
|
||||
console.log(element);
|
||||
});
|
||||
const responsePost = await axios.get('http://localhost:8080/post');
|
||||
responsePost.data.forEach(element => {
|
||||
this.posts.push(element);
|
||||
console.log(element);
|
||||
});
|
||||
}
|
||||
},
|
||||
async beforeMount() {
|
||||
const responseCustomer = await axios.get('http://localhost:8080/customer');
|
||||
responseCustomer.data.forEach(element => {
|
||||
this.customers.push(element);
|
||||
console.log(element);
|
||||
});
|
||||
const responsePost = await axios.get('http://localhost:8080/post');
|
||||
responsePost.data.forEach(element => {
|
||||
this.posts.push(element);
|
||||
console.log(element);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="">
|
||||
|
||||
</style>
|
144
frontend/src/components/Customer.vue
Normal file
144
frontend/src/components/Customer.vue
Normal file
@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row mb-5">
|
||||
<p class='is-center h2'>Профили</p>
|
||||
</div>
|
||||
<div class="row mb-5">
|
||||
<div class="col"></div>
|
||||
<div class="col-10 is-center">
|
||||
<button class="button primary" data-bs-toggle="modal" data-bs-target="#customerCreate">
|
||||
Добавить нового пользователя
|
||||
</button>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
|
||||
<p class='h3 is-center row mb-5'>Список профилей</p>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div v-for="customer in customers" class="row card mb-3">
|
||||
<div class="row">
|
||||
<div class="col is-left h3">ID: {{ customer['id'] }}</div>
|
||||
<div class="col is-center h3">Никнейм: {{ customer['username'] }}</div>
|
||||
<div class="col is-right h3">Пароль: {{ customer['password'] }}</div>
|
||||
</div>
|
||||
<p class="row">Комментарии:</p>
|
||||
<div class="row" v-if="!(customer['comments'].length == 0)">
|
||||
<div class="col">
|
||||
<div v-for="comment in customer['comments']" class="row is-left card mb-3">
|
||||
<div class="row is-left h4">"{{ comment['content'] }}" - к посту '{{ comment['postTitle'] }}' от пользователя {{ comment['postAuthor'] }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="row">Нет комментариев</p>
|
||||
<p class="row">Посты: </p>
|
||||
<div class="row" v-if="!(customer['posts'].length == 0)">
|
||||
<div class="col">
|
||||
<div v-for="post in customer['posts']" class="row is-left card mb-3">
|
||||
<div class="row is-center h1">{{ post['title'] }}</div>
|
||||
<div class="row is-left h3">{{ post['content'] }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="row">Нет постов</p>
|
||||
<div class="row">
|
||||
<button v-on:click="deleteUser(customer['id'])" class="col button dark outline">Удалить</button>
|
||||
<button v-on:click="selectedCustomer = customer; usernameModal=customer['username'];passwordModal=customer['password']" class="col button primary outline" data-bs-toggle="modal" data-bs-target="#customerEdit">Редактировать</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="customerCreate" tabindex="-1" role="dialog" aria-labelledby="customerCreateLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="customerCreateLabel">Создать профиль</h5>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p>Логин</p>
|
||||
<textarea v-model='usernameModal' id="usernameText" cols="30" rows="1"></textarea>
|
||||
<p>Пароль</p>
|
||||
<textarea v-model='passwordModal' id="passwordText" cols="30" rows="1"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" v-on:click='createUser'>Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="customerEdit" tabindex="-1" role="dialog" aria-labelledby="customerEditLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="customerEditLabel">Редактировать профиль</h5>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p>Логин</p>
|
||||
<textarea v-model='usernameModal' id="usernameText" cols="30" rows="1"></textarea>
|
||||
<p>Пароль</p>
|
||||
<textarea v-model='passwordModal' id="passwordText" cols="30" rows="1"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" v-on:click='editUser'>Изменить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
customers: [],
|
||||
usernameModal: '',
|
||||
passwordModal: '',
|
||||
selectedCustomer: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createUser(){
|
||||
const response = await axios.post('http://localhost:8080/customer?username=' + this.usernameModal + '&password=' + this.passwordModal);
|
||||
this.refreshList();
|
||||
},
|
||||
async deleteUser(id) {
|
||||
const response = await axios.delete('http://localhost:8080/customer/' + id);
|
||||
this.refreshList();
|
||||
},
|
||||
async editUser() {
|
||||
const response = await axios.put('http://localhost:8080/customer/' + this.selectedCustomer['id'] + '?username=' + this.usernameModal + '&password=' + this.passwordModal);
|
||||
this.refreshList();
|
||||
},
|
||||
async refreshList() {
|
||||
const response = await axios.get('http://localhost:8080/customer');
|
||||
this.customers = [];
|
||||
response.data.forEach(element => {
|
||||
this.customers.push(element);
|
||||
console.log(element);
|
||||
});
|
||||
}
|
||||
},
|
||||
async beforeMount() {
|
||||
const response = await axios.get('http://localhost:8080/customer');
|
||||
response.data.forEach(element => {
|
||||
this.customers.push(element);
|
||||
console.log(element);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="">
|
||||
|
||||
</style>
|
188
frontend/src/components/Post.vue
Normal file
188
frontend/src/components/Post.vue
Normal file
@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row mb-5">
|
||||
<p class='is-center h2'>Посты</p>
|
||||
</div>
|
||||
<div class="row mb-5">
|
||||
<div class="col"></div>
|
||||
<div class="col-3">
|
||||
<div class="dropdown row">
|
||||
<button class="button secondary outline dropdown-toggle mb-5" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{{ selectedCustomer }}
|
||||
</button>
|
||||
<ul class="dropdown-menu" >
|
||||
<li v-for="customer in customers">
|
||||
<a class="dropdown-item button secondary outline" href="#" v-on:click="getSelectedCustomer(customer)">
|
||||
{{ customer['username'] }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row">
|
||||
<button type='button' class="button primary" data-bs-toggle="modal" data-bs-target="#postCreate">
|
||||
Добавить новый пост
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
|
||||
<div class="row text-center">
|
||||
<p class='h2 mb-5'>Список постов пользователя {{ selectedCustomer }}</p>
|
||||
</div>
|
||||
<div v-if="!(posts.length == 0)" class="row">
|
||||
<div class="col">
|
||||
<div class="row mb-4 card" v-for="post in posts">
|
||||
<div class="col">
|
||||
<div class="row text-center">
|
||||
<span class="h1">{{ post['title'] }}</span>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<span class="h3">{{ post['content'] }}</span>
|
||||
</div>
|
||||
<br class="row" />
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<p class="row h2 is-center mb-3">Комментарии</p>
|
||||
<div v-if="!(post['comments'].length == 0)" class="row text-left mb-5 card" v-for="comment in post['comments']">
|
||||
<div class="row mb-3">
|
||||
<span class="h2 text-primary">{{ comment['customerName'] }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="h3">{{ comment['content'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="h3 row is-center">Пусто</p>
|
||||
</div>
|
||||
</div>
|
||||
<br class="row" />
|
||||
<div class="row">
|
||||
<button type="button" v-on:click="deletePost(post['id'])" class="col button dark outline">Удалить пост</button>
|
||||
<button type="button" v-on:click="selectedPostId = post['id']" class="col button primary outline" data-bs-toggle="modal" data-bs-target="#postEdit">Изменить пост</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="row text-center is-center">
|
||||
Нет постов
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="postCreate" tabindex="-1" role="dialog" aria-labelledby="postCreateLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="postCreateLabel">Создать пост</h5>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p>Пользователь:</p>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-secondary dropdown-toggle ms-3 mb-3" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{{selectedCustomer}}
|
||||
</button>
|
||||
<ul class="dropdown-menu" >
|
||||
<li v-for="customer in customers">
|
||||
<a class="dropdown-item" href="#" v-on:click="getSelectedCustomer(customer)">
|
||||
{{ customer['username'] }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Заголовок:</p>
|
||||
<textarea v-model='titleModal' id="modalText" cols="30" rows="1"></textarea>
|
||||
<p>Содержание:</p>
|
||||
<textarea v-model='contentModal' id="modalText" cols="30" rows="1"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" v-on:click='createPost'>Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="postEdit" tabindex="-1" role="dialog" aria-labelledby="postEditLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="postEditLabel">Редактировать пост</h5>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p>{{ selectedCustomer }}</p>
|
||||
<p>Заголовок</p>
|
||||
<textarea v-model='titleModal' id="editModalTitle" cols="30" rows="1"></textarea>
|
||||
<p>Содержание</p>
|
||||
<textarea v-model='contentModal' id="editModalContent" cols="30" rows="1"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" v-on:click='editPost'>Изменить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
customers: [],
|
||||
selectedCustomerId: 0,
|
||||
selectedCustomer: 'Профиль не выбран',
|
||||
posts: [],
|
||||
titleModal: '',
|
||||
contentModal: '',
|
||||
selectedPostId: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getSelectedCustomer(customer){
|
||||
this.selectedCustomerId = customer['id'];
|
||||
this.selectedCustomer = customer['username'];
|
||||
this.posts = customer['posts'];
|
||||
},
|
||||
async createPost() {
|
||||
const response = await axios.post('http://localhost:8080/post?title=' + this.titleModal + '&content=' + this.contentModal + '&authorId=' + this.selectedCustomerId);
|
||||
this.refreshList();
|
||||
|
||||
},
|
||||
async deletePost(postId) {
|
||||
const response = await axios.delete('http://localhost:8080/post/' + postId);
|
||||
this.refreshList();
|
||||
},
|
||||
async editPost(){
|
||||
const response = await axios.put('http://localhost:8080/post/' + this.selectedPostId + '?title=' + this.titleModal + '&content=' + this.contentModal);
|
||||
this.refreshList();
|
||||
},
|
||||
async refreshList() {
|
||||
const response = await axios.get('http://localhost:8080/customer');
|
||||
this.customers = [];
|
||||
response.data.forEach(element => {
|
||||
this.customers.push(element);
|
||||
if (element['id'] == this.selectedCustomerId) {
|
||||
this.selectedCustomerUsername = element['username'];
|
||||
this.posts = element['posts'];
|
||||
}
|
||||
console.log(element);
|
||||
});
|
||||
this.textModal = '';
|
||||
}
|
||||
},
|
||||
async beforeMount() {
|
||||
const response = await axios.get('http://localhost:8080/customer');
|
||||
response.data.forEach(element => {
|
||||
this.customers.push(element);
|
||||
console.log(element);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="">
|
||||
|
||||
</style>
|
30
frontend/src/main.js
Normal file
30
frontend/src/main.js
Normal file
@ -0,0 +1,30 @@
|
||||
import {createApp} from 'vue'
|
||||
import App from './App'
|
||||
import { createRouter, createWebHistory } from "vue-router"
|
||||
|
||||
import Customer from './components/Customer'
|
||||
import Post from './components/Post'
|
||||
import Comment from './components/Comment'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/customers',
|
||||
component: Customer
|
||||
},
|
||||
{
|
||||
path: '/posts',
|
||||
component: Post
|
||||
},
|
||||
{
|
||||
path: '/comments',
|
||||
component: Comment
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
routes,
|
||||
history: createWebHistory()
|
||||
})
|
||||
|
||||
|
||||
createApp(App).use(router).mount('#app')
|
4
frontend/vue.config.js
Normal file
4
frontend/vue.config.js
Normal file
@ -0,0 +1,4 @@
|
||||
const { defineConfig } = require('@vue/cli-service')
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: true
|
||||
})
|
@ -1,20 +1,20 @@
|
||||
package np.something.DTO;
|
||||
|
||||
import np.something.model.Comment;
|
||||
import np.something.model.Customer;
|
||||
import np.something.model.Post;
|
||||
|
||||
public class CommentDto {
|
||||
public final long id;
|
||||
public final String content;
|
||||
public final Customer customer;
|
||||
public final Post post;
|
||||
public final String customerName;
|
||||
public final String postTitle;
|
||||
public final String postAuthor;
|
||||
|
||||
public CommentDto(Comment comment) {
|
||||
this.id = comment.getId();
|
||||
this.content = comment.getContent();
|
||||
this.customer = comment.getCustomer();
|
||||
this.post = comment.getPost();
|
||||
this.customerName = comment.getCustomer().getUsername();
|
||||
this.postTitle = comment.getPost().getTitle();
|
||||
this.postAuthor = comment.getPost().getCustomer().getUsername();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
@ -25,11 +25,13 @@ public class CommentDto {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
public String getCustomerName() {
|
||||
return customerName;
|
||||
}
|
||||
|
||||
public Post getPost() {
|
||||
return post;
|
||||
public String getPostTitle() {return postTitle;}
|
||||
|
||||
public String getPostAuthor() {
|
||||
return postAuthor;
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,22 @@
|
||||
package np.something.DTO;
|
||||
|
||||
import np.something.model.Comment;
|
||||
import np.something.model.Customer;
|
||||
import np.something.model.Post;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CustomerDto {
|
||||
public final long id;
|
||||
public final String username;
|
||||
public final String hashedPassword;
|
||||
public final List<Comment> comments;
|
||||
public final List<Post> posts;
|
||||
public final String password;
|
||||
public final List<CommentDto> comments;
|
||||
public final List<PostDto> posts;
|
||||
|
||||
public CustomerDto(Customer customer) {
|
||||
this.id = customer.getId();
|
||||
this.username = customer.getUsername();
|
||||
this.hashedPassword = customer.getPassword();
|
||||
this.comments = customer.getComments();
|
||||
this.posts = customer.getPosts();
|
||||
this.password = customer.getPassword();
|
||||
this.comments = customer.getComments().stream().map(CommentDto::new).toList();
|
||||
this.posts = customer.getPosts().stream().map(PostDto::new).toList();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
@ -29,15 +27,15 @@ public class CustomerDto {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getHashedPassword() {
|
||||
return hashedPassword;
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public List<Comment> getComments() {
|
||||
public List<CommentDto> getComments() {
|
||||
return comments;
|
||||
}
|
||||
|
||||
public List<Post> getPosts() {
|
||||
public List<PostDto> getPosts() {
|
||||
return posts;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package np.something.DTO;
|
||||
|
||||
import np.something.model.Comment;
|
||||
import np.something.model.Customer;
|
||||
import np.something.model.Post;
|
||||
|
||||
import java.util.List;
|
||||
@ -10,15 +8,15 @@ public class PostDto {
|
||||
public final long id;
|
||||
public final String title;
|
||||
public final String content;
|
||||
public final Customer customer;
|
||||
public final List<Comment> comments;
|
||||
public final String customerName;
|
||||
public final List<CommentDto> comments;
|
||||
|
||||
public PostDto(Post post) {
|
||||
this.id = post.getId();
|
||||
this.title = post.getTitle();
|
||||
this.content = post.getContent();
|
||||
this.customer = post.getCustomer();
|
||||
this.comments = post.getComments();
|
||||
this.customerName = post.getCustomer().getUsername();
|
||||
this.comments = post.getComments().stream().map(CommentDto::new).toList();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
@ -33,11 +31,11 @@ public class PostDto {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
public String getCustomerName() {
|
||||
return customerName;
|
||||
}
|
||||
|
||||
public List<Comment> getComments() {
|
||||
public List<CommentDto> getComments() {
|
||||
return comments;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
package np.something.controllers;
|
||||
|
||||
import np.something.DTO.CommentDto;
|
||||
import np.something.model.Comment;
|
||||
import np.something.services.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/comment")
|
||||
public class CommentController {
|
||||
private final CommentService commentService;
|
||||
private final CustomerService customerService;
|
||||
private final PostService postService;
|
||||
|
||||
public CommentController(CommentService commentService, CustomerService customerService, PostService postService) {
|
||||
this.commentService = commentService;
|
||||
this.customerService = customerService;
|
||||
this.postService = postService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public CommentDto getComment(@PathVariable Long id) {
|
||||
return new CommentDto(commentService.findComment(id));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<CommentDto> getComments() {
|
||||
return commentService.findAllComments().stream()
|
||||
.map(CommentDto::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public CommentDto createComment(@RequestParam("text") String text, @RequestParam("ownerId") Long ownerId, @RequestParam("postId") Long postId){
|
||||
final Comment comment = commentService.addComment(customerService.findCustomer(ownerId), postService.findPost(postId), text);
|
||||
return new CommentDto(comment);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public CommentDto updateComment(@RequestParam("text") String text, @PathVariable Long id) {
|
||||
return new CommentDto(commentService.updateComment(id, text));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public CommentDto deleteComment(@PathVariable Long id) {
|
||||
return new CommentDto(commentService.deleteComment(id));
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public void deleteAllComments(){
|
||||
commentService.deleteAllComments();
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package np.something.controllers;
|
||||
|
||||
import np.something.DTO.CustomerDto;
|
||||
import np.something.model.Customer;
|
||||
import np.something.services.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/customer")
|
||||
public class CustomerController {
|
||||
private final CustomerService customerService;
|
||||
|
||||
public CustomerController(CustomerService customerService) {
|
||||
this.customerService = customerService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public CustomerDto getCustomer(@PathVariable Long id) {
|
||||
return new CustomerDto(customerService.findCustomer(id));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<CustomerDto> getCustomers() {
|
||||
return customerService.findAllCustomers().stream()
|
||||
.map(CustomerDto::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public CustomerDto createCustomer(@RequestParam("username") String username, @RequestParam("password") String password){
|
||||
final Customer customer = customerService.addCustomer(username, password);
|
||||
return new CustomerDto(customer);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public CustomerDto updateCustomer(@RequestParam("username") String username, @RequestParam("password") String password, @PathVariable Long id) {
|
||||
return new CustomerDto(customerService.updateCustomer(id, username, password));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public CustomerDto deleteCustomer(@PathVariable Long id) {
|
||||
return new CustomerDto(customerService.deleteCustomer(id));
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public void deleteAllCustomers(){
|
||||
customerService.deleteAllCustomers();
|
||||
}
|
||||
}
|
61
src/main/java/np/something/controllers/PostController.java
Normal file
61
src/main/java/np/something/controllers/PostController.java
Normal file
@ -0,0 +1,61 @@
|
||||
package np.something.controllers;
|
||||
|
||||
import np.something.DTO.PostDto;
|
||||
import np.something.services.CustomerService;
|
||||
import np.something.services.PostService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/post")
|
||||
public class PostController {
|
||||
private final PostService postService;
|
||||
private final CustomerService customerService;
|
||||
|
||||
public PostController(PostService postService, CustomerService customerService) {
|
||||
this.postService = postService;
|
||||
this.customerService = customerService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public PostDto getPost(@PathVariable Long id) {
|
||||
return new PostDto(postService.findPost(id));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<PostDto> getPosts() {
|
||||
return postService.findAllPosts().stream()
|
||||
.map(PostDto::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public PostDto createPost(
|
||||
@RequestParam("title") String title,
|
||||
@RequestParam("content") String content,
|
||||
@RequestParam("authorId") Long authorId
|
||||
)
|
||||
{
|
||||
return new PostDto(postService.addPost(customerService.findCustomer(authorId), title, content));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public PostDto updatePost(
|
||||
@PathVariable Long id,
|
||||
@RequestParam("title") String title,
|
||||
@RequestParam("content") String content
|
||||
)
|
||||
{
|
||||
return new PostDto(postService.updatePost(id, title, content));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public PostDto deletePost (@PathVariable Long id) {
|
||||
return new PostDto(postService.deletePost(id));
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public void deleteAllPosts() {
|
||||
postService.deleteAllPosts();
|
||||
}
|
||||
}
|
@ -1,20 +1,24 @@
|
||||
package np.something.util.error;
|
||||
|
||||
import np.something.Exceptions.CommentNotFoundException;
|
||||
import np.something.Exceptions.CustomerNotFoundException;
|
||||
import np.something.Exceptions.PostNotFoundException;
|
||||
import np.something.util.validation.ValidationException;
|
||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import ru.ulstu.is.sbapp.student.service.StudentNotFoundException;
|
||||
import ru.ulstu.is.sbapp.util.validation.ValidationException;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ControllerAdvice
|
||||
public class AdviceController {
|
||||
@ExceptionHandler({
|
||||
StudentNotFoundException.class,
|
||||
CommentNotFoundException.class,
|
||||
CustomerNotFoundException.class,
|
||||
PostNotFoundException.class,
|
||||
ValidationException.class
|
||||
})
|
||||
public ResponseEntity<Object> handleException(Throwable e) {
|
||||
|
@ -2,10 +2,10 @@ package np.something.util.validation;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user