Many fixes
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
{% extends 'superadmin/layout.twig' %}
|
||||
|
||||
{% block title %}Добавить подписку - Суперадмин{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1>Добавить подписку</h1>
|
||||
<a href="{{ base_url('/superadmin/subscriptions') }}" class="btn btn-outline-secondary">
|
||||
<i class="fa-solid fa-arrow-left"></i> Назад к списку
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form action="{{ base_url('/superadmin/subscriptions/store') }}" method="post" class="row g-3">
|
||||
{{ csrf_field()|raw }}
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Организация *</label>
|
||||
<div class="autocomplete-wrapper">
|
||||
<input type="text" class="form-control autocomplete-input" placeholder="Начните вводить название организации..."
|
||||
data-url="{{ base_url('/superadmin/organizations/search') }}" autocomplete="off">
|
||||
<input type="hidden" name="organization_id" class="autocomplete-value" value="">
|
||||
<div class="autocomplete-dropdown"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Модуль *</label>
|
||||
<select name="module_code" class="form-select" required>
|
||||
<option value="">Выберите модуль...</option>
|
||||
{% for code, module in modules %}
|
||||
<option value="{{ code }}">{{ module.name }} - {{ module.price_monthly }} руб/мес</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Количество дней</label>
|
||||
<input type="number" name="duration_days" class="form-control" value="30" min="0" placeholder="0 - бессрочно">
|
||||
<div class="form-text">0 - подписка без срока истечения</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Статус</label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="active">Активна</option>
|
||||
<option value="trial">Триал</option>
|
||||
<option value="expired">Истекла</option>
|
||||
<option value="cancelled">Отменена</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Истекает</label>
|
||||
<input type="text" class="form-control" disabled value="Будет рассчитано автоматически">
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fa-solid fa-plus"></i> Создать подписку
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.autocomplete-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.autocomplete-input {
|
||||
width: 100%;
|
||||
}
|
||||
.autocomplete-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-top: none;
|
||||
border-radius: 0 0 5px 5px;
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
display: none;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
.autocomplete-dropdown.active {
|
||||
display: block;
|
||||
}
|
||||
.autocomplete-item {
|
||||
padding: 12px 15px;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #eee;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.autocomplete-item:hover,
|
||||
.autocomplete-item.selected {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.autocomplete-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.autocomplete-empty {
|
||||
padding: 12px 15px;
|
||||
color: #6c757d;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const input = document.querySelector('.autocomplete-input');
|
||||
const hiddenInput = document.querySelector('.autocomplete-value');
|
||||
const dropdown = document.querySelector('.autocomplete-dropdown');
|
||||
let timeout = null;
|
||||
|
||||
input.addEventListener('input', function() {
|
||||
clearTimeout(timeout);
|
||||
const value = this.value.trim();
|
||||
|
||||
if (value.length < 2) {
|
||||
dropdown.classList.remove('active');
|
||||
hiddenInput.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
fetch(this.dataset.url + '?q=' + encodeURIComponent(value))
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
dropdown.innerHTML = '';
|
||||
|
||||
if (data.results && data.results.length > 0) {
|
||||
data.results.forEach(item => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'autocomplete-item';
|
||||
div.textContent = item.text;
|
||||
div.dataset.id = item.id;
|
||||
div.addEventListener('click', function() {
|
||||
input.value = this.textContent;
|
||||
hiddenInput.value = this.dataset.id;
|
||||
dropdown.classList.remove('active');
|
||||
});
|
||||
dropdown.appendChild(div);
|
||||
});
|
||||
} else {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'autocomplete-empty';
|
||||
div.textContent = 'Организации не найдены';
|
||||
dropdown.appendChild(div);
|
||||
}
|
||||
|
||||
dropdown.classList.add('active');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('.autocomplete-wrapper')) {
|
||||
dropdown.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('focus', function() {
|
||||
if (this.value.trim().length >= 2) {
|
||||
this.dispatchEvent(new Event('input'));
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('keydown', function(e) {
|
||||
const items = dropdown.querySelectorAll('.autocomplete-item');
|
||||
const selected = dropdown.querySelector('.selected');
|
||||
let index = Array.from(items).indexOf(selected);
|
||||
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
if (items.length > 0) {
|
||||
if (index < items.length - 1) {
|
||||
if (selected) selected.classList.remove('selected');
|
||||
items[index + 1].classList.add('selected');
|
||||
}
|
||||
}
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
if (index > 0) {
|
||||
if (selected) selected.classList.remove('selected');
|
||||
items[index - 1].classList.add('selected');
|
||||
}
|
||||
} else if (e.key === 'Enter' && selected) {
|
||||
e.preventDefault();
|
||||
input.value = selected.textContent;
|
||||
hiddenInput.value = selected.dataset.id;
|
||||
dropdown.classList.remove('active');
|
||||
} else if (e.key === 'Escape') {
|
||||
dropdown.classList.remove('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,63 @@
|
||||
{% extends 'superadmin/layout.twig' %}
|
||||
|
||||
{% block title %}Подписки - Суперадмин{% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="/assets/css/modules/data-table.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1>Управление подписками</h1>
|
||||
<a href="{{ base_url('/superadmin/subscriptions/create') }}" class="btn btn-primary">
|
||||
<i class="fa-solid fa-plus"></i> Добавить подписку
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if session.success %}
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
{{ session.success }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if session.error %}
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
{{ session.error }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
{{ tableHtml|raw }}
|
||||
{# CSRF токен для AJAX запросов #}
|
||||
{{ csrf_field()|raw }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ site_url('/assets/js/modules/DataTable.js') }}"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.data-table').forEach(function(container) {
|
||||
const id = container.id;
|
||||
const url = container.dataset.url;
|
||||
const perPage = parseInt(container.dataset.perPage) || 10;
|
||||
|
||||
if (window.dataTables && window.dataTables[id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const table = new DataTable(id, {
|
||||
url: url,
|
||||
perPage: perPage
|
||||
});
|
||||
|
||||
window.dataTables = window.dataTables || {};
|
||||
window.dataTables[id] = table;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user