Compare commits

..

3 Commits

Author SHA1 Message Date
2e267b7c96 Merge branch 'frontend'
# Conflicts:
#	backend/Cargo.lock
#	backend/Cargo.toml
#	backend/src/endpoints/car.rs
#	backend/src/endpoints/car_station.rs
#	backend/src/endpoints/client.rs
#	backend/src/endpoints/mod.rs
#	backend/src/endpoints/owner.rs
#	backend/src/endpoints/rent.rs
#	backend/src/lib.rs
#	backend/src/main.rs
#	backend/src/models/car.rs
#	backend/src/models/mod.rs
#	backend/src/models/rent.rs
#	backend/src/storages/postgres/car.rs
#	backend/src/storages/postgres/car_station.rs
#	backend/src/storages/postgres/client.rs
#	backend/src/storages/postgres/mod.rs
#	backend/src/storages/postgres/owner.rs
#	backend/src/storages/postgres/rent.rs
#	backend/src/storages/traits.rs
2023-05-14 22:50:16 +04:00
6e99d9dd88 Фронтенд: Оно работает 2023-05-14 22:32:01 +04:00
9f43a1c04c Фронтенд: заготовка для дальнейшей работы 2023-04-14 21:29:53 +04:00
15 changed files with 899 additions and 36 deletions

12
.gitignore vendored
View File

@ -1,12 +1,16 @@
# ---> Rust # ---> Rust
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
backend/debug/ frontend/debug/
backend/target/ frontend/target/
backend/.env frontend/.env
frontend/dist
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information # MSVC Windows builds of rustc generate these, which store debugging information
backend/*.pdb frontend/*.pdb
.vscode
.vscode/*

View File

@ -1,12 +0,0 @@
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CarStation {
pub id: i32,
pub address: String
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BindingCarStation {
pub address: String
}

View File

@ -1,18 +0,0 @@
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Client {
pub id: i32,
pub name: String,
pub surname: String,
pub middlename: Option<String>,
pub phone: String
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BindingClient {
pub name: String,
pub surname: String,
pub middlename: Option<String>,
pub phone: String
}

View File

@ -1,2 +0,0 @@
pub mod traits;
pub mod postgres;

423
frontend/app.py Normal file
View File

@ -0,0 +1,423 @@
from flask import Flask, request, render_template, session, redirect, url_for
import requests
app = Flask(__name__)
app.secret_key = 'Kill me already'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
if not request.form.get('username') or not request.form.get('password'):
return render_template('login.html', title='Авторизация', errors='Необходимо заполнить все поля',
logged_in=False)
response = requests.post("http://localhost:8080/api/login",
json={
'username': request.form.get('username'),
'password': request.form.get('password')
})
if response.status_code != 200:
return render_template('login.html', title='Авторизация', errors='Неверный логин или пароль',
logged_in=False)
session['token'] = response.json()['token']
session['administrator_id'] = response.json()['administrator_id']
session['car_station_id'] = response.json()['car_station_id']
return redirect(url_for('rents'))
return render_template('login.html', title='Авторизация', logged_in=False)
@app.route('/logout')
def logout():
session.pop('token')
session.pop('administrator_id')
session.pop('car_station_id')
requests.post('http://localhost:8080/api/logout')
return redirect(url_for('login'))
@app.route('/rents', methods=['GET', 'POST'])
def rents():
if not session['token']:
return redirect(url_for('login'))
rents_data = requests.get('http://localhost:8080/api/rents/', headers={'Authorization': session['token']}).json()
cars = list(
filter(lambda c: c['car_station_id'] == session['car_station_id'],
requests.get('http://localhost:8080/api/cars/', headers={'Authorization': session['token']}).json()
)
)
clients = requests.get('http://localhost:8080/api/clients/', headers={'Authorization': session['token']}).json()
for rent in rents_data:
from datetime import datetime
date_format = '%Y-%m-%dT%H:%M:%S.%f'
parsed_date = datetime.strptime(rent['start_time'], date_format)
rent['start_time'] = parsed_date.strftime('%Y-%m-%d %H:%M:%S')
for car in cars:
if car['id'] == rent['car_id']:
rent['car'] = car
if not rent['time_amount']:
cars.remove(car)
break
for client in clients:
if client['id'] == rent['client_id']:
rent['client'] = client
break
if request.method == 'POST':
if not request.form.get('id') and (not request.form.get('client_id') or not request.form.get('car_id')):
return render_template(
'rents.html',
errors='Необходимо заполнить все поля',
title='Аренды',
rents=rents_data,
cars=cars,
clients=clients,
logged_in=True,
selected_client=int(request.args.get('client')) if request.args.get('client') else None,
selected_car=int(request.args.get('car')) if request.args.get('car') else None
)
response = None
if request.form.get('id'):
response = requests.get(f'http://localhost:8080/api/rents/{request.form.get("id")}/end',
headers={'Authorization': session['token']})
else:
response = requests.post('http://localhost:8080/api/rents/', headers={'Authorization': session['token']}, json={
"client_id": int(request.form.get('client_id')),
"car_id": int(request.form.get('car_id'))
})
if response.status_code != 200:
return render_template(
'rents.html',
title='Аренды',
errors=response.json(),
rents=rents_data,
cars=cars,
clients=clients,
logged_in=True,
selected_client=int(request.args.get('client')) if request.args.get('client') else None,
selected_car=int(request.args.get('car')) if request.args.get('car') else None
)
if request.form.get('id'):
return redirect(url_for('rent', id=request.form.get('id')))
rents_data = requests.get('http://localhost:8080/api/rents/',
headers={'Authorization': session['token']}).json()
cars = list(
filter(lambda c: c['car_station_id'] == session['car_station_id'],
requests.get('http://localhost:8080/api/cars/', headers={'Authorization': session['token']}).json()
)
)
clients = requests.get('http://localhost:8080/api/clients/', headers={'Authorization': session['token']}).json()
for rent in rents_data:
from datetime import datetime
date_format = '%Y-%m-%dT%H:%M:%S.%f'
parsed_date = datetime.strptime(rent['start_time'], date_format)
rent['start_time'] = parsed_date.strftime('%Y-%m-%d %H:%M:%S')
for car in cars:
if car['id'] == rent['car_id']:
rent['car'] = car
if not rent['time_amount']:
cars.remove(car)
break
for client in clients:
if client['id'] == rent['client_id']:
rent['client'] = client
break
return render_template(
'rents.html',
title='Аренды',
rents=rents_data,
cars=cars,
clients=clients,
logged_in=True,
selected_client=int(request.args.get('client')) if request.args.get('client') else None,
selected_car=int(request.args.get('car')) if request.args.get('car') else None
)
@app.route('/rents/<int:id>', methods=['GET', 'POST'])
def rent(id):
if not session['token']:
return redirect(url_for('login'))
rent = requests.get(f'http://localhost:8080/api/rents/{id}', headers={'Authorization': session['token']}).json()
client = requests.get(f'http://localhost:8080/api/clients/{rent["client_id"]}', headers={'Authorization': session['token']}).json()
car = requests.get(f'http://localhost:8080/api/cars/{rent["car_id"]}', headers={'Authorization': session['token']}).json()
rent['client'] = client
rent['car'] = car
from datetime import datetime
date_format = '%Y-%m-%dT%H:%M:%S.%f'
parsed_date = datetime.strptime(rent['start_time'], date_format)
rent['start_time'] = parsed_date.strftime('%Y-%m-%d %H:%M:%S')
import math
return render_template('rent.html', title='Просмотр аренды', rent=rent, logged_in=True, float=float, int=int, math=math)
@app.route('/clients', defaults={'id': 0}, methods=['GET', 'POST'])
@app.route('/clients/<int:id>', methods=['GET', 'POST'])
def clients(id):
if not session['token']:
return redirect(url_for('login'))
clients = requests.get('http://localhost:8080/api/clients/', headers={'Authorization': session['token']}).json()
if request.method == 'POST':
if id != 0:
if not request.form.get('name') or not request.form.get('surname') or not request.form.get('middlename') or not request.form.get('phone'):
return render_template(
'clients.html',
title='Изменение клиента',
errors='Должны быть заполнены все поля!',
current_client=list(filter(lambda c: c['id'] == id, clients))[0],
clients=clients,
logged_in=True
)
response = requests.patch(f'http://localhost:8080/api/clients/{id}', headers={'Authorization': session['token']},
json={
'name': request.form.get('name'),
'surname': request.form.get('surname'),
'middlename': request.form.get('middlename'),
'phone': request.form.get('phone')
})
if response.status_code != 200:
return render_template(
'clients.html',
title='Изменение клиента',
errors=response.json(),
clients=clients,
current_client=list(filter(lambda c: c['id'] == id, clients))[0],
logged_in=True
)
return redirect(url_for('clients'))
else:
if not request.form.get('name') or not request.form.get('surname') or not request.form.get('middlename') or not request.form.get('phone'):
return render_template('clients.html', title='Клиенты', errors='Должны быть заполнены все поля!',
clients=clients, logged_in=True)
response = requests.post('http://localhost:8080/api/clients/', headers={'Authorization': session['token']},
json={
'name': request.form.get('name'),
'surname': request.form.get('surname'),
'middlename': request.form.get('middlename'),
'phone': request.form.get('phone')
})
if response.status_code != 200:
return render_template('clients.html', title='Клиенты', errors=response.json(), clients=clients,
logged_in=True)
clients = requests.get('http://localhost:8080/api/clients/', headers={'Authorization': session['token']}).json()
if id != 0:
return render_template('clients.html', title='Изменение клиента', clients=clients, logged_in=True, current_client=list(filter(lambda c: c['id'] == id, clients))[0])
return render_template('clients.html', title='Клиенты', clients=clients, logged_in=True)
@app.route('/owners', defaults={'id': 0}, methods=['GET', 'POST'])
@app.route('/owners/<int:id>', methods=['GET', 'POST'])
def owners(id):
if not session['token']:
return redirect(url_for('login'))
owners = requests.get('http://localhost:8080/api/owners/', headers={'Authorization': session['token']}).json()
cars = list(
filter(lambda c: c['car_station_id'] == session['car_station_id'],
requests.get('http://localhost:8080/api/cars/', headers={'Authorization': session['token']}).json()
)
)
if request.method == 'POST':
if id != 0:
if not request.form.get('name') or not request.form.get('surname') or not request.form.get('middlename') or not request.form.get('phone'):
return render_template(
'owners.html',
title='Изменение владельца',
errors='Должны быть заполнены все поля!',
current_owner=list(filter(lambda c: c['id'] == id, owners))[0],
owners=owners,
cars=cars,
logged_in=True
)
response = requests.patch(f'http://localhost:8080/api/owners/{id}', headers={'Authorization': session['token']},
json={
'name': request.form.get('name'),
'surname': request.form.get('surname'),
'middlename': request.form.get('middlename'),
'phone': request.form.get('phone')
})
if response.status_code != 200:
return render_template(
'owners.html',
title='Изменение владельца',
errors=response.json(),
owners=owners,
cars=cars,
current_owner=list(filter(lambda c: c['id'] == id, owners))[0],
logged_in=True
)
return redirect(url_for('owners'))
else:
if not request.form.get('name') or not request.form.get('surname') or not request.form.get('middlename') or not request.form.get('phone'):
return render_template('owners.html', title='Владельцы', errors='Должны быть заполнены все поля!',
cars=cars,
owners=owners, logged_in=True)
response = requests.post('http://localhost:8080/api/owners/', headers={'Authorization': session['token']},
json={
'name': request.form.get('name'),
'surname': request.form.get('surname'),
'middlename': request.form.get('middlename'),
'phone': request.form.get('phone')
})
if response.status_code != 200:
return render_template('owners.html', title='Владельцы', errors=response.json(), owners=owners,
cars=cars,
logged_in=True)
owners = requests.get('http://localhost:8080/api/owners/', headers={'Authorization': session['token']}).json()
if id != 0:
return render_template('owners.html', title='Изменение владельца', owners=owners, cars=cars, logged_in=True, current_owner=list(filter(lambda c: c['id'] == id, owners))[0])
return render_template('owners.html', title='Владельца', owners=owners, cars=cars, logged_in=True)
@app.route('/cars', defaults={'id': 0}, methods=['GET', 'POST'])
@app.route('/cars/<int:id>', methods=['GET', 'POST'])
def cars(id):
if not session['token']:
return redirect(url_for('login'))
owners = requests.get('http://localhost:8080/api/owners/', headers={'Authorization': session['token']}).json()
cars = list(
filter(lambda c: c['car_station_id'] == session['car_station_id'],
requests.get('http://localhost:8080/api/cars/', headers={'Authorization': session['token']}).json()
)
)
if request.method == 'POST':
if id != 0:
if not request.form.get('brand') or not request.form.get('model') or not request.form.get('price') or not request.form.get('owner_id'):
return render_template(
'cars.html',
title='Изменение автомобиля',
errors='Должны быть заполнены все поля!',
current_car=list(filter(lambda c: c['id'] == id, cars))[0],
cars=cars,
owners=owners,
logged_in=True,
selected_owner=int(request.args.get('owner')) if request.args.get('owner') else None
)
response = requests.patch(f'http://localhost:8080/api/cars/{id}', headers={'Authorization': session['token']},
json={
'brand': request.form.get('brand'),
'model': request.form.get('model'),
'price': float(request.form.get('price')),
'owner_id': int(request.form.get('owner_id')),
'car_station_id': session['car_station_id']
})
if response.status_code != 200:
return render_template(
'cars.html',
title='Изменение автомобиля',
errors=response.json(),
cars=cars,
owners=owners,
current_car=list(filter(lambda c: c['id'] == id, cars))[0],
logged_in=True,
selected_owner=int(request.args.get('owner')) if request.args.get('owner') else None
)
return redirect(url_for('cars'))
else:
if not request.form.get('brand') or not request.form.get('model') or not request.form.get('price') or not request.form.get('owner_id'):
return render_template('cars.html', title='Автомобили', errors='Должны быть заполнены все поля!',
owners=owners, selected_owner=int(request.args.get('owner')) if request.args.get('owner') else None,
cars=cars, logged_in=True)
response = requests.post('http://localhost:8080/api/cars/', headers={'Authorization': session['token']},
json={
'brand': request.form.get('brand'),
'model': request.form.get('model'),
'price': float(request.form.get('price')),
'owner_id': int(request.form.get('owner_id')),
'car_station_id': session['car_station_id']
})
if response.status_code != 200:
return render_template('cars.html', title='Автомобили', errors=response.json(), cars=cars,
owners=owners, selected_owner=int(request.args.get('owner')) if request.args.get('owner') else None,
logged_in=True)
cars = requests.get('http://localhost:8080/api/cars/', headers={'Authorization': session['token']}).json()
if id != 0:
return render_template('cars.html', title='Изменение автомобиля', cars=cars, logged_in=True, owners=owners, selected_owner=int(request.args.get('owner')) if request.args.get('owner') else None, current_car=list(filter(lambda c: c['id'] == id, cars))[0])
return render_template('cars.html', title='Автомобили', cars=cars, logged_in=True, owners=owners, selected_owner=int(request.args.get('owner')) if request.args.get('owner') else None)
@app.route('/report')
def report():
if not session['token']:
return redirect(url_for('login'))
response = requests.get('http://localhost:8080/api/cars/report', headers={'Authorization': session['token']})
reports = list()
for report in response.json():
report['income'] = float(report['income'])
reports.append(report)
return render_template('report.html', title='Отчёт', reports=reports, logged_in=True)
@app.route('/admin', methods=['GET', 'POST'])
def admin():
if not session['token']:
return redirect(url_for('login'))
if request.method == 'POST':
response = requests.get('http://localhost:8080/benchmark', headers={'Authorization': session['token']})
result = response.json()
return render_template('admin.html', title='Панель администратора', logged_in=True, result=result)
return render_template('admin.html', title='Панель администратора', logged_in=True)
if __name__ == '__main__':
app.run()

BIN
frontend/requirements.txt Normal file

Binary file not shown.

View File

@ -0,0 +1,18 @@
{% extends 'base.html' %}
{% block content %}
<div class="row is-vertical-align">
<div class="col"></div>
<form class="col card is-vertical-align" method="post">
<div class="row mb-5">
<button class="button primary is-center">Произвести прирост населения машин и клиентов</button>
</div>
{% if result %}
<div class="alert alert-primary mb-3 h4" role="alert">
Это заняло вот столько микросекунд: {{ result }}
</div>
{% endif %}
</form>
<div class="col"></div>
</div>
{% endblock %}

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<link rel="stylesheet" href="https://unpkg.com/chota@latest">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.7.0.slim.min.js" integrity="sha256-tG5mcZUtJsZvyKAxYLVXrmjKBVLd6VpVccqz/r4ypFE=" crossorigin="anonymous"></script>
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
</head>
<body>
<div class="container mt-5">
{% if logged_in %}
<div class="nav mb-5">
<div class="nav-left">
<a href="/rents" class="button primary outline">Аренды</a>
<a href="/clients" class="button primary outline">Клиенты</a>
<a href="/owners" class="button primary outline">Владельцы</a>
<a href="/cars" class="button primary outline">Автомобили</a>
<a href="/report" class="button primary outline">Отчёт</a>
</div>
<div class="nav-right">
<a href="/logout" class="button danger outline">Выйти</a>
</div>
</div>
{% endif %}
{% block content %}
{% endblock %}
</div>
{% block script %}
{% endblock %}
</body>
</html>

View File

@ -0,0 +1,74 @@
{% extends "base.html" %}
{% block content %}
<div class="row is-vertical-align">
<div class="col"></div>
<form class="col-6 card is-vertical-align" method="post">
<h3 class="is-center mb-5">{% if current_car %} Просмотр автомобиля {% else %} Регистрация автомобиля {% endif %}</h3>
{% if errors %}
<div class="alert alert-danger mb-3 h4" role="alert">
{{ errors }}
</div>
{% endif %}
<div class="row mb-3">
<label class="h4">Марка: <input type="text" name="brand" {% if current_car %} value="{{ current_car.brand }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">Модель: <input type="text" name="model" {% if current_car %} value="{{ current_car.model }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">Цена: <input type="text" name="price" pattern="\d+\.\d{2}" {% if current_car %} value="{{ current_car.price }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">
Владелец:
<select id="owner_id" name="owner_id" class="mt-2">
{% for owner in owners %}
<option {% if selected_owner and selected_owner == owner['id'] %} selected {% endif %} value="{{ owner['id'] }}">ФИО: {{ owner['surname'] }} {{ owner['name'][0] }}. {{ owner['middlename'][0] }}. Телефон: {{ owner['phone'] }}</option>
{% endfor %}
</select>
</label>
</div>
<div class="row mb-5">
<button class="button primary is-center">{% if current_car %} Изменить {% else %} Зарегистрировать автомобиль {% endif %}</button>
</div>
</form>
<div class="col"></div>
</div>
<div class="row is-vertical-align mt-5">
<div class="card col table table-striped">
<h2 class="is-center mb-4">Все автомобили на стоянке</h2>
<table>
<tr>
<th class="h4">Марка</th>
<th class="h4">Модель</th>
<th class="h4">Цена</th>
<th class="h4">Владелец</th>
<th class="h4">Действия</th>
</tr>
{% for car in cars|sort(attribute="brand")|sort(attribute="model")|sort(attribute="price") %}
<tr>
<td class="h4">{{ car.brand }}</td>
<td class="h4">{{ car.model }}</td>
<td class="h4">{{ car.price }}</td>
<td class="h4"><a href="{{ url_for('owners', id=car.owner_id) }}">Перейти к владельцу</a></td>
<td>
<div class="row">
<a href="{{ url_for("rents", car=car.id) }}" class="button primary outline col">Арендовать</a>
<a href="{{ url_for("cars", id=car.id) }}" class="button primary outline col">Посмотреть</a>
</div>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}
{% block script %}
<script>
$(document).ready(function() {
$('#owner_id').select2();
});
</script>
{% endblock %}

View File

@ -0,0 +1,59 @@
{% extends "base.html" %}
{% block content %}
<div class="row is-vertical-align">
<div class="col"></div>
<form class="col card is-vertical-align" method="post">
<h3 class="is-center mb-5">{% if current_client %} Просмотр клиента {% else %} Регистрация клиента {% endif %}</h3>
{% if errors %}
<div class="alert alert-danger mb-3 h4" role="alert">
{{ errors }}
</div>
{% endif %}
<div class="row mb-3">
<label class="h4">Имя: <input type="text" name="name" {% if current_client %} value="{{ current_client.name }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">Фамилия: <input type="text" name="surname" {% if current_client %} value="{{ current_client.surname }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">Отчество: <input type="text" name="middlename" {% if current_client %} value="{{ current_client.middlename }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">Номер телефона: <input type="text" name="phone" pattern="8\d{10}" {% if current_client %} value="{{ current_client.phone }}" {% else %} value="8" {% endif %}/></label>
</div>
<div class="row mb-5">
<button class="button primary is-center">{% if current_client %} Изменить {% else %} Зарегистрировать клиента {% endif %}</button>
</div>
</form>
<div class="col"></div>
</div>
<div class="row is-vertical-align mt-5">
<div class="card col table table-striped">
<h2 class="is-center mb-4">Все клиенты</h2>
<table>
<tr>
<th class="h4">Номер телефона</th>
<th class="h4">Фамилия</th>
<th class="h4">Имя</th>
<th class="h4">Отчество</th>
<th class="h4">Действия</th>
</tr>
{% for client in clients|sort(attribute="surname")|sort(attribute="name")|sort(attribute="middlename") %}
<tr>
<td class="h4">{{ client.phone }}</td>
<td class="h4">{{ client.surname }}</td>
<td class="h4">{{ client.name }}</td>
<td class="h4">{{ client.middlename }}</td>
<td>
<div class="row">
<a href="{{ url_for("rents", client=client.id) }}" class="button primary outline col">Перейти к аренде</a>
<a href="{{ url_for("clients", id=client.id) }}" class="button primary outline col">Посмотреть</a>
</div>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,24 @@
{% extends "base.html" %}
{% block content %}
<div class="row is-vertical-align">
<div class="col"></div>
<form class="col card is-vertical-align" method="post">
{% if errors %}
<div class="alert alert-danger mb-3 h4" role="alert">
{{ errors }}
</div>
{% endif %}
<div class="row mb-3">
<label class="h4">Логин: <input type="text" name="username"/></label>
</div>
<div class="row mb-3">
<label class="h4">Пароль: <input type="password" name="password"/></label>
</div>
<div class="row mb-5">
<button class="button primary is-center">Войти</button>
</div>
</form>
<div class="col"></div>
</div>
{% endblock %}

View File

@ -0,0 +1,91 @@
{% extends "base.html" %}
{% block content %}
<div class="row is-vertical-align">
<div class="col"></div>
<form class="col card is-vertical-align" method="post">
<h3 class="is-center mb-5">{% if current_owner %} Просмотр владельца {% else %} Регистрация владельца {% endif %}</h3>
{% if errors %}
<div class="alert alert-danger mb-3 h4" role="alert">
{{ errors }}
</div>
{% endif %}
<div class="row mb-3">
<label class="h4">Имя: <input type="text" name="name" {% if current_owner %} value="{{ current_owner.name }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">Фамилия: <input type="text" name="surname" {% if current_owner %} value="{{ current_owner.surname }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">Отчество: <input type="text" name="middlename" {% if current_owner %} value="{{ current_owner.middlename }}" {% endif %}/></label>
</div>
<div class="row mb-3">
<label class="h4">Номер телефона: <input type="text" name="phone" pattern="8\d{10}" {% if current_owner %} value="{{ current_owner.phone }}" {% else %} value="8" {% endif %}/></label>
</div>
<div class="row mb-5">
<button class="button primary is-center">{% if current_owner %} Изменить {% else %} Зарегистрировать клиента {% endif %}</button>
</div>
</form>
<div class="col"></div>
</div>
{% if current_owner %}
<div class="row is-vertical-align mt-5">
<div class="card col table table-striped">
<h2 class="is-center mb-4">Автомобили владельца</h2>
<table>
<tr>
<th class="h4">Марка</th>
<th class="h4">Модель</th>
<th class="h4">Цена</th>
<th class="h4">Владелец</th>
<th class="h4">Действия</th>
</tr>
{% for car in cars|sort(attribute="brand")|sort(attribute="model")|sort(attribute="price") %}
{% if car.owner_id == current_owner.id %}
<tr>
<td class="h4">{{ car.brand }}</td>
<td class="h4">{{ car.model }}</td>
<td class="h4">{{ car.price }}</td>
<td class="h4"><a href="{{ url_for('owners', id=car.owner_id) }}">Перейти к владельцу</a></td>
<td>
<div class="row">
<a href="{{ url_for("rents", car=car.id) }}" class="button primary outline col">Арендовать</a>
<a href="{{ url_for("cars", id=car.id) }}" class="button primary outline col">Посмотреть</a>
</div>
</td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
</div>
{% endif %}
<div class="row is-vertical-align mt-5">
<div class="card col table table-striped">
<h2 class="is-center mb-4">Все владельцы</h2>
<table>
<tr>
<th class="h4">Номер телефона</th>
<th class="h4">Фамилия</th>
<th class="h4">Имя</th>
<th class="h4">Отчество</th>
<th class="h4">Действия</th>
</tr>
{% for owner in owners|sort(attribute="surname")|sort(attribute="name")|sort(attribute="middlename") %}
<tr>
<td class="h4">{{ owner.phone }}</td>
<td class="h4">{{ owner.surname }}</td>
<td class="h4">{{ owner.name }}</td>
<td class="h4">{{ owner.middlename }}</td>
<td>
<div class="row">
<a href="{{ url_for("cars", owner=owner.id) }}" class="button primary outline col">Добавить автомобиль</a>
<a href="{{ url_for("owners", id=owner.id) }}" class="button primary outline col">Посмотреть</a>
</div>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "base.html" %}
{% block content %}
<div class="row is-vertical-align">
<div class="col"></div>
<div class="col-6 card h4">
<div class="row">
<div class="col"></div>
<div class="col-8">
<div class="row mb-3 is-left">
Дата начала: {{ rent.start_time }}
</div>
<div class="row mb-3 is-left">
Номер телефона клиента: {{ rent.client.phone }}
</div>
<div class="row mb-3 is-left">
<span>Клиент: <a href="{{ url_for('clients', id=rent.client_id) }}">{{ rent.client.surname }} {{ rent.client.name }} {{ rent.client.middlename }}</a></span>
</div>
<div class="row mb-3 is-left">
<span>Автомобиль: <a href="{{ url_for('cars', id=rent.car_id) }}">{{ rent.car.brand }} {{ rent.car.model }}</a></span>
</div>
<div class="row mb-3 is-left">
Количество минут: {{ rent.time_amount }}
</div>
<div class="row mb-3 is-left">
<span>Итоговая стоимость: <strong>{{ math.ceil(float(rent.car.price) * int(rent.time_amount) * 100) / 100 }}</strong></span>
</div>
</div>
<div class="col"></div>
</div>
</div>
<div class="col"></div>
</div>
{% endblock %}

View File

@ -0,0 +1,109 @@
{% extends 'base.html' %}
{% block content %}
<div class="row is-vertical-align mb-5">
<div class="col"></div>
<form class="col-6 card is-vertical-align" method="post">
<h3 class="is-center mb-5">Создание аренды</h3>
{% if errors %}
<div class="alert alert-danger mb-3 h4" role="alert">
{{ errors }}
</div>
{% endif %}
<div class="row mb-3">
<label class="h4">
Клиент:
<select id="client_id" name="client_id" class="mt-2">
{% for client in clients %}
<option {% if selected_client and selected_client == client['id'] %} selected {% endif %} value="{{ client['id'] }}">ФИО: {{ client['surname'] }} {{ client['name'][0] }}. {{ client['middlename'][0] }}. Телефон: {{ client['phone'] }}</option>
{% endfor %}
</select>
</label>
</div>
<div class="row mb-3">
<label class="h4">
Машина:
<select id="car_id" name="car_id" class="mt-2">
{% for car in cars %}
<option {% if selected_car and selected_car == car['id'] %} selected {% endif %} value="{{ car['id'] }}">Марка: {{ car['brand'] }}. Модель: {{ car['model'] }}. Цена: {{ car['price'] }}</option>
{% endfor %}
</select>
</label>
</div>
<div class="row mb-5">
<button class="button primary is-center">Создать запись об аренде</button>
</div>
</form>
<div class="col"></div>
</div>
<div class="row is-vertical-align mt-5">
<div class="card col table table-striped">
<h2 class="is-center mb-4">Действительные аренды</h2>
<table>
<tr>
<th class="h4">Дата начала</th>
<th class="h4">Номер телефона клиента</th>
<th class="h4">Клиент</th>
<th class="h4">Автомобиль</th>
<th class="h4">Цена за минуту</th>
<th class="h4">Действия</th>
</tr>
{% for rent in rents|sort(reverse=true, attribute="start_time") %}
{% if not rent.time_amount %}
<tr>
<td class="h4">{{ rent.start_time }}</td>
<td class="h4">{{ rent.client.phone }}</td>
<td class="h4"><a href="{{ url_for('clients', id=rent.client_id) }}">{{ rent.client.surname }} {{ rent.client.name }} {{ rent.client.middlename }}</a></td>
<td class="h4"><a href="{{ url_for('cars', id=rent.car_id) }}">{{ rent.car.brand }} {{ rent.car.model }}</a></td>
<td class="h4">{{ rent.car.price }}</td>
<td>
<form method="post" class="row">
<input name="id" value="{{ rent.id }}" style="visibility: hidden">
<button class="button primary outline col">Завершить</button>
</form>
</td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
</div>
<div class="row is-vertical-align mt-5">
<div class="card col table table-striped">
<h2 class="is-center mb-4">Завершённые аренды</h2>
<table>
<tr>
<th class="h4">Дата начала</th>
<th class="h4">Номер телефона клиента</th>
<th class="h4">Клиент</th>
<th class="h4">Автомобиль</th>
<th class="h4">Цена за минуту</th>
<th class="h4">Действия</th>
</tr>
{% for rent in rents|sort(reverse=true, attribute="start_time") %}
{% if rent.time_amount %}
<tr>
<td class="h4">{{ rent.start_time }}</td>
<td class="h4">{{ rent.client.phone }}</td>
<td class="h4"><a href="{{ url_for('clients', id=rent.client_id) }}">{{ rent.client.surname }} {{ rent.client.name }} {{ rent.client.middlename }}</a></td>
<td class="h4"><a href="{{ url_for('cars', id=rent.car_id) }}">{{ rent.car.brand }} {{ rent.car.model }}</a></td>
<td class="h4">{{ rent.car.price }}</td>
<td>
<a href="{{ url_for('rent', id=rent.id) }}" class="button primary outline">Посмотреть</a>
</td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
</div>
{% endblock %}
{% block script %}
<script>
$(document).ready(function() {
$('#client_id').select2();
$('#car_id').select2();
});
</script>
{% endblock %}

View File

@ -0,0 +1,23 @@
{% extends 'base.html' %}
{% block content %}
<div class="row is-vertical-align mt-5">
<div class="card col table table-striped">
<h2 class="is-center mb-4">Отчёт по машинам</h2>
<table>
<tr>
<th class="h4">Автомобиль</th>
<th class="h4">Взят в аренду в этом месяце (раз)</th>
<th class="h4">Доход с машины за этот месяц</th>
</tr>
{% for report in reports|sort(reverse=true, attribute="income") %}
<tr>
<td class="h4"><a href="{{ url_for('cars', id=report.car_id) }}">{{ report.brand }} {{ report.model }}</a></td>
<td class="h4">{{ report.times }}</td>
<td class="h4"> {{ report.income }} </td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}