my-project/templates/add_client.html
2026-03-23 11:35:48 +05:00

378 lines
16 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}Добавление клиента{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header" style="background: linear-gradient(135deg, var(--steel-blue) 0%, var(--light-steel-blue) 100%); color: white;">
<h2 class="card-title mb-0">
<i class="fas fa-user-plus"></i> Добавление нового клиента
</h2>
</div>
<div class="card-body">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ 'danger' if category == 'error' else 'success' }} alert-dismissible fade show">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
<form method="POST" id="clientForm">
<div class="row">
<!-- Основная информация -->
<div class="col-md-6">
<h5 class="border-bottom pb-2 mb-3" style="color: var(--steel-blue);">Основная информация</h5>
<div class="mb-3">
<label for="name" class="form-label">Название компании (ООО "Ромашка")</label>
<input type="text" class="form-control" id="name" name="name" required maxlength="255"
onkeypress="return blockNumbers(event)" oninput="this.value = this.value.replace(/[0-9]/g, '')"
placeholder="Например: ООО МебельСтиль">
</div>
<div class="mb-3">
<label for="director" class="form-label">Директор (ФИО)</label>
<input type="text" class="form-control" id="director" name="director" maxlength="255"
onkeypress="return blockNumbers(event)" oninput="this.value = this.value.replace(/[0-9]/g, '')"
placeholder="Фамилия Имя Отчество">
</div>
<div class="mb-3">
<label for="contractor_type_id" class="form-label">Тип клиента</label>
<select class="form-select" id="contractor_type_id" name="contractor_type_id" required>
<option value="">Выберите тип клиента</option>
{% for type in contractor_types %}
<option value="{{ type.id }}">{{ type.type_name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label for="rating" class="form-label">Рейтинг (от 0.0 до 5.0)</label>
<input type="number" class="form-control" id="rating" name="rating"
min="0" max="5" step="0.1" value="5.0"
placeholder="Например: 4.5">
<div class="form-text">От 0.0 до 5.0</div>
</div>
</div>
<!-- Контактная информация -->
<div class="col-md-6">
<h5 class="border-bottom pb-2 mb-3" style="color: var(--steel-blue);">Контактная информация</h5>
<div class="mb-3">
<label for="email" class="form-label">Email (company@gmail.com)</label>
<input type="email" class="form-control" id="email" name="email" required maxlength="255"
onkeypress="return allowEnglishOnly(event)" oninput="this.value = this.value.replace(/[а-яА-ЯёЁ]/g, '')"
placeholder="Например: info@company.ru">
</div>
<div class="mb-3">
<label for="phone" class="form-label">Телефон (+7 999 999-99-99)</label>
<input type="tel" class="form-control" id="phone" name="phone" maxlength="50"
onkeypress="return allowPhoneNumbers(event)"
placeholder="+7 (999) 999-99-99">
</div>
<div class="mb-3">
<label for="inn" class="form-label">ИНН (10 или 12 цифр)</label>
<input type="text" class="form-control" id="inn" name="inn" maxlength="12"
onkeypress="return allowOnlyNumbers(event)"
oninput="this.value = this.value.replace(/[^0-9]/g, '').slice(0, 12)"
placeholder="Например: 7701123456">
<div class="form-text">Только цифры, 10 или 12 цифр</div>
</div>
<div class="mb-3">
<label for="address" class="form-label">Юридический адрес (г. Москва, ул. Ленина, д. 1)</label>
<textarea class="form-control" id="address" name="address" rows="3" maxlength="500"
placeholder="Например: 127000, г. Москва, ул. Ленина, д. 5, офис 10"></textarea>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<div class="d-flex justify-content-between">
<a href="{{ url_for('index') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Назад к списку
</a>
<button type="submit" class="btn btn-success">
<i class="fas fa-save"></i> Добавить клиента
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<style>
.card {
border: 1px solid var(--light-steel-blue);
border-radius: 15px;
box-shadow: 0 4px 10px rgba(70, 130, 180, 0.1);
}
.form-label {
color: var(--steel-blue);
font-weight: 500;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
}
.form-control, .form-select {
border: 2px solid var(--light-steel-blue);
border-radius: 8px;
padding: 10px 15px;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
transition: all 0.3s ease;
}
.form-control:focus, .form-select:focus {
border-color: var(--steel-blue);
box-shadow: 0 0 0 0.2rem rgba(70, 130, 180, 0.25);
outline: none;
}
.form-control:hover, .form-select:hover {
border-color: var(--steel-blue);
}
.btn-success {
background: linear-gradient(135deg, #28a745 0%, #218838 100%);
border: none;
border-radius: 8px;
padding: 10px 20px;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
transition: all 0.3s ease;
}
.btn-success:hover {
background: linear-gradient(135deg, #218838 0%, #28a745 100%);
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(40, 167, 69, 0.3);
}
.btn-secondary {
background: linear-gradient(135deg, var(--light-steel-blue) 0%, #9fb6d4 100%);
border: none;
border-radius: 8px;
padding: 10px 20px;
color: #2c3e50;
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
transition: all 0.3s ease;
}
.btn-secondary:hover {
background: linear-gradient(135deg, #9fb6d4 0%, var(--light-steel-blue) 100%);
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(176, 196, 222, 0.3);
}
.alert {
border-radius: 10px;
border: 1px solid var(--light-steel-blue);
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
}
.alert-success {
background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%);
color: #155724;
border-left: 6px solid #28a745;
}
.alert-danger {
background: linear-gradient(135deg, #f8d7da 0%, #f5c6cb 100%);
color: #721c24;
border-left: 6px solid #dc3545;
}
.border-bottom {
border-color: var(--light-steel-blue) !important;
}
textarea.form-control {
resize: vertical;
min-height: 80px;
}
.form-text {
font-family: 'Franklin Gothic', 'Arial Narrow', Arial, sans-serif;
color: #6c757d;
}
input::placeholder, textarea::placeholder {
color: #a0aec0;
font-style: italic;
font-size: 0.9rem;
}
</style>
<script>
// Запрет на ввод цифр в текстовые поля (название компании, ФИО)
function blockNumbers(event) {
const key = event.key;
// Разрешаем: буквы, пробел, backspace, delete, tab, enter, стрелки
if (key === ' ' || key === 'Backspace' || key === 'Delete' || key === 'Tab' ||
key === 'Enter' || key === 'ArrowLeft' || key === 'ArrowRight' ||
key === 'ArrowUp' || key === 'ArrowDown' || key === 'Home' || key === 'End') {
return true;
}
// Запрещаем цифры
if (key >= '0' && key <= '9') {
event.preventDefault();
return false;
}
return true;
}
// Только латинские буквы для email
function allowEnglishOnly(event) {
const key = event.key;
// Разрешаем: латинские буквы, цифры, специальные символы для email
if (key === 'Backspace' || key === 'Delete' || key === 'Tab' ||
key === 'Enter' || key === 'ArrowLeft' || key === 'ArrowRight' ||
key === 'ArrowUp' || key === 'ArrowDown' || key === 'Home' || key === 'End' ||
key === '@' || key === '.' || key === '_' || key === '-') {
return true;
}
// Проверяем, является ли символ латинской буквой или цифрой
const charCode = event.keyCode || event.which;
const isLatin = (charCode >= 65 && charCode <= 90) || (charCode >= 97 && charCode <= 122);
const isNumber = (charCode >= 48 && charCode <= 57);
if (isLatin || isNumber) {
return true;
}
event.preventDefault();
return false;
}
// Разрешаем только цифры (для ИНН)
function allowOnlyNumbers(event) {
const key = event.key;
// Разрешаем: цифры, backspace, delete, tab, enter, стрелки
if (key === 'Backspace' || key === 'Delete' || key === 'Tab' ||
key === 'Enter' || key === 'ArrowLeft' || key === 'ArrowRight' ||
key === 'ArrowUp' || key === 'ArrowDown' || key === 'Home' || key === 'End') {
return true;
}
// Разрешаем только цифры
if (key >= '0' && key <= '9') {
return true;
}
event.preventDefault();
return false;
}
// Для поля телефона разрешаем цифры и некоторые символы
function allowPhoneNumbers(event) {
const key = event.key;
// Разрешаем: цифры, +, -, (, ), пробел, backspace и т.д.
const allowedKeys = ['+', '-', '(', ')', ' '];
if (key === 'Backspace' || key === 'Delete' || key === 'Tab' ||
key === 'Enter' || key === 'ArrowLeft' || key === 'ArrowRight' ||
key === 'ArrowUp' || key === 'ArrowDown' || key === 'Home' || key === 'End') {
return true;
}
if (allowedKeys.includes(key)) {
return true;
}
if (key >= '0' && key <= '9') {
return true;
}
event.preventDefault();
return false;
}
// Валидация формы
document.getElementById('clientForm').addEventListener('submit', function(e) {
const inn = document.getElementById('inn').value;
const name = document.getElementById('name').value;
const director = document.getElementById('director').value;
const email = document.getElementById('email').value;
// Проверка на наличие цифр в названии компании
if (name.match(/[0-9]/)) {
e.preventDefault();
alert('Название компании не должно содержать цифры');
return false;
}
// Проверка на наличие цифр в ФИО директора
if (director && director.match(/[0-9]/)) {
e.preventDefault();
alert('ФИО директора не должно содержать цифры');
return false;
}
// Проверка ИНН
if (inn && !/^\d+$/.test(inn)) {
e.preventDefault();
alert('ИНН должен содержать только цифры');
return false;
}
if (inn && (inn.length !== 10 && inn.length !== 12)) {
e.preventDefault();
alert('ИНН должен содержать 10 или 12 цифр');
return false;
}
// Проверка email на наличие русских букв
if (email.match(/[а-яА-ЯёЁ]/)) {
e.preventDefault();
alert('Email не должен содержать русские буквы');
return false;
}
// Проверка домена email
const allowedDomains = ['gmail.com', 'yandex.ru', 'mail.ru', 'bk.ru', 'list.ru', 'inbox.ru', 'rambler.ru', 'ya.ru'];
const domain = email.split('@')[1];
if (domain) {
const isDomainAllowed = allowedDomains.some(allowed => domain === allowed || domain.endsWith('.' + allowed));
if (!isDomainAllowed && !domain.endsWith('.ru') && !domain.endsWith('.com')) {
if (!confirm('Домен ' + domain + ' не входит в список популярных. Продолжить?')) {
e.preventDefault();
return false;
}
}
}
const rating = parseFloat(document.getElementById('rating').value);
if (rating < 0 || rating > 5) {
e.preventDefault();
alert('Рейтинг должен быть от 0.0 до 5.0');
return false;
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
e.preventDefault();
alert('Введите корректный email адрес');
return false;
}
});
</script>
{% endblock %}