Добавил формы создания и пофиксил баг с пользователями
This commit is contained in:
@@ -79,26 +79,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transponders Card -->
|
||||
<div class="col-lg-6">
|
||||
<div class="card h-100 shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="bg-warning bg-opacity-10 rounded-circle p-2 me-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-wifi text-warning" viewBox="0 0 16 16">
|
||||
<path d="M6.002 3.5a5.5 5.5 0 1 1 3.996 9.5H10A5.5 5.5 0 0 1 6.002 3.5M6.002 5.5a3.5 3.5 0 1 0 3.996 5.5H10A3.5 3.5 0 0 0 6.002 5.5"/>
|
||||
<path d="M10.5 12.5a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5.5.5 0 0 0-1 0 .5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5.5.5 0 0 0-1 0 .5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5 3.5 3.5 0 0 1 7 0"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="card-title mb-0">Добавление транспондеров</h3>
|
||||
</div>
|
||||
<p class="card-text">Добавьте список транспондеров в базу данных.</p>
|
||||
<a href="{% url 'mainapp:add_trans' %}" class="btn btn-warning">
|
||||
Добавить транспондеры
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- VCH Load Data Card -->
|
||||
<div class="col-lg-6">
|
||||
|
||||
@@ -19,6 +19,19 @@
|
||||
<!-- Form fields with Bootstrap styling -->
|
||||
{% include 'mainapp/components/_form_field.html' with field=form.file %}
|
||||
|
||||
<!-- Automatic checkbox -->
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
{{ form.is_automatic }}
|
||||
<label class="form-check-label" for="{{ form.is_automatic.id_for_label }}">
|
||||
{{ form.is_automatic.label }}
|
||||
</label>
|
||||
{% if form.is_automatic.help_text %}
|
||||
<div class="form-text">{{ form.is_automatic.help_text }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||
<a href="{% url 'mainapp:source_list' %}" class="btn btn-secondary me-md-2">Назад</a>
|
||||
<button type="submit" class="btn btn-success">Добавить в базу</button>
|
||||
|
||||
@@ -21,6 +21,19 @@
|
||||
{% include 'mainapp/components/_form_field.html' with field=form.sat_choice %}
|
||||
{% include 'mainapp/components/_form_field.html' with field=form.number_input %}
|
||||
|
||||
<!-- Automatic checkbox -->
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
{{ form.is_automatic }}
|
||||
<label class="form-check-label" for="{{ form.is_automatic.id_for_label }}">
|
||||
{{ form.is_automatic.label }}
|
||||
</label>
|
||||
{% if form.is_automatic.help_text %}
|
||||
<div class="form-text">{{ form.is_automatic.help_text }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||
<a href="{% url 'mainapp:source_list' %}" class="btn btn-secondary me-md-2">Назад</a>
|
||||
<button type="submit" class="btn btn-primary">Добавить в базу</button>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% load static leaflet_tags %}
|
||||
{% load l10n %}
|
||||
|
||||
{% block title %}{% if object %}Редактировать объект: {{ object.name }}{% else %}Создать объект{% endif %}{% endblock %}
|
||||
{% block title %}{% if object %}Редактировать объект: {{ object.name }}{% else %}Создать новый объект{% endif %}{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/checkbox-select-multiple.css' %}">
|
||||
@@ -144,7 +144,7 @@
|
||||
<div class="container-fluid px-3">
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 d-flex justify-content-between align-items-center">
|
||||
<h2>{% if object %}Редактировать объект: {{ object.name }}{% else %}Создать объект{% endif %}</h2>
|
||||
<h2>{% if object %}Редактировать объект: {{ object.name }}{% else %}Создать новый объект{% endif %}</h2>
|
||||
<div>
|
||||
{% if user.customuser.role == 'admin' or user.customuser.role == 'moderator' %}
|
||||
<button type="submit" form="objitem-form" class="btn btn-primary btn-action">Сохранить</button>
|
||||
@@ -248,6 +248,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if object %}
|
||||
<!-- Транспондер -->
|
||||
<div class="form-section">
|
||||
<div class="form-section-header">
|
||||
@@ -339,6 +340,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Блок с картой -->
|
||||
<div class="form-section">
|
||||
|
||||
@@ -40,13 +40,10 @@
|
||||
|
||||
<!-- Action buttons bar -->
|
||||
<div class="d-flex gap-2">
|
||||
{% comment %} <button type="button" class="btn btn-success btn-sm" title="Добавить">
|
||||
<i class="bi bi-plus-circle"></i> Добавить
|
||||
</button>
|
||||
<button type="button" class="btn btn-info btn-sm" title="Изменить">
|
||||
<i class="bi bi-pencil"></i> Изменить
|
||||
</button> {% endcomment %}
|
||||
{% if user.customuser.role == 'admin' or user.customuser.role == 'moderator' %}
|
||||
<a href="{% url 'mainapp:objitem_create' %}" class="btn btn-success btn-sm" title="Создать новый объект">
|
||||
<i class="bi bi-plus-circle"></i> Создать
|
||||
</a>
|
||||
<button type="button" class="btn btn-danger btn-sm" title="Удалить"
|
||||
onclick="deleteSelectedObjects()">
|
||||
<i class="bi bi-trash"></i> Удалить
|
||||
@@ -243,6 +240,23 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Automatic Filter -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Автоматическая:</label>
|
||||
<div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" name="is_automatic" id="is_automatic_1" value="1"
|
||||
{% if is_automatic == '1' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="is_automatic_1">Да</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" name="is_automatic" id="is_automatic_0" value="0"
|
||||
{% if is_automatic == '0' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="is_automatic_0">Нет</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date Filter -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Дата ГЛ:</label>
|
||||
@@ -309,6 +323,7 @@
|
||||
{% include 'mainapp/components/_table_header.html' with label="Тип точки" field="" sortable=False %}
|
||||
{% include 'mainapp/components/_table_header.html' with label="Sigma" field="" sortable=False %}
|
||||
{% include 'mainapp/components/_table_header.html' with label="Зеркала" field="" sortable=False %}
|
||||
{% include 'mainapp/components/_table_header.html' with label="Автоматическая?" field="is_automatic" sort=sort %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -378,10 +393,11 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ item.mirrors }}</td>
|
||||
<td>{{ item.is_automatic }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="22" class="text-center py-4">
|
||||
<td colspan="23" class="text-center py-4">
|
||||
{% if selected_satellite_id %}
|
||||
Нет данных для выбранных фильтров
|
||||
{% else %}
|
||||
@@ -612,6 +628,7 @@
|
||||
setupRadioLikeCheckboxes('has_valid');
|
||||
setupRadioLikeCheckboxes('has_source_type');
|
||||
setupRadioLikeCheckboxes('has_sigma');
|
||||
setupRadioLikeCheckboxes('is_automatic');
|
||||
|
||||
// Date range quick selection functions
|
||||
window.setDateRange = function (period) {
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4>Частотный план</h4>
|
||||
<p class="text-muted">Визуализация транспондеров спутника по частотам. <span style="color: #0d6efd;">■</span> Downlink (синий), <span style="color: #fd7e14;">■</span> Uplink (оранжевый). Используйте колесико мыши для масштабирования, наведите курсор на полосу для подробной информации.</p>
|
||||
<p class="text-muted">Визуализация транспондеров спутника по частотам. <span style="color: #0d6efd;">■</span> Downlink (синий), <span style="color: #fd7e14;">■</span> Uplink (оранжевый). Используйте колесико мыши для масштабирования, наведите курсор на полосу для подробной информации и связи с парным каналом.</p>
|
||||
|
||||
<div class="frequency-plan">
|
||||
<div class="chart-controls">
|
||||
@@ -272,19 +272,6 @@
|
||||
// Transponder data from Django
|
||||
const transpondersData = {{ transponders|safe }};
|
||||
|
||||
// Color mapping for polarizations
|
||||
const polarizationColors = {
|
||||
'H': '#0d6efd',
|
||||
'V': '#198754',
|
||||
'L': '#dc3545',
|
||||
'R': '#ffc107',
|
||||
'default': '#6c757d'
|
||||
};
|
||||
|
||||
function getColor(polarization) {
|
||||
return polarizationColors[polarization] || polarizationColors['default'];
|
||||
}
|
||||
|
||||
// Chart state
|
||||
let canvas, ctx, container;
|
||||
let zoomLevel = 1;
|
||||
@@ -505,19 +492,21 @@ function renderChart() {
|
||||
|
||||
if (barWidth < 1) return;
|
||||
|
||||
const isHovered = hoveredTransponder && hoveredTransponder.transponder.name === t.name;
|
||||
|
||||
// Draw downlink bar
|
||||
ctx.fillStyle = downlinkColor;
|
||||
ctx.fillRect(x1, downlinkBarY, barWidth, downlinkBarHeight);
|
||||
|
||||
// Draw border
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.lineWidth = 1;
|
||||
// Draw border (thicker if hovered)
|
||||
ctx.strokeStyle = isHovered ? '#000' : '#fff';
|
||||
ctx.lineWidth = isHovered ? 3 : 1;
|
||||
ctx.strokeRect(x1, downlinkBarY, barWidth, downlinkBarHeight);
|
||||
|
||||
// Draw name if there's space
|
||||
if (barWidth > 40) {
|
||||
ctx.fillStyle = (pol === 'R') ? '#000' : '#fff';
|
||||
ctx.font = '9px sans-serif';
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = isHovered ? 'bold 10px sans-serif' : '9px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(t.name, x1 + barWidth / 2, downlinkBarY + downlinkBarHeight / 2 + 3);
|
||||
}
|
||||
@@ -529,7 +518,8 @@ function renderChart() {
|
||||
width: barWidth,
|
||||
height: downlinkBarHeight,
|
||||
transponder: t,
|
||||
type: 'downlink'
|
||||
type: 'downlink',
|
||||
centerX: x1 + barWidth / 2
|
||||
});
|
||||
});
|
||||
|
||||
@@ -553,19 +543,21 @@ function renderChart() {
|
||||
// Skip if too small
|
||||
if (barWidth < 1) return;
|
||||
|
||||
const isHovered = hoveredTransponder && hoveredTransponder.transponder.name === t.name;
|
||||
|
||||
// Draw uplink bar
|
||||
ctx.fillStyle = uplinkColor;
|
||||
ctx.fillRect(x1, uplinkBarY, barWidth, uplinkBarHeight);
|
||||
|
||||
// Draw border
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.lineWidth = 1;
|
||||
// Draw border (thicker if hovered)
|
||||
ctx.strokeStyle = isHovered ? '#000' : '#fff';
|
||||
ctx.lineWidth = isHovered ? 3 : 1;
|
||||
ctx.strokeRect(x1, uplinkBarY, barWidth, uplinkBarHeight);
|
||||
|
||||
// Draw name if there's space
|
||||
if (barWidth > 40) {
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = '9px sans-serif';
|
||||
ctx.font = isHovered ? 'bold 10px sans-serif' : '9px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(t.name, x1 + barWidth / 2, uplinkBarY + uplinkBarHeight / 2 + 3);
|
||||
}
|
||||
@@ -577,7 +569,8 @@ function renderChart() {
|
||||
width: barWidth,
|
||||
height: uplinkBarHeight,
|
||||
transponder: t,
|
||||
type: 'uplink'
|
||||
type: 'uplink',
|
||||
centerX: x1 + barWidth / 2
|
||||
});
|
||||
});
|
||||
|
||||
@@ -593,12 +586,43 @@ function renderChart() {
|
||||
}
|
||||
});
|
||||
|
||||
// Draw hover tooltip
|
||||
// Draw connection line between downlink and uplink when hovering
|
||||
if (hoveredTransponder) {
|
||||
drawConnectionLine(hoveredTransponder);
|
||||
drawTooltip(hoveredTransponder);
|
||||
}
|
||||
}
|
||||
|
||||
function drawConnectionLine(rectInfo) {
|
||||
const t = rectInfo.transponder;
|
||||
if (!t.uplink) return; // No uplink to connect
|
||||
|
||||
// Find both downlink and uplink rects for this transponder
|
||||
const downlinkRect = transponderRects.find(r => r.transponder.name === t.name && r.type === 'downlink');
|
||||
const uplinkRect = transponderRects.find(r => r.transponder.name === t.name && r.type === 'uplink');
|
||||
|
||||
if (!downlinkRect || !uplinkRect) return;
|
||||
|
||||
// Draw connecting line
|
||||
const x1 = downlinkRect.centerX;
|
||||
const y1 = downlinkRect.y + downlinkRect.height;
|
||||
const x2 = uplinkRect.centerX;
|
||||
const y2 = uplinkRect.y;
|
||||
|
||||
ctx.save();
|
||||
ctx.strokeStyle = '#ffc107';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.setLineDash([5, 3]);
|
||||
ctx.globalAlpha = 0.8;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawTooltip(rectInfo) {
|
||||
const t = rectInfo.transponder;
|
||||
const isUplink = rectInfo.type === 'uplink';
|
||||
@@ -639,14 +663,16 @@ function drawTooltip(rectInfo) {
|
||||
const mouseX = rectInfo._mouseX || canvas.width / 2;
|
||||
const mouseY = rectInfo._mouseY || canvas.height / 2;
|
||||
let tooltipX = mouseX + 15;
|
||||
let tooltipY = mouseY + 15;
|
||||
let tooltipY = mouseY - tooltipHeight - 15; // Always show above cursor
|
||||
|
||||
// Keep tooltip in bounds
|
||||
// Keep tooltip in bounds horizontally
|
||||
if (tooltipX + tooltipWidth > canvas.width) {
|
||||
tooltipX = mouseX - tooltipWidth - 15;
|
||||
}
|
||||
if (tooltipY + tooltipHeight > canvas.height) {
|
||||
tooltipY = mouseY - tooltipHeight - 15;
|
||||
|
||||
// If tooltip goes above canvas, show below cursor instead
|
||||
if (tooltipY < 0) {
|
||||
tooltipY = mouseY + 15;
|
||||
}
|
||||
|
||||
// Draw tooltip background
|
||||
|
||||
@@ -129,13 +129,15 @@
|
||||
<div class="container-fluid px-3">
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 d-flex justify-content-between align-items-center">
|
||||
<h2>Редактировать объект #{{ object.id }}</h2>
|
||||
<h2>{% if object %}Редактировать объект #{{ object.id }}{% else %}Создать новый источник{% endif %}</h2>
|
||||
<div>
|
||||
{% if user.customuser.role == 'admin' or user.customuser.role == 'moderator' %}
|
||||
<button type="submit" form="source-form" class="btn btn-primary btn-action">Сохранить</button>
|
||||
{% if object %}
|
||||
<a href="{% url 'mainapp:source_delete' object.id %}{% if request.GET.urlencode %}?{{ request.GET.urlencode }}{% endif %}"
|
||||
class="btn btn-danger btn-action">Удалить</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<a href="{% url 'mainapp:source_list' %}{% if request.GET.urlencode %}?{{ request.GET.urlencode }}{% endif %}"
|
||||
class="btn btn-secondary btn-action">Назад</a>
|
||||
</div>
|
||||
@@ -331,6 +333,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if object %}
|
||||
<!-- Привязанные объекты -->
|
||||
<div class="form-section">
|
||||
<div class="form-section-header">
|
||||
@@ -416,6 +419,7 @@
|
||||
<p class="text-muted">Нет привязанных объектов</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -74,6 +74,11 @@
|
||||
|
||||
<!-- Action buttons -->
|
||||
<div class="d-flex gap-2">
|
||||
{% if user.customuser.role == 'admin' or user.customuser.role == 'moderator' %}
|
||||
<a href="{% url 'mainapp:source_create' %}" class="btn btn-success btn-sm" title="Создать новый источник">
|
||||
<i class="bi bi-plus-circle"></i> Создать
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'mainapp:load_excel_data' %}" class="btn btn-primary btn-sm" title="Загрузка данных из Excel">
|
||||
<i class="bi bi-file-earmark-excel"></i> Excel
|
||||
</a>
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
<a href="{% url 'mainapp:transponder_create' %}" class="btn btn-success btn-sm" title="Создать">
|
||||
<i class="bi bi-plus-circle"></i> Создать
|
||||
</a>
|
||||
<a href="{% url 'mainapp:add_trans' %}" class="btn btn-warning btn-sm" title="Загрузить из XML">
|
||||
<i class="bi bi-upload"></i> Загрузить XML
|
||||
</a>
|
||||
<button type="button" class="btn btn-danger btn-sm" title="Удалить"
|
||||
onclick="deleteSelectedTransponders()">
|
||||
<i class="bi bi-trash"></i> Удалить
|
||||
|
||||
Reference in New Issue
Block a user