Постепенно идём к истине

This commit is contained in:
Programmist73 2023-05-15 22:38:15 +04:00
parent 1820b567a6
commit 53911bccf8
38 changed files with 4451 additions and 5824 deletions

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="app"></div>
<script type="module" src="/src/index.js"></script>
</body>
</html>

View File

@ -1,45 +1,64 @@
import React, {useState} from 'react';
import { useRoutes, Outlet, BrowserRouter } from 'react-router-dom';
import { Routes, BrowserRouter, Route } from 'react-router-dom';
import PrivateRoutes from "./components/items/Pages/PrivateRoutes";
import AddLevel from './components/AddLevel';
import MainHead from './components/MainHead';
import AddNation from './components/AddNation';
import AddTank from './components/AddTank';
import AddClient from './components/AddClient';
import PageForChecking from './components/PageForChecking';
import SingupPage from './components/items/Pages/SingupPage';
import LoginPage from './components/items/Pages/LoginPage';
import MyNavBar from './components/items/Pages/MyNavbar';
function Router(props) {
/*function Router(props) {
return useRoutes(props.rootRoute);
}
}*/
function App() {
const routes = [
{ index: true, element: <AddLevel /> },
{ path: 'levels', element: <AddLevel />, label: 'Обзор уровней' },
{ path: 'nations', element: <AddNation />, label: 'Обзор наций' },
{ path: 'tanks', element: <AddTank />, label: 'Обзор танков'},
{ path: 'clients', element: <AddClient />, label: 'Обзор клиентов'},
{ path: 'checkPage', element: <PageForChecking />, label: 'Фильтр по танкам'}
{ index: true, element: <AddLevel />, userGroup: "AUTH"},
{ path: 'levels', element: <AddLevel />, label: 'Обзор уровней', userGroup: "AUTH" },
{ path: 'nations', element: <AddNation />, label: 'Обзор наций', userGroup: "AUTH" },
{ path: 'tanks', element: <AddTank />, label: 'Обзор танков', userGroup: "AUTH"},
{ path: 'clients', element: <AddClient />, label: 'Обзор клиентов', userGroup: "AUTH"},
{ path: 'checkPage', element: <PageForChecking />, label: 'Фильтр по танкам', userGroup: "AUTH"}
];
const links = routes.filter(route => route.hasOwnProperty('label'));
const rootRoute = [
/*const rootRoute = [
{ path: '/', element: render(links), children: routes }
];
function render(links) {
return (
<div className="App">
<MainHead links={links}/>
<Outlet/>
</div>
);
}
];*/
return (
<BrowserRouter>
<Router rootRoute={ rootRoute } />
</BrowserRouter>
<>
<BrowserRouter>
<MyNavBar links={routes}></MyNavBar>
<div className="content-div">
<Routes>
<Route element={<LoginPage />} path="/login" />
<Route element={<SingupPage />} path="/singup" />
<Route element={<PrivateRoutes userGroup="AUTH" />}>
<Route element={<AddTank />} path="/tanks" />
<Route element={<PageForChecking />} path="/checkPage" />
<Route element={<AddNation />} path="/nations" exact />
<Route element={<AddNation />} path="*" />
</Route>
<Route element={<PrivateRoutes userGroup="USER" />}>
<Route element={<AddLevel />} path="/levels" />
</Route>
<Route element={<PrivateRoutes userGroup="ADMIN" />}>
<Route element={<AddClient />} path="/clients" />
</Route>
</Routes>
</div>
<footer className="border-top">
Footer
</footer>
</BrowserRouter>
</>
);
}

View File

@ -18,7 +18,7 @@ export default function AddClient() {
//загрузка всех имеющихся уровней при старте
useEffect(() => {
console.log('Обращение к БД');
axios.get('http://localhost:8080/client/')
axios.get('http://localhost:8080/api/1.0/client/')
.then((responce) => {
console.log(responce.data);
setClientItems(responce.data)
@ -28,7 +28,7 @@ export default function AddClient() {
//обновить список уровней
function CheckArray(){
console.log('Обращение к БД');
axios.get('http://localhost:8080/client/')
axios.get('http://localhost:8080/api/1.0/client/')
.then((responce) => {
console.log(responce.data);
setClientItems(responce.data)
@ -44,8 +44,8 @@ export default function AddClient() {
if(clientNickName === ''){
return;
}
else {//http://localhost:8080/client/?nickName=11&email=11&balance=11
axios.post('http://localhost:8080/client/?nickName=' + clientNickName + '&email=' + clientEmail + '&balance=' + clientBalance)
else {
axios.post('http://localhost:8080/api/1.0/client/?nickName=' + clientNickName + '&email=' + clientEmail + '&balance=' + clientBalance)
.then((response) => {
CheckArray();
setClientNickName('');

View File

@ -0,0 +1,8 @@
export default class UserSignupDto {
constructor(args) {
this.login = args.login;
this.email = args.email;
this.password = args.password;
this.passwordConfirm = args.passwordConfirm;
}
}

View File

@ -0,0 +1,148 @@
import { useEffect, useState, useRef } from "react";
import { useNavigate } from 'react-router-dom';
const hostURL = "http://localhost:8080";
const host = hostURL + "/api/1.0";
const AccountPage = function () {
const [currentUser, setCurrentUser] = useState({});
const loginInput = useRef();
const emailInput = useRef();
const navigate = useNavigate();
useEffect(() => {
getUser().then(user => setCurrentUser(user));
}, []);
const getTokenForHeader = function () {
return "Bearer " + localStorage.getItem("token");
}
const login = async function () {
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(currentUser),
};
const requestUrl = hostURL + "/jwt/login";
const response = await fetch(requestUrl, requestParams);
const result = await response.text();
if (response.status === 200) {
localStorage.setItem("token", result);
localStorage.setItem("user", currentUser.login);
getRole(result);
} else {
localStorage.removeItem("token");
localStorage.removeItem("user");
localStorage.removeItem("role");
}
}
const getRole = async function (token) {
const requestParams = {
method: "GET",
headers: {
"Content-Type": "application/json"
}
};
const requestUrl = hostURL + `/who_am_i?token=${token}`;
const response = await fetch(requestUrl, requestParams);
const result = await response.text();
localStorage.setItem("role", result);
window.dispatchEvent(new Event("storage"));
}
const updateUser = async function () {
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": getTokenForHeader(),
},
body: JSON.stringify(currentUser),
};
const requestUrl = host + `/user`;
const response = await fetch(requestUrl, requestParams);
const result = await response.text();
return result;
}
const getUser = async function () {
const requestParams = {
method: "GET",
headers: {
"Authorization": getTokenForHeader(),
}
};
let login = localStorage.getItem("user");
const requestUrl = host + `/user?login=${login}`;
const response = await fetch(requestUrl, requestParams);
const user = await response.json();
return user;
}
const onSubmit = function (event) {
event.preventDefault();
updateUser().then((result) => {
alert(result);
if (result === "Profile updated") {
login();
}
});
}
const onInput = function (event, fieldName) {
setCurrentUser(oldUser => ({
...oldUser, [fieldName]: event.target.value
}));
}
const logoutButtonOnClick = function () {
localStorage.removeItem("token");
localStorage.removeItem("user");
localStorage.removeItem("role");
window.dispatchEvent(new Event("storage"));
navigate("/login");
}
return (
<>
<div class="border-bottom pb-3 mb-3">
<button class="btn btn-primary"
onClick={logoutButtonOnClick}>
Log Out
</button>
</div>
<h4 className="mb-4">Update profile</h4>
<form onSubmit={onSubmit}>
<div className="mb-3">
<p className="mb-1">New Login</p>
<input className="form-control" type="text" required
ref={loginInput} value={currentUser.login}
onInput={(event) => onInput(event, "login")} />
</div>
<div className="mb-3">
<p className="mb-1">New Email</p>
<input className="form-control" type="text" required
ref={emailInput} value={currentUser.email}
onInput={(event) => onInput(event, "email")} />
</div>
<div className="mb-3">
<p className="mb-1">Enter password</p>
<input className="form-control" type="password" required
ref={emailInput}
onInput={(event) => onInput(event, "password")} />
</div>
<button type="submit" className="btn btn-primary">
Save
</button>
</form>
</>
)
}
export default AccountPage;

View File

@ -0,0 +1,90 @@
import { useState, useEffect } from "react";
import { Link, useNavigate } from 'react-router-dom';
import { useRef } from "react";
const hostURL = "http://localhost:8080";
const LoginPage = function () {
const loginInput = useRef();
const passwordInput = useRef();
const navigate = useNavigate();
useEffect(() => {
}, []);
const login = async function (login, password) {
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({login: login, password: password}),
};
const response = await fetch(hostURL + "/jwt/login", requestParams);
const result = await response.text();
if (response.status === 200) {
localStorage.setItem("token", result);
localStorage.setItem("user", login);
getRole(result);
} else {
localStorage.removeItem("token");
localStorage.removeItem("user");
localStorage.removeItem("role");
}
}
const getRole = async function (token) {
const requestParams = {
method: "GET",
headers: {
"Content-Type": "application/json"
}
};
const requestUrl = hostURL + `/who_am_i?token=${token}`;
const response = await fetch(requestUrl, requestParams);
const result = await response.text();
localStorage.setItem("role", result);
window.dispatchEvent(new Event("storage"));
navigate("/main");
}
const loginFormOnSubmit = function (event) {
event.preventDefault();
login(loginInput.current.value, passwordInput.current.value);
};
return (
<>
<div>
<form onSubmit={(event) => loginFormOnSubmit(event)}>
<div className="mb-3">
<p className="mb-1">Login</p>
<input className="form-control"
type="text" required autofocus
ref={loginInput} />
</div>
<div className="mb-3">
<p className="mb-1">Password</p>
<input className="form-control"
type="password" required
ref={passwordInput} />
</div>
<div className="mb-3">
<button type="submit" className="btn btn-success">
Sing in
</button>
</div>
<div>
<p>
<span>Not a member yet?&nbsp;</span>
<Link to="/singup">Sing Up here</Link>
</p>
</div>
</form>
</div>
</>
)
}
export default LoginPage;

View File

@ -0,0 +1,56 @@
import { useState, useEffect } from "react";
import { Link } from 'react-router-dom';
const MyNavBar = function (props) {
const [userRole, setUserRole] = useState("NONE");
useEffect(() => {
window.addEventListener("storage", () => {
getUserRole();
});
getUserRole();
}, [])
const getUserRole = function () {
const role = localStorage.getItem("role") || "NONE";
setUserRole(role);
}
const validate = function (userGroup) {
if ((userGroup === "AUTH" && userRole !== "NONE") ||
(userGroup === userRole)) {
return true;
}
return false;
}
return (
<nav className="navbar navbar-expand-lg bg-body-tertiary">
<div className="container-fluid">
<Link className="navbar-brand fw-bold" to="main">Logo</Link>
<button className="navbar-toggler" data-bs-toggle="collapse"
data-bs-target="#navbar" aria-controls="navbar"
aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbar">
<div className="navbar-nav">
{props.links.map(route => {
if (validate(route.userGroup)) {
return (
<li key={route.path} className="nav-item">
<Link className="nav-link" to={route.path}>
{route.label}
</Link>
</li> );
}
})}
</div>
</div>
</div>
</nav>
);
}
export default MyNavBar;

View File

@ -0,0 +1,47 @@
import { Outlet, Navigate, useNavigate } from 'react-router-dom';
import { useEffect, useState } from "react";
const PrivateRoutes = (props) => {
const navigate = useNavigate();
useEffect(() => {
window.addEventListener("storage", () => {
let token = localStorage.getItem("token");
if (token) {
getRole(token).then((role) => {
if (localStorage.getItem("role") != role) {
localStorage.removeItem("token");
localStorage.removeItem("user");
localStorage.removeItem("role");
window.dispatchEvent(new Event("storage"));
navigate("/main");
}
});
}
});
}, [])
const getRole = async function (token) {
const requestParams = {
method: "GET",
headers: {
"Content-Type": "application/json"
}
};
const requestUrl = `http://localhost:8080/who_am_i?token=${token}`;
const response = await fetch(requestUrl, requestParams);
const result = await response.text();
return result;
}
let isAllowed = false;
let userRole = localStorage.getItem("role");
if ((props.userGroup === "AUTH" && userRole) || (props.userGroup === userRole)) {
isAllowed = true;
}
return isAllowed ? <Outlet /> : <Navigate to="/login" />;
}
export default PrivateRoutes;

View File

@ -0,0 +1,86 @@
import { useState, useEffect } from "react";
import { Link } from 'react-router-dom';
import { useRef } from "react";
const hostURL = "http://localhost:8080";
const SingupPage = function () {
const loginInput = useRef();
const emailInput = useRef();
const passwordInput = useRef();
const passwordConfirmInput = useRef();
useEffect(() => {
}, []);
const singup = async function (userSinginDto) {
const requestParams = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(userSinginDto),
};
const response = await fetch(hostURL + "/sing_up", requestParams);
const result = await response.text();
alert(result);
}
const singupFormOnSubmit = function (event) {
event.preventDefault();
const userSinginDto = {
login: loginInput.current.value,
email: emailInput.current.value,
password: passwordInput.current.value,
passwordConfirm: passwordConfirmInput.current.value
}
singup(userSinginDto);
};
return (
<>
<div>
<form onSubmit={(event) => singupFormOnSubmit(event)}>
<div className="mb-3">
<p className="mb-1">Login</p>
<input className="form-control"
type="text" required maxlength="64"
ref={loginInput} />
</div>
<div className="mb-3">
<p className="mb-1">Email</p>
<input className="form-control"
type="text" required
ref={emailInput} />
</div>
<div className="mb-3">
<p className="mb-1">Password</p>
<input className="form-control"
type="password" required minlength="3" maxlength="64"
ref={passwordInput} />
</div>
<div className="mb-3">
<p className="mb-1">Confirm Password</p>
<input className="form-control"
type="password" required minlength="3" maxlength="64"
ref={passwordConfirmInput} />
</div>
<div className="mb-3">
<button type="submit" className="btn btn-success">
Create account
</button>
</div>
<div>
<p>
<span>Already have an account?&nbsp;</span>
<Link to="/login">Sing In here</Link>
</p>
</div>
</form>
</div>
</>
)
}
export default SingupPage;

View File

@ -2,7 +2,6 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
ReactDOM.createRoot(document.getElementById('app')).render(
<App />
);
)

View File

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()]
})

View File

@ -24,10 +24,6 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2:2.1.210'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
implementation 'org.webjars:bootstrap:5.1.3'
implementation 'org.webjars:jquery:3.6.0'
implementation 'org.webjars:font-awesome:6.1.0'

View File

@ -1,7 +1,5 @@
package premium_store.controller.controller;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.*;
import premium_store.configuration.OpenAPI30Configuration;
import premium_store.controller.DTO.ClientDTO;
import premium_store.controller.DTO.UserSignupDto;
@ -10,9 +8,15 @@ import premium_store.model.UserRole;
import premium_store.service.GameClientService;
import premium_store.service.TankService;
import org.springframework.data.domain.Page;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.ValidationException;
import java.util.List;
import java.util.stream.IntStream;
@RestController
@CrossOrigin
@ -86,4 +90,27 @@ public class GameClientController {
public ClientDTO deleteClient(@PathVariable Long id) {
return new ClientDTO(gameClientService.deleteClient(id));
}
@GetMapping(OpenAPI30Configuration.API_PREFIX + "/users")
@Secured({UserRole.AsString.ADMIN})
public Pair<Page<ClientDTO>, List<Integer>> getUsers(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "5") int size) {
final Page<ClientDTO> users = gameClientService.findAllPages(page, size)
.map(ClientDTO::new);
final int totalPages = users.getTotalPages();
final List<Integer> pageNumbers = IntStream.rangeClosed(1, totalPages)
.boxed()
.toList();
return new Pair<>(users, pageNumbers);
}
@GetMapping(URL_WHO_AM_I)
public String whoAmI(@RequestParam("token") String token) {
UserDetails userDetails = gameClientService.loadUserByToken(token);
GameClient user = gameClientService.findByLogin(userDetails.getUsername());
return user.getRole().toString();
}
}

View File

@ -0,0 +1,19 @@
package premium_store.controller.controller;
public class Pair<F, S> {
private final F first;
private final S second;
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
public F getFirst() {
return first;
}
public S getSecond() {
return second;
}
}

View File

@ -2,7 +2,6 @@
spring.main.banner-mode=off
server.port=8080
#JPA
server.tomcat.relaxed-query-chars=|,{,},[,]
spring.datasource.url=jdbc:h2:file:./data
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
@ -12,3 +11,5 @@ spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false
jwt.dev-token=my-secret-jwt
jwt.dev=true

View File

@ -1,91 +0,0 @@
.add-nation-input{
padding-left: 10px;
padding-right: 10px;
border: 3px solid;
border-radius: 10px;
border-color: #505050;
}
.add-level-button{
border-radius: 10px;
border-color: #505050;
background-color: #FFE430;
font-weight: 900;
}
.client-card{
display: flex;
width: 100%;
padding: 15px;
margin-top: 5px;
border: 5px solid;
border-color: #14A76C;
border-radius: 10px;
opacity: 0.9;
background-color: #151719;
justify-content: space-around;
align-items: center;
font-family: Courier, monospace;
font-weight: 900;
}
.client-attribute{
padding: 5px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
align-items: center;
}
.client-button-group{
display: flex;
width: 20%;
justify-content: space-around;
align-items: center;
}
.client-button{
padding: 10px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
}
.myModal{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
background: rgba(0, 0, 0, 0.8);
}
.myModal.active{
display: flex;
justify-content: center;
align-items: center;
}
.myModalContent{
display: inline-block;
padding: 15px;
width: 100%;
background: #FF652F;
border-radius: 16px;
min-width: 300px;
min-height: 100px;
justify-content: space-between;
align-items: center;
}
.modalButton{
padding: 5px;
border-radius: 10px;
background-color: #FFE430;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -1,82 +0,0 @@
.add-level-button{
border-radius: 10px;
border-color: #505050;
background-color: #FFE430;
font-weight: 900;
}
.level-card{
display: flex;
width: 100%;
padding: 15px;
margin-top: 5px;
border: 5px solid;
border-color: #14A76C;
border-radius: 10px;
opacity: 0.9;
background-color: #151719;
justify-content: space-around;
align-items: center;
font-family: Courier, monospace;
font-weight: 900;
}
.level-attribute{
padding: 5px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
align-items: center;
}
.level-button-group{
display: flex;
width: 20%;
justify-content: space-around;
align-items: center;
}
.level-button{
padding: 10px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
}
.myModal{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
background: rgba(0, 0, 0, 0.8);
}
.myModal.active{
display: flex;
justify-content: center;
align-items: center;
}
.myModalContent{
display: flex;
padding: 15px;
width: 100%;
background: #FF652F;
border-radius: 16px;
min-width: 300px;
min-height: 100px;
justify-content: space-between;
align-items: center;
}
.modalButton{
padding: 5px;
border-radius: 10px;
background-color: #FFE430;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -1,35 +0,0 @@
.myModal{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
background: rgba(0, 0, 0, 0.8);
}
.myModal.active{
display: flex;
justify-content: center;
align-items: center;
}
.myModalContent{
display: flex;
padding: 15px;
width: 100%;
background: #FF652F;
border-radius: 16px;
min-width: 300px;
min-height: 100px;
justify-content: space-between;
align-items: center;
}
.modalButton{
padding: 5px;
border-radius: 10px;
background-color: #FFE430;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -1,55 +0,0 @@
.add-nation-input{
padding-left: 10px;
padding-right: 10px;
border: 3px solid;
border-radius: 10px;
border-color: #505050;
}
.add-level-button{
border-radius: 10px;
border-color: #505050;
background-color: #FFE430;
font-weight: 900;
}
.nation-card{
display: flex;
width: 100%;
padding: 15px;
margin-top: 5px;
border: 5px solid;
border-color: #14A76C;
border-radius: 10px;
opacity: 0.9;
background-color: #151719;
justify-content: space-around;
align-items: center;
font-family: Courier, monospace;
font-weight: 900;
}
.nation-attribute{
padding: 5px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
align-items: center;
}
.nation-button-group{
display: flex;
margin: 10px;
width: 20%;
justify-content: space-around;
align-items: center;
}
.nation-button{
padding: 10px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -1,100 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/*#505050*/
#root{
display: flex;
justify-content: center;
background-color: #151719;
background-image: url("../images/wot-is-4.jpg");
background-size: cover;
background-attachment: fixed;
font-family: Courier, monospace;
font-weight: 900;
}
.body{
margin: 0; /* Убираем отступы */
height: 100%; /* Высота страницы */
justify-content: center;
background-color: #151719;
background-image: url("./wot-is-4.jpg");
background-size: cover;
background-attachment: fixed;
font-family: Courier, monospace;
font-weight: 900;
}
/*
.App{
width: 1200px;
}
*/
.Group_create_level{
display: flex;
padding: 15px;
background-color: #FFE430;
opacity: 0.8;
border-radius: 10px;
margin-top: 15px;
justify-content: space-around;
align-items: center;
}
.Card_list{
padding: 15px;
border: 5px solid;
border-color: #14A76C;
background-color: #151719;
opacity: 0.9;
border-radius: 10px;
margin-top: 15px;
align-items: center;
}
.Main_head{
display: flex;
padding: 15px;
width: 80%;
margin: 30px;
border: 5px solid;
border-color: #FF652F;
border-radius: 10px;
background-color: #151719;
opacity: 0.9;
justify-content: space-between;
align-items: center;
}
.Button_Main_Group{
padding: 5px;
border-color: #FF652F;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: bold;
align-items: center;
}
.add-level-button{
padding: 10px;
margin-right: 15px;
}
.Main-label{
display: flex;
padding-top: 16px;
font-size: 7vw;
font-variant: small-caps;
font-stretch: ultra-expanded;
justify-content: space-around;
align-items: center;
color: #505050;
-webkit-text-stroke-width: 3.0px;
-webkit-text-stroke-color: #000000;
}

View File

@ -1,89 +0,0 @@
.add-nation-input{
padding-left: 10px;
padding-right: 10px;
border: 3px solid;
border-radius: 10px;
border-color: #505050;
}
.add-tank-button{
border-radius: 10px;
border-color: #505050;
background-color: #FFE430;
font-weight: 900;
}
.tank-card{
display: flex;
width: 100%;
padding: 15px;
margin-top: 5px;
border: 5px solid;
border-color: #14A76C;
border-radius: 10px;
opacity: 0.9;
background-color: #151719;
justify-content: space-around;
align-items: center;
font-family: Courier, monospace;
font-weight: 900;
}
.tank-attribute{
padding: 5px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
align-items: center;
}
.tank-button-group{
display: flex;
width: 20%;
justify-content: space-around;
align-items: center;
}
.tank-button{
padding: 10px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
}
.myModal{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
background: rgba(0, 0, 0, 0.8);
}
.myModal.active{
display: flex;
justify-content: center;
align-items: center;
}
.myModalContent{
display: inline-block;
width: 100%;
padding: 15px;
background: #FF652F;
border-radius: 16px;
min-width: 300px;
min-height: 100px;
align-items: center;
}
.modalButton{
padding: 5px;
border-radius: 10px;
background-color: #FFE430;
font-family: Courier, monospace;
font-weight: 900;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

View File

@ -1,73 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/client.css"/>
</head>
<body>
<div layout:fragment="content">
<div class="Group_create_level">
<h1>Генератор клиентов</h1>
</div>
<form action="#" th:action="@{/clients/{id}(id=${id})}" th:object="${supportClientDTO}" method="post">
<div class="myModalContent">
<label for="name" class="form-label">Логин: </label>
<input
type='text'
class="add-nation-input form-control"
id="name"
th:field="${supportClientDTO.login}"
required="true"
/>
<label for="password" class="form-label">Пароль: </label>
<input
type='text'
class="add-nation-input form-control"
id="password"
th:field="${supportClientDTO.password}"
required="true"
/>
<label for="email" class="form-label">Почта: </label>
<input
type='text'
class="add-nation-input form-control"
id="email"
th:field="${supportClientDTO.email}"
required="true"
/>
<label for="balance" class="form-label">Баланс: </label>
<input
type='text'
class="add-nation-input form-control"
id="balance"
th:field="${supportClientDTO.balance}"
required="true"
/>
<label for="name" class="form-label">Танк: </label>
<select id="level" class="form-select" th:field="${supportClientDTO.tankId}" required="true">
<option th:each="value: ${tanks}"
th:value="${value.id}"
th:text="${value.name}">
</option>
</select>
<button
class="modalButton"
type="submit"
>
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Сохранить</span>
</button>
<button
class="modalButton"
type="submit"
th:href="@{/clients}"
>
Назад
</button>
</div>
</form>
</div>
</body>
</html>

View File

@ -1,68 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/style.css"/>
<link rel="stylesheet" href="/css/client.css"/>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<div layout:fragment="content">
<div class="Group_create_level">
<h1>Генератор клиентов</h1>
<h2>
<a class="add-level-button text-dark" type="button"
th:href="@{/clients/edit/}"
>
Создать клиента
</a>
</h2>
</div>
<div>
<h1 style="text-align: center; font-family: courier, monospace; background: #FF652F; border-radius: 10px">
Список существующих клиентов:
</h1>
</div>
<div th:each="user, iterator: ${users}">
<div class="client-card">
<p class="client-attribute" th:text="'Номер: ' + ${user.id}"/>
<p class="client-attribute" th:text="'Никнейм (логин): ' + ${user.login}"/>
<p class="client-attribute" th:text="'Баланс: ' + ${user.balance}"/>
<div class='client-button-group'>
<form th:action="@{/clients/edit/{id}(id=${user.id})}" method="get">
<button class="client-button" type="submit"
th:id="'edit-' + ${user.id}"
>
Редактировать
</button>
</form>
<form th:action="@{/clients/delete/{id}(id=${user.id})}" method="post">
<button th:id="'remove-' + ${user.id}" class="client-button" type="submit"
>
Удалить
</button>
</form>
<form th:action="@{/clients/tanksOfClient/{id}(id=${user.id})}" method="get">
<button th:id="'list-tank-' + ${user.id}" class="client-button" type="submit"
>
Список танков
</button>
</form>
</div>
</div>
</div>
<div th:if="${totalPages > 0}" class="pagination">
<span style="float: left; padding: 5px 5px;">Страницы:</span>
<a th:each="page : ${pages}"
th:href="@{/clients(page=${page}, size=${users.size})}"
th:text="${page}"
th:class="${page == users.number + 1} ? active">
</a>
</div>
</div>
</body>
<th:block layout:fragment="scripts">
</th:block>
</html>

View File

@ -1,55 +0,0 @@
<!DOCTYPE html>
<html lang="ru"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8"/>
<title>Премиум магазин</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<script type="text/javascript" src="/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="/webjars/bootstrap/5.1.3/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/webjars/font-awesome/6.1.0/css/all.min.css"/>
<link rel="stylesheet" href="/css/style.css"/>
</head>
<body class="body">
<div>
<h1 class="Main-label">Мир танков</h1>
</div>
<div class="justify-content-around">
<div>
<nav class="navbar navbar-expand-lg justify-content-around">
<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 justify-content-around" id="navbarNav">
<ul class="Main_head navbar-nav align-items-center" th:with="activeLink=${#request.requestURI}" sec:authorize="isAuthenticated()">
<a class="nav-link btn border border-3 border-dark fs-4 lh-15 Button_Main_Group text-dark" href="/level"
th:classappend="${#strings.equals(activeLink, '/level')} ? 'active' : ''">Обзор уровней
</a>
<a class="nav-link btn border border-3 border-dark fs-4 lh-15 Button_Main_Group text-dark" href="/tank"
th:classappend="${#strings.equals(activeLink, '/tank')} ? 'active' : ''">Обзор танков
</a>
<a class="nav-link btn border border-3 border-dark fs-4 lh-15 Button_Main_Group text-dark" href="/nation"
th:classappend="${#strings.equals(activeLink, '/nation')} ? 'active' : ''">Обзор наций
</a>
<a class="nav-link btn border border-3 border-dark fs-4 lh-15 Button_Main_Group text-dark" href="/clients"
th:classappend="${#strings.equals(activeLink, '/clients')} ? 'active' : ''" sec:authorize="hasRole('ROLE_ADMIN')">Обзор клиентов
</a>
<a class="nav-link btn border border-3 border-dark fs-4 lh-15 Button_Main_Group text-dark" href="/logout">
Выход(<span th:text="${#authentication.name}"></span>)
</a>
</ul>
</div>
</nav>
</div>
</div>
<div class="container-fluid body">
<div class="container container-padding" layout:fragment="content"></div>
</div>
</body>
<th:block layout:fragment="scripts">
</th:block>
</html>

View File

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/nation.css"/>
<link rel="stylesheet" href="/css/modal-nation.css"/>
</head>
<body>
<div layout:fragment="content">
<div th:each="tank, iterator: ${tanks}">
<div class="nation-card">
<p class="nation-attribute" th:text="'Номер: ' + ${tank.id}"/>
<p class="nation-attribute" th:text="'Название: ' + ${tank.name}"/>
<p class="nation-attribute" th:text="'Стоимость: ' + ${tank.cost}"/>
<p class="nation-attribute" th:text="'Уровень: ' + ${tank.level.level}"/>
</div>
</div>
</div>

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/style.css"/>
</head>
<body>
<div class="container" layout:fragment="content">
<div>
<h1 class="Main-label">Авторизация прошла успешно!</h1>
</div>
<a href="123">ERROR</a>
</div>
</body>
</html>

View File

@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/level.css"/>
</head>
<body>
<div layout:fragment="content">
<div class="Group_create_level">
<h1>Генератор уровней</h1>
</div>
<form action="#" th:action="@{/level/{id}(id=${id})}" th:object="${levelDTO}" method="post">
<div class="myModalContent">
<input
type='text'
class="add-level-input form-control"
id="level"
th:field="${levelDTO.level}"
required="true"
/>
<button
class="modalButton"
type="submit"
>
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Сохранить</span>
</button>
<button
class="modalButton"
type="submit"
th:href="@{/level}"
>
Назад
</button>
</div>
</form>
</div>
</body>
</html>

View File

@ -1,58 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/style.css"/>
<link rel="stylesheet" href="/css/level.css"/>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<div layout:fragment="content">
<div class="Group_create_level">
<h1>Генератор уровней</h1>
<h2>
<a class="add-level-button text-dark" type="button"
th:href="@{/level/edit/}"
sec:authorize="hasRole('ROLE_ADMIN')"
>
Создать уровень
</a>
</h2>
<h2
sec:authorize="hasRole('ROLE_USER')"
>
Режим просмотра
</h2>
</div>
<div>
<h1 style="text-align: center; font-family: courier, monospace; background: #FF652F; border-radius: 10px">
Список существующих уровней:
</h1>
</div>
<div th:each="level, iterator: ${levels}">
<div class="level-card">
<p class="level-attribute" th:text="'Номер: ' + ${level.id}"/>
<p class="level-attribute" th:text="'Уровень: ' + ${level.level}"/>
<div class='level-button-group' sec:authorize="hasRole('ROLE_ADMIN')">
<form th:action="@{/level/edit/{id}(id=${level.id})}" method="get">
<button class="level-button" type="submit"
th:id="'edit-' + ${level.id}"
>
Редактировать
</button>
</form>
<form th:action="@{/level/delete/{id}(id=${level.id})}" method="post">
<button th:id="'remove-' + ${level.id}" class="level-button" type="submit">
Удалить
</button>
</form>
</div>
</div>
</div>
</div>
</body>
<th:block layout:fragment="scripts">
</th:block>
</html>

View File

@ -1,34 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<div class="container" layout:fragment="content">
<div th:if="${param.error}" class="alert alert-danger margin-bottom">
Пользователь не найден или пароль указан не верно
</div>
<div th:if="${param.logout}" class="alert alert-success margin-bottom">
Выход успешно произведен
</div>
<div th:if="${param.created}" class="alert alert-success margin-bottom">
Пользователь '<span th:text="${param.created}"></span>' успешно создан
</div>
<form th:action="@{/login}" method="post" class="container-padding">
<div class="mb-3">
<input type="text" name="username" id="username" class="form-control"
placeholder="Логин" required="true" autofocus="true"/>
</div>
<div class="mb-3">
<input type="password" name="password" id="password" class="form-control"
placeholder="Пароль" required="true"/>
</div>
<button type="submit" class="btn btn-success button-fixed">Войти</button>
<a class="btn btn-primary button-fixed" href="/signup">Регистрация</a>
</form>
</div>
</body>
</html>

View File

@ -1,64 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/nation.css"/>
<link rel="stylesheet" href="/css/modal-nation.css"/>
</head>
<body>
<div layout:fragment="content">
<div class="Group_create_level">
<h1>Генератор наций</h1>
</div>
<form action="#" th:action="@{/nation/{id}(id=${id})}" th:object="${simpleNationDTO}" method="post">
<div class="myModalContent">
<input
type='text'
class="add-nation-input form-control"
id="nation"
th:field="${simpleNationDTO.nation}"
required="true"
/>
<button
class="modalButton"
type="submit"
>
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Сохранить</span>
</button>
<button
class="modalButton"
type="submit"
th:href="@{/nation}"
>
Назад
</button>
</div>
</form>
</div>
<!--<div layout:fragment="content">
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/student/{id}(id=${id})}" th:object="${studentDto}" method="post">
<div class="mb-3">
<label for="firstName" class="form-label">Имя</label>
<input type="text" class="form-control" id="firstName" th:field="${studentDto.firstName}" required="true">
</div>
<div class="mb-3">
<label for="lastName" class="form-label">Фамилия</label>
<input type="text" class="form-control" id="lastName" th:field="${studentDto.lastName}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/student}">
Назад
</a>
</div>
</form>
</div>-->
</body>
</html>

View File

@ -1,46 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/nation.css"/>
<link rel="stylesheet" href="/css/modal-nation.css"/>
</head>
<body>
<div layout:fragment="content">
<form action="#" th:action="@{/nation/{id}(id=${id})}" th:object="${fullNationDTO}" method="get">
<div th:each="tank, iterator: ${fullNationDTO.tanks}">
<div class="nation-card">
<p class="nation-attribute" th:text="'Номер: ' + ${tank.id}"/>
<p class="nation-attribute" th:text="'Название: ' + ${tank.name}"/>
<p class="nation-attribute" th:text="'Стоимость: ' + ${tank.cost}"/>
<p class="nation-attribute" th:text="'Уровень: ' + ${tank.level.level}"/>
</div>
</div>
</form>
</div>
<!--<div layout:fragment="content">
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/student/{id}(id=${id})}" th:object="${studentDto}" method="post">
<div class="mb-3">
<label for="firstName" class="form-label">Имя</label>
<input type="text" class="form-control" id="firstName" th:field="${studentDto.firstName}" required="true">
</div>
<div class="mb-3">
<label for="lastName" class="form-label">Фамилия</label>
<input type="text" class="form-control" id="lastName" th:field="${studentDto.lastName}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/student}">
Назад
</a>
</div>
</form>
</div>-->
</body>
</html>

View File

@ -1,65 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/style.css"/>
<link rel="stylesheet" href="/css/nation.css"/>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<div layout:fragment="content">
<div class="Group_create_level">
<h1>Генератор наций</h1>
<h2>
<a class="add-level-button text-dark" type="button"
th:href="@{/nation/edit/}"
sec:authorize="hasRole('ROLE_ADMIN')"
>
Создать нацию
</a>
</h2>
<h2
sec:authorize="hasRole('ROLE_USER')"
>
Режим просмотра
</h2>
</div>
<div>
<h1 style="text-align: center; font-family: courier, monospace; background: #FF652F; border-radius: 10px">
Список существующих наций:
</h1>
</div>
<div th:each="nation, iterator: ${nations}">
<div class="nation-card">
<p class="nation-attribute" th:text="'Номер: ' + ${nation.id}"/>
<p class="nation-attribute" th:text="'Нация: ' + ${nation.nation}"/>
<div class='nation-button-group'>
<form th:action="@{/nation/edit/{id}(id=${nation.id})}" method="get">
<button class="nation-button" type="submit"
th:id="'edit-' + ${nation.id}"
sec:authorize="hasRole('ROLE_ADMIN')"
>
Редактировать
</button>
</form>
<form th:action="@{/nation/delete/{id}(id=${nation.id})}" method="post">
<button th:id="'remove-' + ${nation.id}" class="nation-button" type="submit"
sec:authorize="hasRole('ROLE_ADMIN')">
Удалить
</button>
</form>
<form th:action="@{/nation/editTank/{id}(id=${nation.id})}" method="get">
<button th:id="'edit-tank-' + ${nation.id}" class="nation-button" type="submit">
Список танков
</button>
</form>
</div>
</div>
</div>
</div>
</body>
<th:block layout:fragment="scripts">
</th:block>
</html>

View File

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<div class="container container-padding" layout:fragment="content">
<div th:if="${errors}" th:text="${errors}" class="margin-bottom alert alert-danger"></div>
<form action="#" th:action="@{/signup}" th:object="${clientDTO}" method="post">
<div class="mb-3">
<input type="text" class="form-control" th:field="${clientDTO.login}"
placeholder="Логин" required="true" autofocus="true" maxlength="64"/>
</div>
<div class="mb-3">
<input type="text" class="form-control" th:field="${clientDTO.email}"
placeholder="Почта" required="true" autofocus="true" maxlength="64"/>
</div>
<div class="mb-3">
<input type="text" class="form-control" th:field="${clientDTO.balance}"
placeholder="Балланс" maxlength="64"/>
</div>
<div class="mb-3">
<input type="password" class="form-control" th:field="${clientDTO.password}"
placeholder="Пароль" required="true" minlength="6" maxlength="64"/>
</div>
<div class="mb-3">
<input type="password" class="form-control" th:field="${clientDTO.passwordConfirm}"
placeholder="Пароль (подтверждение)" required="true" minlength="6" maxlength="64"/>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-success button-fixed">Создать</button>
<a class="btn btn-primary button-fixed" href="/login">Назад</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -1,64 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/tank.css"/>
</head>
<body>
<div layout:fragment="content">
<div class="Group_create_level">
<h1>Генератор танков</h1>
</div>
<form class="justify-content-around" action="#" th:action="@{/tank/{id}(id=${id})}" th:object="${supportTankDTO}" method="post">
<div class="myModalContent">
<label for="name" class="form-label">Название: </label>
<input
type='text'
class="add-nation-input form-control"
id="name"
th:field="${supportTankDTO.name}"
required="true"
/>
<label for="name" class="form-label">Нация: </label>
<select id="nation" class="form-select" th:field="${supportTankDTO.nationId}" required="true">
<option th:each="value: ${nations}"
th:value="${value.id}"
th:text="${value.nation}">
</option>
</select>
<label for="name" class="form-label">Уровень: </label>
<select id="level" class="form-select" th:field="${supportTankDTO.levelId}" required="true">
<option th:each="value: ${levels}"
th:value="${value.id}"
th:text="${value.level}">
</option>
</select>
<label for="name" class="form-label">Стоимость: </label>
<input
type='text'
class="add-nation-input form-control"
id="cost"
th:field="${supportTankDTO.cost}"
required="true"
/>
<button
class="modalButton"
type="submit"
>
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Сохранить</span>
</button>
<button
class="modalButton"
type="submit"
th:href="@{/tank}"
>
Назад
</button>
</div>
</form>
</div>
</body>
</html>

View File

@ -1,104 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/style.css"/>
<link rel="stylesheet" href="/css/tank.css"/>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<div layout:fragment="content">
<div class="Group_create_level">
<h1>Генератор танков</h1>
<h2>
<a class="add-tank-button text-dark" type="button"
th:href="@{/tank/edit/}"
sec:authorize="hasRole('ROLE_ADMIN')"
>
Создать танк
</a>
</h2>
<h2
sec:authorize="hasRole('ROLE_USER')"
>
Режим просмотра
</h2>
<form id="filterForm" th:action="@{/tank/filteredList}" th:object="${sortDTO}" method="get">
<button class="tank-button" type="submit"
th:id="filterStart"
>
Фильтрация
</button>
<select id="nation" class="form-select" required="true" th:field="*{nation}">
<option th:each="value: ${nations}"
th:value="${value.nation}"
th:text="${value.nation}">
</option>
</select>
<select id="firstLevel" class="form-select" required="true" th:field="*{firstLevel}">
<option th:each="value: ${levels}"
th:value="${value.level}"
th:text="${value.level}">
</option>
</select>
<select id="secondLevel" class="form-select" required="true" th:field="*{secondLevel}">
<option th:each="value: ${levels}"
th:value="${value.level}"
th:text="${value.level}">
</option>
</select>
</form>
</div>
<div>
<h1 style="text-align: center; font-family: courier, monospace; background: #FF652F; border-radius: 10px">
Список существующих танков:
</h1>
</div>
<div th:each="tank, iterator: ${tanks}">
<div class="tank-card">
<p class="tank-attribute" th:text="'Номер: ' + ${tank.id}"/>
<p class="tank-attribute" th:text="'Название: ' + ${tank.name}"/>
<p class="tank-attribute" th:text="'Нация: ' + ${tank.nation.getNation()}"/>
<p class="tank-attribute" th:text="'Уровень: ' + ${tank.level.getLevel()}"/>
<p class="tank-attribute" th:text="'Стоимость: ' + ${tank.cost}"/>
<div class='tank-button-group' sec:authorize="hasRole('ROLE_ADMIN')">
<form th:action="@{/tank/edit/{id}(id=${tank.id})}" method="get">
<button class="tank-button" type="submit"
th:id="'edit-' + ${tank.id}"
>
Редактировать
</button>
</form>
<form th:action="@{/tank/delete/{id}(id=${tank.id})}" method="post">
<button th:id="'remove-' + ${tank.id}" class="tank-button" type="submit">
Удалить
</button>
</form>
</div>
</div>
</div>
</div>
</body>
<script>
$(document).ready(function() {
$('#filterStart').on('click', function() {
$.ajax({
url: "http://localhost:8080/api/tank/filteredList/?nation='
+escape(document.forms['filterForm'].elements['nation'].value)&
+escape(document.forms['filterForm'].elements['firstLevel'].value)&
+escape(document.forms['filterForm'].elements['secondLevel'].value)"
}).then(function (data) {
});
});
});
</script>
</html>
<!--
-->
<!--th:action="@{/tank/filteredList/{nation}(nation=${document.elements['nation'].value}){firstLevel}(firstLevel=${document.elements['firstLevel'].value}){secondLevel}(secondLevel=${document.elements['secondLevel'].value})}"-->

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<link rel="stylesheet" href="/css/tank.css"/>
</head>
<body>
<div layout:fragment="content">
<form action="#" th:action="@{/clients/{id}(id=${id})}" th:object="${clientDTO}" method="get">
<div th:each="tank, iterator: ${clientDTO.tanks}">
<div class="tank-card">
<p class="tank-attribute" th:text="'Номер: ' + ${tank.id}"/>
<p class="tank-attribute" th:text="'Название: ' + ${tank.name}"/>
<p class="tank-attribute" th:text="'Стоимость: ' + ${tank.cost}"/>
<p class="tank-attribute" th:text="'Нация: ' + ${tank.nation.nation}"/>
<p class="tank-attribute" th:text="'Уровень: ' + ${tank.level.level}"/>
</div>
</div>
</form>
</div>
</body>
</html>