started front and changes in back
This commit is contained in:
parent
e64d4e6434
commit
5c09ff94f8
28
frontend/.gitignore
vendored
Normal file
28
frontend/.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
29
frontend/README.md
Normal file
29
frontend/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
# frontend
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
14
frontend/index.html
Normal file
14
frontend/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
1694
frontend/package-lock.json
generated
Normal file
1694
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
frontend/package.json
Normal file
21
frontend/package.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.3.6",
|
||||
"bootstrap": "^5.2.3",
|
||||
"vue": "^3.2.47",
|
||||
"vue-router": "^4.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
||||
"vite": "^4.1.4"
|
||||
}
|
||||
}
|
BIN
frontend/public/favicon.ico
Normal file
BIN
frontend/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
19
frontend/src/App.vue
Normal file
19
frontend/src/App.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<script>
|
||||
import Header from './components/Header.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Header
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Header></Header>
|
||||
<div class="container-fluid">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
135
frontend/src/components/Cabinets.vue
Normal file
135
frontend/src/components/Cabinets.vue
Normal file
@ -0,0 +1,135 @@
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import CatalogMixins from '../mixins/CatalogMixins.js';
|
||||
import Cabinet from "../models/Cabinet";
|
||||
import Computer from '../models/Computer';
|
||||
import Monitor from '../models/Monitor';
|
||||
import DataService from '../services/DataService';
|
||||
|
||||
export default {
|
||||
mixins: [
|
||||
CatalogMixins
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
getAllUrl: 'cabinet/',
|
||||
dataUrl: 'cabinet',
|
||||
transformer: (data) => new Cabinet(data),
|
||||
headers: [
|
||||
{ name: 'number', label: 'Номер кабинета' }
|
||||
],
|
||||
headersComps: [
|
||||
{ name: 'modelName', label: 'Модель' },
|
||||
{ name: 'serialNum', label: 'Серийный номер' },
|
||||
{ name: 'monitorName', label: 'Модель монитора' }
|
||||
],
|
||||
selectedItemsComps: [],
|
||||
dataFilterUrl: 'cabinet/filter?',
|
||||
computerUrl: 'computer/',
|
||||
computers: [],
|
||||
monitorUrl: 'monitor/',
|
||||
monitors: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
DataService.readAll(this.computerUrl, (data) => new Computer(data))
|
||||
.then(data => {
|
||||
this.computers = data;
|
||||
});
|
||||
DataService.readAll(this.monitorUrl, (data) => new Monitor(data))
|
||||
.then(data => {
|
||||
this.monitors = data;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
filter() {
|
||||
let urlParams = ""
|
||||
if (document.getElementById('numberFilterInput').value != "") {
|
||||
urlParams += "number=" + this.number;
|
||||
}
|
||||
DataService.readAll(this.dataFilterUrl + urlParams, (data) => new Cabinet(data))
|
||||
.then(data => {
|
||||
this.items = data;
|
||||
});
|
||||
},
|
||||
clearFilters() {
|
||||
this.loadItems();
|
||||
this.id = null;
|
||||
this.number = null;
|
||||
},
|
||||
addComputerInCabinet(cabinetId) {
|
||||
let computerId = document.getElementById('computers').value;
|
||||
let response = axios.post(`http://localhost:8080/api/cabinet/${cabinetId}/computer?computerId=${computerId}`);
|
||||
console.log(response);
|
||||
},
|
||||
itemsComps(computerIds) {
|
||||
let result = [];
|
||||
if (typeof computerIds === 'undefined') {
|
||||
return;
|
||||
}
|
||||
this.computers.forEach(computer => {
|
||||
for (let i = 0; i < computerIds.length; i++) {
|
||||
if (computer.id === computerIds[i]) {
|
||||
for (let j = 0; j < this.monitors.length; j++) {
|
||||
if (computer.monitorId === this.monitors[j].id) {
|
||||
computer._monitor = this.monitors[j];
|
||||
}
|
||||
}
|
||||
result.push(computer);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" id="numberFilterInput" placeholder="Номер кабинета" required v-model="number">
|
||||
|
||||
<button class="btn btn-primary" type="button" id="report-button"
|
||||
@click.prevent="filter">Сформировать</button>
|
||||
<button class="btn btn-outline-secondary" type="button" id="report-button"
|
||||
@click.prevent="clearFilters">Очистить</button>
|
||||
</div>
|
||||
<ToolBar
|
||||
@add="showAddModal"
|
||||
@edit="showEditModal"
|
||||
@remove="removeSelectedItems">
|
||||
</ToolBar>
|
||||
<DataTable
|
||||
:headers="this.headers"
|
||||
:items="this.items"
|
||||
:selectedItems="this.selectedItems"
|
||||
@dblclick="showEditModalDblClick">
|
||||
</DataTable>
|
||||
<Modal
|
||||
:header="this.modal.header"
|
||||
:confirm="this.modal.confirm"
|
||||
v-model:visible="this.modalShow"
|
||||
@done="saveItem">
|
||||
<div class="mb-3">
|
||||
<label for="number" class="form-label">Номер кабинета</label>
|
||||
<input type="text" class="form-control" id="number" required v-model="data.number">
|
||||
</div>
|
||||
<DataTable
|
||||
:headers="this.headersComps"
|
||||
:items="itemsComps(data.computerIds)"
|
||||
:selectedItems="this.selectedItemsComps">
|
||||
</DataTable>
|
||||
<div class="mb-3">
|
||||
<label for="computers" class="form-label">Добавить компьютер</label>
|
||||
<select class="form-select" id="computers" required>
|
||||
<option disabled value="">Выберите компьютер</option>
|
||||
<option v-for="computer in this.computers"
|
||||
:value="computer.id">
|
||||
{{ computer.modelName }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary" type="button" id="addComputerButton"
|
||||
@click.prevent="addComputerInCabinet(data.id)">Добавить</button>
|
||||
</Modal>
|
||||
</template>
|
23
frontend/src/components/Catalogs.vue
Normal file
23
frontend/src/components/Catalogs.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
catalogs: [
|
||||
{ name: 'orders', label: 'Заказы' },
|
||||
// { name: 'students', label: 'Студенты' },
|
||||
// { name: 'disciplines', label: 'Дисциплины' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list-group">
|
||||
<router-link v-for="catalog in this.catalogs"
|
||||
:to="'/catalogs/' + catalog.name"
|
||||
class="list-group-item list-group-item-action">
|
||||
{{ catalog.label }}
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
70
frontend/src/components/DataTable.vue
Normal file
70
frontend/src/components/DataTable.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
headers: Array,
|
||||
items: Array,
|
||||
selectedItems: Array
|
||||
},
|
||||
emits: {
|
||||
dblclick: null
|
||||
},
|
||||
methods: {
|
||||
rowClick(id) {
|
||||
if (this.isSelected(id)) {
|
||||
var index = this.selectedItems.indexOf(id);
|
||||
if (index !== -1) {
|
||||
this.selectedItems.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
this.selectedItems.push(id);
|
||||
}
|
||||
},
|
||||
rowDblClick(id) {
|
||||
this.$emit('dblclick', id);
|
||||
},
|
||||
isSelected(id) {
|
||||
return this.selectedItems.includes(id);
|
||||
},
|
||||
dataConvert(data) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th v-for="header in this.headers"
|
||||
:id="header.name"
|
||||
scope="col">{{ header.label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in this.items"
|
||||
@click="rowClick(item.id)"
|
||||
@dblclick="rowDblClick(item.id)"
|
||||
:class="{selected: isSelected(item.id)}">
|
||||
<th scope="row">{{ index + 1 }}</th>
|
||||
<td v-for="header in this.headers">
|
||||
{{ dataConvert(item[header.name]) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
tbody tr:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
tr.selected {
|
||||
background-color: #0d6efd;
|
||||
opacity: 80%;
|
||||
}
|
||||
tbody tr {
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
35
frontend/src/components/Header.vue
Normal file
35
frontend/src/components/Header.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
getRoutes() {
|
||||
return this.$router.options.routes.filter(route => route.meta?.hasOwnProperty('label'));
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="navbar navbar-expand-lg bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/">
|
||||
<i class="fa-solid fa-book"></i>
|
||||
Рабочее место оператора пункта выдачи заказов
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item"
|
||||
v-for="route in this.getRoutes()">
|
||||
<router-link class="nav-link" :to="route.path">{{ route.meta.label }}</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
63
frontend/src/components/Modal.vue
Normal file
63
frontend/src/components/Modal.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
header: String,
|
||||
confirm: String,
|
||||
visible: Boolean
|
||||
},
|
||||
emits: {
|
||||
done: null,
|
||||
'update:visible': (value) => {
|
||||
if (typeof value !== 'boolean') {
|
||||
throw 'Value is not a boolean';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hide() {
|
||||
this.$emit('update:visible', false);
|
||||
},
|
||||
done() {
|
||||
if (this.$refs.form.checkValidity()) {
|
||||
this.$emit('done');
|
||||
this.hide();
|
||||
} else {
|
||||
this.$refs.form.reportValidity();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="modal fade" tabindex="-1" aria-hidden="true"
|
||||
:class="{ 'modal-show': this.visible, 'show': this.visible }">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="exampleModalLabel">{{ header }}</h1>
|
||||
<button type="button" class="btn-close" aria-label="Close"
|
||||
@click.prevent="hide"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="done" ref="form">
|
||||
<slot></slot>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary"
|
||||
@click.prevent="hide">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary"
|
||||
@click.prevent="done">{{ confirm }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.modal-show {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
247
frontend/src/components/Orders.vue
Normal file
247
frontend/src/components/Orders.vue
Normal file
@ -0,0 +1,247 @@
|
||||
<script>
|
||||
import CatalogMixins from '../mixins/CatalogMixins.js';
|
||||
import Order from "../models/Order";
|
||||
import Car from '../models/Car';
|
||||
import Client from '../models/Client';
|
||||
import PickUpPoint from '../models/PickUpPoint';
|
||||
import DataService from '../services/DataService';
|
||||
|
||||
export default {
|
||||
mixins: [
|
||||
CatalogMixins
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
getAllUrl: 'order',
|
||||
dataUrl: 'order',
|
||||
transformer: (data) => new Order(data),
|
||||
headers: [
|
||||
{ name: 'value', label: 'Оценочная стоимость' },
|
||||
{ name: 'status', label: 'Статус' },
|
||||
{ name: 'date', label: 'Дата' },
|
||||
{ name: 'clientName', label: 'Клиент' },
|
||||
{ name: 'sourcePickUpPointAddress', label: 'Пункт отправления' },
|
||||
{ name: 'destPickUpPointAddress', label: 'Пункт выдачи' },
|
||||
{ name: 'carNumber', label: 'Автомобиль' }
|
||||
],
|
||||
dataFilterUrl: 'order/filter?',
|
||||
carUrl: 'car',
|
||||
cars: [],
|
||||
pickUpPointUrl: 'pickUpPoint',
|
||||
pickUpPoints: [],
|
||||
clientUrl: 'client',
|
||||
clients: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
DataService.readAll(this.carUrl, (data) => new Car(data))
|
||||
.then(data => {
|
||||
this.cars = data;
|
||||
});
|
||||
DataService.readAll(this.pickUpPointUrl, (data) => new PickUpPoint(data))
|
||||
.then(data => {
|
||||
this.pickUpPoints = data;
|
||||
});
|
||||
DataService.readAll(this.clientUrl, (data) => new Client(data))
|
||||
.then(data => {
|
||||
this.clients = data;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
filter() {
|
||||
let urlParams = ""
|
||||
if (document.getElementById('idFilterInput').value != "") {
|
||||
if (urlParams != "") {
|
||||
urlParams += "&";
|
||||
}
|
||||
urlParams += "id=" + this.id;
|
||||
}
|
||||
if (document.getElementById('valueFilterInput').value != "") {
|
||||
if (urlParams != "") {
|
||||
urlParams += "&";
|
||||
}
|
||||
urlParams += "value=" + this.value;
|
||||
}
|
||||
if (document.getElementById('statusFilterSelect').value != "") {
|
||||
if (urlParams != "") {
|
||||
urlParams += "&";
|
||||
}
|
||||
urlParams += "status=" + this.status;
|
||||
}
|
||||
if (document.getElementById('dateFilterInput').value != "") {
|
||||
if (urlParams != "") {
|
||||
urlParams += "&";
|
||||
}
|
||||
urlParams += "date=" + this.date;
|
||||
}
|
||||
if (document.getElementById('clientFilterSelect').value != "") {
|
||||
if (urlParams != "") {
|
||||
urlParams += "&";
|
||||
}
|
||||
urlParams += "clientId=" + this.clientId;
|
||||
}
|
||||
if (document.getElementById('sourcePickUpPointFilterSelect').value != "") {
|
||||
if (urlParams != "") {
|
||||
urlParams += "&";
|
||||
}
|
||||
urlParams += "sourcePickUpPointId=" + this.sourcePickUpPointId;
|
||||
}
|
||||
if (document.getElementById('destPickUpPointFilterSelect').value != "") {
|
||||
if (urlParams != "") {
|
||||
urlParams += "&";
|
||||
}
|
||||
urlParams += "destPickUpPointId=" + this.destPickUpPointId;
|
||||
}
|
||||
if (document.getElementById('carFilterSelect').value != "") {
|
||||
if (urlParams != "") {
|
||||
urlParams += "&";
|
||||
}
|
||||
urlParams += "carId=" + this.carId;
|
||||
}
|
||||
DataService.readAll(this.dataFilterUrl + urlParams, (data) => new Order(data))
|
||||
.then(data => {
|
||||
this.items = data;
|
||||
});
|
||||
},
|
||||
clearFilters() {
|
||||
this.loadItems();
|
||||
this.id = null;
|
||||
this.value = null;
|
||||
this.status = null;
|
||||
this.date = null;
|
||||
this.clientId = null;
|
||||
this.sourcePickUpPointId = null;
|
||||
this.destPickUpPointId = null;
|
||||
this.destPickUpPointId = null;
|
||||
this.carId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" id="idFilterInput" placeholder="Номер заказа" required v-model="id">
|
||||
|
||||
<input type="text" class="form-control" id="valueFilterInput" placeholder="Оценочная стоимость" required v-model="value">
|
||||
|
||||
<select class="form-select" id="statusFilterSelect" v-model="status">
|
||||
<option disabled value="" selected>Выберите статус</option>
|
||||
<option value="accepted">Принят</option>
|
||||
<option value="inDelivery">В пути</option>
|
||||
<option value="delivered">Доставлен</option>
|
||||
<option value="issued">Выдан</option>
|
||||
</select>
|
||||
|
||||
<input type="date" class="form-control" id="dateFilterInput" placeholder="Дата" required v-model="date">
|
||||
|
||||
<select class="form-select" id="clientFilterSelect" v-model="clientId">
|
||||
<option disabled value="" selected>Выберите клиента</option>
|
||||
<option v-for="client in clients" :value="client.id">{{ client.name }}</option>
|
||||
</select>
|
||||
|
||||
<select class="form-select" id="sourcePickUpPointFilterSelect" v-model="sourcePickUpPointId">
|
||||
<option disabled value="" selected>Выберите пункт отправления</option>
|
||||
<option v-for="sourcePickUpPoint in pickUpPoints" :value="sourcePickUpPoint.id">{{ sourcePickUpPoint.address }}</option>
|
||||
</select>
|
||||
|
||||
<select class="form-select" id="destPickUpPointFilterSelect" v-model="destPickUpPointId">
|
||||
<option disabled value="" selected>Выберите пункт получения</option>
|
||||
<option v-for="destPickUpPoint in pickUpPoints" :value="destPickUpPoint.id">{{ destPickUpPoint.address }}</option>
|
||||
</select>
|
||||
|
||||
<select class="form-select" id="carFilterSelect" v-model="carId">
|
||||
<option disabled value="" selected>Выберите автомобиль</option>
|
||||
<option v-for="car in cars" :value="car.id">{{ car.gosNumber }}</option>
|
||||
</select>
|
||||
|
||||
<button class="btn btn-primary" type="button" id="report-button"
|
||||
@click.prevent="filter">Сформировать</button>
|
||||
<button class="btn btn-outline-secondary" type="button" id="report-button"
|
||||
@click.prevent="clearFilters">Очистить</button>
|
||||
</div>
|
||||
<ToolBar
|
||||
@add="showAddModal"
|
||||
@edit="showEditModal"
|
||||
@remove="removeSelectedItems">
|
||||
</ToolBar>
|
||||
<DataTable
|
||||
:headers="this.headers"
|
||||
:items="this.items"
|
||||
:selectedItems="this.selectedItems"
|
||||
@dblclick="showEditModalDblClick">
|
||||
</DataTable>
|
||||
<Modal
|
||||
:header="this.modal.header"
|
||||
:confirm="this.modal.confirm"
|
||||
v-model:visible="this.modalShow"
|
||||
@done="saveItem">
|
||||
<div class="mb-3">
|
||||
<label for="value" class="form-label">Оценочная стоимость</label>
|
||||
<input type="text" class="form-control" id="value" required v-model="data.value">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Статус</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="status" id="statusAccepted" v-model="data.status" value="accepted" checked>
|
||||
<label class="form-check-label" for="statusAccepted">
|
||||
Принят
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="status" id="statusIssued" v-model="data.status" value="issued">
|
||||
<label class="form-check-label" for="statusIssued">
|
||||
Выдан
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="date" class="form-label">Дата</label>
|
||||
<input type="date" class="form-control" id="date" required v-model="data.date">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="clients" class="form-label">Клиент</label>
|
||||
<select class="form-select" id="client" required v-model="data.clientId">
|
||||
<option disabled value="">Выберите клиента</option>
|
||||
<option v-for="client in this.clients"
|
||||
:value="client.id"
|
||||
:selected="data.clientId && client.id === data.clientId">
|
||||
{{ client.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pickUpPoints" class="form-label">Пункт отправления</label>
|
||||
<select class="form-select" id="sourcePickUpPoint" required v-model="data.sourcePickUpPointId">
|
||||
<option disabled value="">Выберите пункт отправления</option>
|
||||
<option v-for="sourcePickUpPoint in this.pickUpPoints"
|
||||
:value="sourcePickUpPoint.id"
|
||||
:selected="data.sourcePickUpPointId && sourcePickUpPoint.id === data.sourcePickUpPointId">
|
||||
{{ sourcePickUpPoint.address }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pickUpPoints" class="form-label">Пункт выдачи</label>
|
||||
<select class="form-select" id="destPickUpPoint" v-model="data.destPickUpPointId">
|
||||
<option disabled value="">Выберите пункт выдачи</option>
|
||||
<option v-for="destPickUpPoint in this.pickUpPoints"
|
||||
:value="destPickUpPoint.id"
|
||||
:selected="data.destPickUpPointId && destPickUpPoint.id === data.destPickUpPointId">
|
||||
{{ destPickUpPoint.address }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="cars" class="form-label">Автомобиль</label>
|
||||
<select class="form-select" id="car" required v-model="data.carId">
|
||||
<option disabled value="">Выберите автомобиль</option>
|
||||
<option v-for="car in this.cars"
|
||||
:value="car.id"
|
||||
:selected="data.carId && car.id === data.carId">
|
||||
{{ car.vin }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
21
frontend/src/components/Reports.vue
Normal file
21
frontend/src/components/Reports.vue
Normal file
@ -0,0 +1,21 @@
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
reports: [
|
||||
{ name: 'group-students', label: 'Список студентов' },
|
||||
{ name: 'group-disciplines', label: 'Список дисциплин' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list-group">
|
||||
<router-link v-for="report in this.reports"
|
||||
:to="'/reports/' + report.name" class="list-group-item list-group-item-action">
|
||||
{{ report.label }}
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
46
frontend/src/components/ToolBar.vue
Normal file
46
frontend/src/components/ToolBar.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
|
||||
},
|
||||
emits: {
|
||||
add: null,
|
||||
edit: null,
|
||||
remove: null
|
||||
},
|
||||
methods: {
|
||||
add() {
|
||||
this.$emit('add');
|
||||
},
|
||||
edit() {
|
||||
this.$emit('edit');
|
||||
},
|
||||
remove() {
|
||||
this.$emit('remove');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="btn-group mt-2" role="group">
|
||||
<button type="button" class="btn btn-success"
|
||||
@click.prevent="add">
|
||||
Добавить
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning"
|
||||
@click.prevent="edit">
|
||||
Изменить
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger"
|
||||
@click.prevent="remove">
|
||||
Удалить
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.btn {
|
||||
min-width: 140px;
|
||||
}
|
||||
</style>
|
17
frontend/src/main.js
Normal file
17
frontend/src/main.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import './style.css'
|
||||
import App from './App.vue'
|
||||
import Cabinets from './components/Cabinets.vue'
|
||||
|
||||
const routes = [
|
||||
{ path: '/', redirect: '/cabinets' },
|
||||
{ path: '/cabinets', component: Cabinets, meta: { label: 'Кабинеты' }}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
linkActiveClass: 'active',
|
||||
routes
|
||||
})
|
||||
createApp(App).use(router).mount('#app')
|
102
frontend/src/mixins/CatalogMixins.js
Normal file
102
frontend/src/mixins/CatalogMixins.js
Normal file
@ -0,0 +1,102 @@
|
||||
import ToolBar from '../components/ToolBar.vue';
|
||||
import DataTable from '../components/DataTable.vue';
|
||||
import Modal from '../components/Modal.vue';
|
||||
import DataService from '../services/DataService';
|
||||
|
||||
const CatalogMixin = {
|
||||
components: {
|
||||
ToolBar, DataTable, Modal
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
getAllUrl: undefined,
|
||||
dataUrl: undefined,
|
||||
transformer: undefined,
|
||||
headers: [],
|
||||
items: [],
|
||||
selectedItems: [],
|
||||
modal: {
|
||||
header: undefined,
|
||||
confirm: undefined,
|
||||
},
|
||||
modalShow: false,
|
||||
data: undefined,
|
||||
isEdit: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadItems();
|
||||
},
|
||||
methods: {
|
||||
loadItems() {
|
||||
this.getItems();
|
||||
this.data = this.transformer();
|
||||
},
|
||||
getItems() {
|
||||
DataService.readAll(this.getAllUrl, this.transformer)
|
||||
.then(data => {
|
||||
this.items = data;
|
||||
});
|
||||
},
|
||||
showAddModal() {
|
||||
this.isEdit = false;
|
||||
this.data = this.transformer();
|
||||
this.modal.header = 'Добавление элемента';
|
||||
this.modal.confirm = 'Добавить';
|
||||
this.modalShow = true;
|
||||
},
|
||||
showEditModal() {
|
||||
if (this.selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.showEditModalDblClick(this.selectedItems[0]);
|
||||
},
|
||||
showEditModalDblClick(editId) {
|
||||
DataService.read(this.dataUrl + "/" + editId, this.transformer)
|
||||
.then(data => {
|
||||
this.data = data;
|
||||
this.isEdit = true;
|
||||
this.modal.header = 'Редактирование элемента';
|
||||
this.modal.confirm = 'Сохранить';
|
||||
this.modalShow = true;
|
||||
});
|
||||
},
|
||||
saveItem() {
|
||||
if (!this.isEdit) {
|
||||
DataService.create(this.dataUrl, this.data)
|
||||
.then(() => {
|
||||
this.getItems();
|
||||
});
|
||||
} else {
|
||||
DataService.update(this.dataUrl + "/" + this.data.id, this.data)
|
||||
.then(() => {
|
||||
this.getItems();
|
||||
});
|
||||
}
|
||||
},
|
||||
removeSelectedItems() {
|
||||
if (this.selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (confirm('Удалить выбранные элементы?')) {
|
||||
const promises = [];
|
||||
const self = this;
|
||||
this.selectedItems.forEach(item => {
|
||||
promises.push(DataService.delete(this.dataUrl + item));
|
||||
});
|
||||
Promise.all(promises).then((results) => {
|
||||
results.forEach(function (id) {
|
||||
const index = self.selectedItems.indexOf(id);
|
||||
if (index === - 1) {
|
||||
return;
|
||||
}
|
||||
self.selectedItems.splice(index, 1);
|
||||
});
|
||||
this.getItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CatalogMixin;
|
26
frontend/src/models/Cabinet.js
Normal file
26
frontend/src/models/Cabinet.js
Normal file
@ -0,0 +1,26 @@
|
||||
export default class Cabinet {
|
||||
constructor(data) {
|
||||
this._id = data?.id;
|
||||
this._number = data?.number;
|
||||
this._computerIds = data?.computerIds;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get number() {
|
||||
return this._number;
|
||||
}
|
||||
|
||||
set number(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New number value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._number = value;
|
||||
}
|
||||
|
||||
get computerIds() {
|
||||
return this._computerIds;
|
||||
}
|
||||
}
|
47
frontend/src/models/Car.js
Normal file
47
frontend/src/models/Car.js
Normal file
@ -0,0 +1,47 @@
|
||||
export default class Car {
|
||||
constructor(data) {
|
||||
this._id = data?.id;
|
||||
this._gosNumber = data?.gosNumber;
|
||||
this._vin = data?.vin;
|
||||
this._driver = data?.driver;
|
||||
this._driverId = data?.driver.id;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get gosNumber() {
|
||||
return this._gosNumber;
|
||||
}
|
||||
|
||||
set gosNumber(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New gos number value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._gosNumber = value;
|
||||
}
|
||||
|
||||
get vin() {
|
||||
return this._vin;
|
||||
}
|
||||
|
||||
set vin(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New vin value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._vin = value;
|
||||
}
|
||||
|
||||
get driverId() {
|
||||
return this._driverId;
|
||||
}
|
||||
|
||||
set driverId(value) {
|
||||
this._driverId = value;
|
||||
}
|
||||
|
||||
get driverName() {
|
||||
return this.driver?.name;
|
||||
}
|
||||
}
|
45
frontend/src/models/Client.js
Normal file
45
frontend/src/models/Client.js
Normal file
@ -0,0 +1,45 @@
|
||||
export default class Student {
|
||||
constructor(data) {
|
||||
this._id = data?.id;
|
||||
this._name = data?.name;
|
||||
this._phone = data?.phone;
|
||||
this._email = data?.email;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
set name(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New name value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._name = value;
|
||||
}
|
||||
|
||||
get phone() {
|
||||
return this._phone;
|
||||
}
|
||||
|
||||
set phone(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New phone value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._phone = value;
|
||||
}
|
||||
|
||||
get email() {
|
||||
return this._email;
|
||||
}
|
||||
|
||||
set email(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New email value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._email = value;
|
||||
}
|
||||
}
|
63
frontend/src/models/Computer.js
Normal file
63
frontend/src/models/Computer.js
Normal file
@ -0,0 +1,63 @@
|
||||
export default class Computer {
|
||||
constructor(data) {
|
||||
this._id = data?.id;
|
||||
this._modelName = data?.modelName;
|
||||
this._serialNum = data?.serialNum;
|
||||
this._monitor = data?.monitor;
|
||||
this._monitorId = data?.monitorId;
|
||||
this._cabinet = data?.cabinet;
|
||||
this._cabinetId = data?.cabinetId;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get modelName() {
|
||||
return this._modelName;
|
||||
}
|
||||
|
||||
set modelName(value) {
|
||||
this._modelName = value;
|
||||
}
|
||||
|
||||
get serialNum() {
|
||||
return this._serialNum;
|
||||
}
|
||||
|
||||
set serialNum(value) {
|
||||
this._serialNum = value;
|
||||
}
|
||||
|
||||
get monitorId() {
|
||||
return this._monitorId;
|
||||
}
|
||||
|
||||
set monitorId(data) {
|
||||
this._monitorId = data;
|
||||
}
|
||||
|
||||
get monitor() {
|
||||
return this._monitor;
|
||||
}
|
||||
|
||||
set monitor(data) {
|
||||
this._monitor = data;
|
||||
}
|
||||
|
||||
get monitorName() {
|
||||
return this._monitor?.modelName;
|
||||
}
|
||||
|
||||
get cabinetId() {
|
||||
return this._cabinetId;
|
||||
}
|
||||
|
||||
set cabinetId(value) {
|
||||
this._cabinetId = value;
|
||||
}
|
||||
|
||||
get cabinetNumber() {
|
||||
return this._cabinet?.numer;
|
||||
}
|
||||
}
|
54
frontend/src/models/Driver.js
Normal file
54
frontend/src/models/Driver.js
Normal file
@ -0,0 +1,54 @@
|
||||
export default class Driver {
|
||||
constructor(data) {
|
||||
this._id = data?.id;
|
||||
this._name = data?.name;
|
||||
this._birthday = data?.birthday;
|
||||
this._phone = data?.phone;
|
||||
this._email = data?.email;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
set name(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New name value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._name = value;
|
||||
}
|
||||
|
||||
get birthday() {
|
||||
return this._age;
|
||||
}
|
||||
|
||||
set birthday(value) {
|
||||
this._birthday = value;
|
||||
}
|
||||
|
||||
get phone() {
|
||||
return this._phone;
|
||||
}
|
||||
|
||||
set phone(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New phone value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._phone = value;
|
||||
}
|
||||
|
||||
get email() {
|
||||
return this._email;
|
||||
}
|
||||
|
||||
set email(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New email value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._email = value;
|
||||
}
|
||||
}
|
21
frontend/src/models/Monitor.js
Normal file
21
frontend/src/models/Monitor.js
Normal file
@ -0,0 +1,21 @@
|
||||
export default class Monitor {
|
||||
constructor(data) {
|
||||
this._id = data?.id;
|
||||
this._modelName = data?.modelName;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get modelName() {
|
||||
return this._modelName;
|
||||
}
|
||||
|
||||
set modelName(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New model name value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._modelName = value;
|
||||
}
|
||||
}
|
92
frontend/src/models/Order.js
Normal file
92
frontend/src/models/Order.js
Normal file
@ -0,0 +1,92 @@
|
||||
export default class Order {
|
||||
constructor(data) {
|
||||
this._id = data?.id;
|
||||
this._value = data?.value;
|
||||
this._status = data?.status;
|
||||
this._date = data?.date.split('T')[0];
|
||||
this._client = data?.client;
|
||||
this._clientId = data?.client.id;
|
||||
this._sourcePickUpPoint = data?.sourcePickUpPoint;
|
||||
this._sourcePickUpPointId = data?.sourcePickUpPoint.id;
|
||||
this._destPickUpPoint = data?.destPickUpPoint;
|
||||
this._destPickUpPointId = data?.destPickUpPoint?.id;
|
||||
this._car = data?.car;
|
||||
this._carId = data?.car.id;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
set value(data) {
|
||||
this._value = data;
|
||||
}
|
||||
|
||||
get status() {
|
||||
return this._status;
|
||||
}
|
||||
|
||||
set status(data) {
|
||||
this._status = data;
|
||||
}
|
||||
|
||||
get date() {
|
||||
return this._date;
|
||||
}
|
||||
|
||||
set date(data) {
|
||||
this._date = data;
|
||||
}
|
||||
|
||||
get clientId() {
|
||||
return this._clientId;
|
||||
}
|
||||
|
||||
set clientId(value) {
|
||||
this._clientId = value;
|
||||
}
|
||||
|
||||
get clientName() {
|
||||
return this._client?.name;
|
||||
}
|
||||
|
||||
get sourcePickUpPointId() {
|
||||
return this._sourcePickUpPointId;
|
||||
}
|
||||
|
||||
set sourcePickUpPointId(value) {
|
||||
this._sourcePickUpPointId = value;
|
||||
}
|
||||
|
||||
get sourcePickUpPointAddress() {
|
||||
return this._sourcePickUpPoint?.address;
|
||||
}
|
||||
|
||||
get destPickUpPointId() {
|
||||
return this._destPickUpPointId;
|
||||
}
|
||||
|
||||
set destPickUpPointId(value) {
|
||||
this._destPickUpPointId = value;
|
||||
}
|
||||
|
||||
get destPickUpPointAddress() {
|
||||
return this._destPickUpPoint?.address;
|
||||
}
|
||||
|
||||
get carId() {
|
||||
return this._carId;
|
||||
}
|
||||
|
||||
set carId(value) {
|
||||
this._carId = value;
|
||||
}
|
||||
|
||||
get carNumber() {
|
||||
return this._car?.gosNumber;
|
||||
}
|
||||
}
|
21
frontend/src/models/PickUpPoint.js
Normal file
21
frontend/src/models/PickUpPoint.js
Normal file
@ -0,0 +1,21 @@
|
||||
export default class PickUpPoint {
|
||||
constructor(data) {
|
||||
this._id = data?.id;
|
||||
this._address = data?.address;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get address() {
|
||||
return this._address;
|
||||
}
|
||||
|
||||
set address(value) {
|
||||
if (typeof value !== 'string' || value === null || value.length == 0) {
|
||||
throw 'New address value ' + value + ' is not a string or empty';
|
||||
}
|
||||
this._address = value;
|
||||
}
|
||||
}
|
42
frontend/src/services/DataService.js
Normal file
42
frontend/src/services/DataService.js
Normal file
@ -0,0 +1,42 @@
|
||||
import axios from 'axios';
|
||||
|
||||
function toJSON(data) {
|
||||
const jsonObj = {};
|
||||
const fields = Object.getOwnPropertyNames(data);
|
||||
for (const field of fields) {
|
||||
if (data[field] === undefined) {
|
||||
continue;
|
||||
}
|
||||
jsonObj[field.substring(1)] = data[field];
|
||||
}
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
export default class DataService {
|
||||
static dataUrlPrefix = 'http://localhost:8080/api/';
|
||||
|
||||
static async readAll(url, transformer) {
|
||||
const response = await axios.get(this.dataUrlPrefix + url);
|
||||
return response.data.map(item => transformer(item));
|
||||
}
|
||||
|
||||
static async read(url, transformer) {
|
||||
const response = await axios.get(this.dataUrlPrefix + url);
|
||||
return transformer(response.data);
|
||||
}
|
||||
|
||||
static async create(url, data) {
|
||||
const response = await axios.post(this.dataUrlPrefix + url, toJSON(data));
|
||||
return true;
|
||||
}
|
||||
|
||||
static async update(url, data) {
|
||||
const response = await axios.put(this.dataUrlPrefix + url, toJSON(data));
|
||||
return true;
|
||||
}
|
||||
|
||||
static async delete(url) {
|
||||
const response = await axios.delete(this.dataUrlPrefix + url);
|
||||
return response.data.id;
|
||||
}
|
||||
}
|
0
frontend/src/style.css
Normal file
0
frontend/src/style.css
Normal file
15
frontend/vite.config.js
Normal file
15
frontend/vite.config.js
Normal file
@ -0,0 +1,15 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue(), vueJsx()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
}
|
||||
})
|
@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import com.kalyshev.yan.cabinet.model.Cabinet;
|
||||
import com.kalyshev.yan.cabinet.service.CabinetService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@ -34,14 +35,21 @@ public class CabinetController {
|
||||
.map(ComputerDto::new)
|
||||
.toList();
|
||||
}
|
||||
@GetMapping("/filter")
|
||||
public List<CabinetDto> getFilteredCabinets(@RequestParam(value = "id", required = false) Long id,
|
||||
@RequestParam(value = "number", required = false) String number) {
|
||||
return cabinetService.findFilteredCabinets(id, number).stream()
|
||||
.map(CabinetDto::new)
|
||||
.toList();
|
||||
}
|
||||
@PostMapping("/")
|
||||
public CabinetDto createCabinet(@RequestBody @Valid CabinetDto cabinetDto) {
|
||||
return new CabinetDto(cabinetService.addCabinet(cabinetDto.getNumber()));
|
||||
}
|
||||
@PostMapping("/computer")
|
||||
public ComputerDto createCabinetComputer(@RequestParam("computerId") Long computerId,
|
||||
@RequestParam("cabinetId") Long cabinetId) {
|
||||
return new ComputerDto(cabinetService.addComputer(computerId, cabinetId));
|
||||
@PostMapping("/{id}/computer")
|
||||
public ComputerDto createCabinetComputer(@PathVariable Long id,
|
||||
@RequestParam("computerId") Long computerId) {
|
||||
return new ComputerDto(cabinetService.addComputer(computerId, id));
|
||||
}
|
||||
@PutMapping("/{id}")
|
||||
public CabinetDto updateCabinet(@PathVariable Long id,
|
||||
|
@ -3,22 +3,31 @@ package com.kalyshev.yan.cabinet.controller;
|
||||
import com.kalyshev.yan.cabinet.model.Cabinet;
|
||||
import com.kalyshev.yan.computer.model.Computer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CabinetDto {
|
||||
private Long id;
|
||||
private String number;
|
||||
private List<Computer> computers;
|
||||
private List<Long> computerIds;
|
||||
public CabinetDto() {}
|
||||
public CabinetDto(Cabinet cabinet) {
|
||||
this.id = cabinet.getId();
|
||||
this.number = cabinet.getNumber();
|
||||
this.computers = List.copyOf(cabinet.getComputers());
|
||||
if (cabinet.getComputers() == null) {
|
||||
this.computerIds = new ArrayList<>();
|
||||
} else {
|
||||
this.computerIds = new ArrayList<>();
|
||||
List<Computer> computers = cabinet.getComputers();
|
||||
for (Computer computer : computers) {
|
||||
computerIds.add(computer.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
public Long getId() { return this.id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getNumber() { return this.number; }
|
||||
public void setNumber(String number) { this.number = number; }
|
||||
public List<Computer> getComputers() { return this.computers; }
|
||||
public void setComputers(List<Computer> computers) { this.computers = computers; }
|
||||
public List<Long> getComputerIds() { return this.computerIds; }
|
||||
public void setComputerIds(List<Long> computerIds) { this.computerIds = computerIds; }
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class Cabinet {
|
||||
return computers;
|
||||
}
|
||||
public void addComputer(Computer computer){
|
||||
if (computers == null){
|
||||
if (computers == null){
|
||||
this.computers = new ArrayList<>();
|
||||
}
|
||||
if (!computers.contains(computer)) {
|
||||
@ -55,12 +55,10 @@ public class Cabinet {
|
||||
Cabinet cabinet = (Cabinet) o;
|
||||
return Objects.equals(id, cabinet.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Cabinet{" +
|
||||
|
@ -14,8 +14,8 @@ import com.kalyshev.yan.cabinet.model.Cabinet;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class CabinetService {
|
||||
@ -44,6 +44,24 @@ public class CabinetService {
|
||||
return cabinet.orElseThrow(() -> new CabinetNotFoundException(id));
|
||||
}
|
||||
@Transactional(readOnly = true)
|
||||
public List<Cabinet> findFilteredCabinets(Long id, String number) {
|
||||
List<Cabinet> allCabinets = cabinetRepository.findAll();
|
||||
List<Cabinet> result = new ArrayList<>();
|
||||
for (Cabinet cabinet : allCabinets) {
|
||||
boolean flag = true;
|
||||
if (id != null && !Objects.equals(cabinet.getId(), id)) {
|
||||
flag = false;
|
||||
}
|
||||
if (number != null && !Objects.equals(cabinet.getNumber(), number)) {
|
||||
flag = false;
|
||||
}
|
||||
if (flag) {
|
||||
result.add(cabinet);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@Transactional(readOnly = true)
|
||||
public List<Cabinet> findAllCabinets() {
|
||||
return cabinetRepository.findAll();
|
||||
}
|
||||
@ -97,10 +115,10 @@ public class CabinetService {
|
||||
}
|
||||
@Transactional
|
||||
public Computer deleteComputer(Long computerId, Long cabinetId) {
|
||||
if ((Object)computerId == null) {
|
||||
if ((Object) computerId == null) {
|
||||
throw new IllegalArgumentException("Computer id is null or empty");
|
||||
}
|
||||
if ((Object)cabinetId == null) {
|
||||
if ((Object) cabinetId == null) {
|
||||
throw new IllegalArgumentException("Cabinet id is null or empty");
|
||||
}
|
||||
final Computer computer = computerRepository.findById(computerId)
|
||||
|
@ -36,10 +36,15 @@ public class ComputerController {
|
||||
public ComputerDto createComputer(@RequestBody @Valid ComputerDto computerDto) {
|
||||
return new ComputerDto(computerService.addComputer(computerDto.getModelName(), computerDto.getSerialNum(), computerDto.getMonitorId(), computerDto.getCabinetId()));
|
||||
}
|
||||
@PostMapping("/cabinet")
|
||||
public CabinetDto setCabinetComputer(@RequestParam("computerId") Long computerId,
|
||||
@PostMapping("/{id}/cabinet")
|
||||
public CabinetDto setCabinetComputer(@PathVariable Long id,
|
||||
@RequestParam("cabinetId") Long cabinetId) {
|
||||
return new CabinetDto(computerService.setCabinet(cabinetId, computerId));
|
||||
return new CabinetDto(computerService.setCabinet(cabinetId, id));
|
||||
}
|
||||
@PostMapping("/{id}/monitor")
|
||||
public MonitorDto setMonitorComputer(@PathVariable Long id,
|
||||
@RequestParam("monitorId") Long monitorId) {
|
||||
return new MonitorDto(computerService.setMonitor(monitorId, id));
|
||||
}
|
||||
@PutMapping("/{id}")
|
||||
public ComputerDto updateComputer(@PathVariable Long id,
|
||||
|
@ -13,8 +13,16 @@ public class ComputerDto {
|
||||
this.id = computer.getId();
|
||||
this.modelName = computer.getModelName();
|
||||
this.serialNum = computer.getSerialNum();
|
||||
this.monitorId = computer.getMonitor().getId();
|
||||
this.cabinetId = computer.getCabinet().getId();
|
||||
if (computer.getMonitor() == null) {
|
||||
this.monitorId = null;
|
||||
} else {
|
||||
this.monitorId = computer.getMonitor().getId();
|
||||
}
|
||||
if (computer.getCabinet() == null) {
|
||||
this.cabinetId = null;
|
||||
} else {
|
||||
this.cabinetId = computer.getCabinet().getId();
|
||||
}
|
||||
}
|
||||
public Long getId() { return this.id; }
|
||||
public String getModelName() { return this.modelName; }
|
||||
|
@ -2,7 +2,9 @@ package com.kalyshev.yan.computer.model;
|
||||
|
||||
import com.kalyshev.yan.cabinet.model.Cabinet;
|
||||
import com.kalyshev.yan.monitor.model.Monitor;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.Null;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -17,7 +19,7 @@ public class Computer {
|
||||
private String modelName;
|
||||
private String serialNum;
|
||||
@ManyToOne( cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "cabinets", nullable = true)
|
||||
@JoinColumn(name = "cabinet", nullable = true)
|
||||
private Cabinet cabinet;
|
||||
@OneToOne()
|
||||
@JoinColumn(name = "monitor_id")
|
||||
@ -43,7 +45,9 @@ public class Computer {
|
||||
return serialNum;
|
||||
}
|
||||
public void setSerialNum(String serialNum) { this.serialNum = serialNum; }
|
||||
public Cabinet getCabinet() { return cabinet; }
|
||||
public Cabinet getCabinet() {
|
||||
return cabinet;
|
||||
}
|
||||
public void setCabinet(Cabinet cabinet) { this.cabinet = cabinet; }
|
||||
|
||||
public Monitor getMonitor() {
|
||||
@ -65,12 +69,10 @@ public class Computer {
|
||||
Computer computer = (Computer) o;
|
||||
return Objects.equals(id, computer.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Computer{" +
|
||||
|
@ -9,6 +9,7 @@ import com.kalyshev.yan.monitor.model.Monitor;
|
||||
import com.kalyshev.yan.monitor.repository.MonitorNotFoundException;
|
||||
import com.kalyshev.yan.monitor.repository.MonitorRepository;
|
||||
import com.kalyshev.yan.util.validation.ValidatorUtil;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
@ -35,7 +36,7 @@ public class ComputerService {
|
||||
this.validatorUtil = validatorUtil;
|
||||
}
|
||||
@Transactional
|
||||
public Computer addComputer(String modelName, String serialNum, Long monitorId, Long cabinetId) {
|
||||
public Computer addComputer(String modelName, String serialNum, @Nullable Long monitorId, @Nullable Long cabinetId) {
|
||||
if (!StringUtils.hasText(modelName)) {
|
||||
throw new IllegalArgumentException("Computer model name is null or empty");
|
||||
}
|
||||
@ -129,4 +130,18 @@ public class ComputerService {
|
||||
computer.setCabinet(cabinet);
|
||||
return cabinet;
|
||||
}
|
||||
@Transactional
|
||||
public Monitor setMonitor(Long monitorId, Long computerId) {
|
||||
if ((Object)computerId == null) {
|
||||
throw new IllegalArgumentException("Computer id is null or empty");
|
||||
}
|
||||
if ((Object)monitorId == null) {
|
||||
throw new IllegalArgumentException("Monitor id is null or empty");
|
||||
}
|
||||
final Computer computer = findComputer(computerId);
|
||||
final Monitor monitor = monitorRepository.findById(monitorId)
|
||||
.orElseThrow(() -> new MonitorNotFoundException(monitorId));
|
||||
computer.setMonitor(monitor);
|
||||
return monitor;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user